kservice.cpp

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