File indexing completed on 2024-05-05 17:44:59

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