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