aboutsummaryrefslogtreecommitdiff
path: root/libqmenumodel
diff options
context:
space:
mode:
authorOlivier Tilloy <olivier.tilloy@canonical.com>2012-10-05 13:26:10 +0000
committerTarmac <>2012-10-05 13:26:10 +0000
commitc3fbab270f60fc374bae50e787e0b2046f127a07 (patch)
tree61d0eae8f1c1e3d23fb6559cb19e920b167b187c /libqmenumodel
parent7961150ad1eaa1b3bc62d5215e274a7b58b0ef72 (diff)
parent696fba50395807c344325af11e71ec74cf370c3d (diff)
downloadqmenumodel-c3fbab270f60fc374bae50e787e0b2046f127a07.tar.gz
qmenumodel-c3fbab270f60fc374bae50e787e0b2046f127a07.tar.bz2
qmenumodel-c3fbab270f60fc374bae50e787e0b2046f127a07.zip
Tweaks to the structure of the code, and added example code.. Approved by Renato Araujo Oliveira Filho, jenkins.
Diffstat (limited to 'libqmenumodel')
-rw-r--r--libqmenumodel/CMakeLists.txt4
-rw-r--r--libqmenumodel/QMenuModel/CMakeLists.txt45
-rw-r--r--libqmenumodel/QMenuModel/plugin.cpp43
-rw-r--r--libqmenumodel/QMenuModel/plugin.h33
-rw-r--r--libqmenumodel/QMenuModel/qmldir1
-rw-r--r--libqmenumodel/src/CMakeLists.txt46
-rw-r--r--libqmenumodel/src/converter.cpp118
-rw-r--r--libqmenumodel/src/converter.h34
-rw-r--r--libqmenumodel/src/dbus-enums.h53
-rw-r--r--libqmenumodel/src/qdbusactiongroup.cpp232
-rw-r--r--libqmenumodel/src/qdbusactiongroup.h85
-rw-r--r--libqmenumodel/src/qdbusmenumodel.cpp109
-rw-r--r--libqmenumodel/src/qdbusmenumodel.h61
-rw-r--r--libqmenumodel/src/qdbusobject.cpp188
-rw-r--r--libqmenumodel/src/qdbusobject.h75
-rw-r--r--libqmenumodel/src/qmenumodel.cpp225
-rw-r--r--libqmenumodel/src/qmenumodel.h66
-rw-r--r--libqmenumodel/src/qstateaction.cpp145
-rw-r--r--libqmenumodel/src/qstateaction.h61
19 files changed, 1624 insertions, 0 deletions
diff --git a/libqmenumodel/CMakeLists.txt b/libqmenumodel/CMakeLists.txt
new file mode 100644
index 0000000..d01cf10
--- /dev/null
+++ b/libqmenumodel/CMakeLists.txt
@@ -0,0 +1,4 @@
+project(libqmenumodel)
+
+add_subdirectory(src)
+add_subdirectory(QMenuModel)
diff --git a/libqmenumodel/QMenuModel/CMakeLists.txt b/libqmenumodel/QMenuModel/CMakeLists.txt
new file mode 100644
index 0000000..5fb1d9f
--- /dev/null
+++ b/libqmenumodel/QMenuModel/CMakeLists.txt
@@ -0,0 +1,45 @@
+project(qmlplugin)
+
+set(QMLPLUGIN_SRC
+ plugin.cpp
+)
+
+set(QMLPLUGIN_HEADERS
+ plugin.h
+)
+
+qt4_wrap_cpp(QMLPLUGIN_MOC
+ ${QMLPLUGIN_HEADERS}
+)
+
+add_library(qmenumodel-qml MODULE
+ ${QMLPLUGIN_SRC}
+ ${QMLPLUGIN_MOC}
+)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${src_SOURCE_DIR}
+ ${QT_INCLUDE_DIR}
+ ${QT_QTCORE_INCLUDE_DIR}
+ ${QT_QTGUI_INCLUDE_DIR}
+ ${QT_QTDECLARATIVE_INCLUDE_DIR}
+ ${GLIB_INCLUDE_DIRS}
+ ${GIO_INCLUDE_DIRS}
+)
+
+target_link_libraries(qmenumodel-qml
+ qmenumodel
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTDCLARATIVE_LIBRARY}
+ ${GLIB_LDFLAGS}
+ ${GIO_LDFLAGS}
+)
+
+execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
+ "${CMAKE_CURRENT_BINARY_DIR}/qmldir")
+
+set(QMLPLUGIN_INSTALL_PREFIX "${QT_IMPORTS_DIR}/QMenuModel")
+install(TARGETS qmenumodel-qml DESTINATION ${QMLPLUGIN_INSTALL_PREFIX})
+install(FILES qmldir DESTINATION ${QMLPLUGIN_INSTALL_PREFIX})
+
diff --git a/libqmenumodel/QMenuModel/plugin.cpp b/libqmenumodel/QMenuModel/plugin.cpp
new file mode 100644
index 0000000..ec51ae9
--- /dev/null
+++ b/libqmenumodel/QMenuModel/plugin.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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>
+ */
+
+#include "plugin.h"
+#include "qmenumodel.h"
+#include "qdbusmenumodel.h"
+#include "qdbusactiongroup.h"
+#include "qstateaction.h"
+
+#include <QtDeclarative>
+
+
+void QMenuModelQmlPlugin::registerTypes(const char *uri)
+{
+ qmlRegisterUncreatableType<QMenuModel>(uri, 0, 1, "QMenuModel",
+ "QMenuModel is a interface");
+ qmlRegisterUncreatableType<QStateAction>(uri, 0, 1, "QStateAction",
+ "QStateAction must be created by QDBusActionGroup::action");
+ qmlRegisterUncreatableType<DBusEnums>(uri, 0, 1, "DBus",
+ "DBus is only a namespace");
+
+ qmlRegisterType<QDBusMenuModel>(uri, 0, 1, "QDBusMenuModel");
+ qmlRegisterType<QDBusActionGroup>(uri, 0, 1, "QDBusActionGroup");
+
+}
+
+Q_EXPORT_PLUGIN2(qmenumodel, QMenuModelQmlPlugin)
diff --git a/libqmenumodel/QMenuModel/plugin.h b/libqmenumodel/QMenuModel/plugin.h
new file mode 100644
index 0000000..e9d6850
--- /dev/null
+++ b/libqmenumodel/QMenuModel/plugin.h
@@ -0,0 +1,33 @@
+/*
+ * 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 QMENUMODELQMLPLUGIN_H
+#define QMENUMODELQMLPLUGIN_H
+
+#include <QDeclarativeExtensionPlugin>
+
+
+class QMenuModelQmlPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif
diff --git a/libqmenumodel/QMenuModel/qmldir b/libqmenumodel/QMenuModel/qmldir
new file mode 100644
index 0000000..32de804
--- /dev/null
+++ b/libqmenumodel/QMenuModel/qmldir
@@ -0,0 +1 @@
+plugin qmenumodel-qml
diff --git a/libqmenumodel/src/CMakeLists.txt b/libqmenumodel/src/CMakeLists.txt
new file mode 100644
index 0000000..17d11f1
--- /dev/null
+++ b/libqmenumodel/src/CMakeLists.txt
@@ -0,0 +1,46 @@
+project(src)
+
+set(QMENUMODEL_SRC
+ converter.cpp
+ qmenumodel.cpp
+ qdbusobject.cpp
+ qdbusmenumodel.cpp
+ qdbusactiongroup.cpp
+ qstateaction.cpp
+)
+
+set(QMENUMODEL_HEADERS
+ converter.h
+ dbus-enums.h
+ qmenumodel.h
+ qdbusobject.h
+ qdbusmenumodel.h
+ qdbusactiongroup.h
+ qstateaction.h
+)
+
+qt4_wrap_cpp(QMENUMODEL_MOC
+ ${QMENUMODEL_HEADERS}
+)
+
+add_library(qmenumodel STATIC
+ ${QMENUMODEL_SRC}
+ ${QMENUMODEL_MOC}
+)
+
+set_target_properties(qmenumodel PROPERTIES COMPILE_FLAGS -fPIC)
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${QT_INCLUDE_DIR}
+ ${QT_QTCORE_INCLUDE_DIR}
+ ${QT_QTGUI_INCLUDE_DIR}
+ ${GLIB_INCLUDE_DIRS}
+ ${GIO_INCLUDE_DIRS}
+)
+
+target_link_libraries(qmenumodel
+ ${QT_QTCORE_LIBRARY}
+ ${GLIB_LDFLAGS}
+ ${GIO_LDFLAGS}
+)
diff --git a/libqmenumodel/src/converter.cpp b/libqmenumodel/src/converter.cpp
new file mode 100644
index 0000000..452f68c
--- /dev/null
+++ b/libqmenumodel/src/converter.cpp
@@ -0,0 +1,118 @@
+extern "C" {
+#include <glib.h>
+}
+
+#include "converter.h"
+
+#include <QDebug>
+#include <QVariant>
+
+/*! \internal */
+QVariant Converter::toQVariant(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(qint16(g_variant_get_int16(value)));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) {
+ result.setValue(quint16(g_variant_get_uint16(value)));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) {
+ result.setValue(qint32(g_variant_get_int32(value)));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) {
+ result.setValue(quint32(g_variant_get_uint32(value)));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) {
+ result.setValue(qint64(g_variant_get_int64(value)));
+ } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) {
+ result.setValue(quint64(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;
+}
+
+static GVariant* toGVariant(const QString &typeName, const QVariant &value)
+{
+ if (typeName == "uchar") {
+ return g_variant_new_byte(value.value<uchar>());
+ } else if (typeName == "short") {
+ return g_variant_new_int16(value.value<short>());
+ } else if (typeName == "ushort") {
+ return g_variant_new_uint16(value.value<ushort>());
+ } else if (typeName == "long") {
+ return g_variant_new_int64(value.value<long>());
+ } else if (typeName == "ulong") {
+ return g_variant_new_uint64(value.value<ulong>());
+ } else {
+ qWarning() << "QVariant type not supported:" << typeName;
+ }
+
+ return NULL;
+}
+
+GVariant* Converter::toGVariant(const QVariant &value)
+{
+ GVariant *result = NULL;
+ if (value.isNull() || !value.isValid())
+ return result;
+
+ switch(value.type()) {
+ case QVariant::Bool:
+ result = g_variant_new_boolean(value.toBool());
+ break;
+ case QVariant::ByteArray:
+ result = g_variant_new_bytestring(value.toByteArray());
+ break;
+ case QVariant::Double:
+ result = g_variant_new_double(value.toDouble());
+ break;
+ case QVariant::Int:
+ result = g_variant_new_int32(value.toInt());
+ break;
+ case QVariant::String:
+ result = g_variant_new_string(value.toString().toLatin1());
+ break;
+ case QVariant::UInt:
+ result = g_variant_new_uint32(value.toUInt());
+ break;
+ default:
+ result = ::toGVariant(value.typeName(), value);
+ }
+
+ return result;
+}
+
diff --git a/libqmenumodel/src/converter.h b/libqmenumodel/src/converter.h
new file mode 100644
index 0000000..5f05bc7
--- /dev/null
+++ b/libqmenumodel/src/converter.h
@@ -0,0 +1,34 @@
+/*
+ * 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
+
+typedef struct _GVariant GVariant;
+class QVariant;
+
+class Converter
+{
+public:
+ static QVariant toQVariant(GVariant *value);
+ static GVariant* toGVariant(const QVariant &value);
+};
+
+#endif // CONVERTER_H
+
diff --git a/libqmenumodel/src/dbus-enums.h b/libqmenumodel/src/dbus-enums.h
new file mode 100644
index 0000000..76149da
--- /dev/null
+++ b/libqmenumodel/src/dbus-enums.h
@@ -0,0 +1,53 @@
+/*
+ * 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:
+ * Olivier Tilloy <olivier.tilloy@canonical.com>
+ */
+
+#ifndef __DBUS_ENUMS__
+#define __DBUS_ENUMS__
+
+#include <QObject>
+
+// This class acts as a namespace only, with the addition that its enums
+// are registered to be exposed on the QML side.
+class DBusEnums : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(BusType)
+ Q_ENUMS(ConnectionStatus)
+
+public:
+ enum BusType {
+ None = 0,
+ SessionBus,
+ SystemBus,
+ LastBusType
+ };
+
+ enum ConnectionStatus {
+ Disconnected = 0,
+ Connecting,
+ Connected
+ };
+
+private:
+ DBusEnums() {}
+};
+
+#endif // __DBUS_ENUMS__
+
diff --git a/libqmenumodel/src/qdbusactiongroup.cpp b/libqmenumodel/src/qdbusactiongroup.cpp
new file mode 100644
index 0000000..5a9e0bd
--- /dev/null
+++ b/libqmenumodel/src/qdbusactiongroup.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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>
+ */
+
+#include "qdbusactiongroup.h"
+#include "qstateaction.h"
+#include "converter.h"
+
+extern "C" {
+#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();
+}
+
+/*!
+ \qmlmethod QDBusActionGroup::action(QString name)
+
+ Look for a action with the same name and return a \l QStateAction object.
+
+ \bold Note: methods should only be called after the Component has completed.
+*/
+QStateAction *QDBusActionGroup::action(const QString &name)
+{
+ QStateAction *act = actionImpl(name);
+ if (act == 0) {
+ act = new QStateAction(this, name);
+ }
+
+ return act;
+}
+
+QVariant QDBusActionGroup::actionState(const QString &name)
+{
+ QVariant result;
+ GVariant *state = g_action_group_get_action_state(m_actionGroup, name.toLatin1());
+ result = Converter::toQVariant(state);
+ if (state) {
+ g_variant_unref(state);
+ }
+ return result;
+}
+
+
+bool QDBusActionGroup::hasAction(const QString &name)
+{
+ if (m_actionGroup) {
+ return g_action_group_has_action(m_actionGroup, name.toLatin1());
+ } else {
+ return false;
+ }
+}
+
+QStateAction *QDBusActionGroup::actionImpl(const QString &name)
+{
+ Q_FOREACH(QStateAction *act, this->findChildren<QStateAction*>()) {
+ if (act->text() == name) {
+ return act;
+ }
+ }
+ return 0;
+}
+
+/*! \internal */
+void QDBusActionGroup::serviceVanish(GDBusConnection *)
+{
+ setActionGroup(NULL);
+}
+
+/*! \internal */
+void QDBusActionGroup::serviceAppear(GDBusConnection *connection)
+{
+ GDBusActionGroup *ag = g_dbus_action_group_get(connection,
+ busName().toLatin1(),
+ objectPath().toLatin1());
+ setActionGroup(ag);
+ if (ag == NULL) {
+ stop();
+ }
+}
+
+/*! \internal */
+void QDBusActionGroup::start()
+{
+ QDBusObject::connect();
+}
+
+/*! \internal */
+void QDBusActionGroup::stop()
+{
+ QDBusObject::disconnect();
+}
+
+/*! \internal */
+void QDBusActionGroup::setIntBusType(int busType)
+{
+ if ((busType > DBusEnums::None) && (busType < DBusEnums::LastBusType)) {
+ setBusType(static_cast<DBusEnums::BusType>(busType));
+ }
+}
+
+/*! \internal */
+void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag)
+{
+ if (m_actionGroup == reinterpret_cast<GActionGroup*>(ag)) {
+ return;
+ }
+
+ if (m_actionGroup) {
+ g_signal_handler_disconnect(m_actionGroup, m_signalActionAddId);
+ g_signal_handler_disconnect(m_actionGroup, m_signalActionRemovedId);
+ g_signal_handler_disconnect(m_actionGroup, m_signalStateChangedId);
+ m_signalActionAddId = m_signalActionRemovedId = m_signalStateChangedId = 0;
+ clear();
+ }
+
+ m_actionGroup = reinterpret_cast<GActionGroup*>(ag);
+
+ if (m_actionGroup) {
+ m_signalActionAddId = g_signal_connect(m_actionGroup,
+ "action-added",
+ G_CALLBACK(QDBusActionGroup::onActionAdded),
+ this);
+
+ m_signalActionRemovedId = g_signal_connect(m_actionGroup,
+ "action-removed",
+ G_CALLBACK(QDBusActionGroup::onActionRemoved),
+ this);
+
+ m_signalStateChangedId = g_signal_connect(m_actionGroup,
+ "action-state-changed",
+ G_CALLBACK(QDBusActionGroup::onActionStateChanged),
+ this);
+
+ gchar **actions = g_action_group_list_actions(m_actionGroup);
+ for(guint i=0; i < g_strv_length(actions); i++) {
+ Q_EMIT actionAppear(actions[i]);
+ }
+ g_strfreev(actions);
+ }
+}
+
+/*! \internal */
+void QDBusActionGroup::clear()
+{
+ Q_FOREACH(QStateAction *act, this->findChildren<QStateAction*>()) {
+ Q_EMIT actionVanish(act->text());
+ }
+
+ if (m_actionGroup != NULL) {
+ g_object_unref(m_actionGroup);
+ m_actionGroup = NULL;
+ }
+}
+
+/*! \internal */
+void QDBusActionGroup::updateActionState(const QString &name, const QVariant &state)
+{
+ if (m_actionGroup != NULL) {
+ g_action_group_activate_action(m_actionGroup, name.toLatin1(), Converter::toGVariant(state));
+ }
+}
+
+/*! \internal */
+void QDBusActionGroup::onActionAdded(GDBusActionGroup *, gchar *name, gpointer data)
+{
+ QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data);
+ Q_EMIT self->actionAppear(name);
+}
+
+/*! \internal */
+void QDBusActionGroup::onActionRemoved(GDBusActionGroup *, gchar *name, gpointer data)
+{
+ QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data);
+ Q_EMIT self->actionVanish(name);
+}
+
+/*! \internal */
+void QDBusActionGroup::onActionStateChanged(GDBusActionGroup *, gchar *name, GVariant *value, gpointer data)
+{
+ QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data);
+ Q_EMIT self->actionStateChanged(name, Converter::toQVariant(value));
+}
diff --git a/libqmenumodel/src/qdbusactiongroup.h b/libqmenumodel/src/qdbusactiongroup.h
new file mode 100644
index 0000000..518f78c
--- /dev/null
+++ b/libqmenumodel/src/qdbusactiongroup.h
@@ -0,0 +1,85 @@
+/*
+ * 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 QDBUSACTIONGROUP_H
+#define QDBUSACTIONGROUP_H
+
+#include "qdbusobject.h"
+
+#include <QObject>
+#include <QVariant>
+
+class QStateAction;
+
+class QDBusActionGroup : public QObject, public QDBusObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int busType READ busType WRITE setIntBusType NOTIFY busTypeChanged)
+ 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)
+
+public:
+ QDBusActionGroup(QObject *parent=0);
+ ~QDBusActionGroup();
+
+ void updateActionState(const QString &name, const QVariant &state);
+ bool hasAction(const QString &name);
+
+ Q_INVOKABLE QStateAction *action(const QString &name);
+ Q_INVOKABLE QVariant actionState(const QString &name);
+
+Q_SIGNALS:
+ void busTypeChanged(DBusEnums::BusType type);
+ void busNameChanged(const QString &busNameChanged);
+ void objectPathChanged(const QString &objectPath);
+ void statusChanged(DBusEnums::ConnectionStatus status);
+ void actionAppear(const QString &name);
+ void actionVanish(const QString &name);
+ void actionStateChanged(const QString &name, QVariant state);
+
+public Q_SLOTS:
+ void start();
+ void stop();
+
+protected:
+ virtual void serviceAppear(GDBusConnection *connection);
+ virtual void serviceVanish(GDBusConnection *connection);
+
+private:
+ GActionGroup *m_actionGroup;
+ int m_signalActionAddId;
+ int m_signalActionRemovedId;
+ int m_signalStateChangedId;
+
+ // workaround to support int as busType
+ void setIntBusType(int busType);
+
+ void setActionGroup(GDBusActionGroup *ag);
+ QStateAction *actionImpl(const QString &name);
+
+ void clear();
+
+ // glib slots
+ static void onActionAdded(GDBusActionGroup *ag, gchar *name, gpointer data);
+ static void onActionRemoved(GDBusActionGroup *ag, gchar *name, gpointer data);
+ static void onActionStateChanged(GDBusActionGroup *ag, gchar *name, GVariant *value, gpointer data);
+};
+
+#endif
diff --git a/libqmenumodel/src/qdbusmenumodel.cpp b/libqmenumodel/src/qdbusmenumodel.cpp
new file mode 100644
index 0000000..88a6084
--- /dev/null
+++ b/libqmenumodel/src/qdbusmenumodel.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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>
+ */
+
+#include "qdbusmenumodel.h"
+
+/*!
+ \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,
+ busName().toLatin1(),
+ objectPath().toLatin1()));
+ setMenuModel(model);
+ if (model == NULL) {
+ stop();
+ }
+}
+
+/*! \internal */
+void QDBusMenuModel::setIntBusType(int busType)
+{
+ if ((busType > DBusEnums::None) && (busType < DBusEnums::LastBusType)) {
+ setBusType(static_cast<DBusEnums::BusType>(busType));
+ }
+}
diff --git a/libqmenumodel/src/qdbusmenumodel.h b/libqmenumodel/src/qdbusmenumodel.h
new file mode 100644
index 0000000..fdf23f7
--- /dev/null
+++ b/libqmenumodel/src/qdbusmenumodel.h
@@ -0,0 +1,61 @@
+/*
+ * 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 QDBUSMENUMODEL_H
+#define QDBUSMENUMODEL_H
+
+#include "qdbusobject.h"
+#include "qmenumodel.h"
+
+extern "C" {
+#include <gio/gio.h>
+}
+
+class QDBusMenuModel : public QMenuModel, public QDBusObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int busType READ busType WRITE setIntBusType NOTIFY busTypeChanged)
+ 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)
+
+public:
+ QDBusMenuModel(QObject *parent=0);
+ ~QDBusMenuModel();
+
+Q_SIGNALS:
+ void busTypeChanged(DBusEnums::BusType type);
+ void busNameChanged(const QString &busNameChanged);
+ void objectPathChanged(const QString &objectPath);
+ void statusChanged(DBusEnums::ConnectionStatus status);
+
+public Q_SLOTS:
+ void start();
+ void stop();
+
+protected:
+ virtual void serviceAppear(GDBusConnection *connection);
+ virtual void serviceVanish(GDBusConnection *connection);
+
+private:
+ // workaround to support int as busType
+ void setIntBusType(int busType);
+};
+
+#endif
diff --git a/libqmenumodel/src/qdbusobject.cpp b/libqmenumodel/src/qdbusobject.cpp
new file mode 100644
index 0000000..abc68b4
--- /dev/null
+++ b/libqmenumodel/src/qdbusobject.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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>
+ */
+
+#include "qdbusobject.h"
+
+#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(DBusEnums::None),
+ m_status(DBusEnums::Disconnected)
+{
+ qRegisterMetaType<DBusEnums::ConnectionStatus>("DBusEnums::ConnectionStatus");
+}
+
+QDBusObject::~QDBusObject()
+{
+ if (m_watchId != 0) {
+ g_bus_unwatch_name (m_watchId);
+ m_watchId = 0;
+ }
+}
+
+DBusEnums::BusType QDBusObject::busType() const
+{
+ return m_busType;
+}
+
+void QDBusObject::setBusType(DBusEnums::BusType type)
+{
+ if (m_busType != type) {
+ if (m_status != DBusEnums::Disconnected)
+ disconnect();
+ m_busType = type;
+ busTypeChanged(m_busType);
+ }
+}
+
+QString QDBusObject::busName() const
+{
+ return m_busName;
+}
+
+void QDBusObject::setBusName(const QString &busName)
+{
+ if (m_busName != busName) {
+ if (m_status != DBusEnums::Disconnected)
+ disconnect();
+ m_busName = busName;
+ busNameChanged(m_busName);
+ }
+}
+
+QString QDBusObject::objectPath() const
+{
+ return m_objectPath;
+}
+
+void QDBusObject::setObjectPath(const QString &objectPath)
+{
+ if (m_objectPath != objectPath) {
+ if (m_status != DBusEnums::Disconnected)
+ disconnect();
+ m_objectPath = objectPath;
+ objectPathChanged(m_objectPath);
+ }
+}
+
+void QDBusObject::setStatus(DBusEnums::ConnectionStatus status)
+{
+ if (m_status != status) {
+ m_status = status;
+ statusChanged(m_status);
+ }
+}
+
+DBusEnums::ConnectionStatus QDBusObject::status() const
+{
+ return m_status;
+}
+
+void QDBusObject::connect()
+{
+ if (m_status != DBusEnums::Disconnected) {
+ return;
+ } else if ((m_busType > DBusEnums::None) && !m_objectPath.isEmpty() && !m_busName.isEmpty()) {
+ GBusType type = m_busType == DBusEnums::SessionBus ? G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM;
+ m_watchId = g_bus_watch_name (type,
+ m_busName.toLatin1(),
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ QDBusObject::onServiceAppeared,
+ QDBusObject::onServiceVanished,
+ this,
+ NULL);
+
+ setStatus(DBusEnums::Connecting);
+ } else {
+ qWarning() << "Invalid dbus connection args";
+ }
+}
+
+void QDBusObject::disconnect()
+{
+ if (m_status != DBusEnums::Disconnected) {
+ g_bus_unwatch_name (m_watchId);
+ m_watchId = 0;
+ setStatus(DBusEnums::Disconnected);
+ }
+}
+
+void QDBusObject::onServiceAppeared(GDBusConnection *connection, const gchar *, const gchar *, gpointer data)
+{
+ QDBusObject *self = reinterpret_cast<QDBusObject*>(data);
+
+ self->setStatus(DBusEnums::Connected);
+ self->serviceAppear(connection);
+}
+
+void QDBusObject::onServiceVanished(GDBusConnection *connection, const gchar *, gpointer data)
+{
+ QDBusObject *self = reinterpret_cast<QDBusObject*>(data);
+
+ self->setStatus(DBusEnums::Connecting);
+ self->serviceVanish(connection);
+}
diff --git a/libqmenumodel/src/qdbusobject.h b/libqmenumodel/src/qdbusobject.h
new file mode 100644
index 0000000..ef2b42f
--- /dev/null
+++ b/libqmenumodel/src/qdbusobject.h
@@ -0,0 +1,75 @@
+/*
+ * 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 QDBUSOBJECT_H
+#define QDBUSOBJECT_H
+
+extern "C" {
+#include <gio/gio.h>
+}
+
+#include <QString>
+
+#include "dbus-enums.h"
+
+class QDBusObject
+{
+public:
+ QDBusObject();
+ ~QDBusObject();
+
+ DBusEnums::BusType busType() const;
+ void setBusType(DBusEnums::BusType type);
+
+ QString busName() const;
+ void setBusName(const QString &busName);
+
+ QString objectPath() const;
+ void setObjectPath(const QString &busName);
+
+ DBusEnums::ConnectionStatus status() const;
+
+ void connect();
+ void disconnect();
+
+protected:
+ virtual void serviceAppear(GDBusConnection *connection) = 0;
+ virtual void serviceVanish(GDBusConnection *connection) = 0;
+
+ // notify functions
+ virtual void busTypeChanged(DBusEnums::BusType type) = 0;
+ virtual void busNameChanged(const QString &busNameChanged) = 0;
+ virtual void objectPathChanged(const QString &objectPath) = 0;
+ virtual void statusChanged(DBusEnums::ConnectionStatus status) = 0;
+
+private:
+ guint m_watchId;
+ DBusEnums::BusType m_busType;
+ QString m_busName;
+ QString m_objectPath;
+ DBusEnums::ConnectionStatus m_status;
+
+ void setStatus(DBusEnums::ConnectionStatus status);
+
+ // glib slots
+ static void onServiceAppeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer data);
+ static void onServiceVanished(GDBusConnection *connection, const gchar *name, gpointer data);
+};
+
+#endif
diff --git a/libqmenumodel/src/qmenumodel.cpp b/libqmenumodel/src/qmenumodel.cpp
new file mode 100644
index 0000000..e88bc66
--- /dev/null
+++ b/libqmenumodel/src/qmenumodel.cpp
@@ -0,0 +1,225 @@
+/*
+ * 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>
+ */
+
+#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),
+ m_signalChangedId(0)
+{
+ static QHash<int, QByteArray> rolesNames;
+ if (rolesNames.empty()) {
+ rolesNames[Action] = "action";
+ rolesNames[Label] = "label";
+ rolesNames[LinkSection] = "linkSection";
+ rolesNames[LinkSubMenu] = "linkSubMenu";
+ rolesNames[Extra] = "extra";
+ }
+ setRoleNames(rolesNames);
+ setMenuModel(other);
+}
+
+/*! \internal */
+QMenuModel::~QMenuModel()
+{
+ setMenuModel(NULL);
+}
+
+/*! \internal */
+void QMenuModel::setMenuModel(GMenuModel *other)
+{
+ if (m_menuModel == other) {
+ return;
+ }
+
+ beginResetModel();
+
+ if (m_menuModel) {
+ g_signal_handler_disconnect(m_menuModel, m_signalChangedId);
+ m_signalChangedId = 0;
+ g_object_unref(m_menuModel);
+ }
+
+ m_menuModel = other;
+
+ if (m_menuModel) {
+ // this will trigger the menu load
+ (void) g_menu_model_get_n_items(m_menuModel);
+ m_signalChangedId = g_signal_connect(m_menuModel,
+ "items-changed",
+ G_CALLBACK(QMenuModel::onItemsChanged),
+ this);
+ }
+
+ endResetModel();
+}
+
+/*! \internal */
+GMenuModel *QMenuModel::menuModel() const
+{
+ return m_menuModel;
+}
+
+/*! \internal */
+QVariant QMenuModel::data(const QModelIndex &index, int role) const
+{
+ QVariant attribute;
+ int rowCountValue = rowCount();
+
+ if ((rowCountValue > 0) && (index.row() >= 0) && (index.row() < rowCountValue)) {
+ if (m_menuModel) {
+ switch (role) {
+ case Action:
+ attribute = getStringAttribute(index, G_MENU_ATTRIBUTE_ACTION);
+ break;
+ case Label:
+ attribute = getStringAttribute(index, G_MENU_ATTRIBUTE_LABEL);
+ break;
+ case LinkSection:
+ attribute = getLink(index, G_MENU_LINK_SECTION);
+ break;
+ case LinkSubMenu:
+ attribute = getLink(index, G_MENU_LINK_SUBMENU);
+ break;
+ case Extra:
+ attribute = getExtraProperties(index);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return attribute;
+}
+
+/*! \internal */
+QModelIndex QMenuModel::parent(const QModelIndex &index) const
+{
+ return QModelIndex();
+}
+
+/*! \internal */
+int QMenuModel::rowCount(const QModelIndex &) const
+{
+ if (m_menuModel) {
+ return g_menu_model_get_n_items(m_menuModel);
+ }
+ return 0;
+}
+
+/*! \internal */
+QVariant QMenuModel::getStringAttribute(const QModelIndex &index,
+ const QString &attribute) const
+{
+ QVariant result;
+ gchar* value = NULL;
+ g_menu_model_get_item_attribute(m_menuModel,
+ index.row(),
+ attribute.toLatin1(),
+ "s", &value);
+ if (value) {
+ result = QVariant(QString::fromLatin1(value));
+ g_free(value);
+ }
+ return result;
+}
+
+/*! \internal */
+QVariant QMenuModel::getLink(const QModelIndex &index,
+ const QString &linkName) const
+{
+ GMenuModel *link;
+
+ link = g_menu_model_get_item_link(m_menuModel,
+ index.row(),
+ linkName.toLatin1());
+
+ if (link) {
+ QMenuModel *other = new QMenuModel(link, const_cast<QMenuModel*>(this));
+ return QVariant::fromValue<QObject*>(other);
+ }
+
+ return QVariant();
+}
+
+/*! \internal */
+QString QMenuModel::parseExtraPropertyName(const QString &name) const
+{
+ QString newName(name);
+ if (name.startsWith("x-")) {
+ newName = name.mid(2);
+ }
+ return newName.replace("-", "_");
+}
+
+/*! \internal */
+QVariant QMenuModel::getExtraProperties(const QModelIndex &index) const
+{
+ GMenuAttributeIter *iter = g_menu_model_iterate_item_attributes(m_menuModel, index.row());
+ if (iter == NULL) {
+ return QVariant();
+ }
+
+ QVariantMap extra;
+ const gchar *attrName = NULL;
+ GVariant *value = NULL;
+ while (g_menu_attribute_iter_get_next (iter, &attrName, &value)) {
+ if (strncmp("x-", attrName, 2) == 0) {
+ extra.insert(parseExtraPropertyName(attrName),
+ Converter::toQVariant(value));
+ }
+ }
+
+ return extra;
+}
+
+/*! \internal */
+void QMenuModel::onItemsChanged(GMenuModel *,
+ gint position,
+ gint removed,
+ gint added,
+ gpointer data)
+{
+ QMenuModel *self = reinterpret_cast<QMenuModel*>(data);
+
+ if (removed > 0) {
+ self->beginRemoveRows(QModelIndex(), position, position + removed - 1);
+ self->endRemoveRows();
+ }
+
+ if (added > 0) {
+ self->beginInsertRows(QModelIndex(), position, position + added - 1);
+ self->endInsertRows();
+ }
+}
+
diff --git a/libqmenumodel/src/qmenumodel.h b/libqmenumodel/src/qmenumodel.h
new file mode 100644
index 0000000..7520480
--- /dev/null
+++ b/libqmenumodel/src/qmenumodel.h
@@ -0,0 +1,66 @@
+/*
+ * 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 QMENUMODEL_H
+#define QMENUMODEL_H
+
+#include <QAbstractListModel>
+
+extern "C" {
+#include <gio/gio.h>
+}
+
+class QMenuModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ enum MenuRoles {
+ Action = 0,
+ Label,
+ LinkSection,
+ LinkSubMenu,
+ Extra
+ };
+
+ ~QMenuModel();
+
+ /* QAbstractItemModel */
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QModelIndex parent (const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+
+protected:
+ QMenuModel(GMenuModel *other=0, QObject *parent=0);
+ void setMenuModel(GMenuModel *model);
+ GMenuModel *menuModel() const;
+
+private:
+ GMenuModel *m_menuModel;
+ guint m_signalChangedId;
+
+ QVariant getStringAttribute(const QModelIndex &index, const QString &attribute) const;
+ QVariant getLink(const QModelIndex &index, const QString &linkName) const;
+ QVariant getExtraProperties(const QModelIndex &index) const;
+ QString parseExtraPropertyName(const QString &name) const;
+
+ static void onItemsChanged(GMenuModel *model, gint position, gint removed, gint added, gpointer data);
+};
+
+#endif
diff --git a/libqmenumodel/src/qstateaction.cpp b/libqmenumodel/src/qstateaction.cpp
new file mode 100644
index 0000000..3629fce
--- /dev/null
+++ b/libqmenumodel/src/qstateaction.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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>
+ */
+
+#include "qstateaction.h"
+
+#include "qdbusactiongroup.h"
+
+/*!
+ \qmlclass QStateAction
+ \inherits QAction
+
+ \brief A QStateAction implementation to be used with \l QDBusActionGroup
+
+ \bold {This component is under heavy development.}
+
+ This class can be used as a proxy for an action that is exported over D-Bus
+
+ \code
+ QDBusActionGroup {
+ id: actionGroup
+ busType: 1
+ busName: "com.ubuntu.menu"
+ objectPath: "com/ubuntu/menu/actions"
+ }
+
+ Button {
+ visible: actionGroup.getAction("button.bvisible").status
+ }
+ \endcode
+*/
+
+/*! \internal */
+QStateAction::QStateAction(QDBusActionGroup *group, const QString &name)
+ : QAction(name, group),
+ m_group(group)
+{
+ QObject::connect(this, SIGNAL(triggered()), this, SLOT(onTriggered()));
+
+ // This keep the code clean
+ // But maybe we need move the action state control to QActionGroup to optimizations
+ QObject::connect(m_group, SIGNAL(actionAppear(QString)),
+ this, SLOT(onActionAppear(QString)));
+ QObject::connect(m_group, SIGNAL(actionVanish(QString)),
+ this, SLOT(onActionVanish(QString)));
+ QObject::connect(m_group, SIGNAL(actionStateChanged(QString,QVariant)),
+ this, SLOT(onActionStateChanged(QString,QVariant)));
+
+
+
+ bool isValid = m_group->hasAction(name);
+ setValid(isValid);
+ if (isValid) {
+ setState(m_group->actionState(name));
+ }
+}
+
+/*!
+ \qmlproperty int QStateAction::state
+ This property holds the current action state
+*/
+QVariant QStateAction::state() const
+{
+ return m_state;
+}
+
+/*!
+ \qmlproperty int QStateAction::isValid
+ This property return if the current Action is valid or not
+ A valid Action is a action which has a DBus action linked
+*/
+bool QStateAction::isValid() const
+{
+ return m_valid;
+}
+
+void QStateAction::updateState(const QVariant &state)
+{
+ m_group->updateActionState(text(), state);
+}
+
+/*! \internal */
+void QStateAction::setValid(bool valid)
+{
+ if (m_valid != valid) {
+ m_valid = valid;
+ Q_EMIT validChanged(m_valid);
+ }
+}
+
+/*! \internal */
+void QStateAction::setState(const QVariant &state)
+{
+ if (m_state != state) {
+ m_state = state;
+ Q_EMIT stateChanged(m_state);
+ }
+}
+
+/*! \internal */
+void QStateAction::onTriggered()
+{
+ updateState(QVariant());
+}
+
+/*! \internal */
+void QStateAction::onActionAppear(const QString &name)
+{
+ if (text() == name) {
+ setState(m_group->actionState(name));
+ setValid(true);
+ }
+}
+
+/*! \internal */
+void QStateAction::onActionVanish(const QString &name)
+{
+ if (text() == name) {
+ setState(QVariant());
+ setValid(false);
+ }
+}
+
+/*! \internal */
+void QStateAction::onActionStateChanged(const QString &name, const QVariant &state)
+{
+ if (text() == name) {
+ setState(state);
+ }
+}
diff --git a/libqmenumodel/src/qstateaction.h b/libqmenumodel/src/qstateaction.h
new file mode 100644
index 0000000..1a5a0fa
--- /dev/null
+++ b/libqmenumodel/src/qstateaction.h
@@ -0,0 +1,61 @@
+/*
+ * 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 QDBUSACTION_H
+#define QDBUSACTION_H
+
+#include <QAction>
+#include <QVariant>
+
+class QDBusActionGroup;
+
+class QStateAction : public QAction
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
+public:
+ QVariant state() const;
+ bool isValid() const;
+
+ Q_INVOKABLE void updateState(const QVariant &state);
+
+Q_SIGNALS:
+ void stateChanged(QVariant state);
+ void validChanged(bool valid);
+
+private Q_SLOTS:
+ void onActionAppear(const QString &name);
+ void onActionVanish(const QString &name);
+ void onActionStateChanged(const QString &name, const QVariant &state);
+ void onTriggered();
+
+private:
+ QDBusActionGroup *m_group;
+ QVariant m_state;
+ bool m_valid;
+
+ QStateAction(QDBusActionGroup *group, const QString &name);
+ void setValid(bool valid);
+ void setState(const QVariant &state);
+
+ friend class QDBusActionGroup;
+};
+
+#endif