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