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