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

KDED

kbuildservicefactory.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999, 2007 David Faure <faure@kde.org>
00003  *                1999 Waldo Bastian <bastian@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 "kbuildservicefactory.h"
00021 #include "kbuildservicegroupfactory.h"
00022 #include "kbuildmimetypefactory.h"
00023 #include "ksycoca.h"
00024 #include "ksycocadict.h"
00025 #include "kresourcelist.h"
00026 #include "kmimetype.h"
00027 #include "kdesktopfile.h"
00028 
00029 #include <kglobal.h>
00030 #include <kstandarddirs.h>
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033 #include <assert.h>
00034 #include <kmimetypefactory.h>
00035 
00036 KBuildServiceFactory::KBuildServiceFactory( KSycocaFactory *serviceTypeFactory,
00037                                             KBuildMimeTypeFactory *mimeTypeFactory,
00038                                             KBuildServiceGroupFactory *serviceGroupFactory ) :
00039     KServiceFactory(),
00040     m_nameMemoryHash(),
00041     m_relNameMemoryHash(),
00042     m_menuIdMemoryHash(),
00043     m_dupeDict(),
00044     m_serviceTypeFactory( serviceTypeFactory ),
00045     m_mimeTypeFactory( mimeTypeFactory ),
00046     m_serviceGroupFactory( serviceGroupFactory )
00047 {
00048     m_resourceList = new KSycocaResourceList();
00049     // We directly care about services desktop files.
00050     // All the application desktop files are parsed on demand from the vfolder menu code.
00051     m_resourceList->add( "services", "*.desktop" );
00052 }
00053 
00054 // return all service types for this factory
00055 // i.e. first arguments to m_resourceList->add() above
00056 QStringList KBuildServiceFactory::resourceTypes()
00057 {
00058     return QStringList() << "services";
00059 }
00060 
00061 KBuildServiceFactory::~KBuildServiceFactory()
00062 {
00063     delete m_resourceList;
00064 }
00065 
00066 KService::Ptr KBuildServiceFactory::findServiceByDesktopName(const QString &name)
00067 {
00068     return m_nameMemoryHash.value(name);
00069 }
00070 
00071 KService::Ptr KBuildServiceFactory::findServiceByDesktopPath(const QString &name)
00072 {
00073     return m_relNameMemoryHash.value(name);
00074 }
00075 
00076 KService::Ptr KBuildServiceFactory::findServiceByMenuId(const QString &menuId)
00077 {
00078     return m_menuIdMemoryHash.value(menuId);
00079 }
00080 
00081 KSycocaEntry* KBuildServiceFactory::createEntry( const QString& file, const char *resource ) const
00082 {
00083     QString name = file;
00084     int pos = name.lastIndexOf('/');
00085     if (pos != -1) {
00086         name = name.mid(pos+1);
00087     }
00088     // Is it a .desktop file?
00089     if (!name.endsWith(".desktop"))
00090         return 0;
00091 
00092     KDesktopFile desktopFile(resource, file);
00093 
00094     KService * serv = new KService(&desktopFile);
00095 
00096     if ( serv->isValid() && !serv->isDeleted() ) {
00097         return serv;
00098     } else {
00099         if (!serv->isDeleted())
00100             kWarning(7012) << "Invalid Service : " << file;
00101         delete serv;
00102         return 0;
00103     }
00104 }
00105 
00106 void KBuildServiceFactory::saveHeader(QDataStream &str)
00107 {
00108     KSycocaFactory::saveHeader(str);
00109 
00110     str << (qint32) m_nameDictOffset;
00111     str << (qint32) m_relNameDictOffset;
00112     str << (qint32) m_offerListOffset;
00113     str << (qint32) m_menuIdDictOffset;
00114 }
00115 
00116 void KBuildServiceFactory::save(QDataStream &str)
00117 {
00118     KSycocaFactory::save(str);
00119 
00120     m_nameDictOffset = str.device()->pos();
00121     m_nameDict->save(str);
00122 
00123     m_relNameDictOffset = str.device()->pos();
00124     m_relNameDict->save(str);
00125 
00126     saveOfferList(str);
00127 
00128     m_menuIdDictOffset = str.device()->pos();
00129     m_menuIdDict->save(str);
00130 
00131     int endOfFactoryData = str.device()->pos();
00132 
00133     // Update header (pass #3)
00134     saveHeader(str);
00135 
00136     // Seek to end.
00137     str.device()->seek(endOfFactoryData);
00138 }
00139 
00140 void KBuildServiceFactory::collectInheritedServices()
00141 {
00142     // With multiple inheritance, the "mimeTypeInheritanceLevel" isn't exactly
00143     // correct (it should only be increased when going up a level, not when iterating
00144     // through the multiple parents at a given level). I don't think we care,
00145     // but just in case we do, this is the reason I didn't port this to mimeType->allParentMimeTypes.
00146     const KMimeType::List allMimeTypes = m_mimeTypeFactory->allMimeTypes();
00147     KMimeType::List::const_iterator itm = allMimeTypes.begin();
00148     for( ; itm != allMimeTypes.end(); ++itm ) {
00149         const KMimeType::Ptr mimeType = *itm;
00150         const QString mimeTypeName = mimeType->name();
00151         QStringList parents = mimeType->parentMimeTypes();
00152         int mimeTypeInheritanceLevel = 0;
00153         while ( !parents.isEmpty() ) {
00154             const QString& parent = parents.takeFirst();
00155             const KMimeType::Ptr parentMimeType = m_mimeTypeFactory->findMimeTypeByName( parent );
00156             if ( parentMimeType ) {
00157                 ++mimeTypeInheritanceLevel;
00158                 const QList<KServiceOffer>& offers = m_offerHash.offersFor(parent);
00159                 QList<KServiceOffer>::const_iterator itserv = offers.begin();
00160                 const QList<KServiceOffer>::const_iterator endserv = offers.end();
00161                 for ( ; itserv != endserv; ++itserv ) {
00162                     KServiceOffer offer(*itserv);
00163                     offer.setMimeTypeInheritanceLevel(mimeTypeInheritanceLevel);
00164                     //kDebug(7021) << "INHERITANCE: Adding service" << (*itserv).service()->entryPath() << "to" << mimeTypeName << "mimeTypeInheritanceLevel=" << mimeTypeInheritanceLevel;
00165                     m_offerHash.addServiceOffer( mimeTypeName, offer );
00166                 }
00167                 parents += parentMimeType->parentMimeTypes();
00168             } else {
00169                 kWarning(7012) << "parent mimetype not found:" << parent;
00170                 break;
00171             }
00172         }
00173     }
00174     // TODO do the same for all/all and all/allfiles, if (!KServiceTypeProfile::configurationMode())
00175 }
00176 
00177 void KBuildServiceFactory::populateServiceTypes()
00178 {
00179     // For every service...
00180     KSycocaEntryDict::Iterator itserv = m_entryDict->begin();
00181     const KSycocaEntryDict::Iterator endserv = m_entryDict->end();
00182     for( ; itserv != endserv ; ++itserv ) {
00183         KService::Ptr service = KService::Ptr::staticCast(*itserv);
00184         QVector<KService::ServiceTypeAndPreference> serviceTypeList = service->_k_accessServiceTypes();
00185         //bool hasAllAll = false;
00186         //bool hasAllFiles = false;
00187 
00188         // Add this service to all its servicetypes (and their parents) and to all its mimetypes
00189         for (int i = 0; i < serviceTypeList.count() /*don't cache it, it can change during iteration!*/; ++i) {
00190             const QString stName = serviceTypeList[i].serviceType;
00191             // It could be a servicetype or a mimetype.
00192             KServiceType::Ptr serviceType = KServiceType::serviceType(stName);
00193             if (!serviceType) {
00194                 serviceType = KServiceType::Ptr::staticCast(m_mimeTypeFactory->findMimeTypeByName(stName, KMimeType::ResolveAliases));
00195             }
00196             // TODO. But maybe we should rename all/all to */*, to also support image/*?
00197             // Not sure how to model all/allfiles then, though
00198             // Also this kind of thing isn't in the XDG standards...
00199 #if 0
00200             if (!serviceType) {
00201                 if ( stName == QLatin1String( "all/all" ) ) {
00202                     hasAllAll = true;
00203                     continue;
00204                 } else if ( stName == QLatin1String( "all/allfiles" ) ) {
00205                     hasAllFiles = true;
00206                     continue;
00207                 }
00208             }
00209 #endif
00210 
00211             if (!serviceType) {
00212                 kDebug(7021) << service->entryPath() << "specifies undefined mimetype/servicetype" << stName;
00213                 continue;
00214             }
00215 
00216             const int preference = serviceTypeList[i].preference;
00217             const QString parent = serviceType->parentServiceType();
00218             if (!parent.isEmpty())
00219                 serviceTypeList.append(KService::ServiceTypeAndPreference(preference, parent));
00220 
00221             //kDebug(7021) << "Adding service" << service->entryPath() << "to" << serviceType->name() << "pref=" << preference;
00222             m_offerHash.addServiceOffer(stName, KServiceOffer(service, preference, 0, service->allowAsDefault()) );
00223         }
00224     }
00225 
00226     // Read user preferences (added/removed associations) and add/remove serviceoffers to m_offerHash
00227     KMimeAssociations mimeAssociations(m_offerHash);
00228     mimeAssociations.parseAllMimeAppsList();
00229 
00230     // Now for each mimetype, collect services from parent mimetypes
00231     collectInheritedServices();
00232 
00233     // Now collect the offsets into the (future) offer list
00234     // The loops look very much like the ones in saveOfferList obviously.
00235     int offersOffset = 0;
00236     const int offerEntrySize = sizeof( qint32 ) * 4; // four qint32s, see saveOfferList.
00237 
00238     KSycocaEntryDict::const_iterator itstf = m_serviceTypeFactory->entryDict()->begin();
00239     const KSycocaEntryDict::const_iterator endstf = m_serviceTypeFactory->entryDict()->end();
00240     for( ; itstf != endstf; ++itstf ) {
00241         KServiceType::Ptr entry = KServiceType::Ptr::staticCast( *itstf );
00242         const int numOffers = m_offerHash.offersFor(entry->name()).count();
00243         if ( numOffers ) {
00244             entry->setServiceOffersOffset( offersOffset );
00245             offersOffset += offerEntrySize * numOffers;
00246         }
00247     }
00248     KSycocaEntryDict::const_iterator itmtf = m_mimeTypeFactory->entryDict()->begin();
00249     const KSycocaEntryDict::const_iterator endmtf = m_mimeTypeFactory->entryDict()->end();
00250     for( ; itmtf != endmtf; ++itmtf )
00251     {
00252         KMimeType::Ptr entry = KMimeType::Ptr::staticCast( *itmtf );
00253         const int numOffers = m_offerHash.offersFor(entry->name()).count();
00254         if ( numOffers ) {
00255             entry->setServiceOffersOffset( offersOffset );
00256             offersOffset += offerEntrySize * numOffers;
00257         }
00258     }
00259 }
00260 
00261 void KBuildServiceFactory::saveOfferList(QDataStream &str)
00262 {
00263     m_offerListOffset = str.device()->pos();
00264 
00265     // For each entry in servicetypeFactory
00266     KSycocaEntryDict::const_iterator itstf = m_serviceTypeFactory->entryDict()->begin();
00267     const KSycocaEntryDict::const_iterator endstf = m_serviceTypeFactory->entryDict()->end();
00268     for( ; itstf != endstf; ++itstf ) {
00269         // export associated services
00270         const KServiceType::Ptr entry = KServiceType::Ptr::staticCast( *itstf );
00271         Q_ASSERT( entry );
00272 
00273         QList<KServiceOffer> offers = m_offerHash.offersFor(entry->name());
00274         qStableSort( offers ); // by initial preference
00275 
00276         for(QList<KServiceOffer>::const_iterator it2 = offers.begin();
00277             it2 != offers.end(); ++it2) {
00278             //kDebug(7021) << "servicetype offers list:" << entry->name() << "->" << (*it2).service()->entryPath();
00279 
00280             str << (qint32) entry->offset();
00281             str << (qint32) (*it2).service()->offset();
00282             str << (qint32) (*it2).preference();
00283             str << (qint32) 0; // mimeTypeInheritanceLevel
00284             // update offerEntrySize in populateServiceTypes if you add/remove something here
00285         }
00286     }
00287 
00288     // For each entry in mimeTypeFactory
00289     KSycocaEntryDict::const_iterator itmtf = m_mimeTypeFactory->entryDict()->begin();
00290     const KSycocaEntryDict::const_iterator endmtf = m_mimeTypeFactory->entryDict()->end();
00291     for( ; itmtf != endmtf; ++itmtf ) {
00292         // export associated services
00293         const KMimeType::Ptr entry = KMimeType::Ptr::staticCast( *itmtf );
00294         Q_ASSERT( entry );
00295         QList<KServiceOffer> offers = m_offerHash.offersFor(entry->name());
00296         qStableSort( offers ); // by initial preference
00297 
00298         for(QList<KServiceOffer>::const_iterator it2 = offers.begin();
00299             it2 != offers.end(); ++it2) {
00300             //kDebug(7021) << "mimetype offers list:" << entry->name() << "->" << (*it2).service()->entryPath() << "pref" << (*it2).preference();
00301             Q_ASSERT((*it2).service()->offset() != 0);
00302             str << (qint32) entry->offset();
00303             str << (qint32) (*it2).service()->offset();
00304             str << (qint32) (*it2).preference();
00305             str << (qint32) (*it2).mimeTypeInheritanceLevel();
00306             // update offerEntrySize in populateServiceTypes if you add/remove something here
00307         }
00308     }
00309 
00310     str << (qint32) 0;               // End of list marker (0)
00311 }
00312 
00313 void KBuildServiceFactory::addEntry(const KSycocaEntry::Ptr& newEntry)
00314 {
00315     Q_ASSERT(newEntry);
00316     if (m_dupeDict.contains(newEntry))
00317         return;
00318 
00319     KSycocaFactory::addEntry(newEntry);
00320 
00321     const KService::Ptr service = KService::Ptr::staticCast( newEntry );
00322     m_dupeDict.insert(newEntry);
00323 
00324     if (!service->isDeleted()) {
00325         const QString parent = service->parentApp();
00326         if (!parent.isEmpty())
00327             m_serviceGroupFactory->addNewChild(parent, KSycocaEntry::Ptr::staticCast(service));
00328     }
00329 
00330     const QString name = service->desktopEntryName();
00331     m_nameDict->add( name, newEntry );
00332     m_nameMemoryHash.insert(name, service);
00333 
00334     const QString relName = service->entryPath();
00335     //kDebug(7021) << "adding service" << service->menuId() << "name=" << name << "relName=" << relName;
00336     m_relNameDict->add( relName, newEntry );
00337     m_relNameMemoryHash.insert(relName, service); // for KMimeAssociations
00338 
00339     const QString menuId = service->menuId();
00340     if (!menuId.isEmpty()) {
00341         m_menuIdDict->add( menuId, newEntry );
00342         m_menuIdMemoryHash.insert(menuId, service); // for KMimeAssociations
00343     }
00344 }
00345 

KDED

Skip menu "KDED"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

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