00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00086
00087
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
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
00251
00252
00253
00254 if (!m_bDeep) {
00255
00256 group =
00257 KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true);
00258
00259 if (0 == group)
00260 return List();
00261 }
00262
00263 if (!sort)
00264 return group->m_serviceList;
00265
00266
00267
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
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
00291 #ifndef USE_SOLARIS
00292
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 {
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
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
00324
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
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
00346
00347
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
00364
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
00372 if (item == ":S")
00373 {
00374 if (allowSeparators)
00375 needSeparator = true;
00376 }
00377 else if (item == ":M")
00378 {
00379
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
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
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;
00405
00406
00407 addItem(sorted, (*it_g).value(), needSeparator);
00408 it_g++;
00409 }
00410 else if (it_g == glist.end())
00411 {
00412
00413 addItem(sorted, (*it_s).value(), needSeparator);
00414 it_s++;
00415 }
00416 else if ((*it_g).index() < (*it_s).index())
00417 {
00418
00419 addItem(sorted, (*it_g).value(), needSeparator);
00420 it_g++;
00421 }
00422 else
00423 {
00424
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 KServiceGroup::Ptr
00474 KServiceGroup::baseGroup( const QString & _baseGroupName )
00475 {
00476 return KServiceGroupFactory::self()->findBaseGroup(_baseGroupName, true);
00477 }
00478
00479 KServiceGroup::Ptr
00480 KServiceGroup::root()
00481 {
00482 return KServiceGroupFactory::self()->findGroupByDesktopPath("/", true);
00483 }
00484
00485 KServiceGroup::Ptr
00486 KServiceGroup::group(const QString &relPath)
00487 {
00488 if (relPath.isEmpty()) return root();
00489 return KServiceGroupFactory::self()->findGroupByDesktopPath(relPath, true);
00490 }
00491
00492 KServiceGroup::Ptr
00493 KServiceGroup::childGroup(const QString &parent)
00494 {
00495 return KServiceGroupFactory::self()->findGroupByDesktopPath("#parent#"+parent, true);
00496 }
00497
00498 QString
00499 KServiceGroup::directoryEntryPath() const
00500 {
00501 return d->directoryEntryPath;
00502 }
00503
00504
00505 void KServiceGroup::virtual_hook( int id, void* data )
00506 { KSycocaEntry::virtual_hook( id, data ); }
00507
00508
00509 KServiceSeparator::KServiceSeparator( )
00510 : KSycocaEntry("separator")
00511 {
00512 }