diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,12 @@ PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5RunnerConfigVersion.cmake" ) +ecm_setup_version(PROJECT + VARIABLE_PREFIX KDBUSRUNNER + VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kdbusrunner_version.h" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5DBusRunnerConfigVersion.cmake" +) + # Dependencies set(REQUIRED_QT_VERSION 5.8.0) @@ -96,5 +102,38 @@ # contains list of debug categories, for kdebugsettings install(FILES krunner.categories DESTINATION ${KDE_INSTALL_CONFDIR}) +# Create a Config.cmake and a ConfigVersion.cmake file and install them +set(DBUSRUNNER_CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KF5DBusRunner") + +if (BUILD_QCH) + ecm_install_qch_export( + TARGETS KF5DBusRunner_QCH + FILE KF5DBusRunnerQchTargets.cmake + DESTINATION "${DBUSRUNNER_CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel + ) + set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5DBusRunnerQchTargets.cmake\")") +endif() + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/KF5DBusRunnerConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF5DBusRunnerConfig.cmake" + INSTALL_DESTINATION "${DBUSRUNNER_CMAKECONFIG_INSTALL_DIR}" +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/KF5DBusRunnerConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF5DBusRunnerConfigVersion.cmake" + DESTINATION "${DBUSRUNNER_CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel) + +install(EXPORT KF5DBusRunnerTargets + DESTINATION "${DBUSRUNNER_CMAKECONFIG_INSTALL_DIR}" + FILE KF5DBusRunnerTargets.cmake + NAMESPACE KF5::) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kdbusrunner_version.h" + DESTINATION "${KF5_INCLUDE_INSTALL_DIR}" + COMPONENT Devel) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/KF5DBusRunnerConfig.cmake.in b/KF5DBusRunnerConfig.cmake.in new file mode 100644 --- /dev/null +++ b/KF5DBusRunnerConfig.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(Qt5Core "@REQUIRED_QT_VERSION@") + +include("${CMAKE_CURRENT_LIST_DIR}/KF5DBusRunnerTargets.cmake") +@PACKAGE_INCLUDE_QCHTARGETS@ diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -13,9 +13,7 @@ ) set(demoapp_SRCS testremoterunner.cpp) -qt5_add_dbus_adaptor(demoapp_SRCS "../src/data/org.kde.krunner1.xml" testremoterunner.h TestRemoteRunner) add_executable(testremoterunner ${demoapp_SRCS}) target_link_libraries(testremoterunner - Qt5::DBus - KF5::Runner + KF5::DBusRunner ) diff --git a/autotests/testremoterunner.h b/autotests/testremoterunner.h --- a/autotests/testremoterunner.h +++ b/autotests/testremoterunner.h @@ -1,16 +1,33 @@ +/* + * Copyright (C) 2017 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #pragma once -#include -#include "../src/dbusutils_p.h" +#include -class TestRemoteRunner : public QObject +class TestRemoteRunner : public KDBusRunner::AbstractRunner { Q_OBJECT public: TestRemoteRunner(const QString &serviceName); -public Q_SLOTS: - RemoteActions Actions(); - RemoteMatches Match(const QString &searchTerm); - void Run(const QString &id, const QString &actionId); +public: + KDBusRunner::Actions actions() const override; + void handleMatchRequest(const KDBusRunner::MatchReply::Ptr &matchReply) override; + void run(const QString &matchId, const QString &actionId) override; }; diff --git a/autotests/testremoterunner.cpp b/autotests/testremoterunner.cpp --- a/autotests/testremoterunner.cpp +++ b/autotests/testremoterunner.cpp @@ -17,63 +17,52 @@ */ #include -#include - #include #include "testremoterunner.h" -#include "krunner1adaptor.h" //Test DBus runner, if the search term contains "foo" it returns a match, otherwise nothing //Run prints a line to stdout TestRemoteRunner::TestRemoteRunner(const QString &serviceName) + : KDBusRunner::AbstractRunner(QStringLiteral("/dave"), serviceName) { - new Krunner1Adaptor(this); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - qDBusRegisterMetaType(); - QDBusConnection::sessionBus().registerService(serviceName); - QDBusConnection::sessionBus().registerObject(QStringLiteral("/dave"), this); } -RemoteMatches TestRemoteRunner::Match(const QString& searchTerm) +void TestRemoteRunner::handleMatchRequest(const KDBusRunner::MatchReply::Ptr &matchReply) { - RemoteMatches ms; - if (searchTerm.contains(QLatin1String("foo"))) { - RemoteMatch m; - m.id = QStringLiteral("id1"); - m.text = QStringLiteral("Match 1"); - m.iconName = QStringLiteral("icon1"); - m.type = Plasma::QueryMatch::ExactMatch; - m.relevance = 0.8; - ms << m; + if (matchReply->query().contains(QLatin1String("foo"))) { + matchReply->addMatches({{ + QStringLiteral("id1"), + QStringLiteral("Match 1"), + QStringLiteral("icon1"), + KDBusRunner::QueryMatch::ExactMatch, + 0.8, + {} + }}); } - return ms; - } -RemoteActions TestRemoteRunner::Actions() +KDBusRunner::Actions TestRemoteRunner::actions() const { - RemoteAction action; - action.id = QStringLiteral("action1"); - action.text = QStringLiteral("Action 1"); - action.iconName = QStringLiteral("document-browser"); - - return RemoteActions({action}); + return {{ + QStringLiteral("action1"), + QStringLiteral("Action 1"), + QStringLiteral("document-browser") + }}; } -void TestRemoteRunner::Run(const QString &id, const QString &actionId) +void TestRemoteRunner::run(const QString &matchId, const QString &actionId) { - std::cout << "Running:" << qPrintable(id) << ":" << qPrintable(actionId) << std::endl; + std::cout << "Running:" << qPrintable(matchId) << ":" << qPrintable(actionId) << std::endl; std::cout.flush(); } int main(int argc, char ** argv) { QCoreApplication app(argc, argv); Q_ASSERT(app.arguments().count() == 2); TestRemoteRunner r(app.arguments()[1]); + r.setEnabled(); app.exec(); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(declarative) +add_subdirectory(dbusrunner) set (KF5Runner_SRCS abstractrunner.cpp diff --git a/src/dbusrunner/CMakeLists.txt b/src/dbusrunner/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/dbusrunner/CMakeLists.txt @@ -0,0 +1,84 @@ +set (KF5DBusRunner_SRCS + abstractrunner_p.cpp + abstractrunner.cpp + matchreply_p.cpp + matchreply.cpp + dbusadaptor.cpp +) + +ecm_qt_declare_logging_category(KF5DBusRunner_SRCS HEADER kdbusrunner_debug.h IDENTIFIER KDBUSRUNNER CATEGORY_NAME org.kde.kdbusrunner) + +add_library(KF5DBusRunner ${KF5DBusRunner_SRCS}) + +generate_export_header(KF5DBusRunner BASE_NAME KDBusRunner) +add_library(KF5::DBusRunner ALIAS KF5DBusRunner) + +target_include_directories(KF5DBusRunner INTERFACE "$") +target_include_directories(KF5DBusRunner PUBLIC "$") + + +target_link_libraries(KF5DBusRunner + PUBLIC + Qt5::Core + PRIVATE + Qt5::DBus +) + +set_target_properties(KF5DBusRunner + PROPERTIES VERSION ${KRUNNER_VERSION_STRING} + SOVERSION 5 + EXPORT_NAME "DBusRunner" +) + +ecm_generate_headers(KDBusRunner_CamelCase_HEADERS + HEADER_NAMES + AbstractRunner + Action + MatchReply + QueryMatch + + PREFIX KDBusRunner + REQUIRED_HEADERS KDBusRunner_HEADERS +) + +# Install files + +install(TARGETS KF5DBusRunner + EXPORT KF5DBusRunnerTargets + ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) + +install(FILES ${KDBusRunner_CamelCase_HEADERS} + DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KDBusRunner/KDBusRunner + COMPONENT Devel) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/kdbusrunner_export.h + ${KDBusRunner_HEADERS} + DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KDBusRunner/kdbusrunner + COMPONENT Devel) + +if(BUILD_QCH) + ecm_add_qch( + KF5DBusRunner_QCH + NAME KDBusRunner + BASE_NAME KF5DBusRunner + VERSION ${KF5_VERSION} + ORG_DOMAIN org.kde + SOURCES # using only public headers, to cover only public API + ${KDBusRunner_HEADERS} + LINK_QCHS + Qt5Core_QCH + BLANK_MACROS + KDBUSRUNNER_EXPORT + KDBUSRUNNER_DEPRECATED + KDBUSRUNNER_DEPRECATED_EXPORT + TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + COMPONENT Devel + ) +endif() + +include(ECMGeneratePriFile) +ecm_generate_pri_file(BASE_NAME KDBusRunner LIB_NAME KF5DBusRunner DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KF5_INCLUDE_INSTALL_DIR}/KDBusRunner) +install(FILES ${PRI_FILENAME} + DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/dbusrunner/abstractrunner.h b/src/dbusrunner/abstractrunner.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/abstractrunner.h @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "kdbusrunner_export.h" +#include "action.h" +#include "matchreply.h" +// Qt +#include + +namespace KDBusRunner +{ + +/** + * @class AbstractRunner abstractrunner.h + * + * @short An abstract base class for KRunner D-Bus plugins + * + * Example: + * @code +#include + +class MyRunner : public KDBusRunner::AbstractRunner +{ + Q_OBJECT + +public: + MyRunner(); + +public: + KDBusRunner::Actions actions() override; + void handleMatchRequest(const KDBusRunner::MatchReply::Ptr &matchReply) override; + void run(const QString &matchId, const QString &actionId) override; +}; + * @endcode + * + * The implementation of the D-Bus runner class: + * @code +MyRunner::MyRunner() + : KDBusRunner::AbstractRunner(QStringLiteral("/myrunner"), QStringLiteral("org.example.myrunner")) +{ +} + +void MyRunner::handleMatchRequest(const KDBusRunner::MatchReply::Ptr &matchReply) +{ + if (matchReply->query().contains(QLatin1String("my"))) { + matchReply->addMatches({{ + QStringLiteral("matchid"), + QStringLiteral("My Match"), + QStringLiteral("fooicon"), + KDBusRunner::QueryMatch::ExactMatch, + 0.8, + {} + }}); + } +} + +KDBusRunner::Actions MyRunner::actions() +{ + return {{ + QStringLiteral("action1"), + QStringLiteral("Open container"), + QStringLiteral("document-browser") + }}; +} + +void MyRunner::run(const QString &matchId, const QString &actionId) +{ + // do actionId with matchId +} + * @endcode + * + * Now the class just needs to be instantiated and activated by enabling it: + * @code +void activateRunner() +{ + auto r = new MyRunner(parent); + r->setEnabled(); +} + * @endcode + * + * The desktop file would get the matching entries: + * @code +X-Plasma-API=DBus +X-Plasma-DBusRunner-Service=org.example.myrunner +X-Plasma-DBusRunner-Path=/myrunner + * @endcode + */ +class KDBUSRUNNER_EXPORT AbstractRunner : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool isEnabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + +public: + /** + * @param dBusObjectPath D-Bus object path to register the runner object at + * @param dBusServiceName D-Bus service name to register, if empty none will be registered + * @param parent optional QObject parent taking ownership + */ + explicit AbstractRunner(const QString &dBusObjectPath, const QString &dBusServiceName = QString(), + QObject *parent = nullptr); + ~AbstractRunner() override; + +public: // API to implement + /** + * Returns a list of descriptions for additional actions possible + * on the matched object. + * + * Default implementation returns an empty list. + * + * @return list of action descriptions + */ + virtual Actions actions() const; + + /** + * Starts the matching. + * For sync processing @p matchReply can be filled within this method. + * For async processing, a reference to @p matchReplay can be kept and completed whenever. + * Note the calling client may time out, so it is advised to only respond to the latest request. + */ + virtual void handleMatchRequest(const MatchReply::Ptr &matchReply) = 0; + + /** + * Called whenever an exact or possible match associated with this + * runner is triggered. + * + * @param matchId The id of the match as used in the QueryMatch results + * @param actionId The action to run/execute + */ + virtual void run(const QString &matchId, const QString &actionId) = 0; + + /** + * @returns @c true if this runner is enabled, @c false otherwise + */ + bool isEnabled() const; + + /** + * By default a runner is not enabled. + * Setting a runner to not enabled will cancel any matching currently on-going. + * + * @param enabled whether the runner should be enabled or not + */ + void setEnabled(bool enabled = true); + + void virtual_hook(int id, void *data); + +Q_SIGNALS: + void enabledChanged(bool enabled); + +private: + const QScopedPointer d; +}; + +} diff --git a/src/dbusrunner/abstractrunner.cpp b/src/dbusrunner/abstractrunner.cpp new file mode 100644 --- /dev/null +++ b/src/dbusrunner/abstractrunner.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "abstractrunner.h" +#include "abstractrunner_p.h" + +#include + +using namespace KDBusRunner; + +AbstractRunner::AbstractRunner(const QString &dBusObjectPath, const QString &dBusServiceName, QObject *parent) + : QObject(parent) + , d(new AbstractRunnerPrivate(dBusObjectPath, dBusServiceName, this)) +{ +} + +AbstractRunner::~AbstractRunner() = default; + + +void AbstractRunner::setEnabled(bool enabled) +{ + d->setEnabled(enabled); +} + +bool AbstractRunner::isEnabled() const +{ + return d->isEnabled(); +} + +Actions AbstractRunner::actions() const +{ + return {}; +} diff --git a/src/dbusrunner/abstractrunner_p.h b/src/dbusrunner/abstractrunner_p.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/abstractrunner_p.h @@ -0,0 +1,63 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "abstractrunner.h" +#include "querymatch.h" +#include "matchreply_p.h" +// Qt +#include +#include +#include + +namespace KDBusRunner +{ + +class AbstractRunnerPrivate : public QObject, protected QDBusContext +{ + Q_OBJECT + +public: + explicit AbstractRunnerPrivate(const QString &dBusObjectPath, const QString &dBusServiceName, + AbstractRunner *parent); + ~AbstractRunnerPrivate() override; + +public: + Actions actions() const; + void handleMatchRequest(const QString &queryTerm); + void run(const QString &id, const QString &actionId); + + void setEnabled(bool enabled); + bool isEnabled() const; + + void unregister(MatchReplyPrivate *matchReply); + +private: + AbstractRunner * const q; + + QString mDBusObjectPath; + QString mDBusServiceName; + + QVector mActiveMatchReplies; + + friend class DBusRunner1Adaptor; +}; + +} diff --git a/src/dbusrunner/abstractrunner_p.cpp b/src/dbusrunner/abstractrunner_p.cpp new file mode 100644 --- /dev/null +++ b/src/dbusrunner/abstractrunner_p.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "abstractrunner_p.h" + +// lib +#include "dbusadaptor_p.h" +#include "matchreply.h" +#include "matchreply_p.h" +// Qr +#include +#include +#include +#include + +using namespace KDBusRunner; + + +inline QDBusArgument &operator<<(QDBusArgument &argument, const QueryMatch &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, QueryMatch &match) +{ + argument.beginStructure(); + argument >> match.id; + argument >> match.text; + argument >> match.iconName; + uint type; + argument >> type; + match.type = static_cast(type); + argument >> match.relevance; + argument >> match.properties; + argument.endStructure(); + + return argument; +} + +inline QDBusArgument &operator<< (QDBusArgument &argument, const Action &action) +{ + argument.beginStructure(); + argument << action.id; + argument << action.text; + argument << action.iconName; + argument.endStructure(); + return argument; +} + +inline const QDBusArgument &operator>>(const QDBusArgument &argument, Action &action) { + argument.beginStructure(); + argument >> action.id; + argument >> action.text; + argument >> action.iconName; + argument.endStructure(); + return argument; +} + + +AbstractRunnerPrivate::AbstractRunnerPrivate(const QString &dBusObjectPath, const QString &dBusServiceName, + AbstractRunner *parent) + : QObject(parent) + , q(parent) + , mDBusObjectPath(dBusObjectPath) + , mDBusServiceName(dBusServiceName) +{ + new DBusRunner1Adaptor(this); + + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); +} + +AbstractRunnerPrivate::~AbstractRunnerPrivate() = default; + +void AbstractRunnerPrivate::setEnabled(bool enabled) +{ + const bool isCurrentlyEnabled = isEnabled(); + if (enabled == isCurrentlyEnabled) { + return; + } + + if (enabled) { + QDBusConnection::sessionBus().registerObject(mDBusObjectPath, this); + if (!mDBusServiceName.isEmpty()) { + QDBusConnection::sessionBus().registerService(mDBusServiceName); + } + } else { + for (const auto& matchReply: qAsConst(mActiveMatchReplies)) { + matchReply->cancel(); + } + Q_ASSERT(mActiveMatchReplies.isEmpty()); + + if (!mDBusServiceName.isEmpty()) { + QDBusConnection::sessionBus().unregisterService(mDBusServiceName); + } + QDBusConnection::sessionBus().unregisterObject(mDBusObjectPath); + } + + emit q->enabledChanged(enabled); +} + +bool AbstractRunnerPrivate::isEnabled() const +{ + return (QDBusConnection::sessionBus().objectRegisteredAt(mDBusObjectPath) == this); +} + +Actions AbstractRunnerPrivate::actions() const +{ + return q->actions(); +} + +void AbstractRunnerPrivate::handleMatchRequest(const QString &queryTerm) +{ + MatchReplyPrivate *p = new MatchReplyPrivate(this, message(), queryTerm); + mActiveMatchReplies.append(p); + + MatchReply::Ptr matchReply(new MatchReply(p)); + q->handleMatchRequest(matchReply); +} + +void AbstractRunnerPrivate::run(const QString& id, const QString& actionId) +{ + q->run(id, actionId); +} + +void AbstractRunnerPrivate::unregister(MatchReplyPrivate *matchReply) +{ + mActiveMatchReplies.removeAll(matchReply); +} diff --git a/src/dbusrunner/action.h b/src/dbusrunner/action.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/action.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "kdbusrunner_export.h" +// Qt +#include +#include +#include + +namespace KDBusRunner +{ + +/** + * @class Action action.h + * + * @short An action for KRunner D-Bus plugins + */ +struct KDBUSRUNNER_EXPORT Action +{ + QString id; + QString text; + QString iconName; +}; + +typedef QVector Actions; + +} + +Q_DECLARE_TYPEINFO(KDBusRunner::Action, Q_MOVABLE_TYPE); +Q_DECLARE_METATYPE(KDBusRunner::Action); +Q_DECLARE_METATYPE(KDBusRunner::Actions); diff --git a/src/dbusrunner/dbusadaptor.cpp b/src/dbusrunner/dbusadaptor.cpp new file mode 100644 --- /dev/null +++ b/src/dbusrunner/dbusadaptor.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "dbusadaptor_p.h" + + +using namespace KDBusRunner; + +DBusRunner1Adaptor::DBusRunner1Adaptor(AbstractRunnerPrivate *parent) + : QDBusAbstractAdaptor(parent) +{ +} + +DBusRunner1Adaptor::~DBusRunner1Adaptor() = default; + +KDBusRunner::QueryMatches DBusRunner1Adaptor::Match(const QString &query) +{ + parent()->setDelayedReply(true); + parent()->handleMatchRequest(query); + + return {}; +} + +void DBusRunner1Adaptor::Run(const QString &matchId, const QString &actionId) +{ + parent()->run(matchId, actionId); +} + +KDBusRunner::Actions DBusRunner1Adaptor::Actions() +{ + return parent()->actions(); +} diff --git a/src/dbusrunner/dbusadaptor_p.h b/src/dbusrunner/dbusadaptor_p.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/dbusadaptor_p.h @@ -0,0 +1,63 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "abstractrunner_p.h" +// Qt +#include + +namespace KDBusRunner +{ + +/* + * Adaptor class for interface org.kde.krunner1 + */ +class DBusRunner1Adaptor: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.krunner1") + Q_CLASSINFO("D-Bus Introspection", "" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" + "") +public: + explicit DBusRunner1Adaptor(AbstractRunnerPrivate *parent); + ~DBusRunner1Adaptor() override; + + inline AbstractRunnerPrivate * parent() const { return static_cast(QObject::parent()); } + +public Q_SLOTS: + KDBusRunner::QueryMatches Match(const QString &query); + void Run(const QString &matchId, const QString &actionId); + KDBusRunner::Actions Actions(); +}; + +} diff --git a/src/dbusrunner/matchreply.h b/src/dbusrunner/matchreply.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/matchreply.h @@ -0,0 +1,112 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "kdbusrunner_export.h" +#include "querymatch.h" + +// Qt +#include + +namespace KDBusRunner +{ +class MatchReplyPrivate; + +/** + * @class MatchReply matchreply.h + * + * @short The MatchReply class provides information related to a search. + */ +class KDBUSRUNNER_EXPORT MatchReply +{ +protected: + explicit MatchReply(MatchReplyPrivate *d); + +public: + ~MatchReply(); + + using Ptr = QSharedPointer; + + /** + * @return the search query term. + */ + QString query() const; + + /** + * Returns whether context is still valid of if matching using it should abort. + * Most useful as an optimization technique inside of AbstractRunner subclasses + * in the match method, e.g.: + * + * while (.. a possibly large iteration) { + * if (!context->isValid()) { + * return; + * } + * + * ... some processing ... + * } + * + * While not required to be used within runners, it provides a nice way + * to avoid unnecessary processing in runners that may run for an extended + * period (as measured in 10s of ms). + * + * @returns @c true if this context is still valid, @c false otherwise + */ + bool isValid() const; + + /** + * Appends lists of matches to the list of matches. + * + * @param matches the matches to add + * @return @c true if the match was added, @c false otherwise + */ + bool addMatches(const QueryMatches &matches); + + /** + * Appends a match to the existing list of matches. + * + * If you are going to be adding multiple matches, use addMatches() instead. + * + * @param match the match to add + * @return @c true if the match was added, @c false otherwise + */ + bool addMatch(const QueryMatch &match); + + /** + * Explicitly complete the reply and submit it. + * + * If not submitted or cancelled, it will be auto-submitted + * once the last reference to it is dropped. + */ + void submit(); + + /** + * Explicitly cancel the reply. + * + * If not submitted or cancelled, it will be auto-submitted + * once the last reference to it is dropped. + */ + void cancel(); + +private: + const QScopedPointer d; + friend class AbstractRunnerPrivate; +}; + +} diff --git a/src/dbusrunner/matchreply.cpp b/src/dbusrunner/matchreply.cpp new file mode 100644 --- /dev/null +++ b/src/dbusrunner/matchreply.cpp @@ -0,0 +1,76 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "matchreply.h" +#include "matchreply_p.h" + +using namespace KDBusRunner; + + +MatchReply::MatchReply(MatchReplyPrivate *dd) + :d(dd) +{ +} + +MatchReply::~MatchReply() +{ + // auto-submit if not yet submitted or cancelled + submit(); +} + +QString MatchReply::query() const +{ + return d->mQuery; +} + +bool MatchReply::isValid() const +{ + return d->isValid(); +} + +bool MatchReply::addMatches(const QueryMatches &matches) +{ + if (!d->isValid()) { + return false; + } + + d->mMatches += matches; + return true; +} + +bool MatchReply::addMatch(const QueryMatch &match) +{ + if (!d->isValid()) { + return false; + } + + d->mMatches += match; + return true; +} + + +void MatchReply::cancel() +{ + d->cancel(); +} + +void MatchReply::submit() +{ + d->submit(); +} diff --git a/src/dbusrunner/matchreply_p.h b/src/dbusrunner/matchreply_p.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/matchreply_p.h @@ -0,0 +1,54 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "querymatch.h" +// Qt +#include + +namespace KDBusRunner +{ +class AbstractRunnerPrivate; + +class MatchReplyPrivate +{ +public: + MatchReplyPrivate(AbstractRunnerPrivate *runner, const QDBusMessage &dBusMessage, const QString& queryTerm) + : mRunner(runner) + , mDBusMessage(dBusMessage) + , mQuery(queryTerm) + { + } + + bool isValid() const + { + return mDBusMessage.type() == QDBusMessage::MethodCallMessage; + } + + void submit(); + void cancel(); + + AbstractRunnerPrivate * const mRunner; + QDBusMessage mDBusMessage; + QueryMatches mMatches; + const QString mQuery; +}; + +} diff --git a/src/dbusrunner/matchreply_p.cpp b/src/dbusrunner/matchreply_p.cpp new file mode 100644 --- /dev/null +++ b/src/dbusrunner/matchreply_p.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "matchreply_p.h" + +#include "abstractrunner_p.h" +// Qt +#include + +using namespace KDBusRunner; + + +void MatchReplyPrivate::cancel() +{ + if (!isValid()) { + return; + } + + QDBusConnection::sessionBus().send(mDBusMessage.createReply(QVariantList())); + mDBusMessage = QDBusMessage(); + mRunner->unregister(this); +} + +void MatchReplyPrivate::submit() +{ + if (!isValid()) { + return; + } + + QDBusConnection::sessionBus().send(mDBusMessage.createReply(QVariant::fromValue(mMatches))); + mDBusMessage = QDBusMessage(); + mRunner->unregister(this); +} diff --git a/src/dbusrunner/querymatch.h b/src/dbusrunner/querymatch.h new file mode 100644 --- /dev/null +++ b/src/dbusrunner/querymatch.h @@ -0,0 +1,101 @@ +/* + * Copyright 2018 David Edmundson + * Copyright 2018 Friedrich W. H. Kossebau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "kdbusrunner_export.h" + +#include +#include +#include + +namespace KDBusRunner +{ + +/** + * @class QueryMatch querymatch.h + * + * @short A match returned by an AbstractRunner in response to a given query. + */ +struct KDBUSRUNNER_EXPORT QueryMatch +{ + /** + * The type of match. Value is important here as it is used for sorting + * @internal Needs to match KRunner::QueryMatch::Type. + */ + enum Type : qint32 { + NoMatch = 0, /**< Null match */ + CompletionMatch = 10, /**< Possible completion for the data of the query */ + PossibleMatch = 30, /**< Something that may match the query */ + InformationalMatch = 50, /**< A purely informational, non-actionable match, + such as the answer to a question or calculation*/ + HelperMatch = 70, /**< A match that represents an action not directly related + to activating the given search term, such as a search + in an external tool or a command learning trigger. Helper + matches tend to be generic to the query and should not + be autoactivated just because the user hits "Enter" + while typing. They must be explicitly selected to + be activated, but unlike InformationalMatch cause + an action to be triggered. */ + ExactMatch = 100 /**< An exact match to the query */ + }; + + QueryMatch() : type(NoMatch), relevance(0) {} + QueryMatch(const QString& id, const QString& text, const QString& iconName, + QueryMatch::Type type, qreal relevance, const QVariantMap& properties) + : id(id), text(text), iconName(iconName), + type(type), relevance(relevance), properties(properties) + {} + + //sssuda{sv} + /** + * A string that can be used as an ID for this match, + * even between different queries. It is based in part + * on the source of the match (the AbstractRunner) and + * distinguishing information provided by the runner, + * ensuring global uniqueness as well as consistency + * between query matches. + */ + QString id; + /** + * The title text for this match + */ + QString text; + /** + * The name of the icon for this match + */ + QString iconName; + /** + * The type of match + */ + Type type; + /** + * The relevance of this action to the search. A number between 0 and 1. + */ + qreal relevance; + QVariantMap properties; +}; + +typedef QVector QueryMatches; + +} + +Q_DECLARE_TYPEINFO(KDBusRunner::QueryMatch, Q_MOVABLE_TYPE); +Q_DECLARE_METATYPE(KDBusRunner::QueryMatch); +Q_DECLARE_METATYPE(KDBusRunner::QueryMatches); diff --git a/src/querymatch.h b/src/querymatch.h --- a/src/querymatch.h +++ b/src/querymatch.h @@ -50,6 +50,7 @@ public: /** * The type of match. Value is important here as it is used for sorting + * @internal Needs to match KDBusRunner::QueryMatch::Type. */ enum Type { NoMatch = 0, /**< Null match */