• 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 KService *
315 VFolderMenu::findApplication(const TQString &relPath)
316 {
317  for(appsInfo *info = m_appsInfoStack.first();
318  info; info = m_appsInfoStack.next())
319  {
320  KService *s = info->applications.find(relPath);
321  if (s)
322  return s;
323  }
324  return 0;
325 }
326 
327 void
328 VFolderMenu::addApplication(const TQString &id, KService *service)
329 {
330  service->setMenuId(id);
331  m_appsInfo->applications.replace(id, service);
332 }
333 
334 void
335 VFolderMenu::buildApplicationIndex(bool unusedOnly)
336 {
337  TQPtrList<appsInfo>::ConstIterator appsInfo_it = m_appsInfoList.begin();
338  for( ; appsInfo_it != m_appsInfoList.end(); ++appsInfo_it )
339  {
340  appsInfo *info = *appsInfo_it;
341  info->dictCategories.clear();
342  for(TQDictIterator<KService> it( info->applications );
343  it.current(); )
344  {
345  KService *s = it.current();
346  TQDictIterator<KService> tmpIt = it;
347  ++it;
348  if (unusedOnly && m_usedAppsDict.find(s->menuId()))
349  {
350  // Remove and skip this one
351  info->applications.remove(tmpIt.currentKey());
352  continue;
353  }
354 
355  TQStringList cats = s->categories();
356  for(TQStringList::ConstIterator it2 = cats.begin();
357  it2 != cats.end(); ++it2)
358  {
359  const TQString &cat = *it2;
360  KService::List *list = info->dictCategories.find(cat);
361  if (!list)
362  {
363  list = new KService::List();
364  info->dictCategories.insert(cat, list);
365  }
366  list->append(s);
367  }
368  }
369  }
370 }
371 
372 void
373 VFolderMenu::createAppsInfo()
374 {
375  if (m_appsInfo) return;
376 
377  m_appsInfo = new appsInfo;
378  m_appsInfoStack.prepend(m_appsInfo);
379  m_appsInfoList.append(m_appsInfo);
380  m_currentMenu->apps_info = m_appsInfo;
381 }
382 
383 void
384 VFolderMenu::loadAppsInfo()
385 {
386  m_appsInfo = m_currentMenu->apps_info;
387  if (!m_appsInfo)
388  return; // No appsInfo for this menu
389 
390  if (m_appsInfoStack.first() == m_appsInfo)
391  return; // Already added (By createAppsInfo?)
392 
393  m_appsInfoStack.prepend(m_appsInfo); // Add
394 }
395 
396 void
397 VFolderMenu::unloadAppsInfo()
398 {
399  m_appsInfo = m_currentMenu->apps_info;
400  if (!m_appsInfo)
401  return; // No appsInfo for this menu
402 
403  if (m_appsInfoStack.first() != m_appsInfo)
404  {
405  return; // Already removed (huh?)
406  }
407 
408  m_appsInfoStack.remove(m_appsInfo); // Remove
409  m_appsInfo = 0;
410 }
411 
412 TQString
413 VFolderMenu::absoluteDir(const TQString &_dir, const TQString &baseDir, bool keepRelativeToCfg)
414 {
415  TQString dir = _dir;
416  if (TQDir::isRelativePath(dir))
417  {
418  dir = baseDir + dir;
419  }
420  if (!dir.endsWith("/"))
421  dir += '/';
422 
423  if (TQDir::isRelativePath(dir) && !keepRelativeToCfg)
424  {
425  dir = TDEGlobal::dirs()->findResource("xdgconf-menu", dir);
426  }
427 
428  dir = TDEGlobal::dirs()->realPath(dir);
429 
430  return dir;
431 }
432 
433 static void tagBaseDir(TQDomDocument &doc, const TQString &tag, const TQString &dir)
434 {
435  TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
436  for(int i = 0; i < (int)mergeFileList.count(); i++)
437  {
438  TQDomAttr attr = doc.createAttribute("__BaseDir");
439  attr.setValue(dir);
440  mergeFileList.item(i).toElement().setAttributeNode(attr);
441  }
442 }
443 
444 static void tagBasePath(TQDomDocument &doc, const TQString &tag, const TQString &path)
445 {
446  TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
447  for(int i = 0; i < (int)mergeFileList.count(); i++)
448  {
449  TQDomAttr attr = doc.createAttribute("__BasePath");
450  attr.setValue(path);
451  mergeFileList.item(i).toElement().setAttributeNode(attr);
452  }
453 }
454 
455 TQDomDocument
456 VFolderMenu::loadDoc()
457 {
458  TQDomDocument doc;
459  if ( m_docInfo.path.isEmpty() )
460  {
461  return doc;
462  }
463  TQFile file( m_docInfo.path );
464  if ( !file.open( IO_ReadOnly ) )
465  {
466  kdWarning(7021) << "Could not open " << m_docInfo.path << endl;
467  return doc;
468  }
469  TQString errorMsg;
470  int errorRow;
471  int errorCol;
472  if ( !doc.setContent( &file, &errorMsg, &errorRow, &errorCol ) ) {
473  kdWarning(7021) << "Parse error in " << m_docInfo.path << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
474  file.close();
475  return doc;
476  }
477  file.close();
478 
479  tagBaseDir(doc, "MergeFile", m_docInfo.baseDir);
480  tagBasePath(doc, "MergeFile", m_docInfo.path);
481  tagBaseDir(doc, "MergeDir", m_docInfo.baseDir);
482  tagBaseDir(doc, "DirectoryDir", m_docInfo.baseDir);
483  tagBaseDir(doc, "AppDir", m_docInfo.baseDir);
484  tagBaseDir(doc, "LegacyDir", m_docInfo.baseDir);
485 
486  return doc;
487 }
488 
489 
490 void
491 VFolderMenu::mergeFile(TQDomElement &parent, const TQDomNode &mergeHere)
492 {
493 kdDebug(7021) << "VFolderMenu::mergeFile: " << m_docInfo.path << endl;
494  TQDomDocument doc = loadDoc();
495 
496  TQDomElement docElem = doc.documentElement();
497  TQDomNode n = docElem.firstChild();
498  TQDomNode last = mergeHere;
499  while( !n.isNull() )
500  {
501  TQDomElement e = n.toElement(); // try to convert the node to an element.
502  TQDomNode next = n.nextSibling();
503 
504  if (e.isNull())
505  {
506  // Skip
507  }
508  // The spec says we must ignore any Name nodes
509  else if (e.tagName() != "Name")
510  {
511  parent.insertAfter(n, last);
512  last = n;
513  }
514 
515  docElem.removeChild(n);
516  n = next;
517  }
518 }
519 
520 
521 void
522 VFolderMenu::mergeMenus(TQDomElement &docElem, TQString &name)
523 {
524  TQMap<TQString,TQDomElement> menuNodes;
525  TQMap<TQString,TQDomElement> directoryNodes;
526  TQMap<TQString,TQDomElement> appDirNodes;
527  TQMap<TQString,TQDomElement> directoryDirNodes;
528  TQMap<TQString,TQDomElement> legacyDirNodes;
529  TQDomElement defaultLayoutNode;
530  TQDomElement layoutNode;
531 
532  TQDomNode n = docElem.firstChild();
533  while( !n.isNull() ) {
534  TQDomElement e = n.toElement(); // try to convert the node to an element.
535  if( e.isNull() ) {
536 // kdDebug(7021) << "Empty node" << endl;
537  }
538  else if( e.tagName() == "DefaultAppDirs") {
539  // Replace with m_defaultAppDirs
540  replaceNode(docElem, n, m_defaultAppDirs, "AppDir");
541  continue;
542  }
543  else if( e.tagName() == "DefaultDirectoryDirs") {
544  // Replace with m_defaultDirectoryDirs
545  replaceNode(docElem, n, m_defaultDirectoryDirs, "DirectoryDir");
546  continue;
547  }
548  else if( e.tagName() == "DefaultMergeDirs") {
549  // Replace with m_defaultMergeDirs
550  replaceNode(docElem, n, m_defaultMergeDirs, "MergeDir");
551  continue;
552  }
553  else if( e.tagName() == "AppDir") {
554  // Filter out dupes
555  foldNode(docElem, e, appDirNodes);
556  }
557  else if( e.tagName() == "DirectoryDir") {
558  // Filter out dupes
559  foldNode(docElem, e, directoryDirNodes);
560  }
561  else if( e.tagName() == "LegacyDir") {
562  // Filter out dupes
563  foldNode(docElem, e, legacyDirNodes);
564  }
565  else if( e.tagName() == "Directory") {
566  // Filter out dupes
567  foldNode(docElem, e, directoryNodes);
568  }
569  else if( e.tagName() == "Move") {
570  // Filter out dupes
571  TQString orig;
572  TQDomNode n2 = e.firstChild();
573  while( !n2.isNull() ) {
574  TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
575  if( e2.tagName() == "Old")
576  {
577  orig = e2.text();
578  break;
579  }
580  n2 = n2.nextSibling();
581  }
582  foldNode(docElem, e, appDirNodes, orig);
583  }
584  else if( e.tagName() == "Menu") {
585  TQString name;
586  mergeMenus(e, name);
587  TQMap<TQString,TQDomElement>::iterator it = menuNodes.find(name);
588  if (it != menuNodes.end())
589  {
590  TQDomElement docElem2 = *it;
591  TQDomNode n2 = docElem2.firstChild();
592  TQDomNode first = e.firstChild();
593  while( !n2.isNull() ) {
594  TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
595  TQDomNode n3 = n2.nextSibling();
596  e.insertBefore(n2, first);
597  docElem2.removeChild(n2);
598  n2 = n3;
599  }
600  // We still have duplicated Name entries
601  // but we don't care about that
602 
603  docElem.removeChild(docElem2);
604  menuNodes.remove(it);
605  }
606  menuNodes.insert(name, e);
607  }
608  else if( e.tagName() == "MergeFile") {
609  if ((e.attribute("type") == "parent"))
610  pushDocInfoParent(e.attribute("__BasePath"), e.attribute("__BaseDir"));
611  else
612  pushDocInfo(e.text(), e.attribute("__BaseDir"));
613 
614  if (!m_docInfo.path.isEmpty())
615  mergeFile(docElem, n);
616  popDocInfo();
617 
618  TQDomNode last = n;
619  n = n.nextSibling();
620  docElem.removeChild(last); // Remove the MergeFile node
621  continue;
622  }
623  else if( e.tagName() == "MergeDir") {
624  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"), true);
625 
626  TQStringList dirs = TDEGlobal::dirs()->findDirs("xdgconf-menu", dir);
627  for(TQStringList::ConstIterator it=dirs.begin();
628  it != dirs.end(); ++it)
629  {
630  registerDirectory(*it);
631  }
632 
633  TQStringList fileList;
634  if (!TQDir::isRelativePath(dir))
635  {
636  // Absolute
637  fileList = TDEGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu", false, false);
638  }
639  else
640  {
641  // Relative
642  (void) TDEGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu", false, true, fileList);
643  }
644 
645  for(TQStringList::ConstIterator it=fileList.begin();
646  it != fileList.end(); ++it)
647  {
648  pushDocInfo(*it);
649  mergeFile(docElem, n);
650  popDocInfo();
651  }
652 
653  TQDomNode last = n;
654  n = n.nextSibling();
655  docElem.removeChild(last); // Remove the MergeDir node
656 
657  continue;
658  }
659  else if( e.tagName() == "Name") {
660  name = e.text();
661  }
662  else if( e.tagName() == "DefaultLayout") {
663  if (!defaultLayoutNode.isNull())
664  docElem.removeChild(defaultLayoutNode);
665  defaultLayoutNode = e;
666  }
667  else if( e.tagName() == "Layout") {
668  if (!layoutNode.isNull())
669  docElem.removeChild(layoutNode);
670  layoutNode = e;
671  }
672  n = n.nextSibling();
673  }
674 }
675 
676 void
677 VFolderMenu::pushDocInfo(const TQString &fileName, const TQString &baseDir)
678 {
679  m_docInfoStack.push(m_docInfo);
680  if (!baseDir.isEmpty())
681  {
682  if (!TQDir::isRelativePath(baseDir))
683  m_docInfo.baseDir = TDEGlobal::dirs()->relativeLocation("xdgconf-menu", baseDir);
684  else
685  m_docInfo.baseDir = baseDir;
686  }
687 
688  TQString baseName = fileName;
689  if (!TQDir::isRelativePath(baseName))
690  registerFile(baseName);
691  else
692  baseName = m_docInfo.baseDir + baseName;
693 
694  m_docInfo.path = locateMenuFile(fileName);
695  if (m_docInfo.path.isEmpty())
696  {
697  m_docInfo.baseDir = TQString::null;
698  m_docInfo.baseName = TQString::null;
699  kdDebug(7021) << "Menu " << fileName << " not found." << endl;
700  return;
701  }
702  int i;
703  i = baseName.findRev('/');
704  if (i > 0)
705  {
706  m_docInfo.baseDir = baseName.left(i+1);
707  m_docInfo.baseName = baseName.mid(i+1, baseName.length() - i - 6);
708  }
709  else
710  {
711  m_docInfo.baseDir = TQString::null;
712  m_docInfo.baseName = baseName.left( baseName.length() - 5 );
713  }
714 }
715 
716 void
717 VFolderMenu::pushDocInfoParent(const TQString &basePath, const TQString &baseDir)
718 {
719  m_docInfoStack.push(m_docInfo);
720 
721  m_docInfo.baseDir = baseDir;
722 
723  TQString fileName = basePath.mid(basePath.findRev('/')+1);
724  m_docInfo.baseName = fileName.left( fileName.length() - 5 );
725  TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
726 
727  TQStringList result = TDEGlobal::dirs()->findAllResources("xdgconf-menu", baseName);
728 
729  while( !result.isEmpty() && (result[0] != basePath))
730  result.remove(result.begin());
731 
732  if (result.count() <= 1)
733  {
734  m_docInfo.path = TQString::null; // No parent found
735  return;
736  }
737  m_docInfo.path = result[1];
738 }
739 
740 void
741 VFolderMenu::popDocInfo()
742 {
743  m_docInfo = m_docInfoStack.pop();
744 }
745 
746 TQString
747 VFolderMenu::locateMenuFile(const TQString &fileName)
748 {
749  if (!TQDir::isRelativePath(fileName))
750  {
751  if (TDEStandardDirs::exists(fileName))
752  return fileName;
753  return TQString::null;
754  }
755 
756  TQString result;
757 
758  //TQString xdgMenuPrefix = TQString::fromLocal8Bit(getenv("XDG_MENU_PREFIX"));
759  // hardcode xdgMenuPrefix to "tde-" string until proper upstream fix
760  TQString xdgMenuPrefix = "tde-";
761  if (!xdgMenuPrefix.isEmpty())
762  {
763  TQFileInfo fileInfo(fileName);
764 
765  TQString fileNameOnly = fileInfo.fileName();
766  if (!fileNameOnly.startsWith(xdgMenuPrefix))
767  fileNameOnly = xdgMenuPrefix + fileNameOnly;
768 
769  TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir +
770  fileInfo.dirPath() + "/" +
771  fileNameOnly);
772  result = locate("xdgconf-menu", baseName);
773  }
774 
775  if (result.isEmpty())
776  {
777  TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
778  result = locate("xdgconf-menu", baseName);
779  }
780 
781  return result;
782 }
783 
784 TQString
785 VFolderMenu::locateDirectoryFile(const TQString &fileName)
786 {
787  if (fileName.isEmpty())
788  return TQString::null;
789 
790  if (!TQDir::isRelativePath(fileName))
791  {
792  if (TDEStandardDirs::exists(fileName))
793  return fileName;
794  return TQString::null;
795  }
796 
797  // First location in the list wins
798  TQString tmp;
799  for(TQStringList::ConstIterator it = m_directoryDirs.begin();
800  it != m_directoryDirs.end();
801  ++it)
802  {
803  tmp = (*it)+fileName;
804  if (TDEStandardDirs::exists(tmp))
805  return tmp;
806  }
807 
808  return TQString::null;
809 }
810 
811 void
812 VFolderMenu::initDirs()
813 {
814  m_defaultDataDirs = TQStringList::split(':', TDEGlobal::dirs()->kfsstnd_prefixes());
815  TQString localDir = m_defaultDataDirs.first();
816  m_defaultDataDirs.remove(localDir); // Remove local dir
817 
818  m_defaultAppDirs = TDEGlobal::dirs()->findDirs("xdgdata-apps", TQString::null);
819  m_defaultDirectoryDirs = TDEGlobal::dirs()->findDirs("xdgdata-dirs", TQString::null);
820  m_defaultLegacyDirs = TDEGlobal::dirs()->resourceDirs("apps");
821 }
822 
823 void
824 VFolderMenu::loadMenu(const TQString &fileName)
825 {
826  m_defaultMergeDirs.clear();
827 
828  if (!fileName.endsWith(".menu"))
829  return;
830 
831  pushDocInfo(fileName);
832  m_defaultMergeDirs << m_docInfo.baseName+"-merged/";
833  m_doc = loadDoc();
834  popDocInfo();
835 
836  if (m_doc.isNull())
837  {
838  if (m_docInfo.path.isEmpty())
839  kdError(7021) << fileName << " not found in " << m_allDirectories << endl;
840  else
841  kdWarning(7021) << "Load error (" << m_docInfo.path << ")" << endl;
842  return;
843  }
844 
845  TQDomElement e = m_doc.documentElement();
846  TQString name;
847  mergeMenus(e, name);
848 }
849 
850 void
851 VFolderMenu::processCondition(TQDomElement &domElem, TQDict<KService> *items)
852 {
853  if (domElem.tagName() == "And")
854  {
855  TQDomNode n = domElem.firstChild();
856  // Look for the first child element
857  while (!n.isNull()) // loop in case of comments
858  {
859  TQDomElement e = n.toElement();
860  n = n.nextSibling();
861  if ( !e.isNull() ) {
862  processCondition(e, items);
863  break; // we only want the first one
864  }
865  }
866 
867  TQDict<KService> andItems;
868  while( !n.isNull() ) {
869  TQDomElement e = n.toElement();
870  if (e.tagName() == "Not")
871  {
872  // Special handling for "and not"
873  TQDomNode n2 = e.firstChild();
874  while( !n2.isNull() ) {
875  TQDomElement e2 = n2.toElement();
876  andItems.clear();
877  processCondition(e2, &andItems);
878  excludeItems(items, &andItems);
879  n2 = n2.nextSibling();
880  }
881  }
882  else
883  {
884  andItems.clear();
885  processCondition(e, &andItems);
886  matchItems(items, &andItems);
887  }
888  n = n.nextSibling();
889  }
890  }
891  else if (domElem.tagName() == "Or")
892  {
893  TQDomNode n = domElem.firstChild();
894  // Look for the first child element
895  while (!n.isNull()) // loop in case of comments
896  {
897  TQDomElement e = n.toElement();
898  n = n.nextSibling();
899  if ( !e.isNull() ) {
900  processCondition(e, items);
901  break; // we only want the first one
902  }
903  }
904 
905  TQDict<KService> orItems;
906  while( !n.isNull() ) {
907  TQDomElement e = n.toElement();
908  if ( !e.isNull() ) {
909  orItems.clear();
910  processCondition(e, &orItems);
911  includeItems(items, &orItems);
912  }
913  n = n.nextSibling();
914  }
915  }
916  else if (domElem.tagName() == "Not")
917  {
918  for (appsInfo *info = m_appsInfoStack.first(); info; info = m_appsInfoStack.next())
919  {
920  for (TQDictIterator<KService> it( info->applications ); it.current(); ++it )
921  {
922  KService *s = it.current();
923  items->replace(s->menuId(), s);
924  }
925  }
926 
927  TQDict<KService> notItems;
928  TQDomNode n = domElem.firstChild();
929  while( !n.isNull() ) {
930  TQDomElement e = n.toElement();
931  if ( !e.isNull() ) {
932  notItems.clear();
933  processCondition(e, &notItems);
934  excludeItems(items, &notItems);
935  }
936  n = n.nextSibling();
937  }
938  }
939  else if (domElem.tagName() == "Category")
940  {
941  for (appsInfo *info = m_appsInfoStack.first(); info; info = m_appsInfoStack.next())
942  {
943  KService::List *list = info->dictCategories.find(domElem.text());
944  if (list)
945  {
946  for(KService::List::ConstIterator it = list->begin(); it != list->end(); ++it)
947  {
948  KService *s = *it;
949  items->replace(s->menuId(), s);
950  }
951  }
952  }
953  }
954  else if (domElem.tagName() == "All")
955  {
956  for (appsInfo *info = m_appsInfoStack.first(); info; info = m_appsInfoStack.next())
957  {
958  for (TQDictIterator<KService> it( info->applications ); it.current(); ++it )
959  {
960  KService *s = it.current();
961  items->replace(s->menuId(), s);
962  }
963  }
964  }
965  else if (domElem.tagName() == "Filename")
966  {
967  TQString filename = domElem.text();
968 kdDebug(7021) << "Adding file " << filename << endl;
969  KService *s = findApplication(filename);
970  if (s)
971  items->replace(filename, s);
972  }
973 }
974 
975 void
976 VFolderMenu::loadApplications(const TQString &dir, const TQString &prefix)
977 {
978  kdDebug(7021) << "Looking up applications under " << dir << endl;
979 
980  // We look for a set of files.
981  DIR *dp = opendir( TQFile::encodeName(dir));
982  if (!dp)
983  return;
984 
985  struct dirent *ep;
986  KDE_struct_stat buff;
987 
988  TQString _dot(".");
989  TQString _dotdot("..");
990 
991  while( ( ep = readdir( dp ) ) != 0L )
992  {
993  TQString fn( TQFile::decodeName(ep->d_name));
994  if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() == '~')
995  continue;
996 
997  TQString pathfn = dir + fn;
998  if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
999  continue; // Couldn't stat (e.g. no read permissions)
1000  }
1001  if ( S_ISDIR( buff.st_mode )) {
1002  loadApplications(pathfn + '/', prefix + fn + '-');
1003  continue;
1004  }
1005 
1006  if ( S_ISREG( buff.st_mode))
1007  {
1008  if (!fn.endsWith(".desktop"))
1009  continue;
1010 
1011  KService *service = 0;
1012  emit newService(pathfn, &service);
1013  if (service)
1014  addApplication(prefix+fn, service);
1015  }
1016  }
1017  closedir( dp );
1018 }
1019 
1020 void
1021 VFolderMenu::processKDELegacyDirs()
1022 {
1023 kdDebug(7021) << "processKDELegacyDirs()" << endl;
1024 
1025  TQDict<KService> items;
1026  TQString prefix = "tde-";
1027 
1028  TQStringList relFiles;
1029  TQRegExp files("\\.(desktop|kdelnk)$");
1030  TQRegExp dirs("\\.directory$");
1031 
1032  (void) TDEGlobal::dirs()->findAllResources( "apps",
1033  TQString::null,
1034  true, // Recursive!
1035  true, // uniq
1036  relFiles);
1037  for(TQStringList::ConstIterator it = relFiles.begin();
1038  it != relFiles.end(); ++it)
1039  {
1040  if (!m_forcedLegacyLoad && (dirs.search(*it) != -1))
1041  {
1042  TQString name = *it;
1043  if (!name.endsWith("/.directory"))
1044  continue; // Probably ".directory", skip it.
1045 
1046  name = name.left(name.length()-11);
1047 
1048  SubMenu *newMenu = new SubMenu;
1049  newMenu->directoryFile = locate("apps", *it);
1050 
1051  insertSubMenu(m_currentMenu, name, newMenu);
1052  continue;
1053  }
1054 
1055  if (files.search(*it) != -1)
1056  {
1057  TQString name = *it;
1058  KService *service = 0;
1059  emit newService(name, &service);
1060 
1061  if (service && !m_forcedLegacyLoad)
1062  {
1063  TQString id = name;
1064  // Strip path from id
1065  int i = id.findRev('/');
1066  if (i >= 0)
1067  id = id.mid(i+1);
1068 
1069  id.prepend(prefix);
1070 
1071  // TODO: add Legacy category
1072  addApplication(id, service);
1073  items.replace(service->menuId(), service);
1074  if (service->categories().isEmpty())
1075  insertService(m_currentMenu, name, service);
1076 
1077  }
1078  }
1079  }
1080  markUsedApplications(&items);
1081  m_legacyLoaded = true;
1082 }
1083 
1084 void
1085 VFolderMenu::processLegacyDir(const TQString &dir, const TQString &relDir, const TQString &prefix)
1086 {
1087 kdDebug(7021) << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")" << endl;
1088 
1089  TQDict<KService> items;
1090  // We look for a set of files.
1091  DIR *dp = opendir( TQFile::encodeName(dir));
1092  if (!dp)
1093  return;
1094 
1095  struct dirent *ep;
1096  KDE_struct_stat buff;
1097 
1098  TQString _dot(".");
1099  TQString _dotdot("..");
1100 
1101  while( ( ep = readdir( dp ) ) != 0L )
1102  {
1103  TQString fn( TQFile::decodeName(ep->d_name));
1104  if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() == '~')
1105  continue;
1106 
1107  TQString pathfn = dir + fn;
1108  if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1109  continue; // Couldn't stat (e.g. no read permissions)
1110  }
1111  if ( S_ISDIR( buff.st_mode )) {
1112  SubMenu *parentMenu = m_currentMenu;
1113 
1114  m_currentMenu = new SubMenu;
1115  m_currentMenu->name = fn;
1116  m_currentMenu->directoryFile = dir + fn + "/.directory";
1117 
1118  parentMenu->subMenus.append(m_currentMenu);
1119 
1120  processLegacyDir(pathfn + '/', relDir+fn+'/', prefix);
1121  m_currentMenu = parentMenu;
1122  continue;
1123  }
1124 
1125  if ( S_ISREG( buff.st_mode))
1126  {
1127  if (!fn.endsWith(".desktop"))
1128  continue;
1129 
1130  KService *service = 0;
1131  emit newService(pathfn, &service);
1132  if (service)
1133  {
1134  TQString id = prefix+fn;
1135 
1136  // TODO: Add legacy category
1137  addApplication(id, service);
1138  items.replace(service->menuId(), service);
1139 
1140  if (service->categories().isEmpty())
1141  m_currentMenu->items.replace(id, service);
1142  }
1143  }
1144  }
1145  closedir( dp );
1146  markUsedApplications(&items);
1147 }
1148 
1149 
1150 
1151 void
1152 VFolderMenu::processMenu(TQDomElement &docElem, int pass)
1153 {
1154  SubMenu *parentMenu = m_currentMenu;
1155  unsigned int oldDirectoryDirsCount = m_directoryDirs.count();
1156 
1157  TQString name;
1158  TQString directoryFile;
1159  bool onlyUnallocated = false;
1160  bool isDeleted = false;
1161  bool kdeLegacyDirsDone = false;
1162  TQDomElement defaultLayoutNode;
1163  TQDomElement layoutNode;
1164 
1165  TQDomElement query;
1166  TQDomNode n = docElem.firstChild();
1167  while( !n.isNull() ) {
1168  TQDomElement e = n.toElement(); // try to convert the node to an element.
1169  if (e.tagName() == "Name")
1170  {
1171  name = e.text();
1172  }
1173  else if (e.tagName() == "Directory")
1174  {
1175  directoryFile = e.text();
1176  }
1177  else if (e.tagName() == "DirectoryDir")
1178  {
1179  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1180 
1181  m_directoryDirs.prepend(dir);
1182  }
1183  else if (e.tagName() == "OnlyUnallocated")
1184  {
1185  onlyUnallocated = true;
1186  }
1187  else if (e.tagName() == "NotOnlyUnallocated")
1188  {
1189  onlyUnallocated = false;
1190  }
1191  else if (e.tagName() == "Deleted")
1192  {
1193  isDeleted = true;
1194  }
1195  else if (e.tagName() == "NotDeleted")
1196  {
1197  isDeleted = false;
1198  }
1199  else if (e.tagName() == "DefaultLayout")
1200  {
1201  defaultLayoutNode = e;
1202  }
1203  else if (e.tagName() == "Layout")
1204  {
1205  layoutNode = e;
1206  }
1207  n = n.nextSibling();
1208  }
1209 
1210  // Setup current menu entry
1211  if (pass == 0)
1212  {
1213  m_currentMenu = 0;
1214  // Look up menu
1215  if (parentMenu)
1216  {
1217  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1218  {
1219  if (menu->name == name)
1220  {
1221  m_currentMenu = menu;
1222  break;
1223  }
1224  }
1225  }
1226 
1227  if (!m_currentMenu) // Not found?
1228  {
1229  // Create menu
1230  m_currentMenu = new SubMenu;
1231  m_currentMenu->name = name;
1232 
1233  if (parentMenu)
1234  parentMenu->subMenus.append(m_currentMenu);
1235  else
1236  m_rootMenu = m_currentMenu;
1237  }
1238  if (directoryFile.isEmpty())
1239  {
1240  kdDebug(7021) << "Menu " << name << " does not specify a directory file." << endl;
1241  }
1242 
1243  // Override previous directoryFile iff available
1244  TQString tmp = locateDirectoryFile(directoryFile);
1245  if (! tmp.isEmpty())
1246  m_currentMenu->directoryFile = tmp;
1247  m_currentMenu->isDeleted = isDeleted;
1248 
1249  m_currentMenu->defaultLayoutNode = defaultLayoutNode;
1250  m_currentMenu->layoutNode = layoutNode;
1251  }
1252  else
1253  {
1254  // Look up menu
1255  if (parentMenu)
1256  {
1257  for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1258  {
1259  if (menu->name == name)
1260  {
1261  m_currentMenu = menu;
1262  break;
1263  }
1264  }
1265  }
1266  else
1267  {
1268  m_currentMenu = m_rootMenu;
1269  }
1270  }
1271 
1272  // Process AppDir and LegacyDir
1273  if (pass == 0)
1274  {
1275  TQDomElement query;
1276  TQDomNode n = docElem.firstChild();
1277  while( !n.isNull() ) {
1278  TQDomElement e = n.toElement(); // try to convert the node to an element.
1279  if (e.tagName() == "AppDir")
1280  {
1281  createAppsInfo();
1282  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1283 
1284  registerDirectory(dir);
1285 
1286  loadApplications(dir, TQString::null);
1287  }
1288  else if (e.tagName() == "KDELegacyDirs")
1289  {
1290  createAppsInfo();
1291  if (!kdeLegacyDirsDone)
1292  {
1293 kdDebug(7021) << "Processing KDE Legacy dirs for <KDE>" << endl;
1294  SubMenu *oldMenu = m_currentMenu;
1295  m_currentMenu = new SubMenu;
1296 
1297  processKDELegacyDirs();
1298 
1299  m_legacyNodes.replace("<KDE>", m_currentMenu);
1300  m_currentMenu = oldMenu;
1301 
1302  kdeLegacyDirsDone = true;
1303  }
1304  }
1305  else if (e.tagName() == "LegacyDir")
1306  {
1307  createAppsInfo();
1308  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1309 
1310  TQString prefix = e.attributes().namedItem("prefix").toAttr().value();
1311 
1312  if (m_defaultLegacyDirs.contains(dir))
1313  {
1314  if (!kdeLegacyDirsDone)
1315  {
1316 kdDebug(7021) << "Processing KDE Legacy dirs for " << dir << endl;
1317  SubMenu *oldMenu = m_currentMenu;
1318  m_currentMenu = new SubMenu;
1319 
1320  processKDELegacyDirs();
1321 
1322  m_legacyNodes.replace("<KDE>", m_currentMenu);
1323  m_currentMenu = oldMenu;
1324 
1325  kdeLegacyDirsDone = true;
1326  }
1327  }
1328  else
1329  {
1330  SubMenu *oldMenu = m_currentMenu;
1331  m_currentMenu = new SubMenu;
1332 
1333  registerDirectory(dir);
1334 
1335  processLegacyDir(dir, TQString::null, prefix);
1336 
1337  m_legacyNodes.replace(dir, m_currentMenu);
1338  m_currentMenu = oldMenu;
1339  }
1340  }
1341  n = n.nextSibling();
1342  }
1343  }
1344 
1345  loadAppsInfo(); // Update the scope wrt the list of applications
1346 
1347  if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
1348  {
1349  n = docElem.firstChild();
1350 
1351  while( !n.isNull() ) {
1352  TQDomElement e = n.toElement(); // try to convert the node to an element.
1353  if (e.tagName() == "Include")
1354  {
1355  TQDict<KService> items;
1356 
1357  TQDomNode n2 = e.firstChild();
1358  while( !n2.isNull() ) {
1359  TQDomElement e2 = n2.toElement();
1360  items.clear();
1361  processCondition(e2, &items);
1362  if (m_track)
1363  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "Before <Include>");
1364  includeItems(&(m_currentMenu->items), &items);
1365  excludeItems(&(m_currentMenu->excludeItems), &items);
1366  markUsedApplications(&items);
1367 
1368  if (m_track)
1369  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "After <Include>");
1370 
1371  n2 = n2.nextSibling();
1372  }
1373  }
1374 
1375  else if (e.tagName() == "Exclude")
1376  {
1377  TQDict<KService> items;
1378 
1379  TQDomNode n2 = e.firstChild();
1380  while( !n2.isNull() ) {
1381  TQDomElement e2 = n2.toElement();
1382  items.clear();
1383  processCondition(e2, &items);
1384  if (m_track)
1385  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "Before <Exclude>");
1386  excludeItems(&(m_currentMenu->items), &items);
1387  includeItems(&(m_currentMenu->excludeItems), &items);
1388  if (m_track)
1389  track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "After <Exclude>");
1390  n2 = n2.nextSibling();
1391  }
1392  }
1393 
1394  n = n.nextSibling();
1395  }
1396  }
1397 
1398  n = docElem.firstChild();
1399  while( !n.isNull() ) {
1400  TQDomElement e = n.toElement(); // try to convert the node to an element.
1401  if (e.tagName() == "Menu")
1402  {
1403  processMenu(e, pass);
1404  }
1405 // We insert legacy dir in pass 0, this way the order in the .menu-file determines
1406 // which .directory file gets used, but the menu-entries of legacy-menus will always
1407 // have the lowest priority.
1408 // else if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
1409  else if (pass == 0)
1410  {
1411  if (e.tagName() == "LegacyDir")
1412  {
1413  // Add legacy nodes to Menu structure
1414  TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
1415  SubMenu *legacyMenu = m_legacyNodes.find(dir);
1416  if (legacyMenu)
1417  {
1418  mergeMenu(m_currentMenu, legacyMenu);
1419  }
1420  }
1421 
1422  else if (e.tagName() == "KDELegacyDirs")
1423  {
1424  // Add legacy nodes to Menu structure
1425  TQString dir = "<KDE>";
1426  SubMenu *legacyMenu = m_legacyNodes.find(dir);
1427  if (legacyMenu)
1428  {
1429  mergeMenu(m_currentMenu, legacyMenu);
1430  }
1431  }
1432  }
1433  n = n.nextSibling();
1434  }
1435 
1436  if (pass == 2)
1437  {
1438  n = docElem.firstChild();
1439  while( !n.isNull() ) {
1440  TQDomElement e = n.toElement(); // try to convert the node to an element.
1441  if (e.tagName() == "Move")
1442  {
1443  TQString orig;
1444  TQString dest;
1445  TQDomNode n2 = e.firstChild();
1446  while( !n2.isNull() ) {
1447  TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
1448  if( e2.tagName() == "Old")
1449  orig = e2.text();
1450  if( e2.tagName() == "New")
1451  dest = e2.text();
1452  n2 = n2.nextSibling();
1453  }
1454  kdDebug(7021) << "Moving " << orig << " to " << dest << endl;
1455  if (!orig.isEmpty() && !dest.isEmpty())
1456  {
1457  SubMenu *menu = takeSubMenu(m_currentMenu, orig);
1458  if (menu)
1459  {
1460  insertSubMenu(m_currentMenu, dest, menu, true); // Destination has priority
1461  }
1462  }
1463  }
1464  n = n.nextSibling();
1465  }
1466 
1467  }
1468 
1469  unloadAppsInfo(); // Update the scope wrt the list of applications
1470 
1471  while (m_directoryDirs.count() > oldDirectoryDirsCount)
1472  m_directoryDirs.pop_front();
1473 
1474  m_currentMenu = parentMenu;
1475 }
1476 
1477 
1478 
1479 static TQString parseAttribute( const TQDomElement &e)
1480 {
1481  TQString option;
1482  if ( e.hasAttribute( "show_empty" ) )
1483  {
1484  TQString str = e.attribute( "show_empty" );
1485  if ( str=="true" )
1486  option= "ME ";
1487  else if ( str=="false" )
1488  option= "NME ";
1489  else
1490  kdDebug()<<" Error in parsing show_empty attribute :"<<str<<endl;
1491  }
1492  if ( e.hasAttribute( "inline" ) )
1493  {
1494  TQString str = e.attribute( "inline" );
1495  if ( str=="true" )
1496  option+="I ";
1497  else if ( str=="false" )
1498  option+="NI ";
1499  else
1500  kdDebug()<<" Error in parsing inlibe attribute :"<<str<<endl;
1501  }
1502  if ( e.hasAttribute( "inline_limit" ) )
1503  {
1504  bool ok;
1505  int value = e.attribute( "inline_limit" ).toInt(&ok);
1506  if ( ok )
1507  option+=TQString( "IL[%1] " ).arg( value );
1508  }
1509  if ( e.hasAttribute( "inline_header" ) )
1510  {
1511  TQString str = e.attribute( "inline_header" );
1512  if ( str=="true")
1513  option+="IH ";
1514  else if ( str == "false" )
1515  option+="NIH ";
1516  else
1517  kdDebug()<<" Error in parsing of inline_header attribute :"<<str<<endl;
1518 
1519  }
1520  if ( e.hasAttribute( "inline_alias" ) && e.attribute( "inline_alias" )=="true")
1521  {
1522  TQString str = e.attribute( "inline_alias" );
1523  if ( str=="true" )
1524  option+="IA";
1525  else if ( str=="false" )
1526  option+="NIA";
1527  else
1528  kdDebug()<<" Error in parsing inline_alias attribute :"<<str<<endl;
1529  }
1530  if( !option.isEmpty())
1531  {
1532  option = option.prepend(":O");
1533  }
1534  return option;
1535 
1536 }
1537 
1538 static TQStringList parseLayoutNode(const TQDomElement &docElem)
1539 {
1540  TQStringList layout;
1541 
1542  TQString optionDefaultLayout;
1543  if( docElem.tagName()=="DefaultLayout")
1544  optionDefaultLayout = parseAttribute( docElem);
1545  if ( !optionDefaultLayout.isEmpty() )
1546  layout.append( optionDefaultLayout );
1547 
1548  TQDomNode n = docElem.firstChild();
1549  while( !n.isNull() ) {
1550  TQDomElement e = n.toElement(); // try to convert the node to an element.
1551  if (e.tagName() == "Separator")
1552  {
1553  layout.append(":S");
1554  }
1555  else if (e.tagName() == "Filename")
1556  {
1557  layout.append(e.text());
1558  }
1559  else if (e.tagName() == "Menuname")
1560  {
1561  layout.append("/"+e.text());
1562  TQString option = parseAttribute( e );
1563  if( !option.isEmpty())
1564  layout.append( option );
1565  }
1566  else if (e.tagName() == "Merge")
1567  {
1568  TQString type = e.attributeNode("type").value();
1569  if (type == "files")
1570  layout.append(":F");
1571  else if (type == "menus")
1572  layout.append(":M");
1573  else if (type == "all")
1574  layout.append(":A");
1575  }
1576 
1577  n = n.nextSibling();
1578  }
1579  return layout;
1580 }
1581 
1582 void
1583 VFolderMenu::layoutMenu(VFolderMenu::SubMenu *menu, TQStringList defaultLayout)
1584 {
1585  if (!menu->defaultLayoutNode.isNull())
1586  {
1587  defaultLayout = parseLayoutNode(menu->defaultLayoutNode);
1588  }
1589 
1590  if (menu->layoutNode.isNull())
1591  {
1592  menu->layoutList = defaultLayout;
1593  }
1594  else
1595  {
1596  menu->layoutList = parseLayoutNode(menu->layoutNode);
1597  if (menu->layoutList.isEmpty())
1598  menu->layoutList = defaultLayout;
1599  }
1600 
1601  for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
1602  {
1603  layoutMenu(subMenu, defaultLayout);
1604  }
1605 }
1606 
1607 void
1608 VFolderMenu::markUsedApplications(TQDict<KService> *items)
1609 {
1610  for(TQDictIterator<KService> it(*items); it.current(); ++it)
1611  {
1612  m_usedAppsDict.replace(it.current()->menuId(), it.current());
1613  }
1614 }
1615 
1616 VFolderMenu::SubMenu *
1617 VFolderMenu::parseMenu(const TQString &file, bool forceLegacyLoad)
1618 {
1619  m_forcedLegacyLoad = false;
1620  m_legacyLoaded = false;
1621  m_appsInfo = 0;
1622 
1623  TQStringList dirs = TDEGlobal::dirs()->resourceDirs("xdgconf-menu");
1624  for(TQStringList::ConstIterator it=dirs.begin();
1625  it != dirs.end(); ++it)
1626  {
1627  registerDirectory(*it);
1628  }
1629 
1630  loadMenu(file);
1631 
1632  delete m_rootMenu;
1633  m_rootMenu = m_currentMenu = 0;
1634 
1635  TQDomElement docElem = m_doc.documentElement();
1636 
1637  for (int pass = 0; pass <= 2; pass++)
1638  {
1639  processMenu(docElem, pass);
1640 
1641  if (pass == 0)
1642  {
1643  buildApplicationIndex(false);
1644  }
1645  if (pass == 1)
1646  {
1647  buildApplicationIndex(true);
1648  }
1649  if (pass == 2)
1650  {
1651  TQStringList defaultLayout;
1652  defaultLayout << ":M"; // Sub-Menus
1653  defaultLayout << ":F"; // Individual entries
1654  layoutMenu(m_rootMenu, defaultLayout);
1655  }
1656  }
1657 
1658  if (!m_legacyLoaded && forceLegacyLoad)
1659  {
1660  m_forcedLegacyLoad = true;
1661  processKDELegacyDirs();
1662  }
1663 
1664  return m_rootMenu;
1665 }
1666 
1667 void
1668 VFolderMenu::setTrackId(const TQString &id)
1669 {
1670  m_track = !id.isEmpty();
1671  m_trackId = id;
1672 }
1673 
1674 #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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kded by doxygen 1.8.8
This website is maintained by Timothy Pearson.