kservicegroup.cpp
00001 /* This file is part of the KDE libraries 00002 * Copyright (C) 2000 Waldo Bastian <bastian@kde.org> 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License version 2 as published by the Free Software Foundation; 00007 * 00008 * This library is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 * Library General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU Library General Public License 00014 * along with this library; see the file COPYING.LIB. If not, write to 00015 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 * Boston, MA 02110-1301, USA. 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 // Fill in defaults. 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 //fprintf(stderr, "KServiceGroup: Unexpected object in list!\n"); 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 // If the entries haven't been loaded yet, we have to reload ourselves 00318 // together with the entries. We can't only load the entries afterwards 00319 // since the offsets could have been changed if the database has changed. 00320 00321 if (!m_bDeep) { 00322 00323 group = 00324 KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true); 00325 00326 if (0 == group) // No guarantee that we still exist! 00327 return List(); 00328 } 00329 00330 if (!sort) 00331 return group->m_serviceList; 00332 00333 // Sort the list alphabetically, according to locale. 00334 // Groups come first, then services. 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 // Choose the right list 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 // strxfrm() crashes on Solaris 00358 #ifndef USE_SOLARIS 00359 // maybe it'd be better to use wcsxfrm() where available 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 { // didn't fit? 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 // Now sort 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]"; //just inline header 00386 } 00387 00388 QString rp = relPath(); 00389 if(rp == "/") rp = QString::null; 00390 00391 // Iterate through the sort spec list. 00392 // If an entry gets mentioned explicitly, we remove it from the sorted list 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 // Remove entry from sorted list of services. 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 // Remove entry from sorted list of services. 00414 // TODO: Remove item from sortOrder-list if not found 00415 // TODO: This prevents duplicates 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 // Iterate through the sort spec list. 00432 // Add the entries to the list according to the sort spec. 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 // Special condition... 00440 if (item == ":S") 00441 { 00442 if (allowSeparators) 00443 needSeparator = true; 00444 } 00445 else if ( item.contains( ":O" ) ) 00446 { 00447 //todo parse attribute: 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 // Add sorted list of sub-menus 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 // Add sorted list of services 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 // Add sorted lists of services and submenus 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; // Done 00502 00503 // Insert remaining sub-menu 00504 addItem(sorted, (*it_g).value(), needSeparator); 00505 it_g++; 00506 } 00507 else if (it_g == glist.end()) 00508 { 00509 // Insert remaining service 00510 addItem(sorted, (*it_s).value(), needSeparator); 00511 it_s++; 00512 } 00513 else if ((*it_g).index() < (*it_s).index()) 00514 { 00515 // Insert sub-menu first 00516 addItem(sorted, (*it_g).value(), needSeparator); 00517 it_g++; 00518 } 00519 else 00520 { 00521 // Insert service first 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") //menu empty 00596 showEmptyMenu=true; 00597 else if ( item == "NME") //not menu empty 00598 showEmptyMenu=false; 00599 else if( item == "I") //inline menu ! 00600 showInline = true; 00601 else if ( item == "NI") //not inline menu! 00602 showInline = false; 00603 else if( item == "IH") //inline header! 00604 showInlineHeader= true; 00605 else if ( item == "NIH") //not inline header! 00606 showInlineHeader = false; 00607 else if( item == "IA") //inline alias! 00608 showInlineAlias = true; 00609 else if ( item == "NIA") //not inline alias! 00610 showInlineAlias = false; 00611 else if( ( item ).contains( "IL" )) //inline limite! 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 ) //error 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 }