File indexing completed on 2024-05-12 05:38:17
0001 /* 0002 SPDX-FileCopyrightText: 2014 Vishesh Handa <me@vhanda.in> 0003 SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #include "baloosearchrunner.h" 0009 0010 #include <KLocalizedString> 0011 #include <QApplication> 0012 #include <QDBusConnection> 0013 #include <QDir> 0014 #include <QIcon> 0015 #include <QMimeData> 0016 #include <QMimeDatabase> 0017 #include <QTimer> 0018 0019 #include <Baloo/IndexerConfig> 0020 #include <Baloo/Query> 0021 0022 #include <KIO/JobUiDelegate> 0023 #include <KIO/JobUiDelegateFactory> 0024 #include <KIO/OpenFileManagerWindowJob> 0025 #include <KIO/OpenUrlJob> 0026 #include <KNotificationJobUiDelegate> 0027 #include <KShell> 0028 0029 #include "krunner1adaptor.h" 0030 0031 static const QString s_openParentDirId = QStringLiteral("openParentDir"); 0032 0033 int main(int argc, char **argv) 0034 { 0035 QCoreApplication::setAttribute(Qt::AA_DisableSessionManager); 0036 QApplication::setQuitOnLastWindowClosed(false); 0037 QApplication app(argc, argv); // KRun needs widgets for error message boxes 0038 SearchRunner r; 0039 return app.exec(); 0040 } 0041 0042 SearchRunner::SearchRunner(QObject *parent) 0043 : QObject(parent) 0044 { 0045 new Krunner1Adaptor(this); 0046 qDBusRegisterMetaType<RemoteMatch>(); 0047 qDBusRegisterMetaType<RemoteMatches>(); 0048 qDBusRegisterMetaType<RemoteAction>(); 0049 qDBusRegisterMetaType<RemoteActions>(); 0050 QDBusConnection::sessionBus().registerObject(QStringLiteral("/runner"), this); 0051 QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.runners.baloo")); 0052 } 0053 0054 RemoteActions SearchRunner::Actions() 0055 { 0056 Baloo::IndexerConfig config; 0057 if (!config.fileIndexingEnabled()) { 0058 sendErrorReply(QDBusError::ErrorType::NotSupported); 0059 } 0060 return RemoteActions({RemoteAction{s_openParentDirId, i18n("Open Containing Folder"), QStringLiteral("document-open-folder")}}); 0061 } 0062 0063 RemoteMatches SearchRunner::Match(const QString &searchTerm) 0064 { 0065 Baloo::IndexerConfig config; 0066 if (!config.fileIndexingEnabled()) { 0067 sendErrorReply(QDBusError::ErrorType::NotSupported); 0068 return {}; 0069 } 0070 0071 // Do not try to show results for queries starting with = 0072 // this should trigger the calculator, but the AdvancedQueryParser::parse method 0073 // in baloo interpreted it as an operator, BUG 345134 0074 if (searchTerm.startsWith(QLatin1Char('='))) { 0075 return RemoteMatches(); 0076 } 0077 0078 // Filter out duplicates 0079 QSet<QUrl> foundUrls; 0080 0081 RemoteMatches matches; 0082 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Audio")), i18n("Audios"), foundUrls); 0083 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Image")), i18n("Images"), foundUrls); 0084 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Video")), i18n("Videos"), foundUrls); 0085 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Spreadsheet")), i18n("Spreadsheets"), foundUrls); 0086 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Presentation")), i18n("Presentations"), foundUrls); 0087 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Folder")), i18n("Folders"), foundUrls); 0088 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Document")), i18n("Documents"), foundUrls); 0089 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Archive")), i18n("Archives"), foundUrls); 0090 matches << matchInternal(searchTerm, QStringList(QStringLiteral("Text")), i18n("Texts"), foundUrls); 0091 matches << matchInternal(searchTerm, QStringList(), i18n("Files"), foundUrls); 0092 0093 return matches; 0094 } 0095 0096 RemoteMatches SearchRunner::matchInternal(const QString &searchTerm, const QStringList &types, const QString &category, QSet<QUrl> &foundUrls) 0097 { 0098 Baloo::Query query; 0099 query.setSearchString(searchTerm); 0100 query.setTypes(types); 0101 query.setLimit(10); 0102 0103 Baloo::ResultIterator it = query.exec(); 0104 0105 RemoteMatches matches; 0106 0107 QMimeDatabase mimeDb; 0108 0109 // KRunner is absolutely daft and allows plugins to set the global 0110 // relevance levels. so Baloo should not set the relevance of results too 0111 // high because then Applications will often appear after if the application 0112 // runner has not a higher relevance. So stupid. 0113 // Each runner plugin should not have to know about the others. 0114 // Anyway, that's why we're starting with .75 0115 float relevance = .75; 0116 while (it.next()) { 0117 RemoteMatch match; 0118 QString localUrl = it.filePath(); 0119 const QUrl url = QUrl::fromLocalFile(localUrl); 0120 0121 if (foundUrls.contains(url)) { 0122 continue; 0123 } 0124 0125 foundUrls.insert(url); 0126 0127 match.id = url.toString(); 0128 match.text = url.fileName(); 0129 match.iconName = mimeDb.mimeTypeForFile(localUrl).iconName(); 0130 match.relevance = relevance; 0131 const QString baseName = QFileInfo(url.fileName()).completeBaseName(); 0132 bool isExactMatch = url.fileName().compare(searchTerm, Qt::CaseInsensitive) == 0 || baseName.compare(searchTerm, Qt::CaseInsensitive) == 0; 0133 bool isPossibleMatch = url.fileName().contains(searchTerm, Qt::CaseInsensitive); 0134 KRunner::QueryMatch::CategoryRelevance categoryRelevance = isExactMatch ? KRunner::QueryMatch::CategoryRelevance::Highest 0135 : isPossibleMatch ? KRunner::QueryMatch::CategoryRelevance::High 0136 : KRunner::QueryMatch::CategoryRelevance::Low; 0137 match.categoryRelevance = qToUnderlying(categoryRelevance); 0138 QVariantMap properties; 0139 0140 QString folderPath = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile(); 0141 folderPath = KShell::tildeCollapse(folderPath); 0142 0143 properties[QStringLiteral("urls")] = QStringList({QString::fromLocal8Bit(url.toEncoded())}); 0144 properties[QStringLiteral("subtext")] = folderPath; 0145 properties[QStringLiteral("category")] = category; 0146 0147 match.properties = properties; 0148 relevance -= 0.05; 0149 0150 matches << match; 0151 } 0152 0153 return matches; 0154 } 0155 0156 void SearchRunner::Run(const QString &id, const QString &actionId) 0157 { 0158 const QUrl url(id); 0159 if (actionId == s_openParentDirId) { 0160 KIO::highlightInFileManager({url}); 0161 return; 0162 } 0163 0164 auto *job = new KIO::OpenUrlJob(url); 0165 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, QApplication::activeWindow())); 0166 job->setShowOpenOrExecuteDialog(true); 0167 job->start(); 0168 }