KDED
kbuildservicefactory.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 "kdesktopfile.h"
00027
00028 #include <kglobal.h>
00029 #include <kstandarddirs.h>
00030 #include <klocale.h>
00031 #include <kdebug.h>
00032 #include <assert.h>
00033 #include <kmimetypefactory.h>
00034
00035 KBuildServiceFactory::KBuildServiceFactory( KSycocaFactory *serviceTypeFactory,
00036 KBuildMimeTypeFactory *mimeTypeFactory,
00037 KBuildServiceGroupFactory *serviceGroupFactory ) :
00038 KServiceFactory(),
00039 m_nameMemoryHash(),
00040 m_relNameMemoryHash(),
00041 m_menuIdMemoryHash(),
00042 m_dupeDict(),
00043 m_serviceTypeFactory( serviceTypeFactory ),
00044 m_mimeTypeFactory( mimeTypeFactory ),
00045 m_serviceGroupFactory( serviceGroupFactory )
00046 {
00047 m_resourceList = new KSycocaResourceList();
00048
00049
00050 m_resourceList->add( "services", "*.desktop" );
00051
00052 m_nameDict = new KSycocaDict();
00053 m_relNameDict = new KSycocaDict();
00054 m_menuIdDict = new KSycocaDict();
00055 }
00056
00057
00058
00059 QStringList KBuildServiceFactory::resourceTypes()
00060 {
00061 return QStringList() << "services";
00062 }
00063
00064 KBuildServiceFactory::~KBuildServiceFactory()
00065 {
00066 delete m_resourceList;
00067 }
00068
00069 KService::Ptr KBuildServiceFactory::findServiceByDesktopName(const QString &name)
00070 {
00071 return m_nameMemoryHash.value(name);
00072 }
00073
00074 KService::Ptr KBuildServiceFactory::findServiceByDesktopPath(const QString &name)
00075 {
00076 return m_relNameMemoryHash.value(name);
00077 }
00078
00079 KService::Ptr KBuildServiceFactory::findServiceByMenuId(const QString &menuId)
00080 {
00081 return m_menuIdMemoryHash.value(menuId);
00082 }
00083
00084 KSycocaEntry* KBuildServiceFactory::createEntry( const QString& file, const char *resource ) const
00085 {
00086 QString name = file;
00087 int pos = name.lastIndexOf('/');
00088 if (pos != -1) {
00089 name = name.mid(pos+1);
00090 }
00091
00092 if (!name.endsWith(".desktop"))
00093 return 0;
00094
00095 KDesktopFile desktopFile(resource, file);
00096
00097 KService * serv = new KService(&desktopFile);
00098
00099
00100
00101
00102 if ( serv->isValid() && !serv->isDeleted() ) {
00103 return serv;
00104 } else {
00105 if (!serv->isDeleted())
00106 kWarning(7012) << "Invalid Service : " << file;
00107 delete serv;
00108 return 0;
00109 }
00110 }
00111
00112 void KBuildServiceFactory::saveHeader(QDataStream &str)
00113 {
00114 KSycocaFactory::saveHeader(str);
00115
00116 str << (qint32) m_nameDictOffset;
00117 str << (qint32) m_relNameDictOffset;
00118 str << (qint32) m_offerListOffset;
00119 str << (qint32) m_menuIdDictOffset;
00120 }
00121
00122 void KBuildServiceFactory::save(QDataStream &str)
00123 {
00124 KSycocaFactory::save(str);
00125
00126 m_nameDictOffset = str.device()->pos();
00127 m_nameDict->save(str);
00128
00129 m_relNameDictOffset = str.device()->pos();
00130 m_relNameDict->save(str);
00131
00132 saveOfferList(str);
00133
00134 m_menuIdDictOffset = str.device()->pos();
00135 m_menuIdDict->save(str);
00136
00137 int endOfFactoryData = str.device()->pos();
00138
00139
00140 saveHeader(str);
00141
00142
00143 str.device()->seek(endOfFactoryData);
00144 }
00145
00146 void KBuildServiceFactory::collectInheritedServices()
00147 {
00148
00149
00150
00151
00152 QSet<KMimeType::Ptr> visitedMimes;
00153 const KMimeType::List allMimeTypes = m_mimeTypeFactory->allMimeTypes();
00154 KMimeType::List::const_iterator itm = allMimeTypes.begin();
00155 for( ; itm != allMimeTypes.end(); ++itm ) {
00156 const KMimeType::Ptr mimeType = *itm;
00157 collectInheritedServices(mimeType, visitedMimes);
00158 }
00159
00160 }
00161
00162 void KBuildServiceFactory::collectInheritedServices(KMimeType::Ptr mimeType, QSet<KMimeType::Ptr>& visitedMimes)
00163 {
00164 if (visitedMimes.contains(mimeType))
00165 return;
00166 visitedMimes.insert(mimeType);
00167
00168
00169
00170
00171 int mimeTypeInheritanceLevel = 0;
00172
00173 const QString mimeTypeName = mimeType->name();
00174 Q_FOREACH(const QString& parent, mimeType->parentMimeTypes()) {
00175 const KMimeType::Ptr parentMimeType =
00176 m_mimeTypeFactory->findMimeTypeByName(parent, KMimeType::ResolveAliases);
00177
00178 if ( parentMimeType ) {
00179 collectInheritedServices(parentMimeType, visitedMimes);
00180
00181 ++mimeTypeInheritanceLevel;
00182 const QList<KServiceOffer>& offers = m_offerHash.offersFor(parent);
00183 QList<KServiceOffer>::const_iterator itserv = offers.begin();
00184 const QList<KServiceOffer>::const_iterator endserv = offers.end();
00185 for ( ; itserv != endserv; ++itserv ) {
00186 if (!m_offerHash.hasRemovedOffer(mimeTypeName, (*itserv).service())) {
00187 KServiceOffer offer(*itserv);
00188 offer.setMimeTypeInheritanceLevel(mimeTypeInheritanceLevel);
00189
00190 m_offerHash.addServiceOffer( mimeTypeName, offer );
00191 }
00192 }
00193 } else {
00194 kWarning(7012) << "parent mimetype not found:" << parent;
00195 break;
00196 }
00197 }
00198 }
00199
00200 void KBuildServiceFactory::postProcessServices()
00201 {
00202
00203
00204
00205
00206 KSycocaEntryDict::Iterator itserv = m_entryDict->begin();
00207 const KSycocaEntryDict::Iterator endserv = m_entryDict->end();
00208 for( ; itserv != endserv ; ++itserv ) {
00209
00210 KSycocaEntry::Ptr entry = *itserv;
00211 KService::Ptr service = KService::Ptr::staticCast(entry);
00212
00213 if (!service->isDeleted()) {
00214 const QString parent = service->parentApp();
00215 if (!parent.isEmpty())
00216 m_serviceGroupFactory->addNewChild(parent, KSycocaEntry::Ptr::staticCast(service));
00217 }
00218
00219 const QString name = service->desktopEntryName();
00220 m_nameDict->add(name, entry);
00221 m_nameMemoryHash.insert(name, service);
00222
00223 const QString relName = service->entryPath();
00224
00225 m_relNameDict->add(relName, entry);
00226 m_relNameMemoryHash.insert(relName, service);
00227
00228 const QString menuId = service->menuId();
00229 if (!menuId.isEmpty()) {
00230 m_menuIdDict->add(menuId, entry);
00231 m_menuIdMemoryHash.insert(menuId, service);
00232 }
00233 }
00234 populateServiceTypes();
00235 }
00236
00237 void KBuildServiceFactory::populateServiceTypes()
00238 {
00239
00240 KSycocaEntryDict::Iterator itserv = m_entryDict->begin();
00241 const KSycocaEntryDict::Iterator endserv = m_entryDict->end();
00242 for( ; itserv != endserv ; ++itserv ) {
00243
00244 KService::Ptr service = KService::Ptr::staticCast(*itserv);
00245 QVector<KService::ServiceTypeAndPreference> serviceTypeList = service->_k_accessServiceTypes();
00246
00247
00248
00249
00250 for (int i = 0; i < serviceTypeList.count() ; ++i) {
00251 const QString stName = serviceTypeList[i].serviceType;
00252
00253 KServiceType::Ptr serviceType = KServiceType::serviceType(stName);
00254 if (!serviceType) {
00255 serviceType = KServiceType::Ptr::staticCast(m_mimeTypeFactory->findMimeTypeByName(stName, KMimeType::ResolveAliases));
00256 }
00257
00258
00259
00260 #if 0
00261 if (!serviceType) {
00262 if ( stName == QLatin1String( "all/all" ) ) {
00263 hasAllAll = true;
00264 continue;
00265 } else if ( stName == QLatin1String( "all/allfiles" ) ) {
00266 hasAllFiles = true;
00267 continue;
00268 }
00269 }
00270 #endif
00271
00272 if (!serviceType) {
00273 kDebug(7021) << service->entryPath() << "specifies undefined mimetype/servicetype" << stName;
00274 continue;
00275 }
00276
00277 const int preference = serviceTypeList[i].preference;
00278 const QString parent = serviceType->parentServiceType();
00279 if (!parent.isEmpty())
00280 serviceTypeList.append(KService::ServiceTypeAndPreference(preference, parent));
00281
00282
00283 m_offerHash.addServiceOffer(stName, KServiceOffer(service, preference, 0, service->allowAsDefault()) );
00284 }
00285 }
00286
00287
00288 KMimeAssociations mimeAssociations(m_offerHash);
00289 mimeAssociations.parseAllMimeAppsList();
00290
00291
00292 collectInheritedServices();
00293
00294
00295
00296 int offersOffset = 0;
00297 const int offerEntrySize = sizeof( qint32 ) * 4;
00298
00299 KSycocaEntryDict::const_iterator itstf = m_serviceTypeFactory->entryDict()->constBegin();
00300 const KSycocaEntryDict::const_iterator endstf = m_serviceTypeFactory->entryDict()->constEnd();
00301 for( ; itstf != endstf; ++itstf ) {
00302 KServiceType::Ptr entry = KServiceType::Ptr::staticCast( *itstf );
00303 const int numOffers = m_offerHash.offersFor(entry->name()).count();
00304 if ( numOffers ) {
00305 entry->setServiceOffersOffset( offersOffset );
00306 offersOffset += offerEntrySize * numOffers;
00307 }
00308 }
00309 KSycocaEntryDict::const_iterator itmtf = m_mimeTypeFactory->entryDict()->constBegin();
00310 const KSycocaEntryDict::const_iterator endmtf = m_mimeTypeFactory->entryDict()->constEnd();
00311 for( ; itmtf != endmtf; ++itmtf )
00312 {
00313 KMimeType::Ptr entry = KMimeType::Ptr::staticCast( *itmtf );
00314 const int numOffers = m_offerHash.offersFor(entry->name()).count();
00315 if ( numOffers ) {
00316 entry->setServiceOffersOffset( offersOffset );
00317 offersOffset += offerEntrySize * numOffers;
00318 }
00319 }
00320 }
00321
00322 void KBuildServiceFactory::saveOfferList(QDataStream &str)
00323 {
00324 m_offerListOffset = str.device()->pos();
00325
00326
00327 KSycocaEntryDict::const_iterator itstf = m_serviceTypeFactory->entryDict()->constBegin();
00328 const KSycocaEntryDict::const_iterator endstf = m_serviceTypeFactory->entryDict()->constEnd();
00329 for( ; itstf != endstf; ++itstf ) {
00330
00331 const KServiceType::Ptr entry = KServiceType::Ptr::staticCast( *itstf );
00332 Q_ASSERT( entry );
00333
00334 QList<KServiceOffer> offers = m_offerHash.offersFor(entry->name());
00335 qStableSort( offers );
00336
00337 for(QList<KServiceOffer>::const_iterator it2 = offers.constBegin();
00338 it2 != offers.constEnd(); ++it2) {
00339
00340
00341 str << (qint32) entry->offset();
00342 str << (qint32) (*it2).service()->offset();
00343 str << (qint32) (*it2).preference();
00344 str << (qint32) 0;
00345
00346 }
00347 }
00348
00349
00350 KSycocaEntryDict::const_iterator itmtf = m_mimeTypeFactory->entryDict()->constBegin();
00351 const KSycocaEntryDict::const_iterator endmtf = m_mimeTypeFactory->entryDict()->constEnd();
00352 for( ; itmtf != endmtf; ++itmtf ) {
00353
00354 const KMimeType::Ptr entry = KMimeType::Ptr::staticCast( *itmtf );
00355 Q_ASSERT( entry );
00356 QList<KServiceOffer> offers = m_offerHash.offersFor(entry->name());
00357 qStableSort( offers );
00358
00359 for(QList<KServiceOffer>::const_iterator it2 = offers.constBegin();
00360 it2 != offers.constEnd(); ++it2) {
00361
00362 Q_ASSERT((*it2).service()->offset() != 0);
00363 str << (qint32) entry->offset();
00364 str << (qint32) (*it2).service()->offset();
00365 str << (qint32) (*it2).preference();
00366 str << (qint32) (*it2).mimeTypeInheritanceLevel();
00367
00368 }
00369 }
00370
00371 str << (qint32) 0;
00372 }
00373
00374 void KBuildServiceFactory::addEntry(const KSycocaEntry::Ptr& newEntry)
00375 {
00376 Q_ASSERT(newEntry);
00377 if (m_dupeDict.contains(newEntry))
00378 return;
00379
00380 const KService::Ptr service = KService::Ptr::staticCast( newEntry );
00381 m_dupeDict.insert(newEntry);
00382 KSycocaFactory::addEntry(newEntry);
00383 }