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
00778
00779 QString xdgMenuPrefix = "kde-";
00780 if (!xdgMenuPrefix.isEmpty())
00781 {
00782 QFileInfo fileInfo(fileName);
00783
00784 QString fileNameOnly = fileInfo.fileName();
00785 if (!fileNameOnly.startsWith(xdgMenuPrefix))
00786 fileNameOnly = xdgMenuPrefix + fileNameOnly;
00787
00788 QString baseName = QDir::cleanDirPath(m_docInfo.baseDir +
00789 fileInfo.dirPath() + "/" +
00790 fileNameOnly);
00791 result = locate("xdgconf-menu", baseName);
00792 }
00793
00794 if (result.isEmpty())
00795 {
00796 QString baseName = QDir::cleanDirPath(m_docInfo.baseDir + fileName);
00797 result = locate("xdgconf-menu", baseName);
00798 }
00799
00800 return result;
00801 }
00802
00803 QString
00804 VFolderMenu::locateDirectoryFile(const QString &fileName)
00805 {
00806 if (fileName.isEmpty())
00807 return QString::null;
00808
00809 if (!QDir::isRelativePath(fileName))
00810 {
00811 if (KStandardDirs::exists(fileName))
00812 return fileName;
00813 return QString::null;
00814 }
00815
00816
00817 QString tmp;
00818 for(QStringList::ConstIterator it = m_directoryDirs.begin();
00819 it != m_directoryDirs.end();
00820 ++it)
00821 {
00822 tmp = (*it)+fileName;
00823 if (KStandardDirs::exists(tmp))
00824 return tmp;
00825 }
00826
00827 return QString::null;
00828 }
00829
00830 void
00831 VFolderMenu::initDirs()
00832 {
00833 m_defaultDataDirs = QStringList::split(':', KGlobal::dirs()->kfsstnd_prefixes());
00834 QString localDir = m_defaultDataDirs.first();
00835 m_defaultDataDirs.remove(localDir);
00836
00837 m_defaultAppDirs = KGlobal::dirs()->findDirs("xdgdata-apps", QString::null);
00838 m_defaultDirectoryDirs = KGlobal::dirs()->findDirs("xdgdata-dirs", QString::null);
00839 m_defaultLegacyDirs = KGlobal::dirs()->resourceDirs("apps");
00840 }
00841
00842 void
00843 VFolderMenu::loadMenu(const QString &fileName)
00844 {
00845 m_defaultMergeDirs.clear();
00846
00847 if (!fileName.endsWith(".menu"))
00848 return;
00849
00850 pushDocInfo(fileName);
00851 m_defaultMergeDirs << m_docInfo.baseName+"-merged/";
00852 m_doc = loadDoc();
00853 popDocInfo();
00854
00855 if (m_doc.isNull())
00856 {
00857 if (m_docInfo.path.isEmpty())
00858 kdError(7021) << fileName << " not found in " << m_allDirectories << endl;
00859 else
00860 kdWarning(7021) << "Load error (" << m_docInfo.path << ")" << endl;
00861 return;
00862 }
00863
00864 QDomElement e = m_doc.documentElement();
00865 QString name;
00866 mergeMenus(e, name);
00867 }
00868
00869 void
00870 VFolderMenu::processCondition(QDomElement &domElem, QDict<KService> *items)
00871 {
00872 if (domElem.tagName() == "And")
00873 {
00874 QDomNode n = domElem.firstChild();
00875
00876 while (!n.isNull())
00877 {
00878 QDomElement e = n.toElement();
00879 n = n.nextSibling();
00880 if ( !e.isNull() ) {
00881 processCondition(e, items);
00882 break;
00883 }
00884 }
00885
00886 QDict<KService> andItems;
00887 while( !n.isNull() ) {
00888 QDomElement e = n.toElement();
00889 if (e.tagName() == "Not")
00890 {
00891
00892 QDomNode n2 = e.firstChild();
00893 while( !n2.isNull() ) {
00894 QDomElement e2 = n2.toElement();
00895 andItems.clear();
00896 processCondition(e2, &andItems);
00897 excludeItems(items, &andItems);
00898 n2 = n2.nextSibling();
00899 }
00900 }
00901 else
00902 {
00903 andItems.clear();
00904 processCondition(e, &andItems);
00905 matchItems(items, &andItems);
00906 }
00907 n = n.nextSibling();
00908 }
00909 }
00910 else if (domElem.tagName() == "Or")
00911 {
00912 QDomNode n = domElem.firstChild();
00913
00914 while (!n.isNull())
00915 {
00916 QDomElement e = n.toElement();
00917 n = n.nextSibling();
00918 if ( !e.isNull() ) {
00919 processCondition(e, items);
00920 break;
00921 }
00922 }
00923
00924 QDict<KService> orItems;
00925 while( !n.isNull() ) {
00926 QDomElement e = n.toElement();
00927 if ( !e.isNull() ) {
00928 orItems.clear();
00929 processCondition(e, &orItems);
00930 includeItems(items, &orItems);
00931 }
00932 n = n.nextSibling();
00933 }
00934 }
00935 else if (domElem.tagName() == "Not")
00936 {
00937 FOR_ALL_APPLICATIONS(it)
00938 {
00939 KService *s = it.current();
00940 items->replace(s->menuId(), s);
00941 }
00942 FOR_ALL_APPLICATIONS_END
00943
00944 QDict<KService> notItems;
00945 QDomNode n = domElem.firstChild();
00946 while( !n.isNull() ) {
00947 QDomElement e = n.toElement();
00948 if ( !e.isNull() ) {
00949 notItems.clear();
00950 processCondition(e, ¬Items);
00951 excludeItems(items, ¬Items);
00952 }
00953 n = n.nextSibling();
00954 }
00955 }
00956 else if (domElem.tagName() == "Category")
00957 {
00958 FOR_CATEGORY(domElem.text(), it)
00959 {
00960 KService *s = *it;
00961 items->replace(s->menuId(), s);
00962 }
00963 FOR_CATEGORY_END
00964 }
00965 else if (domElem.tagName() == "All")
00966 {
00967 FOR_ALL_APPLICATIONS(it)
00968 {
00969 KService *s = it.current();
00970 items->replace(s->menuId(), s);
00971 }
00972 FOR_ALL_APPLICATIONS_END
00973 }
00974 else if (domElem.tagName() == "Filename")
00975 {
00976 QString filename = domElem.text();
00977 kdDebug(7021) << "Adding file " << filename << endl;
00978 KService *s = findApplication(filename);
00979 if (s)
00980 items->replace(filename, s);
00981 }
00982 }
00983
00984 void
00985 VFolderMenu::loadApplications(const QString &dir, const QString &prefix)
00986 {
00987 kdDebug(7021) << "Looking up applications under " << dir << endl;
00988
00989
00990 DIR *dp = opendir( QFile::encodeName(dir));
00991 if (!dp)
00992 return;
00993
00994 struct dirent *ep;
00995 KDE_struct_stat buff;
00996
00997 QString _dot(".");
00998 QString _dotdot("..");
00999
01000 while( ( ep = readdir( dp ) ) != 0L )
01001 {
01002 QString fn( QFile::decodeName(ep->d_name));
01003 if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~')
01004 continue;
01005
01006 QString pathfn = dir + fn;
01007 if ( KDE_stat( QFile::encodeName(pathfn), &buff ) != 0 ) {
01008 continue;
01009 }
01010 if ( S_ISDIR( buff.st_mode )) {
01011 loadApplications(pathfn + '/', prefix + fn + '-');
01012 continue;
01013 }
01014
01015 if ( S_ISREG( buff.st_mode))
01016 {
01017 if (!fn.endsWith(".desktop"))
01018 continue;
01019
01020 KService *service = 0;
01021 emit newService(pathfn, &service);
01022 if (service)
01023 addApplication(prefix+fn, service);
01024 }
01025 }
01026 closedir( dp );
01027 }
01028
01029 void
01030 VFolderMenu::processKDELegacyDirs()
01031 {
01032 kdDebug(7021) << "processKDELegacyDirs()" << endl;
01033
01034 QDict<KService> items;
01035 QString prefix = "kde-";
01036
01037 QStringList relFiles;
01038 QRegExp files("\\.(desktop|kdelnk)$");
01039 QRegExp dirs("\\.directory$");
01040
01041 (void) KGlobal::dirs()->findAllResources( "apps",
01042 QString::null,
01043 true,
01044 true,
01045 relFiles);
01046 for(QStringList::ConstIterator it = relFiles.begin();
01047 it != relFiles.end(); ++it)
01048 {
01049 if (!m_forcedLegacyLoad && (dirs.search(*it) != -1))
01050 {
01051 QString name = *it;
01052 if (!name.endsWith("/.directory"))
01053 continue;
01054
01055 name = name.left(name.length()-11);
01056
01057 SubMenu *newMenu = new SubMenu;
01058 newMenu->directoryFile = locate("apps", *it);
01059
01060 insertSubMenu(m_currentMenu, name, newMenu);
01061 continue;
01062 }
01063
01064 if (files.search(*it) != -1)
01065 {
01066 QString name = *it;
01067 KService *service = 0;
01068 emit newService(name, &service);
01069
01070 if (service && !m_forcedLegacyLoad)
01071 {
01072 QString id = name;
01073
01074 int i = id.findRev('/');
01075 if (i >= 0)
01076 id = id.mid(i+1);
01077
01078 id.prepend(prefix);
01079
01080
01081 addApplication(id, service);
01082 items.replace(service->menuId(), service);
01083 if (service->categories().isEmpty())
01084 insertService(m_currentMenu, name, service);
01085
01086 }
01087 }
01088 }
01089 markUsedApplications(&items);
01090 m_legacyLoaded = true;
01091 }
01092
01093 void
01094 VFolderMenu::processLegacyDir(const QString &dir, const QString &relDir, const QString &prefix)
01095 {
01096 kdDebug(7021) << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")" << endl;
01097
01098 QDict<KService> items;
01099
01100 DIR *dp = opendir( QFile::encodeName(dir));
01101 if (!dp)
01102 return;
01103
01104 struct dirent *ep;
01105 KDE_struct_stat buff;
01106
01107 QString _dot(".");
01108 QString _dotdot("..");
01109
01110 while( ( ep = readdir( dp ) ) != 0L )
01111 {
01112 QString fn( QFile::decodeName(ep->d_name));
01113 if (fn == _dot || fn == _dotdot || fn.at(fn.length() - 1).latin1() == '~')
01114 continue;
01115
01116 QString pathfn = dir + fn;
01117 if ( KDE_stat( QFile::encodeName(pathfn), &buff ) != 0 ) {
01118 continue;
01119 }
01120 if ( S_ISDIR( buff.st_mode )) {
01121 SubMenu *parentMenu = m_currentMenu;
01122
01123 m_currentMenu = new SubMenu;
01124 m_currentMenu->name = fn;
01125 m_currentMenu->directoryFile = dir + fn + "/.directory";
01126
01127 parentMenu->subMenus.append(m_currentMenu);
01128
01129 processLegacyDir(pathfn + '/', relDir+fn+'/', prefix);
01130 m_currentMenu = parentMenu;
01131 continue;
01132 }
01133
01134 if ( S_ISREG( buff.st_mode))
01135 {
01136 if (!fn.endsWith(".desktop"))
01137 continue;
01138
01139 KService *service = 0;
01140 emit newService(pathfn, &service);
01141 if (service)
01142 {
01143 QString id = prefix+fn;
01144
01145
01146 addApplication(id, service);
01147 items.replace(service->menuId(), service);
01148
01149 if (service->categories().isEmpty())
01150 m_currentMenu->items.replace(id, service);
01151 }
01152 }
01153 }
01154 closedir( dp );
01155 markUsedApplications(&items);
01156 }
01157
01158
01159
01160 void
01161 VFolderMenu::processMenu(QDomElement &docElem, int pass)
01162 {
01163 SubMenu *parentMenu = m_currentMenu;
01164 unsigned int oldDirectoryDirsCount = m_directoryDirs.count();
01165
01166 QString name;
01167 QString directoryFile;
01168 bool onlyUnallocated = false;
01169 bool isDeleted = false;
01170 bool kdeLegacyDirsDone = false;
01171 QDomElement defaultLayoutNode;
01172 QDomElement layoutNode;
01173
01174 QDomElement query;
01175 QDomNode n = docElem.firstChild();
01176 while( !n.isNull() ) {
01177 QDomElement e = n.toElement();
01178 if (e.tagName() == "Name")
01179 {
01180 name = e.text();
01181 }
01182 else if (e.tagName() == "Directory")
01183 {
01184 directoryFile = e.text();
01185 }
01186 else if (e.tagName() == "DirectoryDir")
01187 {
01188 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01189
01190 m_directoryDirs.prepend(dir);
01191 }
01192 else if (e.tagName() == "OnlyUnallocated")
01193 {
01194 onlyUnallocated = true;
01195 }
01196 else if (e.tagName() == "NotOnlyUnallocated")
01197 {
01198 onlyUnallocated = false;
01199 }
01200 else if (e.tagName() == "Deleted")
01201 {
01202 isDeleted = true;
01203 }
01204 else if (e.tagName() == "NotDeleted")
01205 {
01206 isDeleted = false;
01207 }
01208 else if (e.tagName() == "DefaultLayout")
01209 {
01210 defaultLayoutNode = e;
01211 }
01212 else if (e.tagName() == "Layout")
01213 {
01214 layoutNode = e;
01215 }
01216 n = n.nextSibling();
01217 }
01218
01219
01220 if (pass == 0)
01221 {
01222 m_currentMenu = 0;
01223
01224 if (parentMenu)
01225 {
01226 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
01227 {
01228 if (menu->name == name)
01229 {
01230 m_currentMenu = menu;
01231 break;
01232 }
01233 }
01234 }
01235
01236 if (!m_currentMenu)
01237 {
01238
01239 m_currentMenu = new SubMenu;
01240 m_currentMenu->name = name;
01241
01242 if (parentMenu)
01243 parentMenu->subMenus.append(m_currentMenu);
01244 else
01245 m_rootMenu = m_currentMenu;
01246 }
01247 if (directoryFile.isEmpty())
01248 {
01249 kdDebug(7021) << "Menu " << name << " does not specify a directory file." << endl;
01250 }
01251
01252
01253 QString tmp = locateDirectoryFile(directoryFile);
01254 if (! tmp.isEmpty())
01255 m_currentMenu->directoryFile = tmp;
01256 m_currentMenu->isDeleted = isDeleted;
01257
01258 m_currentMenu->defaultLayoutNode = defaultLayoutNode;
01259 m_currentMenu->layoutNode = layoutNode;
01260 }
01261 else
01262 {
01263
01264 if (parentMenu)
01265 {
01266 for(SubMenu *menu = parentMenu->subMenus.first(); menu; menu = parentMenu->subMenus.next())
01267 {
01268 if (menu->name == name)
01269 {
01270 m_currentMenu = menu;
01271 break;
01272 }
01273 }
01274 }
01275 else
01276 {
01277 m_currentMenu = m_rootMenu;
01278 }
01279 }
01280
01281
01282 if (pass == 0)
01283 {
01284 QDomElement query;
01285 QDomNode n = docElem.firstChild();
01286 while( !n.isNull() ) {
01287 QDomElement e = n.toElement();
01288 if (e.tagName() == "AppDir")
01289 {
01290 createAppsInfo();
01291 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01292
01293 registerDirectory(dir);
01294
01295 loadApplications(dir, QString::null);
01296 }
01297 else if (e.tagName() == "KDELegacyDirs")
01298 {
01299 createAppsInfo();
01300 if (!kdeLegacyDirsDone)
01301 {
01302 kdDebug(7021) << "Processing KDE Legacy dirs for <KDE>" << endl;
01303 SubMenu *oldMenu = m_currentMenu;
01304 m_currentMenu = new SubMenu;
01305
01306 processKDELegacyDirs();
01307
01308 m_legacyNodes.replace("<KDE>", m_currentMenu);
01309 m_currentMenu = oldMenu;
01310
01311 kdeLegacyDirsDone = true;
01312 }
01313 }
01314 else if (e.tagName() == "LegacyDir")
01315 {
01316 createAppsInfo();
01317 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01318
01319 QString prefix = e.attributes().namedItem("prefix").toAttr().value();
01320
01321 if (m_defaultLegacyDirs.contains(dir))
01322 {
01323 if (!kdeLegacyDirsDone)
01324 {
01325 kdDebug(7021) << "Processing KDE Legacy dirs for " << dir << endl;
01326 SubMenu *oldMenu = m_currentMenu;
01327 m_currentMenu = new SubMenu;
01328
01329 processKDELegacyDirs();
01330
01331 m_legacyNodes.replace("<KDE>", m_currentMenu);
01332 m_currentMenu = oldMenu;
01333
01334 kdeLegacyDirsDone = true;
01335 }
01336 }
01337 else
01338 {
01339 SubMenu *oldMenu = m_currentMenu;
01340 m_currentMenu = new SubMenu;
01341
01342 registerDirectory(dir);
01343
01344 processLegacyDir(dir, QString::null, prefix);
01345
01346 m_legacyNodes.replace(dir, m_currentMenu);
01347 m_currentMenu = oldMenu;
01348 }
01349 }
01350 n = n.nextSibling();
01351 }
01352 }
01353
01354 loadAppsInfo();
01355
01356 if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
01357 {
01358 n = docElem.firstChild();
01359
01360 while( !n.isNull() ) {
01361 QDomElement e = n.toElement();
01362 if (e.tagName() == "Include")
01363 {
01364 QDict<KService> items;
01365
01366 QDomNode n2 = e.firstChild();
01367 while( !n2.isNull() ) {
01368 QDomElement e2 = n2.toElement();
01369 items.clear();
01370 processCondition(e2, &items);
01371 if (m_track)
01372 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "Before <Include>");
01373 includeItems(&(m_currentMenu->items), &items);
01374 excludeItems(&(m_currentMenu->excludeItems), &items);
01375 markUsedApplications(&items);
01376
01377 if (m_track)
01378 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "After <Include>");
01379
01380 n2 = n2.nextSibling();
01381 }
01382 }
01383
01384 else if (e.tagName() == "Exclude")
01385 {
01386 QDict<KService> items;
01387
01388 QDomNode n2 = e.firstChild();
01389 while( !n2.isNull() ) {
01390 QDomElement e2 = n2.toElement();
01391 items.clear();
01392 processCondition(e2, &items);
01393 if (m_track)
01394 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "Before <Exclude>");
01395 excludeItems(&(m_currentMenu->items), &items);
01396 includeItems(&(m_currentMenu->excludeItems), &items);
01397 if (m_track)
01398 track(m_trackId, m_currentMenu->name, &(m_currentMenu->items), &(m_currentMenu->excludeItems), &items, "After <Exclude>");
01399 n2 = n2.nextSibling();
01400 }
01401 }
01402
01403 n = n.nextSibling();
01404 }
01405 }
01406
01407 n = docElem.firstChild();
01408 while( !n.isNull() ) {
01409 QDomElement e = n.toElement();
01410 if (e.tagName() == "Menu")
01411 {
01412 processMenu(e, pass);
01413 }
01414
01415
01416
01417
01418 else if (pass == 0)
01419 {
01420 if (e.tagName() == "LegacyDir")
01421 {
01422
01423 QString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01424 SubMenu *legacyMenu = m_legacyNodes.find(dir);
01425 if (legacyMenu)
01426 {
01427 mergeMenu(m_currentMenu, legacyMenu);
01428 }
01429 }
01430
01431 else if (e.tagName() == "KDELegacyDirs")
01432 {
01433
01434 QString dir = "<KDE>";
01435 SubMenu *legacyMenu = m_legacyNodes.find(dir);
01436 if (legacyMenu)
01437 {
01438 mergeMenu(m_currentMenu, legacyMenu);
01439 }
01440 }
01441 }
01442 n = n.nextSibling();
01443 }
01444
01445 if (pass == 2)
01446 {
01447 n = docElem.firstChild();
01448 while( !n.isNull() ) {
01449 QDomElement e = n.toElement();
01450 if (e.tagName() == "Move")
01451 {
01452 QString orig;
01453 QString dest;
01454 QDomNode n2 = e.firstChild();
01455 while( !n2.isNull() ) {
01456 QDomElement e2 = n2.toElement();
01457 if( e2.tagName() == "Old")
01458 orig = e2.text();
01459 if( e2.tagName() == "New")
01460 dest = e2.text();
01461 n2 = n2.nextSibling();
01462 }
01463 kdDebug(7021) << "Moving " << orig << " to " << dest << endl;
01464 if (!orig.isEmpty() && !dest.isEmpty())
01465 {
01466 SubMenu *menu = takeSubMenu(m_currentMenu, orig);
01467 if (menu)
01468 {
01469 insertSubMenu(m_currentMenu, dest, menu, true);
01470 }
01471 }
01472 }
01473 n = n.nextSibling();
01474 }
01475
01476 }
01477
01478 unloadAppsInfo();
01479
01480 while (m_directoryDirs.count() > oldDirectoryDirsCount)
01481 m_directoryDirs.pop_front();
01482
01483 m_currentMenu = parentMenu;
01484 }
01485
01486
01487
01488 static QString parseAttribute( const QDomElement &e)
01489 {
01490 QString option;
01491 if ( e.hasAttribute( "show_empty" ) )
01492 {
01493 QString str = e.attribute( "show_empty" );
01494 if ( str=="true" )
01495 option= "ME ";
01496 else if ( str=="false" )
01497 option= "NME ";
01498 else
01499 kdDebug()<<" Error in parsing show_empty attribute :"<<str<<endl;
01500 }
01501 if ( e.hasAttribute( "inline" ) )
01502 {
01503 QString str = e.attribute( "inline" );
01504 if ( str=="true" )
01505 option+="I ";
01506 else if ( str=="false" )
01507 option+="NI ";
01508 else
01509 kdDebug()<<" Error in parsing inlibe attribute :"<<str<<endl;
01510 }
01511 if ( e.hasAttribute( "inline_limit" ) )
01512 {
01513 bool ok;
01514 int value = e.attribute( "inline_limit" ).toInt(&ok);
01515 if ( ok )
01516 option+=QString( "IL[%1] " ).arg( value );
01517 }
01518 if ( e.hasAttribute( "inline_header" ) )
01519 {
01520 QString str = e.attribute( "inline_header" );
01521 if ( str=="true")
01522 option+="IH ";
01523 else if ( str == "false" )
01524 option+="NIH ";
01525 else
01526 kdDebug()<<" Error in parsing of inline_header attribute :"<<str<<endl;
01527
01528 }
01529 if ( e.hasAttribute( "inline_alias" ) && e.attribute( "inline_alias" )=="true")
01530 {
01531 QString str = e.attribute( "inline_alias" );
01532 if ( str=="true" )
01533 option+="IA";
01534 else if ( str=="false" )
01535 option+="NIA";
01536 else
01537 kdDebug()<<" Error in parsing inline_alias attribute :"<<str<<endl;
01538 }
01539 if( !option.isEmpty())
01540 {
01541 option = option.prepend(":O");
01542 }
01543 return option;
01544
01545 }
01546
01547 static QStringList parseLayoutNode(const QDomElement &docElem)
01548 {
01549 QStringList layout;
01550
01551 QString optionDefaultLayout;
01552 if( docElem.tagName()=="DefaultLayout")
01553 optionDefaultLayout = parseAttribute( docElem);
01554 if ( !optionDefaultLayout.isEmpty() )
01555 layout.append( optionDefaultLayout );
01556
01557 QDomNode n = docElem.firstChild();
01558 while( !n.isNull() ) {
01559 QDomElement e = n.toElement();
01560 if (e.tagName() == "Separator")
01561 {
01562 layout.append(":S");
01563 }
01564 else if (e.tagName() == "Filename")
01565 {
01566 layout.append(e.text());
01567 }
01568 else if (e.tagName() == "Menuname")
01569 {
01570 layout.append("/"+e.text());
01571 QString option = parseAttribute( e );
01572 if( !option.isEmpty())
01573 layout.append( option );
01574 }
01575 else if (e.tagName() == "Merge")
01576 {
01577 QString type = e.attributeNode("type").value();
01578 if (type == "files")
01579 layout.append(":F");
01580 else if (type == "menus")
01581 layout.append(":M");
01582 else if (type == "all")
01583 layout.append(":A");
01584 }
01585
01586 n = n.nextSibling();
01587 }
01588 return layout;
01589 }
01590
01591 void
01592 VFolderMenu::layoutMenu(VFolderMenu::SubMenu *menu, QStringList defaultLayout)
01593 {
01594 if (!menu->defaultLayoutNode.isNull())
01595 {
01596 defaultLayout = parseLayoutNode(menu->defaultLayoutNode);
01597 }
01598
01599 if (menu->layoutNode.isNull())
01600 {
01601 menu->layoutList = defaultLayout;
01602 }
01603 else
01604 {
01605 menu->layoutList = parseLayoutNode(menu->layoutNode);
01606 if (menu->layoutList.isEmpty())
01607 menu->layoutList = defaultLayout;
01608 }
01609
01610 for(VFolderMenu::SubMenu *subMenu = menu->subMenus.first(); subMenu; subMenu = menu->subMenus.next())
01611 {
01612 layoutMenu(subMenu, defaultLayout);
01613 }
01614 }
01615
01616 void
01617 VFolderMenu::markUsedApplications(QDict<KService> *items)
01618 {
01619 for(QDictIterator<KService> it(*items); it.current(); ++it)
01620 {
01621 m_usedAppsDict.replace(it.current()->menuId(), it.current());
01622 }
01623 }
01624
01625 VFolderMenu::SubMenu *
01626 VFolderMenu::parseMenu(const QString &file, bool forceLegacyLoad)
01627 {
01628 m_forcedLegacyLoad = false;
01629 m_legacyLoaded = false;
01630 m_appsInfo = 0;
01631
01632 QStringList dirs = KGlobal::dirs()->resourceDirs("xdgconf-menu");
01633 for(QStringList::ConstIterator it=dirs.begin();
01634 it != dirs.end(); ++it)
01635 {
01636 registerDirectory(*it);
01637 }
01638
01639 loadMenu(file);
01640
01641 delete m_rootMenu;
01642 m_rootMenu = m_currentMenu = 0;
01643
01644 QDomElement docElem = m_doc.documentElement();
01645
01646 for (int pass = 0; pass <= 2; pass++)
01647 {
01648 processMenu(docElem, pass);
01649
01650 if (pass == 0)
01651 {
01652 buildApplicationIndex(false);
01653 }
01654 if (pass == 1)
01655 {
01656 buildApplicationIndex(true);
01657 }
01658 if (pass == 2)
01659 {
01660 QStringList defaultLayout;
01661 defaultLayout << ":M";
01662 defaultLayout << ":F";
01663 layoutMenu(m_rootMenu, defaultLayout);
01664 }
01665 }
01666
01667 if (!m_legacyLoaded && forceLegacyLoad)
01668 {
01669 m_forcedLegacyLoad = true;
01670 processKDELegacyDirs();
01671 }
01672
01673 return m_rootMenu;
01674 }
01675
01676 void
01677 VFolderMenu::setTrackId(const QString &id)
01678 {
01679 m_track = !id.isEmpty();
01680 m_trackId = id;
01681 }
01682
01683 #include "vfolder_menu.moc"