• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kded
 

kded

vfolder_menu.cpp

00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
00003  *
00004  *  This library is free software; you can redistribute it and/or
00005  *  modify it under the terms of the GNU Library General Public
00006  *  License version 2 as published by the Free Software Foundation;
00007  *
00008  *  This library is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  *  Library General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU Library General Public License
00014  *  along with this library; see the file COPYING.LIB.  If not, write to
00015  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016  *  Boston, MA 02110-1301, USA.
00017  **/
00018 
00019 #include <sys/types.h>
00020 #include <sys/stat.h>
00021 #include <unistd.h>
00022 #include <dirent.h>
00023 #include <stdlib.h> // getenv
00024 
00025 #include <kdebug.h>
00026 #include <tdeglobal.h>
00027 #include <kstandarddirs.h>
00028 #include <kservice.h>
00029 #include <kde_file.h>
00030 
00031 #include <tqmap.h>
00032 #include <tqfile.h>
00033 #include <tqdir.h>
00034 #include <tqregexp.h>
00035 
00036 #include "vfolder_menu.h"
00037 
00038 static void foldNode(TQDomElement &docElem, TQDomElement &e, TQMap<TQString,TQDomElement> &dupeList, TQString s=TQString::null)
00039 {
00040    if (s.isEmpty())
00041       s = e.text();
00042    TQMap<TQString,TQDomElement>::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(TQDomElement &docElem, TQDomNode &n, const TQStringList &list, const TQString &tag)
00054 {
00055    for(TQStringList::ConstIterator it = list.begin();
00056        it != list.end(); ++it)
00057    {
00058       TQDomElement e = docElem.ownerDocument().createElement(tag);
00059       TQDomText txt = docElem.ownerDocument().createTextNode(*it);
00060       e.appendChild(txt);
00061       docElem.insertAfter(e, n);
00062    }
00063 
00064    TQDomNode next = n.nextSibling();
00065    docElem.removeChild(n);
00066    n = next;
00067 //   kdDebug(7021) << "Next tag = " << n.toElement().tagName() << endl;
00068 }
00069 
00070 void VFolderMenu::registerFile(const TQString &file)
00071 {
00072    int i = file.findRev('/');
00073    if (i < 0)
00074       return;
00075 
00076    TQString dir = file.left(i+1); // Include trailing '/'
00077    registerDirectory(dir);
00078 }
00079 
00080 void VFolderMenu::registerDirectory(const TQString &directory)
00081 {
00082    m_allDirectories.append(directory);
00083 }
00084 
00085 TQStringList VFolderMenu::allDirectories()
00086 {
00087    if (m_allDirectories.isEmpty())
00088      return m_allDirectories;
00089    m_allDirectories.sort();
00090 
00091    TQStringList::Iterator it = m_allDirectories.begin();
00092    TQString 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 TQString &menuId, const TQString &menuName, TQDict<KService> *includeList, TQDict<KService> *excludeList, TQDict<KService> *itemList, const TQString &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(TQDict<KService> *items1, TQDict<KService> *items2)
00117 {
00118    for(TQDictIterator<KService> it(*items2); it.current(); ++it)
00119    {
00120        items1->replace(it.current()->menuId(), it.current());
00121    }
00122 }
00123 
00124 void
00125 VFolderMenu::matchItems(TQDict<KService> *items1, TQDict<KService> *items2)
00126 {
00127    for(TQDictIterator<KService> it(*items1); it.current(); )
00128    {
00129        TQString id = it.current()->menuId();
00130        ++it;
00131        if (!items2->find(id))
00132           items1->remove(id);
00133    }
00134 }
00135 
00136 void
00137 VFolderMenu::excludeItems(TQDict<KService> *items1, TQDict<KService> *items2)
00138 {
00139    for(TQDictIterator<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 TQString &menuName)
00147 {
00148    int i = menuName.find('/');
00149    TQString s1 = i > 0 ? menuName.left(i) : menuName;
00150    TQString s2 = menuName.mid(i+1);
00151 
00152    // Look up menu
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             // Take it out
00160             return parentMenu->subMenus.take();
00161          }
00162          else
00163          {
00164             return takeSubMenu(menu, s2);
00165          }
00166       }
00167    }
00168    return 0; // Not found
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), TQString("Before MenuMerge w. %1 (incl)").arg(menu2->name));
00177       track(m_trackId, menu1->name, &(menu1->items), &(menu1->excludeItems), &(menu2->excludeItems), TQString("Before MenuMerge w. %1 (excl)").arg(menu2->name));
00178    }
00179    if (reversePriority)
00180    {
00181       // Merge menu1 with menu2, menu1 takes precedent
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       // Merge menu1 with menu2, menu2 takes precedent
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       // Merge menu1 with menu2, menu1 takes precedent
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       // Merge menu1 with menu2, menu2 takes precedent
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), TQString("After MenuMerge w. %1 (incl)").arg(menu2->name));
00225       track(m_trackId, menu1->name, &(menu1->items), &(menu1->excludeItems), &(menu2->excludeItems), TQString("After MenuMerge w. %1 (excl)").arg(menu2->name));
00226    }
00227 
00228    delete menu2;
00229 }
00230 
00231 void
00232 VFolderMenu::insertSubMenu(SubMenu *parentMenu, const TQString &menuName, SubMenu *newMenu, bool reversePriority)
00233 {
00234    int i = menuName.find('/');
00235 
00236    TQString s1 = menuName.left(i);
00237    TQString s2 = menuName.mid(i+1);
00238 
00239    // Look up menu
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      // Add it here
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 TQString &name, KService *newService)
00273 {
00274    int i = name.find('/');
00275 
00276    if (i == -1)
00277    {
00278      // Add it here
00279      parentMenu->items.replace(newService->menuId(), newService);
00280      return;
00281    }
00282 
00283    TQString s1 = name.left(i);
00284    TQString s2 = name.mid(i+1);
00285 
00286    // Look up menu
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(TQDictIterator<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 TQString &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 TQString &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    TQPtrList<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(TQDictIterator<KService> it( info->applications );
00362           it.current(); )
00363       {
00364          KService *s = it.current();
00365          TQDictIterator<KService> tmpIt = it;
00366          ++it;
00367          if (unusedOnly && m_usedAppsDict.find(s->menuId()))
00368          {
00369             // Remove and skip this one
00370             info->applications.remove(tmpIt.currentKey());
00371             continue;
00372          }
00373 
00374          TQStringList cats = s->categories();
00375          for(TQStringList::ConstIterator it2 = cats.begin();
00376              it2 != cats.end(); ++it2)
00377          {
00378             const TQString &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; // No appsInfo for this menu
00408 
00409    if (m_appsInfoStack.first() == m_appsInfo)
00410       return; // Already added (By createAppsInfo?)
00411 
00412    m_appsInfoStack.prepend(m_appsInfo); // Add
00413 }
00414 
00415 void
00416 VFolderMenu::unloadAppsInfo()
00417 {
00418    m_appsInfo = m_currentMenu->apps_info;
00419    if (!m_appsInfo)
00420       return; // No appsInfo for this menu
00421 
00422    if (m_appsInfoStack.first() != m_appsInfo)
00423    {
00424       return; // Already removed (huh?)
00425    }
00426 
00427    m_appsInfoStack.remove(m_appsInfo); // Remove
00428    m_appsInfo = 0;
00429 }
00430 
00431 TQString
00432 VFolderMenu::absoluteDir(const TQString &_dir, const TQString &baseDir, bool keepRelativeToCfg)
00433 {
00434    TQString dir = _dir;
00435    if (TQDir::isRelativePath(dir))
00436    {
00437       dir = baseDir + dir;
00438    }
00439    if (!dir.endsWith("/"))
00440       dir += '/';
00441 
00442    if (TQDir::isRelativePath(dir) && !keepRelativeToCfg)
00443    {
00444       dir = TDEGlobal::dirs()->findResource("xdgconf-menu", dir);
00445    }
00446 
00447    dir = TDEGlobal::dirs()->realPath(dir);
00448 
00449    return dir;
00450 }
00451 
00452 static void tagBaseDir(TQDomDocument &doc, const TQString &tag, const TQString &dir)
00453 {
00454    TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
00455    for(int i = 0; i < (int)mergeFileList.count(); i++)
00456    {
00457       TQDomAttr attr = doc.createAttribute("__BaseDir");
00458       attr.setValue(dir);
00459       mergeFileList.item(i).toElement().setAttributeNode(attr);
00460    }
00461 }
00462 
00463 static void tagBasePath(TQDomDocument &doc, const TQString &tag, const TQString &path)
00464 {
00465    TQDomNodeList mergeFileList = doc.elementsByTagName(tag);
00466    for(int i = 0; i < (int)mergeFileList.count(); i++)
00467    {
00468       TQDomAttr attr = doc.createAttribute("__BasePath");
00469       attr.setValue(path);
00470       mergeFileList.item(i).toElement().setAttributeNode(attr);
00471    }
00472 }
00473 
00474 TQDomDocument
00475 VFolderMenu::loadDoc()
00476 {
00477    TQDomDocument doc;
00478    if ( m_docInfo.path.isEmpty() )
00479    {
00480       return doc;
00481    }
00482    TQFile 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    TQString 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(TQDomElement &parent, const TQDomNode &mergeHere)
00511 {
00512 kdDebug(7021) << "VFolderMenu::mergeFile: " << m_docInfo.path << endl;
00513    TQDomDocument doc = loadDoc();
00514 
00515    TQDomElement docElem = doc.documentElement();
00516    TQDomNode n = docElem.firstChild();
00517    TQDomNode last = mergeHere;
00518    while( !n.isNull() )
00519    {
00520       TQDomElement e = n.toElement(); // try to convert the node to an element.
00521       TQDomNode next = n.nextSibling();
00522 
00523       if (e.isNull())
00524       {
00525          // Skip
00526       }
00527       // The spec says we must ignore any Name nodes
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(TQDomElement &docElem, TQString &name)
00542 {
00543    TQMap<TQString,TQDomElement> menuNodes;
00544    TQMap<TQString,TQDomElement> directoryNodes;
00545    TQMap<TQString,TQDomElement> appDirNodes;
00546    TQMap<TQString,TQDomElement> directoryDirNodes;
00547    TQMap<TQString,TQDomElement> legacyDirNodes;
00548    TQDomElement defaultLayoutNode;
00549    TQDomElement layoutNode;
00550 
00551    TQDomNode n = docElem.firstChild();
00552    while( !n.isNull() ) {
00553       TQDomElement e = n.toElement(); // try to convert the node to an element.
00554       if( e.isNull() ) {
00555 // kdDebug(7021) << "Empty node" << endl;
00556       }
00557       else if( e.tagName() == "DefaultAppDirs") {
00558          // Replace with m_defaultAppDirs
00559          replaceNode(docElem, n, m_defaultAppDirs, "AppDir");
00560          continue;
00561       }
00562       else if( e.tagName() == "DefaultDirectoryDirs") {
00563          // Replace with m_defaultDirectoryDirs
00564          replaceNode(docElem, n, m_defaultDirectoryDirs, "DirectoryDir");
00565          continue;
00566       }
00567       else if( e.tagName() == "DefaultMergeDirs") {
00568          // Replace with m_defaultMergeDirs
00569          replaceNode(docElem, n, m_defaultMergeDirs, "MergeDir");
00570          continue;
00571       }
00572       else if( e.tagName() == "AppDir") {
00573          // Filter out dupes
00574          foldNode(docElem, e, appDirNodes);
00575       }
00576       else if( e.tagName() == "DirectoryDir") {
00577          // Filter out dupes
00578          foldNode(docElem, e, directoryDirNodes);
00579       }
00580       else if( e.tagName() == "LegacyDir") {
00581          // Filter out dupes
00582          foldNode(docElem, e, legacyDirNodes);
00583       }
00584       else if( e.tagName() == "Directory") {
00585          // Filter out dupes
00586          foldNode(docElem, e, directoryNodes);
00587       }
00588       else if( e.tagName() == "Move") {
00589          // Filter out dupes
00590          TQString orig;
00591          TQDomNode n2 = e.firstChild();
00592          while( !n2.isNull() ) {
00593             TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
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          TQString name;
00605          mergeMenus(e, name);
00606          TQMap<TQString,TQDomElement>::iterator it = menuNodes.find(name);
00607          if (it != menuNodes.end())
00608          {
00609            TQDomElement docElem2 = *it;
00610            TQDomNode n2 = docElem2.firstChild();
00611            TQDomNode first = e.firstChild();
00612            while( !n2.isNull() ) {
00613              TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
00614              TQDomNode n3 = n2.nextSibling();
00615              e.insertBefore(n2, first);
00616              docElem2.removeChild(n2);
00617              n2 = n3;
00618            }
00619            // We still have duplicated Name entries
00620            // but we don't care about that
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          TQDomNode last = n;
00638          n = n.nextSibling();
00639          docElem.removeChild(last); // Remove the MergeFile node
00640          continue;
00641       }
00642       else if( e.tagName() == "MergeDir") {
00643          TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"), true);
00644 
00645          TQStringList dirs = TDEGlobal::dirs()->findDirs("xdgconf-menu", dir);
00646          for(TQStringList::ConstIterator it=dirs.begin();
00647              it != dirs.end(); ++it)
00648          {
00649             registerDirectory(*it);
00650          }
00651 
00652          TQStringList fileList;
00653          if (!TQDir::isRelativePath(dir))
00654          {
00655             // Absolute
00656             fileList = TDEGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu", false, false);
00657          }
00658          else
00659          {
00660             // Relative
00661             (void) TDEGlobal::dirs()->findAllResources("xdgconf-menu", dir+"*.menu", false, true, fileList);
00662          }
00663 
00664          for(TQStringList::ConstIterator it=fileList.begin();
00665              it != fileList.end(); ++it)
00666          {
00667             pushDocInfo(*it);
00668             mergeFile(docElem, n);
00669             popDocInfo();
00670          }
00671 
00672          TQDomNode last = n;
00673          n = n.nextSibling();
00674          docElem.removeChild(last); // Remove the MergeDir node
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 TQString &fileName, const TQString &baseDir)
00697 {
00698    m_docInfoStack.push(m_docInfo);
00699    if (!baseDir.isEmpty())
00700    {
00701       if (!TQDir::isRelativePath(baseDir))
00702          m_docInfo.baseDir = TDEGlobal::dirs()->relativeLocation("xdgconf-menu", baseDir);
00703       else
00704          m_docInfo.baseDir = baseDir;
00705    }
00706 
00707    TQString baseName = fileName;
00708    if (!TQDir::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 = TQString::null;
00717       m_docInfo.baseName = TQString::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 = TQString::null;
00731       m_docInfo.baseName = baseName.left( baseName.length() - 5 );
00732    }
00733 }
00734 
00735 void
00736 VFolderMenu::pushDocInfoParent(const TQString &basePath, const TQString &baseDir)
00737 {
00738     m_docInfoStack.push(m_docInfo);
00739 
00740    m_docInfo.baseDir = baseDir;
00741 
00742    TQString fileName = basePath.mid(basePath.findRev('/')+1);
00743    m_docInfo.baseName = fileName.left( fileName.length() - 5 );
00744    TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
00745 
00746    TQStringList result = TDEGlobal::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 = TQString::null; // No parent found
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 TQString
00766 VFolderMenu::locateMenuFile(const TQString &fileName)
00767 {
00768    if (!TQDir::isRelativePath(fileName))
00769    {
00770       if (TDEStandardDirs::exists(fileName))
00771          return fileName;
00772       return TQString::null;
00773    }
00774 
00775    TQString result;
00776 
00777    //TQString xdgMenuPrefix = TQString::fromLocal8Bit(getenv("XDG_MENU_PREFIX"));
00778    // hardcode xdgMenuPrefix to "kde-" string until proper upstream fix
00779    TQString xdgMenuPrefix = "kde-";
00780    if (!xdgMenuPrefix.isEmpty())
00781    {
00782       TQFileInfo fileInfo(fileName);
00783 
00784       TQString fileNameOnly = fileInfo.fileName();
00785       if (!fileNameOnly.startsWith(xdgMenuPrefix))
00786          fileNameOnly = xdgMenuPrefix + fileNameOnly;
00787 
00788       TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir +
00789                                             fileInfo.dirPath() + "/" +
00790                                             fileNameOnly);
00791       result = locate("xdgconf-menu", baseName);
00792    }
00793 
00794    if (result.isEmpty())
00795    {
00796        TQString baseName = TQDir::cleanDirPath(m_docInfo.baseDir + fileName);
00797        result = locate("xdgconf-menu", baseName);
00798    }
00799 
00800    return result;
00801 }
00802 
00803 TQString
00804 VFolderMenu::locateDirectoryFile(const TQString &fileName)
00805 {
00806    if (fileName.isEmpty())
00807       return TQString::null;
00808 
00809    if (!TQDir::isRelativePath(fileName))
00810    {
00811       if (TDEStandardDirs::exists(fileName))
00812          return fileName;
00813       return TQString::null;
00814    }
00815 
00816    // First location in the list wins
00817    TQString tmp;
00818    for(TQStringList::ConstIterator it = m_directoryDirs.begin();
00819        it != m_directoryDirs.end();
00820        ++it)
00821    {
00822       tmp = (*it)+fileName;
00823       if (TDEStandardDirs::exists(tmp))
00824          return tmp;
00825    }
00826 
00827    return TQString::null;
00828 }
00829 
00830 void
00831 VFolderMenu::initDirs()
00832 {
00833    m_defaultDataDirs = TQStringList::split(':', TDEGlobal::dirs()->kfsstnd_prefixes());
00834    TQString localDir = m_defaultDataDirs.first();
00835    m_defaultDataDirs.remove(localDir); // Remove local dir
00836 
00837    m_defaultAppDirs = TDEGlobal::dirs()->findDirs("xdgdata-apps", TQString::null);
00838    m_defaultDirectoryDirs = TDEGlobal::dirs()->findDirs("xdgdata-dirs", TQString::null);
00839    m_defaultLegacyDirs = TDEGlobal::dirs()->resourceDirs("apps");
00840 }
00841 
00842 void
00843 VFolderMenu::loadMenu(const TQString &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    TQDomElement e = m_doc.documentElement();
00865    TQString name;
00866    mergeMenus(e, name);
00867 }
00868 
00869 void
00870 VFolderMenu::processCondition(TQDomElement &domElem, TQDict<KService> *items)
00871 {
00872    if (domElem.tagName() == "And")
00873    {
00874       TQDomNode n = domElem.firstChild();
00875       // Look for the first child element
00876       while (!n.isNull()) // loop in case of comments
00877       {
00878          TQDomElement e = n.toElement();
00879          n = n.nextSibling();
00880          if ( !e.isNull() ) {
00881              processCondition(e, items);
00882              break; // we only want the first one
00883          }
00884       }
00885 
00886       TQDict<KService> andItems;
00887       while( !n.isNull() ) {
00888          TQDomElement e = n.toElement();
00889          if (e.tagName() == "Not")
00890          {
00891             // Special handling for "and not"
00892             TQDomNode n2 = e.firstChild();
00893             while( !n2.isNull() ) {
00894                TQDomElement 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       TQDomNode n = domElem.firstChild();
00913       // Look for the first child element
00914       while (!n.isNull()) // loop in case of comments
00915       {
00916          TQDomElement e = n.toElement();
00917          n = n.nextSibling();
00918          if ( !e.isNull() ) {
00919              processCondition(e, items);
00920              break; // we only want the first one
00921          }
00922       }
00923 
00924       TQDict<KService> orItems;
00925       while( !n.isNull() ) {
00926          TQDomElement 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       TQDict<KService> notItems;
00945       TQDomNode n = domElem.firstChild();
00946       while( !n.isNull() ) {
00947          TQDomElement e = n.toElement();
00948          if ( !e.isNull() ) {
00949              notItems.clear();
00950              processCondition(e, &notItems);
00951              excludeItems(items, &notItems);
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       TQString 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 TQString &dir, const TQString &prefix)
00986 {
00987    kdDebug(7021) << "Looking up applications under " << dir << endl;
00988 
00989    // We look for a set of files.
00990    DIR *dp = opendir( TQFile::encodeName(dir));
00991    if (!dp)
00992       return;
00993 
00994    struct dirent *ep;
00995    KDE_struct_stat buff;
00996 
00997    TQString _dot(".");
00998    TQString _dotdot("..");
00999 
01000    while( ( ep = readdir( dp ) ) != 0L )
01001    {
01002       TQString fn( TQFile::decodeName(ep->d_name));
01003       if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() == '~')
01004          continue;
01005 
01006       TQString pathfn = dir + fn;
01007       if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
01008          continue; // Couldn't stat (e.g. no read permissions)
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    TQDict<KService> items;
01035    TQString prefix = "kde-";
01036 
01037    TQStringList relFiles;
01038    TQRegExp files("\\.(desktop|kdelnk)$");
01039    TQRegExp dirs("\\.directory$");
01040 
01041    (void) TDEGlobal::dirs()->findAllResources( "apps",
01042                                              TQString::null,
01043                                              true, // Recursive!
01044                                              true, // uniq
01045                                              relFiles);
01046    for(TQStringList::ConstIterator it = relFiles.begin();
01047        it != relFiles.end(); ++it)
01048    {
01049       if (!m_forcedLegacyLoad && (dirs.search(*it) != -1))
01050       {
01051          TQString name = *it;
01052          if (!name.endsWith("/.directory"))
01053             continue; // Probably ".directory", skip it.
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          TQString name = *it;
01067          KService *service = 0;
01068          emit newService(name, &service);
01069 
01070          if (service && !m_forcedLegacyLoad)
01071          {
01072             TQString id = name;
01073             // Strip path from id
01074             int i = id.findRev('/');
01075             if (i >= 0)
01076                id = id.mid(i+1);
01077 
01078             id.prepend(prefix);
01079 
01080             // TODO: add Legacy category
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 TQString &dir, const TQString &relDir, const TQString &prefix)
01095 {
01096 kdDebug(7021) << "processLegacyDir(" << dir << ", " << relDir << ", " << prefix << ")" << endl;
01097 
01098    TQDict<KService> items;
01099    // We look for a set of files.
01100    DIR *dp = opendir( TQFile::encodeName(dir));
01101    if (!dp)
01102       return;
01103 
01104    struct dirent *ep;
01105    KDE_struct_stat buff;
01106 
01107    TQString _dot(".");
01108    TQString _dotdot("..");
01109 
01110    while( ( ep = readdir( dp ) ) != 0L )
01111    {
01112       TQString fn( TQFile::decodeName(ep->d_name));
01113       if (fn == _dot || fn == _dotdot || TQChar(fn.at(fn.length() - 1)).latin1() == '~')
01114          continue;
01115 
01116       TQString pathfn = dir + fn;
01117       if ( KDE_stat( TQFile::encodeName(pathfn), &buff ) != 0 ) {
01118          continue; // Couldn't stat (e.g. no read permissions)
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             TQString id = prefix+fn;
01144 
01145             // TODO: Add legacy category
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(TQDomElement &docElem, int pass)
01162 {
01163    SubMenu *parentMenu = m_currentMenu;
01164    unsigned int oldDirectoryDirsCount = m_directoryDirs.count();
01165 
01166    TQString name;
01167    TQString directoryFile;
01168    bool onlyUnallocated = false;
01169    bool isDeleted = false;
01170    bool kdeLegacyDirsDone = false;
01171    TQDomElement defaultLayoutNode;
01172    TQDomElement layoutNode;
01173 
01174    TQDomElement query;
01175    TQDomNode n = docElem.firstChild();
01176    while( !n.isNull() ) {
01177       TQDomElement e = n.toElement(); // try to convert the node to an element.
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          TQString 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    // Setup current menu entry
01220    if (pass == 0)
01221    {
01222       m_currentMenu = 0;
01223       // Look up menu
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) // Not found?
01237       {
01238          // Create menu
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       // Override previous directoryFile iff available
01253       TQString 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       // Look up menu
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    // Process AppDir and LegacyDir
01282    if (pass == 0)
01283    {
01284       TQDomElement query;
01285       TQDomNode n = docElem.firstChild();
01286       while( !n.isNull() ) {
01287          TQDomElement e = n.toElement(); // try to convert the node to an element.
01288          if (e.tagName() == "AppDir")
01289          {
01290             createAppsInfo();
01291             TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01292 
01293             registerDirectory(dir);
01294 
01295             loadApplications(dir, TQString::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             TQString dir = absoluteDir(e.text(), e.attribute("__BaseDir"));
01318 
01319             TQString 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, TQString::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(); // Update the scope wrt the list of applications
01355 
01356    if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
01357    {
01358       n = docElem.firstChild();
01359 
01360       while( !n.isNull() ) {
01361          TQDomElement e = n.toElement(); // try to convert the node to an element.
01362          if (e.tagName() == "Include")
01363          {
01364             TQDict<KService> items;
01365 
01366             TQDomNode n2 = e.firstChild();
01367             while( !n2.isNull() ) {
01368                TQDomElement 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             TQDict<KService> items;
01387 
01388             TQDomNode n2 = e.firstChild();
01389             while( !n2.isNull() ) {
01390                TQDomElement 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       TQDomElement e = n.toElement(); // try to convert the node to an element.
01410       if (e.tagName() == "Menu")
01411       {
01412          processMenu(e, pass);
01413       }
01414 // We insert legacy dir in pass 0, this way the order in the .menu-file determines
01415 // which .directory file gets used, but the menu-entries of legacy-menus will always
01416 // have the lowest priority.
01417 //      else if (((pass == 1) && !onlyUnallocated) || ((pass == 2) && onlyUnallocated))
01418       else if (pass == 0)
01419       {
01420          if (e.tagName() == "LegacyDir")
01421          {
01422             // Add legacy nodes to Menu structure
01423             TQString 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             // Add legacy nodes to Menu structure
01434             TQString 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          TQDomElement e = n.toElement(); // try to convert the node to an element.
01450          if (e.tagName() == "Move")
01451          {
01452             TQString orig;
01453             TQString dest;
01454             TQDomNode n2 = e.firstChild();
01455             while( !n2.isNull() ) {
01456                TQDomElement e2 = n2.toElement(); // try to convert the node to an element.
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); // Destination has priority
01470               }
01471             }
01472          }
01473          n = n.nextSibling();
01474       }
01475 
01476    }
01477 
01478    unloadAppsInfo(); // Update the scope wrt the list of applications
01479 
01480    while (m_directoryDirs.count() > oldDirectoryDirsCount)
01481       m_directoryDirs.pop_front();
01482 
01483    m_currentMenu = parentMenu;
01484 }
01485 
01486 
01487 
01488 static TQString parseAttribute( const TQDomElement &e)
01489 {
01490     TQString option;
01491     if ( e.hasAttribute( "show_empty" ) )
01492     {
01493         TQString 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         TQString 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+=TQString( "IL[%1] " ).arg( value );
01517     }
01518     if ( e.hasAttribute( "inline_header" ) )
01519     {
01520         TQString 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         TQString 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 TQStringList parseLayoutNode(const TQDomElement &docElem)
01548 {
01549    TQStringList layout;
01550 
01551    TQString optionDefaultLayout;
01552    if( docElem.tagName()=="DefaultLayout")
01553        optionDefaultLayout =  parseAttribute( docElem);
01554    if ( !optionDefaultLayout.isEmpty() )
01555        layout.append( optionDefaultLayout );
01556 
01557    TQDomNode n = docElem.firstChild();
01558    while( !n.isNull() ) {
01559       TQDomElement e = n.toElement(); // try to convert the node to an element.
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          TQString option = parseAttribute( e );
01572          if( !option.isEmpty())
01573              layout.append( option );
01574       }
01575       else if (e.tagName() == "Merge")
01576       {
01577          TQString 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, TQStringList 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(TQDict<KService> *items)
01618 {
01619    for(TQDictIterator<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 TQString &file, bool forceLegacyLoad)
01627 {
01628    m_forcedLegacyLoad = false;
01629    m_legacyLoaded = false;
01630    m_appsInfo = 0;
01631 
01632    TQStringList dirs = TDEGlobal::dirs()->resourceDirs("xdgconf-menu");
01633    for(TQStringList::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    TQDomElement 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          TQStringList defaultLayout;
01661          defaultLayout << ":M"; // Sub-Menus
01662          defaultLayout << ":F"; // Individual entries
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 TQString &id)
01678 {
01679    m_track = !id.isEmpty();
01680    m_trackId = id;
01681 }
01682 
01683 #include "vfolder_menu.moc"

kded

Skip menu "kded"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kded

Skip menu "kded"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kded by doxygen 1.7.1
This website is maintained by Timothy Pearson.