diff options
25 files changed, 399 insertions, 39 deletions
diff --git a/doc/elements-systemui.qdoc b/doc/elements-systemui.qdoc index c82eba0f..b4ad59e2 100644 --- a/doc/elements-systemui.qdoc +++ b/doc/elements-systemui.qdoc @@ -51,7 +51,7 @@ item models. These types are only available for the System UI: -\annotatedlist system-ui +\annotatedlist system-ui-instantiable \section1 Non-Instantiable QML Types diff --git a/doc/manifest.qdoc b/doc/manifest.qdoc index 0679943d..a9091963 100644 --- a/doc/manifest.qdoc +++ b/doc/manifest.qdoc @@ -256,6 +256,7 @@ The fields used for each item within the \c applications list are as follows: provided, a default description is used. \endtable +\target manifest-intent The fields used for each item within the \c intents list are as follows: \table diff --git a/examples/applicationmanager/intents/apps/intents.blue/info.yaml b/examples/applicationmanager/intents/apps/intents.blue/info.yaml index 19f252c4..7ce3930e 100644 --- a/examples/applicationmanager/intents/apps/intents.blue/info.yaml +++ b/examples/applicationmanager/intents/apps/intents.blue/info.yaml @@ -10,8 +10,16 @@ name: intents: - id: rotate-window + name: + en: Rotate Blue requiredCapabilities: [ 'call-blue' ] - id: scale-window + name: + en: Scale Blue - id: blink-window + name: + en: Blink Blue - id: blue-window-private + name: + en: Blue Private Intent visibility: private diff --git a/examples/applicationmanager/intents/apps/intents.green/info.yaml b/examples/applicationmanager/intents/apps/intents.green/info.yaml index 97503419..40575f03 100644 --- a/examples/applicationmanager/intents/apps/intents.green/info.yaml +++ b/examples/applicationmanager/intents/apps/intents.green/info.yaml @@ -10,4 +10,8 @@ name: intents: - id: rotate-window + name: + en: Rotate Green - id: scale-window + name: + en: Scale Green diff --git a/examples/applicationmanager/intents/apps/intents.red/info.yaml b/examples/applicationmanager/intents/apps/intents.red/info.yaml index a08392fc..d61ba316 100644 --- a/examples/applicationmanager/intents/apps/intents.red/info.yaml +++ b/examples/applicationmanager/intents/apps/intents.red/info.yaml @@ -12,5 +12,11 @@ capabilities: 'call-blue' intents: - id: rotate-window + name: + en: Rotate Red - id: scale-window + name: + en: Scale Red - id: blink-window + name: + en: Blink Red diff --git a/examples/applicationmanager/intents/doc/src/intents.qdoc b/examples/applicationmanager/intents/doc/src/intents.qdoc index f1da854a..958fa483 100644 --- a/examples/applicationmanager/intents/doc/src/intents.qdoc +++ b/examples/applicationmanager/intents/doc/src/intents.qdoc @@ -127,7 +127,7 @@ For information on these and other command line options you can run \tt{appman - look at the \l{Configuration} documentation. -\section1 Application implementation +\section1 Application Implementation All the applications (red, green and blue) are identical and their \c main.qml just instantiates the shared IntentsApplicationWindow component. @@ -197,10 +197,36 @@ required capability, while the \b Green doesn't. \printto -\section1 System-UI implementation +\section1 System-UI Implementation -What is special about the System-UI as compared to the applications, is the \l -{IntentServer::disambiguationRequest}{disambiguation mechanism} and the accompanying UI. +Apart from the left side bar that deals with starting and stopping the apps, the System-UI has two +special features that deal with the intent mechanism: + +\list + \li Handling Intents in the System-UI and + \li Disambiguation of Intent Requests +\endlist + +\section2 Handling Intents in the System-UI + +Intents can not only be handled in applications, but also in the System-UI. Since the System-UI is +always running, we do not need to rely on \c info.yaml manifest files to define the supported +intents, but instead can declare the needed meta-data directly as properties of the +IntentServerHandler component. The IntentServerHandler is actually derived from IntentHandler, so +it works the same way as its application side counter part: it only adds the required properties to +define all the meta-data (e.g. \c names, \c icon, ...) on top. + +\snippet applicationmanager/intents/system-ui.qml IntentServerHandler + +The handler callback is nearly the same as the one in the applications. The only noteworthy +difference here is, that we have access to the \l{IntentRequest::}{requestingApplicationId} +to identify where the request originated from; for security reasons, this data is not available to +intent handlers in applications. + +\section2 Disambiguation of Intent Requests + +The example implements an UI that lets the user choose how to +\l {IntentServer::disambiguationRequest}{to disambiguate incoming intent requests}. Registering for the IntentServer's disambiguation requests is done here: \snippet applicationmanager/intents/system-ui.qml Connection diff --git a/examples/applicationmanager/intents/shared/IntentsUIPage.qml b/examples/applicationmanager/intents/shared/IntentsUIPage.qml index 0420a089..010a1501 100644 --- a/examples/applicationmanager/intents/shared/IntentsUIPage.qml +++ b/examples/applicationmanager/intents/shared/IntentsUIPage.qml @@ -104,7 +104,7 @@ Rectangle { Label { text: "Application:" } ComboBox { id: cbApplication - model: [ "<not specified>", "intents.red", "intents.green", "intents.blue" ] + model: [ "<not specified>", "intents.red", "intents.green", "intents.blue", ":sysui:" ] Layout.fillWidth: true } Button { diff --git a/examples/applicationmanager/intents/system-ui.qml b/examples/applicationmanager/intents/system-ui.qml index e3198f80..f212d3c8 100644 --- a/examples/applicationmanager/intents/system-ui.qml +++ b/examples/applicationmanager/intents/system-ui.qml @@ -112,6 +112,23 @@ Item { request.succeeded ? request.result : request.errorMessage) }) } + RotationAnimation on rotation { + id: rotationAnimation + running: false + duration: 500; from: 0; to: 360 + } + //! [IntentServerHandler] + IntentServerHandler { + intentIds: "rotate-window" + names: { "en": "Rotate System-UI" } + visibility: IntentObject.Public + + onRequestReceived: { + rotationAnimation.start() + request.sendReply({ "wasRequestedBy": request.requestingApplicationId }) + } + } + //! [IntentServerHandler] } Repeater { diff --git a/src/intent-client-lib/intentclient.cpp b/src/intent-client-lib/intentclient.cpp index 89f4b949..449061db 100644 --- a/src/intent-client-lib/intentclient.cpp +++ b/src/intent-client-lib/intentclient.cpp @@ -42,9 +42,8 @@ ****************************************************************************/ #include <QScopedPointer> -#include <qqml.h> -#include <QQmlInfo> #include <QQmlEngine> +#include <QQmlInfo> #include "intentclient.h" #include "intentclientsysteminterface.h" @@ -100,16 +99,6 @@ IntentClient *IntentClient::createInstance(IntentClientSystemInterface *systemIn qCWarning(LogIntents) << "Failed to initialize IntentClient:" << exc.what(); return nullptr; } - qmlRegisterSingletonType<IntentClient>("QtApplicationManager", 2, 0, "IntentClient", - [](QQmlEngine *, QJSEngine *) -> QObject * { - QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership); - return instance(); - }); - - qmlRegisterUncreatableType<IntentClientRequest>("QtApplicationManager", 2, 0, "IntentRequest", - qSL("Cannot create objects of type IntentRequest")); - qmlRegisterType<IntentHandler>("QtApplicationManager.Application", 2, 0, "IntentHandler"); - return s_instance = ic.take(); } @@ -272,14 +261,15 @@ void IntentClient::replyFromSystem(const QUuid &requestId, bool error, const QVa } void IntentClient::requestToApplication(const QUuid &requestId, const QString &intentId, + const QString &requestingApplicationId, const QString &applicationId, const QVariantMap ¶meters) { qCDebug(LogIntents) << "Client: Incoming intent request" << requestId << "to application" << applicationId << "for intent" << intentId << "parameters" << parameters; IntentClientRequest *icr = new IntentClientRequest(IntentClientRequest::Direction::ToApplication, - QString(), requestId, intentId, applicationId, - parameters); + requestingApplicationId, requestId, intentId, + applicationId, parameters); IntentHandler *handler = m_handlers.value(qMakePair(intentId, applicationId)); if (handler) { diff --git a/src/intent-client-lib/intentclient.h b/src/intent-client-lib/intentclient.h index f3ba44c2..54bbf24a 100644 --- a/src/intent-client-lib/intentclient.h +++ b/src/intent-client-lib/intentclient.h @@ -92,7 +92,7 @@ private: bool error, const QString &errorMessage); void replyFromSystem(const QUuid &requestId, bool error, const QVariantMap &result); - void requestToApplication(const QUuid &requestId, const QString &intentId, + void requestToApplication(const QUuid &requestId, const QString &intentId, const QString &requestingApplicationId, const QString &applicationId, const QVariantMap ¶meters); private: diff --git a/src/intent-client-lib/intentclientrequest.cpp b/src/intent-client-lib/intentclientrequest.cpp index c6cba1cb..e0aad1e7 100644 --- a/src/intent-client-lib/intentclientrequest.cpp +++ b/src/intent-client-lib/intentclientrequest.cpp @@ -115,6 +115,16 @@ QT_BEGIN_NAMESPACE_AM \note Constant, valid on both sent and received requests. */ +/*! \qmlproperty string IntentRequest::requestingApplicationId + \readonly + + The id of the application which created this intent request. Returns an empty string if called + from within an application context - only the server side has access to this information in + IntentServerHandler::requestReceived. + + \note Constant, valid on both sent and received requests. +*/ + /*! \qmlproperty var IntentRequest::parameters \readonly diff --git a/src/intent-client-lib/intentclientrequest.h b/src/intent-client-lib/intentclientrequest.h index 8d898d32..b11d5648 100644 --- a/src/intent-client-lib/intentclientrequest.h +++ b/src/intent-client-lib/intentclientrequest.h @@ -62,6 +62,7 @@ class IntentClientRequest : public QObject Q_PROPERTY(Direction direction READ direction CONSTANT) Q_PROPERTY(QString intentId READ intentId CONSTANT) Q_PROPERTY(QString applicationId READ applicationId CONSTANT) + Q_PROPERTY(QString requestingApplicationId READ requestingApplicationId CONSTANT) Q_PROPERTY(QVariantMap parameters READ parameters CONSTANT) Q_PROPERTY(bool succeeded READ succeeded NOTIFY replyReceived) Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY replyReceived) diff --git a/src/intent-client-lib/intentclientsysteminterface.h b/src/intent-client-lib/intentclientsysteminterface.h index 307aae8f..f54675e6 100644 --- a/src/intent-client-lib/intentclientsysteminterface.h +++ b/src/intent-client-lib/intentclientsysteminterface.h @@ -74,7 +74,8 @@ signals: void replyFromSystem(const QUuid &requestId, bool error, const QVariantMap &result); void requestToApplication(const QUuid &requestId, const QString &intentId, - const QString &applicationId, const QVariantMap ¶meters); + const QString &requestingApplicationId, const QString &applicationId, + const QVariantMap ¶meters); protected: IntentClient *m_ic = nullptr; diff --git a/src/intent-client-lib/intenthandler.cpp b/src/intent-client-lib/intenthandler.cpp index e8cf146c..2a571403 100644 --- a/src/intent-client-lib/intenthandler.cpp +++ b/src/intent-client-lib/intenthandler.cpp @@ -41,6 +41,8 @@ ** ****************************************************************************/ +#include <QQmlInfo> + #include "intenthandler.h" #include "intentclient.h" @@ -48,7 +50,7 @@ QT_BEGIN_NAMESPACE_AM /*! \qmltype IntentHandler \inqmlmodule QtApplicationManager.Application - \ingroup common-instantiatable + \ingroup application-instantiatable \brief A handler for intent requests received by applications. Any application that has intents listed in its manifest file needs to have a corresponding @@ -57,6 +59,10 @@ QT_BEGIN_NAMESPACE_AM instance or have a dedicated IntentHandler instance for every intent id (or any combination of those). + \note For handling intent requests within the system ui, you have to use the derived component + IntentServerHandler, which works the same way, but provides all the necessary meta-data + from within QML. + Here is a fairly standard way to handle an incoming intent request and send out a result or error message: @@ -86,8 +92,7 @@ QT_BEGIN_NAMESPACE_AM Every handler needs to register at least one unique intent id that it will handle. Having multiple IntentHandlers that are registering the same intent id is not possible. - \note Any changes to this property after component completion will have no effect. This - restriction will likely be removed in a future update. + \note Any changes to this property after component completion will have no effect. */ /*! \qmlsignal IntentHandler::requestReceived(IntentRequest request) @@ -127,18 +132,25 @@ QStringList IntentHandler::intentIds() const void IntentHandler::setIntentIds(const QStringList &intentIds) { - if (intentIds != m_intentIds) { - m_intentIds = intentIds; - emit intentIdsChanged(m_intentIds); + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the intentIds property of an IntentHandler after creation."; + return; } + m_intentIds = intentIds; } void IntentHandler::componentComplete() { IntentClient::instance()->registerHandler(this); + m_completed = true; } void IntentHandler::classBegin() { } +bool IntentHandler::isComponentCompleted() const +{ + return m_completed; +} + QT_END_NAMESPACE_AM diff --git a/src/intent-client-lib/intenthandler.h b/src/intent-client-lib/intenthandler.h index 95c73e41..aaf5e031 100644 --- a/src/intent-client-lib/intenthandler.h +++ b/src/intent-client-lib/intenthandler.h @@ -60,7 +60,7 @@ class IntentHandler : public QObject, public QQmlParserStatus Q_CLASSINFO("AM-QmlType", "QtApplicationManager.Application/IntentHandler 2.0") Q_INTERFACES(QQmlParserStatus) - Q_PROPERTY(QStringList intentIds READ intentIds WRITE setIntentIds NOTIFY intentIdsChanged) + Q_PROPERTY(QStringList intentIds READ intentIds WRITE setIntentIds) public: IntentHandler(QObject *parent = nullptr); @@ -78,10 +78,13 @@ protected: void componentComplete() override; void classBegin() override; + bool isComponentCompleted() const; + private: Q_DISABLE_COPY(IntentHandler) QStringList m_intentIds; + bool m_completed = false; }; QT_END_NAMESPACE_AM diff --git a/src/intent-server-lib/intent.h b/src/intent-server-lib/intent.h index a8a04d52..a519c425 100644 --- a/src/intent-server-lib/intent.h +++ b/src/intent-server-lib/intent.h @@ -114,6 +114,7 @@ private: QUrl m_icon; friend class IntentServer; + friend class IntentServerHandler; }; QT_END_NAMESPACE_AM diff --git a/src/intent-server-lib/intentmodel.cpp b/src/intent-server-lib/intentmodel.cpp index 4342fc9f..f4b1a76a 100644 --- a/src/intent-server-lib/intentmodel.cpp +++ b/src/intent-server-lib/intentmodel.cpp @@ -56,7 +56,7 @@ /*! \qmltype IntentModel \inherits QSortFilterProxyModel - \ingroup system-ui + \ingroup system-ui-instantiable \inqmlmodule QtApplicationManager.SystemUI \brief A proxy model for the IntentServer singleton. diff --git a/src/launcher-lib/intentclientdbusimplementation.cpp b/src/launcher-lib/intentclientdbusimplementation.cpp index 5da608a6..62d9d07c 100644 --- a/src/launcher-lib/intentclientdbusimplementation.cpp +++ b/src/launcher-lib/intentclientdbusimplementation.cpp @@ -43,11 +43,15 @@ #include <QDBusConnection> #include <QDBusPendingReply> #include <QDBusPendingCallWatcher> +#include <QQmlEngine> +#include <qqml.h> + #include "launchermain.h" #include "dbus-utilities.h" #include "intentclient.h" #include "intentclientrequest.h" #include "intentclientdbusimplementation.h" +#include "intenthandler.h" #include "intentinterface_interface.h" @@ -68,6 +72,17 @@ void IntentClientDBusImplementation::initialize(IntentClient *intentClient) Q_DE { IntentClientSystemInterface::initialize(intentClient); + qmlRegisterSingletonType<IntentClient>("QtApplicationManager", 2, 0, "IntentClient", + [](QQmlEngine *, QJSEngine *) -> QObject * { + QQmlEngine::setObjectOwnership(IntentClient::instance(), QQmlEngine::CppOwnership); + return IntentClient::instance(); + }); + + qmlRegisterUncreatableType<IntentClientRequest>("QtApplicationManager", 2, 0, "IntentRequest", + qSL("Cannot create objects of type IntentRequest")); + qmlRegisterType<IntentHandler>("QtApplicationManager.Application", 2, 0, "IntentHandler"); + + m_dbusInterface = new IoQtApplicationManagerIntentInterfaceInterface( QString(), qSL("/IntentServer"), QDBusConnection(m_dbusName), intentClient); @@ -82,7 +97,7 @@ void IntentClientDBusImplementation::initialize(IntentClient *intentClient) Q_DE connect(m_dbusInterface, &IoQtApplicationManagerIntentInterfaceInterface::requestToApplication, intentClient, [this](const QString &requestId, const QString &id, const QString &applicationId, const QVariantMap ¶meters) { - emit requestToApplication(requestId, id, applicationId, convertFromDBusVariant(parameters).toMap()); + emit requestToApplication(requestId, id, QString(), applicationId, convertFromDBusVariant(parameters).toMap()); }); } diff --git a/src/manager-lib/applicationipcinterface.cpp b/src/manager-lib/applicationipcinterface.cpp index a7083461..43a48172 100644 --- a/src/manager-lib/applicationipcinterface.cpp +++ b/src/manager-lib/applicationipcinterface.cpp @@ -64,7 +64,7 @@ /*! \qmltype ApplicationIPCInterface - \ingroup system-ui + \ingroup system-ui-instantiable \inqmlmodule QtApplicationManager.SystemUI \brief The definition of an IPC interface between the application manager and applications. diff --git a/src/manager-lib/applicationmodel.cpp b/src/manager-lib/applicationmodel.cpp index 4deed932..06434601 100644 --- a/src/manager-lib/applicationmodel.cpp +++ b/src/manager-lib/applicationmodel.cpp @@ -57,7 +57,7 @@ /*! \qmltype ApplicationModel \inherits QSortFilterProxyModel - \ingroup system-ui + \ingroup system-ui-instantiable \inqmlmodule QtApplicationManager.SystemUI \brief A proxy model for the ApplicationManager singleton. diff --git a/src/manager-lib/intentaminterface.cpp b/src/manager-lib/intentaminterface.cpp index 52b8e5be..286ff661 100644 --- a/src/manager-lib/intentaminterface.cpp +++ b/src/manager-lib/intentaminterface.cpp @@ -56,6 +56,7 @@ #include <QQmlEngine> #include <QQmlExpression> #include <QQmlContext> +#include <QQmlInfo> #include "error.h" #include "exception.h" @@ -291,6 +292,18 @@ QString IntentClientAMImplementation::currentApplicationId(QObject *hint) void IntentClientAMImplementation::initialize(IntentClient *intentClient) Q_DECL_NOEXCEPT_EXPR(false) { IntentClientSystemInterface::initialize(intentClient); + + qmlRegisterSingletonType<IntentClient>("QtApplicationManager", 2, 0, "IntentClient", + [](QQmlEngine *, QJSEngine *) -> QObject * { + QQmlEngine::setObjectOwnership(IntentClient::instance(), QQmlEngine::CppOwnership); + return IntentClient::instance(); + }); + + qmlRegisterUncreatableType<IntentClientRequest>("QtApplicationManager", 2, 0, "IntentRequest", + qSL("Cannot create objects of type IntentRequest")); + qmlRegisterType<IntentHandler>("QtApplicationManager.Application", 2, 0, "IntentHandler"); + + qmlRegisterType<IntentServerHandler>("QtApplicationManager.SystemUI", 2, 0, "IntentServerHandler"); } void IntentClientAMImplementation::requestToSystem(QPointer<IntentClientRequest> icr) @@ -422,6 +435,7 @@ void IntentServerInProcessIpcConnection::requestToApplication(IntentServerReques QMetaObject::invokeMethod(this, [this, irs]() { auto clientInterface = m_interface->intentClientSystemInterface(); emit clientInterface->requestToApplication(irs->requestId().toString(), irs->intentId(), + irs->requestingApplicationId(), irs->handlingApplicationId(), irs->parameters()); }, Qt::QueuedConnection); } @@ -516,16 +530,15 @@ void IntentServerDBusIpcConnection::replyFromApplication(const QString &requestI convertFromDBusVariant(result).toMap()); } - #endif // defined(AM_MULTI_PROCESS) -QT_END_NAMESPACE_AM - // ^^^ IntentServerDBusIpcConnection ^^^ ////////////////////////////////////////////////////////////////////////// // vvv IntentInterfaceAdaptor vvv +QT_END_NAMESPACE_AM + #if defined(AM_MULTI_PROCESS) IntentInterfaceAdaptor::IntentInterfaceAdaptor(QObject *parent) @@ -551,5 +564,208 @@ QString IntentInterfaceAdaptor::requestToSystem(const QString &intentId, const Q #endif // defined(AM_MULTI_PROCESS) +QT_BEGIN_NAMESPACE_AM + // ^^^ IntentInterfaceAdaptor ^^^ ////////////////////////////////////////////////////////////////////////// +// vvv IntentServerHandler vvv + +/*! \qmltype IntentServerHandler + \inqmlmodule QtApplicationManager.SystemUI + \ingroup system-ui-instantiable + \brief A handler for intent requests received within the system ui. + + If intents need to be handled from within the system ui, you need to have a corresponding + IntentServerHandler instance that is actually able to handle incoming requests. This class gives + you the flexibility to handle multiple, different intent ids via a single IntentServerHandler + instance or have a dedicated IntentServerHandler instance for every intent id (or any + combination of those). + + \note For handling intent requests within an application, you have to use the application side + component IntentHandler, which works the same way, but provides all the necessary + meta-data in the application's info.yaml manifest file. + + For more information see IntentHandler and the description of the \l{manifest-intent} + {meta-data in the manifest documentation}. + + Callbacks connected to the onRequestReceived signal have access to the sender's application ID. + Due to security restrictions, this is \b not the case for such handlers implemented in an + application context via IntentHandler. +*/ + +/*! \qmlproperty url IntentServerHandler::icon + + The intent's icon - see the \l{manifest-intent}{manifest documentation} for more + details. + + \note Any changes to this property after component completion will have no effect. +*/ +/*! \qmlproperty object IntentServerHandler::names + + The intent's name - see the \l{manifest-intent}{manifest documentation} for more + details. + + \note Any changes to this property after component completion will have no effect. +*/ +/*! \qmlproperty list<string> IntentServerHandler::categories + + The intent's categories - see the \l{manifest-intent}{manifest documentation} for more + details. + + \note Any changes to this property after component completion will have no effect. +*/ +/*! \qmlproperty enum IntentServerHandler::visibility + + The intent's visibility - see the \l{manifest-intent}{manifest documentation} for more + details. + Can be either \c IntentObject.Public or \c IntentObject.Private (the default). + + \note Any changes to this property after component completion will have no effect. +*/ +/*! \qmlproperty list<string> IntentServerHandler::requiredCapabilities + + The intent's required capabilities - see the \l{manifest-intent}{manifest documentation} for + more details. + + \note Any changes to this property after component completion will have no effect. +*/ +/*! \qmlproperty object IntentServerHandler::parameterMatch + + The intent's parameter requirements - see the \l{manifest-intent}{manifest documentation} for + more details. + + \note Any changes to this property after component completion will have no effect. +*/ + +IntentServerHandler::IntentServerHandler(QObject *parent) + : IntentHandler(parent) + , m_intent(new Intent()) +{ } + +IntentServerHandler::~IntentServerHandler() +{ + IntentServer *is = IntentServer::instance(); + + for (const auto &intent : m_registeredIntents) + is->removeIntent(intent); + + delete m_intent; +} + +QUrl IntentServerHandler::icon() const +{ + return m_intent->icon(); +} + +QVariantMap IntentServerHandler::names() const +{ + return m_intent->names(); +} + +QStringList IntentServerHandler::categories() const +{ + return m_intent->categories(); +} + +Intent::Visibility IntentServerHandler::visibility() const +{ + return m_intent->visibility(); +} + +QStringList IntentServerHandler::requiredCapabilities() const +{ + return m_intent->requiredCapabilities(); +} + +QVariantMap IntentServerHandler::parameterMatch() const +{ + return m_intent->parameterMatch(); +} + +void IntentServerHandler::setIcon(const QUrl &icon) +{ + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the icon property of an IntentServerHandler after creation."; + return; + } + m_intent->m_icon = icon; +} + +void IntentServerHandler::setNames(const QVariantMap &names) +{ + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the names property of an IntentServerHandler after creation."; + return; + } + m_intent->m_names = names; +} + +void IntentServerHandler::setCategories(const QStringList &categories) +{ + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the categories property of an IntentServerHandler after creation."; + return; + } + m_intent->m_categories = categories; +} + +void IntentServerHandler::setVisibility(Intent::Visibility visibility) +{ + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the visibility property of an IntentServerHandler after creation."; + return; + } + m_intent->m_visibility = visibility; +} + +void IntentServerHandler::setRequiredCapabilities(const QStringList &requiredCapabilities) +{ + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the requiredCapabilities property of an IntentServerHandler after creation."; + return; + } + m_intent->m_requiredCapabilities = requiredCapabilities; +} + +void IntentServerHandler::setParameterMatch(const QVariantMap ¶meterMatch) +{ + if (isComponentCompleted()) { + qmlWarning(this) << "Cannot change the parameterMatch property of an IntentServerHandler after creation."; + return; + } + m_intent->m_parameterMatch = parameterMatch; +} + +void IntentServerHandler::componentComplete() +{ + if (QmlInProcessRuntime::determineRuntime(this)) { + qmlWarning(this) << "Using IntentServerHandler for handling events in an application " + "context does not work. Use IntentHandler instead"; + return; + } + + IntentServer *is = IntentServer::instance(); + is->addPackage(sysUiId); + is->addApplication(sysUiId, sysUiId); + + const auto ids = intentIds(); + for (const auto &intentId : ids) { + // convert from QVariantMap to QMap<QString, QString> + QMap<QString, QString> names; + const auto qvm_names = m_intent->names(); + for (auto it = qvm_names.cbegin(); it != qvm_names.cend(); ++it) + names.insert(it.key(), it.value().toString()); + + auto intent = is->addIntent(intentId, sysUiId, sysUiId, m_intent->requiredCapabilities(), + m_intent->visibility(), m_intent->parameterMatch(), names, + m_intent->icon(), m_intent->categories()); + if (intent) + m_registeredIntents << intent; + else + qmlWarning(this) << "IntentServerHandler: could not add intent" << intentId; + } + + IntentHandler::componentComplete(); +} + +QT_END_NAMESPACE_AM diff --git a/src/manager-lib/intentaminterface.h b/src/manager-lib/intentaminterface.h index 49136b13..9f74a2fe 100644 --- a/src/manager-lib/intentaminterface.h +++ b/src/manager-lib/intentaminterface.h @@ -48,13 +48,16 @@ #include <QString> #include <QVariantMap> #include <QList> +#include <QUrl> #if defined(AM_MULTI_PROCESS) # include <QDBusConnection> # include <QDBusContext> #endif #include <QtAppManCommon/global.h> #include <QtAppManIntentServer/intentserversysteminterface.h> +#include <QtAppManIntentServer/intent.h> #include <QtAppManIntentClient/intentclientsysteminterface.h> +#include <QtAppManIntentClient/intenthandler.h> #include <QtAppManApplication/intentinfo.h> class IntentInterfaceAdaptor; @@ -195,4 +198,49 @@ private: #endif // defined(AM_MULTI_PROCESS) +// server-side IntentHandlers +class IntentServerHandler : public IntentHandler +{ + Q_OBJECT + Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentServerHandler 2.0") + + // the following properties cannot be changed after construction (hence, also no 'changed' signal) + // these replace the meta-data that's provided through the info.yaml manifests for client-side + // handlers + Q_PROPERTY(QUrl icon READ icon WRITE setIcon) + Q_PROPERTY(QVariantMap names READ names WRITE setNames) + Q_PROPERTY(QStringList categories READ categories WRITE setCategories) + Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Intent)::Visibility visibility READ visibility WRITE setVisibility) + Q_PROPERTY(QStringList requiredCapabilities READ requiredCapabilities WRITE setRequiredCapabilities) + Q_PROPERTY(QVariantMap parameterMatch READ parameterMatch WRITE setParameterMatch) + +public: + IntentServerHandler(QObject *parent = nullptr); + ~IntentServerHandler() override; + + QUrl icon() const; + QVariantMap names() const; + QStringList categories() const; + Intent::Visibility visibility() const; + QStringList requiredCapabilities() const; + QVariantMap parameterMatch() const; + +public slots: + void setIcon(const QUrl &icon); + void setNames(const QVariantMap &names); + void setCategories(const QStringList &categories); + void setVisibility(Intent::Visibility visibility); + void setRequiredCapabilities(const QStringList &requiredCapabilities); + void setParameterMatch(const QVariantMap ¶meterMatch); + +protected: + void componentComplete() override; + +private: + Q_DISABLE_COPY(IntentServerHandler) + Intent *m_intent = nullptr; // DRY: just a container for our otherwise needed members vars + QVector<Intent *> m_registeredIntents; + bool m_completed = false; +}; + QT_END_NAMESPACE_AM diff --git a/src/manager-lib/processstatus.cpp b/src/manager-lib/processstatus.cpp index c49f3d6e..c16da4f1 100644 --- a/src/manager-lib/processstatus.cpp +++ b/src/manager-lib/processstatus.cpp @@ -56,7 +56,7 @@ /*! \qmltype ProcessStatus \inqmlmodule QtApplicationManager.SystemUI - \ingroup system-ui + \ingroup system-ui-instantiable \brief Provides information about the status of an application process. ProcessStatus provides information about the process of a given application. diff --git a/src/manager-lib/qmlinprocessapplicationinterface.cpp b/src/manager-lib/qmlinprocessapplicationinterface.cpp index caceabe3..feb37ea3 100644 --- a/src/manager-lib/qmlinprocessapplicationinterface.cpp +++ b/src/manager-lib/qmlinprocessapplicationinterface.cpp @@ -42,6 +42,7 @@ #include <QQmlEngine> #include <QQmlExpression> +#include <QQmlInfo> #include "logging.h" #include "qmlinprocessapplicationinterface.h" @@ -309,7 +310,7 @@ void QmlInProcessApplicationInterfaceExtension::setName(const QString &name) m_name = name; resolveObject(); } else { - qWarning("Cannot change the name property of an ApplicationInterfaceExtension after creation."); + qmlWarning(this) << "Cannot change the name property of an ApplicationInterfaceExtension after creation."; } } diff --git a/src/window-lib/windowitem.cpp b/src/window-lib/windowitem.cpp index 7fb17f69..677360d3 100644 --- a/src/window-lib/windowitem.cpp +++ b/src/window-lib/windowitem.cpp @@ -62,7 +62,7 @@ /*! \qmltype WindowItem \inqmlmodule QtApplicationManager.SystemUI - \ingroup system-ui + \ingroup system-ui-instantiable \brief An Item that renders a given WindowObject. To render a WindowObject inside the System UI, you must specify where and how it should be |