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()
314 #define FOR_ALL_APPLICATIONS(it) \ 315 for(appsInfo *info = m_appsInfoStack.first(); \ 316 info; info = m_appsInfoStack.next()) \ 318 for(TQDictIterator<KService> it( info->applications ); \ 319 it.current(); ++it ) \ 321 #define FOR_ALL_APPLICATIONS_END } } 323 #define FOR_CATEGORY(category, it) \ 324 for(appsInfo *info = m_appsInfoStack.first(); \ 325 info; info = m_appsInfoStack.next()) \ 327 KService::List *list = info->dictCategories.find(category); \ 328 if (list) for(KService::List::ConstIterator it = list->begin(); \ 329 it != list->end(); ++it) \ 331 #define FOR_CATEGORY_END } } 334 VFolderMenu::findApplication(
const TQString &relPath)
336 for(appsInfo *info = m_appsInfoStack.first();
337 info; info = m_appsInfoStack.next())
339 KService *s = info->applications.find(relPath);
347 VFolderMenu::addApplication(
const TQString &
id, KService *service)
349 service->setMenuId(
id);
350 m_appsInfo->applications.replace(
id, service);
354 VFolderMenu::buildApplicationIndex(
bool unusedOnly)
356 TQPtrList<appsInfo>::ConstIterator appsInfo_it = m_appsInfoList.begin();
357 for( ; appsInfo_it != m_appsInfoList.end(); ++appsInfo_it )
359 appsInfo *info = *appsInfo_it;
360 info->dictCategories.clear();
361 for(TQDictIterator<KService> it( info->applications );
364 KService *s = it.current();
365 TQDictIterator<KService> tmpIt = it;
367 if (unusedOnly && m_usedAppsDict.find(s->menuId()))
370 info->applications.remove(tmpIt.currentKey());
374 TQStringList cats = s->categories();
375 for(TQStringList::ConstIterator it2 = cats.begin();
376 it2 != cats.end(); ++it2)
378 const TQString &cat = *it2;
379 KService::List *list = info->dictCategories.find(cat);
382 list =
new KService::List();
383 info->dictCategories.insert(cat, list);
392 VFolderMenu::createAppsInfo()
394 if (m_appsInfo)
return;
396 m_appsInfo =
new appsInfo;
397 m_appsInfoStack.prepend(m_appsInfo);
398 m_appsInfoList.append(m_appsInfo);
399 m_currentMenu->apps_info = m_appsInfo;
403 VFolderMenu::loadAppsInfo()
405 m_appsInfo = m_currentMenu->apps_info;
409 if (m_appsInfoStack.first() == m_appsInfo)
412 m_appsInfoStack.prepend(m_appsInfo);
416 VFolderMenu::unloadAppsInfo()
418 m_appsInfo = m_currentMenu->apps_info;
422 if (m_appsInfoStack.first() != m_appsInfo)
427 m_appsInfoStack.remove(m_appsInfo);
432 VFolderMenu::absoluteDir(
const TQString &_dir,
const TQString &baseDir,
bool keepRelativeToCfg)
435 if (TQDir::isRelativePath(dir))
439 if (!dir.endsWith(
"/"))
442 if (TQDir::isRelativePath(dir) && !keepRelativeToCfg)
444 dir = TDEGlobal::dirs()->findResource(
"xdgconf-menu", dir);
447 dir = TDEGlobal::dirs()->realPath(dir);
452 static void tagBaseDir(TQDomDocument &doc,
const TQString &tag,
const TQString &dir)
454 TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
455 for(
int i = 0; i < (int)mergeFileList.count(); i++)
457 TQDomAttr attr = doc.createAttribute(
"__BaseDir");
459 mergeFileList.item(i).toElement().setAttributeNode(attr);
463 static void tagBasePath(TQDomDocument &doc,
const TQString &tag,
const TQString &path)
465 TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
466 for(
int i = 0; i < (int)mergeFileList.count(); i++)
468 TQDomAttr attr = doc.createAttribute(
"__BasePath");
470 mergeFileList.item(i).toElement().setAttributeNode(attr);
475 VFolderMenu::loadDoc()
478 if ( m_docInfo.path.isEmpty() )
482 TQFile file( m_docInfo.path );
483 if ( !file.open( IO_ReadOnly ) )
485 kdWarning(7021) <<
"Could not open " << m_docInfo.path << endl;
491 if ( !doc.setContent( &file, &errorMsg, &errorRow, &errorCol ) ) {
492 kdWarning(7021) <<
"Parse error in " << m_docInfo.path <<
", line " << errorRow <<
", col " << errorCol <<
": " << errorMsg << endl;
498 tagBaseDir(doc,
"MergeFile", m_docInfo.baseDir);
499 tagBasePath(doc,
"MergeFile", m_docInfo.path);
500 tagBaseDir(doc,
"MergeDir", m_docInfo.baseDir);
501 tagBaseDir(doc,
"DirectoryDir", m_docInfo.baseDir);
502 tagBaseDir(doc,
"AppDir", m_docInfo.baseDir);
503 tagBaseDir(doc,
"LegacyDir", m_docInfo.baseDir);
510 VFolderMenu::mergeFile(TQDomElement &parent,
const TQDomNode &mergeHere)
512 kdDebug(7021) <<
"VFolderMenu::mergeFile: " << m_docInfo.path << endl;
513 TQDomDocument doc = loadDoc();
515 TQDomElement docElem = doc.documentElement();
516 TQDomNode n = docElem.firstChild();
517 TQDomNode last = mergeHere;
520 TQDomElement e = n.toElement();
521 TQDomNode next = n.nextSibling();
528 else if (e.tagName() !=
"Name")
530 parent.insertAfter(n, last);
534 docElem.removeChild(n);
541 VFolderMenu::mergeMenus(TQDomElement &docElem, TQString &name)
543 TQMap<TQString,TQDomElement> menuNodes;
544 TQMap<TQString,TQDomElement> directoryNodes;
545 TQMap<TQString,TQDomElement> appDirNodes;
546 TQMap<TQString,TQDomElement> directoryDirNodes;
547 TQMap<TQString,TQDomElement> legacyDirNodes;
548 TQDomElement defaultLayoutNode;
549 TQDomElement layoutNode;
551 TQDomNode n = docElem.firstChild();
552 while( !n.isNull() ) {
553 TQDomElement e = n.toElement();
557 else if( e.tagName() ==
"DefaultAppDirs") {
559 replaceNode(docElem, n, m_defaultAppDirs,
"AppDir");
562 else if( e.tagName() ==
"DefaultDirectoryDirs") {
564 replaceNode(docElem, n, m_defaultDirectoryDirs,
"DirectoryDir");
567 else if( e.tagName() ==
"DefaultMergeDirs") {
569 replaceNode(docElem, n, m_defaultMergeDirs,
"MergeDir");
572 else if( e.tagName() ==
"AppDir") {
574 foldNode(docElem, e, appDirNodes);
576 else if( e.tagName() ==
"DirectoryDir") {
578 foldNode(docElem, e, directoryDirNodes);
580 else if( e.tagName() ==
"LegacyDir") {
582 foldNode(docElem, e, legacyDirNodes);
584 else if( e.tagName() ==
"Directory") {
586 foldNode(docElem, e, directoryNodes);
588 else if( e.tagName() ==
"Move") {
591 TQDomNode n2 = e.firstChild();
592 while( !n2.isNull() ) {
593 TQDomElement e2 = n2.toElement();
594 if( e2.tagName() ==
"Old")
599 n2 = n2.nextSibling();
601 foldNode(docElem, e, appDirNodes, orig);
603 else if( e.tagName() ==
"Menu") {
606 TQMap<TQString,TQDomElement>::iterator it = menuNodes.find(name);
607 if (it != menuNodes.end())
609 TQDomElement docElem2 = *it;
610 TQDomNode n2 = docElem2.firstChild();
611 TQDomNode first = e.firstChild();
612 while( !n2.isNull() ) {
613 TQDomElement e2 = n2.toElement();
614 TQDomNode n3 = n2.nextSibling();
615 e.insertBefore(n2, first);
616 docElem2.removeChild(n2);
622 docElem.removeChild(docElem2);
623 menuNodes.remove(it);
625 menuNodes.insert(name, e);
627 else if( e.tagName() ==
"MergeFile") {
628 if ((e.attribute(
"type") ==
"parent"))
629 pushDocInfoParent(e.attribute(
"__BasePath"), e.attribute(
"__BaseDir"));
631 pushDocInfo(e.text(), e.attribute(
"__BaseDir"));
633 if (!m_docInfo.path.isEmpty())
634 mergeFile(docElem, n);
639 docElem.removeChild(last);
642 else if( e.tagName() ==
"MergeDir") {
643 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"),
true);
645 TQStringList dirs = TDEGlobal::dirs()->findDirs(
"xdgconf-menu", dir);
646 for(TQStringList::ConstIterator it=dirs.begin();
647 it != dirs.end(); ++it)
649 registerDirectory(*it);
652 TQStringList fileList;
653 if (!TQDir::isRelativePath(dir))
656 fileList = TDEGlobal::dirs()->findAllResources(
"xdgconf-menu", dir+
"*.menu",
false,
false);
661 (void) TDEGlobal::dirs()->findAllResources(
"xdgconf-menu", dir+
"*.menu",
false,
true, fileList);
664 for(TQStringList::ConstIterator it=fileList.begin();
665 it != fileList.end(); ++it)
668 mergeFile(docElem, n);
674 docElem.removeChild(last);
678 else if( e.tagName() ==
"Name") {
681 else if( e.tagName() ==
"DefaultLayout") {
682 if (!defaultLayoutNode.isNull())
683 docElem.removeChild(defaultLayoutNode);
684 defaultLayoutNode = e;
686 else if( e.tagName() ==
"Layout") {
687 if (!layoutNode.isNull())
688 docElem.removeChild(layoutNode);
696 VFolderMenu::pushDocInfo(
const TQString &fileName,
const TQString &baseDir)
698 m_docInfoStack.push(m_docInfo);
699 if (!baseDir.isEmpty())
701 if (!TQDir::isRelativePath(baseDir))
702 m_docInfo.baseDir = TDEGlobal::dirs()->relativeLocation(
"xdgconf-menu", baseDir);
704 m_docInfo.baseDir = baseDir;
707 TQString baseName = fileName;
708 if (!TQDir::isRelativePath(baseName))
709 registerFile(baseName);
711 baseName = m_docInfo.baseDir + baseName;
713 m_docInfo.path = locateMenuFile(fileName);
714 if (m_docInfo.path.isEmpty())
716 m_docInfo.baseDir = TQString::null;
717 m_docInfo.baseName = TQString::null;
718 kdDebug(7021) <<
"Menu " << fileName <<
" not found." << endl;
722 i = baseName.findRev(
'/');
725 m_docInfo.baseDir = baseName.left(i+1);
726 m_docInfo.baseName = baseName.mid(i+1, baseName.length() - i - 6);
730 m_docInfo.baseDir = TQString::null;
731 m_docInfo.baseName = baseName.left( baseName.length() - 5 );
736 VFolderMenu::pushDocInfoParent(
const TQString &basePath,
const TQString &baseDir)
738 m_docInfoStack.push(m_docInfo);
740 m_docInfo.baseDir = baseDir;
742 TQString fileName = basePath.mid(basePath.findRev(
'/')+1);
743 m_docInfo.baseName = fileName.left( fileName.length() - 5 );
744 TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
746 TQStringList result = TDEGlobal::dirs()->findAllResources(
"xdgconf-menu", baseName);
748 while( !result.isEmpty() && (result[0] != basePath))
749 result.remove(result.begin());
751 if (result.count() <= 1)
753 m_docInfo.path = TQString::null;
756 m_docInfo.path = result[1];
760 VFolderMenu::popDocInfo()
762 m_docInfo = m_docInfoStack.pop();
766 VFolderMenu::locateMenuFile(
const TQString &fileName)
768 if (!TQDir::isRelativePath(fileName))
770 if (TDEStandardDirs::exists(fileName))
772 return TQString::null;
779 TQString xdgMenuPrefix =
"kde-";
780 if (!xdgMenuPrefix.isEmpty())
782 TQFileInfo fileInfo(fileName);
784 TQString fileNameOnly = fileInfo.fileName();
785 if (!fileNameOnly.startsWith(xdgMenuPrefix))
786 fileNameOnly = xdgMenuPrefix + fileNameOnly;
788 TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir +
789 fileInfo.dirPath() +
"/" +
791 result = locate(
"xdgconf-menu", baseName);
794 if (result.isEmpty())
796 TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
797 result = locate(
"xdgconf-menu", baseName);
804 VFolderMenu::locateDirectoryFile(
const TQString &fileName)
806 if (fileName.isEmpty())
807 return TQString::null;
809 if (!TQDir::isRelativePath(fileName))
811 if (TDEStandardDirs::exists(fileName))
813 return TQString::null;
818 for(TQStringList::ConstIterator it = m_directoryDirs.begin();
819 it != m_directoryDirs.end();
822 tmp = (*it)+fileName;
823 if (TDEStandardDirs::exists(tmp))
827 return TQString::null;
831 VFolderMenu::initDirs()
833 m_defaultDataDirs = TQStringList::split(
':', TDEGlobal::dirs()->kfsstnd_prefixes());
834 TQString localDir = m_defaultDataDirs.first();
835 m_defaultDataDirs.remove(localDir);
837 m_defaultAppDirs = TDEGlobal::dirs()->findDirs(
"xdgdata-apps", TQString::null);
838 m_defaultDirectoryDirs = TDEGlobal::dirs()->findDirs(
"xdgdata-dirs", TQString::null);
839 m_defaultLegacyDirs = TDEGlobal::dirs()->resourceDirs(
"apps");
843 VFolderMenu::loadMenu(
const TQString &fileName)
845 m_defaultMergeDirs.clear();
847 if (!fileName.endsWith(
".menu"))
850 pushDocInfo(fileName);
851 m_defaultMergeDirs << m_docInfo.baseName+
"-merged/";
857 if (m_docInfo.path.isEmpty())
858 kdError(7021) << fileName <<
" not found in " << m_allDirectories << endl;
860 kdWarning(7021) <<
"Load error (" << m_docInfo.path <<
")" << endl;
864 TQDomElement e = m_doc.documentElement();
870 VFolderMenu::processCondition(TQDomElement &domElem, TQDict<KService> *items)
872 if (domElem.tagName() ==
"And")
874 TQDomNode n = domElem.firstChild();
878 TQDomElement e = n.toElement();
881 processCondition(e, items);
886 TQDict<KService> andItems;
887 while( !n.isNull() ) {
888 TQDomElement e = n.toElement();
889 if (e.tagName() ==
"Not")
892 TQDomNode n2 = e.firstChild();
893 while( !n2.isNull() ) {
894 TQDomElement e2 = n2.toElement();
896 processCondition(e2, &andItems);
897 excludeItems(items, &andItems);
898 n2 = n2.nextSibling();
904 processCondition(e, &andItems);
905 matchItems(items, &andItems);
910 else if (domElem.tagName() ==
"Or")
912 TQDomNode n = domElem.firstChild();
916 TQDomElement e = n.toElement();
919 processCondition(e, items);
924 TQDict<KService> orItems;
925 while( !n.isNull() ) {
926 TQDomElement e = n.toElement();
929 processCondition(e, &orItems);
930 includeItems(items, &orItems);
935 else if (domElem.tagName() ==
"Not")
937 FOR_ALL_APPLICATIONS(it)
939 KService *s = it.current();
940 items->replace(s->menuId(), s);
942 FOR_ALL_APPLICATIONS_END
944 TQDict<KService> notItems;
945 TQDomNode n = domElem.firstChild();
946 while( !n.isNull() ) {
947 TQDomElement e = n.toElement();
950 processCondition(e, ¬Items);
951 excludeItems(items, ¬Items);
956 else if (domElem.tagName() ==
"Category")
958 FOR_CATEGORY(domElem.text(), it)
961 items->replace(s->menuId(), s);
965 else if (domElem.tagName() ==
"All")
967 FOR_ALL_APPLICATIONS(it)
969 KService *s = it.current();
970 items->replace(s->menuId(), s);
972 FOR_ALL_APPLICATIONS_END
974 else if (domElem.tagName() ==
"Filename")
976 TQString filename = domElem.text();
977 kdDebug(7021) <<
"Adding file " << filename << endl;
978 KService *s = findApplication(filename);
980 items->replace(filename, s);
985 VFolderMenu::loadApplications(
const TQString &dir,
const TQString &prefix)
987 kdDebug(7021) <<
"Looking up applications under " << dir << endl;
990 DIR *dp = opendir( TQFile::encodeName(dir));
995 KDE_struct_stat buff;
998 TQString _dotdot(
"..");
1000 while( ( ep = readdir( dp ) ) != 0L )
1002 TQString fn( TQFile::decodeName(ep->d_name));
1003 if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() ==
'~')
1006 TQString pathfn = dir + fn;
1007 if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1010 if ( S_ISDIR( buff.st_mode )) {
1011 loadApplications(pathfn +
'/', prefix + fn +
'-');
1015 if ( S_ISREG( buff.st_mode))
1017 if (!fn.endsWith(
".desktop"))
1020 KService *service = 0;
1021 emit newService(pathfn, &service);
1023 addApplication(prefix+fn, service);
1030 VFolderMenu::processKDELegacyDirs()
1032 kdDebug(7021) <<
"processKDELegacyDirs()" << endl;
1034 TQDict<KService> items;
1035 TQString prefix =
"kde-";
1037 TQStringList relFiles;
1038 TQRegExp files(
"\\.(desktop|kdelnk)$");
1039 TQRegExp dirs(
"\\.directory$");
1041 (void) TDEGlobal::dirs()->findAllResources(
"apps",
1046 for(TQStringList::ConstIterator it = relFiles.begin();
1047 it != relFiles.end(); ++it)
1049 if (!m_forcedLegacyLoad && (dirs.search(*it) != -1))
1051 TQString name = *it;
1052 if (!name.endsWith(
"/.directory"))
1055 name = name.left(name.length()-11);
1057 SubMenu *newMenu =
new SubMenu;
1058 newMenu->directoryFile = locate(
"apps", *it);
1060 insertSubMenu(m_currentMenu, name, newMenu);
1064 if (files.search(*it) != -1)
1066 TQString name = *it;
1067 KService *service = 0;
1068 emit newService(name, &service);
1070 if (service && !m_forcedLegacyLoad)
1074 int i =
id.findRev(
'/');
1081 addApplication(
id, service);
1082 items.replace(service->menuId(), service);
1083 if (service->categories().isEmpty())
1084 insertService(m_currentMenu, name, service);
1089 markUsedApplications(&items);
1090 m_legacyLoaded =
true;
1094 VFolderMenu::processLegacyDir(
const TQString &dir,
const TQString &relDir,
const TQString &prefix)
1096 kdDebug(7021) <<
"processLegacyDir(" << dir <<
", " << relDir <<
", " << prefix <<
")" << endl;
1098 TQDict<KService> items;
1100 DIR *dp = opendir( TQFile::encodeName(dir));
1105 KDE_struct_stat buff;
1108 TQString _dotdot(
"..");
1110 while( ( ep = readdir( dp ) ) != 0L )
1112 TQString fn( TQFile::decodeName(ep->d_name));
1113 if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() ==
'~')
1116 TQString pathfn = dir + fn;
1117 if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
1120 if ( S_ISDIR( buff.st_mode )) {
1121 SubMenu *parentMenu = m_currentMenu;
1123 m_currentMenu =
new SubMenu;
1124 m_currentMenu->name = fn;
1125 m_currentMenu->directoryFile = dir + fn +
"/.directory";
1127 parentMenu->subMenus.append(m_currentMenu);
1129 processLegacyDir(pathfn +
'/', relDir+fn+
'/', prefix);
1130 m_currentMenu = parentMenu;
1134 if ( S_ISREG( buff.st_mode))
1136 if (!fn.endsWith(
".desktop"))
1139 KService *service = 0;
1140 emit newService(pathfn, &service);
1143 TQString
id = prefix+fn;
1146 addApplication(
id, service);
1147 items.replace(service->menuId(), service);
1149 if (service->categories().isEmpty())
1150 m_currentMenu->items.replace(
id, service);
1155 markUsedApplications(&items);
1161 VFolderMenu::processMenu(TQDomElement &docElem,
int pass)
1163 SubMenu *parentMenu = m_currentMenu;
1164 unsigned int oldDirectoryDirsCount = m_directoryDirs.count();
1167 TQString directoryFile;
1168 bool onlyUnallocated =
false;
1169 bool isDeleted =
false;
1170 bool kdeLegacyDirsDone =
false;
1171 TQDomElement defaultLayoutNode;
1172 TQDomElement layoutNode;
1175 TQDomNode n = docElem.firstChild();
1176 while( !n.isNull() ) {
1177 TQDomElement e = n.toElement();
1178 if (e.tagName() ==
"Name")
1182 else if (e.tagName() ==
"Directory")
1184 directoryFile = e.text();
1186 else if (e.tagName() ==
"DirectoryDir")
1188 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1190 m_directoryDirs.prepend(dir);
1192 else if (e.tagName() ==
"OnlyUnallocated")
1194 onlyUnallocated =
true;
1196 else if (e.tagName() ==
"NotOnlyUnallocated")
1198 onlyUnallocated =
false;
1200 else if (e.tagName() ==
"Deleted")
1204 else if (e.tagName() ==
"NotDeleted")
1208 else if (e.tagName() ==
"DefaultLayout")
1210 defaultLayoutNode = e;
1212 else if (e.tagName() ==
"Layout")
1216 n = n.nextSibling();
1226 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1228 if (menu->name == name)
1230 m_currentMenu = menu;
1239 m_currentMenu =
new SubMenu;
1240 m_currentMenu->name = name;
1243 parentMenu->subMenus.append(m_currentMenu);
1245 m_rootMenu = m_currentMenu;
1247 if (directoryFile.isEmpty())
1249 kdDebug(7021) <<
"Menu " << name <<
" does not specify a directory file." << endl;
1253 TQString tmp = locateDirectoryFile(directoryFile);
1254 if (! tmp.isEmpty())
1255 m_currentMenu->directoryFile = tmp;
1256 m_currentMenu->isDeleted = isDeleted;
1258 m_currentMenu->defaultLayoutNode = defaultLayoutNode;
1259 m_currentMenu->layoutNode = layoutNode;
1266 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
1268 if (menu->name == name)
1270 m_currentMenu = menu;
1277 m_currentMenu = m_rootMenu;
1285 TQDomNode n = docElem.firstChild();
1286 while( !n.isNull() ) {
1287 TQDomElement e = n.toElement();
1288 if (e.tagName() ==
"AppDir")
1291 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1293 registerDirectory(dir);
1295 loadApplications(dir, TQString::null);
1297 else if (e.tagName() ==
"KDELegacyDirs")
1300 if (!kdeLegacyDirsDone)
1302 kdDebug(7021) <<
"Processing KDE Legacy dirs for <KDE>" << endl;
1303 SubMenu *oldMenu = m_currentMenu;
1304 m_currentMenu =
new SubMenu;
1306 processKDELegacyDirs();
1308 m_legacyNodes.replace(
"<KDE>", m_currentMenu);
1309 m_currentMenu = oldMenu;
1311 kdeLegacyDirsDone =
true;
1314 else if (e.tagName() ==
"LegacyDir")
1317 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1319 TQString prefix = e.attributes().namedItem(
"prefix").toAttr().value();
1321 if (m_defaultLegacyDirs.contains(dir))
1323 if (!kdeLegacyDirsDone)
1325 kdDebug(7021) <<
"Processing KDE Legacy dirs for " << dir << endl;
1326 SubMenu *oldMenu = m_currentMenu;
1327 m_currentMenu =
new SubMenu;
1329 processKDELegacyDirs();
1331 m_legacyNodes.replace(
"<KDE>", m_currentMenu);
1332 m_currentMenu = oldMenu;
1334 kdeLegacyDirsDone =
true;
1339 SubMenu *oldMenu = m_currentMenu;
1340 m_currentMenu =
new SubMenu;
1342 registerDirectory(dir);
1344 processLegacyDir(dir, TQString::null, prefix);
1346 m_legacyNodes.replace(dir, m_currentMenu);
1347 m_currentMenu = oldMenu;
1350 n = n.nextSibling();
1356 if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
1358 n = docElem.firstChild();
1360 while( !n.isNull() ) {
1361 TQDomElement e = n.toElement();
1362 if (e.tagName() ==
"Include")
1364 TQDict<KService> items;
1366 TQDomNode n2 = e.firstChild();
1367 while( !n2.isNull() ) {
1368 TQDomElement e2 = n2.toElement();
1370 processCondition(e2, &items);
1372 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items,
"Before <Include>");
1373 includeItems(&(m_currentMenu->items), &items);
1374 excludeItems(&(m_currentMenu->excludeItems), &items);
1375 markUsedApplications(&items);
1378 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items,
"After <Include>");
1380 n2 = n2.nextSibling();
1384 else if (e.tagName() ==
"Exclude")
1386 TQDict<KService> items;
1388 TQDomNode n2 = e.firstChild();
1389 while( !n2.isNull() ) {
1390 TQDomElement e2 = n2.toElement();
1392 processCondition(e2, &items);
1394 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items,
"Before <Exclude>");
1395 excludeItems(&(m_currentMenu->items), &items);
1396 includeItems(&(m_currentMenu->excludeItems), &items);
1398 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items,
"After <Exclude>");
1399 n2 = n2.nextSibling();
1403 n = n.nextSibling();
1407 n = docElem.firstChild();
1408 while( !n.isNull() ) {
1409 TQDomElement e = n.toElement();
1410 if (e.tagName() ==
"Menu")
1412 processMenu(e, pass);
1420 if (e.tagName() ==
"LegacyDir")
1423 TQString dir = absoluteDir(e.text(), e.attribute(
"__BaseDir"));
1424 SubMenu *legacyMenu = m_legacyNodes.find(dir);
1427 mergeMenu(m_currentMenu, legacyMenu);
1431 else if (e.tagName() ==
"KDELegacyDirs")
1434 TQString dir =
"<KDE>";
1435 SubMenu *legacyMenu = m_legacyNodes.find(dir);
1438 mergeMenu(m_currentMenu, legacyMenu);
1442 n = n.nextSibling();
1447 n = docElem.firstChild();
1448 while( !n.isNull() ) {
1449 TQDomElement e = n.toElement();
1450 if (e.tagName() ==
"Move")
1454 TQDomNode n2 = e.firstChild();
1455 while( !n2.isNull() ) {
1456 TQDomElement e2 = n2.toElement();
1457 if( e2.tagName() ==
"Old")
1459 if( e2.tagName() ==
"New")
1461 n2 = n2.nextSibling();
1463 kdDebug(7021) <<
"Moving " << orig <<
" to " << dest << endl;
1464 if (!orig.isEmpty() && !dest.isEmpty())
1466 SubMenu *menu = takeSubMenu(m_currentMenu, orig);
1469 insertSubMenu(m_currentMenu, dest, menu,
true);
1473 n = n.nextSibling();
1480 while (m_directoryDirs.count() > oldDirectoryDirsCount)
1481 m_directoryDirs.pop_front();
1483 m_currentMenu = parentMenu;
1488 static TQString parseAttribute(
const TQDomElement &e)
1491 if ( e.hasAttribute(
"show_empty" ) )
1493 TQString str = e.attribute(
"show_empty" );
1496 else if ( str==
"false" )
1499 kdDebug()<<
" Error in parsing show_empty attribute :"<<str<<endl;
1501 if ( e.hasAttribute(
"inline" ) )
1503 TQString str = e.attribute(
"inline" );
1506 else if ( str==
"false" )
1509 kdDebug()<<
" Error in parsing inlibe attribute :"<<str<<endl;
1511 if ( e.hasAttribute(
"inline_limit" ) )
1514 int value = e.attribute(
"inline_limit" ).toInt(&ok);
1516 option+=TQString(
"IL[%1] " ).arg( value );
1518 if ( e.hasAttribute(
"inline_header" ) )
1520 TQString str = e.attribute(
"inline_header" );
1523 else if ( str ==
"false" )
1526 kdDebug()<<
" Error in parsing of inline_header attribute :"<<str<<endl;
1529 if ( e.hasAttribute(
"inline_alias" ) && e.attribute(
"inline_alias" )==
"true")
1531 TQString str = e.attribute(
"inline_alias" );
1534 else if ( str==
"false" )
1537 kdDebug()<<
" Error in parsing inline_alias attribute :"<<str<<endl;
1539 if( !option.isEmpty())
1541 option = option.prepend(
":O");
1547 static TQStringList parseLayoutNode(
const TQDomElement &docElem)
1549 TQStringList layout;
1551 TQString optionDefaultLayout;
1552 if( docElem.tagName()==
"DefaultLayout")
1553 optionDefaultLayout = parseAttribute( docElem);
1554 if ( !optionDefaultLayout.isEmpty() )
1555 layout.append( optionDefaultLayout );
1557 TQDomNode n = docElem.firstChild();
1558 while( !n.isNull() ) {
1559 TQDomElement e = n.toElement();
1560 if (e.tagName() ==
"Separator")
1562 layout.append(
":S");
1564 else if (e.tagName() ==
"Filename")
1566 layout.append(e.text());
1568 else if (e.tagName() ==
"Menuname")
1570 layout.append(
"/"+e.text());
1571 TQString option = parseAttribute( e );
1572 if( !option.isEmpty())
1573 layout.append( option );
1575 else if (e.tagName() ==
"Merge")
1577 TQString type = e.attributeNode(
"type").value();
1578 if (type ==
"files")
1579 layout.append(
":F");
1580 else if (type ==
"menus")
1581 layout.append(
":M");
1582 else if (type ==
"all")
1583 layout.append(
":A");
1586 n = n.nextSibling();
1592 VFolderMenu::layoutMenu(VFolderMenu::SubMenu *menu, TQStringList defaultLayout)
1594 if (!menu->defaultLayoutNode.isNull())
1596 defaultLayout = parseLayoutNode(menu->defaultLayoutNode);
1599 if (menu->layoutNode.isNull())
1601 menu->layoutList = defaultLayout;
1605 menu->layoutList = parseLayoutNode(menu->layoutNode);
1606 if (menu->layoutList.isEmpty())
1607 menu->layoutList = defaultLayout;
1610 for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
1612 layoutMenu(subMenu, defaultLayout);
1617 VFolderMenu::markUsedApplications(TQDict<KService> *items)
1619 for(TQDictIterator<KService> it(*items); it.current(); ++it)
1621 m_usedAppsDict.replace(it.current()->menuId(), it.current());
1625 VFolderMenu::SubMenu *
1626 VFolderMenu::parseMenu(
const TQString &file,
bool forceLegacyLoad)
1628 m_forcedLegacyLoad =
false;
1629 m_legacyLoaded =
false;
1632 TQStringList dirs = TDEGlobal::dirs()->resourceDirs(
"xdgconf-menu");
1633 for(TQStringList::ConstIterator it=dirs.begin();
1634 it != dirs.end(); ++it)
1636 registerDirectory(*it);
1642 m_rootMenu = m_currentMenu = 0;
1644 TQDomElement docElem = m_doc.documentElement();
1646 for (
int pass = 0; pass <= 2; pass++)
1648 processMenu(docElem, pass);
1652 buildApplicationIndex(
false);
1656 buildApplicationIndex(
true);
1660 TQStringList defaultLayout;
1661 defaultLayout <<
":M";
1662 defaultLayout <<
":F";
1663 layoutMenu(m_rootMenu, defaultLayout);
1667 if (!m_legacyLoaded && forceLegacyLoad)
1669 m_forcedLegacyLoad =
true;
1670 processKDELegacyDirs();
1677 VFolderMenu::setTrackId(
const TQString &
id)
1679 m_track = !
id.isEmpty();
1683 #include "vfolder_menu.moc"