TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

935 lines
28 KiB

  1. /* This file is part of the KDE libraries
  2. * Copyright (C) 1999 - 2001 Waldo Bastian <bastian@kde.org>
  3. * Copyright (C) 1999 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. // $Id$
  20. #include <config.h>
  21. #include "kservice.h"
  22. #include "kservice_p.h"
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <stddef.h>
  26. #include <unistd.h>
  27. #include <stdlib.h>
  28. #include <tqstring.h>
  29. #include <tqfile.h>
  30. #include <tqdir.h>
  31. #include <tqtl.h>
  32. #include <ksimpleconfig.h>
  33. #include <kapplication.h>
  34. #include <kdebug.h>
  35. #include <kdesktopfile.h>
  36. #include <kglobal.h>
  37. #include <kiconloader.h>
  38. #include <klocale.h>
  39. #include <kconfigbase.h>
  40. #include <kstandarddirs.h>
  41. #include <dcopclient.h>
  42. #include "kservicefactory.h"
  43. #include "kservicetypefactory.h"
  44. #include "kservicetype.h"
  45. #include "kuserprofile.h"
  46. #include "ksycoca.h"
  47. class KService::KServicePrivate
  48. {
  49. public:
  50. TQStringList categories;
  51. TQString menuId;
  52. };
  53. KService::KService( const TQString & _name, const TQString &_exec, const TQString &_icon)
  54. : KSycocaEntry( TQString::null)
  55. {
  56. d = new KServicePrivate;
  57. m_bValid = true;
  58. m_bDeleted = false;
  59. m_strType = "Application";
  60. m_strName = _name;
  61. m_strExec = _exec;
  62. m_strIcon = _icon;
  63. m_bTerminal = false;
  64. m_bAllowAsDefault = true;
  65. m_initialPreference = 10;
  66. }
  67. KService::KService( const TQString & _fullpath )
  68. : KSycocaEntry( _fullpath)
  69. {
  70. KDesktopFile config( _fullpath );
  71. init(&config);
  72. }
  73. KService::KService( KDesktopFile *config )
  74. : KSycocaEntry( config->fileName())
  75. {
  76. init(config);
  77. }
  78. void
  79. KService::init( KDesktopFile *config )
  80. {
  81. d = new KServicePrivate;
  82. m_bValid = true;
  83. bool absPath = !TQDir::isRelativePath(entryPath());
  84. bool kde4application = config->fileName().startsWith("/usr/share/applications/kde4/");
  85. config->setDesktopGroup();
  86. TQMap<TQString, TQString> entryMap = config->entryMap(config->group());
  87. entryMap.remove("Encoding"); // reserved as part of Desktop Entry Standard
  88. entryMap.remove("Version"); // reserved as part of Desktop Entry Standard
  89. m_bDeleted = config->readBoolEntry( "Hidden", false );
  90. entryMap.remove("Hidden");
  91. if (m_bDeleted)
  92. {
  93. //kdDebug() << "Hidden=true for " << entryPath() << endl;
  94. m_bValid = false;
  95. return;
  96. }
  97. m_strName = config->readName();
  98. entryMap.remove("Name");
  99. if ( m_strName.isEmpty() )
  100. {
  101. if (config->readEntry( "Exec" ).isEmpty())
  102. {
  103. //kdWarning(7012) << "The desktop entry file " << entryPath()
  104. // << " has no Name and no Exec" << endl;
  105. m_bValid = false;
  106. return;
  107. }
  108. // Try to make up a name.
  109. m_strName = entryPath();
  110. int i = m_strName.findRev('/');
  111. m_strName = m_strName.mid(i+1);
  112. i = m_strName.findRev('.');
  113. if (i != -1)
  114. m_strName = m_strName.left(i);
  115. }
  116. m_strType = config->readType();
  117. entryMap.remove("Type");
  118. if ( m_strType.isEmpty() )
  119. {
  120. /*kdWarning(7012) << "The desktop entry file " << entryPath()
  121. << " has no Type=... entry."
  122. << " It should be \"Application\" or \"Service\"" << endl;
  123. m_bValid = false;
  124. return;*/
  125. m_strType = "Application";
  126. } else if ( m_strType != "Application" && m_strType != "Service" )
  127. {
  128. kdWarning(7012) << "The desktop entry file " << entryPath()
  129. << " has Type=" << m_strType
  130. << " instead of \"Application\" or \"Service\"" << endl;
  131. m_bValid = false;
  132. return;
  133. }
  134. // In case Try Exec is set, check if the application is available
  135. if (!config->tryExec()) {
  136. //kdDebug(7012) << "tryExec said false for " << entryPath() << endl;
  137. m_bDeleted = true;
  138. m_bValid = false;
  139. return;
  140. }
  141. TQString resource = config->resource();
  142. if ( (m_strType == "Application") &&
  143. (!resource.isEmpty()) &&
  144. (resource != "apps") &&
  145. !absPath)
  146. {
  147. kdWarning(7012) << "The desktop entry file " << entryPath()
  148. << " has Type=" << m_strType << " but is located under \"" << resource
  149. << "\" instead of \"apps\"" << endl;
  150. m_bValid = false;
  151. return;
  152. }
  153. if ( (m_strType == "Service") &&
  154. (!resource.isEmpty()) &&
  155. (resource != "services") &&
  156. !absPath)
  157. {
  158. kdWarning(7012) << "The desktop entry file " << entryPath()
  159. << " has Type=" << m_strType << " but is located under \"" << resource
  160. << "\" instead of \"services\"" << endl;
  161. m_bValid = false;
  162. return;
  163. }
  164. TQString name = entryPath();
  165. int pos = name.findRev('/');
  166. if (pos != -1)
  167. name = name.mid(pos+1);
  168. pos = name.find('.');
  169. if (pos != -1)
  170. name = name.left(pos);
  171. m_strExec = config->readPathEntry( "Exec" );
  172. if (kde4application && !m_strExec.startsWith("/")) {
  173. m_strExec = "TDEHOME=$HOME/.trinity XDG_DATA_DIRS=/usr/share TDEDIRS=/usr/ XDG_CONFIG_DIRS=/etc/xdg/ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:$PATH "+m_strExec;
  174. } else if (config->readBoolEntry("X-TDE-SubstituteUID")) {
  175. int space = m_strExec.find(" ");
  176. if (space==-1)
  177. m_strExec = KStandardDirs::findExe(m_strExec);
  178. else {
  179. const TQString command = m_strExec.left(space);
  180. m_strExec.replace(command,KStandardDirs::findExe(command));
  181. }
  182. }
  183. entryMap.remove("Exec");
  184. m_strIcon = config->readEntry( "Icon", "unknown" );
  185. if (kde4application) {
  186. if (TQFile::exists("/usr/share/icons/oxygen/22x22/apps/" + m_strIcon + ".png")) {
  187. m_strIcon = "/usr/share/icons/oxygen/22x22/apps/" + m_strIcon + ".png";
  188. } else if (TQFile::exists("/usr/share/icons/hicolor/22x22/apps/" + m_strIcon + ".png")) {
  189. m_strIcon = "/usr/share/icons/hicolor/22x22/apps/" + m_strIcon + ".png";
  190. }
  191. }
  192. entryMap.remove("Icon");
  193. m_bTerminal = (config->readBoolEntry( "Terminal" )); // should be a property IMHO
  194. entryMap.remove("Terminal");
  195. m_strTerminalOptions = config->readEntry( "TerminalOptions" ); // should be a property IMHO
  196. entryMap.remove("TerminalOptions");
  197. m_strPath = config->readPath();
  198. entryMap.remove("Path");
  199. m_strComment = config->readComment();
  200. entryMap.remove("Comment");
  201. m_strGenName = config->readGenericName();
  202. if (kde4application) {
  203. m_strGenName += " [KDE4]";
  204. }
  205. entryMap.remove("GenericName");
  206. TQString untranslatedGenericName = config->readEntryUntranslated( "GenericName" );
  207. if (!untranslatedGenericName.isEmpty())
  208. entryMap.insert("UntranslatedGenericName", untranslatedGenericName);
  209. m_lstKeywords = config->readListEntry("Keywords");
  210. entryMap.remove("Keywords");
  211. d->categories = config->readListEntry("Categories", ';');
  212. entryMap.remove("Categories");
  213. m_strLibrary = config->readEntry( "X-TDE-Library" );
  214. entryMap.remove("X-TDE-Library");
  215. m_strInit = config->readEntry("X-TDE-Init" );
  216. entryMap.remove("X-TDE-Init");
  217. m_lstServiceTypes = config->readListEntry( "ServiceTypes" );
  218. entryMap.remove("ServiceTypes");
  219. // For compatibility with KDE 1.x
  220. if (!kde4application)
  221. m_lstServiceTypes += config->readListEntry( "MimeType", ';' );
  222. entryMap.remove("MimeType");
  223. if ( m_strType == "Application" && !m_lstServiceTypes.contains("Application") )
  224. // Applications implement the service type "Application" ;-)
  225. m_lstServiceTypes += "Application";
  226. TQString dcopServiceType = config->readEntry("X-DCOP-ServiceType").lower();
  227. entryMap.remove("X-DCOP-ServiceType");
  228. if (dcopServiceType == "unique")
  229. m_DCOPServiceType = DCOP_Unique;
  230. else if (dcopServiceType == "multi")
  231. m_DCOPServiceType = DCOP_Multi;
  232. else if (dcopServiceType == "wait")
  233. m_DCOPServiceType = DCOP_Wait;
  234. else
  235. m_DCOPServiceType = DCOP_None;
  236. m_strDesktopEntryName = name.lower();
  237. if (kde4application)
  238. m_strDesktopEntryName = "kde4-" + m_strDesktopEntryName;
  239. m_bAllowAsDefault = config->readBoolEntry( "AllowDefault", true );
  240. entryMap.remove("AllowDefault");
  241. m_initialPreference = config->readNumEntry( "X-TDE-InitialPreference", 1 );
  242. entryMap.remove("X-TDE-InitialPreference");
  243. if ( m_initialPreference == 1 )
  244. m_initialPreference = config->readNumEntry( "InitialPreference", 1 );
  245. entryMap.remove("InitialPreference");
  246. // Store all additional entries in the property map.
  247. // A TQMap<TQString,TQString> would be easier for this but we can't
  248. // brake BC, so we have to store it in m_mapProps.
  249. // tqWarning("Path = %s", entryPath().latin1());
  250. TQMap<TQString,TQString>::ConstIterator it = entryMap.begin();
  251. for( ; it != entryMap.end();++it)
  252. {
  253. //tqDebug(" Key = %s Data = %s", it.key().latin1(), it.data().latin1());
  254. TQString key = it.key();
  255. if (kde4application && key=="OnlyShowIn" && it.data()=="KDE;")
  256. key = "NotShowIn";
  257. m_mapProps.insert( key, TQVariant( it.data()));
  258. }
  259. }
  260. KService::KService( TQDataStream& _str, int offset ) : KSycocaEntry( _str, offset )
  261. {
  262. d = new KServicePrivate;
  263. load( _str );
  264. }
  265. KService::~KService()
  266. {
  267. //debug("KService::~KService()");
  268. delete d;
  269. }
  270. TQPixmap KService::pixmap( KIcon::Group _group, int _force_size, int _state, TQString * _path ) const
  271. {
  272. KIconLoader *iconLoader=KGlobal::iconLoader();
  273. if (!iconLoader->extraDesktopThemesAdded())
  274. {
  275. TQPixmap pixmap=iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path, true );
  276. if (!pixmap.isNull() ) return pixmap;
  277. iconLoader->addExtraDesktopThemes();
  278. }
  279. return iconLoader->loadIcon( m_strIcon, _group, _force_size, _state, _path );
  280. }
  281. void KService::load( TQDataStream& s )
  282. {
  283. // dummies are here because of fields that were removed, to keep bin compat.
  284. // Feel free to re-use, but fields for Applications only (not generic services)
  285. // should rather be added to application.desktop
  286. TQ_INT8 def, term, dummy1, dummy2;
  287. TQ_INT8 dst, initpref;
  288. TQString dummyStr1, dummyStr2;
  289. int dummyI1, dummyI2;
  290. TQ_UINT32 dummyUI32;
  291. // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x!
  292. // !! This data structure should remain binary compatible at all times !!
  293. // You may add new fields at the end. Make sure to update the version
  294. // number in ksycoca.h
  295. s >> m_strType >> m_strName >> m_strExec >> m_strIcon
  296. >> term >> m_strTerminalOptions
  297. >> m_strPath >> m_strComment >> m_lstServiceTypes >> def >> m_mapProps
  298. >> m_strLibrary >> dummyI1 >> dummyI2
  299. >> dst
  300. >> m_strDesktopEntryName
  301. >> dummy1 >> dummyStr1 >> initpref >> dummyStr2 >> dummy2
  302. >> m_lstKeywords >> m_strInit >> dummyUI32 >> m_strGenName
  303. >> d->categories >> d->menuId;
  304. m_bAllowAsDefault = def;
  305. m_bTerminal = term;
  306. m_DCOPServiceType = (DCOPServiceType_t) dst;
  307. m_initialPreference = initpref;
  308. m_bValid = true;
  309. }
  310. void KService::save( TQDataStream& s )
  311. {
  312. KSycocaEntry::save( s );
  313. TQ_INT8 def = m_bAllowAsDefault, initpref = m_initialPreference;
  314. TQ_INT8 term = m_bTerminal;
  315. TQ_INT8 dst = (TQ_INT8) m_DCOPServiceType;
  316. TQ_INT8 dummy1 = 0, dummy2 = 0; // see ::load
  317. TQString dummyStr1, dummyStr2;
  318. int dummyI1 = 0, dummyI2 = 0;
  319. TQ_UINT32 dummyUI32 = 0;
  320. // WARNING: IN KDE 3.x THIS NEEDS TO REMAIN COMPATIBLE WITH KDE 2.x!
  321. // !! This data structure should remain binary compatible at all times !!
  322. // You may add new fields at the end. Make sure to update the version
  323. // number in ksycoca.h
  324. s << m_strType << m_strName << m_strExec << m_strIcon
  325. << term << m_strTerminalOptions
  326. << m_strPath << m_strComment << m_lstServiceTypes << def << m_mapProps
  327. << m_strLibrary << dummyI1 << dummyI2
  328. << dst
  329. << m_strDesktopEntryName
  330. << dummy1 << dummyStr1 << initpref << dummyStr2 << dummy2
  331. << m_lstKeywords << m_strInit << dummyUI32 << m_strGenName
  332. << d->categories << d->menuId;
  333. }
  334. bool KService::hasServiceType( const TQString& _servicetype ) const
  335. {
  336. if (!m_bValid) return false; // safety test
  337. //kdDebug(7012) << "Testing " << m_strDesktopEntryName << " for " << _servicetype << endl;
  338. KMimeType::Ptr mimePtr = KMimeType::mimeType( _servicetype );
  339. if ( mimePtr && mimePtr == KMimeType::defaultMimeTypePtr() )
  340. mimePtr = 0;
  341. bool isNumber;
  342. // For each service type we are associated with, if it doesn't
  343. // match then we try its parent service types.
  344. TQStringList::ConstIterator it = m_lstServiceTypes.begin();
  345. for( ; it != m_lstServiceTypes.end(); ++it )
  346. {
  347. (*it).toInt(&isNumber);
  348. if (isNumber)
  349. continue;
  350. //kdDebug(7012) << " has " << (*it) << endl;
  351. KServiceType::Ptr ptr = KServiceType::serviceType( *it );
  352. if ( ptr && ptr->inherits( _servicetype ) )
  353. return true;
  354. // The mimetype inheritance ("is also") works the other way.
  355. // e.g. if we're looking for a handler for mimePtr==smb-workgroup
  356. // then a handler for inode/directory is ok.
  357. if ( mimePtr && mimePtr->is( *it ) )
  358. return true;
  359. }
  360. return false;
  361. }
  362. int KService::initialPreferenceForMimeType( const TQString& mimeType ) const
  363. {
  364. if (!m_bValid) return 0; // safety test
  365. bool isNumber;
  366. // For each service type we are associated with
  367. TQStringList::ConstIterator it = m_lstServiceTypes.begin();
  368. for( ; it != m_lstServiceTypes.end(); ++it )
  369. {
  370. (*it).toInt(&isNumber);
  371. if (isNumber)
  372. continue;
  373. //kdDebug(7012) << " has " << (*it) << endl;
  374. KServiceType::Ptr ptr = KServiceType::serviceType( *it );
  375. if ( !ptr || !ptr->inherits( mimeType ) )
  376. continue;
  377. int initalPreference = m_initialPreference;
  378. ++it;
  379. if (it != m_lstServiceTypes.end())
  380. {
  381. int i = (*it).toInt(&isNumber);
  382. if (isNumber)
  383. initalPreference = i;
  384. }
  385. return initalPreference;
  386. }
  387. KMimeType::Ptr mimePtr = KMimeType::mimeType( mimeType );
  388. if ( mimePtr && mimePtr == KMimeType::defaultMimeTypePtr() )
  389. mimePtr = 0;
  390. // Try its parent service types.
  391. it = m_lstServiceTypes.begin();
  392. for( ; it != m_lstServiceTypes.end(); ++it )
  393. {
  394. (*it).toInt(&isNumber);
  395. if (isNumber)
  396. continue;
  397. // The mimetype inheritance ("is also") works the other way.
  398. // e.g. if we're looking for a handler for mimePtr==smb-workgroup
  399. // then a handler for inode/directory is ok.
  400. if ( !mimePtr || !mimePtr->is( *it ) )
  401. continue;
  402. int initalPreference = m_initialPreference;
  403. ++it;
  404. if (it != m_lstServiceTypes.end())
  405. {
  406. int i = (*it).toInt(&isNumber);
  407. if (isNumber)
  408. initalPreference = i;
  409. }
  410. return initalPreference;
  411. }
  412. return 0;
  413. }
  414. class KServiceReadProperty : public KConfigBase
  415. {
  416. public:
  417. KServiceReadProperty(const TQString &_key, const TQCString &_value)
  418. : key(_key), value(_value) { }
  419. bool internalHasGroup(const TQCString &) const { /*tqDebug("hasGroup(const TQCString &)");*/ return false; }
  420. TQStringList groupList() const { return TQStringList(); }
  421. TQMap<TQString,TQString> entryMap(const TQString &group) const
  422. { Q_UNUSED(group); return TQMap<TQString,TQString>(); }
  423. void reparseConfiguration() { }
  424. KEntryMap internalEntryMap( const TQString &pGroup) const
  425. { Q_UNUSED(pGroup); return KEntryMap(); }
  426. KEntryMap internalEntryMap() const { return KEntryMap(); }
  427. void putData(const KEntryKey &_key, const KEntry& _data, bool _checkGroup)
  428. { Q_UNUSED(_key); Q_UNUSED(_data); Q_UNUSED(_checkGroup); }
  429. KEntry lookupData(const KEntryKey &_key) const
  430. { Q_UNUSED(_key); KEntry entry; entry.mValue = value; return entry; }
  431. protected:
  432. TQString key;
  433. TQCString value;
  434. };
  435. TQVariant KService::property( const TQString& _name) const
  436. {
  437. return property( _name, TQVariant::Invalid);
  438. }
  439. // Return a string TQVariant if string isn't null, and invalid variant otherwise
  440. // (the variant must be invalid if the field isn't in the .desktop file)
  441. // This allows trader queries like "exist Library" to work.
  442. static TQVariant makeStringVariant( const TQString& string )
  443. {
  444. // Using isEmpty here would be wrong.
  445. // Empty is "specified but empty", null is "not specified" (in the .desktop file)
  446. return string.isNull() ? TQVariant() : TQVariant( string );
  447. }
  448. TQVariant KService::property( const TQString& _name, TQVariant::Type t ) const
  449. {
  450. if ( _name == "Type" )
  451. return TQVariant( m_strType ); // can't be null
  452. else if ( _name == "Name" )
  453. return TQVariant( m_strName ); // can't be null
  454. else if ( _name == "Exec" )
  455. return makeStringVariant( m_strExec );
  456. else if ( _name == "Icon" )
  457. return makeStringVariant( m_strIcon );
  458. else if ( _name == "Terminal" )
  459. return TQVariant( static_cast<int>(m_bTerminal) );
  460. else if ( _name == "TerminalOptions" )
  461. return makeStringVariant( m_strTerminalOptions );
  462. else if ( _name == "Path" )
  463. return makeStringVariant( m_strPath );
  464. else if ( _name == "Comment" )
  465. return makeStringVariant( m_strComment );
  466. else if ( _name == "GenericName" )
  467. return makeStringVariant( m_strGenName );
  468. else if ( _name == "ServiceTypes" )
  469. return TQVariant( m_lstServiceTypes );
  470. else if ( _name == "AllowAsDefault" )
  471. return TQVariant( static_cast<int>(m_bAllowAsDefault) );
  472. else if ( _name == "InitialPreference" )
  473. return TQVariant( m_initialPreference );
  474. else if ( _name == "Library" )
  475. return makeStringVariant( m_strLibrary );
  476. else if ( _name == "DesktopEntryPath" ) // can't be null
  477. return TQVariant( entryPath() );
  478. else if ( _name == "DesktopEntryName")
  479. return TQVariant( m_strDesktopEntryName ); // can't be null
  480. else if ( _name == "Categories")
  481. return TQVariant( d->categories );
  482. else if ( _name == "Keywords")
  483. return TQVariant( m_lstKeywords );
  484. // Ok we need to convert the property from a TQString to its real type.
  485. // Maybe the caller helped us.
  486. if (t == TQVariant::Invalid)
  487. {
  488. // No luck, let's ask KServiceTypeFactory what the type of this property
  489. // is supposed to be.
  490. t = KServiceTypeFactory::self()->findPropertyTypeByName(_name);
  491. if (t == TQVariant::Invalid)
  492. {
  493. kdDebug(7012) << "Request for unknown property '" << _name << "'\n";
  494. return TQVariant(); // Unknown property: Invalid variant.
  495. }
  496. }
  497. // Then we use a homebuild class based on KConfigBase to convert the TQString.
  498. // For some often used property types we do the conversion ourselves.
  499. TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( _name );
  500. if ( (it == m_mapProps.end()) || (!it.data().isValid()))
  501. {
  502. //kdDebug(7012) << "Property not found " << _name << endl;
  503. return TQVariant(); // No property set.
  504. }
  505. switch(t)
  506. {
  507. case TQVariant::String:
  508. return it.data();
  509. case TQVariant::Bool:
  510. case TQVariant::Int:
  511. {
  512. TQString aValue = it.data().toString();
  513. int val = 0;
  514. if (aValue == "true" || aValue == "on" || aValue == "yes")
  515. val = 1;
  516. else
  517. {
  518. bool bOK;
  519. val = aValue.toInt( &bOK );
  520. if( !bOK )
  521. val = 0;
  522. }
  523. if (t == TQVariant::Bool)
  524. {
  525. return TQVariant((bool)val, 1);
  526. }
  527. return TQVariant(val);
  528. }
  529. default:
  530. // All others
  531. KServiceReadProperty ksrp(_name, it.data().toString().utf8());
  532. return ksrp.readPropertyEntry(_name, t);
  533. }
  534. }
  535. TQStringList KService::propertyNames() const
  536. {
  537. TQStringList res;
  538. TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.begin();
  539. for( ; it != m_mapProps.end(); ++it )
  540. res.append( it.key() );
  541. res.append( "Type" );
  542. res.append( "Name" );
  543. res.append( "Comment" );
  544. res.append( "GenericName" );
  545. res.append( "Icon" );
  546. res.append( "Exec" );
  547. res.append( "Terminal" );
  548. res.append( "TerminalOptions" );
  549. res.append( "Path" );
  550. res.append( "ServiceTypes" );
  551. res.append( "AllowAsDefault" );
  552. res.append( "InitialPreference" );
  553. res.append( "Library" );
  554. res.append( "DesktopEntryPath" );
  555. res.append( "DesktopEntryName" );
  556. res.append( "Keywords" );
  557. res.append( "Categories" );
  558. return res;
  559. }
  560. KService::List KService::allServices()
  561. {
  562. return KServiceFactory::self()->allServices();
  563. }
  564. KService::Ptr KService::serviceByName( const TQString& _name )
  565. {
  566. KService * s = KServiceFactory::self()->findServiceByName( _name );
  567. return KService::Ptr( s );
  568. }
  569. KService::Ptr KService::serviceByDesktopPath( const TQString& _name )
  570. {
  571. KService * s = KServiceFactory::self()->findServiceByDesktopPath( _name );
  572. return KService::Ptr( s );
  573. }
  574. KService::Ptr KService::serviceByDesktopName( const TQString& _name )
  575. {
  576. KService * s = KServiceFactory::self()->findServiceByDesktopName( _name.lower() );
  577. if (!s && !_name.startsWith("kde-"))
  578. s = KServiceFactory::self()->findServiceByDesktopName( "kde-"+_name.lower() );
  579. return KService::Ptr( s );
  580. }
  581. KService::Ptr KService::serviceByMenuId( const TQString& _name )
  582. {
  583. KService * s = KServiceFactory::self()->findServiceByMenuId( _name );
  584. return KService::Ptr( s );
  585. }
  586. KService::Ptr KService::serviceByStorageId( const TQString& _storageId )
  587. {
  588. KService::Ptr service = KService::serviceByMenuId( _storageId );
  589. if (service)
  590. return service;
  591. service = KService::serviceByDesktopPath(_storageId);
  592. if (service)
  593. return service;
  594. if (!TQDir::isRelativePath(_storageId) && TQFile::exists(_storageId))
  595. return new KService(_storageId);
  596. TQString tmp = _storageId;
  597. tmp = tmp.mid(tmp.findRev('/')+1); // Strip dir
  598. if (tmp.endsWith(".desktop"))
  599. tmp.truncate(tmp.length()-8);
  600. if (tmp.endsWith(".kdelnk"))
  601. tmp.truncate(tmp.length()-7);
  602. service = KService::serviceByDesktopName(tmp);
  603. return service;
  604. }
  605. KService::List KService::allInitServices()
  606. {
  607. return KServiceFactory::self()->allInitServices();
  608. }
  609. bool KService::substituteUid() const {
  610. TQVariant v = property("X-TDE-SubstituteUID", TQVariant::Bool);
  611. return v.isValid() && v.toBool();
  612. }
  613. TQString KService::username() const {
  614. // See also KDesktopFile::tryExec()
  615. TQString user;
  616. TQVariant v = property("X-TDE-Username", TQVariant::String);
  617. user = v.isValid() ? v.toString() : TQString::null;
  618. if (user.isEmpty())
  619. user = ::getenv("ADMIN_ACCOUNT");
  620. if (user.isEmpty())
  621. user = "root";
  622. return user;
  623. }
  624. bool KService::noDisplay() const {
  625. TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( "NoDisplay" );
  626. if ( (it != m_mapProps.end()) && (it.data().isValid()))
  627. {
  628. TQString aValue = it.data().toString().lower();
  629. if (aValue == "true" || aValue == "on" || aValue == "yes")
  630. return true;
  631. }
  632. it = m_mapProps.find( "OnlyShowIn" );
  633. if ( (it != m_mapProps.end()) && (it.data().isValid()))
  634. {
  635. TQString aValue = it.data().toString();
  636. TQStringList aList = TQStringList::split(';', aValue);
  637. if ((!aList.contains("TDE")) && (!aList.contains("KDE")))
  638. return true;
  639. }
  640. it = m_mapProps.find( "NotShowIn" );
  641. if ( (it != m_mapProps.end()) && (it.data().isValid()))
  642. {
  643. TQString aValue = it.data().toString();
  644. TQStringList aList = TQStringList::split(';', aValue);
  645. if ((aList.contains("TDE")) || (aList.contains("KDE")))
  646. return true;
  647. }
  648. if (!kapp->authorizeControlModule(d->menuId))
  649. return true;
  650. return false;
  651. }
  652. TQString KService::untranslatedGenericName() const {
  653. TQVariant v = property("UntranslatedGenericName", TQVariant::String);
  654. return v.isValid() ? v.toString() : TQString::null;
  655. }
  656. bool KService::SuSEunimportant() const {
  657. TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( "X-SuSE-Unimportant" );
  658. if ( (it == m_mapProps.end()) || (!it.data().isValid()))
  659. {
  660. return false;
  661. }
  662. TQString aValue = it.data().toString();
  663. if (aValue == "true" || aValue == "on" || aValue == "yes")
  664. return true;
  665. else
  666. return false;
  667. }
  668. TQString KService::parentApp() const {
  669. TQMap<TQString,TQVariant>::ConstIterator it = m_mapProps.find( "X-TDE-ParentApp" );
  670. if ( (it == m_mapProps.end()) || (!it.data().isValid()))
  671. {
  672. return TQString::null;
  673. }
  674. return it.data().toString();
  675. }
  676. bool KService::allowMultipleFiles() const {
  677. // Can we pass multiple files on the command line or do we have to start the application for every single file ?
  678. if ( m_strExec.find( "%F" ) != -1 || m_strExec.find( "%U" ) != -1 ||
  679. m_strExec.find( "%N" ) != -1 || m_strExec.find( "%D" ) != -1 )
  680. return true;
  681. else
  682. return false;
  683. }
  684. TQStringList KService::categories() const
  685. {
  686. return d->categories;
  687. }
  688. TQString KService::menuId() const
  689. {
  690. return d->menuId;
  691. }
  692. void KService::setMenuId(const TQString &menuId)
  693. {
  694. d->menuId = menuId;
  695. }
  696. TQString KService::storageId() const
  697. {
  698. if (!d->menuId.isEmpty())
  699. return d->menuId;
  700. return entryPath();
  701. }
  702. TQString KService::locateLocal()
  703. {
  704. if (d->menuId.isEmpty() || desktopEntryPath().startsWith(".hidden") ||
  705. (TQDir::isRelativePath(desktopEntryPath()) && d->categories.isEmpty()))
  706. return KDesktopFile::locateLocal(desktopEntryPath());
  707. return ::locateLocal("xdgdata-apps", d->menuId);
  708. }
  709. TQString KService::newServicePath(bool showInMenu, const TQString &suggestedName,
  710. TQString *menuId, const TQStringList *reservedMenuIds)
  711. {
  712. TQString base = suggestedName;
  713. if (!showInMenu)
  714. base.prepend("kde-");
  715. TQString result;
  716. for(int i = 1; true; i++)
  717. {
  718. if (i == 1)
  719. result = base + ".desktop";
  720. else
  721. result = base + TQString("-%1.desktop").arg(i);
  722. if (reservedMenuIds && reservedMenuIds->contains(result))
  723. continue;
  724. // Lookup service by menu-id
  725. KService::Ptr s = serviceByMenuId(result);
  726. if (s)
  727. continue;
  728. if (showInMenu)
  729. {
  730. if (!locate("xdgdata-apps", result).isEmpty())
  731. continue;
  732. }
  733. else
  734. {
  735. TQString file = result.mid(4); // Strip "kde-"
  736. if (!locate("apps", ".hidden/"+file).isEmpty())
  737. continue;
  738. }
  739. break;
  740. }
  741. if (menuId)
  742. *menuId = result;
  743. if (showInMenu)
  744. {
  745. return ::locateLocal("xdgdata-apps", result);
  746. }
  747. else
  748. {
  749. TQString file = result.mid(4); // Strip "kde-"
  750. return ::locateLocal("apps", ".hidden/"+file);
  751. }
  752. }
  753. void KService::virtual_hook( int id, void* data )
  754. { KSycocaEntry::virtual_hook( id, data ); }
  755. void KService::rebuildKSycoca(TQWidget *parent)
  756. {
  757. KServiceProgressDialog dlg(parent, "ksycoca_progress",
  758. i18n("Updating System Configuration"),
  759. i18n("Updating system configuration."));
  760. TQByteArray data;
  761. DCOPClient *client = kapp->dcopClient();
  762. int result = client->callAsync("kded", "kbuildsycoca", "recreate()",
  763. data, TQT_TQOBJECT(&dlg), TQT_SLOT(slotFinished()));
  764. if (result)
  765. {
  766. dlg.exec();
  767. }
  768. }
  769. KServiceProgressDialog::KServiceProgressDialog(TQWidget *parent, const char *name,
  770. const TQString &caption, const TQString &text)
  771. : KProgressDialog(parent, name, caption, text, true)
  772. {
  773. connect(&m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotProgress()));
  774. progressBar()->setTotalSteps(20);
  775. m_timeStep = 700;
  776. m_timer.start(m_timeStep);
  777. setAutoClose(false);
  778. }
  779. void
  780. KServiceProgressDialog::slotProgress()
  781. {
  782. int p = progressBar()->progress();
  783. if (p == 18)
  784. {
  785. progressBar()->reset();
  786. progressBar()->setProgress(1);
  787. m_timeStep = m_timeStep * 2;
  788. m_timer.start(m_timeStep);
  789. }
  790. else
  791. {
  792. progressBar()->setProgress(p+1);
  793. }
  794. }
  795. void
  796. KServiceProgressDialog::slotFinished()
  797. {
  798. progressBar()->setProgress(20);
  799. m_timer.stop();
  800. TQTimer::singleShot(1000, this, TQT_SLOT(close()));
  801. }
  802. #include "kservice_p.moc"