kservice.cpp
00001 /* This file is part of the KDE libraries 00002 * Copyright (C) 1999 - 2001 Waldo Bastian <bastian@kde.org> 00003 * Copyright (C) 1999 David Faure <faure@kde.org> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License version 2 as published by the Free Software Foundation; 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Library General Public License 00015 * along with this library; see the file COPYING.LIB. If not, write to 00016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 * Boston, MA 02110-1301, USA. 00018 **/ 00019 00020 // $Id$ 00021 00022 #include <config.h> 00023 00024 #include "kservice.h" 00025 #include "kservice_p.h" 00026 00027 #include <sys/types.h> 00028 #include <sys/stat.h> 00029 00030 #include <stddef.h> 00031 #include <unistd.h> 00032 #include <stdlib.h> 00033 00034 #include <qstring.h> 00035 #include <qfile.h> 00036 #include <qdir.h> 00037 #include <qtl.h> 00038 00039 #include <ksimpleconfig.h> 00040 #include <kapplication.h> 00041 #include <kdebug.h> 00042 #include <kdesktopfile.h> 00043 #include <kglobal.h> 00044 #include <kiconloader.h> 00045 #include <klocale.h> 00046 #include <kconfigbase.h> 00047 #include <kstandarddirs.h> 00048 #include <dcopclient.h> 00049 00050 #include "kservicefactory.h" 00051 #include "kservicetypefactory.h" 00052 #include "kservicetype.h" 00053 #include "kuserprofile.h" 00054 #include "ksycoca.h" 00055 00056 class KService::KServicePrivate 00057 { 00058 public: 00059 QStringList categories; 00060 QString menuId; 00061 }; 00062 00063 KService::KService( const QString & _name, const QString &_exec, const QString &_icon) 00064 : KSycocaEntry( QString::null) 00065 { 00066 d = new KServicePrivate; 00067 m_bValid = true; 00068 m_bDeleted = false; 00069 m_strType = "Application"; 00070 m_strName = _name; 00071 m_strExec = _exec; 00072 m_strIcon = _icon; 00073 m_bTerminal = false; 00074 m_bAllowAsDefault = true; 00075 m_initialPreference = 10; 00076 } 00077 00078 00079 KService::KService( const QString & _fullpath ) 00080 : KSycocaEntry( _fullpath) 00081 { 00082 KDesktopFile config( _fullpath ); 00083 00084 init(&config); 00085 } 00086 00087 KService::KService( KDesktopFile *config ) 00088 : KSycocaEntry( config->fileName()) 00089 { 00090 init(config); 00091 } 00092 00093 void 00094 KService::init( KDesktopFile *config ) 00095 { 00096 d = new KServicePrivate; 00097 m_bValid = true; 00098 00099 bool absPath = !QDir::isRelativePath(entryPath()); 00100 00101 config->setDesktopGroup(); 00102 00103 QMap<QString, QString> entryMap = config->entryMap(config->group()); 00104 00105 entryMap.remove("Encoding"); // reserved as part of Desktop Entry Standard 00106 entryMap.remove("Version"); // reserved as part of Desktop Entry Standard 00107 00108 m_bDeleted = config->readBoolEntry( "Hidden", false ); 00109 entryMap.remove("Hidden"); 00110 if (m_bDeleted) 00111 { 00112 //kdDebug() << "Hidden=true for " << entryPath() << endl; 00113 m_bValid = false; 00114 return; 00115 } 00116 00117 m_strName = config->readEntry( "Name" ); 00118 entryMap.remove("Name"); 00119 if ( m_strName.isEmpty() ) 00120 { 00121 if (config->readEntry( "Exec" ).isEmpty()) 00122 { 00123 //kdWarning(7012) << "The desktop entry file " << entryPath() 00124 // << " has no Name and no Exec" << endl; 00125 m_bValid = false; 00126 return; 00127 } 00128 // Try to make up a name. 00129 m_strName = entryPath(); 00130 int i = m_strName.findRev('/'); 00131 m_strName = m_strName.mid(i+1); 00132 i = m_strName.findRev('.'); 00133 if (i != -1) 00134 m_strName = m_strName.left(i); 00135 } 00136 00137 m_strType = config->readEntry( "Type" ); 00138 entryMap.remove("Type"); 00139 if ( m_strType.isEmpty() ) 00140 { 00141 /*kdWarning(7012) << "The desktop entry file " << entryPath() 00142 << " has no Type=... entry." 00143 << " It should be \"Application\" or \"Service\"" << endl; 00144 m_bValid = false; 00145 return;*/ 00146 m_strType = "Application"; 00147 } else if ( m_strType != "Application" && m_strType != "Service" ) 00148 { 00149 kdWarning(7012) << "The desktop entry file " << entryPath() 00150 << " has Type=" << m_strType 00151 << " instead of \"Application\" or \"Service\"" << endl; 00152 m_bValid = false; 00153 return; 00154 } 00155 00156 // In case Try Exec is set, check if the application is available 00157 if (!config->tryExec()) { 00158 //kdDebug(7012) << "tryExec said false for " << entryPath() << endl; 00159 m_bDeleted = true; 00160 m_bValid = false; 00161 return; 00162 } 00163 00164 QString resource = config->resource(); 00165 00166 if ( (m_strType == "Application") && 00167 (!resource.isEmpty()) && 00168 (resource != "apps") && 00169 !absPath) 00170 { 00171 kdWarning(7012) << "The desktop entry file " << entryPath() 00172 << " has Type=" << m_strType << " but is located under \"" << resource 00173 << "\" instead of \"apps\"" << endl; 00174 m_bValid = false; 00175 return; 00176 } 00177 00178 if ( (m_strType == "Service") && 00179 (!resource.isEmpty()) && 00180 (resource != "services") && 00181 !absPath) 00182 { 00183 kdWarning(7012) << "The desktop entry file " << entryPath() 00184 << " has Type=" << m_strType << " but is located under \"" << resource 00185 << "\" instead of \"services\"" << endl; 00186 m_bValid = false; 00187 return; 00188 } 00189 00190 QString name = entryPath(); 00191 int pos = name.findRev('/'); 00192 if (pos != -1) 00193 name = name.mid(pos+1); 00194 pos = name.find('.'); 00195 if (pos != -1) 00196 name = name.left(pos); 00197 00198 m_strExec = config->readPathEntry( "Exec" ); 00199 entryMap.remove("Exec"); 00200 00201 m_strIcon = config->readEntry( "Icon", "unknown" ); 00202 entryMap.remove("Icon"); 00203 m_bTerminal = (config->readBoolEntry( "Terminal" )); // should be a property IMHO 00204 entryMap.remove("Terminal"); 00205 m_strTerminalOptions = config->readEntry( "TerminalOptions" ); // should be a property IMHO 00206 entryMap.remove("TerminalOptions"); 00207 m_strPath = config->readPathEntry( "Path" ); 00208 entryMap.remove("Path"); 00209 m_strComment = config->readEntry( "Comment" ); 00210 entryMap.remove("Comment"); 00211 m_strGenName = config->readEntry( "GenericName" ); 00212 entryMap.remove("GenericName"); 00213 QString untranslatedGenericName = config->readEntryUntranslated( "GenericName" ); 00214 if (!untranslatedGenericName.isEmpty()) 00215 entryMap.insert("UntranslatedGenericName", untranslatedGenericName); 00216 00217 m_lstKeywords = config->readListEntry("Keywords"); 00218 entryMap.remove("Keywords"); 00219 d->categories = config->readListEntry("Categories", ';'); 00220 entryMap.remove("Categories"); 00221 m_strLibrary = config->readEntry( "X-KDE-Library" ); 00222 entryMap.remove("X-KDE-Library"); 00223 m_strInit = config->readEntry("X-KDE-Init" ); 00224 entryMap.remove("X-KDE-Init"); 00225 00226 m_lstServiceTypes = config->readListEntry( "ServiceTypes" ); 00227 entryMap.remove("ServiceTypes"); 00228 // For compatibility with KDE 1.x 00229 m_lstServiceTypes += config->readListEntry( "MimeType", ';' ); 00230 entryMap.remove("MimeType"); 00231 00232 if ( m_strType == "Application" && !m_lstServiceTypes.contains("Application") ) 00233 // Applications implement the service type "Application" ;-) 00234 m_lstServiceTypes += "Application"; 00235 00236 QString dcopServiceType = config->readEntry("X-DCOP-ServiceType").lower(); 00237 entryMap.remove("X-DCOP-ServiceType"); 00238 if (dcopServiceType == "unique") 00239 m_DCOPServiceType = DCOP_Unique; 00240 else if (dcopServiceType == "multi") 00241 m_DCOPServiceType = DCOP_Multi; 00242 else if (dcopServiceType == "wait") 00243 m_DCOPServiceType = DCOP_Wait; 00244 else 00245 m_DCOPServiceType = DCOP_None; 00246 00247 m_strDesktopEntryName = name.lower(); 00248 00249 m_bAllowAsDefault = config->readBoolEntry( "AllowDefault", true ); 00250 entryMap.remove("AllowDefault"); 00251 00252 m_initialPreference = config->readNumEntry( "InitialPreference", 1 ); 00253 entryMap.remove("InitialPreference"); 00254 00255 // Store all additional entries in the property map. 00256 // A QMap<QString,QString> would be easier for this but we can't 00257 // brake BC, so we have to store it in m_mapProps. 00258 // qWarning("Path = %s", entryPath().latin1()); 00259 QMap<QString,QString>::ConstIterator it = entryMap.begin(); 00260 for( ; it != entryMap.end();++it) 00261 { 00262 //qDebug(" Key = %s Data = %s", it.key().latin1(), it.data().latin1()); 00263 m_mapProps.insert( it.key(), QVariant( it.data())); 00264 } 00265 } 00266 00267 KService::KService( QDataStream& _str, int offset ) : KSycocaEntry( _str, offset ) 00268 { 00269 d = new KServicePrivate; 00270 load( _str ); 00271 } 00272 00273 KService::~KService() 00274 { 00275 //debug("KService::~KService()"); 00276 delete d; 00277 } 00278 00279 QPixmap KService::pixmap( KIcon::Group _group, int _force_size, int _state, QString * _path ) const 00280 { 00281 KIconLoader *iconLoader=KGlobal::iconLoader(); 00282 if (!iconLoader->extraDesktopThemesAdded()) 00283 { 00284 QPixmap pixmap=iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path, true ); 00285 if (!pixmap.isNull() ) return pixmap; 00286 00287 iconLoader->addExtraDesktopThemes(); 00288 } 00289 00290 return iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path ); 00291 } 00292 00293 void KService::load( QDataStream& s ) 00294 { 00295 // dummies are here because of fields that were removed, to keep bin compat. 00296 // Feel free to re-use, but fields for Applications only (not generic services) 00297 // should rather be added to application.desktop 00298 Q_INT8 def, term, dummy1, dummy2; 00299 Q_INT8 dst, initpref; 00300 QString dummyStr1, dummyStr2; 00301 int dummyI1, dummyI2; 00302 Q_UINT32 dummyUI32; 00303 00304 // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x! 00305 // !! This data structure should remain binary compatible at all times !! 00306 // You may add new fields at the end. Make sure to update the version 00307 // number in ksycoca.h 00308 s >> m_strType >> m_strName >> m_strExec >> m_strIcon 00309 >> term >> m_strTerminalOptions 00310 >> m_strPath >> m_strComment >> m_lstServiceTypes >> def >> m_mapProps 00311 >> m_strLibrary >> dummyI1 >> dummyI2 00312 >> dst 00313 >> m_strDesktopEntryName 00314 >> dummy1 >> dummyStr1 >> initpref >> dummyStr2 >> dummy2 00315 >> m_lstKeywords >> m_strInit >> dummyUI32 >> m_strGenName 00316 >> d->categories >> d->menuId; 00317 00318 m_bAllowAsDefault = def; 00319 m_bTerminal = term; 00320 m_DCOPServiceType = (DCOPServiceType_t) dst; 00321 m_initialPreference = initpref; 00322 00323 m_bValid = true; 00324 } 00325 00326 void KService::save( QDataStream& s ) 00327 { 00328 KSycocaEntry::save( s ); 00329 Q_INT8 def = m_bAllowAsDefault, initpref = m_initialPreference; 00330 Q_INT8 term = m_bTerminal; 00331 Q_INT8 dst = (Q_INT8) m_DCOPServiceType; 00332 Q_INT8 dummy1 = 0, dummy2 = 0; // see ::load 00333 QString dummyStr1, dummyStr2; 00334 int dummyI1 = 0, dummyI2 = 0; 00335 Q_UINT32 dummyUI32 = 0; 00336 00337 // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x! 00338 // !! This data structure should remain binary compatible at all times !! 00339 // You may add new fields at the end. Make sure to update the version 00340 // number in ksycoca.h 00341 s << m_strType << m_strName << m_strExec << m_strIcon 00342 << term << m_strTerminalOptions 00343 << m_strPath << m_strComment << m_lstServiceTypes << def << m_mapProps 00344 << m_strLibrary << dummyI1 << dummyI2 00345 << dst 00346 << m_strDesktopEntryName 00347 << dummy1 << dummyStr1 << initpref << dummyStr2 << dummy2 00348 << m_lstKeywords << m_strInit << dummyUI32 << m_strGenName 00349 << d->categories << d->menuId; 00350 } 00351 00352 bool KService::hasServiceType( const QString& _servicetype ) const 00353 { 00354 if (!m_bValid) return false; // safety test 00355 00356 //kdDebug(7012) << "Testing " << m_strDesktopEntryName << " for " << _servicetype << endl; 00357 00358 KMimeType::Ptr mimePtr = KMimeType::mimeType( _servicetype ); 00359 if ( mimePtr && mimePtr == KMimeType::defaultMimeTypePtr() ) 00360 mimePtr = 0; 00361 00362 bool isNumber; 00363 // For each service type we are associated with, if it doesn't 00364 // match then we try its parent service types. 00365 QStringList::ConstIterator it = m_lstServiceTypes.begin(); 00366 for( ; it != m_lstServiceTypes.end(); ++it ) 00367 { 00368 (*it).toInt(&isNumber); 00369 if (isNumber) 00370 continue; 00371 //kdDebug(7012) << " has " << (*it) << endl; 00372 KServiceType::Ptr ptr = KServiceType::serviceType( *it ); 00373 if ( ptr && ptr->inherits( _servicetype ) ) 00374 return true; 00375 00376 // The mimetype inheritance ("is also") works the other way. 00377 // e.g. if we're looking for a handler for mimePtr==smb-workgroup 00378 // then a handler for inode/directory is ok. 00379 if ( mimePtr && mimePtr->is( *it ) ) 00380 return true; 00381 } 00382 return false; 00383 } 00384 00385 int KService::initialPreferenceForMimeType( const QString& mimeType ) const 00386 { 00387 if (!m_bValid) return 0; // safety test 00388 00389 bool isNumber; 00390 00391 // For each service type we are associated with 00392 QStringList::ConstIterator it = m_lstServiceTypes.begin(); 00393 for( ; it != m_lstServiceTypes.end(); ++it ) 00394 { 00395 (*it).toInt(&isNumber); 00396 if (isNumber) 00397 continue; 00398 //kdDebug(7012) << " has " << (*it) << endl; 00399 KServiceType::Ptr ptr = KServiceType::serviceType( *it ); 00400 if ( !ptr || !ptr->inherits( mimeType ) ) 00401 continue; 00402 00403 int initalPreference = m_initialPreference; 00404 ++it; 00405 if (it != m_lstServiceTypes.end()) 00406 { 00407 int i = (*it).toInt(&isNumber); 00408 if (isNumber) 00409 initalPreference = i; 00410 } 00411 return initalPreference; 00412 } 00413 00414 KMimeType::Ptr mimePtr = KMimeType::mimeType( mimeType ); 00415 if ( mimePtr && mimePtr == KMimeType::defaultMimeTypePtr() ) 00416 mimePtr = 0; 00417 00418 // Try its parent service types. 00419 it = m_lstServiceTypes.begin(); 00420 for( ; it != m_lstServiceTypes.end(); ++it ) 00421 { 00422 (*it).toInt(&isNumber); 00423 if (isNumber) 00424 continue; 00425 00426 // The mimetype inheritance ("is also") works the other way. 00427 // e.g. if we're looking for a handler for mimePtr==smb-workgroup 00428 // then a handler for inode/directory is ok. 00429 if ( !mimePtr || !mimePtr->is( *it ) ) 00430 continue; 00431 00432 int initalPreference = m_initialPreference; 00433 ++it; 00434 if (it != m_lstServiceTypes.end()) 00435 { 00436 int i = (*it).toInt(&isNumber); 00437 if (isNumber) 00438 initalPreference = i; 00439 } 00440 return initalPreference; 00441 } 00442 return 0; 00443 } 00444 00445 class KServiceReadProperty : public KConfigBase 00446 { 00447 public: 00448 KServiceReadProperty(const QString &_key, const QCString &_value) 00449 : key(_key), value(_value) { } 00450 00451 bool internalHasGroup(const QCString &) const { /*qDebug("hasGroup(const QCString &)");*/ return false; } 00452 00453 QStringList groupList() const { return QStringList(); } 00454 00455 QMap<QString,QString> entryMap(const QString &group) const 00456 { Q_UNUSED(group); return QMap<QString,QString>(); } 00457 00458 void reparseConfiguration() { } 00459 00460 KEntryMap internalEntryMap( const QString &pGroup) const 00461 { Q_UNUSED(pGroup); return KEntryMap(); } 00462 00463 KEntryMap internalEntryMap() const { return KEntryMap(); } 00464 00465 void putData(const KEntryKey &_key, const KEntry& _data, bool _checkGroup) 00466 { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); } 00467 00468 KEntry lookupData(const KEntryKey &_key) const 00469 { Q_UNUSED(_key); KEntry entry; entry.mValue = value; return entry; } 00470 protected: 00471 QString key; 00472 QCString value; 00473 }; 00474 00475 QVariant KService::property( const QString& _name) const 00476 { 00477 return property( _name, QVariant::Invalid); 00478 } 00479 00480 // Return a string QVariant if string isn't null, and invalid variant otherwise 00481 // (the variant must be invalid if the field isn't in the .desktop file) 00482 // This allows trader queries like "exist Library" to work. 00483 static QVariant makeStringVariant( const QString& string ) 00484 { 00485 // Using isEmpty here would be wrong. 00486 // Empty is "specified but empty", null is "not specified" (in the .desktop file) 00487 return string.isNull() ? QVariant() : QVariant( string ); 00488 } 00489 00490 QVariant KService::property( const QString& _name, QVariant::Type t ) const 00491 { 00492 if ( _name == "Type" ) 00493 return QVariant( m_strType ); // can't be null 00494 else if ( _name == "Name" ) 00495 return QVariant( m_strName ); // can't be null 00496 else if ( _name == "Exec" ) 00497 return makeStringVariant( m_strExec ); 00498 else if ( _name == "Icon" ) 00499 return makeStringVariant( m_strIcon ); 00500 else if ( _name == "Terminal" ) 00501 return QVariant( static_cast<int>(m_bTerminal) ); 00502 else if ( _name == "TerminalOptions" ) 00503 return makeStringVariant( m_strTerminalOptions ); 00504 else if ( _name == "Path" ) 00505 return makeStringVariant( m_strPath ); 00506 else if ( _name == "Comment" ) 00507 return makeStringVariant( m_strComment ); 00508 else if ( _name == "GenericName" ) 00509 return makeStringVariant( m_strGenName ); 00510 else if ( _name == "ServiceTypes" ) 00511 return QVariant( m_lstServiceTypes ); 00512 else if ( _name == "AllowAsDefault" ) 00513 return QVariant( static_cast<int>(m_bAllowAsDefault) ); 00514 else if ( _name == "InitialPreference" ) 00515 return QVariant( m_initialPreference ); 00516 else if ( _name == "Library" ) 00517 return makeStringVariant( m_strLibrary ); 00518 else if ( _name == "DesktopEntryPath" ) // can't be null 00519 return QVariant( entryPath() ); 00520 else if ( _name == "DesktopEntryName") 00521 return QVariant( m_strDesktopEntryName ); // can't be null 00522 else if ( _name == "Categories") 00523 return QVariant( d->categories ); 00524 else if ( _name == "Keywords") 00525 return QVariant( m_lstKeywords ); 00526 00527 // Ok we need to convert the property from a QString to its real type. 00528 // Maybe the caller helped us. 00529 if (t == QVariant::Invalid) 00530 { 00531 // No luck, let's ask KServiceTypeFactory what the type of this property 00532 // is supposed to be. 00533 t = KServiceTypeFactory::self()->findPropertyTypeByName(_name); 00534 if (t == QVariant::Invalid) 00535 { 00536 kdDebug(7012) << "Request for unknown property '" << _name << "'\n"; 00537 return QVariant(); // Unknown property: Invalid variant. 00538 } 00539 } 00540 00541 // Then we use a homebuild class based on KConfigBase to convert the QString. 00542 // For some often used property types we do the conversion ourselves. 00543 QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( _name ); 00544 if ( (it == m_mapProps.end()) || (!it.data().isValid())) 00545 { 00546 //kdDebug(7012) << "Property not found " << _name << endl; 00547 return QVariant(); // No property set. 00548 } 00549 00550 switch(t) 00551 { 00552 case QVariant::String: 00553 return it.data(); 00554 case QVariant::Bool: 00555 case QVariant::Int: 00556 { 00557 QString aValue = it.data().toString(); 00558 int val = 0; 00559 if (aValue == "true" || aValue == "on" || aValue == "yes") 00560 val = 1; 00561 else 00562 { 00563 bool bOK; 00564 val = aValue.toInt( &bOK ); 00565 if( !bOK ) 00566 val = 0; 00567 } 00568 if (t == QVariant::Bool) 00569 { 00570 return QVariant((bool)val, 1); 00571 } 00572 return QVariant(val); 00573 } 00574 default: 00575 // All others 00576 KServiceReadProperty ksrp(_name, it.data().toString().utf8()); 00577 return ksrp.readPropertyEntry(_name, t); 00578 } 00579 } 00580 00581 QStringList KService::propertyNames() const 00582 { 00583 QStringList res; 00584 00585 QMap<QString,QVariant>::ConstIterator it = m_mapProps.begin(); 00586 for( ; it != m_mapProps.end(); ++it ) 00587 res.append( it.key() ); 00588 00589 res.append( "Type" ); 00590 res.append( "Name" ); 00591 res.append( "Comment" ); 00592 res.append( "GenericName" ); 00593 res.append( "Icon" ); 00594 res.append( "Exec" ); 00595 res.append( "Terminal" ); 00596 res.append( "TerminalOptions" ); 00597 res.append( "Path" ); 00598 res.append( "ServiceTypes" ); 00599 res.append( "AllowAsDefault" ); 00600 res.append( "InitialPreference" ); 00601 res.append( "Library" ); 00602 res.append( "DesktopEntryPath" ); 00603 res.append( "DesktopEntryName" ); 00604 res.append( "Keywords" ); 00605 res.append( "Categories" ); 00606 00607 return res; 00608 } 00609 00610 KService::List KService::allServices() 00611 { 00612 return KServiceFactory::self()->allServices(); 00613 } 00614 00615 KService::Ptr KService::serviceByName( const QString& _name ) 00616 { 00617 KService * s = KServiceFactory::self()->findServiceByName( _name ); 00618 return KService::Ptr( s ); 00619 } 00620 00621 KService::Ptr KService::serviceByDesktopPath( const QString& _name ) 00622 { 00623 KService * s = KServiceFactory::self()->findServiceByDesktopPath( _name ); 00624 return KService::Ptr( s ); 00625 } 00626 00627 KService::Ptr KService::serviceByDesktopName( const QString& _name ) 00628 { 00629 KService * s = KServiceFactory::self()->findServiceByDesktopName( _name.lower() ); 00630 if (!s && !_name.startsWith("kde-")) 00631 s = KServiceFactory::self()->findServiceByDesktopName( "kde-"+_name.lower() ); 00632 return KService::Ptr( s ); 00633 } 00634 00635 KService::Ptr KService::serviceByMenuId( const QString& _name ) 00636 { 00637 KService * s = KServiceFactory::self()->findServiceByMenuId( _name ); 00638 return KService::Ptr( s ); 00639 } 00640 00641 KService::Ptr KService::serviceByStorageId( const QString& _storageId ) 00642 { 00643 KService::Ptr service = KService::serviceByMenuId( _storageId ); 00644 if (service) 00645 return service; 00646 00647 service = KService::serviceByDesktopPath(_storageId); 00648 if (service) 00649 return service; 00650 00651 if (!QDir::isRelativePath(_storageId) && QFile::exists(_storageId)) 00652 return new KService(_storageId); 00653 00654 QString tmp = _storageId; 00655 tmp = tmp.mid(tmp.findRev('/')+1); // Strip dir 00656 00657 if (tmp.endsWith(".desktop")) 00658 tmp.truncate(tmp.length()-8); 00659 00660 if (tmp.endsWith(".kdelnk")) 00661 tmp.truncate(tmp.length()-7); 00662 00663 service = KService::serviceByDesktopName(tmp); 00664 00665 return service; 00666 } 00667 00668 KService::List KService::allInitServices() 00669 { 00670 return KServiceFactory::self()->allInitServices(); 00671 } 00672 00673 bool KService::substituteUid() const { 00674 QVariant v = property("X-KDE-SubstituteUID", QVariant::Bool); 00675 return v.isValid() && v.toBool(); 00676 } 00677 00678 QString KService::username() const { 00679 // See also KDesktopFile::tryExec() 00680 QString user; 00681 QVariant v = property("X-KDE-Username", QVariant::String); 00682 user = v.isValid() ? v.toString() : QString::null; 00683 if (user.isEmpty()) 00684 user = ::getenv("ADMIN_ACCOUNT"); 00685 if (user.isEmpty()) 00686 user = "root"; 00687 return user; 00688 } 00689 00690 bool KService::noDisplay() const { 00691 QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( "NoDisplay" ); 00692 if ( (it != m_mapProps.end()) && (it.data().isValid())) 00693 { 00694 QString aValue = it.data().toString().lower(); 00695 if (aValue == "true" || aValue == "on" || aValue == "yes") 00696 return true; 00697 } 00698 00699 it = m_mapProps.find( "OnlyShowIn" ); 00700 if ( (it != m_mapProps.end()) && (it.data().isValid())) 00701 { 00702 QString aValue = it.data().toString(); 00703 QStringList aList = QStringList::split(';', aValue); 00704 if (!aList.contains("KDE")) 00705 return true; 00706 } 00707 00708 it = m_mapProps.find( "NotShowIn" ); 00709 if ( (it != m_mapProps.end()) && (it.data().isValid())) 00710 { 00711 QString aValue = it.data().toString(); 00712 QStringList aList = QStringList::split(';', aValue); 00713 if (aList.contains("KDE")) 00714 return true; 00715 } 00716 00717 if (!kapp->authorizeControlModule(d->menuId)) 00718 return true; 00719 00720 return false; 00721 } 00722 00723 QString KService::untranslatedGenericName() const { 00724 QVariant v = property("UntranslatedGenericName", QVariant::String); 00725 return v.isValid() ? v.toString() : QString::null; 00726 } 00727 00728 QString KService::parentApp() const { 00729 QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( "X-KDE-ParentApp" ); 00730 if ( (it == m_mapProps.end()) || (!it.data().isValid())) 00731 { 00732 return QString::null; 00733 } 00734 00735 return it.data().toString(); 00736 } 00737 00738 bool KService::allowMultipleFiles() const { 00739 // Can we pass multiple files on the command line or do we have to start the application for every single file ? 00740 if ( m_strExec.find( "%F" ) != -1 || m_strExec.find( "%U" ) != -1 || 00741 m_strExec.find( "%N" ) != -1 || m_strExec.find( "%D" ) != -1 ) 00742 return true; 00743 else 00744 return false; 00745 } 00746 00747 QStringList KService::categories() const 00748 { 00749 return d->categories; 00750 } 00751 00752 QString KService::menuId() const 00753 { 00754 return d->menuId; 00755 } 00756 00757 void KService::setMenuId(const QString &menuId) 00758 { 00759 d->menuId = menuId; 00760 } 00761 00762 QString KService::storageId() const 00763 { 00764 if (!d->menuId.isEmpty()) 00765 return d->menuId; 00766 return entryPath(); 00767 } 00768 00769 QString KService::locateLocal() 00770 { 00771 if (d->menuId.isEmpty() || desktopEntryPath().startsWith(".hidden") || 00772 (QDir::isRelativePath(desktopEntryPath()) && d->categories.isEmpty())) 00773 return KDesktopFile::locateLocal(desktopEntryPath()); 00774 00775 return ::locateLocal("xdgdata-apps", d->menuId); 00776 } 00777 00778 QString KService::newServicePath(bool showInMenu, const QString &suggestedName, 00779 QString *menuId, const QStringList *reservedMenuIds) 00780 { 00781 QString base = suggestedName; 00782 if (!showInMenu) 00783 base.prepend("kde-"); 00784 00785 QString result; 00786 for(int i = 1; true; i++) 00787 { 00788 if (i == 1) 00789 result = base + ".desktop"; 00790 else 00791 result = base + QString("-%1.desktop").arg(i); 00792 00793 if (reservedMenuIds && reservedMenuIds->contains(result)) 00794 continue; 00795 00796 // Lookup service by menu-id 00797 KService::Ptr s = serviceByMenuId(result); 00798 if (s) 00799 continue; 00800 00801 if (showInMenu) 00802 { 00803 if (!locate("xdgdata-apps", result).isEmpty()) 00804 continue; 00805 } 00806 else 00807 { 00808 QString file = result.mid(4); // Strip "kde-" 00809 if (!locate("apps", ".hidden/"+file).isEmpty()) 00810 continue; 00811 } 00812 00813 break; 00814 } 00815 if (menuId) 00816 *menuId = result; 00817 00818 if (showInMenu) 00819 { 00820 return ::locateLocal("xdgdata-apps", result); 00821 } 00822 else 00823 { 00824 QString file = result.mid(4); // Strip "kde-" 00825 return ::locateLocal("apps", ".hidden/"+file); 00826 } 00827 } 00828 00829 00830 void KService::virtual_hook( int id, void* data ) 00831 { KSycocaEntry::virtual_hook( id, data ); } 00832 00833 00834 void KService::rebuildKSycoca(QWidget *parent) 00835 { 00836 KServiceProgressDialog dlg(parent, "ksycoca_progress", 00837 i18n("Updating System Configuration"), 00838 i18n("Updating system configuration.")); 00839 00840 QByteArray data; 00841 DCOPClient *client = kapp->dcopClient(); 00842 00843 int result = client->callAsync("kded", "kbuildsycoca", "recreate()", 00844 data, &dlg, SLOT(slotFinished())); 00845 00846 if (result) 00847 { 00848 dlg.exec(); 00849 } 00850 } 00851 00852 KServiceProgressDialog::KServiceProgressDialog(QWidget *parent, const char *name, 00853 const QString &caption, const QString &text) 00854 : KProgressDialog(parent, name, caption, text, true) 00855 { 00856 connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotProgress())); 00857 progressBar()->setTotalSteps(20); 00858 m_timeStep = 700; 00859 m_timer.start(m_timeStep); 00860 setAutoClose(false); 00861 } 00862 00863 void 00864 KServiceProgressDialog::slotProgress() 00865 { 00866 int p = progressBar()->progress(); 00867 if (p == 18) 00868 { 00869 progressBar()->reset(); 00870 progressBar()->setProgress(1); 00871 m_timeStep = m_timeStep * 2; 00872 m_timer.start(m_timeStep); 00873 } 00874 else 00875 { 00876 progressBar()->setProgress(p+1); 00877 } 00878 } 00879 00880 void 00881 KServiceProgressDialog::slotFinished() 00882 { 00883 progressBar()->setProgress(20); 00884 m_timer.stop(); 00885 QTimer::singleShot(1000, this, SLOT(close())); 00886 } 00887 00888 #include "kservice_p.moc"