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