File indexing completed on 2023-09-24 04:11:07
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2000 Torben Weis <weis@kde.org> 0004 SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kmimetypetrader.h" 0010 0011 #include "kmimetypefactory_p.h" 0012 #include "kservicefactory_p.h" 0013 #include "kservicetype.h" 0014 #include "kservicetypeprofile.h" 0015 #include "kservicetypetrader.h" 0016 #include "ksycoca.h" 0017 #include "ksycoca_p.h" 0018 #include "servicesdebug.h" 0019 #include <QMimeDatabase> 0020 0021 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 82) 0022 0023 class KMimeTypeTraderPrivate 0024 { 0025 public: 0026 KMimeTypeTraderPrivate() 0027 { 0028 } 0029 }; 0030 0031 class KMimeTypeTraderSingleton 0032 { 0033 public: 0034 KMimeTypeTrader instance; 0035 }; 0036 0037 Q_GLOBAL_STATIC(KMimeTypeTraderSingleton, s_self) 0038 0039 KMimeTypeTrader *KMimeTypeTrader::self() 0040 { 0041 return &s_self()->instance; 0042 } 0043 0044 KMimeTypeTrader::KMimeTypeTrader() 0045 : d(new KMimeTypeTraderPrivate()) 0046 { 0047 } 0048 0049 KMimeTypeTrader::~KMimeTypeTrader() 0050 { 0051 delete d; 0052 } 0053 0054 static KServiceOfferList mimeTypeSycocaOffers(const QString &mimeType) 0055 { 0056 KServiceOfferList lst; 0057 0058 QMimeDatabase db; 0059 QString mime = db.mimeTypeForName(mimeType).name(); 0060 if (mime.isEmpty()) { 0061 if (!mimeType.startsWith(QLatin1String("x-scheme-handler/"))) { // don't warn for unknown scheme handler MIME types 0062 qCWarning(SERVICES) << "KMimeTypeTrader: MIME type" << mimeType << "not found"; 0063 return lst; // empty 0064 } 0065 mime = mimeType; 0066 } 0067 KSycoca::self()->ensureCacheValid(); 0068 KMimeTypeFactory *factory = KSycocaPrivate::self()->mimeTypeFactory(); 0069 const int offset = factory->entryOffset(mime); 0070 if (!offset) { // shouldn't happen, now that we know the MIME type exists 0071 if (!mimeType.startsWith(QLatin1String("x-scheme-handler/"))) { // don't warn for unknown scheme handler MIME types 0072 qCDebug(SERVICES) << "KMimeTypeTrader: no entry offset for" << mimeType; 0073 } 0074 return lst; // empty 0075 } 0076 0077 const int serviceOffersOffset = factory->serviceOffersOffset(mime); 0078 if (serviceOffersOffset > -1) { 0079 lst = KSycocaPrivate::self()->serviceFactory()->offers(offset, serviceOffersOffset); 0080 } 0081 return lst; 0082 } 0083 0084 static KService::List mimeTypeSycocaServiceOffers(const QString &mimeType) 0085 { 0086 KService::List lst; 0087 QMimeDatabase db; 0088 QString mime = db.mimeTypeForName(mimeType).name(); 0089 if (mime.isEmpty()) { 0090 if (!mimeType.startsWith(QLatin1String("x-scheme-handler/"))) { // don't warn for unknown scheme handler MIME types 0091 qCWarning(SERVICES) << "KMimeTypeTrader: MIME type" << mimeType << "not found"; 0092 return lst; // empty 0093 } 0094 mime = mimeType; 0095 } 0096 KSycoca::self()->ensureCacheValid(); 0097 KMimeTypeFactory *factory = KSycocaPrivate::self()->mimeTypeFactory(); 0098 const int offset = factory->entryOffset(mime); 0099 if (!offset) { 0100 qCWarning(SERVICES) << "KMimeTypeTrader: MIME type" << mimeType << "not found"; 0101 return lst; // empty 0102 } 0103 const int serviceOffersOffset = factory->serviceOffersOffset(mime); 0104 if (serviceOffersOffset > -1) { 0105 lst = KSycocaPrivate::self()->serviceFactory()->serviceOffers(offset, serviceOffersOffset); 0106 } 0107 return lst; 0108 } 0109 0110 #define CHECK_SERVICETYPE(genericServiceTypePtr) \ 0111 if (!genericServiceTypePtr) { \ 0112 qCWarning(SERVICES) << "KMimeTypeTrader: couldn't find service type" << genericServiceType \ 0113 << "\nPlease ensure that the .desktop file for it is installed; then run kbuildsycoca5."; \ 0114 return; \ 0115 } 0116 0117 /** 0118 * Filter the offers for the requested MIME type for the @p genericServiceType. 0119 * 0120 * @param list list of offers (key=service, value=initialPreference) 0121 * @param genericServiceType the generic service type (e.g. "Application" or "KParts/ReadOnlyPart") 0122 */ 0123 void KMimeTypeTrader::filterMimeTypeOffers(KServiceOfferList &list, const QString &genericServiceType) // static, internal 0124 { 0125 KServiceType::Ptr genericServiceTypePtr = KServiceType::serviceType(genericServiceType); 0126 CHECK_SERVICETYPE(genericServiceTypePtr); 0127 0128 KSycoca::self()->ensureCacheValid(); 0129 0130 QMutableListIterator<KServiceOffer> it(list); 0131 while (it.hasNext()) { 0132 const KService::Ptr servPtr = it.next().service(); 0133 // Expand servPtr->hasServiceType( genericServiceTypePtr ) to avoid lookup each time: 0134 if (!KSycocaPrivate::self()->serviceFactory()->hasOffer(genericServiceTypePtr, servPtr) // 0135 || !servPtr->showInCurrentDesktop()) { 0136 it.remove(); 0137 } 0138 } 0139 } 0140 0141 void KMimeTypeTrader::filterMimeTypeOffers(KService::List &list, const QString &genericServiceType) // static, internal 0142 { 0143 KServiceType::Ptr genericServiceTypePtr = KServiceType::serviceType(genericServiceType); 0144 CHECK_SERVICETYPE(genericServiceTypePtr); 0145 0146 KSycoca::self()->ensureCacheValid(); 0147 0148 QMutableListIterator<KService::Ptr> it(list); 0149 while (it.hasNext()) { 0150 const KService::Ptr servPtr = it.next(); 0151 // Expand servPtr->hasServiceType( genericServiceTypePtr ) to avoid lookup each time: 0152 if (!KSycocaPrivate::self()->serviceFactory()->hasOffer(genericServiceTypePtr->offset(), 0153 genericServiceTypePtr->serviceOffersOffset(), 0154 servPtr->offset()) 0155 || !servPtr->showInCurrentDesktop()) { 0156 it.remove(); 0157 } 0158 } 0159 } 0160 0161 #undef CHECK_SERVICETYPE 0162 0163 KService::List KMimeTypeTrader::query(const QString &mimeType, const QString &genericServiceType, const QString &constraint) const 0164 { 0165 // Get all services of this mime type. 0166 KService::List lst = mimeTypeSycocaServiceOffers(mimeType); 0167 filterMimeTypeOffers(lst, genericServiceType); 0168 0169 KServiceTypeTrader::applyConstraints(lst, constraint); 0170 0171 // qCDebug(SERVICES) << "query for MIME type " << mimeType << ", " << genericServiceType 0172 // << " : returning " << lst.count() << " offers"; 0173 return lst; 0174 } 0175 0176 KService::Ptr KMimeTypeTrader::preferredService(const QString &mimeType, const QString &genericServiceType) 0177 { 0178 // First, get all offers known to ksycoca. 0179 KServiceOfferList offers = mimeTypeSycocaOffers(mimeType); 0180 0181 // Assign preferences from the profile to those offers - and filter for genericServiceType 0182 Q_ASSERT(!genericServiceType.isEmpty()); 0183 filterMimeTypeOffers(offers, genericServiceType); 0184 0185 auto itOff = offers.constBegin(); 0186 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 67) 0187 // Look for the first one that is allowed as default. 0188 // Since the allowed-as-default are first anyway, we only have 0189 // to look at the first one to know. 0190 if (itOff != offers.constEnd() && (*itOff).allowAsDefault()) { 0191 #else 0192 if (itOff != offers.constEnd()) { 0193 #endif 0194 return (*itOff).service(); 0195 } 0196 0197 // qCDebug(SERVICES) << "No offers, or none allowed as default"; 0198 return KService::Ptr(); 0199 } 0200 0201 #endif