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