File indexing completed on 2024-11-03 06:49:08
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2000 Torben Weis <weis@kde.org> 0004 SPDX-FileCopyrightText: 2006-2020 David Faure <faure@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "kapplicationtrader.h" 0010 0011 #include "kmimetypefactory_p.h" 0012 #include "kservicefactory_p.h" 0013 #include "ksycoca.h" 0014 #include "ksycoca_p.h" 0015 #include "servicesdebug.h" 0016 0017 #include <QMimeDatabase> 0018 0019 #include <KConfigGroup> 0020 #include <KSharedConfig> 0021 0022 static KService::List mimeTypeSycocaServiceOffers(const QString &mimeType) 0023 { 0024 KService::List lst; 0025 QMimeDatabase db; 0026 QString mime = db.mimeTypeForName(mimeType).name(); 0027 if (mime.isEmpty()) { 0028 if (!mimeType.startsWith(QLatin1String("x-scheme-handler/"))) { // don't warn for unknown scheme handler mimetypes 0029 qCWarning(SERVICES) << "KApplicationTrader: mimeType" << mimeType << "not found"; 0030 return lst; // empty 0031 } 0032 mime = mimeType; 0033 } 0034 KSycoca::self()->ensureCacheValid(); 0035 KMimeTypeFactory *factory = KSycocaPrivate::self()->mimeTypeFactory(); 0036 const int offset = factory->entryOffset(mime); 0037 if (!offset) { 0038 qCWarning(SERVICES) << "KApplicationTrader: mimeType" << mimeType << "not found"; 0039 return lst; // empty 0040 } 0041 const int serviceOffersOffset = factory->serviceOffersOffset(mime); 0042 if (serviceOffersOffset > -1) { 0043 lst = KSycocaPrivate::self()->serviceFactory()->serviceOffers(offset, serviceOffersOffset); 0044 } 0045 return lst; 0046 } 0047 0048 static void applyFilter(KService::List &list, KApplicationTrader::FilterFunc filterFunc, bool mustShowInCurrentDesktop) 0049 { 0050 if (list.isEmpty()) { 0051 return; 0052 } 0053 0054 // Find all services matching the constraint 0055 // and remove the other ones 0056 auto removeFunc = [&](const KService::Ptr &serv) { 0057 return (filterFunc && !filterFunc(serv)) || (mustShowInCurrentDesktop && !serv->showInCurrentDesktop()); 0058 }; 0059 list.erase(std::remove_if(list.begin(), list.end(), removeFunc), list.end()); 0060 } 0061 0062 KService::List KApplicationTrader::query(FilterFunc filterFunc) 0063 { 0064 // Get all applications 0065 KSycoca::self()->ensureCacheValid(); 0066 KService::List lst = KSycocaPrivate::self()->serviceFactory()->allServices(); 0067 0068 applyFilter(lst, filterFunc, true); // true = filter out service with NotShowIn=KDE or equivalent 0069 0070 qCDebug(SERVICES) << "query returning" << lst.count() << "offers"; 0071 return lst; 0072 } 0073 0074 KService::List KApplicationTrader::queryByMimeType(const QString &mimeType, FilterFunc filterFunc) 0075 { 0076 // Get all services of this MIME type. 0077 KService::List lst = mimeTypeSycocaServiceOffers(mimeType); 0078 0079 applyFilter(lst, filterFunc, false); // false = allow NotShowIn=KDE services listed in mimeapps.list 0080 0081 qCDebug(SERVICES) << "query for mimeType" << mimeType << "returning" << lst.count() << "offers"; 0082 return lst; 0083 } 0084 0085 KService::Ptr KApplicationTrader::preferredService(const QString &mimeType) 0086 { 0087 const KService::List offers = queryByMimeType(mimeType); 0088 if (!offers.isEmpty()) { 0089 return offers.at(0); 0090 } 0091 return KService::Ptr(); 0092 } 0093 0094 void KApplicationTrader::setPreferredService(const QString &mimeType, const KService::Ptr service) 0095 { 0096 if (mimeType.isEmpty() || !(service && service->isValid())) { 0097 return; 0098 } 0099 KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation); 0100 0101 // Save the default application according to mime-apps-spec 1.0 0102 KConfigGroup defaultApp(profile, QStringLiteral("Default Applications")); 0103 defaultApp.writeXdgListEntry(mimeType, QStringList(service->storageId())); 0104 0105 KConfigGroup addedApps(profile, QStringLiteral("Added Associations")); 0106 QStringList apps = addedApps.readXdgListEntry(mimeType); 0107 apps.removeAll(service->storageId()); 0108 apps.prepend(service->storageId()); // make it the preferred app 0109 addedApps.writeXdgListEntry(mimeType, apps); 0110 0111 profile->sync(); 0112 0113 // Also make sure the "auto embed" setting for this MIME type is off 0114 KSharedConfig::Ptr fileTypesConfig = KSharedConfig::openConfig(QStringLiteral("filetypesrc"), KConfig::NoGlobals); 0115 fileTypesConfig->group(QStringLiteral("EmbedSettings")).writeEntry(QStringLiteral("embed-") + mimeType, false); 0116 fileTypesConfig->sync(); 0117 } 0118 0119 bool KApplicationTrader::isSubsequence(const QString &pattern, const QString &text, Qt::CaseSensitivity cs) 0120 { 0121 if (pattern.isEmpty()) { 0122 return false; 0123 } 0124 const bool chk_case = cs == Qt::CaseSensitive; 0125 0126 auto textIt = text.cbegin(); 0127 auto patternIt = pattern.cbegin(); 0128 for (; textIt != text.cend() && patternIt != pattern.cend(); ++textIt) { 0129 if ((chk_case && *textIt == *patternIt) || (!chk_case && textIt->toLower() == patternIt->toLower())) { 0130 ++patternIt; 0131 } 0132 } 0133 return patternIt == pattern.cend(); 0134 }