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