• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

kservice.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 - 2001 Waldo Bastian <bastian@kde.org>
00003  *  Copyright (C) 1999 - 2005 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 #include "kservice.h"
00021 #include "kservice_p.h"
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 
00026 #include <stddef.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 
00030 #include <QtCore/QCharRef>
00031 #include <QtCore/QFile>
00032 #include <QtCore/QDir>
00033 #include <QtCore/QMap>
00034 
00035 #include <kauthorized.h>
00036 #include <kdebug.h>
00037 #include <kdesktopfile.h>
00038 #include <kglobal.h>
00039 #include <kconfiggroup.h>
00040 #include <kstandarddirs.h>
00041 
00042 #include "kservicefactory.h"
00043 #include "kservicetypefactory.h"
00044 
00045 QDataStream &operator<<(QDataStream &s, const KService::ServiceTypeAndPreference &st)
00046 {
00047     s << st.preference << st.serviceType;
00048     return s;
00049 }
00050 QDataStream &operator>>(QDataStream &s, KService::ServiceTypeAndPreference &st)
00051 {
00052     s >> st.preference >> st.serviceType;
00053     return s;
00054 }
00055 
00056 void KServicePrivate::init( const KDesktopFile *config, KService* q )
00057 {
00058     const QString entryPath = q->entryPath();
00059     bool absPath = !QDir::isRelativePath(entryPath);
00060 
00061     // TODO: it makes sense to have a KConstConfigGroup I guess
00062     const KConfigGroup desktopGroup = const_cast<KDesktopFile*>(config)->desktopGroup();
00063     QMap<QString, QString> entryMap = desktopGroup.entryMap();
00064 
00065     entryMap.remove("Encoding"); // reserved as part of Desktop Entry Standard
00066     entryMap.remove("Version");  // reserved as part of Desktop Entry Standard
00067 
00068     q->setDeleted( desktopGroup.readEntry("Hidden", false) );
00069     entryMap.remove("Hidden");
00070     if ( q->isDeleted() ) {
00071         m_bValid = false;
00072         return;
00073     }
00074 
00075     m_strName = config->readName();
00076     entryMap.remove("Name");
00077     if ( m_strName.isEmpty() )
00078     {
00079         // Try to make up a name.
00080         m_strName = entryPath;
00081         int i = m_strName.lastIndexOf('/');
00082         m_strName = m_strName.mid(i+1);
00083         i = m_strName.lastIndexOf('.');
00084         if (i != -1)
00085             m_strName = m_strName.left(i);
00086     }
00087 
00088     m_strType = config->readType();
00089     entryMap.remove("Type");
00090     if ( m_strType.isEmpty() )
00091     {
00092         /*kWarning(7012) << "The desktop entry file " << entryPath
00093           << " has no Type=... entry."
00094           << " It should be \"Application\" or \"Service\"" << endl;
00095           m_bValid = false;
00096           return;*/
00097         m_strType = "Application";
00098     } else if ( m_strType != "Application" && m_strType != "Service" )
00099     {
00100         kWarning(7012) << "The desktop entry file " << entryPath
00101                        << " has Type=" << m_strType
00102                        << " instead of \"Application\" or \"Service\"" << endl;
00103         m_bValid = false;
00104         return;
00105     }
00106 
00107     // NOT readPathEntry, it is not XDG-compliant. Path entries written by
00108     // KDE4 will be still treated as such, though.
00109     m_strExec = desktopGroup.readEntry( "Exec", QString() );
00110     entryMap.remove("Exec");
00111 
00112     if ( m_strType == "Application" ) {
00113         // It's an application? Should have an Exec line then, otherwise we can't run it
00114         if (m_strExec.isEmpty()) {
00115             kWarning(7012) << "The desktop entry file " << entryPath
00116                            << " has Type=" << m_strType
00117                            << " but no Exec line" << endl;
00118             m_bValid = false;
00119             return;
00120         }
00121     }
00122 
00123     // In case Try Exec is set, check if the application is available
00124     if (!config->tryExec()) {
00125         q->setDeleted( true );
00126         m_bValid = false;
00127         return;
00128     }
00129 
00130     QString resource = config->resource();
00131 
00132     if ( (m_strType == "Application") &&
00133          (!resource.isEmpty()) &&
00134          (resource != "apps") &&
00135          !absPath)
00136     {
00137         kWarning(7012) << "The desktop entry file " << entryPath
00138                        << " has Type=" << m_strType << " but is located under \"" << resource
00139                        << "\" instead of \"apps\"" << endl;
00140         m_bValid = false;
00141         return;
00142     }
00143 
00144     if ( (m_strType == "Service") &&
00145          (!resource.isEmpty()) &&
00146          (resource != "services") &&
00147          !absPath)
00148     {
00149         kWarning(7012) << "The desktop entry file " << entryPath
00150                        << " has Type=" << m_strType << " but is located under \"" << resource
00151                        << "\" instead of \"services\"";
00152         m_bValid = false;
00153         return;
00154     }
00155 
00156     QString _name = entryPath;
00157     int pos = _name.lastIndexOf('/');
00158     if (pos != -1)
00159         _name = _name.mid(pos+1);
00160     pos = _name.indexOf('.');
00161     if (pos != -1)
00162         _name = _name.left(pos);
00163 
00164     m_strIcon = config->readIcon();
00165     entryMap.remove("Icon");
00166     m_bTerminal = desktopGroup.readEntry( "Terminal", false); // should be a property IMHO
00167     entryMap.remove("Terminal");
00168     m_strTerminalOptions = desktopGroup.readEntry( "TerminalOptions" ); // should be a property IMHO
00169     entryMap.remove("TerminalOptions");
00170     m_strPath = config->readPath();
00171     entryMap.remove("Path");
00172     m_strComment = config->readComment();
00173     entryMap.remove("Comment");
00174     m_strGenName = config->readGenericName();
00175     entryMap.remove("GenericName");
00176     QString _untranslatedGenericName = desktopGroup.readEntryUntranslated( "GenericName" );
00177     if (!_untranslatedGenericName.isEmpty())
00178         entryMap.insert("UntranslatedGenericName", _untranslatedGenericName);
00179 
00180     m_lstKeywords = desktopGroup.readEntry("Keywords", QStringList());
00181     entryMap.remove("Keywords");
00182     m_lstKeywords += desktopGroup.readEntry("X-KDE-Keywords", QStringList());
00183     entryMap.remove("X-KDE-Keywords");
00184     categories = desktopGroup.readXdgListEntry("Categories");
00185     entryMap.remove("Categories");
00186     // TODO KDE5: only care for X-KDE-Library in Type=Service desktop files
00187     // This will prevent people defining a part and an app in the same desktop file
00188     // which makes user-preference handling difficult.
00189     m_strLibrary = desktopGroup.readEntry( "X-KDE-Library" );
00190     entryMap.remove("X-KDE-Library");
00191     if (!m_strLibrary.isEmpty() && m_strType == "Application") {
00192         kWarning(7012) << "The desktop entry file" << entryPath
00193                        << "has Type=" << m_strType
00194                        << "but also has a X-KDE-Library key. This works for now,"
00195                           " but makes user-preference handling difficult, so support for this might"
00196                           " be removed at some point. Consider splitting it into two desktop files.";
00197     }
00198 
00199     QStringList lstServiceTypes = desktopGroup.readEntry( "ServiceTypes", QStringList() );
00200     entryMap.remove("ServiceTypes");
00201     lstServiceTypes += desktopGroup.readEntry( "X-KDE-ServiceTypes", QStringList() );
00202     entryMap.remove("X-KDE-ServiceTypes");
00203     lstServiceTypes += desktopGroup.readXdgListEntry( "MimeType" );
00204     entryMap.remove("MimeType");
00205 
00206     if ( m_strType == "Application" && !lstServiceTypes.contains("Application") )
00207         // Applications implement the service type "Application" ;-)
00208         lstServiceTypes += "Application";
00209 
00210     m_initialPreference = desktopGroup.readEntry( "InitialPreference", 1 );
00211     entryMap.remove("InitialPreference");
00212 
00213     // Assign the "initial preference" to each mimetype/servicetype
00214     // (and to set such preferences in memory from kbuildsycoca)
00215     m_serviceTypes.reserve(lstServiceTypes.size());
00216     QListIterator<QString> st_it(lstServiceTypes);
00217     while ( st_it.hasNext() ) {
00218         const QString st = st_it.next();
00219         if (st.isEmpty()) {
00220             kWarning(7012) << "The desktop entry file" << entryPath
00221                            << "has an empty mimetype!";
00222             continue;
00223         }
00224         int initialPreference = m_initialPreference;
00225         if ( st_it.hasNext() ) {
00226             // TODO better syntax - separate group with mimetype=number entries?
00227             bool isNumber;
00228             const int val = st_it.peekNext().toInt(&isNumber);
00229             if (isNumber) {
00230                 initialPreference = val;
00231                 st_it.next();
00232             }
00233         }
00234         m_serviceTypes.push_back(KService::ServiceTypeAndPreference(initialPreference, st));
00235     }
00236 
00237     if (entryMap.contains("Actions")) {
00238         parseActions(config, q);
00239     }
00240 
00241     QString dbusStartupType = desktopGroup.readEntry("X-DBUS-StartupType").toLower();
00242     entryMap.remove("X-DBUS-StartupType");
00243     if (dbusStartupType == "unique")
00244         m_DBUSStartusType = KService::DBusUnique;
00245     else if (dbusStartupType == "multi")
00246         m_DBUSStartusType = KService::DBusMulti;
00247     else if (dbusStartupType == "wait")
00248         m_DBUSStartusType = KService::DBusWait;
00249     else
00250         m_DBUSStartusType = KService::DBusNone;
00251 
00252     m_strDesktopEntryName = _name.toLower();
00253 
00254     m_bAllowAsDefault = desktopGroup.readEntry("AllowDefault", true);
00255     entryMap.remove("AllowDefault");
00256 
00257     // allow plugin users to translate categories without needing a separate key
00258     QMap<QString,QString>::Iterator entry = entryMap.find("X-KDE-PluginInfo-Category");
00259     if (entry != entryMap.end()) {
00260         const QString& key = entry.key();
00261         m_mapProps.insert(key, QVariant(desktopGroup.readEntryUntranslated(key)));
00262         m_mapProps.insert(key + "-Translated", QVariant(*entry));
00263         entryMap.erase(entry);
00264     }
00265 
00266     // Store all additional entries in the property map.
00267     // A QMap<QString,QString> would be easier for this but we can't
00268     // break BC, so we have to store it in m_mapProps.
00269 //  qDebug("Path = %s", entryPath.toLatin1().constData());
00270     QMap<QString,QString>::ConstIterator it = entryMap.constBegin();
00271     for( ; it != entryMap.constEnd();++it) {
00272         const QString key = it.key();
00273         // do not store other translations like Name[fr]; kbuildsycoca will rerun if we change languages anyway
00274         if (!key.contains('[')) {
00275             //kDebug(7012) << "  Key =" << key << " Data =" << *it;
00276             m_mapProps.insert(key, QVariant(*it));
00277         }
00278     }
00279 }
00280 
00281 void KServicePrivate::parseActions(const KDesktopFile *config, KService* q)
00282 {
00283     const QStringList keys = config->readActions();
00284     if (keys.isEmpty())
00285         return;
00286 
00287     QStringList::ConstIterator it = keys.begin();
00288     const QStringList::ConstIterator end = keys.end();
00289     for ( ; it != end; ++it ) {
00290         const QString group = *it;
00291         if (group == "_SEPARATOR_") {
00292             m_actions.append(KServiceAction(group, QString(), QString(), QString(), false));
00293             continue;
00294         }
00295 
00296         if (config->hasActionGroup(group)) {
00297             const KConfigGroup cg = config->actionGroup(group);
00298             if ( !cg.hasKey( "Name" ) || !cg.hasKey( "Exec" ) ) {
00299                 kWarning(7012) << "The action" << group << "in the desktop file" << q->entryPath()
00300                                << "has no Name or no Exec key";
00301             } else {
00302                 m_actions.append(KServiceAction(group,
00303                                                 cg.readEntry("Name"),
00304                                                 cg.readEntry("Icon"),
00305                                                 cg.readEntry("Exec"),
00306                                                 cg.readEntry("NoDisplay", false)));
00307             }
00308         } else {
00309             kWarning(7012) << "The desktop file" << q->entryPath()
00310                            << "references the action" << group << "but doesn't define it";
00311         }
00312     }
00313 }
00314 
00315 void KServicePrivate::load(QDataStream& s)
00316 {
00317     qint8 def, term;
00318     qint8 dst, initpref;
00319     QStringList dummyList; // KDE4: you can reuse this for another QStringList. KDE5: remove
00320 
00321     // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KDE 4.x VERSIONS!
00322     // !! This data structure should remain binary compatible at all times !!
00323     // You may add new fields at the end. Make sure to update the version
00324     // number in ksycoca.h
00325     s >> m_strType >> m_strName >> m_strExec >> m_strIcon
00326       >> term >> m_strTerminalOptions
00327       >> m_strPath >> m_strComment >> dummyList >> def >> m_mapProps
00328       >> m_strLibrary
00329       >> dst
00330       >> m_strDesktopEntryName
00331       >> initpref
00332       >> m_lstKeywords >> m_strGenName
00333       >> categories >> menuId >> m_actions >> m_serviceTypes;
00334 
00335     m_bAllowAsDefault = (bool)def;
00336     m_bTerminal = (bool)term;
00337     m_DBUSStartusType = (KService::DBusStartupType) dst;
00338     m_initialPreference = initpref;
00339 
00340     m_bValid = true;
00341 }
00342 
00343 void KServicePrivate::save(QDataStream& s)
00344 {
00345     KSycocaEntryPrivate::save( s );
00346     qint8 def = m_bAllowAsDefault, initpref = m_initialPreference;
00347     qint8 term = m_bTerminal;
00348     qint8 dst = (qint8) m_DBUSStartusType;
00349 
00350     // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KDE 4.x VERSIONS!
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 << QStringList() << def << m_mapProps
00357       << m_strLibrary
00358       << dst
00359       << m_strDesktopEntryName
00360       << initpref
00361       << m_lstKeywords << m_strGenName
00362       << categories << menuId << m_actions << m_serviceTypes;
00363 }
00364 
00366 
00367 KService::KService( const QString & _name, const QString &_exec, const QString &_icon)
00368     : KSycocaEntry(*new KServicePrivate(QString()))
00369 {
00370     Q_D(KService);
00371     d->m_strType = "Application";
00372     d->m_strName = _name;
00373     d->m_strExec = _exec;
00374     d->m_strIcon = _icon;
00375     d->m_bTerminal = false;
00376     d->m_bAllowAsDefault = true;
00377     d->m_initialPreference = 10;
00378 }
00379 
00380 
00381 KService::KService( const QString & _fullpath )
00382     : KSycocaEntry(*new KServicePrivate(_fullpath))
00383 {
00384     Q_D(KService);
00385 
00386     KDesktopFile config( _fullpath );
00387     d->init(&config, this);
00388 }
00389 
00390 KService::KService( const KDesktopFile *config )
00391     : KSycocaEntry(*new KServicePrivate(config->fileName()))
00392 {
00393     Q_D(KService);
00394 
00395     d->init(config, this);
00396 }
00397 
00398 KService::KService( QDataStream& _str, int _offset )
00399     : KSycocaEntry(*new KServicePrivate(_str, _offset))
00400 {
00401 }
00402 
00403 KService::~KService()
00404 {
00405 }
00406 
00407 bool KService::hasServiceType( const QString& serviceType ) const
00408 {
00409     Q_D(const KService);
00410 
00411     if (!d->m_bValid) return false; // (useless) safety test
00412     const KServiceType::Ptr ptr = KServiceType::serviceType( serviceType );
00413     // share the implementation, at least as long as
00414     // we don't have special code for mimetype inheritance
00415     return hasMimeType( ptr.data() );
00416 }
00417 
00418 bool KService::hasMimeType( const KServiceType* ptr ) const
00419 {
00420     Q_D(const KService);
00421     if (!ptr) return false;
00422     int serviceOffset = offset();
00423     // doesn't seem to work:
00424     //if ( serviceOffset == 0 )
00425     //    serviceOffset = serviceByStorageId( storageId() );
00426     if ( serviceOffset )
00427         return KServiceFactory::self()->hasOffer( ptr->offset(), ptr->serviceOffersOffset(), serviceOffset );
00428 
00429     // fall-back code for services that are NOT from ksycoca
00430     // For each service type we are associated with, if it doesn't
00431     // match then we try its parent service types.
00432     QVector<ServiceTypeAndPreference>::ConstIterator it = d->m_serviceTypes.begin();
00433     for( ; it != d->m_serviceTypes.end(); ++it ) {
00434         const QString& st = (*it).serviceType;
00435         //kDebug(7012) << "    has " << (*it);
00436         if ( st == ptr->name() )
00437             return true;
00438         // also the case of parent servicetypes
00439         KServiceType::Ptr p = KServiceType::serviceType( st );
00440         if ( p && p->inherits( ptr->name() ) )
00441             return true;
00442         // TODO: should we handle inherited mimetypes here?
00443         // KMimeType was in kio when this code was written, this is the only reason it's not done.
00444         // But this should matter only in a very rare case, since most code gets KServices from ksycoca.
00445         // Warning, change hasServiceType if you implement this here (and check kbuildservicefactory).
00446     }
00447     return false;
00448 }
00449 
00450 QVariant KServicePrivate::property( const QString& _name) const
00451 {
00452     return property( _name, QVariant::Invalid);
00453 }
00454 
00455 // Return a string QVariant if string isn't null, and invalid variant otherwise
00456 // (the variant must be invalid if the field isn't in the .desktop file)
00457 // This allows trader queries like "exist Library" to work.
00458 static QVariant makeStringVariant( const QString& string )
00459 {
00460     // Using isEmpty here would be wrong.
00461     // Empty is "specified but empty", null is "not specified" (in the .desktop file)
00462     return string.isNull() ? QVariant() : QVariant( string );
00463 }
00464 
00465 QVariant KService::property( const QString& _name, QVariant::Type t ) const
00466 {
00467     Q_D(const KService);
00468     return d->property(_name, t);
00469 }
00470 
00471 QVariant KServicePrivate::property( const QString& _name, QVariant::Type t ) const
00472 {
00473     if ( _name == "Type" )
00474         return QVariant( m_strType ); // can't be null
00475     else if ( _name == "Name" )
00476         return QVariant( m_strName ); // can't be null
00477     else if ( _name == "Exec" )
00478         return makeStringVariant( m_strExec );
00479     else if ( _name == "Icon" )
00480         return makeStringVariant( m_strIcon );
00481     else if ( _name == "Terminal" )
00482         return QVariant( m_bTerminal );
00483     else if ( _name == "TerminalOptions" )
00484         return makeStringVariant( m_strTerminalOptions );
00485     else if ( _name == "Path" )
00486         return makeStringVariant( m_strPath );
00487     else if ( _name == "Comment" )
00488         return makeStringVariant( m_strComment );
00489     else if ( _name == "GenericName" )
00490         return makeStringVariant( m_strGenName );
00491     else if ( _name == "ServiceTypes" )
00492         return QVariant( serviceTypes() );
00493     else if ( _name == "AllowAsDefault" )
00494         return QVariant( m_bAllowAsDefault );
00495     else if ( _name == "InitialPreference" )
00496         return QVariant( m_initialPreference );
00497     else if ( _name == "Library" )
00498         return makeStringVariant( m_strLibrary );
00499     else if ( _name == "DesktopEntryPath" ) // can't be null
00500         return QVariant( path );
00501     else if ( _name == "DesktopEntryName")
00502         return QVariant( m_strDesktopEntryName ); // can't be null
00503     else if ( _name == "Categories")
00504         return QVariant( categories );
00505     else if ( _name == "Keywords")
00506         return QVariant( m_lstKeywords );
00507 
00508     // Ok we need to convert the property from a QString to its real type.
00509     // Maybe the caller helped us.
00510     if (t == QVariant::Invalid)
00511     {
00512         // No luck, let's ask KServiceTypeFactory what the type of this property
00513         // is supposed to be.
00514         t = KServiceTypeFactory::self()->findPropertyTypeByName(_name);
00515         if (t == QVariant::Invalid)
00516         {
00517             kDebug(7012) << "Request for unknown property '" << _name << "'\n";
00518             return QVariant(); // Unknown property: Invalid variant.
00519         }
00520     }
00521 
00522     QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( _name );
00523     if ( (it == m_mapProps.end()) || (!it->isValid()))
00524     {
00525         //kDebug(7012) << "Property not found " << _name;
00526         return QVariant(); // No property set.
00527     }
00528 
00529     switch(t)
00530     {
00531     case QVariant::String:
00532         return *it; // no conversion necessary
00533     default:
00534         // All others
00535         // For instance properties defined as StringList, like MimeTypes.
00536         // XXX This API is accessible only through a friend declaration.
00537         return KConfigGroup::convertToQVariant(_name.toUtf8().constData(), it->toString().toUtf8(), t);
00538     }
00539 }
00540 
00541 QStringList KServicePrivate::propertyNames() const
00542 {
00543     QStringList res;
00544 
00545     QMap<QString,QVariant>::ConstIterator it = m_mapProps.begin();
00546     for( ; it != m_mapProps.end(); ++it )
00547         res.append( it.key() );
00548 
00549     res.append( "Type" );
00550     res.append( "Name" );
00551     res.append( "Comment" );
00552     res.append( "GenericName" );
00553     res.append( "Icon" );
00554     res.append( "Exec" );
00555     res.append( "Terminal" );
00556     res.append( "TerminalOptions" );
00557     res.append( "Path" );
00558     res.append( "ServiceTypes" );
00559     res.append( "AllowAsDefault" );
00560     res.append( "InitialPreference" );
00561     res.append( "Library" );
00562     res.append( "DesktopEntryPath" );
00563     res.append( "DesktopEntryName" );
00564     res.append( "Keywords" );
00565     res.append( "Categories" );
00566 
00567     return res;
00568 }
00569 
00570 KService::List KService::allServices()
00571 {
00572     return KServiceFactory::self()->allServices();
00573 }
00574 
00575 KService::Ptr KService::serviceByName( const QString& _name )
00576 {
00577     return KServiceFactory::self()->findServiceByName( _name );
00578 }
00579 
00580 KService::Ptr KService::serviceByDesktopPath( const QString& _name )
00581 {
00582     return KServiceFactory::self()->findServiceByDesktopPath( _name );
00583 }
00584 
00585 KService::Ptr KService::serviceByDesktopName( const QString& _name )
00586 {
00587     // Prefer kde4-konsole over kde-konsole, if both are available
00588     QString name = _name.toLower();
00589     KService::Ptr s;
00590     if (!_name.startsWith("kde4-"))
00591         s = KServiceFactory::self()->findServiceByDesktopName( "kde4-" + name );
00592     if (!s)
00593         s = KServiceFactory::self()->findServiceByDesktopName( name );
00594 
00595     return s;
00596 }
00597 
00598 KService::Ptr KService::serviceByMenuId( const QString& _name )
00599 {
00600     return KServiceFactory::self()->findServiceByMenuId( _name );
00601 }
00602 
00603 KService::Ptr KService::serviceByStorageId( const QString& _storageId )
00604 {
00605     KService::Ptr service = KService::serviceByMenuId( _storageId );
00606     if (service)
00607         return service;
00608 
00609     service = KService::serviceByDesktopPath(_storageId);
00610     if (service)
00611         return service;
00612 
00613     if (!QDir::isRelativePath(_storageId) && QFile::exists(_storageId))
00614         return KService::Ptr(new KService(_storageId));
00615 
00616     QString tmp = _storageId;
00617     tmp = tmp.mid(tmp.lastIndexOf('/')+1); // Strip dir
00618 
00619     if (tmp.endsWith(".desktop"))
00620         tmp.truncate(tmp.length()-8);
00621 
00622     if (tmp.endsWith(".kdelnk"))
00623         tmp.truncate(tmp.length()-7);
00624 
00625     service = KService::serviceByDesktopName(tmp);
00626 
00627     return service;
00628 }
00629 
00630 bool KService::substituteUid() const {
00631     QVariant v = property("X-KDE-SubstituteUID", QVariant::Bool);
00632     return v.isValid() && v.toBool();
00633 }
00634 
00635 QString KService::username() const {
00636     // See also KDesktopFile::tryExec()
00637     QString user;
00638     QVariant v = property("X-KDE-Username", QVariant::String);
00639     user = v.isValid() ? v.toString() : QString();
00640     if (user.isEmpty())
00641         user = QString::fromLocal8Bit(qgetenv("ADMIN_ACCOUNT"));
00642     if (user.isEmpty())
00643         user = "root";
00644     return user;
00645 }
00646 
00647 bool KService::noDisplay() const {
00648     if ( qvariant_cast<bool>(property("NoDisplay", QVariant::Bool)) )
00649         return true;
00650 
00651     Q_D(const KService);
00652 
00653     QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find( "OnlyShowIn" );
00654     if ( (it != d->m_mapProps.end()) && (it->isValid()))
00655     {
00656         QString aValue = it->toString();
00657         QStringList aList = aValue.split(';');
00658         if (!aList.contains("KDE"))
00659             return true;
00660     }
00661 
00662     it = d->m_mapProps.find( "NotShowIn" );
00663     if ( (it != d->m_mapProps.end()) && (it->isValid()))
00664     {
00665         QString aValue = it->toString();
00666         QStringList aList = aValue.split(';');
00667         if (aList.contains("KDE"))
00668             return true;
00669     }
00670 
00671     if (!KAuthorized::authorizeControlModule( storageId() ) )
00672         return true;
00673 
00674     return false;
00675 }
00676 
00677 QString KService::untranslatedGenericName() const {
00678     QVariant v = property("UntranslatedGenericName", QVariant::String);
00679     return v.isValid() ? v.toString() : QString();
00680 }
00681 
00682 QString KService::parentApp() const {
00683     Q_D(const KService);
00684     QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find( "X-KDE-ParentApp" );
00685     if ( (it == d->m_mapProps.end()) || (!it->isValid()))
00686     {
00687         return QString();
00688     }
00689 
00690     return it->toString();
00691 }
00692 
00693 QString KService::pluginKeyword() const
00694 {
00695     Q_D(const KService);
00696     QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find("X-KDE-PluginKeyword");
00697     if ((it == d->m_mapProps.end()) || (!it->isValid())) {
00698         return QString();
00699     }
00700 
00701     return it->toString();
00702 }
00703 
00704 QString KService::docPath() const
00705 {
00706     Q_D(const KService);
00707     QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find("X-DocPath");
00708     if ((it == d->m_mapProps.end()) || (!it->isValid())) {
00709         it = d->m_mapProps.find("DocPath");
00710         if ((it == d->m_mapProps.end()) || (!it->isValid())) {
00711             return QString();
00712         }
00713     }
00714 
00715     return it->toString();
00716 }
00717 
00718 bool KService::allowMultipleFiles() const {
00719     Q_D(const KService);
00720     // Can we pass multiple files on the command line or do we have to start the application for every single file ?
00721     return (d->m_strExec.contains( "%F" ) || d->m_strExec.contains( "%U" ) ||
00722             d->m_strExec.contains( "%N" ) || d->m_strExec.contains( "%D" ));
00723 }
00724 
00725 QStringList KService::categories() const
00726 {
00727     Q_D(const KService);
00728     return d->categories;
00729 }
00730 
00731 QString KService::menuId() const
00732 {
00733     Q_D(const KService);
00734     return d->menuId;
00735 }
00736 
00737 void KService::setMenuId(const QString &_menuId)
00738 {
00739     Q_D(KService);
00740     d->menuId = _menuId;
00741 }
00742 
00743 QString KService::storageId() const
00744 {
00745     Q_D(const KService);
00746     return d->storageId();
00747 }
00748 
00749 QString KService::locateLocal() const
00750 {
00751     Q_D(const KService);
00752     if (d->menuId.isEmpty() || entryPath().startsWith(".hidden") ||
00753         (QDir::isRelativePath(entryPath()) && d->categories.isEmpty()))
00754         return KDesktopFile::locateLocal(entryPath());
00755 
00756     return KStandardDirs::locateLocal("xdgdata-apps", d->menuId);
00757 }
00758 
00759 QString KService::newServicePath(bool showInMenu, const QString &suggestedName,
00760                                  QString *menuId, const QStringList *reservedMenuIds)
00761 {
00762     Q_UNUSED(showInMenu); // TODO KDE5: remove argument
00763 
00764     QString base = suggestedName;
00765     QString result;
00766     for(int i = 1; true; i++)
00767     {
00768         if (i == 1)
00769             result = base + ".desktop";
00770         else
00771             result = base + QString("-%1.desktop").arg(i);
00772 
00773         if (reservedMenuIds && reservedMenuIds->contains(result))
00774             continue;
00775 
00776         // Lookup service by menu-id
00777         KService::Ptr s = serviceByMenuId(result);
00778         if (s)
00779             continue;
00780 
00781         if (!KStandardDirs::locate("xdgdata-apps", result).isEmpty())
00782             continue;
00783 
00784         break;
00785     }
00786     if (menuId)
00787         *menuId = result;
00788 
00789     return KStandardDirs::locateLocal("xdgdata-apps", result);
00790 }
00791 
00792 bool KService::isApplication() const
00793 {
00794     Q_D(const KService);
00795     return d->m_strType == "Application";
00796 }
00797 
00798 QString KService::type() const
00799 {
00800     Q_D(const KService);
00801     return d->m_strType;
00802 }
00803 
00804 QString KService::exec() const
00805 {
00806     Q_D(const KService);
00807     if (d->m_strType == "Application" && d->m_strExec.isEmpty())
00808     {
00809         kWarning(7012) << "The desktop entry file " << entryPath()
00810                        << " has Type=" << d->m_strType << " but has no Exec field." << endl;
00811     }
00812     return d->m_strExec;
00813 }
00814 
00815 QString KService::library() const
00816 {
00817     Q_D(const KService);
00818     return d->m_strLibrary;
00819 }
00820 
00821 QString KService::icon() const
00822 {
00823     Q_D(const KService);
00824     return d->m_strIcon;
00825 }
00826 
00827 QString KService::terminalOptions() const
00828 {
00829     Q_D(const KService);
00830     return d->m_strTerminalOptions;
00831 }
00832 
00833 bool KService::terminal() const
00834 {
00835     Q_D(const KService);
00836     return d->m_bTerminal;
00837 }
00838 
00839 // KDE4: remove and port code to entryPath?
00840 QString KService::desktopEntryPath() const
00841 {
00842     return entryPath();
00843 }
00844 
00845 QString KService::desktopEntryName() const
00846 {
00847     Q_D(const KService);
00848     return d->m_strDesktopEntryName;
00849 }
00850 
00851 KService::DBusStartupType KService::dbusStartupType() const
00852 {
00853     Q_D(const KService);
00854     return d->m_DBUSStartusType;
00855 }
00856 
00857 QString KService::path() const
00858 {
00859     Q_D(const KService);
00860     return d->m_strPath;
00861 }
00862 
00863 QString KService::comment() const
00864 {
00865     Q_D(const KService);
00866     return d->m_strComment;
00867 }
00868 
00869 QString KService::genericName() const
00870 {
00871     Q_D(const KService);
00872     return d->m_strGenName;
00873 }
00874 
00875 QStringList KService::keywords() const
00876 {
00877     Q_D(const KService);
00878     return d->m_lstKeywords;
00879 }
00880 
00881 QStringList KServicePrivate::serviceTypes() const
00882 {
00883     QStringList ret;
00884     QVector<KService::ServiceTypeAndPreference>::const_iterator it = m_serviceTypes.begin();
00885     for ( ; it < m_serviceTypes.end(); ++it ) {
00886         Q_ASSERT(!(*it).serviceType.isEmpty());
00887         ret.append((*it).serviceType);
00888     }
00889     return ret;
00890 }
00891 
00892 QStringList KService::serviceTypes() const
00893 {
00894     Q_D(const KService);
00895     return d->serviceTypes();
00896 }
00897 
00898 bool KService::allowAsDefault() const
00899 {
00900     Q_D(const KService);
00901     return d->m_bAllowAsDefault;
00902 }
00903 
00904 int KService::initialPreference() const
00905 {
00906     Q_D(const KService);
00907     return d->m_initialPreference;
00908 }
00909 
00910 void KService::setTerminal(bool b)
00911 {
00912     Q_D(KService);
00913     d->m_bTerminal = b;
00914 }
00915 
00916 void KService::setTerminalOptions(const QString &options)
00917 {
00918     Q_D(KService);
00919     d->m_strTerminalOptions = options;
00920 }
00921 
00922 QVector<KService::ServiceTypeAndPreference> & KService::_k_accessServiceTypes()
00923 {
00924     Q_D(KService);
00925     return d->m_serviceTypes;
00926 }
00927 
00928 QList<KServiceAction> KService::actions() const
00929 {
00930     Q_D(const KService);
00931     return d->m_actions;
00932 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal