aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt18
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/converter.cpp61
-rw-r--r--src/common/converter.h36
-rw-r--r--src/common/qdbusactiongroup.cpp106
-rw-r--r--src/common/qdbusactiongroup.h23
-rw-r--r--src/common/qdbusmenumodel.cpp69
-rw-r--r--src/common/qdbusmenumodel.h7
-rw-r--r--src/common/qdbusobject.cpp50
-rw-r--r--src/common/qmenumodel.cpp83
-rw-r--r--src/common/qmenumodel.h1
-rw-r--r--tests/client/CMakeLists.txt1
-rw-r--r--tests/script/dbusmenuscript.cpp13
-rw-r--r--tests/script/dbusmenuscript.h2
-rw-r--r--tests/script/menuscript.py53
15 files changed, 383 insertions, 142 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65e6fa8..fe36672 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,12 +36,16 @@ else()
add_subdirectory(tests)
endif()
+# Doc
+OPTION(GENERATE_DOC "Enable qdoc generation" OFF)
+if(GENERATE_DOC)
+ message(STATUS "QDoc enabled.")
+ find_program(QDOC_BIN qdoc3)
+ if(NOT QDOC_BIN)
+ message(FATAL_ERROR "qdoc command not found")
+ else()
+ add_subdirectory(doc)
+ endif()
+endif()
-# Tests Tools
-#if(NOT DBUS_RUNNER)
-# message(STATUS "dbus-test-runner not found tests disabled.")
-#else()
-# enable_testing()
-# add_subdirectory(tests)
-#endif()
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 1428000..a4f5e2e 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,6 +1,7 @@
project(qmenumodelcommon)
set(QMENUMODELCOMMON_SRC
+ converter.cpp
qmenumodel.cpp
qdbusobject.cpp
qdbusmenumodel.cpp
@@ -8,6 +9,7 @@ set(QMENUMODELCOMMON_SRC
)
set(QMENUMODELCOMMON_HEADERS
+ converter.h
qmenumodel.h
qdbusobject.h
qdbusmenumodel.h
diff --git a/src/common/converter.cpp b/src/common/converter.cpp
new file mode 100644
index 0000000..a8ccb0f
--- /dev/null
+++ b/src/common/converter.cpp
@@ -0,0 +1,61 @@
+#include "converter.h"
+
+#include <QDebug>
+
+/*! \internal */
+QVariant Converter::parseGVariant(GVariant *value)
+{
+ QVariant result;
+ if (value == NULL) {
+ return result;
+ }
+
+ const GVariantType *type = g_variant_get_type(value);
+ if (g_variant_type_equal(type, G_VARIANT_TYPE_BOOLEAN)) {
+ result.setValue((bool)g_variant_get_boolean(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) {
+ result.setValue(g_variant_get_byte(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) {
+ result.setValue(g_variant_get_int16(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) {
+ result.setValue(g_variant_get_uint16(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) {
+ result.setValue(g_variant_get_int32(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) {
+ result.setValue(g_variant_get_uint32(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) {
+ result.setValue(g_variant_get_int64(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) {
+ result.setValue(g_variant_get_uint64(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_DOUBLE)) {
+ result.setValue(g_variant_get_double(value));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_STRING)) {
+ gsize size = 0;
+ const gchar *v = g_variant_get_string(value, &size);
+ result.setValue(QString::fromLatin1(v, size));
+ } else {
+ qWarning() << "Unsupported GVariant value";
+ }
+
+ /* TODO: implement convertions to others types
+ * G_VARIANT_TYPE_HANDLE
+ * G_VARIANT_TYPE_OBJECT_PATH
+ * G_VARIANT_TYPE_SIGNATURE
+ * G_VARIANT_TYPE_VARIANT
+ * G_VARIANT_TYPE_ANY
+ * G_VARIANT_TYPE_BASIC
+ * G_VARIANT_TYPE_MAYBE
+ * G_VARIANT_TYPE_ARRAY
+ * G_VARIANT_TYPE_TUPLE
+ * G_VARIANT_TYPE_UNIT
+ * G_VARIANT_TYPE_DICT_ENTRY
+ * G_VARIANT_TYPE_DICTIONARY
+ * G_VARIANT_TYPE_STRING_ARRAY
+ * G_VARIANT_TYPE_BYTESTRING
+ * G_VARIANT_TYPE_OBJECT_PATH_ARRAY
+ * G_VARIANT_TYPE_BYTESTRING_ARRAY
+ * G_VARIANT_TYPE_VARDICT
+ */
+
+ return result;
+}
diff --git a/src/common/converter.h b/src/common/converter.h
new file mode 100644
index 0000000..adbad71
--- /dev/null
+++ b/src/common/converter.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Renato Araujo Oliveira Filho <renato@canonical.com>
+ */
+
+#ifndef CONVERTER_H
+#define CONVERTER_H
+
+#include <QVariant>
+#include <glib.h>
+
+class Converter
+{
+public:
+ static QVariant parseGVariant(GVariant *value);
+
+private:
+ Converter();
+ Converter(const Converter &other);
+};
+
+#endif
diff --git a/src/common/qdbusactiongroup.cpp b/src/common/qdbusactiongroup.cpp
index 51bc4ac..e453215 100644
--- a/src/common/qdbusactiongroup.cpp
+++ b/src/common/qdbusactiongroup.cpp
@@ -18,26 +18,60 @@
*/
#include "qdbusactiongroup.h"
+#include "converter.h"
#include <QDebug>
#include <gio/gio.h>
+/*!
+ \qmlclass QDBusActionGroup
+ \inherits QDBusObject
+
+ \brief A DBusActionGroup implementation to be used with \l QDBusMenuModel
+
+ \bold {This component is under heavy development.}
+
+ This class can be used as a proxy for an action group that is exported over D-Bus
+
+ \code
+ QDBusActionGroup {
+ id: actionGroup
+ busType: 1
+ busName: "com.ubuntu.menu"
+ objectPath: "com/ubuntu/menu/actions"
+ }
+
+ Button {
+ onClicked: actionGroup.getAction("app.quit").trigger()
+ }
+ \endcode
+*/
+
+/*! \internal */
QDBusActionGroup::QDBusActionGroup(QObject *parent)
:QObject(parent),
m_actionGroup(NULL)
{
}
+/*! \internal */
QDBusActionGroup::~QDBusActionGroup()
{
clear();
}
-QAction *QDBusActionGroup::getAction(const QString &actionName)
+/*!
+ \qmlmethod QDBusActionGroup::action(QString name)
+
+ Look for a action with the same name and return a \l QAction object.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+QAction *QDBusActionGroup::action(const QString &name)
{
Q_FOREACH(QAction *act, m_actions) {
- if (act->text() == actionName) {
+ if (act->text() == name) {
return act;
}
}
@@ -45,11 +79,22 @@ QAction *QDBusActionGroup::getAction(const QString &actionName)
return NULL;
}
+/*!
+ \qmlproperty int QDBusActionGroup::count
+ This property holds the number of actions inside of \l QDBusActionGroup
+*/
+int QDBusActionGroup::count() const
+{
+ return m_actions.count();
+}
+
+/*! \internal */
void QDBusActionGroup::serviceVanish(GDBusConnection *)
{
clear();
}
+/*! \internal */
void QDBusActionGroup::serviceAppear(GDBusConnection *connection)
{
GDBusActionGroup *ag = g_dbus_action_group_get(connection,
@@ -61,36 +106,19 @@ void QDBusActionGroup::serviceAppear(GDBusConnection *connection)
}
}
+/*! \internal */
void QDBusActionGroup::start()
{
QDBusObject::connect();
}
+/*! \internal */
void QDBusActionGroup::stop()
{
QDBusObject::disconnect();
}
-void QDBusActionGroup::busTypeChanged(BusType)
-{
- busTypeChanged();
-}
-
-void QDBusActionGroup::busNameChanged(const QString &)
-{
- busNameChanged();
-}
-
-void QDBusActionGroup::objectPathChanged(const QString &objectPath)
-{
- objectPathChanged();
-}
-
-void QDBusActionGroup::statusChanged(ConnectionStatus status)
-{
- statusChanged();
-}
-
+/*! \internal */
void QDBusActionGroup::setIntBusType(int busType)
{
if ((busType > None) && (busType < LastBusType)) {
@@ -98,6 +126,7 @@ void QDBusActionGroup::setIntBusType(int busType)
}
}
+/*! \internal */
void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag)
{
if (m_actionGroup == reinterpret_cast<GActionGroup*>(ag)) {
@@ -107,16 +136,16 @@ void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag)
if (m_actionGroup) {
g_signal_handler_disconnect(m_actionGroup, m_signalActionAddId);
g_signal_handler_disconnect(m_actionGroup, m_signalActionRemovedId);
- m_signalActionAddId = m_signalActionRemovedId = 0;
+ g_signal_handler_disconnect(m_actionGroup, m_signalStateChangedId);
+ m_signalActionAddId = m_signalActionRemovedId = m_signalStateChangedId = 0;
g_object_unref(m_actionGroup);
}
m_actionGroup = reinterpret_cast<GActionGroup*>(ag);
if (m_actionGroup) {
-
m_signalActionAddId = g_signal_connect(m_actionGroup,
- "action-add",
+ "action-added",
G_CALLBACK(QDBusActionGroup::onActionAdded),
this);
@@ -125,6 +154,11 @@ void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag)
G_CALLBACK(QDBusActionGroup::onActionRemoved),
this);
+ m_signalStateChangedId = g_signal_connect(m_actionGroup,
+ "action-state-changed",
+ G_CALLBACK(QDBusActionGroup::onActionStateChanged),
+ this);
+
gchar **actionNames = g_action_group_list_actions(m_actionGroup);
for(int i=0; actionNames[i] != NULL; i++) {
addAction(actionNames[i]);
@@ -133,6 +167,7 @@ void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag)
}
}
+/*! \internal */
void QDBusActionGroup::addAction(const char *actionName)
{
QAction *act = new QAction(actionName, this);
@@ -150,35 +185,51 @@ void QDBusActionGroup::addAction(const char *actionName)
}
}
+ QObject::connect(act, SIGNAL(triggered()), this, SLOT(onActionTriggered()));
+
// remove any older action with the same name
removeAction(actionName);
m_actions.insert(act);
+ Q_EMIT countChanged(m_actions.count());
}
+/*! \internal */
+void QDBusActionGroup::onActionTriggered()
+{
+ QAction *act = qobject_cast<QAction*>(QObject::sender());
+ g_action_group_activate_action(m_actionGroup, act->text().toLatin1(), NULL);
+}
+
+/*! \internal */
void QDBusActionGroup::removeAction(const char *actionName)
{
Q_FOREACH(QAction *act, m_actions) {
if (act->text() == actionName) {
m_actions.remove(act);
delete act;
+ Q_EMIT countChanged(m_actions.count());
break;
}
}
}
+/*! \internal */
void QDBusActionGroup::updateAction(const char *actionName, GVariant *state)
{
- QAction *action = getAction(actionName);
+ QAction *action = this->action(actionName);
if ((action != NULL) && (state != NULL)) {
const GVariantType *stateType = g_variant_get_type(state);
if (stateType == G_VARIANT_TYPE_BOOLEAN) {
action->setChecked(g_variant_get_boolean(state));
}
+
+ Q_EMIT actionStateChanged(actionName, Converter::parseGVariant(state));
}
}
+/*! \internal */
void QDBusActionGroup::clear()
{
Q_FOREACH(QAction *act, m_actions) {
@@ -192,12 +243,14 @@ void QDBusActionGroup::clear()
}
}
+/*! \internal */
void QDBusActionGroup::onActionAdded(GDBusActionGroup *, gchar *actionName, gpointer data)
{
QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data);
self->addAction(actionName);
}
+/*! \internal */
void QDBusActionGroup::onActionRemoved(GDBusActionGroup *, gchar *actionName, gpointer data)
{
QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data);
@@ -205,6 +258,7 @@ void QDBusActionGroup::onActionRemoved(GDBusActionGroup *, gchar *actionName, gp
}
+/*! \internal */
void QDBusActionGroup::onActionStateChanged(GDBusActionGroup *ag, gchar *actionName, GVariant *value, gpointer data)
{
QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data);
diff --git a/src/common/qdbusactiongroup.h b/src/common/qdbusactiongroup.h
index 4ae0074..3ff7927 100644
--- a/src/common/qdbusactiongroup.h
+++ b/src/common/qdbusactiongroup.h
@@ -33,36 +33,41 @@ class QDBusActionGroup : public QObject, public QDBusObject
Q_PROPERTY(QString busName READ busName WRITE setBusName NOTIFY busNameChanged)
Q_PROPERTY(QString objectPath READ objectPath WRITE setObjectPath NOTIFY objectPathChanged)
Q_PROPERTY(int status READ status NOTIFY statusChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
QDBusActionGroup(QObject *parent=0);
~QDBusActionGroup();
+ int count() const;
+
Q_SIGNALS:
- void busTypeChanged();
- void busNameChanged();
- void objectPathChanged();
- void statusChanged();
+ void busTypeChanged(BusType type);
+ void busNameChanged(const QString &busNameChanged);
+ void objectPathChanged(const QString &objectPath);
+ void statusChanged(ConnectionStatus status);
+ void actionStateChanged(const QString &name, QVariant value);
+ void countChanged(int count);
public Q_SLOTS:
void start();
void stop();
- QAction *getAction(const QString &actionName);
+ QAction *action(const QString &actionName);
protected:
virtual void serviceAppear(GDBusConnection *connection);
virtual void serviceVanish(GDBusConnection *connection);
- virtual void busTypeChanged(BusType type);
- virtual void busNameChanged(const QString &busNameChanged);
- virtual void objectPathChanged(const QString &objectPath);
- virtual void statusChanged(ConnectionStatus status);
+
+private Q_SLOTS:
+ void onActionTriggered();
private:
GActionGroup *m_actionGroup;
QSet<QAction*> m_actions;
int m_signalActionAddId;
int m_signalActionRemovedId;
+ int m_signalStateChangedId;
// workaround to support int as bustType
void setIntBusType(int busType);
diff --git a/src/common/qdbusmenumodel.cpp b/src/common/qdbusmenumodel.cpp
index cae1288..9b824b4 100644
--- a/src/common/qdbusmenumodel.cpp
+++ b/src/common/qdbusmenumodel.cpp
@@ -20,30 +20,76 @@
#include "qdbusmenumodel.h"
#include <QDebug>
+/*!
+ \qmlclass QDBusMenuModel
+ \inherits QDBusObject
+
+ \brief The QDBusMenuModel class defines the list model for DBus menus
+
+ \bold {This component is under heavy development.}
+
+ This class expose the menu previous exported over DBus.
+
+ \code
+ QDBusMenuModel {
+ id: menuModel
+ busType: 1
+ busName: "com.ubuntu.menu"
+ objectPath: "com/ubuntu/menu"
+ }
+
+ ListView {
+ id: view
+ model: menuModel
+ Component.onCompleted: menuModel.start()
+ }
+ \endcode
+*/
+
+/*! \internal */
QDBusMenuModel::QDBusMenuModel(QObject *parent)
:QMenuModel(0, parent)
{
}
+/*! \internal */
QDBusMenuModel::~QDBusMenuModel()
{
}
+/*!
+ \qmlmethod QDBusMenuModel::start()
+
+ Start dbus watch for the busName and wait until it appears.
+ The status will change to connecting after call this function, and as soon the busName
+ apperas and the objectPat was found this will change to Connected.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
void QDBusMenuModel::start()
{
QDBusObject::connect();
}
+/*!
+ \qmlmethod QDBusMenuModel::stop()
+
+ Stops dbus watch and clear the model, the status wil change to Disconnected.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
void QDBusMenuModel::stop()
{
QDBusObject::disconnect();
}
+/*! \internal */
void QDBusMenuModel::serviceVanish(GDBusConnection *)
{
setMenuModel(NULL);
}
+/*! \internal */
void QDBusMenuModel::serviceAppear(GDBusConnection *connection)
{
GMenuModel *model = reinterpret_cast<GMenuModel*>(g_dbus_menu_model_get(connection,
@@ -55,28 +101,7 @@ void QDBusMenuModel::serviceAppear(GDBusConnection *connection)
}
}
-/*
-void QDBusMenuModel::busTypeChanged(BusType)
-{
- busTypeChanged();
-}
-
-void QDBusMenuModel::busNameChanged(const QString &)
-{
- busNameChanged();
-}
-
-void QDBusMenuModel::objectPathChanged(const QString &objectPath)
-{
- objectPathChanged();
-}
-
-void QDBusMenuModel::statusChanged(ConnectionStatus status)
-{
- statusChanged();
-}
-*/
-
+/*! \internal */
void QDBusMenuModel::setIntBusType(int busType)
{
if ((busType > None) && (busType < LastBusType)) {
diff --git a/src/common/qdbusmenumodel.h b/src/common/qdbusmenumodel.h
index 14ac4a2..8308268 100644
--- a/src/common/qdbusmenumodel.h
+++ b/src/common/qdbusmenumodel.h
@@ -51,13 +51,6 @@ protected:
virtual void serviceAppear(GDBusConnection *connection);
virtual void serviceVanish(GDBusConnection *connection);
- /*
- virtual void busTypeChanged(BusType type);
- virtual void busNameChanged(const QString &busNameChanged);
- virtual void objectPathChanged(const QString &objectPath);
- virtual void statusChanged(ConnectionStatus status);
- */
-
private:
// workaround to support int as bustType
void setIntBusType(int busType);
diff --git a/src/common/qdbusobject.cpp b/src/common/qdbusobject.cpp
index 174a9d8..d5ac44b 100644
--- a/src/common/qdbusobject.cpp
+++ b/src/common/qdbusobject.cpp
@@ -21,12 +21,58 @@
#include <QDebug>
+/*!
+ \qmlclass QDBusObject
+ \brief The QDBusObject is a base class
+
+ \bold {This component is under heavy development.}
+
+ This is a abstracted class used by QDBusMenuModel and QDBusActionGroup
+*/
+
+/*!
+ \qmlproperty int QDBusObject::busType
+ This property holds the dbus session type which will be used during the connection.
+
+ This must be seteed before call start method
+ The valid values are:
+ \list
+ \o 1 - SessionBus
+ \o 2 - SystemBus
+ \endlist
+*/
+
+/*!
+ \qmlproperty int QDBusObject::busName
+ This property holds the dbus service name related with menu.
+
+ This must be seteed before call start method
+*/
+
+/*!
+ \qmlproperty int QDBusObject::objectPath
+ This property holds the dbus object path related with the menu.
+
+ This must be seteed before call start method
+*/
+
+/*!
+ \qmlproperty int QDBusObject::status
+ This property holds current dbus connection status
+
+ Te velid status are:
+ \list
+ \o 0 - Disconnected
+ \o 1 - Connecting
+ \o 2 - Connected
+ \endlist
+*/
+
QDBusObject::QDBusObject()
:m_watchId(0),
m_busType(None),
m_status(QDBusObject::Disconnected)
{
- qDebug() << "DBUS CREATED";
qRegisterMetaType<QDBusObject::ConnectionStatus>("QDBusObject::ConnectionStatus");
}
@@ -128,7 +174,6 @@ void QDBusObject::disconnect()
void QDBusObject::onServiceAppeared(GDBusConnection *connection, const gchar *, const gchar *, gpointer data)
{
QDBusObject *self = reinterpret_cast<QDBusObject*>(data);
- qDebug() << "service appear";
self->setStatus(QDBusObject::Connected);
self->serviceAppear(connection);
@@ -137,7 +182,6 @@ void QDBusObject::onServiceAppeared(GDBusConnection *connection, const gchar *,
void QDBusObject::onServiceFanished(GDBusConnection *connection, const gchar *, gpointer data)
{
QDBusObject *self = reinterpret_cast<QDBusObject*>(data);
- qDebug() << "service disappear";
self->setStatus(QDBusObject::Connecting);
self->serviceVanish(connection);
diff --git a/src/common/qmenumodel.cpp b/src/common/qmenumodel.cpp
index 230365c..ffb3fb6 100644
--- a/src/common/qmenumodel.cpp
+++ b/src/common/qmenumodel.cpp
@@ -18,9 +18,20 @@
*/
#include "qmenumodel.h"
+#include "converter.h"
#include <QDebug>
+/*!
+ \qmlclass QMenuModel
+ \brief The QMenuModel class implements the base list model for menus
+
+ \bold {This component is under heavy development.}
+
+ This is a abstracted class used by \l QDBusMenuModel.
+*/
+
+/*! \internal */
QMenuModel::QMenuModel(GMenuModel *other, QObject *parent)
: QAbstractListModel(parent),
m_menuModel(0),
@@ -38,11 +49,13 @@ QMenuModel::QMenuModel(GMenuModel *other, QObject *parent)
setMenuModel(other);
}
+/*! \internal */
QMenuModel::~QMenuModel()
{
setMenuModel(NULL);
}
+/*! \internal */
void QMenuModel::setMenuModel(GMenuModel *other)
{
if (m_menuModel == other) {
@@ -71,17 +84,19 @@ void QMenuModel::setMenuModel(GMenuModel *other)
endResetModel();
}
+/*! \internal */
GMenuModel *QMenuModel::menuModel() const
{
return m_menuModel;
}
-/* QAbstractItemModel */
+/*! \internal */
int QMenuModel::columnCount(const QModelIndex &) const
{
return 1;
}
+/*! \internal */
QVariant QMenuModel::data(const QModelIndex &index, int role) const
{
QVariant attribute;
@@ -113,11 +128,13 @@ QVariant QMenuModel::data(const QModelIndex &index, int role) const
return attribute;
}
+/*! \internal */
QModelIndex QMenuModel::parent(const QModelIndex &index) const
{
return QModelIndex();
}
+/*! \internal */
int QMenuModel::rowCount(const QModelIndex &) const
{
if (m_menuModel) {
@@ -126,6 +143,7 @@ int QMenuModel::rowCount(const QModelIndex &) const
return 0;
}
+/*! \internal */
QVariant QMenuModel::getStringAttribute(const QModelIndex &index,
const QString &attribute) const
{
@@ -142,6 +160,7 @@ QVariant QMenuModel::getStringAttribute(const QModelIndex &index,
return result;
}
+/*! \internal */
QVariant QMenuModel::getLink(const QModelIndex &index,
const QString &linkName) const
{
@@ -159,6 +178,7 @@ QVariant QMenuModel::getLink(const QModelIndex &index,
return QVariant();
}
+/*! \internal */
QVariant QMenuModel::getExtraProperties(const QModelIndex &index) const
{
GMenuAttributeIter *iter = g_menu_model_iterate_item_attributes(m_menuModel, index.row());
@@ -171,14 +191,14 @@ QVariant QMenuModel::getExtraProperties(const QModelIndex &index) const
GVariant *value = NULL;
while (g_menu_attribute_iter_get_next (iter, &attrName, &value)) {
if (strncmp("x-", attrName, 2) == 0) {
- extra->setProperty(attrName, parseGVariant(value));
+ extra->setProperty(attrName, Converter::parseGVariant(value));
}
}
return QVariant::fromValue<QObject*>(extra);
}
-
+/*! \internal */
void QMenuModel::onItemsChanged(GMenuModel *,
gint position,
gint removed,
@@ -198,60 +218,3 @@ void QMenuModel::onItemsChanged(GMenuModel *,
}
}
-QVariant QMenuModel::parseGVariant(GVariant *value)
-{
- QVariant result;
- if (value == NULL) {
- return result;
- }
-
- const GVariantType *type = g_variant_get_type(value);
- if (g_variant_type_equal(type, G_VARIANT_TYPE_BOOLEAN)) {
- result.setValue((bool)g_variant_get_boolean(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) {
- result.setValue(g_variant_get_byte(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) {
- result.setValue(g_variant_get_int16(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) {
- result.setValue(g_variant_get_uint16(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) {
- result.setValue(g_variant_get_int32(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) {
- result.setValue(g_variant_get_uint32(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) {
- result.setValue(g_variant_get_int64(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) {
- result.setValue(g_variant_get_uint64(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_DOUBLE)) {
- result.setValue(g_variant_get_double(value));
- } else if (g_variant_type_equal(type, G_VARIANT_TYPE_STRING)) {
- gsize size = 0;
- const gchar *v = g_variant_get_string(value, &size);
- result.setValue(QString::fromLatin1(v, size));
- } else {
- qWarning() << "Unsupported GVariant value";
- }
-
- /* TODO: implement convertions to others types
- * G_VARIANT_TYPE_HANDLE
- * G_VARIANT_TYPE_OBJECT_PATH
- * G_VARIANT_TYPE_SIGNATURE
- * G_VARIANT_TYPE_VARIANT
- * G_VARIANT_TYPE_ANY
- * G_VARIANT_TYPE_BASIC
- * G_VARIANT_TYPE_MAYBE
- * G_VARIANT_TYPE_ARRAY
- * G_VARIANT_TYPE_TUPLE
- * G_VARIANT_TYPE_UNIT
- * G_VARIANT_TYPE_DICT_ENTRY
- * G_VARIANT_TYPE_DICTIONARY
- * G_VARIANT_TYPE_STRING_ARRAY
- * G_VARIANT_TYPE_BYTESTRING
- * G_VARIANT_TYPE_OBJECT_PATH_ARRAY
- * G_VARIANT_TYPE_BYTESTRING_ARRAY
- * G_VARIANT_TYPE_VARDICT
- */
-
- return result;
-}
-
diff --git a/src/common/qmenumodel.h b/src/common/qmenumodel.h
index e594ea7..e102f72 100644
--- a/src/common/qmenumodel.h
+++ b/src/common/qmenumodel.h
@@ -58,7 +58,6 @@ private:
QVariant getExtraProperties(const QModelIndex &index) const;
static void onItemsChanged(GMenuModel *model, gint position, gint removed, gint added, gpointer data);
- static QVariant parseGVariant(GVariant *value);
};
#endif
diff --git a/tests/client/CMakeLists.txt b/tests/client/CMakeLists.txt
index bf77461..473ebcd 100644
--- a/tests/client/CMakeLists.txt
+++ b/tests/client/CMakeLists.txt
@@ -44,3 +44,4 @@ endif()
declare_test(servicetest)
declare_test(menuchangestest)
declare_test(modeltest)
+declare_test(actiongrouptest)
diff --git a/tests/script/dbusmenuscript.cpp b/tests/script/dbusmenuscript.cpp
index baf5ac2..b190d5b 100644
--- a/tests/script/dbusmenuscript.cpp
+++ b/tests/script/dbusmenuscript.cpp
@@ -91,3 +91,16 @@ void DBusMenuScript::run()
QTest::qWait(WAIT_TIMEOUT);
}
}
+
+QString DBusMenuScript::popActivatedAction()
+{
+ if (m_script) {
+ QDBusMessage reply = m_script->call("popActivatedAction");
+ if (reply.arguments().count() > 0) {
+ return reply.arguments()[0].toString();
+ }
+ }
+
+ return QString();
+}
+
diff --git a/tests/script/dbusmenuscript.h b/tests/script/dbusmenuscript.h
index 6e9532b..8a93e83 100644
--- a/tests/script/dbusmenuscript.h
+++ b/tests/script/dbusmenuscript.h
@@ -47,6 +47,8 @@ public:
void publishMenu();
void unpublishMenu();
+ QString popActivatedAction();
+
private:
QDBusInterface *m_script;
};
diff --git a/tests/script/menuscript.py b/tests/script/menuscript.py
index 05e226c..f50aacd 100644
--- a/tests/script/menuscript.py
+++ b/tests/script/menuscript.py
@@ -53,6 +53,11 @@ class Script(dbus.service.Object):
self._list.walk()
steps -= 1
+ @dbus.service.method(dbus_interface=INTERFACE_NAME,
+ in_signature='', out_signature='s')
+ def popActivatedAction(self):
+ return self._list._activatedActions.pop(0)
+
@staticmethod
def create(aList):
global bus
@@ -87,6 +92,12 @@ class Action(object):
item = Gio.MenuItem.new(self._kargs['label'], self._kargs['actionName'])
self.setProperties(item, self._kargs['properties'])
parent.append_item(item)
+
+ # Action
+ act = Gio.SimpleAction.new(self._kargs['actionName'], None)
+ act.connect('activate', self._list._onActionActivated)
+ self._list._rootAction.insert(act)
+
elif self._kargs['link'] == 'section':
section = Gio.Menu()
parent.append_section(self._kargs['label'], section)
@@ -99,6 +110,9 @@ class Action(object):
(menu, mId) = self._list.getMenu(menuId)
if mId != -1:
menu.remove(mId)
+ if self._kargs['actionName']:
+ # Remove action
+ self._list._rootAction.remove(self._kargs['actionName'])
else:
print "Remove menu item"
@@ -111,11 +125,15 @@ class Action(object):
class ActionList(object):
def __init__(self, objectPath):
self._actions = []
+ self._actions_bk = []
self._objectPath = objectPath
self._bux = None
- self._exportID = None
+ self._exportMenuID = None
+ self._exportActionID = None
self._ownNameID = None
self._root = None
+ self._rootAction = None
+ self._activatedActions = []
def appendItem(self, label, actionName, link=None, parentId=None, properties=None):
self._actions.append(Action(self, 'append',
@@ -125,9 +143,20 @@ class ActionList(object):
link=link,
properties=properties))
- def removeItem(self, menuId):
+ def removeItem(self, menuId, actionName=None):
self._actions.append(Action(self, 'remove',
- menuId=menuId))
+ menuId=menuId,
+ actionName=actionName))
+
+ def _save(self):
+ self._actions_bk = []
+ self._actions_bk.extend(self._actions)
+
+
+ def _restore(self):
+ if len(self._actions_bk):
+ self._actions = []
+ self._actions.extend(self._actions_bk)
def _findMenu(self, root, ids):
if len(ids) == 0:
@@ -155,18 +184,28 @@ class ActionList(object):
def _exportService(self, connection, name):
self._root = Gio.Menu()
+ self._rootAction = Gio.SimpleActionGroup()
self._bus = connection
- self._exportID = connection.export_menu_model(MENU_OBJECT_PATH, self._root)
+ self._exportMenuID = connection.export_menu_model(MENU_OBJECT_PATH, self._root)
+ self._exportActionID = connection.export_action_group(MENU_OBJECT_PATH, self._rootAction)
def start(self):
+ self._save()
self._ownNameID = Gio.bus_own_name(2, MENU_SERVICE_NAME, 0, self._exportService, None, None)
def stop(self):
- if self._exportID:
- self._bus.unexport_menu_model(self._exportID)
- self._exportID = None
+ if self._exportMenuID:
+ self._bus.unexport_menu_model(self._exportMenuID)
+ self._exportMenuID = None
+
+ if self._exportActionID:
+ self._bus.unexport_action_group(self._exportActionID)
+ self._exportActionID = None
if self._ownNameID:
Gio.bus_unown_name(self._ownNameID)
self._ownNameID = None
+ self._restore()
+ def _onActionActivated(self, action, parameter):
+ self._activatedActions.append(action.get_name())