kio Library API Documentation

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