diff --git a/runners/baloo/CMakeLists.txt b/runners/baloo/CMakeLists.txt --- a/runners/baloo/CMakeLists.txt +++ b/runners/baloo/CMakeLists.txt @@ -1,20 +1,33 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_runner_baloosearch5\") -add_library(krunner_baloosearchrunner MODULE baloosearchrunner.cpp) -target_link_libraries(krunner_baloosearchrunner +set(baloosearchrunner_SRCS + baloosearchrunner.cpp) + +qt5_add_dbus_adaptor(baloosearchrunner_SRCS "org.kde.krunner1.xml" baloosearchrunner.h SearchRunner) +add_executable(baloorunner ${baloosearchrunner_SRCS}) + +target_link_libraries(baloorunner KF5::Runner KF5::KIOWidgets KF5::I18n KF5::Baloo + Qt5::DBus ) +configure_file(org.kde.baloorunner.service.in + ${CMAKE_CURRENT_BINARY_DIR}/org.kde.baloorunner.service) + + install( - TARGETS krunner_baloosearchrunner - DESTINATION ${KDE_INSTALL_PLUGINDIR} + TARGETS baloorunner + DESTINATION ${LIBEXEC_INSTALL_DIR} ) install( FILES plasma-runner-baloosearch.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.baloorunner.service + DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}) diff --git a/runners/baloo/baloosearchrunner.h b/runners/baloo/baloosearchrunner.h --- a/runners/baloo/baloosearchrunner.h +++ b/runners/baloo/baloosearchrunner.h @@ -1,6 +1,7 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2014 Vishesh Handa + * Copyright (C) 2017 David Edmundson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,35 +22,35 @@ #ifndef _BALOO_SEARCH_RUNNER_H_ #define _BALOO_SEARCH_RUNNER_H_ -#include +#include +#include +#include + #include +#include "dbusutils_p.h" -class QMimeData; +class QTimer; -class SearchRunner : public Plasma::AbstractRunner +class SearchRunner : public QObject, protected QDBusContext { Q_OBJECT public: - SearchRunner(QObject* parent, const QVariantList& args); - SearchRunner(QObject* parent, const QString& serviceId = QString()); + SearchRunner(QObject* parent=0); ~SearchRunner() override; - void match(Plasma::RunnerContext& context) override; - void run(const Plasma::RunnerContext& context, const Plasma::QueryMatch& action) override; - - QStringList categories() const override; - QIcon categoryIcon(const QString& category) const override; - - QList actionsForMatch(const Plasma::QueryMatch &match) override; - QMimeData *mimeDataForMatch(const Plasma::QueryMatch &match) override; - -protected Q_SLOTS: - void init() override; + RemoteActions Actions(); + RemoteMatches Match(const QString &searchTerm); + void Run(const QString &id, const QString &actionId); private: - QList match(Plasma::RunnerContext& context, const QString& type, + void performMatch(); + RemoteMatches matchInternal(const QString &searchTerm, const QString& type, const QString& category); + + QDBusMessage m_lastRequest; + QString m_searchTerm; + QTimer *m_timer; }; #endif // _BALOO_SEARCH_RUNNER_H_ diff --git a/runners/baloo/baloosearchrunner.cpp b/runners/baloo/baloosearchrunner.cpp --- a/runners/baloo/baloosearchrunner.cpp +++ b/runners/baloo/baloosearchrunner.cpp @@ -1,6 +1,7 @@ /* * This file is part of the KDE Baloo Project * Copyright (C) 2014 Vishesh Handa + * Copyright (C) 2017 David Edmundson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,185 +30,162 @@ #include #include #include +#include +#include +#include #include #include #include +#include "dbusutils_p.h" +#include "krunner1adaptor.h" + static const QString s_openParentDirId = QStringLiteral("openParentDir"); -SearchRunner::SearchRunner(QObject* parent, const QVariantList& args) - : Plasma::AbstractRunner(parent, args) +int main (int argc, char **argv) { + Baloo::IndexerConfig config; + if (!config.fileIndexingEnabled()) { + return -1; + } + QApplication::setQuitOnLastWindowClosed(false); + QApplication app(argc, argv); //KRun needs widgets for error message boxes + SearchRunner r; + return app.exec(); } -SearchRunner::SearchRunner(QObject* parent, const QString& serviceId) - : Plasma::AbstractRunner(parent, serviceId) +SearchRunner::SearchRunner(QObject* parent) + : QObject(parent), + m_timer(new QTimer(this)) { -} -void SearchRunner::init() -{ - Plasma::RunnerSyntax syntax(QStringLiteral(":q"), i18n("Search through files, emails and contacts")); + m_timer->setSingleShot(true); + connect(m_timer, &QTimer::timeout, this, &SearchRunner::performMatch); - addAction(s_openParentDirId, QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("Open Containing Folder")); + new Krunner1Adaptor(this); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + QDBusConnection::sessionBus().registerService("org.kde.runners.baloo"); + QDBusConnection::sessionBus().registerObject("/runner", this); } SearchRunner::~SearchRunner() { } - -QStringList SearchRunner::categories() const +RemoteActions SearchRunner::Actions() { - QStringList list; - list << i18n("Audio") - << i18n("Image") - << i18n("Document") - << i18n("Video") - << i18n("Folder"); - - return list; + return RemoteActions({RemoteAction{ + s_openParentDirId, + i18n("Open Containing Folder"), + QStringLiteral("document-open-folder") + }}); } -QIcon SearchRunner::categoryIcon(const QString& category) const +RemoteMatches SearchRunner::Match(const QString& searchTerm) { - if (category == i18n("Audio")) { - return QIcon::fromTheme(QStringLiteral("audio")); - } else if (category == i18n("Image")) { - return QIcon::fromTheme(QStringLiteral("image")); - } else if (category == i18n("Document")) { - return QIcon::fromTheme(QStringLiteral("application-pdf")); - } else if (category == i18n("Video")) { - return QIcon::fromTheme(QStringLiteral("video")); - } else if (category == i18n("Folder")) { - return QIcon::fromTheme(QStringLiteral("folder")); + setDelayedReply(true); + + if (m_lastRequest.type() != QDBusMessage::InvalidMessage) { + QDBusConnection::sessionBus().send(m_lastRequest.createReply(QVariantList())); } - return Plasma::AbstractRunner::categoryIcon(category); -} + m_lastRequest = message(); + m_searchTerm = searchTerm; -QList SearchRunner::match(Plasma::RunnerContext& context, const QString& type, - const QString& category) -{ - Baloo::IndexerConfig config; - if (!config.fileIndexingEnabled()) { - return QList(); + // Baloo (as of 2014-11-20) is single threaded. It has an internal mutex which results in + // queries being queued one after another. Also, Baloo is really really slow for small queries + // For example - on my SSD, it takes about 1.4 seconds for 'f' with an SSD. + // When searching for "fire", it results in "f", "fi", "fir" and then "fire" being searched + // We're therefore hacking around this by having a small delay for very short queries so that + // they do not get queued internally in Baloo + // + int waitTimeMs = 0; + + if (searchTerm.length() <= 3) { + waitTimeMs = 100; } + //we're still using the event delayed call even when the length is < 3 so that if we have multiple Match() calls in our DBus queue, we only process the last one + m_timer->start(waitTimeMs); - if (!context.isValid()) - return QList(); + return RemoteMatches(); +} - const QStringList categories = context.enabledCategories(); - if (!categories.isEmpty() && !categories.contains(category)) - return QList(); +void SearchRunner::performMatch() +{ + RemoteMatches matches; + matches << matchInternal(m_searchTerm, QStringLiteral("Audio"), i18n("Audio")); + matches << matchInternal(m_searchTerm, QStringLiteral("Image"), i18n("Image")); + matches << matchInternal(m_searchTerm, QStringLiteral("Document"), i18n("Document")); + matches << matchInternal(m_searchTerm, QStringLiteral("Video"), i18n("Video")); + matches << matchInternal(m_searchTerm, QStringLiteral("Folder"), i18n("Folder")); + + QDBusConnection::sessionBus().send(m_lastRequest.createReply(QVariant::fromValue(matches))); + m_lastRequest = QDBusMessage(); +} +RemoteMatches SearchRunner::matchInternal(const QString& searchTerm, const QString &type, const QString &category) +{ Baloo::Query query; - query.setSearchString(context.query()); + query.setSearchString(searchTerm); query.setType(type); query.setLimit(10); Baloo::ResultIterator it = query.exec(); - QList matches; + RemoteMatches matches; QMimeDatabase mimeDb; - // KRunner is absolutely retarded and allows plugins to set the global + // KRunner is absolutely daft and allows plugins to set the global // relevance levels. so Baloo should not set the relevance of results too // high because then Applications will often appear after if the application // runner has not a higher relevance. So stupid. // Each runner plugin should not have to know about the others. // Anyway, that's why we're starting with .75 float relevance = .75; - while (context.isValid() && it.next()) { - Plasma::QueryMatch match(this); + while (it.next()) { + RemoteMatch match; QString localUrl = it.filePath(); const QUrl url = QUrl::fromLocalFile(localUrl); - - QString iconName = mimeDb.mimeTypeForFile(localUrl).iconName(); - match.setIconName(iconName); - match.setId(it.filePath()); - match.setText(url.fileName()); - match.setData(url); - match.setType(Plasma::QueryMatch::PossibleMatch); - match.setMatchCategory(category); - match.setRelevance(relevance); - relevance -= 0.05; + match.id = it.filePath(); + match.text = url.fileName(); + match.iconName = mimeDb.mimeTypeForFile(localUrl).iconName(); + match.relevance = relevance; + match.type = Plasma::QueryMatch::PossibleMatch; + QVariantMap properties; QString folderPath = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile(); if (folderPath.startsWith(QDir::homePath())) { folderPath.replace(0, QDir::homePath().length(), QStringLiteral("~")); } - match.setSubtext(folderPath); - matches << match; - } + properties["urls"] = QStringList({url.toEncoded()}); + properties["subtext"] = folderPath; + properties["category"] = category; - return matches; -} + match.properties = properties; + relevance -= 0.05; -void SearchRunner::match(Plasma::RunnerContext& context) -{ - const QString text = context.query(); - // - // Baloo (as of 2014-11-20) is single threaded. It has an internal mutex which results in - // queries being queued one after another. Also, Baloo is really really slow for small queries - // For example - on my SSD, it takes about 1.4 seconds for 'f' with an SSD. - // When searching for "fire", it results in "f", "fi", "fir" and then "fire" being searched - // We're therefore hacking around this by having a small delay for very short queries so that - // they do not get queued internally in Baloo - // - if (text.length() <= 3) { - QEventLoop loop; - QTimer timer; - connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); - timer.setSingleShot(true); - timer.start(100); - loop.exec(); - - if (!context.isValid()) { - return; - } + matches << match; } - QList matches; - matches << match(context, QStringLiteral("Audio"), i18n("Audio")); - matches << match(context, QStringLiteral("Image"), i18n("Image")); - matches << match(context, QStringLiteral("Document"), i18n("Document")); - matches << match(context, QStringLiteral("Video"), i18n("Video")); - matches << match(context, QStringLiteral("Folder"), i18n("Folder")); - - context.addMatches(matches); + return matches; } -void SearchRunner::run(const Plasma::RunnerContext&, const Plasma::QueryMatch& match) +void SearchRunner::Run(const QString& id, const QString& actionId) { - const QUrl url = match.data().toUrl(); - - if (match.selectedAction() && match.selectedAction() == action(s_openParentDirId)) { + const QUrl url = QUrl::fromLocalFile(id); + if (actionId == s_openParentDirId) { KIO::highlightInFileManager({url}); return; } new KRun(url, 0); } -QList SearchRunner::actionsForMatch(const Plasma::QueryMatch &match) -{ - Q_UNUSED(match) - - return {action(s_openParentDirId)}; -} - -QMimeData *SearchRunner::mimeDataForMatch(const Plasma::QueryMatch &match) -{ - QMimeData *result = new QMimeData(); - result->setUrls({match.data().toUrl()}); - return result; -} - -K_EXPORT_PLASMA_RUNNER(baloosearchrunner, SearchRunner) - #include "baloosearchrunner.moc" diff --git a/runners/baloo/dbusutils_p.h b/runners/baloo/dbusutils_p.h new file mode 100644 --- /dev/null +++ b/runners/baloo/dbusutils_p.h @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include +#include +#include + +struct RemoteMatch +{ + //sssuda{sv} + QString id; + QString text; + QString iconName; + Plasma::QueryMatch::Type type = Plasma::QueryMatch::NoMatch; + qreal relevance = 0; + QVariantMap properties; +}; + +typedef QList RemoteMatches; + +struct RemoteAction +{ + QString id; + QString text; + QString iconName; +}; + +typedef QList RemoteActions; + +inline QDBusArgument &operator<< (QDBusArgument &argument, const RemoteMatch &match) { + argument.beginStructure(); + argument << match.id; + argument << match.text; + argument << match.iconName; + argument << match.type; + argument << match.relevance; + argument << match.properties; + argument.endStructure(); + return argument; +} + +inline const QDBusArgument &operator>>(const QDBusArgument &argument, RemoteMatch &match) { + argument.beginStructure(); + argument >> match.id; + argument >> match.text; + argument >> match.iconName; + uint type; + argument >> type; + match.type = (Plasma::QueryMatch::Type)type; + argument >> match.relevance; + argument >> match.properties; + argument.endStructure(); + + return argument; +} + +inline QDBusArgument &operator<< (QDBusArgument &argument, const RemoteAction &action) +{ + argument.beginStructure(); + argument << action.id; + argument << action.text; + argument << action.iconName; + argument.endStructure(); + return argument; +} + +inline const QDBusArgument &operator>>(const QDBusArgument &argument, RemoteAction &action) { + argument.beginStructure(); + argument >> action.id; + argument >> action.text; + argument >> action.iconName; + argument.endStructure(); + return argument; +} + +Q_DECLARE_METATYPE(RemoteMatch); +Q_DECLARE_METATYPE(RemoteMatches); +Q_DECLARE_METATYPE(RemoteAction); +Q_DECLARE_METATYPE(RemoteActions); + diff --git a/runners/baloo/org.kde.baloorunner.service.in b/runners/baloo/org.kde.baloorunner.service.in new file mode 100644 --- /dev/null +++ b/runners/baloo/org.kde.baloorunner.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.kde.runners.baloo +Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/baloorunner diff --git a/runners/baloo/org.kde.krunner1.xml b/runners/baloo/org.kde.krunner1.xml new file mode 100644 --- /dev/null +++ b/runners/baloo/org.kde.krunner1.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/runners/baloo/plasma-runner-baloosearch.desktop b/runners/baloo/plasma-runner-baloosearch.desktop --- a/runners/baloo/plasma-runner-baloosearch.desktop +++ b/runners/baloo/plasma-runner-baloosearch.desktop @@ -83,11 +83,13 @@ X-KDE-ServiceTypes=Plasma/Runner Type=Service Icon=baloo -X-KDE-Library=krunner_baloosearchrunner X-KDE-PluginInfo-Author=Vishesh Handa X-KDE-PluginInfo-Email=me@vhanda.in X-KDE-PluginInfo-Name=baloosearch X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-License=LGPL X-Plasma-AdvertiseSingleRunnerQueryMode=true X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-API=DBus +X-Plasma-DBusRunner-Service=org.kde.runners.baloo +X-Plasma-DBusRunner-Path=/runner