File indexing completed on 2024-12-01 09:55:34
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2003 Waldo Bastian <bastian@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #ifndef VFOLDER_MENU_H 0009 #define VFOLDER_MENU_H 0010 0011 #include <QDomDocument> 0012 #include <QHash> 0013 #include <QObject> 0014 #include <QSet> 0015 #include <QStack> 0016 #include <QStringList> 0017 0018 #include <kservice.h> 0019 0020 class KBuildSycocaInterface; 0021 class KServiceFactory; 0022 0023 class VFolderMenu : public QObject 0024 { 0025 Q_OBJECT 0026 public: 0027 class AppsInfo; 0028 class SubMenu 0029 { 0030 public: 0031 SubMenu() 0032 : isDeleted(false) 0033 , apps_info(nullptr) 0034 { 0035 items.reserve(43); 0036 } 0037 ~SubMenu() 0038 { 0039 qDeleteAll(subMenus); 0040 } 0041 SubMenu(const SubMenu &) = delete; 0042 SubMenu &operator=(const SubMenu &) = delete; 0043 0044 public: 0045 QString name; 0046 QString directoryFile; 0047 QList<SubMenu *> subMenus; 0048 QHash<QString, KService::Ptr> items; 0049 QHash<QString, KService::Ptr> excludeItems; // Needed when merging due to Move. 0050 QDomElement defaultLayoutNode; 0051 QDomElement layoutNode; 0052 bool isDeleted; 0053 QStringList layoutList; 0054 AppsInfo *apps_info; 0055 }; 0056 0057 VFolderMenu(KServiceFactory *serviceFactory, KBuildSycocaInterface *kbuildsycocaInterface); 0058 ~VFolderMenu() override; 0059 0060 /** 0061 * Parses VFolder menu definition and generates a menu layout. 0062 * The newService signals is used as callback to load 0063 * a specific service description. 0064 * 0065 * @param file Menu file to load 0066 */ 0067 SubMenu *parseMenu(const QString &file); 0068 0069 /** 0070 * Returns a list of all directories involved in the last call to 0071 * parseMenu(). 0072 * 0073 * A change in any of these directories or in any of their child- 0074 * directories can result in changes to the menu. 0075 */ 0076 QStringList allDirectories(); 0077 0078 /** 0079 * Debug function to enable tracking of what happens with a specific 0080 * menu item id 0081 */ 0082 void setTrackId(const QString &id); 0083 0084 public: 0085 struct MenuItem { 0086 enum Type { MI_Service, MI_SubMenu, MI_Separator }; 0087 Type type; 0088 KService::Ptr service; 0089 SubMenu *submenu; 0090 }; 0091 0092 public: 0093 QStringList m_allDirectories; // A list of all the directories that we touch 0094 0095 QStringList m_defaultAppDirs; 0096 QStringList m_defaultDirectoryDirs; 0097 QStringList m_defaultMergeDirs; 0098 0099 QStringList m_directoryDirs; // Current set of applicable <DirectoryDir> dirs 0100 QHash<QString, SubMenu *> m_legacyNodes; // Dictionary that stores Menu nodes 0101 // associated with legacy tree. 0102 0103 class DocInfo 0104 { 0105 public: 0106 QString baseDir; // Relative base dir of current menu file 0107 QString baseName; // Filename of current menu file without ".menu" 0108 QString path; // Full path of current menu file including ".menu" 0109 }; 0110 0111 DocInfo m_docInfo; // DocInfo for current doc 0112 QStack<VFolderMenu::DocInfo> m_docInfoStack; 0113 0114 class AppsInfo 0115 { 0116 public: 0117 AppsInfo() 0118 { 0119 dictCategories.reserve(53); 0120 applications.reserve(997); 0121 appRelPaths.reserve(997); 0122 } 0123 0124 ~AppsInfo() 0125 { 0126 } 0127 0128 QHash<QString, KService::List> dictCategories; // category -> apps 0129 QHash<QString, KService::Ptr> applications; // rel path -> service 0130 QHash<KService::Ptr, QString> appRelPaths; // service -> rel path 0131 }; 0132 0133 AppsInfo *m_appsInfo; // AppsInfo for current menu 0134 QList<AppsInfo *> m_appsInfoStack; // All applicable AppsInfo for current menu 0135 QList<AppsInfo *> m_appsInfoList; // List of all AppsInfo objects. 0136 QSet<QString /*menuId*/> m_usedAppsDict; // all applications that have been allocated 0137 0138 QDomDocument m_doc; 0139 SubMenu *m_rootMenu; 0140 SubMenu *m_currentMenu; 0141 bool m_track; 0142 QString m_trackId; 0143 0144 private: 0145 /** 0146 * Lookup application by relative path 0147 */ 0148 KService::Ptr findApplication(const QString &relPath); 0149 0150 /** 0151 * Lookup applications by category 0152 */ 0153 QList<KService::List *> findCategory(const QString &category); 0154 0155 /** 0156 * Add new application 0157 */ 0158 void addApplication(const QString &id, KService::Ptr service); 0159 0160 /** 0161 * Build application indices 0162 */ 0163 void buildApplicationIndex(bool unusedOnly); 0164 0165 /** 0166 * Create a AppsInfo frame for current menu 0167 */ 0168 void createAppsInfo(); 0169 0170 /** 0171 * Load additional AppsInfo frame for current menu 0172 */ 0173 void loadAppsInfo(); 0174 0175 /** 0176 * Unload additional AppsInfo frame for current menu 0177 */ 0178 void unloadAppsInfo(); 0179 0180 QDomDocument loadDoc(); 0181 void mergeMenus(QDomElement &docElem, QString &name); 0182 void mergeFile(QDomElement &docElem, const QDomNode &mergeHere); 0183 void loadMenu(const QString &filename); 0184 0185 /** 0186 * Merge the items2 set into the items1 set 0187 */ 0188 void includeItems(QHash<QString, KService::Ptr> &items1, const QHash<QString, KService::Ptr> &items2); 0189 0190 /** 0191 * Remove all items from the items1 set that aren't also in the items2 set 0192 */ 0193 void matchItems(QHash<QString, KService::Ptr> &items1, const QHash<QString, KService::Ptr> &items2); 0194 0195 /** 0196 * Remove all items in the items2 set from the items1 set 0197 */ 0198 void excludeItems(QHash<QString, KService::Ptr> &items1, const QHash<QString, KService::Ptr> &items2); 0199 0200 /** 0201 * Search the parentMenu tree for the menu menuName and takes it 0202 * out. 0203 * 0204 * This function returns a pointer to the menu if it was found 0205 * or @c nullptr if it was not found. 0206 */ 0207 SubMenu *takeSubMenu(SubMenu *parentMenu, const QString &menuName); 0208 0209 /** 0210 * Insert the menu newMenu with name menuName into the parentMenu. 0211 * If such menu already exist the result is merged, if any additional 0212 * submenus are required they are created. 0213 * If reversePriority is false, newMenu has priority over the existing 0214 * menu during merging. 0215 * If reversePriority is true, the existing menu has priority over newMenu 0216 * during merging. 0217 */ 0218 void insertSubMenu(VFolderMenu::SubMenu *parentMenu, const QString &menuName, VFolderMenu::SubMenu *newMenu, bool reversePriority = false); 0219 0220 /** 0221 * Merge menu2 and its submenus into menu1 and its submenus 0222 * If reversePriority is false, menu2 has priority over menu1 0223 * If reversePriority is true, menu1 has priority over menu2 0224 */ 0225 void mergeMenu(SubMenu *menu1, SubMenu *menu2, bool reversePriority = false); 0226 0227 /** 0228 * Inserts service into the menu using name relative to parentMenu 0229 * Any missing sub-menus are created. 0230 */ 0231 void insertService(SubMenu *parentMenu, const QString &name, KService::Ptr newService); 0232 0233 /** 0234 * Register the directory that @p file is in. 0235 * @see allDirectories() 0236 */ 0237 void registerFile(const QString &file); 0238 0239 /** 0240 * Fill m_usedAppsDict with all applications from @p items 0241 */ 0242 void markUsedApplications(const QHash<QString, KService::Ptr> &items); 0243 0244 /** 0245 * Register @p directory 0246 * @see allDirectories() 0247 */ 0248 void registerDirectory(const QString &directory); 0249 0250 void processLegacyDir(const QString &dir, const QString &relDir, const QString &prefix); 0251 void processMenu(QDomElement &docElem, int pass); 0252 void layoutMenu(VFolderMenu::SubMenu *menu, QStringList defaultLayout); 0253 void processCondition(QDomElement &docElem, QHash<QString, KService::Ptr> &items); 0254 0255 void initDirs(); 0256 0257 void pushDocInfo(const QString &fileName, const QString &baseDir = QString()); 0258 void pushDocInfoParent(const QString &basePath, const QString &baseDir); 0259 void popDocInfo(); 0260 0261 QString absoluteDir(const QString &_dir, const QString &baseDir, bool keepRelativeToCfg = false); 0262 QString locateMenuFile(const QString &fileName); 0263 QString locateDirectoryFile(const QString &fileName); 0264 void loadApplications(const QString &, const QString &); 0265 QStringList parseLayoutNode(const QDomElement &docElem) const; 0266 0267 private: 0268 KServiceFactory *m_serviceFactory; 0269 KBuildSycocaInterface *m_kbuildsycocaInterface; 0270 }; 0271 0272 #endif