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., 51 Franklin Street, Fifth Floor,
00016  *  Boston, MA 02110-1301, USA.
00017  **/
00018 
00019 #include <kiconloader.h>
00020 #include <kglobal.h>
00021 #include <kstandarddirs.h>
00022 #include <klocale.h>
00023 #include <kdebug.h>
00024 #include <ksortablevaluelist.h>
00025 #include "kservicefactory.h"
00026 #include "kservicegroupfactory.h"
00027 #include "kservicegroup.h"
00028 #include "kservice.h"
00029 #include "ksycoca.h"
00030 
00031 class KServiceGroup::Private
00032 {
00033 public:
00034     Private() { m_bNoDisplay = false; m_bShowEmptyMenu = false;m_bShowInlineHeader=false;m_bInlineAlias=false; m_bAllowInline = false;m_inlineValue = 4;}
00035   bool m_bNoDisplay;
00036     bool m_bShowEmptyMenu;
00037     bool m_bShowInlineHeader;
00038     bool m_bInlineAlias;
00039     bool m_bAllowInline;
00040     int m_inlineValue;
00041     QStringList suppressGenericNames;
00042     QString directoryEntryPath;
00043     QStringList sortOrder;
00044 };
00045 
00046 KServiceGroup::KServiceGroup( const QString & name )
00047  : KSycocaEntry(name), m_childCount(-1)
00048 {
00049   d = new KServiceGroup::Private;
00050   m_bDeleted = false;
00051   m_bDeep = false;
00052 }
00053 
00054 KServiceGroup::KServiceGroup( const QString &configFile, const QString & _relpath )
00055  : KSycocaEntry(_relpath), m_childCount(-1)
00056 {
00057   d = new KServiceGroup::Private;
00058   m_bDeleted = false;
00059   m_bDeep = false;
00060 
00061   QString cfg = configFile;
00062   if (cfg.isEmpty())
00063      cfg = _relpath+".directory";
00064 
00065   d->directoryEntryPath = cfg;
00066 
00067   KDesktopFile config( cfg, true, "apps" );
00068 
00069   m_strCaption = config.readName();
00070   m_strIcon = config.readEntry( "Icon" );
00071   m_strComment = config.readComment();
00072   m_bDeleted = config.readBoolEntry( "Hidden", false );
00073   d->m_bNoDisplay = config.readBoolEntry( "NoDisplay", false );
00074   QStringList tmpList;
00075   if (config.hasKey("OnlyShowIn"))
00076   {
00077      if (!config.readListEntry("OnlyShowIn", ';').contains("KDE"))
00078         d->m_bNoDisplay = true;
00079   }
00080   if (config.hasKey("NotShowIn"))
00081   {
00082      if (config.readListEntry("NotShowIn", ';').contains("KDE"))
00083         d->m_bNoDisplay = true;
00084   }
00085 
00086   m_strBaseGroupName = config.readEntry( "X-KDE-BaseGroup" );
00087   d->suppressGenericNames = config.readListEntry( "X-KDE-SuppressGenericNames" );
00088   d->sortOrder = config.readListEntry("SortOrder");
00089 
00090   // Fill in defaults.
00091   if (m_strCaption.isEmpty())
00092   {
00093      m_strCaption = _relpath;
00094      if (m_strCaption.right(1) == "/")
00095         m_strCaption = m_strCaption.left(m_strCaption.length()-1);
00096      int i = m_strCaption.findRev('/');
00097      if (i > 0)
00098         m_strCaption = m_strCaption.mid(i+1);
00099   }
00100   if (m_strIcon.isEmpty())
00101      m_strIcon = "folder";
00102 }
00103 
00104 KServiceGroup::KServiceGroup( QDataStream& _str, int offset, bool deep ) :
00105     KSycocaEntry( _str, offset )
00106 {
00107   d = new KServiceGroup::Private;
00108   m_bDeep = deep;
00109   load( _str );
00110 }
00111 
00112 KServiceGroup::~KServiceGroup()
00113 {
00114   delete d;
00115 }
00116 
00117 int KServiceGroup::childCount()
00118 {
00119   if (m_childCount == -1)
00120   {
00121      m_childCount = 0;
00122 
00123      for( List::ConstIterator it = m_serviceList.begin();
00124           it != m_serviceList.end(); it++)
00125      {
00126         KSycocaEntry *p = (*it);
00127         if (p->isType(KST_KService))
00128         {
00129            KService *service = static_cast<KService *>(p);
00130            if (!service->noDisplay())
00131               m_childCount++;
00132         }
00133         else if (p->isType(KST_KServiceGroup))
00134         {
00135            KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
00136            m_childCount += serviceGroup->childCount();
00137         }
00138      }
00139   }
00140   return m_childCount;
00141 }
00142 
00143 
00144 bool KServiceGroup::showInlineHeader() const
00145 {
00146     return d->m_bShowInlineHeader;
00147 }
00148 
00149 bool KServiceGroup::showEmptyMenu() const
00150 {
00151     return d->m_bShowEmptyMenu;
00152 }
00153 
00154 bool KServiceGroup::inlineAlias() const
00155 {
00156     return d->m_bInlineAlias;
00157 }
00158 
00159 void KServiceGroup::setInlineAlias(bool _b)
00160 {
00161     d->m_bInlineAlias = _b;
00162 }
00163 
00164 void KServiceGroup::setShowEmptyMenu(bool _b)
00165 {
00166     d->m_bShowEmptyMenu=_b;
00167 }
00168 
00169 void KServiceGroup::setShowInlineHeader(bool _b)
00170 {
00171     d->m_bShowInlineHeader=_b;
00172 }
00173 
00174 int KServiceGroup::inlineValue() const
00175 {
00176     return d->m_inlineValue;
00177 }
00178 
00179 void KServiceGroup::setInlineValue(int _val)
00180 {
00181     d->m_inlineValue = _val;
00182 }
00183 
00184 bool KServiceGroup::allowInline() const
00185 {
00186     return d->m_bAllowInline;
00187 }
00188 
00189 void KServiceGroup::setAllowInline(bool _b)
00190 {
00191     d->m_bAllowInline = _b;
00192 }
00193 
00194 bool KServiceGroup::noDisplay() const
00195 {
00196   return d->m_bNoDisplay || m_strCaption.startsWith(".");
00197 }
00198 
00199 QStringList KServiceGroup::suppressGenericNames() const
00200 {
00201   return d->suppressGenericNames;
00202 }
00203 
00204 void KServiceGroup::load( QDataStream& s )
00205 {
00206   QStringList groupList;
00207   Q_INT8 noDisplay;
00208   Q_INT8 _showEmptyMenu;
00209   Q_INT8 inlineHeader;
00210   Q_INT8 _inlineAlias;
00211   Q_INT8 _allowInline;
00212   s >> m_strCaption >> m_strIcon >>
00213       m_strComment >> groupList >> m_strBaseGroupName >> m_childCount >>
00214       noDisplay >> d->suppressGenericNames >> d->directoryEntryPath >>
00215       d->sortOrder >> _showEmptyMenu >> inlineHeader >> _inlineAlias >> _allowInline;
00216 
00217   d->m_bNoDisplay = (noDisplay != 0);
00218   d->m_bShowEmptyMenu = ( _showEmptyMenu != 0 );
00219   d->m_bShowInlineHeader = ( inlineHeader != 0 );
00220   d->m_bInlineAlias = ( _inlineAlias != 0 );
00221   d->m_bAllowInline = ( _allowInline != 0 );
00222 
00223   if (m_bDeep)
00224   {
00225      for(QStringList::ConstIterator it = groupList.begin();
00226          it != groupList.end(); it++)
00227      {
00228         QString path = *it;
00229         if (path[path.length()-1] == '/')
00230         {
00231            KServiceGroup *serviceGroup;
00232            serviceGroup = KServiceGroupFactory::self()->findGroupByDesktopPath(path, false);
00233            if (serviceGroup)
00234               m_serviceList.append( SPtr(serviceGroup) );
00235         }
00236         else
00237         {
00238            KService *service;
00239            service = KServiceFactory::self()->findServiceByDesktopPath(path);
00240            if (service)
00241               m_serviceList.append( SPtr(service) );
00242         }
00243      }
00244   }
00245 }
00246 
00247 void KServiceGroup::addEntry( KSycocaEntry *entry)
00248 {
00249   m_serviceList.append(entry);
00250 }
00251 
00252 void KServiceGroup::save( QDataStream& s )
00253 {
00254   KSycocaEntry::save( s );
00255 
00256   QStringList groupList;
00257   for( List::ConstIterator it = m_serviceList.begin();
00258        it != m_serviceList.end(); it++)
00259   {
00260      KSycocaEntry *p = (*it);
00261      if (p->isType(KST_KService))
00262      {
00263         KService *service = static_cast<KService *>(p);
00264         groupList.append( service->desktopEntryPath());
00265      }
00266      else if (p->isType(KST_KServiceGroup))
00267      {
00268         KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p);
00269         groupList.append( serviceGroup->relPath());
00270      }
00271      else
00272      {
00273         //fprintf(stderr, "KServiceGroup: Unexpected object in list!\n");
00274      }
00275   }
00276 
00277   (void) childCount();
00278 
00279   Q_INT8 noDisplay = d->m_bNoDisplay ? 1 : 0;
00280   Q_INT8 _showEmptyMenu = d->m_bShowEmptyMenu ? 1 : 0;
00281   Q_INT8 inlineHeader = d->m_bShowInlineHeader ? 1 : 0;
00282   Q_INT8 _inlineAlias = d->m_bInlineAlias ? 1 : 0;
00283   Q_INT8 _allowInline = d->m_bAllowInline ? 1 : 0;
00284   s << m_strCaption << m_strIcon <<
00285       m_strComment << groupList << m_strBaseGroupName << m_childCount <<
00286       noDisplay << d->suppressGenericNames << d->directoryEntryPath <<
00287       d->sortOrder <<_showEmptyMenu <<inlineHeader<<_inlineAlias<<_allowInline;
00288 }
00289 
00290 KServiceGroup::List
00291 KServiceGroup::entries(bool sort)
00292 {
00293    return entries(sort, true);
00294 }
00295 
00296 KServiceGroup::List
00297 KServiceGroup::entries(bool sort, bool excludeNoDisplay)
00298 {
00299    return entries(sort, excludeNoDisplay, false);
00300 }
00301 
00302 static void addItem(KServiceGroup::List &sorted, const KSycocaEntry::Ptr &p, bool &addSeparator)
00303 {
00304    if (addSeparator && !sorted.isEmpty())
00305       sorted.append(new KServiceSeparator());
00306    sorted.append(p);
00307    addSeparator = false;
00308 }
00309 
00310 KServiceGroup::List
00311 KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName)
00312 {
00313     KServiceGroup *group = this;
00314 
00315     // If the entries haven't been loaded yet, we have to reload ourselves
00316     // together with the entries. We can't only load the entries afterwards
00317     // since the offsets could have been changed if the database has changed.
00318 
00319     if (!m_bDeep) {
00320 
00321         group =
00322             KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true);
00323 
00324         if (0 == group) // No guarantee that we still exist!
00325             return List();
00326     }
00327 
00328     if (!sort)
00329         return group->m_serviceList;
00330 
00331     // Sort the list alphabetically, according to locale.
00332     // Groups come first, then services.
00333 
00334     KSortableValueList<SPtr,QCString> slist;
00335     KSortableValueList<SPtr,QCString> glist;
00336     for (List::ConstIterator it(group->m_serviceList.begin()); it != group->m_serviceList.end(); ++it)
00337     {
00338         KSycocaEntry *p = (*it);
00339     bool noDisplay = p->isType(KST_KServiceGroup) ?
00340                                    static_cast<KServiceGroup *>(p)->noDisplay() :
00341                                    static_cast<KService *>(p)->noDisplay();
00342         if (excludeNoDisplay && noDisplay)
00343            continue;
00344         // Choose the right list
00345         KSortableValueList<SPtr,QCString> & list = p->isType(KST_KServiceGroup) ? glist : slist;
00346         QString name;
00347         if (p->isType(KST_KServiceGroup))
00348           name = static_cast<KServiceGroup *>(p)->caption();
00349         else if (sortByGenericName)
00350           name = static_cast<KService *>(p)->genericName() + " " + p->name();
00351         else
00352           name = p->name() + " " + static_cast<KService *>(p)->genericName();
00353 
00354         QCString key( name.length() * 4 + 1 );
00355         // strxfrm() crashes on Solaris
00356 #ifndef USE_SOLARIS
00357         // maybe it'd be better to use wcsxfrm() where available
00358         size_t ln = strxfrm( key.data(), name.local8Bit().data(), key.size());
00359         if( ln != size_t( -1 ))
00360         {
00361             if( ln >= key.size())
00362             { // didn't fit?
00363                 key.resize( ln + 1 );
00364                 if( strxfrm( key.data(), name.local8Bit().data(), key.size()) == size_t( -1 ))
00365                     key = name.local8Bit();
00366             }
00367         }
00368         else
00369 #endif
00370         {
00371             key = name.local8Bit();
00372         }
00373         list.insert(key,SPtr(*it));
00374     }
00375     // Now sort
00376     slist.sort();
00377     glist.sort();
00378 
00379     if (d->sortOrder.isEmpty())
00380     {
00381        d->sortOrder << ":M";
00382        d->sortOrder << ":F";
00383        d->sortOrder << ":OIH IL[4]"; //just inline header
00384     }
00385 
00386     QString rp = relPath();
00387     if(rp == "/") rp = QString::null;
00388 
00389     // Iterate through the sort spec list.
00390     // If an entry gets mentioned explicitly, we remove it from the sorted list
00391     for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it)
00392     {
00393         const QString &item = *it;
00394         if (item.isEmpty()) continue;
00395         if (item[0] == '/')
00396         {
00397           QString groupPath = rp + item.mid(1) + "/";
00398            // Remove entry from sorted list of services.
00399           for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
00400           {
00401              KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)((*it2).value()));
00402              if (group->relPath() == groupPath)
00403              {
00404                 glist.remove(it2);
00405                 break;
00406              }
00407           }
00408         }
00409         else if (item[0] != ':')
00410         {
00411            // Remove entry from sorted list of services.
00412            // TODO: Remove item from sortOrder-list if not found
00413            // TODO: This prevents duplicates
00414           for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2)
00415           {
00416              KService *service = (KService *)((KSycocaEntry *)((*it2).value()));
00417              if (service->menuId() == item)
00418              {
00419                 slist.remove(it2);
00420                 break;
00421              }
00422           }
00423         }
00424     }
00425 
00426     List sorted;
00427 
00428     bool needSeparator = false;
00429     // Iterate through the sort spec list.
00430     // Add the entries to the list according to the sort spec.
00431     for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it)
00432     {
00433         const QString &item = *it;
00434         if (item.isEmpty()) continue;
00435         if (item[0] == ':')
00436         {
00437           // Special condition...
00438           if (item == ":S")
00439           {
00440              if (allowSeparators)
00441                 needSeparator = true;
00442           }
00443           else if ( item.contains( ":O" ) )
00444           {
00445               //todo parse attribute:
00446               QString tmp(  item );
00447               tmp = tmp.remove(":O");
00448               QStringList optionAttribute = QStringList::split(" ",tmp);
00449               if( optionAttribute.count()==0)
00450                   optionAttribute.append(tmp);
00451               bool showEmptyMenu = false;
00452               bool showInline = false;
00453               bool showInlineHeader = false;
00454               bool showInlineAlias = false;
00455               int inlineValue = -1;
00456 
00457               for ( QStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3 )
00458               {
00459                   parseAttribute( *it3,  showEmptyMenu, showInline, showInlineHeader, showInlineAlias, inlineValue );
00460               }
00461               for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
00462               {
00463                   KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2).value());
00464                   group->setShowEmptyMenu(  showEmptyMenu  );
00465                   group->setAllowInline( showInline );
00466                   group->setShowInlineHeader( showInlineHeader );
00467                   group->setInlineAlias( showInlineAlias );
00468                   group->setInlineValue( inlineValue );
00469               }
00470 
00471           }
00472           else if (item == ":M")
00473           {
00474             // Add sorted list of sub-menus
00475             for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2)
00476             {
00477               addItem(sorted, (*it2).value(), needSeparator);
00478             }
00479           }
00480           else if (item == ":F")
00481           {
00482             // Add sorted list of services
00483             for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2)
00484             {
00485               addItem(sorted, (*it2).value(), needSeparator);
00486             }
00487           }
00488           else if (item == ":A")
00489           {
00490             // Add sorted lists of services and submenus
00491             KSortableValueList<SPtr,QCString>::Iterator it_s = slist.begin();
00492             KSortableValueList<SPtr,QCString>::Iterator it_g = glist.begin();
00493 
00494             while(true)
00495             {
00496                if (it_s == slist.end())
00497                {
00498                   if (it_g == glist.end())
00499                      break; // Done
00500 
00501                   // Insert remaining sub-menu
00502                   addItem(sorted, (*it_g).value(), needSeparator);
00503                   it_g++;
00504                }
00505                else if (it_g == glist.end())
00506                {
00507                   // Insert remaining service
00508                   addItem(sorted, (*it_s).value(), needSeparator);
00509                   it_s++;
00510                }
00511                else if ((*it_g).index() < (*it_s).index())
00512                {
00513                   // Insert sub-menu first
00514                   addItem(sorted, (*it_g).value(), needSeparator);
00515                   it_g++;
00516                }
00517                else
00518                {
00519                   // Insert service first
00520                   addItem(sorted, (*it_s).value(), needSeparator);
00521                   it_s++;
00522                }
00523             }
00524           }
00525         }
00526         else if (item[0] == '/')
00527         {
00528             QString groupPath = rp + item.mid(1) + "/";
00529 
00530             for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2)
00531             {
00532                 if (!(*it2)->isType(KST_KServiceGroup))
00533                     continue;
00534                 KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2));
00535                 if (group->relPath() == groupPath)
00536                 {
00537                     if (!excludeNoDisplay || !group->noDisplay())
00538                     {
00539                         const QString &nextItem = *( ++it );
00540                         if ( nextItem.startsWith( ":O" ) )
00541                         {
00542                             QString tmp(  nextItem );
00543                             tmp = tmp.remove(":O");
00544                             QStringList optionAttribute = QStringList::split(" ",tmp);
00545                             if( optionAttribute.count()==0)
00546                                 optionAttribute.append(tmp);
00547                             bool bShowEmptyMenu = false;
00548                             bool bShowInline = false;
00549                             bool bShowInlineHeader = false;
00550                             bool bShowInlineAlias = false;
00551                             int inlineValue = -1;
00552                             for ( QStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3 )
00553                             {
00554                                 parseAttribute( *it3 , bShowEmptyMenu, bShowInline, bShowInlineHeader, bShowInlineAlias , inlineValue );
00555                                 group->setShowEmptyMenu( bShowEmptyMenu );
00556                                 group->setAllowInline( bShowInline );
00557                                 group->setShowInlineHeader( bShowInlineHeader );
00558                                 group->setInlineAlias( bShowInlineAlias );
00559                                 group->setInlineValue( inlineValue );
00560                             }
00561                         }
00562                         else
00563                             it--;
00564 
00565                         addItem(sorted, (group), needSeparator);
00566                     }
00567                     break;
00568                 }
00569             }
00570         }
00571         else
00572         {
00573             for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2)
00574             {
00575                 if (!(*it2)->isType(KST_KService))
00576                     continue;
00577                 KService *service = (KService *)((KSycocaEntry *)(*it2));
00578                 if (service->menuId() == item)
00579                 {
00580                     if (!excludeNoDisplay || !service->noDisplay())
00581                         addItem(sorted, (*it2), needSeparator);
00582                     break;
00583                 }
00584             }
00585         }
00586     }
00587 
00588     return sorted;
00589 }
00590 
00591 void KServiceGroup::parseAttribute( const QString &item ,  bool &showEmptyMenu, bool &showInline, bool &showInlineHeader, bool & showInlineAlias , int &inlineValue )
00592 {
00593     if( item == "ME") //menu empty
00594         showEmptyMenu=true;
00595     else if ( item == "NME") //not menu empty
00596         showEmptyMenu=false;
00597     else if( item == "I") //inline menu !
00598         showInline = true;
00599     else if ( item == "NI") //not inline menu!
00600         showInline = false;
00601     else if( item == "IH") //inline  header!
00602         showInlineHeader= true;
00603     else if ( item == "NIH") //not inline  header!
00604         showInlineHeader = false;
00605     else if( item == "IA") //inline alias!
00606         showInlineAlias = true;
00607     else if (  item == "NIA") //not inline alias!
00608         showInlineAlias = false;
00609     else if( ( item ).contains( "IL" )) //inline limite!
00610     {
00611         QString tmp( item );
00612         tmp = tmp.remove( "IL[" );
00613         tmp = tmp.remove( "]" );
00614         bool ok;
00615         int _inlineValue = tmp.toInt(&ok);
00616         if ( !ok ) //error
00617             _inlineValue = -1;
00618         inlineValue =  _inlineValue;
00619     }
00620     else
00621         kdDebug()<<" This attribute is not supported :"<<item<<endl;
00622 }
00623 
00624 void KServiceGroup::setLayoutInfo(const QStringList &layout)
00625 {
00626     d->sortOrder = layout;
00627 }
00628 
00629 QStringList KServiceGroup::layoutInfo() const
00630 {
00631     return d->sortOrder;
00632 }
00633 
00634 KServiceGroup::Ptr
00635 KServiceGroup::baseGroup( const QString & _baseGroupName )
00636 {
00637     return KServiceGroupFactory::self()->findBaseGroup(_baseGroupName, true);
00638 }
00639 
00640 KServiceGroup::Ptr
00641 KServiceGroup::root()
00642 {
00643    return KServiceGroupFactory::self()->findGroupByDesktopPath("/", true);
00644 }
00645 
00646 KServiceGroup::Ptr
00647 KServiceGroup::group(const QString &relPath)
00648 {
00649    if (relPath.isEmpty()) return root();
00650    return KServiceGroupFactory::self()->findGroupByDesktopPath(relPath, true);
00651 }
00652 
00653 KServiceGroup::Ptr
00654 KServiceGroup::childGroup(const QString &parent)
00655 {
00656    return KServiceGroupFactory::self()->findGroupByDesktopPath("#parent#"+parent, true);
00657 }
00658 
00659 QString
00660 KServiceGroup::directoryEntryPath() const
00661 {
00662    return d->directoryEntryPath;
00663 }
00664 
00665 
00666 void KServiceGroup::virtual_hook( int id, void* data )
00667 { KSycocaEntry::virtual_hook( id, data ); }
00668 
00669 
00670 KServiceSeparator::KServiceSeparator( )
00671  : KSycocaEntry("separator")
00672 {
00673 }
KDE Home | KDE Accessibility Home | Description of Access Keys