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