00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00316
00317
00318
00319 if (!m_bDeep) {
00320
00321 group =
00322 KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true);
00323
00324 if (0 == group)
00325 return List();
00326 }
00327
00328 if (!sort)
00329 return group->m_serviceList;
00330
00331
00332
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
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
00356 #ifndef USE_SOLARIS
00357
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 {
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
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]";
00384 }
00385
00386 QString rp = relPath();
00387 if(rp == "/") rp = QString::null;
00388
00389
00390
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
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
00412
00413
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
00430
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
00438 if (item == ":S")
00439 {
00440 if (allowSeparators)
00441 needSeparator = true;
00442 }
00443 else if ( item.contains( ":O" ) )
00444 {
00445
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
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
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
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;
00500
00501
00502 addItem(sorted, (*it_g).value(), needSeparator);
00503 it_g++;
00504 }
00505 else if (it_g == glist.end())
00506 {
00507
00508 addItem(sorted, (*it_s).value(), needSeparator);
00509 it_s++;
00510 }
00511 else if ((*it_g).index() < (*it_s).index())
00512 {
00513
00514 addItem(sorted, (*it_g).value(), needSeparator);
00515 it_g++;
00516 }
00517 else
00518 {
00519
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")
00594 showEmptyMenu=true;
00595 else if ( item == "NME")
00596 showEmptyMenu=false;
00597 else if( item == "I")
00598 showInline = true;
00599 else if ( item == "NI")
00600 showInline = false;
00601 else if( item == "IH")
00602 showInlineHeader= true;
00603 else if ( item == "NIH")
00604 showInlineHeader = false;
00605 else if( item == "IA")
00606 showInlineAlias = true;
00607 else if ( item == "NIA")
00608 showInlineAlias = false;
00609 else if( ( item ).contains( "IL" ))
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 )
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 }