1/*
2 This file is part of the KDE libraries
3 Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#ifndef KDED_VFOLDER_MENU_H
21#define KDED_VFOLDER_MENU_H
22
23#include <QtCore/QObject>
24#include <QtXml/QDomDocument>
25#include <QtCore/QStringList>
26#include <QtCore/QHash>
27#include <QtCore/QSet>
28#include <QtCore/QStack>
29
30#include <kservice.h>
31
32class KBuildSycocaInterface;
33class KBuildServiceFactory;
34
35class VFolderMenu : public QObject
36{
37 Q_OBJECT
38public:
39 class AppsInfo;
40 class SubMenu {
41 public:
42 SubMenu() : isDeleted(false),apps_info(0) { items.reserve(43); }
43 ~SubMenu() { qDeleteAll(subMenus); }
44
45 public:
46 QString name;
47 QString directoryFile;
48 QList<SubMenu*> subMenus;
49 QHash<QString,KService::Ptr> items;
50 QHash<QString,KService::Ptr> excludeItems; // Needed when merging due to Move.
51 QDomElement defaultLayoutNode;
52 QDomElement layoutNode;
53 bool isDeleted;
54 QStringList layoutList;
55 AppsInfo *apps_info;
56 };
57
58 VFolderMenu(KBuildServiceFactory* serviceFactory, KBuildSycocaInterface* kbuildsycocaInterface);
59 ~VFolderMenu();
60
61 /**
62 * Parses VFolder menu definition and generates a menu layout.
63 * The newService signals is used as callback to load
64 * a specific service description.
65 *
66 * @param file Menu file to load
67 * @param forceLegacyLoad flag indicating whether the KDE "applnk"
68 * directory should be processed at least once.
69 */
70 SubMenu *parseMenu(const QString &file, bool forceLegacyLoad=false);
71
72 /**
73 * Returns a list of all directories involved in the last call to
74 * parseMenu(), excluding the KDE Legacy directories.
75 *
76 * A change in any of these directories or in any of their child-
77 * directories can result in changes to the menu.
78 */
79 QStringList allDirectories();
80
81 /**
82 * Debug function to enable tracking of what happens with a specific
83 * menu item id
84 */
85 void setTrackId(const QString &id);
86
87public:
88 struct MenuItem
89 {
90 enum Type { MI_Service, MI_SubMenu, MI_Separator };
91 Type type;
92 KService::Ptr service;
93 SubMenu *submenu;
94 };
95
96public:
97 QStringList m_allDirectories; // A list of all the directories that we touch
98
99 QStringList m_defaultDataDirs;
100 QStringList m_defaultAppDirs;
101 QStringList m_defaultDirectoryDirs;
102 QStringList m_defaultMergeDirs;
103 QStringList m_defaultLegacyDirs;
104
105 QStringList m_directoryDirs; // Current set of applicable <DirectoryDir> dirs
106 QHash<QString, SubMenu*> m_legacyNodes; // Dictionary that stores Menu nodes
107 // associated with legacy tree.
108
109 class DocInfo {
110 public:
111 QString baseDir; // Relative base dir of current menu file
112 QString baseName; // Filename of current menu file without ".menu"
113 QString path; // Full path of current menu file including ".menu"
114 };
115
116
117 DocInfo m_docInfo; // DocInfo for current doc
118 QStack<VFolderMenu::DocInfo> m_docInfoStack;
119
120 class AppsInfo {
121 public:
122 AppsInfo()
123 {
124 dictCategories.reserve(53);
125 applications.reserve(997);
126 appRelPaths.reserve(997);
127 }
128
129 ~AppsInfo()
130 {
131 }
132
133 QHash<QString,KService::List> dictCategories; // category -> apps
134 QHash<QString,KService::Ptr> applications; // rel path -> service
135 QHash<KService::Ptr,QString> appRelPaths; // service -> rel path
136 };
137
138 AppsInfo *m_appsInfo; // AppsInfo for current menu
139 QList<AppsInfo*> m_appsInfoStack; // All applicable AppsInfo for current menu
140 QList<AppsInfo*> m_appsInfoList; // List of all AppsInfo objects.
141 QSet<QString /*menuId*/> m_usedAppsDict; // all applications that have been allocated
142
143 QDomDocument m_doc;
144 SubMenu *m_rootMenu;
145 SubMenu *m_currentMenu;
146 bool m_forcedLegacyLoad;
147 bool m_legacyLoaded;
148 bool m_track;
149 QString m_trackId;
150
151private:
152 /**
153 * Lookup application by relative path
154 */
155 KService::Ptr findApplication(const QString &relPath);
156
157 /**
158 * Lookup applications by category
159 */
160 QList<KService::List*> findCategory(const QString &category);
161
162 /**
163 * Add new application
164 */
165 void addApplication(const QString &id, KService::Ptr service);
166
167 /**
168 * Build application indices
169 */
170 void buildApplicationIndex(bool unusedOnly);
171
172 /**
173 * Create a AppsInfo frame for current menu
174 */
175 void createAppsInfo();
176
177 /**
178 * Load additional AppsInfo frame for current menu
179 */
180 void loadAppsInfo();
181
182 /**
183 * Unload additional AppsInfo frame for current menu
184 */
185 void unloadAppsInfo();
186
187 QDomDocument loadDoc();
188 void mergeMenus(QDomElement &docElem, QString &name);
189 void mergeFile(QDomElement &docElem, const QDomNode &mergeHere);
190 void loadMenu(const QString &filename);
191
192 /**
193 * Merge the items2 set into the items1 set
194 */
195 void includeItems(QHash<QString,KService::Ptr>& items1, const QHash<QString,KService::Ptr>& items2);
196
197 /**
198 * Remove all items from the items1 set that aren't also in the items2 set
199 */
200 void matchItems(QHash<QString,KService::Ptr>& items1, const QHash<QString,KService::Ptr>& items2);
201
202 /**
203 * Remove all items in the items2 set from the items1 set
204 */
205 void excludeItems(QHash<QString,KService::Ptr>& items1, const QHash<QString,KService::Ptr>& items2);
206
207 /**
208 * Search the parentMenu tree for the menu menuName and takes it
209 * out.
210 *
211 * This function returns a pointer to the menu if it was found
212 * or 0 if it was not found.
213 */
214 SubMenu* takeSubMenu(SubMenu *parentMenu, const QString &menuName);
215
216 /**
217 * Insert the menu newMenu with name menuName into the parentMenu.
218 * If such menu already exist the result is merged, if any additional
219 * submenus are required they are created.
220 * If reversePriority is false, newMenu has priority over the existing
221 * menu during merging.
222 * If reversePriority is true, the existing menu has priority over newMenu
223 * during merging.
224 */
225 void insertSubMenu(VFolderMenu::SubMenu *parentMenu, const QString &menuName, VFolderMenu::SubMenu *newMenu, bool reversePriority=false);
226
227 /**
228 * Merge menu2 and its submenus into menu1 and its submenus
229 * If reversePriority is false, menu2 has priority over menu1
230 * If reversePriority is true, menu1 has priority over menu2
231 */
232 void mergeMenu(SubMenu *menu1, SubMenu *menu2, bool reversePriority=false);
233
234 /**
235 * Inserts service into the menu using name relative to parentMenu
236 * Any missing sub-menus are created.
237 */
238 void insertService(SubMenu *parentMenu, const QString &name, KService::Ptr newService);
239
240 /**
241 * Register the directory that @p file is in.
242 * @see allDirectories()
243 */
244 void registerFile(const QString &file);
245
246 /**
247 * Fill m_usedAppsDict with all applications from @p items
248 */
249 void markUsedApplications(const QHash<QString,KService::Ptr>& items);
250
251 /**
252 * Register @p directory
253 * @see allDirectories()
254 */
255 void registerDirectory(const QString &directory);
256
257 void processKDELegacyDirs();
258 void processLegacyDir(const QString &dir, const QString &relDir, const QString &prefix);
259 void processMenu(QDomElement &docElem, int pass);
260 void layoutMenu(VFolderMenu::SubMenu *menu, QStringList defaultLayout);
261 void processCondition(QDomElement &docElem, QHash<QString,KService::Ptr>& items);
262
263 void initDirs();
264
265 void pushDocInfo(const QString &fileName, const QString &baseDir = QString());
266 void pushDocInfoParent(const QString &basePath, const QString &baseDir);
267 void popDocInfo();
268
269 QString absoluteDir(const QString &_dir, const QString &baseDir, bool keepRelativeToCfg=false);
270 QString locateMenuFile(const QString &fileName);
271 QString locateDirectoryFile(const QString &fileName);
272 void loadApplications(const QString&, const QString&);
273
274private:
275 KBuildServiceFactory* m_serviceFactory;
276 KBuildSycocaInterface* m_kbuildsycocaInterface;
277};
278
279#endif
280