kio Library API Documentation

kservicegroup.cpp

00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 2000 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., 59 Temple Place - Suite 330,
00016  *  Boston, MA 02111-1307, USA.
00017  **/
00018 
00019 // $Id: kservicegroup.cpp,v 1.33 2004/05/10 12:52:36 waba Exp $
00020 
00021 #include <kiconloader.h>
00022 #include <kglobal.h>
00023 #include <kstandarddirs.h>
00024 #include <klocale.h>
00025 #include <kdebug.h>
00026 #include <ksortablevaluelist.h>
00027 #include "kservicefactory.h"
00028 #include "kservicegroupfactory.h"
00029 #include "kservicegroup.h"
00030 #include "kservice.h"
00031 #include "ksycoca.h"
00032 
00033 class KServiceGroup::Private
00034 {
00035 public:
00036   Private() { m_bNoDisplay = false; m_bShortMenu = false; m_bGeneralDescription = false; }
00037   bool m_bNoDisplay;
00038   bool m_bShortMenu;
00039   bool m_bGeneralDescription;
00040   QStringList suppressGenericNames;
00041   QString directoryEntryPath;
00042   QStringList sortOrder;
00043 };
00044 
00045 KServiceGroup::KServiceGroup( const QString & name )
00046  : KSycocaEntry(name), m_childCount(-1)
00047 {
00048   d = new KServiceGroup::Private;
00049   m_bDeleted = false;
00050 }
00051 
00052 KServiceGroup::KServiceGroup( const QString &configFile, const QString & _relpath )
00053  : KSycocaEntry(_relpath), m_childCount(-1)
00054 {
00055   d = new KServiceGroup::Private;
00056   m_bDeleted = false;
00057 
00058   QString cfg = configFile;
00059   if (cfg.isEmpty())
00060      cfg = _relpath+".directory";
00061 
00062   d->directoryEntryPath = cfg;
00063 
00064   KConfig config( cfg, true, false, "apps" );
00065 
00066   config.setDesktopGroup();
00067 
00068   m_strCaption = config.readEntry( "Name" );
00069   m_strIcon = config.readEntry( "Icon" );
00070   m_strComment = config.readEntry( "Comment" );
00071   m_bDeleted = config.readBoolEntry( "Hidden", false );
00072   d->m_bNoDisplay = config.readBoolEntry( "NoDisplay", false );
00073   d->m_bShortMenu = config.readBoolEntry( "X-SuSE-AutoShortMenu", true );
00074   d->m_bGeneralDescription = config.readBoolEntry( "X-SuSE-GeneralDescription", false );
00075   QStringList tmpList;
00076   if (config.hasKey("OnlyShowIn"))
00077   {
00078      if (!config.readListEntry("OnlyShowIn", ';').contains("KDE"))
00079         d->m_bNoDisplay = true;
00080   }
00081   if (config.hasKey("NotShowIn"))
00082   {
00083      if (config.readListEntry("NotShowIn", ';').contains("KDE"))
00084         d->m_bNoDisplay = true;
00085   }
00086   
00087   m_strBaseGroupName = config.readEntry( "X-KDE-BaseGroup" );
00088   d->suppressGenericNames = config.readListEntry( "X-KDE-SuppressGenericNames" );
00089 //  d->sortOrder = config.readListEntry("SortOrder");
00090 
00091   // Fill in defaults.
00092   if (m_strCaption.isEmpty())
00093   {
00094      m_strCaption = _relpath;
00095      if (m_strCaption.right(1) == "/")
00096         m_strCaption = m_strCaption.left(m_strCaption.length()-1);
00097      int i = m_strCaption.findRev('/');
00098      if (i > 0)
00099         m_strCaption = m_strCaption.mid(i+1);
00100   }
00101   if (m_strIcon.isEmpty())
00102      m_strIcon = "folder";
00103 }
00104 
00105 KServiceGroup::KServiceGroup( QDataStream& _str, int offset, bool deep ) :
00106     KSycocaEntry( _str, offset )
00107 {
00108   d = new KServiceGroup::Private;
00109   m_bDeep = deep;
00110   load( _str );
00111 }
00112 
00113 KServiceGroup::~KServiceGroup()
00114 {
00115   delete d;
00116 }
00117 
00118 int KServiceGroup::childCount()
00119 {
00120   if (m_childCount == -1)
00121   {
00122      KConfig global("kdeglobals");
00123      global.setGroup("KDE");
00124      bool showUnimportant = global.readBoolEntry("showUnimportant", false);
00125 
00126      m_childCount = 0;
00127 
00128      for( List::ConstIterator it = m_serviceList.begin();
00129           it != m_serviceList.end(); it++)
00130      {
00131         KSycocaEntry *p = (*it);
00132         if (p->isType(KST_KService))
00133         {
00134            KService *service = static_cast<KService *>(p);
00135            if (!service->noDisplay())
00136              if ( showUnimportant || !service->SuSEunimportant() )
00137                m_childCount++;
00138         }
00139         else if (p->isType(KST_KServiceGroup))
00140         {
00141            KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
00142            m_childCount += serviceGroup->childCount();
00143         }
00144      }
00145   }
00146   return m_childCount;
00147 }
00148 
00149 
00150 bool KServiceGroup::noDisplay() const
00151 {
00152   return d->m_bNoDisplay || m_strCaption.startsWith(".");
00153 }
00154 
00155 QStringList KServiceGroup::suppressGenericNames() const
00156 {
00157   return d->suppressGenericNames;
00158 }
00159 
00160 bool KServiceGroup::SuSEgeneralDescription() const
00161 {
00162     return d->m_bGeneralDescription;
00163 }
00164 
00165 bool KServiceGroup::SuSEshortMenu() const
00166 {
00167     return d->m_bShortMenu;
00168 }
00169 
00170 void KServiceGroup::load( QDataStream& s )
00171 {
00172   QStringList groupList;
00173   Q_INT8 noDisplay;
00174   s >> m_strCaption >> m_strIcon >>
00175       m_strComment >> groupList >> m_strBaseGroupName >> m_childCount >>
00176       noDisplay >> d->suppressGenericNames >> d->directoryEntryPath >>
00177       d->sortOrder >> d->m_bShortMenu >> d->m_bGeneralDescription;
00178 
00179   d->m_bNoDisplay = (noDisplay != 0);
00180 
00181   if (m_bDeep)
00182   {
00183      for(QStringList::ConstIterator it = groupList.begin();
00184          it != groupList.end(); it++)
00185      {
00186         QString path = *it;
00187         if (path[path.length()-1] == '/')
00188         {
00189            KServiceGroup *serviceGroup;
00190            serviceGroup = KServiceGroupFactory::self()->findGroupByDesktopPath(path, false);
00191            if (serviceGroup)
00192               m_serviceList.append( SPtr(serviceGroup) );
00193         }
00194         else
00195         {
00196            KService *service;
00197            service = KServiceFactory::self()->findServiceByDesktopPath(path);
00198            if (service)
00199               m_serviceList.append( SPtr(service) );
00200         }
00201      }
00202   }
00203 }
00204 
00205 void KServiceGroup::addEntry( KSycocaEntry *entry)
00206 {
00207   m_serviceList.append(entry);
00208 }
00209 
00210 void KServiceGroup::save( QDataStream& s )
00211 {
00212   KSycocaEntry::save( s );
00213 
00214   QStringList groupList;
00215   for( List::ConstIterator it = m_serviceList.begin();
00216        it != m_serviceList.end(); it++)
00217   {
00218      KSycocaEntry *p = (*it);
00219      if (p->isType(KST_KService))
00220      {
00221         KService *service = static_cast<KService *>(p);
00222         groupList.append( service->desktopEntryPath());
00223      }
00224      else if (p->isType(KST_KServiceGroup))
00225      {
00226         KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
00227         groupList.append( serviceGroup->relPath());
00228      }
00229      else
00230      {
00231         //fprintf(stderr, "KServiceGroup: Unexpected object in list!\n");
00232      }
00233   }
00234 
00235   (void) childCount();
00236 
00237   Q_INT8 noDisplay = d->m_bNoDisplay ? 1 : 0;
00238   s << m_strCaption << m_strIcon <<
00239       m_strComment << groupList << m_strBaseGroupName << m_childCount <<
00240       noDisplay << d->suppressGenericNames << d->directoryEntryPath <<
00241       d->sortOrder << d->m_bShortMenu << d->m_bGeneralDescription;
00242 }
00243 
00244 KServiceGroup::List
00245 KServiceGroup::entries(bool sort)
00246 {
00247    return entries(sort, true);
00248 }
00249 
00250 KServiceGroup::List
00251 KServiceGroup::entries(bool sort, bool excludeNoDisplay)
00252 {
00253    return entries(sort, excludeNoDisplay, false);
00254 }
00255 
00256 static void addItem(KServiceGroup::List &sorted, const KSycocaEntry::Ptr &p, bool &addSeparator)
00257 {
00258    if (addSeparator && !sorted.isEmpty())
00259       sorted.append(new KServiceSeparator());
00260    sorted.append(p);
00261    addSeparator = false;
00262 }
00263 
00264 KServiceGroup::List
00265 KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
00266 {
00267    return SuSEentries(sort, excludeNoDisplay, allowSeparators, sortByGenericName);
00268 }
00269 
00270 KServiceGroup::List
00271 KServiceGroup::SuSEentries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName, bool excludeSuSEunimportant)
00272 {
00273     KServiceGroup *group = this;
00274 
00275     // If the entries haven't been loaded yet, we have to reload ourselves
00276     // together with the entries. We can't only load the entries afterwards
00277     // since the offsets could have been changed if the database has changed.
00278 
00279     if (!m_bDeep) {
00280 
00281         group =
00282             KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true);
00283 
00284         if (0 == group) // No guarantee that we still exist!
00285             return List();
00286     }
00287 
00288     if (!sort)
00289         return group->m_serviceList;
00290 
00291     // Sort the list alphabetically, according to locale.
00292     // Groups come first, then services.
00293 
00294     KSortableValueList<SPtr,QCString> slist;
00295     KSortableValueList<SPtr,QCString> glist;
00296     for (List::ConstIterator it(group->m_serviceList.begin()); it != group->m_serviceList.end(); ++it)
00297     {
00298         KSycocaEntry *p = (*it);
00299     bool noDisplay = p->isType(KST_KServiceGroup) ?
00300                                    static_cast<KServiceGroup *>(p)->noDisplay() :
00301                                    static_cast<KService *>(p)->noDisplay();
00302         if (excludeNoDisplay && noDisplay)
00303            continue;
00304     bool SuSEunimportant = p->isType(KST_KService) &&
00305                                    static_cast<KService *>(p)->SuSEunimportant();
00306         if (excludeSuSEunimportant && SuSEunimportant)
00307            continue;
00308 
00309         // Choose the right list
00310         KSortableValueList<SPtr,QCString> & list = p->isType(KST_KServiceGroup) ? glist : slist;
00311         QString name;
00312         if (p->isType(KST_KServiceGroup))
00313           name = static_cast<KServiceGroup *>(p)->caption();
00314         else if (sortByGenericName)
00315           name = static_cast<KService *>(p)->genericName() + " " + p->name();
00316         else
00317           name = p->name() + " " + static_cast<KService *>(p)->genericName();
00318                                                                       
00319         QCString key( name.length() * 4 + 1 );
00320         // strxfrm() crashes on Solaris
00321 #ifndef USE_SOLARIS
00322         // maybe it'd be better to use wcsxfrm() where available
00323         size_t ln = strxfrm( key.data(), name.local8Bit().data(), key.size());
00324         if( ln != size_t( -1 ))
00325         {
00326             if( ln >= key.size())
00327             { // didn't fit?
00328                 key.resize( ln + 1 );
00329                 if( strxfrm( key.data(), name.local8Bit().data(), key.size()) == size_t( -1 ))
00330                     key = name.local8Bit();
00331             }
00332         }
00333         else
00334 #endif
00335         {
00336             key = name.local8Bit();
00337         }
00338         list.insert(key,SPtr(*it));
00339     }
00340 
00341     return group->SuSEsortEntries( slist, glist, excludeNoDisplay, allowSeparators );
00342 }
00343 
00344 KServiceGroup::List
00345 KServiceGroup::SuSEsortEntries( KSortableValueList<SPtr,QCString> slist, KSortableValueList<SPtr,QCString> glist, bool excludeNoDisplay, bool allowSeparators )
00346 {
00347     KServiceGroup *group = this;
00348 
00349     // Now sort
00350     slist.sort();
00351     glist.sort();
00352 
00353     if (d->sortOrder.isEmpty())
00354     {
00355        d->sortOrder << ":M";
00356        d->sortOrder << ":F";
00357     }
00358 
00359     QString rp = relPath();
00360     if(rp == "/") rp = QString::null;
00361 
00362     // Iterate through the sort spec list.
00363     // If an entry gets mentioned explicitly, we remove it from the sorted list
00364     for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it)
00365     {
00366         const QString &item = *it;
00367         if (item.isEmpty()) continue;
00368         if (item[0] == '/')
00369         {
00370           QString groupPath = rp + item.mid(1) + "/";
00371            // Remove entry from sorted list of services.
00372           for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
00373           {
00374              KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)((*it2).value()));
00375              if (group->relPath() == groupPath)
00376              {
00377                 glist.remove(it2);
00378                 break;
00379              }
00380           }
00381         }
00382         else if (item[0] != ':')
00383         {
00384            // Remove entry from sorted list of services.
00385            // TODO: Remove item from sortOrder-list if not found
00386            // TODO: This prevents duplicates
00387           for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2)
00388           {
00389              KService *service = (KService *)((KSycocaEntry *)((*it2).value()));
00390              if (service->menuId() == item)
00391              {
00392                 slist.remove(it2);
00393                 break;
00394              }
00395           }
00396         }
00397     }
00398 
00399     List sorted;
00400 
00401     bool needSeparator = false;
00402     // Iterate through the sort spec list.
00403     // Add the entries to the list according to the sort spec.
00404     for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it)
00405     {
00406         const QString &item = *it;
00407         if (item.isEmpty()) continue;
00408         if (item[0] == ':')
00409         {
00410           // Special condition...
00411           if (item == ":S")
00412           {
00413              if (allowSeparators)
00414                 needSeparator = true;
00415           }
00416           else if (item == ":M")
00417           {
00418             // Add sorted list of sub-menus
00419             for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
00420             {
00421               addItem(sorted, (*it2).value(), needSeparator);
00422             }
00423           }
00424           else if (item == ":F")
00425           {
00426             // Add sorted list of services
00427             for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2)
00428             {
00429               addItem(sorted, (*it2).value(), needSeparator);
00430             }
00431           }
00432           else if (item == ":A")
00433           {
00434             // Add sorted lists of services and submenus
00435             KSortableValueList<SPtr,QCString>::Iterator it_s = slist.begin();
00436             KSortableValueList<SPtr,QCString>::Iterator it_g = glist.begin();
00437             
00438             while(true)
00439             {
00440                if (it_s == slist.end())
00441                {
00442                   if (it_g == glist.end())
00443                      break; // Done
00444                      
00445                   // Insert remaining sub-menu
00446                   addItem(sorted, (*it_g).value(), needSeparator);
00447                   it_g++;
00448                }
00449                else if (it_g == glist.end())
00450                {
00451                   // Insert remaining service
00452                   addItem(sorted, (*it_s).value(), needSeparator);
00453                   it_s++;
00454                }
00455                else if ((*it_g).index() < (*it_s).index())
00456                {
00457                   // Insert sub-menu first
00458                   addItem(sorted, (*it_g).value(), needSeparator);
00459                   it_g++;
00460                }
00461                else
00462                {
00463                   // Insert service first
00464                   addItem(sorted, (*it_s).value(), needSeparator);
00465                   it_s++;
00466                }
00467             }
00468           }
00469         }
00470         else if (item[0] == '/')
00471         {
00472           QString groupPath = rp + item.mid(1) + "/";
00473 
00474           for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2)
00475           {
00476             if (!(*it2)->isType(KST_KServiceGroup))
00477                continue;
00478             KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2));
00479             if (group->relPath() == groupPath)
00480             {
00481                if (!excludeNoDisplay || !group->noDisplay())
00482                   addItem(sorted, (*it2), needSeparator);
00483                break;
00484             }
00485           }
00486         }
00487         else
00488         {
00489           for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2)
00490           {
00491             if (!(*it2)->isType(KST_KService))
00492                continue;
00493             KService *service = (KService *)((KSycocaEntry *)(*it2));
00494             if (service->menuId() == item)
00495             {
00496                if (!excludeNoDisplay || !service->noDisplay())
00497                   addItem(sorted, (*it2), needSeparator);
00498                break;
00499             }
00500           }
00501         }
00502     }
00503 
00504     return sorted;
00505 }
00506 
00507 void KServiceGroup::setLayoutInfo(const QStringList &layout)
00508 {
00509     d->sortOrder = layout;
00510 }
00511 
00512 QStringList KServiceGroup::layoutInfo() const
00513 {
00514     return d->sortOrder;
00515 }
00516 
00517 KServiceGroup::Ptr
00518 KServiceGroup::baseGroup( const QString & _baseGroupName )
00519 {
00520     return KServiceGroupFactory::self()->findBaseGroup(_baseGroupName, true);
00521 }
00522 
00523 KServiceGroup::Ptr
00524 KServiceGroup::root()
00525 {
00526    return KServiceGroupFactory::self()->findGroupByDesktopPath("/", true);
00527 }
00528 
00529 KServiceGroup::Ptr
00530 KServiceGroup::group(const QString &relPath)
00531 {
00532    if (relPath.isEmpty()) return root();
00533    return KServiceGroupFactory::self()->findGroupByDesktopPath(relPath, true);
00534 }
00535 
00536 KServiceGroup::Ptr
00537 KServiceGroup::childGroup(const QString &parent)
00538 {
00539    return KServiceGroupFactory::self()->findGroupByDesktopPath("#parent#"+parent, true);
00540 }
00541 
00542 QString
00543 KServiceGroup::directoryEntryPath() const
00544 {
00545    return d->directoryEntryPath;
00546 }
00547 
00548 
00549 void KServiceGroup::virtual_hook( int id, void* data )
00550 { KSycocaEntry::virtual_hook( id, data ); }
00551 
00552 
00553 KServiceSeparator::KServiceSeparator( )
00554  : KSycocaEntry("separator")
00555 {
00556 }
KDE Logo
This file is part of the documentation for kio Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Mar 22 19:50:53 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003