00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "vfolder_menu.h"
00020 #include "kbuildservicefactory.h"
00021
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <unistd.h>
00025 #include <dirent.h>
00026 #include <config.h>
00027
00028 #include <kdebug.h>
00029 #include <kglobal.h>
00030 #include <kstandarddirs.h>
00031 #include <kservice.h>
00032 #include <kde_file.h>
00033
00034 #include <QtCore/QMap>
00035 #include <QtCore/QFile>
00036 #include <QtCore/QDir>
00037 #include <QtCore/QRegExp>
00038 #include <QtCore/QDirIterator>
00039
00040 static void foldNode(QDomElement &docElem, QDomElement &e, QMap<QString,QDomElement> &dupeList, QString s=QString())
00041 {
00042 if (s.isEmpty())
00043 s = e.text();
00044 QMap<QString,QDomElement>::iterator it = dupeList.find(s);
00045 if (it != dupeList.end())
00046 {
00047 kDebug(7021) << e.tagName() << "and" << s << "requires combining!";
00048
00049 docElem.removeChild(*it);
00050 dupeList.erase(it);
00051 }
00052 dupeList.insert(s, e);
00053 }
00054
00055 static void replaceNode(QDomElement &docElem, QDomNode &n, const QStringList &list, const QString &tag)
00056 {
00057 for(QStringList::ConstIterator it = list.begin();
00058 it != list.end(); ++it)
00059 {
00060 QDomElement e = docElem.ownerDocument().createElement(tag);
00061 QDomText txt = docElem.ownerDocument().createTextNode(*it);
00062 e.appendChild(txt);
00063 docElem.insertAfter(e, n);
00064 }
00065
00066 QDomNode next = n.nextSibling();
00067 docElem.removeChild(n);
00068 n = next;
00069
00070 }
00071
00072 void VFolderMenu::registerFile(const QString &file)
00073 {
00074 int i = file.lastIndexOf('/');
00075 if (i < 0)
00076 return;
00077
00078 QString dir = file.left(i+1);
00079 registerDirectory(dir);
00080 }
00081
00082 void VFolderMenu::registerDirectory(const QString &directory)
00083 {
00084 m_allDirectories.append(directory);
00085 }
00086
00087 QStringList VFolderMenu::allDirectories()
00088 {
00089 if (m_allDirectories.isEmpty())
00090 return m_allDirectories;
00091 m_allDirectories.sort();
00092
00093 QStringList::Iterator it = m_allDirectories.begin();
00094 QString previous = *it++;
00095 for(;it != m_allDirectories.end();)
00096 {
00097 if ((*it).startsWith(previous))
00098 {
00099 it = m_allDirectories.erase(it);
00100 }
00101 else
00102 {
00103 previous = *it;
00104 ++it;
00105 }
00106 }
00107 return m_allDirectories;
00108 }
00109
00110 static void
00111 track(const QString &menuId, const QString &menuName, const QHash<QString,KService::Ptr>& includeList, const QHash<QString,KService::Ptr>& excludeList, const QHash<QString,KService::Ptr>& itemList, const QString &comment)
00112 {
00113 if (itemList.contains(menuId))
00114 printf("%s: %s INCL %d EXCL %d\n", qPrintable(menuName), qPrintable(comment), includeList.contains(menuId) ? 1 : 0, excludeList.contains(menuId) ? 1 : 0);
00115 }
00116
00117 void
00118 VFolderMenu::includeItems(QHash<QString,KService::Ptr>& items1, const QHash<QString,KService::Ptr>& items2)
00119 {
00120 foreach (const KService::Ptr &p, items2) {
00121 items1.insert(p->menuId(), p);
00122 }
00123 }
00124
00125 void
00126 VFolderMenu::matchItems(QHash<QString,KService::Ptr>& items1, const QHash<QString,KService::Ptr>& items2)
00127 {
00128 foreach (const KService::Ptr &p, items1)
00129 {
00130 QString id = p->menuId();
00131 if (!items2.contains(id))
00132 items1.remove(id);
00133 }
00134 }
00135
00136 void
00137 VFolderMenu::excludeItems(QHash<QString,KService::Ptr>& items1, const QHash<QString,KService::Ptr>& items2)
00138 {
00139 foreach (const KService::Ptr &p, items2)
00140 items1.remove(p->menuId());
00141 }
00142
00143 VFolderMenu::SubMenu*
00144 VFolderMenu::takeSubMenu(SubMenu *parentMenu, const QString &menuName)
00145 {
00146 const int i = menuName.indexOf('/');
00147 const QString s1 = i > 0 ? menuName.left(i) : menuName;
00148 const QString s2 = menuName.mid(i+1);
00149
00150
00151 for (QList<SubMenu*>::Iterator it = parentMenu->subMenus.begin(); it != parentMenu->subMenus.end(); ++it)
00152 {
00153 SubMenu* menu = *it;
00154 if (menu->name == s1)
00155 {
00156 if (i == -1)
00157 {
00158
00159 parentMenu->subMenus.erase(it);
00160 return menu;
00161 }
00162 else
00163 {
00164 return takeSubMenu(menu, s2);
00165 }
00166 }
00167 }
00168 return 0;
00169 }
00170
00171 void
00172 VFolderMenu::mergeMenu(SubMenu *menu1, SubMenu *menu2, bool reversePriority)
00173 {
00174 if (m_track)
00175 {
00176 track(m_trackId, menu1->name, menu1->items, menu1->excludeItems, menu2->items, QString("Before MenuMerge w. %1 (incl)").arg(menu2->name));
00177 track(m_trackId, menu1->name, menu1->items, menu1->excludeItems, menu2->excludeItems, QString("Before MenuMerge w. %1 (excl)").arg(menu2->name));
00178 }
00179 if (reversePriority)
00180 {
00181
00182 excludeItems(menu2->items, menu1->excludeItems);
00183 includeItems(menu1->items, menu2->items);
00184 excludeItems(menu2->excludeItems, menu1->items);
00185 includeItems(menu1->excludeItems, menu2->excludeItems);
00186 }
00187 else
00188 {
00189
00190 excludeItems(menu1->items, menu2->excludeItems);
00191 includeItems(menu1->items, menu2->items);
00192 includeItems(menu1->excludeItems, menu2->excludeItems);
00193 menu1->isDeleted = menu2->isDeleted;
00194 }
00195 while (!menu2->subMenus.isEmpty())
00196 {
00197 SubMenu *subMenu = menu2->subMenus.takeFirst();
00198 insertSubMenu(menu1, subMenu->name, subMenu, reversePriority);
00199 }
00200
00201 if (reversePriority)
00202 {
00203
00204 if (menu1->directoryFile.isEmpty())
00205 menu1->directoryFile = menu2->directoryFile;
00206 if (menu1->defaultLayoutNode.isNull())
00207 menu1->defaultLayoutNode = menu2->defaultLayoutNode;
00208 if (menu1->layoutNode.isNull())
00209 menu1->layoutNode = menu2->layoutNode;
00210 }
00211 else
00212 {
00213
00214 if (!menu2->directoryFile.isEmpty())
00215 menu1->directoryFile = menu2->directoryFile;
00216 if (!menu2->defaultLayoutNode.isNull())
00217 menu1->defaultLayoutNode = menu2->defaultLayoutNode;
00218 if (!menu2->layoutNode.isNull())
00219 menu1->layoutNode = menu2->layoutNode;
00220 }
00221
00222 if (m_track)
00223 {
00224 track(m_trackId, menu1->name, menu1->items, menu1->excludeItems, menu2->items, QString("After MenuMerge w. %1 (incl)").arg(menu2->name));
00225 track(m_trackId, menu1->name, menu1->items, menu1->excludeItems, menu2->excludeItems, QString("After MenuMerge w. %1 (excl)").arg(menu2->name));
00226 }
00227
00228 delete menu2;
00229 }
00230
00231 void
00232 VFolderMenu::insertSubMenu(SubMenu *parentMenu, const QString &menuName, SubMenu *newMenu, bool reversePriority)
00233 {
00234 const int i = menuName.indexOf('/');
00235 const QString s1 = menuName.left(i);
00236 const QString s2 = menuName.mid(i+1);
00237
00238
00239 foreach (SubMenu *menu, parentMenu->subMenus)
00240 {
00241 if (menu->name == s1)
00242 {
00243 if (i == -1)
00244 {
00245 mergeMenu(menu, newMenu, reversePriority);
00246 return;
00247 }
00248 else
00249 {
00250 insertSubMenu(menu, s2, newMenu, reversePriority);
00251 return;
00252 }
00253 }
00254 }
00255 if (i == -1)
00256 {
00257
00258 newMenu->name = menuName;
00259 parentMenu->subMenus.append(newMenu);
00260 }
00261 else
00262 {
00263 SubMenu *menu = new SubMenu;
00264 menu->name = s1;
00265 parentMenu->subMenus.append(menu);
00266 insertSubMenu(menu, s2, newMenu);
00267 }
00268 }
00269
00270 void
00271 VFolderMenu::insertService(SubMenu *parentMenu, const QString &name, KService::Ptr newService)
00272 {
00273 const int i = name.indexOf('/');
00274
00275 if (i == -1)
00276 {
00277
00278 parentMenu->items.insert(newService->menuId(), newService);
00279 return;
00280 }
00281
00282 QString s1 = name.left(i);
00283 QString s2 = name.mid(i+1);
00284
00285
00286 foreach (SubMenu *menu, parentMenu->subMenus)
00287 {
00288 if (menu->name == s1)
00289 {
00290 insertService(menu, s2, newService);
00291 return;
00292 }
00293 }
00294
00295 SubMenu *menu = new SubMenu;
00296 menu->name = s1;
00297 parentMenu->subMenus.append(menu);
00298 insertService(menu, s2, newService);
00299 }
00300
00301
00302 VFolderMenu::VFolderMenu(KBuildServiceFactory* serviceFactory) :
00303 m_track(false),
00304 m_serviceFactory(serviceFactory)
00305 {
00306 m_usedAppsDict.reserve(797);
00307 m_rootMenu = 0;
00308 initDirs();
00309 }
00310
00311 VFolderMenu::~VFolderMenu()
00312 {
00313 delete m_rootMenu;
00314 delete m_appsInfo;
00315 }
00316
00317 #define FOR_ALL_APPLICATIONS(it) \
00318 foreach (AppsInfo *info, m_appsInfoStack) \
00319 { \
00320 QHashIterator<QString,KService::Ptr> it = info->applications; \
00321 while (it.hasNext()) \
00322 { \
00323 it.next();
00324 #define FOR_ALL_APPLICATIONS_END } }
00325
00326 #define FOR_CATEGORY(category, it) \
00327 foreach (AppsInfo *info, m_appsInfoStack) \
00328 { \
00329 const KService::List list = info->dictCategories.value(category); \
00330 for(KService::List::ConstIterator it = list.constBegin(); \
00331 it != list.constEnd(); ++it) \
00332 {
00333 #define FOR_CATEGORY_END } }
00334
00335 KService::Ptr
00336 VFolderMenu::findApplication(const QString &relPath)
00337 {
00338 foreach(AppsInfo *info, m_appsInfoStack)
00339 {
00340 if (info->applications.contains(relPath)) {
00341 KService::Ptr s = info->applications[relPath];
00342 if (s)
00343 return s;
00344 }
00345 }
00346 return KService::Ptr();
00347 }
00348
00349 void
00350 VFolderMenu::addApplication(const QString &id, KService::Ptr service)
00351 {
00352 service->setMenuId(id);
00353 m_appsInfo->applications.insert(id, service);
00354 m_serviceFactory->addEntry(KSycocaEntry::Ptr::staticCast(service));
00355 }
00356
00357 void
00358 VFolderMenu::buildApplicationIndex(bool unusedOnly)
00359 {
00360 foreach (AppsInfo *info, m_appsInfoList)
00361 {
00362 info->dictCategories.clear();
00363 QMutableHashIterator<QString,KService::Ptr> it = info->applications;
00364 while (it.hasNext())
00365 {
00366 KService::Ptr s = it.next().value();
00367 if (unusedOnly && m_usedAppsDict.contains(s->menuId()))
00368 {
00369
00370 it.remove();
00371 continue;
00372 }
00373
00374 const QStringList cats = s->categories();
00375 for(QStringList::ConstIterator it2 = cats.begin();
00376 it2 != cats.end(); ++it2)
00377 {
00378 const QString &cat = *it2;
00379 info->dictCategories[cat].append(s);
00380 }
00381 }
00382 }
00383 }
00384
00385 void
00386 VFolderMenu::createAppsInfo()
00387 {
00388 if (m_appsInfo) return;
00389
00390 m_appsInfo = new AppsInfo;
00391 m_appsInfoStack.prepend(m_appsInfo);
00392 m_appsInfoList.append(m_appsInfo);
00393 m_currentMenu->apps_info = m_appsInfo;
00394 }
00395
00396 void
00397 VFolderMenu::loadAppsInfo()
00398 {
00399 m_appsInfo = m_currentMenu->apps_info;
00400 if (!m_appsInfo)
00401 return;
00402
00403 if (m_appsInfoStack.count() && m_appsInfoStack.first() == m_appsInfo)
00404 return;
00405
00406 m_appsInfoStack.prepend(m_appsInfo);
00407 }
00408
00409 void
00410 VFolderMenu::unloadAppsInfo()
00411 {
00412 m_appsInfo = m_currentMenu->apps_info;
00413 if (!m_appsInfo)
00414 return;
00415
00416 if (m_appsInfoStack.first() != m_appsInfo)
00417 {
00418 return;
00419 }
00420
00421 m_appsInfoStack.removeAll(m_appsInfo);
00422 m_appsInfo = 0;
00423 }
00424
00425 QString
00426 VFolderMenu::absoluteDir(const QString &_dir, const QString &baseDir, bool keepRelativeToCfg)
00427 {
00428 QString dir = _dir;
00429 if (QDir::isRelativePath(dir))
00430 {
00431 dir = baseDir + dir;
00432 }
00433 if (!dir.endsWith('/'))
00434 dir += '/';
00435
00436 if (QDir::isRelativePath(dir) && !keepRelativeToCfg)
00437 {
00438 dir = KGlobal::dirs()->findResource("xdgconf-menu", dir);
00439 }
00440
00441 dir = KGlobal::dirs()->realPath(dir);
00442
00443 return dir;
00444 }
00445
00446 static void tagBaseDir(QDomDocument &doc, const QString &tag, const QString &dir)
00447 {
00448 QDomNodeList mergeFileList = doc.elementsByTagName(tag);
00449 for(int i = 0; i < (int)mergeFileList.count(); i++)
00450 {
00451 QDomAttr attr = doc.createAttribute("__BaseDir");
00452 attr.setValue(dir);
00453 mergeFileList.item(i).toElement().setAttributeNode(attr);
00454 }
00455 }
00456
00457 static void tagBasePath(QDomDocument &doc, const QString &tag, const QString &path)
00458 {
00459 QDomNodeList mergeFileList = doc.elementsByTagName(tag);
00460 for(int i = 0; i < (int)mergeFileList.count(); i++)
00461 {
00462 QDomAttr attr = doc.createAttribute("__BasePath");
00463 attr.setValue(path);
00464 mergeFileList.item(i).toElement().setAttributeNode(attr);
00465 }
00466 }
00467
00468 QDomDocument
00469 VFolderMenu::loadDoc()
00470 {
00471 QDomDocument doc;
00472 if ( m_docInfo.path.isEmpty() )
00473 {
00474 return doc;
00475 }
00476 QFile file( m_docInfo.path );
00477 if ( !file.open( QIODevice::ReadOnly ) )
00478 {
00479 kWarning(7021) << "Could not open " << m_docInfo.path;
00480 return doc;
00481 }
00482 QString errorMsg;
00483 int errorRow;
00484 int errorCol;
00485 if ( !doc.setContent( &file, &errorMsg, &errorRow, &errorCol ) ) {
00486 kWarning(7021) << "Parse error in " << m_docInfo.path << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg;
00487 file.close();
00488 return doc;
00489 }
00490 file.close();
00491
00492 tagBaseDir(doc, "MergeFile", m_docInfo.baseDir);
00493 tagBasePath(doc, "MergeFile", m_docInfo.path);
00494 tagBaseDir(doc, "MergeDir", m_docInfo.baseDir);
00495 tagBaseDir(doc, "DirectoryDir", m_docInfo.baseDir);
00496 tagBaseDir(doc, "AppDir", m_docInfo.baseDir);
00497 tagBaseDir(doc, "LegacyDir", m_docInfo.baseDir);
00498
00499 return doc;
00500 }
00501
00502
00503 void
00504 VFolderMenu::mergeFile(QDomElement &parent, const QDomNode &mergeHere)
00505 {
00506 kDebug(7021) << "VFolderMenu::mergeFile:" << m_docInfo.path;
00507 QDomDocument doc = loadDoc();
00508
00509 QDomElement docElem = doc.documentElement();
00510 QDomNode n = docElem.firstChild();
00511 QDomNode last = mergeHere;
00512 while( !n.isNull() )
00513 {
00514 QDomElement e = n.toElement();
00515 QDomNode next = n.nextSibling();
00516
00517 if (e.isNull())
00518 {
00519
00520 }
00521
00522 else if (e.tagName() != "Name")
00523 {
00524 parent.insertAfter(n, last);
00525 last = n;
00526 }
00527
00528 docElem.removeChild(n);
00529 n = next;
00530 }
00531 }
00532
00533
00534 void
00535 VFolderMenu::mergeMenus(QDomElement &docElem, QString &name)
00536 {
00537 QMap<QString,QDomElement> menuNodes;
00538 QMap<QString,QDomElement> directoryNodes;
00539 QMap<QString,QDomElement> appDirNodes;
00540 QMap<QString,QDomElement> directoryDirNodes;
00541 QMap<QString,QDomElement> legacyDirNodes;
00542 QDomElement defaultLayoutNode;
00543 QDomElement layoutNode;
00544
00545 QDomNode n = docElem.firstChild();
00546 while( !n.isNull() ) {
00547 QDomElement e = n.toElement();
00548 if( e.isNull() ) {
00549
00550 }
00551 else if( e.tagName() == "DefaultAppDirs") {
00552
00553 replaceNode(docElem, n, m_defaultAppDirs, "AppDir");
00554 continue;
00555 }
00556 else if( e.tagName() == "DefaultDirectoryDirs") {
00557
00558 replaceNode(docElem, n, m_defaultDirectoryDirs, "DirectoryDir");
00559 continue;
00560 }
00561 else if( e.tagName() == "DefaultMergeDirs") {
00562
00563 replaceNode(docElem, n, m_defaultMergeDirs, "MergeDir");
00564 continue;
00565 }
00566 else if( e.tagName() == "AppDir") {
00567
00568 foldNode(docElem, e, appDirNodes);
00569 }
00570 else if( e.tagName() == "DirectoryDir") {
00571
00572 foldNode(docElem, e, directoryDirNodes);
00573 }
00574 else if( e.tagName() == "LegacyDir") {
00575
00576 foldNode(docElem, e, legacyDirNodes);
00577 }
00578 else if( e.tagName() == "Directory") {
00579
00580 foldNode(docElem, e, directoryNodes);
00581 }
00582 else if( e.tagName() == "Move") {
00583
00584 QString orig;
00585 QDomNode n2 = e.firstChild();
00586 while( !n2.isNull() ) {
00587 QDomElement e2 = n2.toElement();
00588 if( e2.tagName() == "Old")
00589 {
00590 orig = e2.text();
00591 break;
00592 }
00593 n2 = n2.nextSibling();
00594 }
00595 foldNode(docElem, e, appDirNodes, orig);
00596 }
00597 else if( e.tagName() == "Menu") {
00598 QString name;
00599 mergeMenus(e, name);
00600 QMap<QString,QDomElement>::iterator it = menuNodes.find(name);
00601 if (it != menuNodes.end())
00602 {
00603 QDomElement docElem2 = *it;
00604 QDomNode n2 = docElem2.firstChild();
00605 QDomNode first = e.firstChild();
00606 while( !n2.isNull() ) {
00607 QDomElement e2 = n2.toElement();
00608 QDomNode n3 = n2.nextSibling();
00609 e.insertBefore(n2, first);
00610 docElem2.removeChild(n2);
00611 n2 = n3;
00612 }
00613
00614
00615
00616 docElem.removeChild(docElem2);
00617 menuNodes.erase(it);
00618 }
00619 menuNodes.insert(name, e);
00620 }
00621 else if( e.tagName() == "MergeFile") {
00622 if ((e.attribute("type") == "parent"))
00623 pushDocInfoParent(e.attribute("__BasePath"), e.attribute("__BaseDir"));
00624 else
00625 pushDocInfo(e.text(), e.attribute("__BaseDir"));
00626
00627 if (!m_docInfo.path.isEmpty())
00628 mergeFile(docElem, n);
00629 popDocInfo();
00630
00631 QDomNode last = n;
00632 n = n.nextSibling();
00633 docElem.removeChild(last);
00634 continue;
00635 }
00636 else if( e.tagName() == "MergeDir") {
00637 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"), true);
00638
00639 const QStringList dirs = KGlobal::dirs()->findDirs("xdgconf-menu", dir);
00640 for(QStringList::ConstIterator it=dirs.begin();
00641 it != dirs.end(); ++it)
00642 {
00643 registerDirectory(*it);
00644 }
00645
00646 QStringList fileList;
00647 if (!QDir::isRelativePath(dir))
00648 {
00649
00650 fileList = KGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu");
00651 }
00652 else
00653 {
00654
00655 (void) KGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu",
00656 KStandardDirs::NoDuplicates, fileList);
00657 }
00658
00659 for(QStringList::ConstIterator it=fileList.constBegin();
00660 it != fileList.constEnd(); ++it)
00661 {
00662 pushDocInfo(*it);
00663 mergeFile(docElem, n);
00664 popDocInfo();
00665 }
00666
00667 QDomNode last = n;
00668 n = n.nextSibling();
00669 docElem.removeChild(last);
00670
00671 continue;
00672 }
00673 else if( e.tagName() == "Name") {
00674 name = e.text();
00675 }
00676 else if( e.tagName() == "DefaultLayout") {
00677 if (!defaultLayoutNode.isNull())
00678 docElem.removeChild(defaultLayoutNode);
00679 defaultLayoutNode = e;
00680 }
00681 else if( e.tagName() == "Layout") {
00682 if (!layoutNode.isNull())
00683 docElem.removeChild(layoutNode);
00684 layoutNode = e;
00685 }
00686 n = n.nextSibling();
00687 }
00688 }
00689
00690 void
00691 VFolderMenu::pushDocInfo(const QString &fileName, const QString &baseDir)
00692 {
00693 m_docInfoStack.push(m_docInfo);
00694 if (!baseDir.isEmpty())
00695 {
00696 if (!QDir::isRelativePath(baseDir))
00697 m_docInfo.baseDir = KGlobal::dirs()->relativeLocation("xdgconf-menu", baseDir);
00698 else
00699 m_docInfo.baseDir = baseDir;
00700 }
00701
00702 QString baseName = fileName;
00703 if (!QDir::isRelativePath(baseName))
00704 registerFile(baseName);
00705 else
00706 baseName = m_docInfo.baseDir + baseName;
00707
00708 m_docInfo.path = locateMenuFile(fileName);
00709 if (m_docInfo.path.isEmpty())
00710 {
00711 m_docInfo.baseDir.clear();
00712 m_docInfo.baseName.clear();
00713 kDebug(7021) << "Menu" << fileName << "not found.";
00714 return;
00715 }
00716 int i;
00717 i = baseName.lastIndexOf('/');
00718 if (i > 0)
00719 {
00720 m_docInfo.baseDir = baseName.left(i+1);
00721 m_docInfo.baseName = baseName.mid(i+1, baseName.length() - i - 6);
00722 }
00723 else
00724 {
00725 m_docInfo.baseDir.clear();
00726 m_docInfo.baseName = baseName.left( baseName.length() - 5 );
00727 }
00728 }
00729
00730 void
00731 VFolderMenu::pushDocInfoParent(const QString &basePath, const QString &baseDir)
00732 {
00733 m_docInfoStack.push(m_docInfo);
00734
00735 m_docInfo.baseDir = baseDir;
00736
00737 QString fileName = basePath.mid(basePath.lastIndexOf('/')+1);
00738 m_docInfo.baseName = fileName.left( fileName.length() - 5 );
00739 QString baseName = QDir::cleanPath(m_docInfo.baseDir + fileName);
00740
00741 QStringList result = KGlobal::dirs()->findAllResources("xdgconf-menu", baseName);
00742
00743 while( !result.isEmpty() && (result[0] != basePath))
00744 result.erase(result.begin());
00745
00746 if (result.count() <= 1)
00747 {
00748 m_docInfo.path.clear();
00749 return;
00750 }
00751 m_docInfo.path = result[1];
00752 }
00753
00754 void
00755 VFolderMenu::popDocInfo()
00756 {
00757 m_docInfo = m_docInfoStack.pop();
00758 }
00759
00760 QString
00761 VFolderMenu::locateMenuFile(const QString &fileName)
00762 {
00763 if (!QDir::isRelativePath(fileName))
00764 {
00765 if (KStandardDirs::exists(fileName))
00766 return fileName;
00767 return QString();
00768 }
00769
00770 QString result;
00771
00772 QString xdgMenuPrefix = QString::fromLocal8Bit(qgetenv("XDG_MENU_PREFIX"));
00773 if (!xdgMenuPrefix.isEmpty())
00774 {
00775 QFileInfo fileInfo(fileName);
00776
00777 QString fileNameOnly = fileInfo.fileName();
00778 if (!fileNameOnly.startsWith(xdgMenuPrefix))
00779 fileNameOnly = xdgMenuPrefix + fileNameOnly;
00780
00781 QString baseName = QDir::cleanPath(m_docInfo.baseDir +
00782 fileInfo.path() + '/' + fileNameOnly);
00783 result = KStandardDirs::locate("xdgconf-menu", baseName);
00784 }
00785
00786 if (result.isEmpty())
00787 {
00788 QString baseName = QDir::cleanPath(m_docInfo.baseDir + fileName);
00789 result = KStandardDirs::locate("xdgconf-menu", baseName);
00790 }
00791
00792 return result;
00793 }
00794
00795 QString
00796 VFolderMenu::locateDirectoryFile(const QString &fileName)
00797 {
00798 if (fileName.isEmpty())
00799 return QString();
00800
00801 if (!QDir::isRelativePath(fileName))
00802 {
00803 if (KStandardDirs::exists(fileName))
00804 return fileName;
00805 return QString();
00806 }
00807
00808
00809 for(QStringList::ConstIterator it = m_directoryDirs.constBegin();
00810 it != m_directoryDirs.constEnd();
00811 ++it)
00812 {
00813 QString tmp = (*it)+fileName;
00814 if (KStandardDirs::exists(tmp))
00815 return tmp;
00816 }
00817
00818 return QString();
00819 }
00820
00821 void
00822 VFolderMenu::initDirs()
00823 {
00824 m_defaultDataDirs = KGlobal::dirs()->kfsstnd_prefixes().split(':', QString::SkipEmptyParts);
00825 const QString localDir = m_defaultDataDirs.first();
00826 m_defaultDataDirs.removeAll(localDir);
00827
00828 m_defaultAppDirs = KGlobal::dirs()->findDirs("xdgdata-apps", QString());
00829 m_defaultDirectoryDirs = KGlobal::dirs()->findDirs("xdgdata-dirs", QString());
00830 m_defaultLegacyDirs = KGlobal::dirs()->resourceDirs("apps");
00831 }
00832
00833 void
00834 VFolderMenu::loadMenu(const QString &fileName)
00835 {
00836 m_defaultMergeDirs.clear();
00837
00838 if (!fileName.endsWith(".menu"))
00839 return;
00840
00841 pushDocInfo(fileName);
00842 m_defaultMergeDirs << m_docInfo.baseName+"-merged/";
00843 m_doc = loadDoc();
00844 popDocInfo();
00845
00846 if (m_doc.isNull())
00847 {
00848 if (m_docInfo.path.isEmpty())
00849 kError(7021) << fileName << " not found in " << m_allDirectories << endl;
00850 else
00851 kWarning(7021) << "Load error (" << m_docInfo.path << ")";
00852 return;
00853 }
00854
00855 QDomElement e = m_doc.documentElement();
00856 QString name;
00857 mergeMenus(e, name);
00858 }
00859
00860 void
00861 VFolderMenu::processCondition(QDomElement &domElem, QHash<QString,KService::Ptr>& items)
00862 {
00863 if (domElem.tagName() == "And")
00864 {
00865 QDomNode n = domElem.firstChild();
00866
00867 while (!n.isNull())
00868 {
00869 QDomElement e = n.toElement();
00870 n = n.nextSibling();
00871 if ( !e.isNull() ) {
00872 processCondition(e, items);
00873 break;
00874 }
00875 }
00876
00877 QHash<QString,KService::Ptr> andItems;
00878 while( !n.isNull() ) {
00879 QDomElement e = n.toElement();
00880 if (e.tagName() == "Not")
00881 {
00882
00883 QDomNode n2 = e.firstChild();
00884 while( !n2.isNull() ) {
00885 QDomElement e2 = n2.toElement();
00886 andItems.clear();
00887 processCondition(e2, andItems);
00888 excludeItems(items, andItems);
00889 n2 = n2.nextSibling();
00890 }
00891 }
00892 else
00893 {
00894 andItems.clear();
00895 processCondition(e, andItems);
00896 matchItems(items, andItems);
00897 }
00898 n = n.nextSibling();
00899 }
00900 }
00901 else if (domElem.tagName() == "Or")
00902 {
00903 QDomNode n = domElem.firstChild();
00904
00905 while (!n.isNull())
00906 {
00907 QDomElement e = n.toElement();
00908 n = n.nextSibling();
00909 if ( !e.isNull() ) {
00910 processCondition(e, items);
00911 break;
00912 }
00913 }
00914
00915 QHash<QString,KService::Ptr> orItems;
00916 while( !n.isNull() ) {
00917 QDomElement e = n.toElement();
00918 if ( !e.isNull() ) {
00919 orItems.clear();
00920 processCondition(e, orItems);
00921 includeItems(items, orItems);
00922 }
00923 n = n.nextSibling();
00924 }
00925 }
00926 else if (domElem.tagName() == "Not")
00927 {
00928 FOR_ALL_APPLICATIONS(it)
00929 {
00930 KService::Ptr s = it.value();
00931 items.insert(s->menuId(), s);
00932 }
00933 FOR_ALL_APPLICATIONS_END
00934
00935 QHash<QString,KService::Ptr> notItems;
00936 QDomNode n = domElem.firstChild();
00937 while( !n.isNull() ) {
00938 QDomElement e = n.toElement();
00939 if ( !e.isNull() ) {
00940 notItems.clear();
00941 processCondition(e, notItems);
00942 excludeItems(items, notItems);
00943 }
00944 n = n.nextSibling();
00945 }
00946 }
00947 else if (domElem.tagName() == "Category")
00948 {
00949 FOR_CATEGORY(domElem.text(), it)
00950 {
00951 KService::Ptr s = *it;
00952 items.insert(s->menuId(), s);
00953 }
00954 FOR_CATEGORY_END
00955 }
00956 else if (domElem.tagName() == "All")
00957 {
00958 FOR_ALL_APPLICATIONS(it)
00959 {
00960 KService::Ptr s = it.value();
00961 items.insert(s->menuId(), s);
00962 }
00963 FOR_ALL_APPLICATIONS_END
00964 }
00965 else if (domElem.tagName() == "Filename")
00966 {
00967 const QString filename = domElem.text();
00968
00969 KService::Ptr s = findApplication(filename);
00970 if (s)
00971 items.insert(filename, s);
00972 }
00973 }
00974
00975 void
00976 VFolderMenu::loadApplications(const QString &dir, const QString &prefix)
00977 {
00978 kDebug(7021) << "Looking up applications under" << dir;
00979
00980 QDirIterator it(dir);
00981 while (it.hasNext()) {
00982 it.next();
00983 const QFileInfo fi = it.fileInfo();
00984 const QString fn = fi.fileName();
00985 if (fi.isDir()) {
00986 if(fn == QLatin1String(".") || fn == QLatin1String(".."))
00987 continue;
00988 loadApplications(fi.filePath(), prefix + fn + '-');
00989 continue;
00990 }
00991 if (fi.isFile()) {
00992 if (!fn.endsWith(QLatin1String(".desktop")))
00993 continue;
00994 KService::Ptr service;
00995 emit newService(fi.absoluteFilePath(), &service);
00996 if (service)
00997 addApplication(prefix + fn, service);
00998 }
00999 }
01000 }
01001
01002 void
01003 VFolderMenu::processKDELegacyDirs()
01004 {
01005 kDebug(7021);
01006
01007 QHash<QString,KService::Ptr> items;
01008 QString prefix = "kde4-";
01009
01010 QStringList relFiles;
01011
01012 (void) KGlobal::dirs()->findAllResources( "apps",
01013 QString(),
01014 KStandardDirs::Recursive |
01015 KStandardDirs::NoDuplicates,
01016 relFiles);
01017 for(QStringList::ConstIterator it = relFiles.constBegin();
01018 it != relFiles.constEnd(); ++it)
01019 {
01020 if (!m_forcedLegacyLoad && (*it).endsWith(QLatin1String(".directory")))
01021 {
01022 QString name = *it;
01023 if (!name.endsWith("/.directory"))
01024 continue;
01025
01026 name = name.left(name.length()-11);
01027
01028 SubMenu *newMenu = new SubMenu;
01029 newMenu->directoryFile = KStandardDirs::locate("apps", *it);
01030
01031 insertSubMenu(m_currentMenu, name, newMenu);
01032 continue;
01033 }
01034
01035 if ((*it).endsWith(QLatin1String(".desktop")))
01036 {
01037 QString name = *it;
01038 KService::Ptr service;
01039 emit newService(name, &service);
01040
01041 if (service && !m_forcedLegacyLoad)
01042 {
01043 QString id = name;
01044
01045 int i = id.lastIndexOf('/');
01046 if (i >= 0)
01047 id = id.mid(i+1);
01048
01049 id.prepend(prefix);
01050
01051
01052 addApplication(id, service);
01053 items.insert(service->menuId(), service);
01054 if (service->categories().isEmpty())
01055 insertService(m_currentMenu, name, service);
01056
01057 }
01058 }
01059 }
01060 markUsedApplications(items);
01061 m_legacyLoaded = true;
01062 }
01063
01064 void
01065 VFolderMenu::processLegacyDir(const QString &dir, const QString &relDir, const QString &prefix)
01066 {
01067 kDebug(7021).nospace() << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")";
01068
01069 QHash<QString,KService::Ptr> items;
01070 QDirIterator it(dir);
01071 while (it.hasNext()) {
01072 it.next();
01073 const QFileInfo fi = it.fileInfo();
01074 const QString fn = fi.fileName();
01075 if (fi.isDir() && !fi.isSymLink()) {
01076 if(fn == QLatin1String(".") || fn == QLatin1String(".."))
01077 continue;
01078 SubMenu *parentMenu = m_currentMenu;
01079
01080 m_currentMenu = new SubMenu;
01081 m_currentMenu->name = fn;
01082 m_currentMenu->directoryFile = fi.absoluteFilePath() + "/.directory";
01083
01084 parentMenu->subMenus.append(m_currentMenu);
01085
01086 processLegacyDir(fi.filePath(), relDir + fn + '/', prefix);
01087 m_currentMenu = parentMenu;
01088 continue;
01089 }
01090 if (fi.isFile() && !fi.isSymLink()) {
01091 if (!fn.endsWith(QLatin1String(".desktop")))
01092 continue;
01093 KService::Ptr service;
01094 emit newService(fi.absoluteFilePath(), &service);
01095 if (service)
01096 {
01097 const QString id = prefix + fn;
01098
01099
01100 addApplication(id, service);
01101 items.insert(service->menuId(), service);
01102
01103 if (service->categories().isEmpty())
01104 m_currentMenu->items.insert(id, service);
01105 }
01106 }
01107 }
01108 markUsedApplications(items);
01109 }
01110
01111
01112
01113 void
01114 VFolderMenu::processMenu(QDomElement &docElem, int pass)
01115 {
01116 SubMenu *parentMenu = m_currentMenu;
01117 int oldDirectoryDirsCount = m_directoryDirs.count();
01118
01119 QString name;
01120 QString directoryFile;
01121 bool onlyUnallocated = false;
01122 bool isDeleted = false;
01123 bool kdeLegacyDirsDone = false;
01124 QDomElement defaultLayoutNode;
01125 QDomElement layoutNode;
01126
01127 QDomElement query;
01128 QDomNode n = docElem.firstChild();
01129 while( !n.isNull() ) {
01130 QDomElement e = n.toElement();
01131 if (e.tagName() == "Name")
01132 {
01133 name = e.text();
01134 }
01135 else if (e.tagName() == "Directory")
01136 {
01137 directoryFile = e.text();
01138 }
01139 else if (e.tagName() == "DirectoryDir")
01140 {
01141 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01142
01143 m_directoryDirs.prepend(dir);
01144 }
01145 else if (e.tagName() == "OnlyUnallocated")
01146 {
01147 onlyUnallocated = true;
01148 }
01149 else if (e.tagName() == "NotOnlyUnallocated")
01150 {
01151 onlyUnallocated = false;
01152 }
01153 else if (e.tagName() == "Deleted")
01154 {
01155 isDeleted = true;
01156 }
01157 else if (e.tagName() == "NotDeleted")
01158 {
01159 isDeleted = false;
01160 }
01161 else if (e.tagName() == "DefaultLayout")
01162 {
01163 defaultLayoutNode = e;
01164 }
01165 else if (e.tagName() == "Layout")
01166 {
01167 layoutNode = e;
01168 }
01169 n = n.nextSibling();
01170 }
01171
01172
01173 if (pass == 0)
01174 {
01175 m_currentMenu = 0;
01176
01177 if (parentMenu)
01178 {
01179 foreach (SubMenu *menu, parentMenu->subMenus)
01180 {
01181 if (menu->name == name)
01182 {
01183 m_currentMenu = menu;
01184 break;
01185 }
01186 }
01187 }
01188
01189 if (!m_currentMenu)
01190 {
01191
01192 m_currentMenu = new SubMenu;
01193 m_currentMenu->name = name;
01194
01195 if (parentMenu)
01196 parentMenu->subMenus.append(m_currentMenu);
01197 else
01198 m_rootMenu = m_currentMenu;
01199 }
01200 if (directoryFile.isEmpty())
01201 {
01202 kDebug(7021) << "Menu" << name << "does not specify a directory file.";
01203 }
01204
01205
01206 QString tmp = locateDirectoryFile(directoryFile);
01207 if (! tmp.isEmpty())
01208 m_currentMenu->directoryFile = tmp;
01209 m_currentMenu->isDeleted = isDeleted;
01210
01211 m_currentMenu->defaultLayoutNode = defaultLayoutNode;
01212 m_currentMenu->layoutNode = layoutNode;
01213 }
01214 else
01215 {
01216
01217 if (parentMenu)
01218 {
01219 foreach (SubMenu *menu, parentMenu->subMenus)
01220 {
01221 if (menu->name == name)
01222 {
01223 m_currentMenu = menu;
01224 break;
01225 }
01226 }
01227 }
01228 else
01229 {
01230 m_currentMenu = m_rootMenu;
01231 }
01232 }
01233
01234
01235 if (pass == 0)
01236 {
01237 QDomElement query;
01238 QDomNode n = docElem.firstChild();
01239 while( !n.isNull() ) {
01240 QDomElement e = n.toElement();
01241 if (e.tagName() == "AppDir")
01242 {
01243 createAppsInfo();
01244 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01245
01246 registerDirectory(dir);
01247
01248 loadApplications(dir, QString());
01249 }
01250 else if (e.tagName() == "KDELegacyDirs")
01251 {
01252 createAppsInfo();
01253 if (!kdeLegacyDirsDone)
01254 {
01255 kDebug(7021) << "Processing KDE Legacy dirs for <KDE>";
01256 SubMenu *oldMenu = m_currentMenu;
01257 m_currentMenu = new SubMenu;
01258
01259 processKDELegacyDirs();
01260
01261 m_legacyNodes.insert("<KDE>", m_currentMenu);
01262 m_currentMenu = oldMenu;
01263
01264 kdeLegacyDirsDone = true;
01265 }
01266 }
01267 else if (e.tagName() == "LegacyDir")
01268 {
01269 createAppsInfo();
01270 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01271
01272 QString prefix = e.attributes().namedItem("prefix").toAttr().value();
01273
01274 if (m_defaultLegacyDirs.contains(dir))
01275 {
01276 if (!kdeLegacyDirsDone)
01277 {
01278 kDebug(7021) << "Processing KDE Legacy dirs for" << dir;
01279 SubMenu *oldMenu = m_currentMenu;
01280 m_currentMenu = new SubMenu;
01281
01282 processKDELegacyDirs();
01283
01284 m_legacyNodes.insert("<KDE>", m_currentMenu);
01285 m_currentMenu = oldMenu;
01286
01287 kdeLegacyDirsDone = true;
01288 }
01289 }
01290 else
01291 {
01292 SubMenu *oldMenu = m_currentMenu;
01293 m_currentMenu = new SubMenu;
01294
01295 registerDirectory(dir);
01296
01297 processLegacyDir(dir, QString(), prefix);
01298
01299 m_legacyNodes.insert(dir, m_currentMenu);
01300 m_currentMenu = oldMenu;
01301 }
01302 }
01303 n = n.nextSibling();
01304 }
01305 }
01306
01307 loadAppsInfo();
01308
01309 if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
01310 {
01311 n = docElem.firstChild();
01312
01313 while( !n.isNull() ) {
01314 QDomElement e = n.toElement();
01315 if (e.tagName() == "Include")
01316 {
01317 QHash<QString,KService::Ptr> items;
01318
01319 QDomNode n2 = e.firstChild();
01320 while( !n2.isNull() ) {
01321 QDomElement e2 = n2.toElement();
01322 items.clear();
01323 processCondition(e2, items);
01324 if (m_track)
01325 track(m_trackId, m_currentMenu->name, m_currentMenu->items, m_currentMenu->excludeItems, items, "Before <Include>");
01326 includeItems(m_currentMenu->items, items);
01327 excludeItems(m_currentMenu->excludeItems, items);
01328 markUsedApplications(items);
01329
01330 if (m_track)
01331 track(m_trackId, m_currentMenu->name, m_currentMenu->items, m_currentMenu->excludeItems, items, "After <Include>");
01332
01333 n2 = n2.nextSibling();
01334 }
01335 }
01336
01337 else if (e.tagName() == "Exclude")
01338 {
01339 QHash<QString,KService::Ptr> items;
01340
01341 QDomNode n2 = e.firstChild();
01342 while( !n2.isNull() ) {
01343 QDomElement e2 = n2.toElement();
01344 items.clear();
01345 processCondition(e2, items);
01346 if (m_track)
01347 track(m_trackId, m_currentMenu->name, m_currentMenu->items, m_currentMenu->excludeItems, items, "Before <Exclude>");
01348 excludeItems(m_currentMenu->items, items);
01349 includeItems(m_currentMenu->excludeItems, items);
01350 if (m_track)
01351 track(m_trackId, m_currentMenu->name, m_currentMenu->items, m_currentMenu->excludeItems, items, "After <Exclude>");
01352 n2 = n2.nextSibling();
01353 }
01354 }
01355
01356 n = n.nextSibling();
01357 }
01358 }
01359
01360 n = docElem.firstChild();
01361 while( !n.isNull() ) {
01362 QDomElement e = n.toElement();
01363 if (e.tagName() == "Menu")
01364 {
01365 processMenu(e, pass);
01366 }
01367
01368
01369
01370
01371 else if (pass == 0)
01372 {
01373 if (e.tagName() == "LegacyDir")
01374 {
01375
01376 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01377 SubMenu *legacyMenu = m_legacyNodes[dir];
01378 if (legacyMenu)
01379 {
01380 mergeMenu(m_currentMenu, legacyMenu);
01381 }
01382 }
01383
01384 else if (e.tagName() == "KDELegacyDirs")
01385 {
01386
01387 QString dir = "<KDE>";
01388 SubMenu *legacyMenu = m_legacyNodes[dir];
01389 if (legacyMenu)
01390 {
01391 mergeMenu(m_currentMenu, legacyMenu);
01392 }
01393 }
01394 }
01395 n = n.nextSibling();
01396 }
01397
01398 if (pass == 2)
01399 {
01400 n = docElem.firstChild();
01401 while( !n.isNull() ) {
01402 QDomElement e = n.toElement();
01403 if (e.tagName() == "Move")
01404 {
01405 QString orig;
01406 QString dest;
01407 QDomNode n2 = e.firstChild();
01408 while( !n2.isNull() ) {
01409 QDomElement e2 = n2.toElement();
01410 if( e2.tagName() == "Old")
01411 orig = e2.text();
01412 if( e2.tagName() == "New")
01413 dest = e2.text();
01414 n2 = n2.nextSibling();
01415 }
01416 kDebug(7021) << "Moving" << orig << "to" << dest;
01417 if (!orig.isEmpty() && !dest.isEmpty())
01418 {
01419 SubMenu *menu = takeSubMenu(m_currentMenu, orig);
01420 if (menu)
01421 {
01422 insertSubMenu(m_currentMenu, dest, menu, true);
01423 }
01424 }
01425 }
01426 n = n.nextSibling();
01427 }
01428
01429 }
01430
01431 unloadAppsInfo();
01432
01433 while (m_directoryDirs.count() > oldDirectoryDirsCount)
01434 m_directoryDirs.pop_front();
01435
01436 m_currentMenu = parentMenu;
01437 }
01438
01439
01440
01441 static QString parseAttribute( const QDomElement &e)
01442 {
01443 QString option;
01444 if ( e.hasAttribute( "show_empty" ) )
01445 {
01446 QString str = e.attribute( "show_empty" );
01447 if ( str=="true" )
01448 option= "ME ";
01449 else if ( str=="false" )
01450 option= "NME ";
01451 else
01452 kDebug()<<" Error in parsing show_empty attribute :"<<str;
01453 }
01454 if ( e.hasAttribute( "inline" ) )
01455 {
01456 QString str = e.attribute( "inline" );
01457 if ( str=="true" )
01458 option+="I ";
01459 else if ( str=="false" )
01460 option+="NI ";
01461 else
01462 kDebug()<<" Error in parsing inlibe attribute :"<<str;
01463 }
01464 if ( e.hasAttribute( "inline_limit" ) )
01465 {
01466 bool ok;
01467 int value = e.attribute( "inline_limit" ).toInt(&ok);
01468 if ( ok )
01469 option+=QString( "IL[%1] " ).arg( value );
01470 }
01471 if ( e.hasAttribute( "inline_header" ) )
01472 {
01473 QString str = e.attribute( "inline_header" );
01474 if ( str=="true")
01475 option+="IH ";
01476 else if ( str == "false" )
01477 option+="NIH ";
01478 else
01479 kDebug()<<" Error in parsing of inline_header attribute :"<<str;
01480
01481 }
01482 if ( e.hasAttribute( "inline_alias" ) && e.attribute( "inline_alias" )=="true")
01483 {
01484 QString str = e.attribute( "inline_alias" );
01485 if ( str=="true" )
01486 option+="IA";
01487 else if ( str=="false" )
01488 option+="NIA";
01489 else
01490 kDebug()<<" Error in parsing inline_alias attribute :"<<str;
01491 }
01492 if( !option.isEmpty())
01493 {
01494 option = option.prepend(":O");
01495 }
01496 return option;
01497
01498 }
01499
01500 static QStringList parseLayoutNode(const QDomElement &docElem)
01501 {
01502 QStringList layout;
01503
01504 QString optionDefaultLayout;
01505 if( docElem.tagName()=="DefaultLayout")
01506 optionDefaultLayout = parseAttribute( docElem);
01507 if ( !optionDefaultLayout.isEmpty() )
01508 layout.append( optionDefaultLayout );
01509
01510 QDomNode n = docElem.firstChild();
01511 while( !n.isNull() ) {
01512 QDomElement e = n.toElement();
01513 if (e.tagName() == "Separator")
01514 {
01515 layout.append(":S");
01516 }
01517 else if (e.tagName() == "Filename")
01518 {
01519 layout.append(e.text());
01520 }
01521 else if (e.tagName() == "Menuname")
01522 {
01523 layout.append('/'+e.text());
01524 QString option = parseAttribute( e );
01525 if( !option.isEmpty())
01526 layout.append( option );
01527 }
01528 else if (e.tagName() == "Merge")
01529 {
01530 QString type = e.attributeNode("type").value();
01531 if (type == "files")
01532 layout.append(":F");
01533 else if (type == "menus")
01534 layout.append(":M");
01535 else if (type == "all")
01536 layout.append(":A");
01537 }
01538
01539 n = n.nextSibling();
01540 }
01541 return layout;
01542 }
01543
01544 void
01545 VFolderMenu::layoutMenu(VFolderMenu::SubMenu *menu, QStringList defaultLayout)
01546 {
01547 if (!menu->defaultLayoutNode.isNull())
01548 {
01549 defaultLayout = parseLayoutNode(menu->defaultLayoutNode);
01550 }
01551
01552 if (menu->layoutNode.isNull())
01553 {
01554 menu->layoutList = defaultLayout;
01555 }
01556 else
01557 {
01558 menu->layoutList = parseLayoutNode(menu->layoutNode);
01559 if (menu->layoutList.isEmpty())
01560 menu->layoutList = defaultLayout;
01561 }
01562
01563 foreach (VFolderMenu::SubMenu *subMenu, menu->subMenus)
01564 {
01565 layoutMenu(subMenu, defaultLayout);
01566 }
01567 }
01568
01569 void
01570 VFolderMenu::markUsedApplications(const QHash<QString,KService::Ptr>& items)
01571 {
01572 foreach(const KService::Ptr &p, items)
01573 m_usedAppsDict.insert(p->menuId());
01574 }
01575
01576 VFolderMenu::SubMenu *
01577 VFolderMenu::parseMenu(const QString &file, bool forceLegacyLoad)
01578 {
01579 m_forcedLegacyLoad = false;
01580 m_legacyLoaded = false;
01581 m_appsInfo = 0;
01582
01583 const QStringList dirs = KGlobal::dirs()->resourceDirs("xdgconf-menu");
01584 for(QStringList::ConstIterator it=dirs.begin();
01585 it != dirs.end(); ++it)
01586 {
01587 registerDirectory(*it);
01588 }
01589
01590 loadMenu(file);
01591
01592 delete m_rootMenu;
01593 m_rootMenu = m_currentMenu = 0;
01594
01595 QDomElement docElem = m_doc.documentElement();
01596
01597 for (int pass = 0; pass <= 2; pass++)
01598 {
01599
01600
01601
01602 processMenu(docElem, pass);
01603
01604 switch (pass) {
01605 case 0:
01606
01607
01608 buildApplicationIndex(false);
01609 break;
01610 case 1:
01611
01612
01613 buildApplicationIndex(true );
01614 break;
01615 case 2:
01616 {
01617 QStringList defaultLayout;
01618 defaultLayout << ":M";
01619 defaultLayout << ":F";
01620 layoutMenu(m_rootMenu, defaultLayout);
01621 break;
01622 }
01623 default:
01624 break;
01625 }
01626 }
01627
01628 if (!m_legacyLoaded && forceLegacyLoad)
01629 {
01630 m_forcedLegacyLoad = true;
01631 processKDELegacyDirs();
01632 }
01633
01634 return m_rootMenu;
01635 }
01636
01637 void
01638 VFolderMenu::setTrackId(const QString &id)
01639 {
01640 m_track = !id.isEmpty();
01641 m_trackId = id;
01642 }
01643
01644 #include "vfolder_menu.moc"