• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.4 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • services
kservice.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  * Copyright (C) 1999 - 2001 Waldo Bastian <bastian@kde.org>
3  * Copyright (C) 1999 - 2005 David Faure <faure@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License version 2 as published by the Free Software Foundation;
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "kservice.h"
21 #include "kservice_p.h"
22 #include "kmimetypefactory.h"
23 #include "kmimetyperepository_p.h"
24 
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 
28 #include <stddef.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 
32 #include <QtCore/QCharRef>
33 #include <QtCore/QFile>
34 #include <QtCore/QDir>
35 #include <QtCore/QMap>
36 
37 #include <kauthorized.h>
38 #include <kdebug.h>
39 #include <kdesktopfile.h>
40 #include <kglobal.h>
41 #include <kconfiggroup.h>
42 #include <kstandarddirs.h>
43 
44 #include "kservicefactory.h"
45 #include "kservicetypefactory.h"
46 
47 int servicesDebugArea() {
48  static int s_area = KDebug::registerArea("kdecore (services)");
49  return s_area;
50 }
51 
52 QDataStream &operator<<(QDataStream &s, const KService::ServiceTypeAndPreference &st)
53 {
54  s << st.preference << st.serviceType;
55  return s;
56 }
57 QDataStream &operator>>(QDataStream &s, KService::ServiceTypeAndPreference &st)
58 {
59  s >> st.preference >> st.serviceType;
60  return s;
61 }
62 
63 void KServicePrivate::init( const KDesktopFile *config, KService* q )
64 {
65  const QString entryPath = q->entryPath();
66  bool absPath = !QDir::isRelativePath(entryPath);
67 
68  // TODO: it makes sense to have a KConstConfigGroup I guess
69  const KConfigGroup desktopGroup = const_cast<KDesktopFile*>(config)->desktopGroup();
70  QMap<QString, QString> entryMap = desktopGroup.entryMap();
71 
72  entryMap.remove(QLatin1String("Encoding")); // reserved as part of Desktop Entry Standard
73  entryMap.remove(QLatin1String("Version")); // reserved as part of Desktop Entry Standard
74 
75  q->setDeleted( desktopGroup.readEntry("Hidden", false) );
76  entryMap.remove(QLatin1String("Hidden"));
77  if ( q->isDeleted() ) {
78  m_bValid = false;
79  return;
80  }
81 
82  m_strName = config->readName();
83  entryMap.remove(QLatin1String("Name"));
84  if ( m_strName.isEmpty() )
85  {
86  // Try to make up a name.
87  m_strName = entryPath;
88  int i = m_strName.lastIndexOf(QLatin1Char('/'));
89  m_strName = m_strName.mid(i+1);
90  i = m_strName.lastIndexOf(QLatin1Char('.'));
91  if (i != -1)
92  m_strName = m_strName.left(i);
93  }
94 
95  m_strType = config->readType();
96  entryMap.remove(QLatin1String("Type"));
97  if ( m_strType.isEmpty() )
98  {
99  /*kWarning(servicesDebugArea()) << "The desktop entry file " << entryPath
100  << " has no Type=... entry."
101  << " It should be \"Application\" or \"Service\"" << endl;
102  m_bValid = false;
103  return;*/
104  m_strType = QString::fromLatin1("Application");
105  } else if (m_strType != QLatin1String("Application") && m_strType != QLatin1String("Service")) {
106  kWarning(servicesDebugArea()) << "The desktop entry file " << entryPath
107  << " has Type=" << m_strType
108  << " instead of \"Application\" or \"Service\"" << endl;
109  m_bValid = false;
110  return;
111  }
112 
113  // NOT readPathEntry, it is not XDG-compliant. Path entries written by
114  // KDE4 will be still treated as such, though.
115  m_strExec = desktopGroup.readEntry( "Exec", QString() );
116  entryMap.remove(QLatin1String("Exec"));
117 
118  if (m_strType == QLatin1String("Application")) {
119  // It's an application? Should have an Exec line then, otherwise we can't run it
120  if (m_strExec.isEmpty()) {
121  kWarning(servicesDebugArea()) << "The desktop entry file " << entryPath
122  << " has Type=" << m_strType
123  << " but no Exec line" << endl;
124  m_bValid = false;
125  return;
126  }
127  }
128 
129  // In case Try Exec is set, check if the application is available
130  if (!config->tryExec()) {
131  q->setDeleted( true );
132  m_bValid = false;
133  return;
134  }
135 
136  const QByteArray resource = config->resource();
137 
138  if ( (m_strType == QLatin1String("Application")) &&
139  (!resource.isEmpty()) &&
140  (resource != "apps") &&
141  !absPath)
142  {
143  kWarning(servicesDebugArea()) << "The desktop entry file " << entryPath
144  << " has Type=" << m_strType << " but is located under \"" << resource
145  << "\" instead of \"apps\"" << endl;
146  m_bValid = false;
147  return;
148  }
149 
150  if ( (m_strType == QLatin1String("Service")) &&
151  (!resource.isEmpty()) &&
152  (resource != "services") &&
153  !absPath)
154  {
155  kWarning(servicesDebugArea()) << "The desktop entry file " << entryPath
156  << " has Type=" << m_strType << " but is located under \"" << resource
157  << "\" instead of \"services\"";
158  m_bValid = false;
159  return;
160  }
161 
162  QString _name = entryPath;
163  int pos = _name.lastIndexOf(QLatin1Char('/'));
164  if (pos != -1)
165  _name = _name.mid(pos+1);
166  pos = _name.indexOf(QLatin1Char('.'));
167  if (pos != -1)
168  _name = _name.left(pos);
169 
170  m_strIcon = config->readIcon();
171  entryMap.remove(QLatin1String("Icon"));
172  m_bTerminal = desktopGroup.readEntry( "Terminal", false); // should be a property IMHO
173  entryMap.remove(QLatin1String("Terminal"));
174  m_strTerminalOptions = desktopGroup.readEntry( "TerminalOptions" ); // should be a property IMHO
175  entryMap.remove(QLatin1String("TerminalOptions"));
176  m_strPath = config->readPath();
177  entryMap.remove(QLatin1String("Path"));
178  m_strComment = config->readComment();
179  entryMap.remove(QLatin1String("Comment"));
180  m_strGenName = config->readGenericName();
181  entryMap.remove(QLatin1String("GenericName"));
182  QString _untranslatedGenericName = desktopGroup.readEntryUntranslated( "GenericName" );
183  if (!_untranslatedGenericName.isEmpty())
184  entryMap.insert(QLatin1String("UntranslatedGenericName"), _untranslatedGenericName);
185 
186  m_lstKeywords = desktopGroup.readEntry("Keywords", QStringList());
187  entryMap.remove(QLatin1String("Keywords"));
188  m_lstKeywords += desktopGroup.readEntry("X-KDE-Keywords", QStringList());
189  entryMap.remove(QLatin1String("X-KDE-Keywords"));
190  categories = desktopGroup.readXdgListEntry("Categories");
191  entryMap.remove(QLatin1String("Categories"));
192  // TODO KDE5: only care for X-KDE-Library in Type=Service desktop files
193  // This will prevent people defining a part and an app in the same desktop file
194  // which makes user-preference handling difficult.
195  m_strLibrary = desktopGroup.readEntry( "X-KDE-Library" );
196  entryMap.remove(QLatin1String("X-KDE-Library"));
197  if (!m_strLibrary.isEmpty() && m_strType == QLatin1String("Application")) {
198  kWarning(servicesDebugArea()) << "The desktop entry file" << entryPath
199  << "has Type=" << m_strType
200  << "but also has a X-KDE-Library key. This works for now,"
201  " but makes user-preference handling difficult, so support for this might"
202  " be removed at some point. Consider splitting it into two desktop files.";
203  }
204 
205  QStringList lstServiceTypes = desktopGroup.readEntry( "ServiceTypes", QStringList() );
206  entryMap.remove(QLatin1String("ServiceTypes"));
207  lstServiceTypes += desktopGroup.readEntry( "X-KDE-ServiceTypes", QStringList() );
208  entryMap.remove(QLatin1String("X-KDE-ServiceTypes"));
209  lstServiceTypes += desktopGroup.readXdgListEntry( "MimeType" );
210  entryMap.remove(QLatin1String("MimeType"));
211 
212  if ( m_strType == QLatin1String("Application") && !lstServiceTypes.contains(QLatin1String("Application")) )
213  // Applications implement the service type "Application" ;-)
214  lstServiceTypes += QString::fromLatin1("Application");
215 
216  m_initialPreference = desktopGroup.readEntry( "InitialPreference", 1 );
217  entryMap.remove(QLatin1String("InitialPreference"));
218 
219  // Assign the "initial preference" to each mimetype/servicetype
220  // (and to set such preferences in memory from kbuildsycoca)
221  m_serviceTypes.reserve(lstServiceTypes.size());
222  QListIterator<QString> st_it(lstServiceTypes);
223  while ( st_it.hasNext() ) {
224  const QString st = st_it.next();
225  if (st.isEmpty()) {
226  kWarning(servicesDebugArea()) << "The desktop entry file" << entryPath
227  << "has an empty mimetype!";
228  continue;
229  }
230  int initialPreference = m_initialPreference;
231  if ( st_it.hasNext() ) {
232  // TODO better syntax - separate group with mimetype=number entries?
233  bool isNumber;
234  const int val = st_it.peekNext().toInt(&isNumber);
235  if (isNumber) {
236  initialPreference = val;
237  st_it.next();
238  }
239  }
240  m_serviceTypes.push_back(KService::ServiceTypeAndPreference(initialPreference, st));
241  }
242 
243  if (entryMap.contains(QLatin1String("Actions"))) {
244  parseActions(config, q);
245  }
246 
247  QString dbusStartupType = desktopGroup.readEntry("X-DBUS-StartupType").toLower();
248  entryMap.remove(QLatin1String("X-DBUS-StartupType"));
249  if (dbusStartupType == QLatin1String("unique"))
250  m_DBUSStartusType = KService::DBusUnique;
251  else if (dbusStartupType == QLatin1String("multi"))
252  m_DBUSStartusType = KService::DBusMulti;
253  else if (dbusStartupType == QLatin1String("wait"))
254  m_DBUSStartusType = KService::DBusWait;
255  else
256  m_DBUSStartusType = KService::DBusNone;
257 
258  m_strDesktopEntryName = _name.toLower();
259 
260  m_bAllowAsDefault = desktopGroup.readEntry("AllowDefault", true);
261  entryMap.remove(QLatin1String("AllowDefault"));
262 
263  // allow plugin users to translate categories without needing a separate key
264  QMap<QString,QString>::Iterator entry = entryMap.find(QString::fromLatin1("X-KDE-PluginInfo-Category"));
265  if (entry != entryMap.end()) {
266  const QString& key = entry.key();
267  m_mapProps.insert(key, QVariant(desktopGroup.readEntryUntranslated(key)));
268  m_mapProps.insert(key + QLatin1String("-Translated"), QVariant(*entry));
269  entryMap.erase(entry);
270  }
271 
272  // Store all additional entries in the property map.
273  // A QMap<QString,QString> would be easier for this but we can't
274  // break BC, so we have to store it in m_mapProps.
275 // qDebug("Path = %s", entryPath.toLatin1().constData());
276  QMap<QString,QString>::ConstIterator it = entryMap.constBegin();
277  for( ; it != entryMap.constEnd();++it) {
278  const QString key = it.key();
279  // do not store other translations like Name[fr]; kbuildsycoca will rerun if we change languages anyway
280  if (!key.contains(QLatin1Char('['))) {
281  //kDebug(servicesDebugArea()) << " Key =" << key << " Data =" << *it;
282  m_mapProps.insert(key, QVariant(*it));
283  }
284  }
285 }
286 
287 void KServicePrivate::parseActions(const KDesktopFile *config, KService* q)
288 {
289  const QStringList keys = config->readActions();
290  if (keys.isEmpty())
291  return;
292 
293  QStringList::ConstIterator it = keys.begin();
294  const QStringList::ConstIterator end = keys.end();
295  for ( ; it != end; ++it ) {
296  const QString group = *it;
297  if (group == QLatin1String("_SEPARATOR_")) {
298  m_actions.append(KServiceAction(group, QString(), QString(), QString(), false));
299  continue;
300  }
301 
302  if (config->hasActionGroup(group)) {
303  const KConfigGroup cg = config->actionGroup(group);
304  if ( !cg.hasKey( "Name" ) || !cg.hasKey( "Exec" ) ) {
305  kWarning(servicesDebugArea()) << "The action" << group << "in the desktop file" << q->entryPath()
306  << "has no Name or no Exec key";
307  } else {
308  m_actions.append(KServiceAction(group,
309  cg.readEntry("Name"),
310  cg.readEntry("Icon"),
311  cg.readEntry("Exec"),
312  cg.readEntry("NoDisplay", false)));
313  }
314  } else {
315  kWarning(servicesDebugArea()) << "The desktop file" << q->entryPath()
316  << "references the action" << group << "but doesn't define it";
317  }
318  }
319 }
320 
321 void KServicePrivate::load(QDataStream& s)
322 {
323  qint8 def, term;
324  qint8 dst, initpref;
325  QStringList dummyList; // KDE4: you can reuse this for another QStringList. KDE5: remove
326 
327  // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KDE 4.x VERSIONS!
328  // !! This data structure should remain binary compatible at all times !!
329  // You may add new fields at the end. Make sure to update the version
330  // number in ksycoca.h
331  s >> m_strType >> m_strName >> m_strExec >> m_strIcon
332  >> term >> m_strTerminalOptions
333  >> m_strPath >> m_strComment >> dummyList >> def >> m_mapProps
334  >> m_strLibrary
335  >> dst
336  >> m_strDesktopEntryName
337  >> initpref
338  >> m_lstKeywords >> m_strGenName
339  >> categories >> menuId >> m_actions >> m_serviceTypes;
340 
341  m_bAllowAsDefault = (bool)def;
342  m_bTerminal = (bool)term;
343  m_DBUSStartusType = (KService::DBusStartupType) dst;
344  m_initialPreference = initpref;
345 
346  m_bValid = true;
347 }
348 
349 void KServicePrivate::save(QDataStream& s)
350 {
351  KSycocaEntryPrivate::save( s );
352  qint8 def = m_bAllowAsDefault, initpref = m_initialPreference;
353  qint8 term = m_bTerminal;
354  qint8 dst = (qint8) m_DBUSStartusType;
355 
356  // WARNING: THIS NEEDS TO REMAIN COMPATIBLE WITH PREVIOUS KDE 4.x VERSIONS!
357  // !! This data structure should remain binary compatible at all times !!
358  // You may add new fields at the end. Make sure to update the version
359  // number in ksycoca.h
360  s << m_strType << m_strName << m_strExec << m_strIcon
361  << term << m_strTerminalOptions
362  << m_strPath << m_strComment << QStringList() << def << m_mapProps
363  << m_strLibrary
364  << dst
365  << m_strDesktopEntryName
366  << initpref
367  << m_lstKeywords << m_strGenName
368  << categories << menuId << m_actions << m_serviceTypes;
369 }
370 
372 
373 KService::KService( const QString & _name, const QString &_exec, const QString &_icon)
374  : KSycocaEntry(*new KServicePrivate(QString()))
375 {
376  Q_D(KService);
377  d->m_strType = QString::fromLatin1("Application");
378  d->m_strName = _name;
379  d->m_strExec = _exec;
380  d->m_strIcon = _icon;
381  d->m_bTerminal = false;
382  d->m_bAllowAsDefault = true;
383  d->m_initialPreference = 10;
384 }
385 
386 
387 KService::KService( const QString & _fullpath )
388  : KSycocaEntry(*new KServicePrivate(_fullpath))
389 {
390  Q_D(KService);
391 
392  KDesktopFile config( _fullpath );
393  d->init(&config, this);
394 }
395 
396 KService::KService( const KDesktopFile *config )
397  : KSycocaEntry(*new KServicePrivate(config->fileName()))
398 {
399  Q_D(KService);
400 
401  d->init(config, this);
402 }
403 
404 KService::KService( QDataStream& _str, int _offset )
405  : KSycocaEntry(*new KServicePrivate(_str, _offset))
406 {
407 }
408 
409 KService::~KService()
410 {
411 }
412 
413 bool KService::hasServiceType( const QString& serviceType ) const
414 {
415  Q_D(const KService);
416 
417  if (!d->m_bValid) return false; // (useless) safety test
418  const KServiceType::Ptr ptr = KServiceType::serviceType( serviceType );
419  const int serviceOffset = offset();
420  // doesn't seem to work:
421  //if ( serviceOffset == 0 )
422  // serviceOffset = serviceByStorageId( storageId() );
423  if ( serviceOffset )
424  return KServiceFactory::self()->hasOffer( ptr->offset(), ptr->serviceOffersOffset(), serviceOffset );
425 
426  // fall-back code for services that are NOT from ksycoca
427  // For each service type we are associated with, if it doesn't
428  // match then we try its parent service types.
429  QVector<ServiceTypeAndPreference>::ConstIterator it = d->m_serviceTypes.begin();
430  for( ; it != d->m_serviceTypes.end(); ++it ) {
431  const QString& st = (*it).serviceType;
432  //kDebug(servicesDebugArea()) << " has " << (*it);
433  if ( st == ptr->name() )
434  return true;
435  // also the case of parent servicetypes
436  KServiceType::Ptr p = KServiceType::serviceType( st );
437  if ( p && p->inherits( ptr->name() ) )
438  return true;
439  }
440  return false;
441 }
442 
443 #ifndef KDE_NO_DEPRECATED
444 bool KService::hasMimeType( const KServiceType* ptr ) const
445 {
446  if (!ptr) return false;
447 
448  return hasMimeType(ptr->name());
449 }
450 #endif
451 
452 bool KService::hasMimeType(const QString& mimeType) const
453 {
454  Q_D(const KService);
455  const QString mime = KMimeTypeRepository::self()->canonicalName(mimeType);
456  int serviceOffset = offset();
457  if ( serviceOffset ) {
458  KMimeTypeFactory *factory = KMimeTypeFactory::self();
459  const int mimeOffset = factory->entryOffset(mime);
460  const int serviceOffersOffset = factory->serviceOffersOffset(mime);
461  if (serviceOffersOffset == -1)
462  return false;
463  return KServiceFactory::self()->hasOffer(mimeOffset, serviceOffersOffset, serviceOffset);
464  }
465 
466  // fall-back code for services that are NOT from ksycoca
467  QVector<ServiceTypeAndPreference>::ConstIterator it = d->m_serviceTypes.begin();
468  for( ; it != d->m_serviceTypes.end(); ++it ) {
469  const QString& st = (*it).serviceType;
470  //kDebug(servicesDebugArea()) << " has " << (*it);
471  if ( st == mime )
472  return true;
473  // TODO: should we handle inherited mimetypes here?
474  // KMimeType was in kio when this code was written, this is the only reason it's not done.
475  // But this should matter only in a very rare case, since most code gets KServices from ksycoca.
476  // Warning, change hasServiceType if you implement this here (and check kbuildservicefactory).
477  }
478  return false;
479 }
480 
481 QVariant KServicePrivate::property( const QString& _name) const
482 {
483  return property( _name, QVariant::Invalid);
484 }
485 
486 // Return a string QVariant if string isn't null, and invalid variant otherwise
487 // (the variant must be invalid if the field isn't in the .desktop file)
488 // This allows trader queries like "exist Library" to work.
489 static QVariant makeStringVariant( const QString& string )
490 {
491  // Using isEmpty here would be wrong.
492  // Empty is "specified but empty", null is "not specified" (in the .desktop file)
493  return string.isNull() ? QVariant() : QVariant( string );
494 }
495 
496 QVariant KService::property( const QString& _name, QVariant::Type t ) const
497 {
498  Q_D(const KService);
499  return d->property(_name, t);
500 }
501 
502 QVariant KServicePrivate::property( const QString& _name, QVariant::Type t ) const
503 {
504  if ( _name == QLatin1String("Type") )
505  return QVariant( m_strType ); // can't be null
506  else if ( _name == QLatin1String("Name") )
507  return QVariant( m_strName ); // can't be null
508  else if ( _name == QLatin1String("Exec") )
509  return makeStringVariant( m_strExec );
510  else if ( _name == QLatin1String("Icon") )
511  return makeStringVariant( m_strIcon );
512  else if ( _name == QLatin1String("Terminal") )
513  return QVariant( m_bTerminal );
514  else if ( _name == QLatin1String("TerminalOptions") )
515  return makeStringVariant( m_strTerminalOptions );
516  else if ( _name == QLatin1String("Path") )
517  return makeStringVariant( m_strPath );
518  else if ( _name == QLatin1String("Comment") )
519  return makeStringVariant( m_strComment );
520  else if ( _name == QLatin1String("GenericName") )
521  return makeStringVariant( m_strGenName );
522  else if ( _name == QLatin1String("ServiceTypes") )
523  return QVariant( serviceTypes() );
524  else if ( _name == QLatin1String("AllowAsDefault") )
525  return QVariant( m_bAllowAsDefault );
526  else if ( _name == QLatin1String("InitialPreference") )
527  return QVariant( m_initialPreference );
528  else if ( _name == QLatin1String("Library") )
529  return makeStringVariant( m_strLibrary );
530  else if ( _name == QLatin1String("DesktopEntryPath") ) // can't be null
531  return QVariant( path );
532  else if ( _name == QLatin1String("DesktopEntryName"))
533  return QVariant( m_strDesktopEntryName ); // can't be null
534  else if ( _name == QLatin1String("Categories"))
535  return QVariant( categories );
536  else if ( _name == QLatin1String("Keywords"))
537  return QVariant( m_lstKeywords );
538 
539  // Ok we need to convert the property from a QString to its real type.
540  // Maybe the caller helped us.
541  if (t == QVariant::Invalid)
542  {
543  // No luck, let's ask KServiceTypeFactory what the type of this property
544  // is supposed to be.
545  t = KServiceTypeFactory::self()->findPropertyTypeByName(_name);
546  if (t == QVariant::Invalid)
547  {
548  kDebug(servicesDebugArea()) << "Request for unknown property '" << _name << "'\n";
549  return QVariant(); // Unknown property: Invalid variant.
550  }
551  }
552 
553  QMap<QString,QVariant>::ConstIterator it = m_mapProps.find( _name );
554  if ( (it == m_mapProps.end()) || (!it->isValid()))
555  {
556  //kDebug(servicesDebugArea()) << "Property not found " << _name;
557  return QVariant(); // No property set.
558  }
559 
560  switch(t)
561  {
562  case QVariant::String:
563  return *it; // no conversion necessary
564  default:
565  // All others
566  // For instance properties defined as StringList, like MimeTypes.
567  // XXX This API is accessible only through a friend declaration.
568  return KConfigGroup::convertToQVariant(_name.toUtf8().constData(), it->toString().toUtf8(), t);
569  }
570 }
571 
572 QStringList KServicePrivate::propertyNames() const
573 {
574  QStringList res;
575 
576  QMap<QString,QVariant>::ConstIterator it = m_mapProps.begin();
577  for( ; it != m_mapProps.end(); ++it )
578  res.append( it.key() );
579 
580  res.append( QString::fromLatin1("Type") );
581  res.append( QString::fromLatin1("Name") );
582  res.append( QString::fromLatin1("Comment") );
583  res.append( QString::fromLatin1("GenericName") );
584  res.append( QString::fromLatin1("Icon") );
585  res.append( QString::fromLatin1("Exec") );
586  res.append( QString::fromLatin1("Terminal") );
587  res.append( QString::fromLatin1("TerminalOptions") );
588  res.append( QString::fromLatin1("Path") );
589  res.append( QString::fromLatin1("ServiceTypes") );
590  res.append( QString::fromLatin1("AllowAsDefault") );
591  res.append( QString::fromLatin1("InitialPreference") );
592  res.append( QString::fromLatin1("Library") );
593  res.append( QString::fromLatin1("DesktopEntryPath") );
594  res.append( QString::fromLatin1("DesktopEntryName") );
595  res.append( QString::fromLatin1("Keywords") );
596  res.append( QString::fromLatin1("Categories") );
597 
598  return res;
599 }
600 
601 KService::List KService::allServices()
602 {
603  return KServiceFactory::self()->allServices();
604 }
605 
606 #ifndef KDE_NO_DEPRECATED
607 KService::Ptr KService::serviceByName( const QString& _name )
608 {
609  return KServiceFactory::self()->findServiceByName( _name );
610 }
611 #endif
612 
613 KService::Ptr KService::serviceByDesktopPath( const QString& _name )
614 {
615  return KServiceFactory::self()->findServiceByDesktopPath( _name );
616 }
617 
618 KService::Ptr KService::serviceByDesktopName( const QString& _name )
619 {
620  // Prefer kde4-konsole over kde-konsole, if both are available
621  QString name = _name.toLower();
622  KService::Ptr s;
623  if (!_name.startsWith(QLatin1String("kde4-")))
624  s = KServiceFactory::self()->findServiceByDesktopName(QString::fromLatin1("kde4-") + name);
625  if (!s)
626  s = KServiceFactory::self()->findServiceByDesktopName( name );
627 
628  return s;
629 }
630 
631 KService::Ptr KService::serviceByMenuId( const QString& _name )
632 {
633  return KServiceFactory::self()->findServiceByMenuId( _name );
634 }
635 
636 KService::Ptr KService::serviceByStorageId( const QString& _storageId )
637 {
638  KService::Ptr service = KService::serviceByMenuId( _storageId );
639  if (service)
640  return service;
641 
642  service = KService::serviceByDesktopPath(_storageId);
643  if (service)
644  return service;
645 
646  if (!QDir::isRelativePath(_storageId) && QFile::exists(_storageId))
647  return KService::Ptr(new KService(_storageId));
648 
649  QString tmp = _storageId;
650  tmp = tmp.mid(tmp.lastIndexOf(QLatin1Char('/'))+1); // Strip dir
651 
652  if (tmp.endsWith(QLatin1String(".desktop")))
653  tmp.truncate(tmp.length()-8);
654 
655  if (tmp.endsWith(QLatin1String(".kdelnk")))
656  tmp.truncate(tmp.length()-7);
657 
658  service = KService::serviceByDesktopName(tmp);
659 
660  return service;
661 }
662 
663 bool KService::substituteUid() const {
664  QVariant v = property(QLatin1String("X-KDE-SubstituteUID"), QVariant::Bool);
665  return v.isValid() && v.toBool();
666 }
667 
668 QString KService::username() const {
669  // See also KDesktopFile::tryExec()
670  QString user;
671  QVariant v = property(QLatin1String("X-KDE-Username"), QVariant::String);
672  user = v.isValid() ? v.toString() : QString();
673  if (user.isEmpty())
674  user = QString::fromLocal8Bit(qgetenv("ADMIN_ACCOUNT"));
675  if (user.isEmpty())
676  user = QString::fromLatin1("root");
677  return user;
678 }
679 
680 bool KService::showInKDE() const
681 {
682  Q_D(const KService);
683 
684  QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find( QString::fromLatin1("OnlyShowIn") );
685  if ( (it != d->m_mapProps.end()) && (it->isValid()))
686  {
687  const QStringList aList = it->toString().split(QLatin1Char(';'));
688  if (!aList.contains(QString::fromLatin1("KDE")))
689  return false;
690  }
691 
692  it = d->m_mapProps.find( QString::fromLatin1("NotShowIn") );
693  if ( (it != d->m_mapProps.end()) && (it->isValid()))
694  {
695  const QStringList aList = it->toString().split(QLatin1Char(';'));
696  if (aList.contains(QString::fromLatin1("KDE")))
697  return false;
698  }
699  return true;
700 }
701 
702 bool KService::noDisplay() const {
703  if ( qvariant_cast<bool>(property(QString::fromLatin1("NoDisplay"), QVariant::Bool)) )
704  return true;
705 
706  if (!showInKDE())
707  return true;
708 
709  if (!KAuthorized::authorizeControlModule( storageId() ) )
710  return true;
711 
712  return false;
713 }
714 
715 QString KService::untranslatedGenericName() const {
716  QVariant v = property(QString::fromLatin1("UntranslatedGenericName"), QVariant::String);
717  return v.isValid() ? v.toString() : QString();
718 }
719 
720 QString KService::parentApp() const {
721  Q_D(const KService);
722  QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find(QLatin1String("X-KDE-ParentApp"));
723  if ( (it == d->m_mapProps.end()) || (!it->isValid()))
724  {
725  return QString();
726  }
727 
728  return it->toString();
729 }
730 
731 QString KService::pluginKeyword() const
732 {
733  Q_D(const KService);
734  QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find(QString::fromLatin1("X-KDE-PluginKeyword"));
735  if ((it == d->m_mapProps.end()) || (!it->isValid())) {
736  return QString();
737  }
738 
739  return it->toString();
740 }
741 
742 QString KService::docPath() const
743 {
744  Q_D(const KService);
745  QMap<QString,QVariant>::ConstIterator it = d->m_mapProps.find(QLatin1String("X-DocPath"));
746  if ((it == d->m_mapProps.end()) || (!it->isValid())) {
747  it = d->m_mapProps.find(QString::fromLatin1("DocPath"));
748  if ((it == d->m_mapProps.end()) || (!it->isValid())) {
749  return QString();
750  }
751  }
752 
753  return it->toString();
754 }
755 
756 bool KService::allowMultipleFiles() const {
757  Q_D(const KService);
758  // Can we pass multiple files on the command line or do we have to start the application for every single file ?
759  return (d->m_strExec.contains( QLatin1String("%F") ) || d->m_strExec.contains( QLatin1String("%U") ) ||
760  d->m_strExec.contains( QLatin1String("%N") ) || d->m_strExec.contains( QLatin1String("%D") ));
761 }
762 
763 QStringList KService::categories() const
764 {
765  Q_D(const KService);
766  return d->categories;
767 }
768 
769 QString KService::menuId() const
770 {
771  Q_D(const KService);
772  return d->menuId;
773 }
774 
775 void KService::setMenuId(const QString &_menuId)
776 {
777  Q_D(KService);
778  d->menuId = _menuId;
779 }
780 
781 QString KService::storageId() const
782 {
783  Q_D(const KService);
784  return d->storageId();
785 }
786 
787 QString KService::locateLocal() const
788 {
789  Q_D(const KService);
790  if (d->menuId.isEmpty() || entryPath().startsWith(QLatin1String(".hidden")) ||
791  (QDir::isRelativePath(entryPath()) && d->categories.isEmpty()))
792  return KDesktopFile::locateLocal(entryPath());
793 
794  return KStandardDirs::locateLocal("xdgdata-apps", d->menuId);
795 }
796 
797 QString KService::newServicePath(bool showInMenu, const QString &suggestedName,
798  QString *menuId, const QStringList *reservedMenuIds)
799 {
800  Q_UNUSED(showInMenu); // TODO KDE5: remove argument
801 
802  QString base = suggestedName;
803  QString result;
804  for(int i = 1; true; i++)
805  {
806  if (i == 1)
807  result = base + QString::fromLatin1(".desktop");
808  else
809  result = base + QString::fromLatin1("-%1.desktop").arg(i);
810 
811  if (reservedMenuIds && reservedMenuIds->contains(result))
812  continue;
813 
814  // Lookup service by menu-id
815  KService::Ptr s = serviceByMenuId(result);
816  if (s)
817  continue;
818 
819  if (!KStandardDirs::locate("xdgdata-apps", result).isEmpty())
820  continue;
821 
822  break;
823  }
824  if (menuId)
825  *menuId = result;
826 
827  return KStandardDirs::locateLocal("xdgdata-apps", result);
828 }
829 
830 bool KService::isApplication() const
831 {
832  Q_D(const KService);
833  return d->m_strType == QLatin1String("Application");
834 }
835 
836 #ifndef KDE_NO_DEPRECATED
837 QString KService::type() const
838 {
839  Q_D(const KService);
840  return d->m_strType;
841 }
842 #endif
843 
844 QString KService::exec() const
845 {
846  Q_D(const KService);
847  if (d->m_strType == QLatin1String("Application") && d->m_strExec.isEmpty())
848  {
849  kWarning(servicesDebugArea()) << "The desktop entry file " << entryPath()
850  << " has Type=" << d->m_strType << " but has no Exec field." << endl;
851  }
852  return d->m_strExec;
853 }
854 
855 QString KService::library() const
856 {
857  Q_D(const KService);
858  return d->m_strLibrary;
859 }
860 
861 QString KService::icon() const
862 {
863  Q_D(const KService);
864  return d->m_strIcon;
865 }
866 
867 QString KService::terminalOptions() const
868 {
869  Q_D(const KService);
870  return d->m_strTerminalOptions;
871 }
872 
873 bool KService::terminal() const
874 {
875  Q_D(const KService);
876  return d->m_bTerminal;
877 }
878 
879 // KDE5: remove and port code to entryPath?
880 #ifndef KDE_NO_DEPRECATED
881 QString KService::desktopEntryPath() const
882 {
883  return entryPath();
884 }
885 #endif
886 
887 QString KService::desktopEntryName() const
888 {
889  Q_D(const KService);
890  return d->m_strDesktopEntryName;
891 }
892 
893 KService::DBusStartupType KService::dbusStartupType() const
894 {
895  Q_D(const KService);
896  return d->m_DBUSStartusType;
897 }
898 
899 QString KService::path() const
900 {
901  Q_D(const KService);
902  return d->m_strPath;
903 }
904 
905 QString KService::comment() const
906 {
907  Q_D(const KService);
908  return d->m_strComment;
909 }
910 
911 QString KService::genericName() const
912 {
913  Q_D(const KService);
914  return d->m_strGenName;
915 }
916 
917 QStringList KService::keywords() const
918 {
919  Q_D(const KService);
920  return d->m_lstKeywords;
921 }
922 
923 QStringList KServicePrivate::serviceTypes() const
924 {
925  QStringList ret;
926  QVector<KService::ServiceTypeAndPreference>::const_iterator it = m_serviceTypes.begin();
927  for ( ; it < m_serviceTypes.end(); ++it ) {
928  Q_ASSERT(!(*it).serviceType.isEmpty());
929  ret.append((*it).serviceType);
930  }
931  return ret;
932 }
933 
934 QStringList KService::serviceTypes() const
935 {
936  Q_D(const KService);
937  return d->serviceTypes();
938 }
939 
940 QStringList KService::mimeTypes() const
941 {
942  Q_D(const KService);
943  QStringList ret;
944  QVector<KService::ServiceTypeAndPreference>::const_iterator it = d->m_serviceTypes.begin();
945  for ( ; it < d->m_serviceTypes.end(); ++it ) {
946  const QString sv = (*it).serviceType;
947  if (KMimeType::mimeType(sv)) // keep only mimetypes, filter out servicetypes
948  ret.append(sv);
949  }
950  return ret;
951 }
952 
953 bool KService::allowAsDefault() const
954 {
955  Q_D(const KService);
956  return d->m_bAllowAsDefault;
957 }
958 
959 int KService::initialPreference() const
960 {
961  Q_D(const KService);
962  return d->m_initialPreference;
963 }
964 
965 void KService::setTerminal(bool b)
966 {
967  Q_D(KService);
968  d->m_bTerminal = b;
969 }
970 
971 void KService::setTerminalOptions(const QString &options)
972 {
973  Q_D(KService);
974  d->m_strTerminalOptions = options;
975 }
976 
977 QVector<KService::ServiceTypeAndPreference> & KService::_k_accessServiceTypes()
978 {
979  Q_D(KService);
980  return d->m_serviceTypes;
981 }
982 
983 QList<KServiceAction> KService::actions() const
984 {
985  Q_D(const KService);
986  return d->m_actions;
987 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue Jul 17 2012 07:26:01 by doxygen 1.8.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.8.4 API Reference

Skip menu "kdelibs-4.8.4 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