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

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal