summaryrefslogtreecommitdiff
path: root/src/intent-server-lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/intent-server-lib')
-rw-r--r--src/intent-server-lib/intent-server-lib.pro6
-rw-r--r--src/intent-server-lib/intent.cpp138
-rw-r--r--src/intent-server-lib/intent.h53
-rw-r--r--src/intent-server-lib/intentmodel.cpp285
-rw-r--r--src/intent-server-lib/intentmodel.h100
-rw-r--r--src/intent-server-lib/intentserver.cpp446
-rw-r--r--src/intent-server-lib/intentserver.h99
-rw-r--r--src/intent-server-lib/intentserverrequest.cpp9
-rw-r--r--src/intent-server-lib/intentserverrequest.h9
-rw-r--r--src/intent-server-lib/intentserversysteminterface.cpp8
-rw-r--r--src/intent-server-lib/intentserversysteminterface.h2
11 files changed, 912 insertions, 243 deletions
diff --git a/src/intent-server-lib/intent-server-lib.pro b/src/intent-server-lib/intent-server-lib.pro
index 19ebf29c..34519bfc 100644
--- a/src/intent-server-lib/intent-server-lib.pro
+++ b/src/intent-server-lib/intent-server-lib.pro
@@ -15,12 +15,14 @@ HEADERS += \
intent.h \
intentserver.h \
intentserverrequest.h \
- intentserversysteminterface.h
+ intentserversysteminterface.h \
+ intentmodel.h \
SOURCES += \
intent.cpp \
intentserver.cpp \
intentserverrequest.cpp \
- intentserversysteminterface.cpp
+ intentserversysteminterface.cpp \
+ intentmodel.cpp \
load(qt_module)
diff --git a/src/intent-server-lib/intent.cpp b/src/intent-server-lib/intent.cpp
index b1151910..72eff40b 100644
--- a/src/intent-server-lib/intent.cpp
+++ b/src/intent-server-lib/intent.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -44,48 +45,48 @@
#include <QRegularExpression>
#include <QVariant>
+#include <QLocale>
QT_BEGIN_NAMESPACE_AM
/*!
- \qmltype Intent
+ \qmltype IntentObject
\inqmlmodule QtApplicationManager.SystemUI
\ingroup system-ui-non-instantiable
\brief This type represents an Intent definition on the System-UI side.
- This is a QML gadget class representing a single Intent definition for a specific application.
+ This is a QML object class representing a single Intent definition for a specific application.
It is not creatable from QML code and all properties are read-only. Only functions and
- properties of IntentServer will return instances of this class.
+ properties of IntentServer will return pointers to this class.
*/
-/*! \qmlproperty bool Intent::valid
+/*! \qmlproperty string IntentObject::intentId
\readonly
- Set to \c true, if this instance reprensents a valid intent, or \c false otherwise.
+ The id of the intent.
*/
-/*! \qmlproperty string Intent::intentId
+/*! \qmlproperty string IntentObject::packageId
\readonly
- The id of the intent.
+ The id of the package that the handling application of this intent is part of.
*/
-/*! \qmlproperty string Intent::applicationId
+/*! \qmlproperty string IntentObject::applicationId
\readonly
- The id of the application that is handling this intent.
+ The id of the application responsible for handling this intent.
*/
-/*! \qmlproperty Intent.Visibility Intent::visibility
+/*! \qmlproperty IntentObject.Visibility IntentObject::visibility
\readonly
- The visibility of this intent for other applications.
+ The visibility of this intent for other packages.
\list
- \li Intent.Public - Any application can request this intent.
- \li Intent.Private - Only the handling application can request this intent (this will be more
- useful once application background services have been implemented).
+ \li IntentObject.Public - Any application can request this intent.
+ \li IntentObject.Private - Only applications from the same package can request this intent.
\endlist
*/
-/*! \qmlproperty list<string> Intent::requiredCapabilities
+/*! \qmlproperty list<string> IntentObject::requiredCapabilities
\readonly
An \l{ApplicationObject}{application} requesting this intent needs to have all of the given
capabilities.
@@ -93,56 +94,47 @@ QT_BEGIN_NAMESPACE_AM
\sa ApplicationObject::capabilities
*/
-/*! \qmlproperty var Intent::parameterMatch
+/*! \qmlproperty var IntentObject::parameterMatch
\readonly
- A handling application can limit what parameter values it accepts. One example would be an
- open-mime-type intent that is implemented by many applications: there would be a \c mimeType
- parameter and each application could limit the requests it wants to receive by setting a
- parameterMatch on this \c mimeType parameter, e.g. \c{{ mimeType: "^image/.*\.png$" }}
+ A handling application can limit what parameter values it accepts. The property itself is an
+ object that corresponds to a subset of allowed parameter object of this intent.
+ When set, the parameters of each incoming intent request are matched against this object,
+ following these rules:
+ \list
+ \li a field missing from \c parameterMatch is ignored.
+ \li a field of type \c string specified in \c parameterMatch is matched as a regular
+ expressions against the corresponding parameter value.
+ \li for fields of type \c list specified in \c parameterMatch, the corresponding parameter value
+ has to match any of the values in the list (using QVariant compare).
+ \li any other fields in \c parameterMatch are compared as QVariants to the corresponding
+ parameter value.
+ \endlist
+ One example would be an \c open-mime-type intent that is implemented by many applications: there
+ would be a \c mimeType parameter and each application could limit the requests it wants to
+ receive by setting a parameterMatch on this \c mimeType parameter, e.g.
+ \c{{ mimeType: "^image/.*\.png$" }}
*/
Intent::Intent()
{ }
-Intent::Intent(const Intent &other)
- : m_intentId(other.m_intentId)
- , m_visibility(other.m_visibility)
- , m_requiredCapabilities(other.m_requiredCapabilities)
- , m_parameterMatch(other.m_parameterMatch)
- , m_applicationId(other.m_applicationId)
- , m_backgroundHandlerId(other.m_backgroundHandlerId)
-{ }
-
-Intent::Intent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
- const QStringList &capabilities, Intent::Visibility visibility, const QVariantMap &parameterMatch)
+Intent::Intent(const QString &id, const QString &packageId, const QString &applicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories)
: m_intentId(id)
, m_visibility(visibility)
, m_requiredCapabilities(capabilities)
, m_parameterMatch(parameterMatch)
+ , m_packageId(packageId)
, m_applicationId(applicationId)
- , m_backgroundHandlerId(backgroundHandlerId)
-{ }
-
-Intent::operator bool() const
+ , m_categories(categories)
+ , m_icon(icon)
{
- return !m_intentId.isEmpty();
-}
-
-bool Intent::operator==(const Intent &other) const
-{
- return (m_intentId == other.m_intentId)
- && (m_visibility == other.m_visibility)
- && (m_requiredCapabilities == other.m_requiredCapabilities)
- && (m_parameterMatch == other.m_parameterMatch)
- && (m_applicationId == other.m_applicationId)
- && (m_backgroundHandlerId == other.m_backgroundHandlerId);
-}
-
-bool Intent::operator <(const Intent &other) const
-{
- return (m_intentId < other.m_intentId) ? true : (m_applicationId < other.m_applicationId);
+ for (auto it = names.cbegin(); it != names.cend(); ++it)
+ m_names.insert(it.key(), it.value());
}
QString Intent::intentId() const
@@ -165,14 +157,14 @@ QVariantMap Intent::parameterMatch() const
return m_parameterMatch;
}
-QString Intent::applicationId() const
+QString Intent::packageId() const
{
- return m_applicationId;
+ return m_packageId;
}
-QString Intent::backgroundServiceId() const
+QString Intent::applicationId() const
{
- return m_backgroundHandlerId;
+ return m_applicationId;
}
bool Intent::checkParameterMatch(const QVariantMap &parameters) const
@@ -200,7 +192,7 @@ bool Intent::checkParameterMatch(const QVariantMap &parameters) const
bool foundMatch = false;
const QVariantList rvlist = requiredValue.toList();
for (const QVariant &rv2 : rvlist) {
- if (actualValue.canConvert(rv2.type()) && actualValue == rv2) {
+ if (actualValue.canConvert(int(rv2.type())) && actualValue == rv2) {
foundMatch = true;
break;
}
@@ -219,4 +211,36 @@ bool Intent::checkParameterMatch(const QVariantMap &parameters) const
return true;
}
+QUrl Intent::icon() const
+{
+ return m_icon;
+}
+
+QString Intent::name() const
+{
+ QVariant name;
+ if (!m_names.isEmpty()) {
+ name = m_names.value(QLocale::system().name()); //TODO: language changes
+ if (name.isNull())
+ name = m_names.value(qSL("en"));
+ if (name.isNull())
+ name = m_names.value(qSL("en_US"));
+ if (name.isNull())
+ name = *m_names.constBegin();
+ } else {
+ name = intentId();
+ }
+ return name.toString();
+}
+
+QVariantMap Intent::names() const
+{
+ return m_names;
+}
+
+QStringList Intent::categories() const
+{
+ return m_categories;
+}
+
QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intent.h b/src/intent-server-lib/intent.h
index 0de7f4f1..a8a04d52 100644
--- a/src/intent-server-lib/intent.h
+++ b/src/intent-server-lib/intent.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,24 +43,31 @@
#pragma once
+#include <QObject>
#include <QString>
+#include <QUrl>
#include <QStringList>
#include <QVariantMap>
#include <QtAppManCommon/global.h>
QT_BEGIN_NAMESPACE_AM
-class Intent
+class Intent : public QObject
{
- Q_GADGET
- Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/Intent 2.0 UNCREATABLE")
+ Q_OBJECT
+ Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentObject 2.0 UNCREATABLE")
- Q_PROPERTY(bool valid READ (operator bool))
- Q_PROPERTY(QString intentId READ intentId)
- Q_PROPERTY(QString applicationId READ applicationId)
- Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Intent)::Visibility visibility READ visibility)
- Q_PROPERTY(QStringList requiredCapabilities READ requiredCapabilities)
- Q_PROPERTY(QVariantMap parameterMatch READ parameterMatch)
+ Q_PROPERTY(QString intentId READ intentId CONSTANT)
+ Q_PROPERTY(QString packageId READ packageId CONSTANT)
+ Q_PROPERTY(QString applicationId READ applicationId CONSTANT)
+ Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Intent)::Visibility visibility READ visibility CONSTANT)
+ Q_PROPERTY(QStringList requiredCapabilities READ requiredCapabilities CONSTANT)
+ Q_PROPERTY(QVariantMap parameterMatch READ parameterMatch CONSTANT)
+
+ Q_PROPERTY(QUrl icon READ icon CONSTANT)
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QVariantMap names READ names CONSTANT)
+ Q_PROPERTY(QStringList categories READ categories CONSTANT)
public:
enum Visibility {
@@ -69,38 +77,45 @@ public:
Q_ENUM(Visibility)
Intent();
- Intent(const Intent &other);
QString intentId() const;
Visibility visibility() const;
QStringList requiredCapabilities() const;
QVariantMap parameterMatch() const;
+ QString packageId() const;
QString applicationId() const;
- QString backgroundServiceId() const;
bool checkParameterMatch(const QVariantMap &parameters) const;
- explicit operator bool() const;
- bool operator ==(const Intent &other) const;
- bool operator <(const Intent &other) const; // need for QMetaType::registerComparators
+ QUrl icon() const;
+ QString name() const;
+ QVariantMap names() const;
+ QString description() const;
+ QVariantMap descriptions() const;
+ QStringList categories() const;
private:
- Intent(const QString &intentId, const QString &applicationId, const QString &backgroundHandlerId,
+ Intent(const QString &intentId, const QString &packageId, const QString &applicationId,
const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch = QVariantMap());
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories);
QString m_intentId;
Visibility m_visibility = Private;
QStringList m_requiredCapabilities;
QVariantMap m_parameterMatch;
+ QString m_packageId;
QString m_applicationId;
- QString m_backgroundHandlerId;
+
+ QVariantMap m_names; // language -> name
+ QStringList m_categories;
+ QUrl m_icon;
friend class IntentServer;
};
QT_END_NAMESPACE_AM
-Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_AM(Intent))
+Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_AM(Intent *))
diff --git a/src/intent-server-lib/intentmodel.cpp b/src/intent-server-lib/intentmodel.cpp
new file mode 100644
index 00000000..4342fc9f
--- /dev/null
+++ b/src/intent-server-lib/intentmodel.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+#include <QJSEngine>
+#include <QJSValueList>
+
+#include "global.h"
+#include "logging.h"
+#include "intentserver.h"
+#include "intentmodel.h"
+#include "intent.h"
+
+
+/*!
+ \qmltype IntentModel
+ \inherits QSortFilterProxyModel
+ \ingroup system-ui
+ \inqmlmodule QtApplicationManager.SystemUI
+ \brief A proxy model for the IntentServer singleton.
+
+ The IntentModel type provides a customizable model that can be used to tailor the
+ IntentServer model to your needs. The IntentServer singleton is a model itself,
+ that includes all available intents. In contrast, the IntentModel supports filtering
+ and sorting.
+
+ Since the IntentModel is based on the IntentServer model, the latter is referred
+ to as the \e source model. The IntentModel includes the same \l {IntentServer Roles}
+ {roles} as the IntentServer model.
+
+ \note If you require a model with all intents, with no filtering whatsoever, you should
+ use the IntentServer directly, as it has better performance.
+
+ The following code snippet displays the icons of all the intents belonging to the \c
+ com.pelagicore.test package:
+
+ \qml
+ import QtQuick 2.6
+ import QtApplicationManager.SystemUI 2.0
+
+ ListView {
+ model: IntentModel {
+ filterFunction: function(intent) {
+ return intent.packageId == 'com.pelagicore.test'
+ }
+ }
+
+ delegate: Image {
+ source: icon
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty int IntentModel::count
+ \readonly
+
+ Holds the number of intents included in this model.
+*/
+
+/*!
+ \qmlproperty var IntentModel::filterFunction
+
+ A JavaScript function callback that is invoked for each intent in the IntentServer
+ source model. This function gets one IntentObject parameter and must return a Boolean.
+ If the intent passed should be included in this model, then the function must return
+ \c true; \c false otherwise.
+
+ If you need no filtering at all, you should set this property to an undefined (the default) or
+ null value.
+
+ \note Whenever this function is changed, the filter is reevaluated. Changes in the source model
+ are reflected. Since the type is derived from QSortFilterProxyModel, the
+ \l {QSortFilterProxyModel::invalidate()}{invalidate()} slot can be used to force a reevaluation.
+*/
+
+/*!
+ \qmlproperty var IntentModel::sortFunction
+
+ A JavaScript function callback that is invoked to sort the intents in this model. This function
+ gets two IntentObject parameters and must return a Boolean. If the first intent should have a
+ smaller index in this model than the second, the function must return \c true; \c false
+ otherwise.
+
+ If you need no sorting at all, you should set this property to an undefined (the default) or
+ null value.
+
+ \note Whenever this function is changed, the model is sorted. Changes in the source model are
+ reflected. Since the type is derived from QSortFilterProxyModel, the
+ \l {QSortFilterProxyModel::invalidate()}{invalidate()} slot can be used to force a sort.
+*/
+
+
+QT_BEGIN_NAMESPACE_AM
+
+
+class IntentModelPrivate
+{
+public:
+ QJSEngine *m_engine = nullptr;
+ QJSValue m_filterFunction;
+ QJSValue m_sortFunction;
+};
+
+
+IntentModel::IntentModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+ , d(new IntentModelPrivate())
+{
+ setSourceModel(IntentServer::instance());
+
+ connect(this, &QAbstractItemModel::rowsInserted, this, &IntentModel::countChanged);
+ connect(this, &QAbstractItemModel::rowsRemoved, this, &IntentModel::countChanged);
+ connect(this, &QAbstractItemModel::layoutChanged, this, &IntentModel::countChanged);
+ connect(this, &QAbstractItemModel::modelReset, this, &IntentModel::countChanged);
+}
+
+int IntentModel::count() const
+{
+ return rowCount();
+}
+
+bool IntentModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+ Q_UNUSED(source_parent)
+
+ if (!d->m_engine)
+ d->m_engine = getJSEngine();
+ if (!d->m_engine)
+ qCWarning(LogSystem) << "IntentModel can't filter without a JavaScript engine";
+
+ if (d->m_engine && d->m_filterFunction.isCallable()) {
+ const QObject *intent = IntentServer::instance()->intent(source_row);
+ QJSValueList args = { d->m_engine->newQObject(const_cast<QObject*>(intent)) };
+ return d->m_filterFunction.call(args).toBool();
+ }
+
+ return true;
+}
+
+bool IntentModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
+{
+ if (!d->m_engine)
+ d->m_engine = getJSEngine();
+ if (!d->m_engine)
+ qCWarning(LogSystem) << "IntentModel can't sort without a JavaScript engine";
+
+ if (d->m_engine && d->m_sortFunction.isCallable()) {
+ const QObject *intent1 = IntentServer::instance()->intent(source_left.row());
+ const QObject *intent2 = IntentServer::instance()->intent(source_right.row());
+ QJSValueList args = { d->m_engine->newQObject(const_cast<QObject*>(intent1)),
+ d->m_engine->newQObject(const_cast<QObject*>(intent2)) };
+ return d->m_sortFunction.call(args).toBool();
+ }
+
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+}
+
+QJSValue IntentModel::filterFunction() const
+{
+ return d->m_filterFunction;
+}
+
+void IntentModel::setFilterFunction(const QJSValue &callback)
+{
+ if (!callback.equals(d->m_filterFunction)) {
+ d->m_filterFunction = callback;
+ emit filterFunctionChanged();
+ invalidateFilter();
+ }
+}
+
+QJSValue IntentModel::sortFunction() const
+{
+ return d->m_sortFunction;
+}
+
+void IntentModel::setSortFunction(const QJSValue &callback)
+{
+ if (!callback.equals(d->m_sortFunction)) {
+ d->m_sortFunction = callback;
+ emit sortFunctionChanged();
+ invalidate();
+ sort(0);
+ }
+}
+
+/*!
+ \qmlmethod int IntentModel::indexOfIntent(string intentId, string applicationId, var parameters)
+
+ Maps the intent corresponding to the given \a intentId, \a applicationId and \a parameters to
+ its position within this model. Returns \c -1 if the specified intent is invalid, or not part of
+ this model.
+*/
+int IntentModel::indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters) const
+{
+ int idx = IntentServer::instance()->indexOfIntent(intentId, applicationId, parameters);
+ return idx != -1 ? mapFromSource(idx) : idx;
+}
+
+/*!
+ \qmlmethod int IntentModel::indexOfIntent(IntentObject intent)
+
+ Maps the \a intent to its position within this model. Returns \c -1 if the specified intent is
+ invalid, or not part of this model.
+*/
+int IntentModel::indexOfIntent(Intent *intent)
+{
+ int idx = IntentServer::instance()->indexOfIntent(intent);
+ return idx != -1 ? mapFromSource(idx) : idx;
+
+}
+
+/*!
+ \qmlmethod int IntentModel::mapToSource(int index)
+
+ Maps an intent's \a index in this model to the corresponding index in the
+ IntentServer model. Returns \c -1 if the specified \a index is invalid.
+*/
+int IntentModel::mapToSource(int ourIndex) const
+{
+ return QSortFilterProxyModel::mapToSource(index(ourIndex, 0)).row();
+}
+
+/*!
+ \qmlmethod int IntentModel::mapFromSource(int index)
+
+ Maps an intenet's \a index from the IntentServer model to the corresponding index in
+ this model. Returns \c -1 if the specified \a index is invalid.
+*/
+int IntentModel::mapFromSource(int sourceIndex) const
+{
+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(sourceIndex, 0)).row();
+}
+
+QJSEngine *IntentModel::getJSEngine() const
+{
+ QQmlContext *context = QQmlEngine::contextForObject(this);
+ return context ? reinterpret_cast<QJSEngine*>(context->engine()) : nullptr;
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentmodel.h b/src/intent-server-lib/intentmodel.h
new file mode 100644
index 00000000..c8d7b257
--- /dev/null
+++ b/src/intent-server-lib/intentmodel.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QSortFilterProxyModel>
+#include <QJSValue>
+#include <QtAppManCommon/global.h>
+
+QT_FORWARD_DECLARE_CLASS(QJSEngine);
+
+QT_BEGIN_NAMESPACE_AM
+
+class Intent;
+class IntentModelPrivate;
+
+class IntentModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentModel 2.0")
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(QJSValue filterFunction READ filterFunction WRITE setFilterFunction NOTIFY filterFunctionChanged)
+ Q_PROPERTY(QJSValue sortFunction READ sortFunction WRITE setSortFunction NOTIFY sortFunctionChanged)
+
+public:
+ IntentModel(QObject *parent = nullptr);
+
+ int count() const;
+
+ QJSValue filterFunction() const;
+ void setFilterFunction(const QJSValue &callback);
+
+ QJSValue sortFunction() const;
+ void setSortFunction(const QJSValue &callback);
+
+ Q_INVOKABLE int indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = {}) const;
+ Q_INVOKABLE int indexOfIntent(Intent *intent);
+ Q_INVOKABLE int mapToSource(int ourIndex) const;
+ Q_INVOKABLE int mapFromSource(int sourceIndex) const;
+
+protected:
+ using QSortFilterProxyModel::mapToSource;
+ using QSortFilterProxyModel::mapFromSource;
+
+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
+ bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
+
+signals:
+ void countChanged();
+ void filterFunctionChanged();
+ void sortFunctionChanged();
+
+private:
+ QJSEngine *getJSEngine() const;
+
+ IntentModelPrivate *d;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intentserver.cpp b/src/intent-server-lib/intentserver.cpp
index 0ba11e2f..9a0603f3 100644
--- a/src/intent-server-lib/intentserver.cpp
+++ b/src/intent-server-lib/intentserver.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -43,6 +44,8 @@
#include "intentserver.h"
#include "intentserversysteminterface.h"
#include "intentserverrequest.h"
+#include "intentmodel.h"
+
#include <QtAppManCommon/logging.h>
#include <algorithm>
@@ -66,11 +69,58 @@ QT_BEGIN_NAMESPACE_AM
\brief The System-UI side singleton representing the Intents sub-system.
This singleton serves two purposes: for one, it gives the System-UI access to the database of
- all the available intents via intentList, plus it exposes the API to deal with ambigous intent
+ all the available intents via its item model API, plus it exposes the API to deal with ambigous intent
requests. Intent requests can be ambigous if the requesting party only specified the \c
intentId, but not the targeted \c applicationId in its call to
IntentClient::sendIntentRequest(). In these cases, it is the responsibility of the System-UI to
disambiguate these requests by reacting on the disambiguationRequest() signal.
+
+ The type is derived from \c QAbstractListModel, so it can be used directly
+ as a model in app-grid views.
+
+ \target IntentServer Roles
+
+ The following roles are available in this model:
+
+ \table
+ \header
+ \li Role name
+ \li Type
+ \li Description
+ \row
+ \li \c intentId
+ \li string
+ \li The id of the intent.
+ \row
+ \li \c packageId
+ \li string
+ \li The unique id of the package that the handling application of this intent is part of.
+ \row
+ \li \c applicationId
+ \li string
+ \li The id of the application responsible for handling this intent.
+ \row
+ \li \c name
+ \li string
+ \li The name of the intent. If possible, already translated to the current locale.
+ If no name was defined for the intent, the name of the corresponding package will be
+ returned.
+ \row
+ \li \c icon
+ \li string
+ \li The URL of the intent's icon.
+ If no icon was defined for the intent, the icon of the corresponding package will be
+ returned.
+ \row
+ \li \c categories
+ \li list<string>
+ \li The categories this intent is registered for via its meta-data file.
+ \row
+ \li \c intent
+ \li Intent
+ \li The underlying Intent object for quick access to the properties outside of a
+ model delegate.
+ \endtable
*/
/*! \qmlsignal IntentServer::intentAdded(Intent intent)
@@ -87,7 +137,20 @@ QT_BEGIN_NAMESPACE_AM
intentList.
*/
+enum Roles
+{
+ IntentId = Qt::UserRole,
+ ApplicationId,
+ PackageId,
+ ParameterMatch,
+ Name,
+ Icon,
+ Categories,
+ IntentItem
+};
+
IntentServer *IntentServer::s_instance = nullptr;
+QHash<int, QByteArray> IntentServer::s_roleNames;
IntentServer *IntentServer::createInstance(IntentServerSystemInterface *systemInterface)
{
@@ -99,15 +162,8 @@ IntentServer *IntentServer::createInstance(IntentServerSystemInterface *systemIn
QScopedPointer<IntentServer> is(new IntentServer(systemInterface));
systemInterface->initialize(is.data());
- qRegisterMetaType<Intent>("Intent");
- QMetaType::registerComparators<Intent>();
-
- // Have a nicer name in the C++ API, since QML cannot cope with QList<Q_GADGET-type>
- qRegisterMetaType<QVariantList>("IntentList");
-
- // needed to get access to the Visibility enum from QML
- qmlRegisterUncreatableType<Intent>("QtApplicationManager.SystemUI", 2, 0, "Intent",
- qSL("Cannot create objects of type Intent"));
+ qmlRegisterType<Intent>("QtApplicationManager.SystemUI", 2, 0, "IntentObject");
+ qmlRegisterType<IntentModel>("QtApplicationManager.SystemUI", 2, 0, "IntentModel");
qmlRegisterSingletonType<IntentServer>("QtApplicationManager.SystemUI", 2, 0, "IntentServer",
[](QQmlEngine *, QJSEngine *) -> QObject * {
@@ -140,12 +196,21 @@ void IntentServer::setReplyFromApplicationTimeout(int timeout)
}
IntentServer::IntentServer(IntentServerSystemInterface *systemInterface, QObject *parent)
- : QObject(parent)
+ : QAbstractListModel(parent)
, m_systemInterface(systemInterface)
{
m_systemInterface->setParent(this);
- connect(this, &IntentServer::intentAdded, this, &IntentServer::intentListChanged);
- connect(this, &IntentServer::intentRemoved, this, &IntentServer::intentListChanged);
+
+ if (s_roleNames.isEmpty()) {
+ s_roleNames.insert(IntentId, "intentId");
+ s_roleNames.insert(ApplicationId, "applicationId");
+ s_roleNames.insert(PackageId, "packageId");
+ s_roleNames.insert(ParameterMatch, "parameterMatch");
+ s_roleNames.insert(Name, "name");
+ s_roleNames.insert(Icon, "icon");
+ s_roleNames.insert(Categories, "categories");
+ s_roleNames.insert(IntentItem, "intent");
+ }
}
IntentServer::~IntentServer()
@@ -153,120 +218,120 @@ IntentServer::~IntentServer()
s_instance = nullptr;
}
-bool IntentServer::addApplication(const QString &applicationId)
+bool IntentServer::addPackage(const QString &packageId)
{
- if (m_knownApplications.contains(applicationId))
+ if (m_knownApplications.contains(packageId))
return false;
- m_knownApplications << applicationId;
+ m_knownApplications.insert(packageId, QStringList());
return true;
}
-void IntentServer::removeApplication(const QString &applicationId)
+void IntentServer::removePackage(const QString &packageId)
{
- m_knownBackgroundServices.remove(applicationId);
- m_knownApplications.removeOne(applicationId);
+ m_knownApplications.remove(packageId);
}
-bool IntentServer::addApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId)
+bool IntentServer::addApplication(const QString &applicationId, const QString &packageId)
{
- if (!m_knownApplications.contains(applicationId))
+ if (!m_knownApplications.contains(packageId))
return false;
- const QStringList services = m_knownBackgroundServices.value(applicationId);
- if (services.contains(backgroundServiceId))
+ if (m_knownApplications.value(packageId).contains(applicationId))
return false;
- m_knownBackgroundServices[applicationId].append(backgroundServiceId);
+ m_knownApplications[packageId].append(applicationId);
return true;
}
-void IntentServer::removeApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId)
-{
- m_knownBackgroundServices[applicationId].removeAll(backgroundServiceId);
-}
-
-Intent IntentServer::addIntent(const QString &id, const QString &applicationId,
- const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch)
+void IntentServer::removeApplication(const QString &applicationId, const QString &packageId)
{
- return addIntent(id, applicationId, QString(), capabilities, visibility, parameterMatch);
+ m_knownApplications[packageId].removeAll(applicationId);
}
-Intent IntentServer::addIntent(const QString &id, const QString &applicationId,
- const QString &backgroundHandlerId,
- const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch)
+Intent *IntentServer::addIntent(const QString &id, const QString &packageId,
+ const QString &handlingApplicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories)
{
- if (id.isEmpty()
- || !m_knownApplications.contains(applicationId)
- || find(id, applicationId)
- || (!backgroundHandlerId.isEmpty()
- && !m_knownBackgroundServices[applicationId].contains(backgroundHandlerId))) {
- return Intent();
+ try {
+ if (id.isEmpty())
+ throw "no id specified";
+ if (packageId.isEmpty())
+ throw "no packageId specified";
+ if (handlingApplicationId.isEmpty())
+ throw "no handlingApplicationId specified";
+ if (!m_knownApplications.contains(packageId))
+ throw "packageId is not known";
+ if (!m_knownApplications.value(packageId).contains(handlingApplicationId))
+ throw "applicationId is not known or not part of the specified package";
+ if (applicationIntent(id, handlingApplicationId))
+ throw "intent with given id/handlingApplicationId already exists";
+ } catch (const char *e) {
+ qCWarning(LogIntents) << "Cannot add intent" << id << "in package" << packageId
+ << "handled by" << handlingApplicationId << ":" << e;
+ return nullptr;
}
- auto intent = Intent(id, applicationId, backgroundHandlerId, capabilities, visibility,
- parameterMatch);
+ auto intent = new Intent(id, packageId, handlingApplicationId, capabilities, visibility,
+ parameterMatch, names, icon, categories);
+ QQmlEngine::setObjectOwnership(intent, QQmlEngine::CppOwnership);
+
+ beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_intents << intent;
+ endInsertRows();
+
+ emit countChanged();
emit intentAdded(intent);
return intent;
}
-void IntentServer::removeIntent(const Intent &intent)
+void IntentServer::removeIntent(Intent *intent)
{
int index = m_intents.indexOf(intent);
if (index >= 0) {
+ emit intentAboutToBeRemoved(intent);
+ beginRemoveRows(QModelIndex(), index, index);
m_intents.removeAt(index);
- emit intentRemoved(intent);
- }
-}
+ endRemoveRows();
-QVector<Intent> IntentServer::all() const
-{
- return m_intents;
+ emit countChanged();
+ }
}
-QVector<Intent> IntentServer::filterByIntentId(const QVector<Intent> &intents, const QString &intentId,
- const QVariantMap &parameters) const
+QVector<Intent *> IntentServer::filterByIntentId(const QVector<Intent *> &intents, const QString &intentId,
+ const QVariantMap &parameters) const
{
- QVector<Intent> result;
+ QVector<Intent *> result;
std::copy_if(intents.cbegin(), intents.cend(), std::back_inserter(result),
- [intentId, parameters](const Intent &intent) -> bool {
- return (intent.intentId() == intentId) && intent.checkParameterMatch(parameters);
+ [intentId, parameters](Intent *intent) -> bool {
+ return (intent->intentId() == intentId) && intent->checkParameterMatch(parameters);
});
return result;
}
-QVector<Intent> IntentServer::filterByHandlingApplicationId(const QVector<Intent> &intents,
- const QString &handlingApplicationId,
- const QVariantMap &parameters) const
-{
- QVector<Intent> result;
- std::copy_if(intents.cbegin(), intents.cend(), std::back_inserter(result),
- [handlingApplicationId, parameters](const Intent &intent) -> bool {
- return (intent.applicationId() == handlingApplicationId) && intent.checkParameterMatch(parameters);
-
- });
- return result;
-}
-QVector<Intent> IntentServer::filterByRequestingApplicationId(const QVector<Intent> &intents,
- const QString &requestingApplicationId) const
+QVector<Intent *> IntentServer::filterByRequestingApplicationId(const QVector<Intent *> &intents,
+ const QString &requestingApplicationId) const
{
- QVector<Intent> result;
+ const QString requestingPackageId = packageIdForApplicationId(requestingApplicationId);
+
+ QVector<Intent *> result;
std::copy_if(intents.cbegin(), intents.cend(), std::back_inserter(result),
- [this, requestingApplicationId](const Intent &intent) -> bool {
+ [this, requestingPackageId, requestingApplicationId](Intent *intent) -> bool {
// filter on visibility and capabilities, if the requesting app is different from the
// handling app
- if (intent.applicationId() != requestingApplicationId) {
- if (intent.visibility() == Intent::Private) {
- qCDebug(LogIntents) << "Not considering" << intent.intentId() << "/" << intent.applicationId()
- << "due to private visibility";
+
+ if (intent->packageId() != requestingPackageId) {
+ if (intent->visibility() == Intent::Private) {
+ qCDebug(LogIntents) << "Not considering" << intent->intentId() << "in package"
+ << intent->packageId() << "due to private visibility";
return false;
- } else if (!intent.requiredCapabilities().isEmpty()
+ } else if (!intent->requiredCapabilities().isEmpty()
&& !m_systemInterface->checkApplicationCapabilities(requestingApplicationId,
- intent.requiredCapabilities())) {
- qCDebug(LogIntents) << "Not considering" << intent.intentId() << "/" << intent.applicationId()
- << "due to missing capabilities";
+ intent->requiredCapabilities())) {
+ qCDebug(LogIntents) << "Not considering" << intent->intentId() << "in package"
+ << intent->packageId()
+ << "due to missing capabilities of requesting application";
return false;
}
}
@@ -275,35 +340,181 @@ QVector<Intent> IntentServer::filterByRequestingApplicationId(const QVector<Inte
return result;
}
-/*! \qmlproperty list<Intent> IntentServer::intentList
+int IntentServer::rowCount(const QModelIndex &parent) const
+{
+ return parent.isValid() ? -1 : m_intents.count();
+}
+
+QVariant IntentServer::data(const QModelIndex &index, int role) const
+{
+ if (index.parent().isValid() || !index.isValid())
+ return QVariant();
+
+ Intent *intent = m_intents.at(index.row());
+
+ switch (role) {
+ case IntentId:
+ return intent->intentId();
+ case PackageId:
+ return intent->packageId();
+ case ApplicationId:
+ return intent->applicationId();
+ case ParameterMatch:
+ return intent->parameterMatch();
+ case Name:
+ return intent->name();
+ case Icon:
+ return intent->icon();
+ case Categories:
+ return intent->categories();
+ case IntentItem:
+ return QVariant::fromValue(intent);
+ }
+ return QVariant();
+}
+
+QHash<int, QByteArray> IntentServer::roleNames() const
+{
+ return s_roleNames;
+}
+
+int IntentServer::count() const
+{
+ return rowCount();
+}
- The list of all registered \l{Intent}{Intents} in the system.
+/*!
+ \qmlmethod object IntentServer::get(int index)
+
+ Retrieves the model data at \a index as a JavaScript object. See the
+ \l {IntentServer Roles}{role names} for the expected object fields.
+
+ Returns an empty object if the specified \a index is invalid.
+
+ \note This is very inefficient if you only want to access a single property from QML; use
+ intent() instead to access the Intent object's properties directly.
*/
+QVariantMap IntentServer::get(int index) const
+{
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "IntentServer::get(index): invalid index:" << index;
+ return QVariantMap();
+ }
-IntentList IntentServer::intentList() const
+ QVariantMap map;
+ QHash<int, QByteArray> roles = roleNames();
+ for (auto it = roles.begin(); it != roles.end(); ++it)
+ map.insert(qL1S(it.value()), data(this->index(index), it.key()));
+ return map;
+}
+
+/*!
+ \qmlmethod IntentObject IntentServer::intent(int index)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a index in the
+ model, or \c null if the index is invalid.
+
+ \note The object ownership of the returned Intent object stays with the application-manager.
+ If you want to store this pointer, you can use the IntentServer's QAbstractListModel
+ signals or the intentAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Intent *IntentServer::intent(int index) const
{
- return convertToQml(all());
+ if (index < 0 || index >= count()) {
+ qCWarning(LogSystem) << "IntentServer::intent(index): invalid index:" << index;
+ return nullptr;
+ }
+ return m_intents.at(index);
}
-/*! \qmlmethod Intent IntentServer::find(string intentId, string applicationId, var parameters)
+/*! \qmlmethod IntentObject IntentServer::applicationIntent(string intentId, string applicationId, var parameters)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a intentId, \a applicationId
+ and \a parameters or \c null if the id does not exist.
This method exposes the same functionality that is used internally to match incoming Intent
requests for the intent identified by \a intentId and targeted for the application identified by
\a applicationId.
Although you could iterate over the intentList yourself in JavaScript, this function has the
added benefit of also checking the optionally provided \a parameters against any given
- \l{Intent::parameterMatch}{parameter matches}.
+ \l{IntentObject::parameterMatch}{parameter matches}.
+
+ \note The object ownership of the returned Intent object stays with the application-manager.
+ If you want to store this pointer, you can use the IntentServer's QAbstractListModel
+ signals or the intentAboutToBeRemoved signal to get notified if the object is about
+ to be deleted on the C++ side.
+*/
+Intent *IntentServer::applicationIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters) const
+{
+ auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
+ [intentId, applicationId, parameters](Intent *intent) -> bool {
+ return (intent->applicationId() == applicationId) && (intent->intentId() == intentId)
+ && intent->checkParameterMatch(parameters);
+ });
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+/*! \qmlmethod IntentObject IntentServer::packageIntent(string intentId, string packageId, var parameters)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a intentId, \a packageId
+ and \a parameters or \c null if the id does not exist.
+
+ \sa applicationIntent
+*/
+Intent *IntentServer::packageIntent(const QString &intentId, const QString &packageId,
+ const QVariantMap &parameters) const
+{
+ auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
+ [intentId, packageId, parameters](Intent *intent) -> bool {
+ return (intent->packageId() == packageId) && (intent->intentId() == intentId)
+ && intent->checkParameterMatch(parameters);
+ });
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+/*! \qmlmethod IntentObject IntentServer::packageIntent(string intentId, string packageId, string applicationId, var parameters)
+
+ Returns the \l{IntentObject}{intent} corresponding to the given \a intentId, \a packageId,
+ \a applicationId and \a parameters or \c null if the id does not exist.
- If no matching Intent is found, the function will return an \l{Intent::valid}{invalid} Intent.
+ \sa applicationIntent
*/
-Intent IntentServer::find(const QString &intentId, const QString &applicationId, const QVariantMap &parameters) const
+Intent *IntentServer::packageIntent(const QString &intentId, const QString &packageId,
+ const QString &applicationId, const QVariantMap &parameters) const
{
auto it = std::find_if(m_intents.cbegin(), m_intents.cend(),
- [intentId, applicationId, parameters](const Intent &intent) -> bool {
- return (intent.applicationId() == applicationId) && (intent.intentId() == intentId)
- && intent.checkParameterMatch(parameters);
+ [intentId, packageId, applicationId, parameters](Intent *intent) -> bool {
+ return (intent->packageId() == packageId) && (intent->applicationId() == applicationId)
+ && (intent->intentId() == intentId) && intent->checkParameterMatch(parameters);
});
- return (it != m_intents.cend()) ? *it : Intent();
+ return (it != m_intents.cend()) ? *it : nullptr;
+}
+
+/*! \qmlmethod int IntentServer::indexOfIntent(string intentId, string applicationId, var parameters)
+
+ Maps the intent corresponding to the given \a intentId, \a applicationId and \a parameters to
+ its position within this model. Returns \c -1 if the specified intent is invalid.
+
+ \sa intent()
+*/
+int IntentServer::indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters) const
+{
+ return m_intents.indexOf(applicationIntent(intentId, applicationId, parameters));
+}
+
+/*! \qmlmethod int IntentServer::indexOfIntent(IntentObject intent)
+
+ Maps the \a intent to its position within this model. Returns \c -1 if the specified intent is
+ invalid.
+
+ \sa intent()
+*/
+int IntentServer::indexOfIntent(Intent *intent)
+{
+ return m_intents.indexOf(intent);
}
void IntentServer::triggerRequestQueue()
@@ -333,7 +544,7 @@ void IntentServer::processRequestQueue()
if (!isSignalConnected(QMetaMethod::fromSignal(&IntentServer::disambiguationRequest))) {
// If the System-UI does not react to the signal, then just use the first match.
- isr->setHandlingApplicationId(isr->potentialIntents().first().applicationId());
+ isr->setHandlingApplicationId(isr->potentialIntents().first()->packageId());
} else {
m_disambiguationQueue.enqueue(isr);
isr->setState(IntentServerRequest::State::WaitingForDisambiguation);
@@ -413,12 +624,23 @@ void IntentServer::processRequestQueue()
triggerRequestQueue();
}
-IntentList IntentServer::convertToQml(const QVector<Intent> &intents)
+QList<QObject *> IntentServer::convertToQml(const QVector<Intent *> &intents)
{
- QVariantList vl;
+ QList<QObject *> ol;
for (auto intent : intents)
- vl << QVariant::fromValue(intent);
- return vl;
+ ol << intent;
+ return ol;
+}
+
+QString IntentServer::packageIdForApplicationId(const QString &applicationId) const
+{
+ for (auto pit = m_knownApplications.cbegin(); pit != m_knownApplications.cend(); ++pit) {
+ for (auto ait = pit.value().cbegin(); ait != pit.value().cend(); ++ait) {
+ if (*ait == applicationId)
+ return pit.key();
+ }
+ }
+ return QString();
}
/*!
@@ -449,7 +671,7 @@ IntentList IntentServer::convertToQml(const QVector<Intent> &intents)
\sa IntentClient::sendIntentRequest
*/
-void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, const Intent &selectedIntent)
+void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, Intent *selectedIntent)
{
internalDisambiguateRequest(requestId, false, selectedIntent);
}
@@ -464,10 +686,10 @@ void IntentServer::acknowledgeDisambiguationRequest(const QUuid &requestId, cons
*/
void IntentServer::rejectDisambiguationRequest(const QUuid &requestId)
{
- internalDisambiguateRequest(requestId, true, Intent());
+ internalDisambiguateRequest(requestId, true, nullptr);
}
-void IntentServer::internalDisambiguateRequest(const QUuid &requestId, bool reject, const Intent &selectedIntent)
+void IntentServer::internalDisambiguateRequest(const QUuid &requestId, bool reject, Intent *selectedIntent)
{
IntentServerRequest *isr = nullptr;
for (int i = 0; i < m_disambiguationQueue.size(); ++i) {
@@ -478,17 +700,17 @@ void IntentServer::internalDisambiguateRequest(const QUuid &requestId, bool reje
}
if (!isr) {
- qmlWarning(this) << "Got a disambiguation acknowledge or reject for intent" << requestId
- << "but no disambiguation was expected for this intent";
+ qmlWarning(this) << "Got a disambiguation acknowledge or reject for intent " << requestId
+ << ", but no disambiguation was expected for this intent";
} else {
if (reject) {
isr->setRequestFailed(qSL("Disambiguation was rejected"));
} else if (isr->potentialIntents().contains(selectedIntent)) {
- isr->setHandlingApplicationId(selectedIntent.applicationId());
+ isr->setHandlingApplicationId(selectedIntent->packageId());
isr->setState(IntentServerRequest::State::Disambiguated);
} else {
qCWarning(LogIntents) << "IntentServer::acknowledgeDisambiguationRequest for intent"
- << requestId << "tried to disambiguate to the intent" << selectedIntent.intentId()
+ << requestId << "tried to disambiguate to the intent" << selectedIntent->intentId()
<< "which was not in the list of potential disambiguations";
isr->setRequestFailed(qSL("Failed to disambiguate"));
@@ -570,11 +792,13 @@ IntentServerRequest *IntentServer::requestToSystem(const QString &requestingAppl
return nullptr;
}
- QVector<Intent> intents;
- if (applicationId.isEmpty())
- intents = filterByIntentId(all(), intentId, parameters);
- else if (Intent intent = find(intentId, applicationId, parameters))
- intents << intent;
+ QVector<Intent *> intents;
+ if (applicationId.isEmpty()) {
+ intents = filterByIntentId(m_intents, intentId, parameters);
+ } else {
+ if (Intent *intent = this->applicationIntent(intentId, applicationId, parameters))
+ intents << intent;
+ }
if (intents.isEmpty()) {
qCWarning(LogIntents) << "Unknown intent" << intentId << "was requested from application"
diff --git a/src/intent-server-lib/intentserver.h b/src/intent-server-lib/intentserver.h
index 1bf62ade..6bd16228 100644
--- a/src/intent-server-lib/intentserver.h
+++ b/src/intent-server-lib/intentserver.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -42,7 +43,7 @@
#pragma once
-#include <QObject>
+#include <QAbstractListModel>
#include <QVariantMap>
#include <QVector>
#include <QUuid>
@@ -57,16 +58,13 @@ class AbstractRuntime;
class IntentServerRequest;
class IntentServerSystemInterface;
-// We cannot expose a list of Q_GADGETs to QML in a type-safe way. We can however
-// at least try to make the C++ side of the API a bit more descriptive.
-typedef QVariantList IntentList;
-class IntentServer : public QObject
+class IntentServer : public QAbstractListModel
{
Q_OBJECT
Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/IntentServer 2.0 SINGLETON")
- Q_PROPERTY(IntentList intentList READ intentList NOTIFY intentListChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
~IntentServer() override;
@@ -77,51 +75,63 @@ public:
void setStartApplicationTimeout(int timeout);
void setReplyFromApplicationTimeout(int timeout);
- bool addApplication(const QString &applicationId);
- void removeApplication(const QString &applicationId);
+ bool addPackage(const QString &packageId);
+ void removePackage(const QString &packageId);
- bool addApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId);
- void removeApplicationBackgroundHandler(const QString &applicationId, const QString &backgroundServiceId);
+ bool addApplication(const QString &applicationId, const QString &packageId);
+ void removeApplication(const QString &applicationId, const QString &packageId);
- Intent addIntent(const QString &id, const QString &applicationId, const QStringList &capabilities,
- Intent::Visibility visibility, const QVariantMap &parameterMatch = QVariantMap());
+ Intent *addIntent(const QString &id, const QString &packageId, const QString &handlingApplicationId,
+ const QStringList &capabilities, Intent::Visibility visibility,
+ const QVariantMap &parameterMatch, const QMap<QString, QString> &names,
+ const QUrl &icon, const QStringList &categories);
- Intent addIntent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
- const QStringList &capabilities, Intent::Visibility visibility,
- const QVariantMap &parameterMatch = QVariantMap());
+ void removeIntent(Intent *intent);
- void removeIntent(const Intent &intent);
+ QVector<Intent *> filterByIntentId(const QVector<Intent *> &intents, const QString &intentId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ QVector<Intent *> filterByRequestingApplicationId(const QVector<Intent *> &intents,
+ const QString &requestingApplicationId) const;
- QVector<Intent> all() const;
- QVector<Intent> filterByIntentId(const QVector<Intent> &intents, const QString &intentId,
- const QVariantMap &parameters = QVariantMap{}) const;
- QVector<Intent> filterByHandlingApplicationId(const QVector<Intent> &intents,
- const QString &handlingApplicationId,
- const QVariantMap &parameters = QVariantMap{}) const;
- QVector<Intent> filterByRequestingApplicationId(const QVector<Intent> &intents,
- const QString &requestingApplicationId) const;
+ // the item model part
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
// vvv QML API vvv
- IntentList intentList() const;
-
- Q_INVOKABLE Intent find(const QString &intentId, const QString &applicationId,
- const QVariantMap &parameters = QVariantMap{}) const;
-
- Q_INVOKABLE void acknowledgeDisambiguationRequest(const QUuid &requestId, const Intent &selectedIntent);
+ int count() const;
+
+ Q_INVOKABLE QVariantMap get(int index) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *intent(int index) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *applicationIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *packageIntent(const QString &intentId, const QString &packageId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE QT_PREPEND_NAMESPACE_AM(Intent) *packageIntent(const QString &intentId, const QString &packageId,
+ const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE int indexOfIntent(const QString &intentId, const QString &applicationId,
+ const QVariantMap &parameters = QVariantMap{}) const;
+ Q_INVOKABLE int indexOfIntent(Intent *intent);
+
+ Q_INVOKABLE void acknowledgeDisambiguationRequest(const QUuid &requestId, Intent *selectedIntent);
Q_INVOKABLE void rejectDisambiguationRequest(const QUuid &requestId);
signals:
- void intentAdded(const Intent &intent);
- void intentRemoved(const Intent &intent);
- void intentListChanged();
+ void intentAdded(QT_PREPEND_NAMESPACE_AM(Intent) *intent);
+ void intentAboutToBeRemoved(QT_PREPEND_NAMESPACE_AM(Intent) *intent);
- void disambiguationRequest(const QUuid &requestId, const IntentList &potentialIntents,
+ void countChanged();
+
+ // QML can only accept QList<QObject *> as signal parameter. Using QList<Intent *> or
+ // QVector<QObject> will lead to an undefined QVariant on the QML side.
+ void disambiguationRequest(const QUuid &requestId, const QList<QObject *> &potentialIntents,
const QVariantMap &parameters);
/// ^^^ QML API ^^^
private:
- void internalDisambiguateRequest(const QUuid &requestId, bool reject, const Intent &selectedIntent);
+ void internalDisambiguateRequest(const QUuid &requestId, bool reject, Intent *selectedIntent);
void applicationWasStarted(const QString &applicationId);
void replyFromApplication(const QString &replyingApplicationId, const QUuid &requestId,
bool error, const QVariantMap &result);
@@ -132,15 +142,17 @@ private:
void enqueueRequest(IntentServerRequest *isr);
void processRequestQueue();
- static IntentList convertToQml(const QVector<Intent> &intents);
+ static QList<QObject *> convertToQml(const QVector<Intent *> &intents);
+ QString packageIdForApplicationId(const QString &applicationId) const;
private:
IntentServer(IntentServerSystemInterface *systemInterface, QObject *parent = nullptr);
Q_DISABLE_COPY(IntentServer)
static IntentServer *s_instance;
- QStringList m_knownApplications;
- QMap<QString, QStringList> m_knownBackgroundServices;
+ static QHash<int, QByteArray> s_roleNames;
+
+ QMap<QString, QStringList> m_knownApplications;
QQueue<IntentServerRequest *> m_requestQueue;
@@ -148,11 +160,12 @@ private:
QQueue<IntentServerRequest *> m_startingAppQueue;
QQueue<IntentServerRequest *> m_sentToAppQueue;
- int m_disambiguationTimeout = 10000;
- int m_startingAppTimeout = 3000;
- int m_sentToAppTimeout = 5000;
+ // no timeouts by default -- these have to be set at runtime
+ int m_disambiguationTimeout = 0;
+ int m_startingAppTimeout = 0;
+ int m_sentToAppTimeout = 0;
- QVector<Intent> m_intents;
+ QVector<Intent *> m_intents;
IntentServerSystemInterface *m_systemInterface;
friend class IntentServerSystemInterface;
diff --git a/src/intent-server-lib/intentserverrequest.cpp b/src/intent-server-lib/intentserverrequest.cpp
index 52fd8280..059d20e8 100644
--- a/src/intent-server-lib/intentserverrequest.cpp
+++ b/src/intent-server-lib/intentserverrequest.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -45,7 +46,7 @@
QT_BEGIN_NAMESPACE_AM
IntentServerRequest::IntentServerRequest(const QString &requestingApplicationId, const QString &intentId,
- const QVector<Intent> &potentialIntents,
+ const QVector<Intent *> &potentialIntents,
const QVariantMap &parameters)
: m_id(QUuid::createUuid())
, m_state(State::ReceivedRequest)
@@ -57,7 +58,7 @@ IntentServerRequest::IntentServerRequest(const QString &requestingApplicationId,
Q_ASSERT(!potentialIntents.isEmpty());
if (potentialIntents.size() == 1)
- setHandlingApplicationId(potentialIntents.first().applicationId());
+ setHandlingApplicationId(potentialIntents.first()->applicationId());
}
IntentServerRequest::State IntentServerRequest::state() const
@@ -85,7 +86,7 @@ QString IntentServerRequest::handlingApplicationId() const
return m_handlingApplicationId;
}
-QVector<Intent> IntentServerRequest::potentialIntents() const
+QVector<Intent *> IntentServerRequest::potentialIntents() const
{
return m_potentialIntents;
}
diff --git a/src/intent-server-lib/intentserverrequest.h b/src/intent-server-lib/intentserverrequest.h
index 1d3b2980..78904c52 100644
--- a/src/intent-server-lib/intentserverrequest.h
+++ b/src/intent-server-lib/intentserverrequest.h
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -60,7 +61,7 @@ class IntentServerRequest
public:
IntentServerRequest(const QString &requestingApplicationId, const QString &intentId,
- const QVector<Intent> &potentialIntents, const QVariantMap &parameters);
+ const QVector<Intent *> &potentialIntents, const QVariantMap &parameters);
enum class State {
ReceivedRequest,
@@ -79,7 +80,7 @@ public:
QString intentId() const;
QString requestingApplicationId() const;
QString handlingApplicationId() const;
- QVector<Intent> potentialIntents() const;
+ QVector<Intent *> potentialIntents() const;
QVariantMap parameters() const;
bool succeeded() const;
QVariantMap result() const;
@@ -97,7 +98,7 @@ private:
QString m_intentId;
QString m_requestingApplicationId;
QString m_handlingApplicationId;
- QVector<Intent> m_potentialIntents;
+ QVector<Intent *> m_potentialIntents;
QVariantMap m_parameters;
QVariantMap m_result;
};
diff --git a/src/intent-server-lib/intentserversysteminterface.cpp b/src/intent-server-lib/intentserversysteminterface.cpp
index 84e54b02..f6552c02 100644
--- a/src/intent-server-lib/intentserversysteminterface.cpp
+++ b/src/intent-server-lib/intentserversysteminterface.cpp
@@ -1,10 +1,11 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage
@@ -60,7 +61,10 @@ IntentServer *IntentServerSystemInterface::intentServer() const
return m_is;
}
-IntentServerRequest *IntentServerSystemInterface::requestToSystem(const QString &requestingApplicationId, const QString &intentId, const QString &applicationId, const QVariantMap &parameters)
+IntentServerRequest *IntentServerSystemInterface::requestToSystem(const QString &requestingApplicationId,
+ const QString &intentId,
+ const QString &applicationId,
+ const QVariantMap &parameters)
{
// not possible to do via signal, due to return value
return m_is->requestToSystem(requestingApplicationId, intentId, applicationId, parameters);
diff --git a/src/intent-server-lib/intentserversysteminterface.h b/src/intent-server-lib/intentserversysteminterface.h
index 3e03806b..1a2d22e5 100644
--- a/src/intent-server-lib/intentserversysteminterface.h
+++ b/src/intent-server-lib/intentserversysteminterface.h
@@ -4,7 +4,7 @@
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the Luxoft Application Manager.
+** This file is part of the Qt Application Manager.
**
** $QT_BEGIN_LICENSE:LGPL-QTAS$
** Commercial License Usage