• 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 <tdestandarddirs.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
38static 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
53static 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
70void 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
80void VFolderMenu::registerDirectory(const TQString &directory)
81{
82 m_allDirectories.append(directory);
83}
84
85TQStringList 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
108static void
109track(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
115void
116VFolderMenu::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
124void
125VFolderMenu::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
136void
137VFolderMenu::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
145VFolderMenu::SubMenu*
146VFolderMenu::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
171void
172VFolderMenu::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
231void
232VFolderMenu::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
271void
272VFolderMenu::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
303VFolderMenu::VFolderMenu() : m_usedAppsDict(797), m_track(false)
304{
305 m_rootMenu = 0;
306 initDirs();
307}
308
309VFolderMenu::~VFolderMenu()
310{
311 delete m_rootMenu;
312}
313
314KService *
315VFolderMenu::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
327void
328VFolderMenu::addApplication(const TQString &id, KService *service)
329{
330 service->setMenuId(id);
331 m_appsInfo->applications.replace(id, service);
332}
333
334void
335VFolderMenu::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
372void
373VFolderMenu::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
383void
384VFolderMenu::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
396void
397VFolderMenu::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
412TQString
413VFolderMenu::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
433static 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
444static 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
455TQDomDocument
456VFolderMenu::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
490void
491VFolderMenu::mergeFile(TQDomElement &parent, const TQDomNode &mergeHere)
492{
493kdDebug(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
521void
522VFolderMenu::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
676void
677VFolderMenu::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
716void
717VFolderMenu::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
740void
741VFolderMenu::popDocInfo()
742{
743 m_docInfo = m_docInfoStack.pop();
744}
745
746TQString
747VFolderMenu::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
784TQString
785VFolderMenu::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
811void
812VFolderMenu::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
823void
824VFolderMenu::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
850void
851VFolderMenu::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();
968kdDebug(7021) << "Adding file " << filename << endl;
969 KService *s = findApplication(filename);
970 if (s)
971 items->replace(filename, s);
972 }
973}
974
975void
976VFolderMenu::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
1020void
1021VFolderMenu::processKDELegacyDirs()
1022{
1023kdDebug(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
1084void
1085VFolderMenu::processLegacyDir(const TQString &dir, const TQString &relDir, const TQString &prefix)
1086{
1087kdDebug(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
1151void
1152VFolderMenu::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 {
1293kdDebug(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 {
1316kdDebug(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
1479static 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
1538static 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
1582void
1583VFolderMenu::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
1607void
1608VFolderMenu::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
1616VFolderMenu::SubMenu *
1617VFolderMenu::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
1667void
1668VFolderMenu::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
  • 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.9.4
This website is maintained by Timothy Pearson.