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