19 #include <sys/types.h>
26 #include <tdeglobal.h>
27 #include <kstandarddirs.h>
36 #include "vfolder_menu.h"
38 static void foldNode(TQDomElement &docElem, TQDomElement &e, TQMap<TQString,TQDomElement> &dupeList, TQString s=TQString::null)
42 TQMap<TQString,TQDomElement>::iterator it = dupeList.find(s);
43 if (it != dupeList.end())
45 kdDebug(7021) << e.tagName() <<
" and " << s <<
" requires combining!" << endl;
47 docElem.removeChild(*it);
50 dupeList.insert(s, e);
53 static void replaceNode(TQDomElement &docElem, TQDomNode &n,
const TQStringList &list,
const TQString &tag)
55 for(TQStringList::ConstIterator it = list.begin();
56 it != list.end(); ++it)
58 TQDomElement e = docElem.ownerDocument().createElement(tag);
59 TQDomText txt = docElem.ownerDocument().createTextNode(*it);
61 docElem.insertAfter(e, n);
64 TQDomNode next = n.nextSibling();
65 docElem.removeChild(n);
70 void VFolderMenu::registerFile(
const TQString &file)
72 int i = file.findRev(
'/');
76 TQString dir = file.left(i+1);
77 registerDirectory(dir);
80 void VFolderMenu::registerDirectory(
const TQString &directory)
82 m_allDirectories.append(directory);
85 TQStringList VFolderMenu::allDirectories()
87 if (m_allDirectories.isEmpty())
88 return m_allDirectories;
89 m_allDirectories.sort();
91 TQStringList::Iterator it = m_allDirectories.begin();
92 TQString previous = *it++;
93 for(;it != m_allDirectories.end();)
95 if ((*it).startsWith(previous))
97 it = m_allDirectories.remove(it);
105 return m_allDirectories;
109 track(
const TQString &menuId,
const TQString &menuName, TQDict<KService> *includeList, TQDict<KService> *excludeList, TQDict<KService> *itemList,
const TQString &comment)
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);
116 VFolderMenu::includeItems(TQDict<KService> *items1, TQDict<KService> *items2)
118 for(TQDictIterator<KService> it(*items2); it.current(); ++it)
120 items1->replace(it.current()->menuId(), it.current());
125 VFolderMenu::matchItems(TQDict<KService> *items1, TQDict<KService> *items2)
127 for(TQDictIterator<KService> it(*items1); it.current(); )
129 TQString
id = it.current()->menuId();
131 if (!items2->find(
id))
137 VFolderMenu::excludeItems(TQDict<KService> *items1, TQDict<KService> *items2)
139 for(TQDictIterator<KService> it(*items2); it.current(); ++it)
141 items1->remove(it.current()->menuId());
145 VFolderMenu::SubMenu*
146 VFolderMenu::takeSubMenu(SubMenu *parentMenu,
const TQString &menuName)
148 int i = menuName.find(
'/');
149 TQString s1 = i > 0 ? menuName.left(i) : menuName;
150 TQString s2 = menuName.mid(i+1);
153 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
155 if (menu->name == s1)
160 return parentMenu->subMenus.take();
164 return takeSubMenu(menu, s2);
172 VFolderMenu::mergeMenu(SubMenu *menu1, SubMenu *menu2,
bool reversePriority)
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));
182 excludeItems(&(menu2->items), &(menu1->excludeItems));
183 includeItems(&(menu1->items), &(menu2->items));
184 excludeItems(&(menu2->excludeItems), &(menu1->items));
185 includeItems(&(menu1->excludeItems), &(menu2->excludeItems));
190 excludeItems(&(menu1->items), &(menu2->excludeItems));
191 includeItems(&(menu1->items), &(menu2->items));
192 includeItems(&(menu1->excludeItems), &(menu2->excludeItems));
193 menu1->isDeleted = menu2->isDeleted;
195 for(; menu2->subMenus.first(); )
197 SubMenu *subMenu = menu2->subMenus.take();
198 insertSubMenu(menu1, subMenu->name, subMenu, reversePriority);
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;
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;
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));
232 VFolderMenu::insertSubMenu(SubMenu *parentMenu,
const TQString &menuName, SubMenu *newMenu,
bool reversePriority)
234 int i = menuName.find(
'/');
236 TQString s1 = menuName.left(i);
237 TQString s2 = menuName.mid(i+1);
240 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
242 if (menu->name == s1)
246 mergeMenu(menu, newMenu, reversePriority);
251 insertSubMenu(menu, s2, newMenu, reversePriority);
259 newMenu->name = menuName;
260 parentMenu->subMenus.append(newMenu);
264 SubMenu *menu =
new SubMenu;
266 parentMenu->subMenus.append(menu);
267 insertSubMenu(menu, s2, newMenu);
272 VFolderMenu::insertService(SubMenu *parentMenu,
const TQString &name, KService *newService)
274 int i = name.find(
'/');
279 parentMenu->items.replace(newService->menuId(), newService);
283 TQString s1 = name.left(i);
284 TQString s2 = name.mid(i+1);
287 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
289 if (menu->name == s1)
291 insertService(menu, s2, newService);
296 SubMenu *menu =
new SubMenu;
298 parentMenu->subMenus.append(menu);
299 insertService(menu, s2, newService);
303 VFolderMenu::VFolderMenu() : m_usedAppsDict(797), m_track(false)
309 VFolderMenu::~VFolderMenu()
315 VFolderMenu::findApplication(
const TQString &relPath)
317 for(appsInfo *info = m_appsInfoStack.first();
318 info; info = m_appsInfoStack.next())
320 KService *s = info->applications.find(relPath);
328 VFolderMenu::addApplication(
const TQString &
id, KService *service)
330 service->setMenuId(
id);
331 m_appsInfo->applications.replace(
id, service);
335 VFolderMenu::buildApplicationIndex(
bool unusedOnly)
337 TQPtrList<appsInfo>::ConstIterator appsInfo_it = m_appsInfoList.begin();
338 for( ; appsInfo_it != m_appsInfoList.end(); ++appsInfo_it )
340 appsInfo *info = *appsInfo_it;
341 info->dictCategories.clear();
342 for(TQDictIterator<KService> it( info->applications );
345 KService *s = it.current();
346 TQDictIterator<KService> tmpIt = it;
348 if (unusedOnly && m_usedAppsDict.find(s->menuId()))
351 info->applications.remove(tmpIt.currentKey());
355 TQStringList cats = s->categories();
356 for(TQStringList::ConstIterator it2 = cats.begin();
357 it2 != cats.end(); ++it2)
359 const TQString &cat = *it2;
360 KService::List *list = info->dictCategories.find(cat);
363 list =
new KService::List();
364 info->dictCategories.insert(cat, list);
373 VFolderMenu::createAppsInfo()
375 if (m_appsInfo)
return;
377 m_appsInfo =
new appsInfo;
378 m_appsInfoStack.prepend(m_appsInfo);
379 m_appsInfoList.append(m_appsInfo);
380 m_currentMenu->apps_info = m_appsInfo;
384 VFolderMenu::loadAppsInfo()
386 m_appsInfo = m_currentMenu->apps_info;
390 if (m_appsInfoStack.first() == m_appsInfo)
393 m_appsInfoStack.prepend(m_appsInfo);
397 VFolderMenu::unloadAppsInfo()
399 m_appsInfo = m_currentMenu->apps_info;
403 if (m_appsInfoStack.first() != m_appsInfo)
408 m_appsInfoStack.remove(m_appsInfo);
413 VFolderMenu::absoluteDir(
const TQString &_dir,
const TQString &baseDir,
bool keepRelativeToCfg)
416 if (TQDir::isRelativePath(dir))
420 if (!dir.endsWith(
"/"))
423 if (TQDir::isRelativePath(dir) && !keepRelativeToCfg)
425 dir = TDEGlobal::dirs()->findResource(
"xdgconf-menu", dir);
428 dir = TDEGlobal::dirs()->realPath(dir);
433 static void tagBaseDir(TQDomDocument &doc,
const TQString &tag,
const TQString &dir)
435 TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
436 for(
int i = 0; i < (int)mergeFileList.count(); i++)
438 TQDomAttr attr = doc.createAttribute(
"__BaseDir");
440 mergeFileList.item(i).toElement().setAttributeNode(attr);
444 static void tagBasePath(TQDomDocument &doc,
const TQString &tag,
const TQString &path)
446 TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
447 for(
int i = 0; i < (int)mergeFileList.count(); i++)
449 TQDomAttr attr = doc.createAttribute(
"__BasePath");
451 mergeFileList.item(i).toElement().setAttributeNode(attr);
456 VFolderMenu::loadDoc()
459 if ( m_docInfo.path.isEmpty() )
463 TQFile file( m_docInfo.path );
464 if ( !file.open( IO_ReadOnly ) )
466 kdWarning(7021) <<
"Could not open " << m_docInfo.path << endl;
472 if ( !doc.setContent( &file, &errorMsg, &errorRow, &errorCol ) ) {
473 kdWarning(7021) <<
"Parse error in " << m_docInfo.path <<
", line " << errorRow <<
", col " << errorCol <<
": " << errorMsg << endl;
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);
491 VFolderMenu::mergeFile(TQDomElement &parent,
const TQDomNode &mergeHere)
493 kdDebug(7021) <<
"VFolderMenu::mergeFile: " << m_docInfo.path << endl;
494 TQDomDocument doc = loadDoc();
496 TQDomElement docElem = doc.documentElement();
497 TQDomNode n = docElem.firstChild();
498 TQDomNode last = mergeHere;
501 TQDomElement e = n.toElement();
502 TQDomNode next = n.nextSibling();
509 else if (e.tagName() !=
"Name")
511 parent.insertAfter(n, last);
515 docElem.removeChild(n);
522 VFolderMenu::mergeMenus(TQDomElement &docElem, TQString &name)
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;
532 TQDomNode n = docElem.firstChild();
533 while( !n.isNull() ) {
534 TQDomElement e = n.toElement();
538 else if( e.tagName() ==
"DefaultAppDirs") {
540 replaceNode(docElem, n, m_defaultAppDirs,
"AppDir");
543 else if( e.tagName() ==
"DefaultDirectoryDirs") {
545 replaceNode(docElem, n, m_defaultDirectoryDirs,
"DirectoryDir");
548 else if( e.tagName() ==
"DefaultMergeDirs") {
550 replaceNode(docElem, n, m_defaultMergeDirs,
"MergeDir");
553 else if( e.tagName() ==
"AppDir") {
555 foldNode(docElem, e, appDirNodes);
557 else if( e.tagName() ==
"DirectoryDir") {
559 foldNode(docElem, e, directoryDirNodes);
561 else if( e.tagName() ==
"LegacyDir") {
563 foldNode(docElem, e, legacyDirNodes);
565 else if( e.tagName() ==
"Directory") {
567 foldNode(docElem, e, directoryNodes);
569 else if( e.tagName() ==
"Move") {
572 TQDomNode n2 = e.firstChild();
573 while( !n2.isNull() ) {
574 TQDomElement e2 = n2.toElement();
575 if( e2.tagName() ==
"Old")
580 n2 = n2.nextSibling();
582 foldNode(docElem, e, appDirNodes, orig);
584 else if( e.tagName() ==
"Menu") {
587 TQMap<TQString,TQDomElement>::iterator it = menuNodes.find(name);
588 if (it != menuNodes.end())
590 TQDomElement docElem2 = *it;
591 TQDomNode n2 = docElem2.firstChild();
592 TQDomNode first = e.firstChild();
593 while( !n2.isNull() ) {
594 TQDomElement e2 = n2.toElement();
595 TQDomNode n3 = n2.nextSibling();
596 e.insertBefore(n2, first);
597 docElem2.removeChild(n2);
603 docElem.removeChild(docElem2);
604 menuNodes.remove(it);
606 menuNodes.insert(name, e);
608 else if( e.tagName() ==
"MergeFile") {
609 if ((e.attribute(
"type") ==
"parent"))
610 pushDocInfoParent(e.attribute(
"__BasePath"), e.attribute(
"__BaseDir"));
612 pushDocInfo(e.text(), e.attribute(
"__BaseDir"));
614 if (!m_docInfo.path.isEmpty())
615 mergeFile(docElem, n);
620 docElem.removeChild(last);
623 else if( e.tagName() ==
"MergeDir") {
624 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"),
true);
626 TQStringList dirs = TDEGlobal::dirs()->findDirs(
"xdgconf-menu", dir);
627 for(TQStringList::ConstIterator it=dirs.begin();
628 it != dirs.end(); ++it)
630 registerDirectory(*it);
633 TQStringList fileList;
634 if (!TQDir::isRelativePath(dir))
637 fileList = TDEGlobal::dirs()->findAllResources(
"xdgconf-menu", dir+
"*.menu",
false,
false);
642 (void) TDEGlobal::dirs()->findAllResources(
"xdgconf-menu", dir+
"*.menu",
false,
true, fileList);
645 for(TQStringList::ConstIterator it=fileList.begin();
646 it != fileList.end(); ++it)
649 mergeFile(docElem, n);
655 docElem.removeChild(last);
659 else if( e.tagName() ==
"Name") {
662 else if( e.tagName() ==
"DefaultLayout") {
663 if (!defaultLayoutNode.isNull())
664 docElem.removeChild(defaultLayoutNode);
665 defaultLayoutNode = e;
667 else if( e.tagName() ==
"Layout") {
668 if (!layoutNode.isNull())
669 docElem.removeChild(layoutNode);
677 VFolderMenu::pushDocInfo(
const TQString &fileName,
const TQString &baseDir)
679 m_docInfoStack.push(m_docInfo);
680 if (!baseDir.isEmpty())
682 if (!TQDir::isRelativePath(baseDir))
683 m_docInfo.baseDir = TDEGlobal::dirs()->relativeLocation(
"xdgconf-menu", baseDir);
685 m_docInfo.baseDir = baseDir;
688 TQString baseName = fileName;
689 if (!TQDir::isRelativePath(baseName))
690 registerFile(baseName);
692 baseName = m_docInfo.baseDir + baseName;
694 m_docInfo.path = locateMenuFile(fileName);
695 if (m_docInfo.path.isEmpty())
697 m_docInfo.baseDir = TQString::null;
698 m_docInfo.baseName = TQString::null;
699 kdDebug(7021) <<
"Menu " << fileName <<
" not found." << endl;
703 i = baseName.findRev(
'/');
706 m_docInfo.baseDir = baseName.left(i+1);
707 m_docInfo.baseName = baseName.mid(i+1, baseName.length() - i - 6);
711 m_docInfo.baseDir = TQString::null;
712 m_docInfo.baseName = baseName.left( baseName.length() - 5 );
717 VFolderMenu::pushDocInfoParent(
const TQString &basePath,
const TQString &baseDir)
719 m_docInfoStack.push(m_docInfo);
721 m_docInfo.baseDir = baseDir;
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);
727 TQStringList result = TDEGlobal::dirs()->findAllResources(
"xdgconf-menu", baseName);
729 while( !result.isEmpty() && (result[0] != basePath))
730 result.remove(result.begin());
732 if (result.count() <= 1)
734 m_docInfo.path = TQString::null;
737 m_docInfo.path = result[1];
741 VFolderMenu::popDocInfo()
743 m_docInfo = m_docInfoStack.pop();
747 VFolderMenu::locateMenuFile(
const TQString &fileName)
749 if (!TQDir::isRelativePath(fileName))
751 if (TDEStandardDirs::exists(fileName))
753 return TQString::null;
760 TQString xdgMenuPrefix =
"tde-";
761 if (!xdgMenuPrefix.isEmpty())
763 TQFileInfo fileInfo(fileName);
765 TQString fileNameOnly = fileInfo.fileName();
766 if (!fileNameOnly.startsWith(xdgMenuPrefix))
767 fileNameOnly = xdgMenuPrefix + fileNameOnly;
769 TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir +
770 fileInfo.dirPath() +
"/" +
772 result = locate(
"xdgconf-menu", baseName);
775 if (result.isEmpty())
777 TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
778 result = locate(
"xdgconf-menu", baseName);
785 VFolderMenu::locateDirectoryFile(
const TQString &fileName)
787 if (fileName.isEmpty())
788 return TQString::null;
790 if (!TQDir::isRelativePath(fileName))
792 if (TDEStandardDirs::exists(fileName))
794 return TQString::null;
799 for(TQStringList::ConstIterator it = m_directoryDirs.begin();
800 it != m_directoryDirs.end();
803 tmp = (*it)+fileName;
804 if (TDEStandardDirs::exists(tmp))
808 return TQString::null;
812 VFolderMenu::initDirs()
814 m_defaultDataDirs = TQStringList::split(
':', TDEGlobal::dirs()->kfsstnd_prefixes());
815 TQString localDir = m_defaultDataDirs.first();
816 m_defaultDataDirs.remove(localDir);
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");
824 VFolderMenu::loadMenu(
const TQString &fileName)
826 m_defaultMergeDirs.clear();
828 if (!fileName.endsWith(
".menu"))
831 pushDocInfo(fileName);
832 m_defaultMergeDirs << m_docInfo.baseName+
"-merged/";
838 if (m_docInfo.path.isEmpty())
839 kdError(7021) << fileName <<
" not found in " << m_allDirectories << endl;
841 kdWarning(7021) <<
"Load error (" << m_docInfo.path <<
")" << endl;
845 TQDomElement e = m_doc.documentElement();
851 VFolderMenu::processCondition(TQDomElement &domElem, TQDict<KService> *items)
853 if (domElem.tagName() ==
"And")
855 TQDomNode n = domElem.firstChild();
859 TQDomElement e = n.toElement();
862 processCondition(e, items);
867 TQDict<KService> andItems;
868 while( !n.isNull() ) {
869 TQDomElement e = n.toElement();
870 if (e.tagName() ==
"Not")
873 TQDomNode n2 = e.firstChild();
874 while( !n2.isNull() ) {
875 TQDomElement e2 = n2.toElement();
877 processCondition(e2, &andItems);
878 excludeItems(items, &andItems);
879 n2 = n2.nextSibling();
885 processCondition(e, &andItems);
886 matchItems(items, &andItems);
891 else if (domElem.tagName() ==
"Or")
893 TQDomNode n = domElem.firstChild();
897 TQDomElement e = n.toElement();
900 processCondition(e, items);
905 TQDict<KService> orItems;
906 while( !n.isNull() ) {
907 TQDomElement e = n.toElement();
910 processCondition(e, &orItems);
911 includeItems(items, &orItems);
916 else if (domElem.tagName() ==
"Not")
918 for (appsInfo *info = m_appsInfoStack.first(); info; info = m_appsInfoStack.next())
920 for (TQDictIterator<KService> it( info->applications ); it.current(); ++it )
922 KService *s = it.current();
923 items->replace(s->menuId(), s);
927 TQDict<KService> notItems;
928 TQDomNode n = domElem.firstChild();
929 while( !n.isNull() ) {
930 TQDomElement e = n.toElement();
933 processCondition(e, ¬Items);
934 excludeItems(items, ¬Items);
939 else if (domElem.tagName() ==
"Category")
941 for (appsInfo *info = m_appsInfoStack.first(); info; info = m_appsInfoStack.next())
943 KService::List *list = info->dictCategories.find(domElem.text());
946 for(KService::List::ConstIterator it = list->begin(); it != list->end(); ++it)
949 items->replace(s->menuId(), s);
954 else if (domElem.tagName() ==
"All")
956 for (appsInfo *info = m_appsInfoStack.first(); info; info = m_appsInfoStack.next())
958 for (TQDictIterator<KService> it( info->applications ); it.current(); ++it )
960 KService *s = it.current();
961 items->replace(s->menuId(), s);
965 else if (domElem.tagName() ==
"Filename")
967 TQString filename = domElem.text();
968 kdDebug(7021) <<
"Adding file " << filename << endl;
969 KService *s = findApplication(filename);
971 items->replace(filename, s);
976 VFolderMenu::loadApplications(
const TQString &dir,
const TQString &prefix)
978 kdDebug(7021) <<
"Looking up applications under " << dir << endl;
981 DIR *dp = opendir( TQFile::encodeName(dir));
986 KDE_struct_stat buff;
989 TQString _dotdot(
"..");
991 while( ( ep = readdir( dp ) ) != 0L )
993 TQString fn( TQFile::decodeName(ep->d_name));
994 if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() ==
'~')
997 TQString pathfn = dir + fn;
998 if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1001 if ( S_ISDIR( buff.st_mode )) {
1002 loadApplications(pathfn +
'/', prefix + fn +
'-');
1006 if ( S_ISREG( buff.st_mode))
1008 if (!fn.endsWith(
".desktop"))
1011 KService *service = 0;
1012 emit newService(pathfn, &service);
1014 addApplication(prefix+fn, service);
1021 VFolderMenu::processKDELegacyDirs()
1023 kdDebug(7021) <<
"processKDELegacyDirs()" << endl;
1025 TQDict<KService> items;
1026 TQString prefix =
"tde-";
1028 TQStringList relFiles;
1029 TQRegExp files(
"\\.(desktop|kdelnk)$");
1030 TQRegExp dirs(
"\\.directory$");
1032 (void) TDEGlobal::dirs()->findAllResources(
"apps",
1037 for(TQStringList::ConstIterator it = relFiles.begin();
1038 it != relFiles.end(); ++it)
1040 if (!m_forcedLegacyLoad && (dirs.search(*it) != -1))
1042 TQString name = *it;
1043 if (!name.endsWith(
"/.directory"))
1046 name = name.left(name.length()-11);
1048 SubMenu *newMenu =
new SubMenu;
1049 newMenu->directoryFile = locate(
"apps", *it);
1051 insertSubMenu(m_currentMenu, name, newMenu);
1055 if (files.search(*it) != -1)
1057 TQString name = *it;
1058 KService *service = 0;
1059 emit newService(name, &service);
1061 if (service && !m_forcedLegacyLoad)
1065 int i =
id.findRev(
'/');
1072 addApplication(
id, service);
1073 items.replace(service->menuId(), service);
1074 if (service->categories().isEmpty())
1075 insertService(m_currentMenu, name, service);
1080 markUsedApplications(&items);
1081 m_legacyLoaded =
true;
1085 VFolderMenu::processLegacyDir(
const TQString &dir,
const TQString &relDir,
const TQString &prefix)
1087 kdDebug(7021) <<
"processLegacyDir(" << dir <<
", " << relDir <<
", " << prefix <<
")" << endl;
1089 TQDict<KService> items;
1091 DIR *dp = opendir( TQFile::encodeName(dir));
1096 KDE_struct_stat buff;
1099 TQString _dotdot(
"..");
1101 while( ( ep = readdir( dp ) ) != 0L )
1103 TQString fn( TQFile::decodeName(ep->d_name));
1104 if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() ==
'~')
1107 TQString pathfn = dir + fn;
1108 if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1111 if ( S_ISDIR( buff.st_mode )) {
1112 SubMenu *parentMenu = m_currentMenu;
1114 m_currentMenu =
new SubMenu;
1115 m_currentMenu->name = fn;
1116 m_currentMenu->directoryFile = dir + fn +
"/.directory";
1118 parentMenu->subMenus.append(m_currentMenu);
1120 processLegacyDir(pathfn +
'/', relDir+fn+
'/', prefix);
1121 m_currentMenu = parentMenu;
1125 if ( S_ISREG( buff.st_mode))
1127 if (!fn.endsWith(
".desktop"))
1130 KService *service = 0;
1131 emit newService(pathfn, &service);
1134 TQString
id = prefix+fn;
1137 addApplication(
id, service);
1138 items.replace(service->menuId(), service);
1140 if (service->categories().isEmpty())
1141 m_currentMenu->items.replace(
id, service);
1146 markUsedApplications(&items);
1152 VFolderMenu::processMenu(TQDomElement &docElem,
int pass)
1154 SubMenu *parentMenu = m_currentMenu;
1155 unsigned int oldDirectoryDirsCount = m_directoryDirs.count();
1158 TQString directoryFile;
1159 bool onlyUnallocated =
false;
1160 bool isDeleted =
false;
1161 bool kdeLegacyDirsDone =
false;
1162 TQDomElement defaultLayoutNode;
1163 TQDomElement layoutNode;
1166 TQDomNode n = docElem.firstChild();
1167 while( !n.isNull() ) {
1168 TQDomElement e = n.toElement();
1169 if (e.tagName() ==
"Name")
1173 else if (e.tagName() ==
"Directory")
1175 directoryFile = e.text();
1177 else if (e.tagName() ==
"DirectoryDir")
1179 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1181 m_directoryDirs.prepend(dir);
1183 else if (e.tagName() ==
"OnlyUnallocated")
1185 onlyUnallocated =
true;
1187 else if (e.tagName() ==
"NotOnlyUnallocated")
1189 onlyUnallocated =
false;
1191 else if (e.tagName() ==
"Deleted")
1195 else if (e.tagName() ==
"NotDeleted")
1199 else if (e.tagName() ==
"DefaultLayout")
1201 defaultLayoutNode = e;
1203 else if (e.tagName() ==
"Layout")
1207 n = n.nextSibling();
1217 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1219 if (menu->name == name)
1221 m_currentMenu = menu;
1230 m_currentMenu =
new SubMenu;
1231 m_currentMenu->name = name;
1234 parentMenu->subMenus.append(m_currentMenu);
1236 m_rootMenu = m_currentMenu;
1238 if (directoryFile.isEmpty())
1240 kdDebug(7021) <<
"Menu " << name <<
" does not specify a directory file." << endl;
1244 TQString tmp = locateDirectoryFile(directoryFile);
1245 if (! tmp.isEmpty())
1246 m_currentMenu->directoryFile = tmp;
1247 m_currentMenu->isDeleted = isDeleted;
1249 m_currentMenu->defaultLayoutNode = defaultLayoutNode;
1250 m_currentMenu->layoutNode = layoutNode;
1257 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1259 if (menu->name == name)
1261 m_currentMenu = menu;
1268 m_currentMenu = m_rootMenu;
1276 TQDomNode n = docElem.firstChild();
1277 while( !n.isNull() ) {
1278 TQDomElement e = n.toElement();
1279 if (e.tagName() ==
"AppDir")
1282 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1284 registerDirectory(dir);
1286 loadApplications(dir, TQString::null);
1288 else if (e.tagName() ==
"KDELegacyDirs")
1291 if (!kdeLegacyDirsDone)
1293 kdDebug(7021) <<
"Processing KDE Legacy dirs for <KDE>" << endl;
1294 SubMenu *oldMenu = m_currentMenu;
1295 m_currentMenu =
new SubMenu;
1297 processKDELegacyDirs();
1299 m_legacyNodes.replace(
"<KDE>", m_currentMenu);
1300 m_currentMenu = oldMenu;
1302 kdeLegacyDirsDone =
true;
1305 else if (e.tagName() ==
"LegacyDir")
1308 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1310 TQString prefix = e.attributes().namedItem(
"prefix").toAttr().value();
1312 if (m_defaultLegacyDirs.contains(dir))
1314 if (!kdeLegacyDirsDone)
1316 kdDebug(7021) <<
"Processing KDE Legacy dirs for " << dir << endl;
1317 SubMenu *oldMenu = m_currentMenu;
1318 m_currentMenu =
new SubMenu;
1320 processKDELegacyDirs();
1322 m_legacyNodes.replace(
"<KDE>", m_currentMenu);
1323 m_currentMenu = oldMenu;
1325 kdeLegacyDirsDone =
true;
1330 SubMenu *oldMenu = m_currentMenu;
1331 m_currentMenu =
new SubMenu;
1333 registerDirectory(dir);
1335 processLegacyDir(dir, TQString::null, prefix);
1337 m_legacyNodes.replace(dir, m_currentMenu);
1338 m_currentMenu = oldMenu;
1341 n = n.nextSibling();
1347 if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
1349 n = docElem.firstChild();
1351 while( !n.isNull() ) {
1352 TQDomElement e = n.toElement();
1353 if (e.tagName() ==
"Include")
1355 TQDict<KService> items;
1357 TQDomNode n2 = e.firstChild();
1358 while( !n2.isNull() ) {
1359 TQDomElement e2 = n2.toElement();
1361 processCondition(e2, &items);
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);
1369 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items,
"After <Include>");
1371 n2 = n2.nextSibling();
1375 else if (e.tagName() ==
"Exclude")
1377 TQDict<KService> items;
1379 TQDomNode n2 = e.firstChild();
1380 while( !n2.isNull() ) {
1381 TQDomElement e2 = n2.toElement();
1383 processCondition(e2, &items);
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);
1389 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items,
"After <Exclude>");
1390 n2 = n2.nextSibling();
1394 n = n.nextSibling();
1398 n = docElem.firstChild();
1399 while( !n.isNull() ) {
1400 TQDomElement e = n.toElement();
1401 if (e.tagName() ==
"Menu")
1403 processMenu(e, pass);
1411 if (e.tagName() ==
"LegacyDir")
1414 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1415 SubMenu *legacyMenu = m_legacyNodes.find(dir);
1418 mergeMenu(m_currentMenu, legacyMenu);
1422 else if (e.tagName() ==
"KDELegacyDirs")
1425 TQString dir =
"<KDE>";
1426 SubMenu *legacyMenu = m_legacyNodes.find(dir);
1429 mergeMenu(m_currentMenu, legacyMenu);
1433 n = n.nextSibling();
1438 n = docElem.firstChild();
1439 while( !n.isNull() ) {
1440 TQDomElement e = n.toElement();
1441 if (e.tagName() ==
"Move")
1445 TQDomNode n2 = e.firstChild();
1446 while( !n2.isNull() ) {
1447 TQDomElement e2 = n2.toElement();
1448 if( e2.tagName() ==
"Old")
1450 if( e2.tagName() ==
"New")
1452 n2 = n2.nextSibling();
1454 kdDebug(7021) <<
"Moving " << orig <<
" to " << dest << endl;
1455 if (!orig.isEmpty() && !dest.isEmpty())
1457 SubMenu *menu = takeSubMenu(m_currentMenu, orig);
1460 insertSubMenu(m_currentMenu, dest, menu,
true);
1464 n = n.nextSibling();
1471 while (m_directoryDirs.count() > oldDirectoryDirsCount)
1472 m_directoryDirs.pop_front();
1474 m_currentMenu = parentMenu;
1479 static TQString parseAttribute(
const TQDomElement &e)
1482 if ( e.hasAttribute(
"show_empty" ) )
1484 TQString str = e.attribute(
"show_empty" );
1487 else if ( str==
"false" )
1490 kdDebug()<<
" Error in parsing show_empty attribute :"<<str<<endl;
1492 if ( e.hasAttribute(
"inline" ) )
1494 TQString str = e.attribute(
"inline" );
1497 else if ( str==
"false" )
1500 kdDebug()<<
" Error in parsing inlibe attribute :"<<str<<endl;
1502 if ( e.hasAttribute(
"inline_limit" ) )
1505 int value = e.attribute(
"inline_limit" ).toInt(&ok);
1507 option+=TQString(
"IL[%1] " ).arg( value );
1509 if ( e.hasAttribute(
"inline_header" ) )
1511 TQString str = e.attribute(
"inline_header" );
1514 else if ( str ==
"false" )
1517 kdDebug()<<
" Error in parsing of inline_header attribute :"<<str<<endl;
1520 if ( e.hasAttribute(
"inline_alias" ) && e.attribute(
"inline_alias" )==
"true")
1522 TQString str = e.attribute(
"inline_alias" );
1525 else if ( str==
"false" )
1528 kdDebug()<<
" Error in parsing inline_alias attribute :"<<str<<endl;
1530 if( !option.isEmpty())
1532 option = option.prepend(
":O");
1538 static TQStringList parseLayoutNode(
const TQDomElement &docElem)
1540 TQStringList layout;
1542 TQString optionDefaultLayout;
1543 if( docElem.tagName()==
"DefaultLayout")
1544 optionDefaultLayout = parseAttribute( docElem);
1545 if ( !optionDefaultLayout.isEmpty() )
1546 layout.append( optionDefaultLayout );
1548 TQDomNode n = docElem.firstChild();
1549 while( !n.isNull() ) {
1550 TQDomElement e = n.toElement();
1551 if (e.tagName() ==
"Separator")
1553 layout.append(
":S");
1555 else if (e.tagName() ==
"Filename")
1557 layout.append(e.text());
1559 else if (e.tagName() ==
"Menuname")
1561 layout.append(
"/"+e.text());
1562 TQString option = parseAttribute( e );
1563 if( !option.isEmpty())
1564 layout.append( option );
1566 else if (e.tagName() ==
"Merge")
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");
1577 n = n.nextSibling();
1583 VFolderMenu::layoutMenu(VFolderMenu::SubMenu *menu, TQStringList defaultLayout)
1585 if (!menu->defaultLayoutNode.isNull())
1587 defaultLayout = parseLayoutNode(menu->defaultLayoutNode);
1590 if (menu->layoutNode.isNull())
1592 menu->layoutList = defaultLayout;
1596 menu->layoutList = parseLayoutNode(menu->layoutNode);
1597 if (menu->layoutList.isEmpty())
1598 menu->layoutList = defaultLayout;
1601 for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
1603 layoutMenu(subMenu, defaultLayout);
1608 VFolderMenu::markUsedApplications(TQDict<KService> *items)
1610 for(TQDictIterator<KService> it(*items); it.current(); ++it)
1612 m_usedAppsDict.replace(it.current()->menuId(), it.current());
1616 VFolderMenu::SubMenu *
1617 VFolderMenu::parseMenu(
const TQString &file,
bool forceLegacyLoad)
1619 m_forcedLegacyLoad =
false;
1620 m_legacyLoaded =
false;
1623 TQStringList dirs = TDEGlobal::dirs()->resourceDirs(
"xdgconf-menu");
1624 for(TQStringList::ConstIterator it=dirs.begin();
1625 it != dirs.end(); ++it)
1627 registerDirectory(*it);
1633 m_rootMenu = m_currentMenu = 0;
1635 TQDomElement docElem = m_doc.documentElement();
1637 for (
int pass = 0; pass <= 2; pass++)
1639 processMenu(docElem, pass);
1643 buildApplicationIndex(
false);
1647 buildApplicationIndex(
true);
1651 TQStringList defaultLayout;
1652 defaultLayout <<
":M";
1653 defaultLayout <<
":F";
1654 layoutMenu(m_rootMenu, defaultLayout);
1658 if (!m_legacyLoaded && forceLegacyLoad)
1660 m_forcedLegacyLoad =
true;
1661 processKDELegacyDirs();
1668 VFolderMenu::setTrackId(
const TQString &
id)
1670 m_track = !
id.isEmpty();
1674 #include "vfolder_menu.moc"