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