• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kded
 

kded

  • kded
vfolder_menu.cpp
1 /* This file is part of the KDE libraries
2  * Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License version 2 as published by the Free Software Foundation;
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * Library General Public License for more details.
12  *
13  * You should have received a copy of the GNU Library General Public License
14  * along with this library; see the file COPYING.LIB. If not, write to
15  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  * Boston, MA 02110-1301, USA.
17  **/
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <dirent.h>
23 #include <stdlib.h> // getenv
24 
25 #include <kdebug.h>
26 #include <tdeglobal.h>
27 #include <kstandarddirs.h>
28 #include <kservice.h>
29 #include <kde_file.h>
30 
31 #include <tqmap.h>
32 #include <tqfile.h>
33 #include <tqdir.h>
34 #include <tqregexp.h>
35 
36 #include "vfolder_menu.h"
37 
38 static void foldNode(TQDomElement &docElem, TQDomElement &e, TQMap<TQString,TQDomElement> &dupeList, TQString s=TQString::null)
39 {
40  if (s.isEmpty())
41  s = e.text();
42  TQMap<TQString,TQDomElement>::iterator it = dupeList.find(s);
43  if (it != dupeList.end())
44  {
45  kdDebug(7021) << e.tagName() << " and " << s << " requires combining!" << endl;
46 
47  docElem.removeChild(*it);
48  dupeList.remove(it);
49  }
50  dupeList.insert(s, e);
51 }
52 
53 static void replaceNode(TQDomElement &docElem, TQDomNode &n, const TQStringList &list, const TQString &tag)
54 {
55  for(TQStringList::ConstIterator it = list.begin();
56  it != list.end(); ++it)
57  {
58  TQDomElement e = docElem.ownerDocument().createElement(tag);
59  TQDomText txt = docElem.ownerDocument().createTextNode(*it);
60  e.appendChild(txt);
61  docElem.insertAfter(e, n);
62  }
63 
64  TQDomNode next = n.nextSibling();
65  docElem.removeChild(n);
66  n = next;
67 // kdDebug(7021) << "Next tag = " << n.toElement().tagName() << endl;
68 }
69 
70 void VFolderMenu::registerFile(const TQString &file)
71 {
72  int i = file.findRev('/');
73  if (i < 0)
74  return;
75 
76  TQString dir = file.left(i+1); // Include trailing '/'
77  registerDirectory(dir);
78 }
79 
80 void VFolderMenu::registerDirectory(const TQString &directory)
81 {
82  m_allDirectories.append(directory);
83 }
84 
85 TQStringList VFolderMenu::allDirectories()
86 {
87  if (m_allDirectories.isEmpty())
88  return m_allDirectories;
89  m_allDirectories.sort();
90 
91  TQStringList::Iterator it = m_allDirectories.begin();
92  TQString previous = *it++;
93  for(;it != m_allDirectories.end();)
94  {
95  if ((*it).startsWith(previous))
96  {
97  it = m_allDirectories.remove(it);
98  }
99  else
100  {
101  previous = *it;
102  ++it;
103  }
104  }
105  return m_allDirectories;
106 }
107 
108 static void
109 track(const TQString &menuId, const TQString &menuName, TQDict<KService> *includeList, TQDict<KService> *excludeList, TQDict<KService> *itemList, const TQString &comment)
110 {
111  if (itemList->find(menuId))
112  printf("%s: %s INCL %d EXCL %d\n", menuName.latin1(), comment.latin1(), includeList->find(menuId) ? 1 : 0, excludeList->find(menuId) ? 1 : 0);
113 }
114 
115 void
116 VFolderMenu::includeItems(TQDict<KService> *items1, TQDict<KService> *items2)
117 {
118  for(TQDictIterator<KService> it(*items2); it.current(); ++it)
119  {
120  items1->replace(it.current()->menuId(), it.current());
121  }
122 }
123 
124 void
125 VFolderMenu::matchItems(TQDict<KService> *items1, TQDict<KService> *items2)
126 {
127  for(TQDictIterator<KService> it(*items1); it.current(); )
128  {
129  TQString id = it.current()->menuId();
130  ++it;
131  if (!items2->find(id))
132  items1->remove(id);
133  }
134 }
135 
136 void
137 VFolderMenu::excludeItems(TQDict<KService> *items1, TQDict<KService> *items2)
138 {
139  for(TQDictIterator<KService> it(*items2); it.current(); ++it)
140  {
141  items1->remove(it.current()->menuId());
142  }
143 }
144 
145 VFolderMenu::SubMenu*
146 VFolderMenu::takeSubMenu(SubMenu *parentMenu, const TQString &menuName)
147 {
148  int i = menuName.find('/');
149  TQString s1 = i > 0 ? menuName.left(i) : menuName;
150  TQString s2 = menuName.mid(i+1);
151 
152  // Look up menu
153  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
154  {
155  if (menu->name == s1)
156  {
157  if (i == -1)
158  {
159  // Take it out
160  return parentMenu->subMenus.take();
161  }
162  else
163  {
164  return takeSubMenu(menu, s2);
165  }
166  }
167  }
168  return 0; // Not found
169 }
170 
171 void
172 VFolderMenu::mergeMenu(SubMenu *menu1, SubMenu *menu2, bool reversePriority)
173 {
174  if (m_track)
175  {
176  track(m_trackId, menu1->name, &(menu1->items), &(menu1->excludeItems), &(menu2->items), TQString("Before MenuMerge w. %1 (incl)").arg(menu2->name));
177  track(m_trackId, menu1->name, &(menu1->items), &(menu1->excludeItems), &(menu2->excludeItems), TQString("Before MenuMerge w. %1 (excl)").arg(menu2->name));
178  }
179  if (reversePriority)
180  {
181  // Merge menu1 with menu2, menu1 takes precedent
182  excludeItems(&(menu2->items), &(menu1->excludeItems));
183  includeItems(&(menu1->items), &(menu2->items));
184  excludeItems(&(menu2->excludeItems), &(menu1->items));
185  includeItems(&(menu1->excludeItems), &(menu2->excludeItems));
186  }
187  else
188  {
189  // Merge menu1 with menu2, menu2 takes precedent
190  excludeItems(&(menu1->items), &(menu2->excludeItems));
191  includeItems(&(menu1->items), &(menu2->items));
192  includeItems(&(menu1->excludeItems), &(menu2->excludeItems));
193  menu1->isDeleted = menu2->isDeleted;
194  }
195  for(; menu2->subMenus.first(); )
196  {
197  SubMenu *subMenu = menu2->subMenus.take();
198  insertSubMenu(menu1, subMenu->name, subMenu, reversePriority);
199  }
200 
201  if (reversePriority)
202  {
203  // Merge menu1 with menu2, menu1 takes precedent
204  if (menu1->directoryFile.isEmpty())
205  menu1->directoryFile = menu2->directoryFile;
206  if (menu1->defaultLayoutNode.isNull())
207  menu1->defaultLayoutNode = menu2->defaultLayoutNode;
208  if (menu1->layoutNode.isNull())
209  menu1->layoutNode = menu2->layoutNode;
210  }
211  else
212  {
213  // Merge menu1 with menu2, menu2 takes precedent
214  if (!menu2->directoryFile.isEmpty())
215  menu1->directoryFile = menu2->directoryFile;
216  if (!menu2->defaultLayoutNode.isNull())
217  menu1->defaultLayoutNode = menu2->defaultLayoutNode;
218  if (!menu2->layoutNode.isNull())
219  menu1->layoutNode = menu2->layoutNode;
220  }
221 
222  if (m_track)
223  {
224  track(m_trackId, menu1->name, &(menu1->items), &(menu1->excludeItems), &(menu2->items), TQString("After MenuMerge w. %1 (incl)").arg(menu2->name));
225  track(m_trackId, menu1->name, &(menu1->items), &(menu1->excludeItems), &(menu2->excludeItems), TQString("After MenuMerge w. %1 (excl)").arg(menu2->name));
226  }
227 
228  delete menu2;
229 }
230 
231 void
232 VFolderMenu::insertSubMenu(SubMenu *parentMenu, const TQString &menuName, SubMenu *newMenu, bool reversePriority)
233 {
234  int i = menuName.find('/');
235 
236  TQString s1 = menuName.left(i);
237  TQString s2 = menuName.mid(i+1);
238 
239  // Look up menu
240  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
241  {
242  if (menu->name == s1)
243  {
244  if (i == -1)
245  {
246  mergeMenu(menu, newMenu, reversePriority);
247  return;
248  }
249  else
250  {
251  insertSubMenu(menu, s2, newMenu, reversePriority);
252  return;
253  }
254  }
255  }
256  if (i == -1)
257  {
258  // Add it here
259  newMenu->name = menuName;
260  parentMenu->subMenus.append(newMenu);
261  }
262  else
263  {
264  SubMenu *menu = new SubMenu;
265  menu->name = s1;
266  parentMenu->subMenus.append(menu);
267  insertSubMenu(menu, s2, newMenu);
268  }
269 }
270 
271 void
272 VFolderMenu::insertService(SubMenu *parentMenu, const TQString &name, KService *newService)
273 {
274  int i = name.find('/');
275 
276  if (i == -1)
277  {
278  // Add it here
279  parentMenu->items.replace(newService->menuId(), newService);
280  return;
281  }
282 
283  TQString s1 = name.left(i);
284  TQString s2 = name.mid(i+1);
285 
286  // Look up menu
287  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
288  {
289  if (menu->name == s1)
290  {
291  insertService(menu, s2, newService);
292  return;
293  }
294  }
295 
296  SubMenu *menu = new SubMenu;
297  menu->name = s1;
298  parentMenu->subMenus.append(menu);
299  insertService(menu, s2, newService);
300 }
301 
302 
303 VFolderMenu::VFolderMenu() : m_usedAppsDict(797), m_track(false)
304 {
305  m_rootMenu = 0;
306  initDirs();
307 }
308 
309 VFolderMenu::~VFolderMenu()
310 {
311  delete m_rootMenu;
312 }
313 
314 #define FOR_ALL_APPLICATIONS(it) \
315  for(appsInfo *info = m_appsInfoStack.first(); \
316  info; info = m_appsInfoStack.next()) \
317  { \
318  for(TQDictIterator<KService> it( info->applications ); \
319  it.current(); ++it ) \
320  {
321 #define FOR_ALL_APPLICATIONS_END } }
322 
323 #define FOR_CATEGORY(category, it) \
324  for(appsInfo *info = m_appsInfoStack.first(); \
325  info; info = m_appsInfoStack.next()) \
326  { \
327  KService::List *list = info->dictCategories.find(category); \
328  if (list) for(KService::List::ConstIterator it = list->begin(); \
329  it != list->end(); ++it) \
330  {
331 #define FOR_CATEGORY_END } }
332 
333 KService *
334 VFolderMenu::findApplication(const TQString &relPath)
335 {
336  for(appsInfo *info = m_appsInfoStack.first();
337  info; info = m_appsInfoStack.next())
338  {
339  KService *s = info->applications.find(relPath);
340  if (s)
341  return s;
342  }
343  return 0;
344 }
345 
346 void
347 VFolderMenu::addApplication(const TQString &id, KService *service)
348 {
349  service->setMenuId(id);
350  m_appsInfo->applications.replace(id, service);
351 }
352 
353 void
354 VFolderMenu::buildApplicationIndex(bool unusedOnly)
355 {
356  TQPtrList<appsInfo>::ConstIterator appsInfo_it = m_appsInfoList.begin();
357  for( ; appsInfo_it != m_appsInfoList.end(); ++appsInfo_it )
358  {
359  appsInfo *info = *appsInfo_it;
360  info->dictCategories.clear();
361  for(TQDictIterator<KService> it( info->applications );
362  it.current(); )
363  {
364  KService *s = it.current();
365  TQDictIterator<KService> tmpIt = it;
366  ++it;
367  if (unusedOnly && m_usedAppsDict.find(s->menuId()))
368  {
369  // Remove and skip this one
370  info->applications.remove(tmpIt.currentKey());
371  continue;
372  }
373 
374  TQStringList cats = s->categories();
375  for(TQStringList::ConstIterator it2 = cats.begin();
376  it2 != cats.end(); ++it2)
377  {
378  const TQString &cat = *it2;
379  KService::List *list = info->dictCategories.find(cat);
380  if (!list)
381  {
382  list = new KService::List();
383  info->dictCategories.insert(cat, list);
384  }
385  list->append(s);
386  }
387  }
388  }
389 }
390 
391 void
392 VFolderMenu::createAppsInfo()
393 {
394  if (m_appsInfo) return;
395 
396  m_appsInfo = new appsInfo;
397  m_appsInfoStack.prepend(m_appsInfo);
398  m_appsInfoList.append(m_appsInfo);
399  m_currentMenu->apps_info = m_appsInfo;
400 }
401 
402 void
403 VFolderMenu::loadAppsInfo()
404 {
405  m_appsInfo = m_currentMenu->apps_info;
406  if (!m_appsInfo)
407  return; // No appsInfo for this menu
408 
409  if (m_appsInfoStack.first() == m_appsInfo)
410  return; // Already added (By createAppsInfo?)
411 
412  m_appsInfoStack.prepend(m_appsInfo); // Add
413 }
414 
415 void
416 VFolderMenu::unloadAppsInfo()
417 {
418  m_appsInfo = m_currentMenu->apps_info;
419  if (!m_appsInfo)
420  return; // No appsInfo for this menu
421 
422  if (m_appsInfoStack.first() != m_appsInfo)
423  {
424  return; // Already removed (huh?)
425  }
426 
427  m_appsInfoStack.remove(m_appsInfo); // Remove
428  m_appsInfo = 0;
429 }
430 
431 TQString
432 VFolderMenu::absoluteDir(const TQString &_dir, const TQString &baseDir, bool keepRelativeToCfg)
433 {
434  TQString dir = _dir;
435  if (TQDir::isRelativePath(dir))
436  {
437  dir = baseDir + dir;
438  }
439  if (!dir.endsWith("/"))
440  dir += '/';
441 
442  if (TQDir::isRelativePath(dir) && !keepRelativeToCfg)
443  {
444  dir = TDEGlobal::dirs()->findResource("xdgconf-menu", dir);
445  }
446 
447  dir = TDEGlobal::dirs()->realPath(dir);
448 
449  return dir;
450 }
451 
452 static void tagBaseDir(TQDomDocument &doc, const TQString &tag, const TQString &dir)
453 {
454  TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
455  for(int i = 0; i < (int)mergeFileList.count(); i++)
456  {
457  TQDomAttr attr = doc.createAttribute("__BaseDir");
458  attr.setValue(dir);
459  mergeFileList.item(i).toElement().setAttributeNode(attr);
460  }
461 }
462 
463 static void tagBasePath(TQDomDocument &doc, const TQString &tag, const TQString &path)
464 {
465  TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
466  for(int i = 0; i < (int)mergeFileList.count(); i++)
467  {
468  TQDomAttr attr = doc.createAttribute("__BasePath");
469  attr.setValue(path);
470  mergeFileList.item(i).toElement().setAttributeNode(attr);
471  }
472 }
473 
474 TQDomDocument
475 VFolderMenu::loadDoc()
476 {
477  TQDomDocument doc;
478  if ( m_docInfo.path.isEmpty() )
479  {
480  return doc;
481  }
482  TQFile file( m_docInfo.path );
483  if ( !file.open( IO_ReadOnly ) )
484  {
485  kdWarning(7021) << "Could not open " << m_docInfo.path << endl;
486  return doc;
487  }
488  TQString errorMsg;
489  int errorRow;
490  int errorCol;
491  if ( !doc.setContent( &file, &errorMsg, &errorRow, &errorCol ) ) {
492  kdWarning(7021) << "Parse error in " << m_docInfo.path << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
493  file.close();
494  return doc;
495  }
496  file.close();
497 
498  tagBaseDir(doc, "MergeFile", m_docInfo.baseDir);
499  tagBasePath(doc, "MergeFile", m_docInfo.path);
500  tagBaseDir(doc, "MergeDir", m_docInfo.baseDir);
501  tagBaseDir(doc, "DirectoryDir", m_docInfo.baseDir);
502  tagBaseDir(doc, "AppDir", m_docInfo.baseDir);
503  tagBaseDir(doc, "LegacyDir", m_docInfo.baseDir);
504 
505  return doc;
506 }
507 
508 
509 void
510 VFolderMenu::mergeFile(TQDomElement &parent, const TQDomNode &mergeHere)
511 {
512 kdDebug(7021) << "VFolderMenu::mergeFile: " << m_docInfo.path << endl;
513  TQDomDocument doc = loadDoc();
514 
515  TQDomElement docElem = doc.documentElement();
516  TQDomNode n = docElem.firstChild();
517  TQDomNode last = mergeHere;
518  while( !n.isNull() )
519  {
520  TQDomElement e = n.toElement(); // try to convert the node to an element.
521  TQDomNode next = n.nextSibling();
522 
523  if (e.isNull())
524  {
525  // Skip
526  }
527  // The spec says we must ignore any Name nodes
528  else if (e.tagName() != "Name")
529  {
530  parent.insertAfter(n, last);
531  last = n;
532  }
533 
534  docElem.removeChild(n);
535  n = next;
536  }
537 }
538 
539 
540 void
541 VFolderMenu::mergeMenus(TQDomElement &docElem, TQString &name)
542 {
543  TQMap<TQString,TQDomElement> menuNodes;
544  TQMap<TQString,TQDomElement> directoryNodes;
545  TQMap<TQString,TQDomElement> appDirNodes;
546  TQMap<TQString,TQDomElement> directoryDirNodes;
547  TQMap<TQString,TQDomElement> legacyDirNodes;
548  TQDomElement defaultLayoutNode;
549  TQDomElement layoutNode;
550 
551  TQDomNode n = docElem.firstChild();
552  while( !n.isNull() ) {
553  TQDomElement e = n.toElement(); // try to convert the node to an element.
554  if( e.isNull() ) {
555 // kdDebug(7021) << "Empty node" << endl;
556  }
557  else if( e.tagName() == "DefaultAppDirs") {
558  // Replace with m_defaultAppDirs
559  replaceNode(docElem, n, m_defaultAppDirs, "AppDir");
560  continue;
561  }
562  else if( e.tagName() == "DefaultDirectoryDirs") {
563  // Replace with m_defaultDirectoryDirs
564  replaceNode(docElem, n, m_defaultDirectoryDirs, "DirectoryDir");
565  continue;
566  }
567  else if( e.tagName() == "DefaultMergeDirs") {
568  // Replace with m_defaultMergeDirs
569  replaceNode(docElem, n, m_defaultMergeDirs, "MergeDir");
570  continue;
571  }
572  else if( e.tagName() == "AppDir") {
573  // Filter out dupes
574  foldNode(docElem, e, appDirNodes);
575  }
576  else if( e.tagName() == "DirectoryDir") {
577  // Filter out dupes
578  foldNode(docElem, e, directoryDirNodes);
579  }
580  else if( e.tagName() == "LegacyDir") {
581  // Filter out dupes
582  foldNode(docElem, e, legacyDirNodes);
583  }
584  else if( e.tagName() == "Directory") {
585  // Filter out dupes
586  foldNode(docElem, e, directoryNodes);
587  }
588  else if( e.tagName() == "Move") {
589  // Filter out dupes
590  TQString orig;
591  TQDomNode n2 = e.firstChild();
592  while( !n2.isNull() ) {
593  TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
594  if( e2.tagName() == "Old")
595  {
596  orig = e2.text();
597  break;
598  }
599  n2 = n2.nextSibling();
600  }
601  foldNode(docElem, e, appDirNodes, orig);
602  }
603  else if( e.tagName() == "Menu") {
604  TQString name;
605  mergeMenus(e, name);
606  TQMap<TQString,TQDomElement>::iterator it = menuNodes.find(name);
607  if (it != menuNodes.end())
608  {
609  TQDomElement docElem2 = *it;
610  TQDomNode n2 = docElem2.firstChild();
611  TQDomNode first = e.firstChild();
612  while( !n2.isNull() ) {
613  TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
614  TQDomNode n3 = n2.nextSibling();
615  e.insertBefore(n2, first);
616  docElem2.removeChild(n2);
617  n2 = n3;
618  }
619  // We still have duplicated Name entries
620  // but we don't care about that
621 
622  docElem.removeChild(docElem2);
623  menuNodes.remove(it);
624  }
625  menuNodes.insert(name, e);
626  }
627  else if( e.tagName() == "MergeFile") {
628  if ((e.attribute("type") == "parent"))
629  pushDocInfoParent(e.attribute("__BasePath"), e.attribute("__BaseDir"));
630  else
631  pushDocInfo(e.text(), e.attribute("__BaseDir"));
632 
633  if (!m_docInfo.path.isEmpty())
634  mergeFile(docElem, n);
635  popDocInfo();
636 
637  TQDomNode last = n;
638  n = n.nextSibling();
639  docElem.removeChild(last); // Remove the MergeFile node
640  continue;
641  }
642  else if( e.tagName() == "MergeDir") {
643  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"), true);
644 
645  TQStringList dirs = TDEGlobal::dirs()->findDirs("xdgconf-menu", dir);
646  for(TQStringList::ConstIterator it=dirs.begin();
647  it != dirs.end(); ++it)
648  {
649  registerDirectory(*it);
650  }
651 
652  TQStringList fileList;
653  if (!TQDir::isRelativePath(dir))
654  {
655  // Absolute
656  fileList = TDEGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu", false, false);
657  }
658  else
659  {
660  // Relative
661  (void) TDEGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu", false, true, fileList);
662  }
663 
664  for(TQStringList::ConstIterator it=fileList.begin();
665  it != fileList.end(); ++it)
666  {
667  pushDocInfo(*it);
668  mergeFile(docElem, n);
669  popDocInfo();
670  }
671 
672  TQDomNode last = n;
673  n = n.nextSibling();
674  docElem.removeChild(last); // Remove the MergeDir node
675 
676  continue;
677  }
678  else if( e.tagName() == "Name") {
679  name = e.text();
680  }
681  else if( e.tagName() == "DefaultLayout") {
682  if (!defaultLayoutNode.isNull())
683  docElem.removeChild(defaultLayoutNode);
684  defaultLayoutNode = e;
685  }
686  else if( e.tagName() == "Layout") {
687  if (!layoutNode.isNull())
688  docElem.removeChild(layoutNode);
689  layoutNode = e;
690  }
691  n = n.nextSibling();
692  }
693 }
694 
695 void
696 VFolderMenu::pushDocInfo(const TQString &fileName, const TQString &baseDir)
697 {
698  m_docInfoStack.push(m_docInfo);
699  if (!baseDir.isEmpty())
700  {
701  if (!TQDir::isRelativePath(baseDir))
702  m_docInfo.baseDir = TDEGlobal::dirs()->relativeLocation("xdgconf-menu", baseDir);
703  else
704  m_docInfo.baseDir = baseDir;
705  }
706 
707  TQString baseName = fileName;
708  if (!TQDir::isRelativePath(baseName))
709  registerFile(baseName);
710  else
711  baseName = m_docInfo.baseDir + baseName;
712 
713  m_docInfo.path = locateMenuFile(fileName);
714  if (m_docInfo.path.isEmpty())
715  {
716  m_docInfo.baseDir = TQString::null;
717  m_docInfo.baseName = TQString::null;
718  kdDebug(7021) << "Menu " << fileName << " not found." << endl;
719  return;
720  }
721  int i;
722  i = baseName.findRev('/');
723  if (i > 0)
724  {
725  m_docInfo.baseDir = baseName.left(i+1);
726  m_docInfo.baseName = baseName.mid(i+1, baseName.length() - i - 6);
727  }
728  else
729  {
730  m_docInfo.baseDir = TQString::null;
731  m_docInfo.baseName = baseName.left( baseName.length() - 5 );
732  }
733 }
734 
735 void
736 VFolderMenu::pushDocInfoParent(const TQString &basePath, const TQString &baseDir)
737 {
738  m_docInfoStack.push(m_docInfo);
739 
740  m_docInfo.baseDir = baseDir;
741 
742  TQString fileName = basePath.mid(basePath.findRev('/')+1);
743  m_docInfo.baseName = fileName.left( fileName.length() - 5 );
744  TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
745 
746  TQStringList result = TDEGlobal::dirs()->findAllResources("xdgconf-menu", baseName);
747 
748  while( !result.isEmpty() && (result[0] != basePath))
749  result.remove(result.begin());
750 
751  if (result.count() <= 1)
752  {
753  m_docInfo.path = TQString::null; // No parent found
754  return;
755  }
756  m_docInfo.path = result[1];
757 }
758 
759 void
760 VFolderMenu::popDocInfo()
761 {
762  m_docInfo = m_docInfoStack.pop();
763 }
764 
765 TQString
766 VFolderMenu::locateMenuFile(const TQString &fileName)
767 {
768  if (!TQDir::isRelativePath(fileName))
769  {
770  if (TDEStandardDirs::exists(fileName))
771  return fileName;
772  return TQString::null;
773  }
774 
775  TQString result;
776 
777  //TQString xdgMenuPrefix = TQString::fromLocal8Bit(getenv("XDG_MENU_PREFIX"));
778  // hardcode xdgMenuPrefix to "kde-" string until proper upstream fix
779  TQString xdgMenuPrefix = "kde-";
780  if (!xdgMenuPrefix.isEmpty())
781  {
782  TQFileInfo fileInfo(fileName);
783 
784  TQString fileNameOnly = fileInfo.fileName();
785  if (!fileNameOnly.startsWith(xdgMenuPrefix))
786  fileNameOnly = xdgMenuPrefix + fileNameOnly;
787 
788  TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir +
789  fileInfo.dirPath() + "/" +
790  fileNameOnly);
791  result = locate("xdgconf-menu", baseName);
792  }
793 
794  if (result.isEmpty())
795  {
796  TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
797  result = locate("xdgconf-menu", baseName);
798  }
799 
800  return result;
801 }
802 
803 TQString
804 VFolderMenu::locateDirectoryFile(const TQString &fileName)
805 {
806  if (fileName.isEmpty())
807  return TQString::null;
808 
809  if (!TQDir::isRelativePath(fileName))
810  {
811  if (TDEStandardDirs::exists(fileName))
812  return fileName;
813  return TQString::null;
814  }
815 
816  // First location in the list wins
817  TQString tmp;
818  for(TQStringList::ConstIterator it = m_directoryDirs.begin();
819  it != m_directoryDirs.end();
820  ++it)
821  {
822  tmp = (*it)+fileName;
823  if (TDEStandardDirs::exists(tmp))
824  return tmp;
825  }
826 
827  return TQString::null;
828 }
829 
830 void
831 VFolderMenu::initDirs()
832 {
833  m_defaultDataDirs = TQStringList::split(':', TDEGlobal::dirs()->kfsstnd_prefixes());
834  TQString localDir = m_defaultDataDirs.first();
835  m_defaultDataDirs.remove(localDir); // Remove local dir
836 
837  m_defaultAppDirs = TDEGlobal::dirs()->findDirs("xdgdata-apps", TQString::null);
838  m_defaultDirectoryDirs = TDEGlobal::dirs()->findDirs("xdgdata-dirs", TQString::null);
839  m_defaultLegacyDirs = TDEGlobal::dirs()->resourceDirs("apps");
840 }
841 
842 void
843 VFolderMenu::loadMenu(const TQString &fileName)
844 {
845  m_defaultMergeDirs.clear();
846 
847  if (!fileName.endsWith(".menu"))
848  return;
849 
850  pushDocInfo(fileName);
851  m_defaultMergeDirs << m_docInfo.baseName+"-merged/";
852  m_doc = loadDoc();
853  popDocInfo();
854 
855  if (m_doc.isNull())
856  {
857  if (m_docInfo.path.isEmpty())
858  kdError(7021) << fileName << " not found in " << m_allDirectories << endl;
859  else
860  kdWarning(7021) << "Load error (" << m_docInfo.path << ")" << endl;
861  return;
862  }
863 
864  TQDomElement e = m_doc.documentElement();
865  TQString name;
866  mergeMenus(e, name);
867 }
868 
869 void
870 VFolderMenu::processCondition(TQDomElement &domElem, TQDict<KService> *items)
871 {
872  if (domElem.tagName() == "And")
873  {
874  TQDomNode n = domElem.firstChild();
875  // Look for the first child element
876  while (!n.isNull()) // loop in case of comments
877  {
878  TQDomElement e = n.toElement();
879  n = n.nextSibling();
880  if ( !e.isNull() ) {
881  processCondition(e, items);
882  break; // we only want the first one
883  }
884  }
885 
886  TQDict<KService> andItems;
887  while( !n.isNull() ) {
888  TQDomElement e = n.toElement();
889  if (e.tagName() == "Not")
890  {
891  // Special handling for "and not"
892  TQDomNode n2 = e.firstChild();
893  while( !n2.isNull() ) {
894  TQDomElement e2 = n2.toElement();
895  andItems.clear();
896  processCondition(e2, &andItems);
897  excludeItems(items, &andItems);
898  n2 = n2.nextSibling();
899  }
900  }
901  else
902  {
903  andItems.clear();
904  processCondition(e, &andItems);
905  matchItems(items, &andItems);
906  }
907  n = n.nextSibling();
908  }
909  }
910  else if (domElem.tagName() == "Or")
911  {
912  TQDomNode n = domElem.firstChild();
913  // Look for the first child element
914  while (!n.isNull()) // loop in case of comments
915  {
916  TQDomElement e = n.toElement();
917  n = n.nextSibling();
918  if ( !e.isNull() ) {
919  processCondition(e, items);
920  break; // we only want the first one
921  }
922  }
923 
924  TQDict<KService> orItems;
925  while( !n.isNull() ) {
926  TQDomElement e = n.toElement();
927  if ( !e.isNull() ) {
928  orItems.clear();
929  processCondition(e, &orItems);
930  includeItems(items, &orItems);
931  }
932  n = n.nextSibling();
933  }
934  }
935  else if (domElem.tagName() == "Not")
936  {
937  FOR_ALL_APPLICATIONS(it)
938  {
939  KService *s = it.current();
940  items->replace(s->menuId(), s);
941  }
942  FOR_ALL_APPLICATIONS_END
943 
944  TQDict<KService> notItems;
945  TQDomNode n = domElem.firstChild();
946  while( !n.isNull() ) {
947  TQDomElement e = n.toElement();
948  if ( !e.isNull() ) {
949  notItems.clear();
950  processCondition(e, &notItems);
951  excludeItems(items, &notItems);
952  }
953  n = n.nextSibling();
954  }
955  }
956  else if (domElem.tagName() == "Category")
957  {
958  FOR_CATEGORY(domElem.text(), it)
959  {
960  KService *s = *it;
961  items->replace(s->menuId(), s);
962  }
963  FOR_CATEGORY_END
964  }
965  else if (domElem.tagName() == "All")
966  {
967  FOR_ALL_APPLICATIONS(it)
968  {
969  KService *s = it.current();
970  items->replace(s->menuId(), s);
971  }
972  FOR_ALL_APPLICATIONS_END
973  }
974  else if (domElem.tagName() == "Filename")
975  {
976  TQString filename = domElem.text();
977 kdDebug(7021) << "Adding file " << filename << endl;
978  KService *s = findApplication(filename);
979  if (s)
980  items->replace(filename, s);
981  }
982 }
983 
984 void
985 VFolderMenu::loadApplications(const TQString &dir, const TQString &prefix)
986 {
987  kdDebug(7021) << "Looking up applications under " << dir << endl;
988 
989  // We look for a set of files.
990  DIR *dp = opendir( TQFile::encodeName(dir));
991  if (!dp)
992  return;
993 
994  struct dirent *ep;
995  KDE_struct_stat buff;
996 
997  TQString _dot(".");
998  TQString _dotdot("..");
999 
1000  while( ( ep = readdir( dp ) ) != 0L )
1001  {
1002  TQString fn( TQFile::decodeName(ep->d_name));
1003  if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() == '~')
1004  continue;
1005 
1006  TQString pathfn = dir + fn;
1007  if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1008  continue; // Couldn't stat (e.g. no read permissions)
1009  }
1010  if ( S_ISDIR( buff.st_mode )) {
1011  loadApplications(pathfn + '/', prefix + fn + '-');
1012  continue;
1013  }
1014 
1015  if ( S_ISREG( buff.st_mode))
1016  {
1017  if (!fn.endsWith(".desktop"))
1018  continue;
1019 
1020  KService *service = 0;
1021  emit newService(pathfn, &service);
1022  if (service)
1023  addApplication(prefix+fn, service);
1024  }
1025  }
1026  closedir( dp );
1027 }
1028 
1029 void
1030 VFolderMenu::processKDELegacyDirs()
1031 {
1032 kdDebug(7021) << "processKDELegacyDirs()" << endl;
1033 
1034  TQDict<KService> items;
1035  TQString prefix = "kde-";
1036 
1037  TQStringList relFiles;
1038  TQRegExp files("\\.(desktop|kdelnk)$");
1039  TQRegExp dirs("\\.directory$");
1040 
1041  (void) TDEGlobal::dirs()->findAllResources( "apps",
1042  TQString::null,
1043  true, // Recursive!
1044  true, // uniq
1045  relFiles);
1046  for(TQStringList::ConstIterator it = relFiles.begin();
1047  it != relFiles.end(); ++it)
1048  {
1049  if (!m_forcedLegacyLoad && (dirs.search(*it) != -1))
1050  {
1051  TQString name = *it;
1052  if (!name.endsWith("/.directory"))
1053  continue; // Probably ".directory", skip it.
1054 
1055  name = name.left(name.length()-11);
1056 
1057  SubMenu *newMenu = new SubMenu;
1058  newMenu->directoryFile = locate("apps", *it);
1059 
1060  insertSubMenu(m_currentMenu, name, newMenu);
1061  continue;
1062  }
1063 
1064  if (files.search(*it) != -1)
1065  {
1066  TQString name = *it;
1067  KService *service = 0;
1068  emit newService(name, &service);
1069 
1070  if (service && !m_forcedLegacyLoad)
1071  {
1072  TQString id = name;
1073  // Strip path from id
1074  int i = id.findRev('/');
1075  if (i >= 0)
1076  id = id.mid(i+1);
1077 
1078  id.prepend(prefix);
1079 
1080  // TODO: add Legacy category
1081  addApplication(id, service);
1082  items.replace(service->menuId(), service);
1083  if (service->categories().isEmpty())
1084  insertService(m_currentMenu, name, service);
1085 
1086  }
1087  }
1088  }
1089  markUsedApplications(&items);
1090  m_legacyLoaded = true;
1091 }
1092 
1093 void
1094 VFolderMenu::processLegacyDir(const TQString &dir, const TQString &relDir, const TQString &prefix)
1095 {
1096 kdDebug(7021) << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")" << endl;
1097 
1098  TQDict<KService> items;
1099  // We look for a set of files.
1100  DIR *dp = opendir( TQFile::encodeName(dir));
1101  if (!dp)
1102  return;
1103 
1104  struct dirent *ep;
1105  KDE_struct_stat buff;
1106 
1107  TQString _dot(".");
1108  TQString _dotdot("..");
1109 
1110  while( ( ep = readdir( dp ) ) != 0L )
1111  {
1112  TQString fn( TQFile::decodeName(ep->d_name));
1113  if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() == '~')
1114  continue;
1115 
1116  TQString pathfn = dir + fn;
1117  if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1118  continue; // Couldn't stat (e.g. no read permissions)
1119  }
1120  if ( S_ISDIR( buff.st_mode )) {
1121  SubMenu *parentMenu = m_currentMenu;
1122 
1123  m_currentMenu = new SubMenu;
1124  m_currentMenu->name = fn;
1125  m_currentMenu->directoryFile = dir + fn + "/.directory";
1126 
1127  parentMenu->subMenus.append(m_currentMenu);
1128 
1129  processLegacyDir(pathfn + '/', relDir+fn+'/', prefix);
1130  m_currentMenu = parentMenu;
1131  continue;
1132  }
1133 
1134  if ( S_ISREG( buff.st_mode))
1135  {
1136  if (!fn.endsWith(".desktop"))
1137  continue;
1138 
1139  KService *service = 0;
1140  emit newService(pathfn, &service);
1141  if (service)
1142  {
1143  TQString id = prefix+fn;
1144 
1145  // TODO: Add legacy category
1146  addApplication(id, service);
1147  items.replace(service->menuId(), service);
1148 
1149  if (service->categories().isEmpty())
1150  m_currentMenu->items.replace(id, service);
1151  }
1152  }
1153  }
1154  closedir( dp );
1155  markUsedApplications(&items);
1156 }
1157 
1158 
1159 
1160 void
1161 VFolderMenu::processMenu(TQDomElement &docElem, int pass)
1162 {
1163  SubMenu *parentMenu = m_currentMenu;
1164  unsigned int oldDirectoryDirsCount = m_directoryDirs.count();
1165 
1166  TQString name;
1167  TQString directoryFile;
1168  bool onlyUnallocated = false;
1169  bool isDeleted = false;
1170  bool kdeLegacyDirsDone = false;
1171  TQDomElement defaultLayoutNode;
1172  TQDomElement layoutNode;
1173 
1174  TQDomElement query;
1175  TQDomNode n = docElem.firstChild();
1176  while( !n.isNull() ) {
1177  TQDomElement e = n.toElement(); // try to convert the node to an element.
1178  if (e.tagName() == "Name")
1179  {
1180  name = e.text();
1181  }
1182  else if (e.tagName() == "Directory")
1183  {
1184  directoryFile = e.text();
1185  }
1186  else if (e.tagName() == "DirectoryDir")
1187  {
1188  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1189 
1190  m_directoryDirs.prepend(dir);
1191  }
1192  else if (e.tagName() == "OnlyUnallocated")
1193  {
1194  onlyUnallocated = true;
1195  }
1196  else if (e.tagName() == "NotOnlyUnallocated")
1197  {
1198  onlyUnallocated = false;
1199  }
1200  else if (e.tagName() == "Deleted")
1201  {
1202  isDeleted = true;
1203  }
1204  else if (e.tagName() == "NotDeleted")
1205  {
1206  isDeleted = false;
1207  }
1208  else if (e.tagName() == "DefaultLayout")
1209  {
1210  defaultLayoutNode = e;
1211  }
1212  else if (e.tagName() == "Layout")
1213  {
1214  layoutNode = e;
1215  }
1216  n = n.nextSibling();
1217  }
1218 
1219  // Setup current menu entry
1220  if (pass == 0)
1221  {
1222  m_currentMenu = 0;
1223  // Look up menu
1224  if (parentMenu)
1225  {
1226  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1227  {
1228  if (menu->name == name)
1229  {
1230  m_currentMenu = menu;
1231  break;
1232  }
1233  }
1234  }
1235 
1236  if (!m_currentMenu) // Not found?
1237  {
1238  // Create menu
1239  m_currentMenu = new SubMenu;
1240  m_currentMenu->name = name;
1241 
1242  if (parentMenu)
1243  parentMenu->subMenus.append(m_currentMenu);
1244  else
1245  m_rootMenu = m_currentMenu;
1246  }
1247  if (directoryFile.isEmpty())
1248  {
1249  kdDebug(7021) << "Menu " << name << " does not specify a directory file." << endl;
1250  }
1251 
1252  // Override previous directoryFile iff available
1253  TQString tmp = locateDirectoryFile(directoryFile);
1254  if (! tmp.isEmpty())
1255  m_currentMenu->directoryFile = tmp;
1256  m_currentMenu->isDeleted = isDeleted;
1257 
1258  m_currentMenu->defaultLayoutNode = defaultLayoutNode;
1259  m_currentMenu->layoutNode = layoutNode;
1260  }
1261  else
1262  {
1263  // Look up menu
1264  if (parentMenu)
1265  {
1266  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1267  {
1268  if (menu->name == name)
1269  {
1270  m_currentMenu = menu;
1271  break;
1272  }
1273  }
1274  }
1275  else
1276  {
1277  m_currentMenu = m_rootMenu;
1278  }
1279  }
1280 
1281  // Process AppDir and LegacyDir
1282  if (pass == 0)
1283  {
1284  TQDomElement query;
1285  TQDomNode n = docElem.firstChild();
1286  while( !n.isNull() ) {
1287  TQDomElement e = n.toElement(); // try to convert the node to an element.
1288  if (e.tagName() == "AppDir")
1289  {
1290  createAppsInfo();
1291  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1292 
1293  registerDirectory(dir);
1294 
1295  loadApplications(dir, TQString::null);
1296  }
1297  else if (e.tagName() == "KDELegacyDirs")
1298  {
1299  createAppsInfo();
1300  if (!kdeLegacyDirsDone)
1301  {
1302 kdDebug(7021) << "Processing KDE Legacy dirs for <KDE>" << endl;
1303  SubMenu *oldMenu = m_currentMenu;
1304  m_currentMenu = new SubMenu;
1305 
1306  processKDELegacyDirs();
1307 
1308  m_legacyNodes.replace("<KDE>", m_currentMenu);
1309  m_currentMenu = oldMenu;
1310 
1311  kdeLegacyDirsDone = true;
1312  }
1313  }
1314  else if (e.tagName() == "LegacyDir")
1315  {
1316  createAppsInfo();
1317  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1318 
1319  TQString prefix = e.attributes().namedItem("prefix").toAttr().value();
1320 
1321  if (m_defaultLegacyDirs.contains(dir))
1322  {
1323  if (!kdeLegacyDirsDone)
1324  {
1325 kdDebug(7021) << "Processing KDE Legacy dirs for " << dir << endl;
1326  SubMenu *oldMenu = m_currentMenu;
1327  m_currentMenu = new SubMenu;
1328 
1329  processKDELegacyDirs();
1330 
1331  m_legacyNodes.replace("<KDE>", m_currentMenu);
1332  m_currentMenu = oldMenu;
1333 
1334  kdeLegacyDirsDone = true;
1335  }
1336  }
1337  else
1338  {
1339  SubMenu *oldMenu = m_currentMenu;
1340  m_currentMenu = new SubMenu;
1341 
1342  registerDirectory(dir);
1343 
1344  processLegacyDir(dir, TQString::null, prefix);
1345 
1346  m_legacyNodes.replace(dir, m_currentMenu);
1347  m_currentMenu = oldMenu;
1348  }
1349  }
1350  n = n.nextSibling();
1351  }
1352  }
1353 
1354  loadAppsInfo(); // Update the scope wrt the list of applications
1355 
1356  if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
1357  {
1358  n = docElem.firstChild();
1359 
1360  while( !n.isNull() ) {
1361  TQDomElement e = n.toElement(); // try to convert the node to an element.
1362  if (e.tagName() == "Include")
1363  {
1364  TQDict<KService> items;
1365 
1366  TQDomNode n2 = e.firstChild();
1367  while( !n2.isNull() ) {
1368  TQDomElement e2 = n2.toElement();
1369  items.clear();
1370  processCondition(e2, &items);
1371  if (m_track)
1372  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "Before <Include>");
1373  includeItems(&(m_currentMenu->items), &items);
1374  excludeItems(&(m_currentMenu->excludeItems), &items);
1375  markUsedApplications(&items);
1376 
1377  if (m_track)
1378  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "After <Include>");
1379 
1380  n2 = n2.nextSibling();
1381  }
1382  }
1383 
1384  else if (e.tagName() == "Exclude")
1385  {
1386  TQDict<KService> items;
1387 
1388  TQDomNode n2 = e.firstChild();
1389  while( !n2.isNull() ) {
1390  TQDomElement e2 = n2.toElement();
1391  items.clear();
1392  processCondition(e2, &items);
1393  if (m_track)
1394  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "Before <Exclude>");
1395  excludeItems(&(m_currentMenu->items), &items);
1396  includeItems(&(m_currentMenu->excludeItems), &items);
1397  if (m_track)
1398  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "After <Exclude>");
1399  n2 = n2.nextSibling();
1400  }
1401  }
1402 
1403  n = n.nextSibling();
1404  }
1405  }
1406 
1407  n = docElem.firstChild();
1408  while( !n.isNull() ) {
1409  TQDomElement e = n.toElement(); // try to convert the node to an element.
1410  if (e.tagName() == "Menu")
1411  {
1412  processMenu(e, pass);
1413  }
1414 // We insert legacy dir in pass 0, this way the order in the .menu-file determines
1415 // which .directory file gets used, but the menu-entries of legacy-menus will always
1416 // have the lowest priority.
1417 // else if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
1418  else if (pass == 0)
1419  {
1420  if (e.tagName() == "LegacyDir")
1421  {
1422  // Add legacy nodes to Menu structure
1423  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1424  SubMenu *legacyMenu = m_legacyNodes.find(dir);
1425  if (legacyMenu)
1426  {
1427  mergeMenu(m_currentMenu, legacyMenu);
1428  }
1429  }
1430 
1431  else if (e.tagName() == "KDELegacyDirs")
1432  {
1433  // Add legacy nodes to Menu structure
1434  TQString dir = "<KDE>";
1435  SubMenu *legacyMenu = m_legacyNodes.find(dir);
1436  if (legacyMenu)
1437  {
1438  mergeMenu(m_currentMenu, legacyMenu);
1439  }
1440  }
1441  }
1442  n = n.nextSibling();
1443  }
1444 
1445  if (pass == 2)
1446  {
1447  n = docElem.firstChild();
1448  while( !n.isNull() ) {
1449  TQDomElement e = n.toElement(); // try to convert the node to an element.
1450  if (e.tagName() == "Move")
1451  {
1452  TQString orig;
1453  TQString dest;
1454  TQDomNode n2 = e.firstChild();
1455  while( !n2.isNull() ) {
1456  TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
1457  if( e2.tagName() == "Old")
1458  orig = e2.text();
1459  if( e2.tagName() == "New")
1460  dest = e2.text();
1461  n2 = n2.nextSibling();
1462  }
1463  kdDebug(7021) << "Moving " << orig << " to " << dest << endl;
1464  if (!orig.isEmpty() && !dest.isEmpty())
1465  {
1466  SubMenu *menu = takeSubMenu(m_currentMenu, orig);
1467  if (menu)
1468  {
1469  insertSubMenu(m_currentMenu, dest, menu, true); // Destination has priority
1470  }
1471  }
1472  }
1473  n = n.nextSibling();
1474  }
1475 
1476  }
1477 
1478  unloadAppsInfo(); // Update the scope wrt the list of applications
1479 
1480  while (m_directoryDirs.count() > oldDirectoryDirsCount)
1481  m_directoryDirs.pop_front();
1482 
1483  m_currentMenu = parentMenu;
1484 }
1485 
1486 
1487 
1488 static TQString parseAttribute( const TQDomElement &e)
1489 {
1490  TQString option;
1491  if ( e.hasAttribute( "show_empty" ) )
1492  {
1493  TQString str = e.attribute( "show_empty" );
1494  if ( str=="true" )
1495  option= "ME ";
1496  else if ( str=="false" )
1497  option= "NME ";
1498  else
1499  kdDebug()<<" Error in parsing show_empty attribute :"<<str<<endl;
1500  }
1501  if ( e.hasAttribute( "inline" ) )
1502  {
1503  TQString str = e.attribute( "inline" );
1504  if ( str=="true" )
1505  option+="I ";
1506  else if ( str=="false" )
1507  option+="NI ";
1508  else
1509  kdDebug()<<" Error in parsing inlibe attribute :"<<str<<endl;
1510  }
1511  if ( e.hasAttribute( "inline_limit" ) )
1512  {
1513  bool ok;
1514  int value = e.attribute( "inline_limit" ).toInt(&ok);
1515  if ( ok )
1516  option+=TQString( "IL[%1] " ).arg( value );
1517  }
1518  if ( e.hasAttribute( "inline_header" ) )
1519  {
1520  TQString str = e.attribute( "inline_header" );
1521  if ( str=="true")
1522  option+="IH ";
1523  else if ( str == "false" )
1524  option+="NIH ";
1525  else
1526  kdDebug()<<" Error in parsing of inline_header attribute :"<<str<<endl;
1527 
1528  }
1529  if ( e.hasAttribute( "inline_alias" ) && e.attribute( "inline_alias" )=="true")
1530  {
1531  TQString str = e.attribute( "inline_alias" );
1532  if ( str=="true" )
1533  option+="IA";
1534  else if ( str=="false" )
1535  option+="NIA";
1536  else
1537  kdDebug()<<" Error in parsing inline_alias attribute :"<<str<<endl;
1538  }
1539  if( !option.isEmpty())
1540  {
1541  option = option.prepend(":O");
1542  }
1543  return option;
1544 
1545 }
1546 
1547 static TQStringList parseLayoutNode(const TQDomElement &docElem)
1548 {
1549  TQStringList layout;
1550 
1551  TQString optionDefaultLayout;
1552  if( docElem.tagName()=="DefaultLayout")
1553  optionDefaultLayout = parseAttribute( docElem);
1554  if ( !optionDefaultLayout.isEmpty() )
1555  layout.append( optionDefaultLayout );
1556 
1557  TQDomNode n = docElem.firstChild();
1558  while( !n.isNull() ) {
1559  TQDomElement e = n.toElement(); // try to convert the node to an element.
1560  if (e.tagName() == "Separator")
1561  {
1562  layout.append(":S");
1563  }
1564  else if (e.tagName() == "Filename")
1565  {
1566  layout.append(e.text());
1567  }
1568  else if (e.tagName() == "Menuname")
1569  {
1570  layout.append("/"+e.text());
1571  TQString option = parseAttribute( e );
1572  if( !option.isEmpty())
1573  layout.append( option );
1574  }
1575  else if (e.tagName() == "Merge")
1576  {
1577  TQString type = e.attributeNode("type").value();
1578  if (type == "files")
1579  layout.append(":F");
1580  else if (type == "menus")
1581  layout.append(":M");
1582  else if (type == "all")
1583  layout.append(":A");
1584  }
1585 
1586  n = n.nextSibling();
1587  }
1588  return layout;
1589 }
1590 
1591 void
1592 VFolderMenu::layoutMenu(VFolderMenu::SubMenu *menu, TQStringList defaultLayout)
1593 {
1594  if (!menu->defaultLayoutNode.isNull())
1595  {
1596  defaultLayout = parseLayoutNode(menu->defaultLayoutNode);
1597  }
1598 
1599  if (menu->layoutNode.isNull())
1600  {
1601  menu->layoutList = defaultLayout;
1602  }
1603  else
1604  {
1605  menu->layoutList = parseLayoutNode(menu->layoutNode);
1606  if (menu->layoutList.isEmpty())
1607  menu->layoutList = defaultLayout;
1608  }
1609 
1610  for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
1611  {
1612  layoutMenu(subMenu, defaultLayout);
1613  }
1614 }
1615 
1616 void
1617 VFolderMenu::markUsedApplications(TQDict<KService> *items)
1618 {
1619  for(TQDictIterator<KService> it(*items); it.current(); ++it)
1620  {
1621  m_usedAppsDict.replace(it.current()->menuId(), it.current());
1622  }
1623 }
1624 
1625 VFolderMenu::SubMenu *
1626 VFolderMenu::parseMenu(const TQString &file, bool forceLegacyLoad)
1627 {
1628  m_forcedLegacyLoad = false;
1629  m_legacyLoaded = false;
1630  m_appsInfo = 0;
1631 
1632  TQStringList dirs = TDEGlobal::dirs()->resourceDirs("xdgconf-menu");
1633  for(TQStringList::ConstIterator it=dirs.begin();
1634  it != dirs.end(); ++it)
1635  {
1636  registerDirectory(*it);
1637  }
1638 
1639  loadMenu(file);
1640 
1641  delete m_rootMenu;
1642  m_rootMenu = m_currentMenu = 0;
1643 
1644  TQDomElement docElem = m_doc.documentElement();
1645 
1646  for (int pass = 0; pass <= 2; pass++)
1647  {
1648  processMenu(docElem, pass);
1649 
1650  if (pass == 0)
1651  {
1652  buildApplicationIndex(false);
1653  }
1654  if (pass == 1)
1655  {
1656  buildApplicationIndex(true);
1657  }
1658  if (pass == 2)
1659  {
1660  TQStringList defaultLayout;
1661  defaultLayout << ":M"; // Sub-Menus
1662  defaultLayout << ":F"; // Individual entries
1663  layoutMenu(m_rootMenu, defaultLayout);
1664  }
1665  }
1666 
1667  if (!m_legacyLoaded && forceLegacyLoad)
1668  {
1669  m_forcedLegacyLoad = true;
1670  processKDELegacyDirs();
1671  }
1672 
1673  return m_rootMenu;
1674 }
1675 
1676 void
1677 VFolderMenu::setTrackId(const TQString &id)
1678 {
1679  m_track = !id.isEmpty();
1680  m_trackId = id;
1681 }
1682 
1683 #include "vfolder_menu.moc"

kded

Skip menu "kded"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kded

Skip menu "kded"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kded by doxygen 1.8.11
This website is maintained by Timothy Pearson.