File indexing completed on 2024-04-28 15:29:49

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