kio Library API Documentation

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., 59 Temple Place - Suite 330, 00016 * Boston, MA 02111-1307, USA. 00017 **/ 00018 00019 // $Id: kservicegroup.cpp,v 1.31 2003/12/23 07:36:00 binner Exp $ 00020 00021 #include <kiconloader.h> 00022 #include <kglobal.h> 00023 #include <kstandarddirs.h> 00024 #include <klocale.h> 00025 #include <kdebug.h> 00026 #include <ksortablevaluelist.h> 00027 #include "kservicefactory.h" 00028 #include "kservicegroupfactory.h" 00029 #include "kservicegroup.h" 00030 #include "kservice.h" 00031 #include "ksycoca.h" 00032 00033 class KServiceGroup::Private 00034 { 00035 public: 00036 Private() { m_bNoDisplay = false; } 00037 bool m_bNoDisplay; 00038 QStringList suppressGenericNames; 00039 QString directoryEntryPath; 00040 QStringList sortOrder; 00041 }; 00042 00043 KServiceGroup::KServiceGroup( const QString & name ) 00044 : KSycocaEntry(name), m_childCount(-1) 00045 { 00046 d = new KServiceGroup::Private; 00047 m_bDeleted = false; 00048 } 00049 00050 KServiceGroup::KServiceGroup( const QString &configFile, const QString & _relpath ) 00051 : KSycocaEntry(_relpath), m_childCount(-1) 00052 { 00053 d = new KServiceGroup::Private; 00054 m_bDeleted = false; 00055 00056 QString cfg = configFile; 00057 if (cfg.isEmpty()) 00058 cfg = _relpath+".directory"; 00059 00060 d->directoryEntryPath = cfg; 00061 00062 KConfig config( cfg, true, false, "apps" ); 00063 00064 config.setDesktopGroup(); 00065 00066 m_strCaption = config.readEntry( "Name" ); 00067 m_strIcon = config.readEntry( "Icon" ); 00068 m_strComment = config.readEntry( "Comment" ); 00069 m_bDeleted = config.readBoolEntry( "Hidden", false ); 00070 d->m_bNoDisplay = config.readBoolEntry( "NoDisplay", false ); 00071 QStringList tmpList; 00072 if (config.hasKey("OnlyShowIn")) 00073 { 00074 if (!config.readListEntry("OnlyShowIn", ';').contains("KDE")) 00075 d->m_bNoDisplay = true; 00076 } 00077 if (config.hasKey("NotShowIn")) 00078 { 00079 if (config.readListEntry("NotShowIn", ';').contains("KDE")) 00080 d->m_bNoDisplay = true; 00081 } 00082 00083 m_strBaseGroupName = config.readEntry( "X-KDE-BaseGroup" ); 00084 d->suppressGenericNames = config.readListEntry( "X-KDE-SuppressGenericNames" ); 00085 d->sortOrder = config.readListEntry("SortOrder"); 00086 kdDebug()<<"cfg :"<<cfg<< " m_strComment :"<<m_strComment<<" m_strCaption :"<<m_strCaption<<" m_strBaseGroupName :"<<m_strBaseGroupName<<" d->sortOrder : "<<d->sortOrder.join( ";" )<<endl; 00087 00088 // Fill in defaults. 00089 if (m_strCaption.isEmpty()) 00090 { 00091 m_strCaption = _relpath; 00092 if (m_strCaption.right(1) == "/") 00093 m_strCaption = m_strCaption.left(m_strCaption.length()-1); 00094 int i = m_strCaption.findRev('/'); 00095 if (i > 0) 00096 m_strCaption = m_strCaption.mid(i+1); 00097 } 00098 if (m_strIcon.isEmpty()) 00099 m_strIcon = "folder"; 00100 } 00101 00102 KServiceGroup::KServiceGroup( QDataStream& _str, int offset, bool deep ) : 00103 KSycocaEntry( _str, offset ) 00104 { 00105 d = new KServiceGroup::Private; 00106 m_bDeep = deep; 00107 load( _str ); 00108 } 00109 00110 KServiceGroup::~KServiceGroup() 00111 { 00112 delete d; 00113 } 00114 00115 int KServiceGroup::childCount() 00116 { 00117 if (m_childCount == -1) 00118 { 00119 m_childCount = 0; 00120 00121 for( List::ConstIterator it = m_serviceList.begin(); 00122 it != m_serviceList.end(); it++) 00123 { 00124 KSycocaEntry *p = (*it); 00125 if (p->isType(KST_KService)) 00126 { 00127 KService *service = static_cast<KService *>(p); 00128 if (!service->noDisplay()) 00129 m_childCount++; 00130 } 00131 else if (p->isType(KST_KServiceGroup)) 00132 { 00133 KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p); 00134 m_childCount += serviceGroup->childCount(); 00135 } 00136 } 00137 } 00138 return m_childCount; 00139 } 00140 00141 00142 bool KServiceGroup::noDisplay() const 00143 { 00144 return d->m_bNoDisplay || m_strCaption.startsWith("."); 00145 } 00146 00147 QStringList KServiceGroup::suppressGenericNames() const 00148 { 00149 return d->suppressGenericNames; 00150 } 00151 00152 void KServiceGroup::load( QDataStream& s ) 00153 { 00154 QStringList groupList; 00155 Q_INT8 noDisplay; 00156 s >> m_strCaption >> m_strIcon >> 00157 m_strComment >> groupList >> m_strBaseGroupName >> m_childCount >> 00158 noDisplay >> d->suppressGenericNames >> d->directoryEntryPath >> 00159 d->sortOrder; 00160 00161 d->m_bNoDisplay = (noDisplay != 0); 00162 00163 if (m_bDeep) 00164 { 00165 for(QStringList::ConstIterator it = groupList.begin(); 00166 it != groupList.end(); it++) 00167 { 00168 QString path = *it; 00169 if (path[path.length()-1] == '/') 00170 { 00171 KServiceGroup *serviceGroup; 00172 serviceGroup = KServiceGroupFactory::self()->findGroupByDesktopPath(path, false); 00173 if (serviceGroup) 00174 m_serviceList.append( SPtr(serviceGroup) ); 00175 } 00176 else 00177 { 00178 KService *service; 00179 service = KServiceFactory::self()->findServiceByDesktopPath(path); 00180 if (service) 00181 m_serviceList.append( SPtr(service) ); 00182 } 00183 } 00184 } 00185 } 00186 00187 void KServiceGroup::addEntry( KSycocaEntry *entry) 00188 { 00189 m_serviceList.append(entry); 00190 } 00191 00192 void KServiceGroup::save( QDataStream& s ) 00193 { 00194 KSycocaEntry::save( s ); 00195 00196 QStringList groupList; 00197 for( List::ConstIterator it = m_serviceList.begin(); 00198 it != m_serviceList.end(); it++) 00199 { 00200 KSycocaEntry *p = (*it); 00201 if (p->isType(KST_KService)) 00202 { 00203 KService *service = static_cast<KService *>(p); 00204 groupList.append( service->desktopEntryPath()); 00205 } 00206 else if (p->isType(KST_KServiceGroup)) 00207 { 00208 KServiceGroup *serviceGroup = static_cast<KServiceGroup *>(p); 00209 groupList.append( serviceGroup->relPath()); 00210 } 00211 else 00212 { 00213 //fprintf(stderr, "KServiceGroup: Unexpected object in list!\n"); 00214 } 00215 } 00216 00217 (void) childCount(); 00218 00219 Q_INT8 noDisplay = d->m_bNoDisplay ? 1 : 0; 00220 s << m_strCaption << m_strIcon << 00221 m_strComment << groupList << m_strBaseGroupName << m_childCount << 00222 noDisplay << d->suppressGenericNames << d->directoryEntryPath << 00223 d->sortOrder; 00224 } 00225 00226 KServiceGroup::List 00227 KServiceGroup::entries(bool sort) 00228 { 00229 return entries(sort, true); 00230 } 00231 00232 KServiceGroup::List 00233 KServiceGroup::entries(bool sort, bool excludeNoDisplay) 00234 { 00235 return entries(sort, excludeNoDisplay, false); 00236 } 00237 00238 static void addItem(KServiceGroup::List &sorted, const KSycocaEntry::Ptr &p, bool &addSeparator) 00239 { 00240 if (addSeparator && !sorted.isEmpty()) 00241 sorted.append(new KServiceSeparator()); 00242 sorted.append(p); 00243 addSeparator = false; 00244 } 00245 00246 KServiceGroup::List 00247 KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName) 00248 { 00249 KServiceGroup *group = this; 00250 00251 // If the entries haven't been loaded yet, we have to reload ourselves 00252 // together with the entries. We can't only load the entries afterwards 00253 // since the offsets could have been changed if the database has changed. 00254 00255 if (!m_bDeep) { 00256 00257 group = 00258 KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true); 00259 00260 if (0 == group) // No guarantee that we still exist! 00261 return List(); 00262 } 00263 00264 if (!sort) 00265 return group->m_serviceList; 00266 00267 // Sort the list alphabetically, according to locale. 00268 // Groups come first, then services. 00269 00270 KSortableValueList<SPtr,QCString> slist; 00271 KSortableValueList<SPtr,QCString> glist; 00272 for (List::ConstIterator it(group->m_serviceList.begin()); it != group->m_serviceList.end(); ++it) 00273 { 00274 KSycocaEntry *p = (*it); 00275 bool noDisplay = p->isType(KST_KServiceGroup) ? 00276 static_cast<KServiceGroup *>(p)->noDisplay() : 00277 static_cast<KService *>(p)->noDisplay(); 00278 if (excludeNoDisplay && noDisplay) 00279 continue; 00280 // Choose the right list 00281 KSortableValueList<SPtr,QCString> & list = p->isType(KST_KServiceGroup) ? glist : slist; 00282 QString name; 00283 if (p->isType(KST_KServiceGroup)) 00284 name = static_cast<KServiceGroup *>(p)->caption(); 00285 else if (sortByGenericName) 00286 name = static_cast<KService *>(p)->genericName() + " " + p->name(); 00287 else 00288 name = p->name() + " " + static_cast<KService *>(p)->genericName(); 00289 00290 QCString key( name.length() * 4 + 1 ); 00291 // strxfrm() crashes on Solaris 00292 #ifndef USE_SOLARIS 00293 // maybe it'd be better to use wcsxfrm() where available 00294 size_t ln = strxfrm( key.data(), name.local8Bit().data(), key.size()); 00295 if( ln != size_t( -1 )) 00296 { 00297 if( ln >= key.size()) 00298 { // didn't fit? 00299 key.resize( ln + 1 ); 00300 if( strxfrm( key.data(), name.local8Bit().data(), key.size()) == size_t( -1 )) 00301 key = name.local8Bit(); 00302 } 00303 } 00304 else 00305 #endif 00306 { 00307 key = name.local8Bit(); 00308 } 00309 list.insert(key,SPtr(*it)); 00310 } 00311 // Now sort 00312 slist.sort(); 00313 glist.sort(); 00314 00315 if (d->sortOrder.isEmpty()) 00316 { 00317 d->sortOrder << ":M"; 00318 d->sortOrder << ":F"; 00319 } 00320 00321 QString rp = relPath(); 00322 if(rp == "/") rp = QString::null; 00323 00324 // Iterate through the sort spec list. 00325 // If an entry gets mentioned explicitly, we remove it from the sorted list 00326 for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it) 00327 { 00328 const QString &item = *it; 00329 if (item.isEmpty()) continue; 00330 if (item[0] == '/') 00331 { 00332 QString groupPath = rp + item.mid(1) + "/"; 00333 // Remove entry from sorted list of services. 00334 for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) 00335 { 00336 KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)((*it2).value())); 00337 if (group->relPath() == groupPath) 00338 { 00339 glist.remove(it2); 00340 break; 00341 } 00342 } 00343 } 00344 else if (item[0] != ':') 00345 { 00346 // Remove entry from sorted list of services. 00347 // TODO: Remove item from sortOrder-list if not found 00348 // TODO: This prevents duplicates 00349 for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2) 00350 { 00351 KService *service = (KService *)((KSycocaEntry *)((*it2).value())); 00352 if (service->menuId() == item) 00353 { 00354 slist.remove(it2); 00355 break; 00356 } 00357 } 00358 } 00359 } 00360 00361 List sorted; 00362 00363 bool needSeparator = false; 00364 // Iterate through the sort spec list. 00365 // Add the entries to the list according to the sort spec. 00366 for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it) 00367 { 00368 const QString &item = *it; 00369 if (item.isEmpty()) continue; 00370 if (item[0] == ':') 00371 { 00372 // Special condition... 00373 if (item == ":S") 00374 { 00375 if (allowSeparators) 00376 needSeparator = true; 00377 } 00378 else if (item == ":M") 00379 { 00380 // Add sorted list of sub-menus 00381 for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) 00382 { 00383 addItem(sorted, (*it2).value(), needSeparator); 00384 } 00385 } 00386 else if (item == ":F") 00387 { 00388 // Add sorted list of services 00389 for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2) 00390 { 00391 addItem(sorted, (*it2).value(), needSeparator); 00392 } 00393 } 00394 else if (item == ":A") 00395 { 00396 // Add sorted lists of services and submenus 00397 KSortableValueList<SPtr,QCString>::Iterator it_s = slist.begin(); 00398 KSortableValueList<SPtr,QCString>::Iterator it_g = glist.begin(); 00399 00400 while(true) 00401 { 00402 if (it_s == slist.end()) 00403 { 00404 if (it_g == glist.end()) 00405 break; // Done 00406 00407 // Insert remaining sub-menu 00408 addItem(sorted, (*it_g).value(), needSeparator); 00409 it_g++; 00410 } 00411 else if (it_g == glist.end()) 00412 { 00413 // Insert remaining service 00414 addItem(sorted, (*it_s).value(), needSeparator); 00415 it_s++; 00416 } 00417 else if ((*it_g).index() < (*it_s).index()) 00418 { 00419 // Insert sub-menu first 00420 addItem(sorted, (*it_g).value(), needSeparator); 00421 it_g++; 00422 } 00423 else 00424 { 00425 // Insert service first 00426 addItem(sorted, (*it_s).value(), needSeparator); 00427 it_s++; 00428 } 00429 } 00430 } 00431 } 00432 else if (item[0] == '/') 00433 { 00434 QString groupPath = rp + item.mid(1) + "/"; 00435 00436 for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2) 00437 { 00438 if (!(*it2)->isType(KST_KServiceGroup)) 00439 continue; 00440 KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2)); 00441 if (group->relPath() == groupPath) 00442 { 00443 if (!excludeNoDisplay || !group->noDisplay()) 00444 addItem(sorted, (*it2), needSeparator); 00445 break; 00446 } 00447 } 00448 } 00449 else 00450 { 00451 for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2) 00452 { 00453 if (!(*it2)->isType(KST_KService)) 00454 continue; 00455 KService *service = (KService *)((KSycocaEntry *)(*it2)); 00456 if (service->menuId() == item) 00457 { 00458 if (!excludeNoDisplay || !service->noDisplay()) 00459 addItem(sorted, (*it2), needSeparator); 00460 break; 00461 } 00462 } 00463 } 00464 } 00465 00466 return sorted; 00467 } 00468 00469 void KServiceGroup::setLayoutInfo(const QStringList &layout) 00470 { 00471 d->sortOrder = layout; 00472 } 00473 00474 KServiceGroup::Ptr 00475 KServiceGroup::baseGroup( const QString & _baseGroupName ) 00476 { 00477 return KServiceGroupFactory::self()->findBaseGroup(_baseGroupName, true); 00478 } 00479 00480 KServiceGroup::Ptr 00481 KServiceGroup::root() 00482 { 00483 return KServiceGroupFactory::self()->findGroupByDesktopPath("/", true); 00484 } 00485 00486 KServiceGroup::Ptr 00487 KServiceGroup::group(const QString &relPath) 00488 { 00489 if (relPath.isEmpty()) return root(); 00490 return KServiceGroupFactory::self()->findGroupByDesktopPath(relPath, true); 00491 } 00492 00493 KServiceGroup::Ptr 00494 KServiceGroup::childGroup(const QString &parent) 00495 { 00496 return KServiceGroupFactory::self()->findGroupByDesktopPath("#parent#"+parent, true); 00497 } 00498 00499 QString 00500 KServiceGroup::directoryEntryPath() const 00501 { 00502 return d->directoryEntryPath; 00503 } 00504 00505 00506 void KServiceGroup::virtual_hook( int id, void* data ) 00507 { KSycocaEntry::virtual_hook( id, data ); } 00508 00509 00510 KServiceSeparator::KServiceSeparator( ) 00511 : KSycocaEntry("separator") 00512 { 00513 }
KDE Logo
This file is part of the documentation for kio Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 8 11:14:59 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003