aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRenato Araujo Oliveira Filho <renato.filho@canonical.com>2012-09-05 16:15:39 -0300
committerRenato Araujo Oliveira Filho <renato.filho@canonical.com>2012-09-05 16:15:39 -0300
commit0dfd3d4cd4214a732e4a5cda59fd4dfc082b8425 (patch)
treea4d1d4e876e31a1265581ee89c673eb66aaaae8d /src
downloadqmenumodel-0dfd3d4cd4214a732e4a5cda59fd4dfc082b8425.tar.gz
qmenumodel-0dfd3d4cd4214a732e4a5cda59fd4dfc082b8425.tar.bz2
qmenumodel-0dfd3d4cd4214a732e4a5cda59fd4dfc082b8425.zip
Initial import.
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/QMenuModel/CMakeLists.txt43
-rw-r--r--src/QMenuModel/plugin.cpp15
-rw-r--r--src/QMenuModel/plugin.h14
-rw-r--r--src/QMenuModel/qdbusmenumodel.cpp125
-rw-r--r--src/QMenuModel/qdbusmenumodel.h65
-rw-r--r--src/QMenuModel/qmenumodel.cpp163
-rw-r--r--src/QMenuModel/qmenumodel.h44
-rw-r--r--src/QMenuModel/qmldir1
9 files changed, 473 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..e2c06cb
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(src)
+
+add_subdirectory(QMenuModel)
diff --git a/src/QMenuModel/CMakeLists.txt b/src/QMenuModel/CMakeLists.txt
new file mode 100644
index 0000000..dae9ff4
--- /dev/null
+++ b/src/QMenuModel/CMakeLists.txt
@@ -0,0 +1,43 @@
+set(QMENUMODEL_SRC
+ qmenumodel.cpp
+ qdbusmenumodel.cpp
+ plugin.cpp
+)
+
+set(QMENUMODEL_HEADERS
+ qmenumodel.h
+ qdbusmenumodel.h
+ plugin.h
+)
+
+qt4_wrap_cpp(QMENUMODEL_MOC
+ ${QMENUMODEL_HEADERS}
+)
+
+add_library(qmenumodel MODULE
+ ${QMENUMODEL_SRC}
+ ${QMENUMODEL_MOC}
+)
+
+#set_target_properties(dbusmenuqmlcommon PROPERTIES COMPILE_FLAGS -fPIC)
+
+include_directories(
+ ${CMAKE_CURRENT_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
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTGUI_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")
diff --git a/src/QMenuModel/plugin.cpp b/src/QMenuModel/plugin.cpp
new file mode 100644
index 0000000..e6a828b
--- /dev/null
+++ b/src/QMenuModel/plugin.cpp
@@ -0,0 +1,15 @@
+#include "plugin.h"
+#include "qmenumodel.h"
+#include "qdbusmenumodel.h"
+
+#include <QtDeclarative>
+
+
+void QMenuModelQmlPlugin::registerTypes(const char *uri)
+{
+ qmlRegisterUncreatableType<QMenuModel>(uri, 1, 0, "QMenuModel",
+ "QMenuModel is a interface");
+ qmlRegisterType<QDBusMenuModel>(uri, 1, 0, "QDBusMenuModel");
+}
+
+Q_EXPORT_PLUGIN2(qmenumodel, QMenuModelQmlPlugin)
diff --git a/src/QMenuModel/plugin.h b/src/QMenuModel/plugin.h
new file mode 100644
index 0000000..9346d32
--- /dev/null
+++ b/src/QMenuModel/plugin.h
@@ -0,0 +1,14 @@
+#ifndef QMENUMODELQMLPLUGIN_H
+#define QMENUMODELQMLPLUGIN_H
+
+#include <QDeclarativeExtensionPlugin>
+
+
+class QMenuModelQmlPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif
diff --git a/src/QMenuModel/qdbusmenumodel.cpp b/src/QMenuModel/qdbusmenumodel.cpp
new file mode 100644
index 0000000..96f936c
--- /dev/null
+++ b/src/QMenuModel/qdbusmenumodel.cpp
@@ -0,0 +1,125 @@
+#include "qdbusmenumodel.h"
+#include <QDebug>
+
+QDBusMenuModel::QDBusMenuModel(QObject *parent)
+ :QMenuModel(parent),
+ m_watchId(0),
+ m_busType(None)
+{
+}
+
+QDBusMenuModel::~QDBusMenuModel()
+{
+ disconnect();
+}
+
+QDBusMenuModel::BusType QDBusMenuModel::busType() const
+{
+ return m_busType;
+}
+
+void QDBusMenuModel::setBusType(QDBusMenuModel::BusType type)
+{
+ if (m_busType != type) {
+ if (isConnected())
+ disconnect();
+ m_busType = type;
+ Q_EMIT busTypeChanged(m_busType);
+ }
+}
+
+QString QDBusMenuModel::busName() const
+{
+ return m_busName;
+}
+
+void QDBusMenuModel::setBusName(const QString &busName)
+{
+ if (m_busName != busName) {
+ if (isConnected())
+ disconnect();
+ m_busName = busName;
+ Q_EMIT busNameChanged(m_busName);
+ }
+}
+
+QString QDBusMenuModel::objectPath() const
+{
+ return m_objectPath;
+}
+
+void QDBusMenuModel::setObjectPath(const QString &objectPath)
+{
+ if (m_objectPath != objectPath) {
+ if (isConnected())
+ disconnect();
+ m_objectPath = objectPath;
+ Q_EMIT objectPathChanged(m_objectPath);
+ }
+}
+
+void QDBusMenuModel::connect()
+{
+ if (isConnected() || (m_watchId > 0)) {
+ return;
+ } else if ((m_busType > None) && !m_objectPath.isEmpty() && !m_busName.isEmpty()) {
+ qDebug() << "Wait for service";
+ GBusType type = m_busType == 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,
+ QDBusMenuModel::onServiceAppeared,
+ QDBusMenuModel::onServiceFanished,
+ this,
+ NULL);
+ } else {
+ Q_EMIT connectionError("Invalid menu model connection args");
+ }
+}
+
+void QDBusMenuModel::disconnect()
+{
+ if (isConnected()) {
+ g_bus_unwatch_name (m_watchId);
+ m_watchId = 0;
+
+ setMenuModel(NULL);
+ Q_EMIT disconnected();
+ }
+}
+
+bool QDBusMenuModel::isConnected() const
+{
+ return (m_watchId != 0);
+}
+
+void QDBusMenuModel::setIntBusType(int busType)
+{
+ if ((busType > None) && (busType < LastBusType)) {
+ setBusType(static_cast<BusType>(busType));
+ }
+}
+
+void QDBusMenuModel::onServiceAppeared(GDBusConnection *connection, const gchar *, const gchar *, gpointer data)
+{
+ qDebug() << "Service appears";
+ QDBusMenuModel *self = reinterpret_cast<QDBusMenuModel*>(data);
+ GMenuModel *model = reinterpret_cast<GMenuModel*>(g_dbus_menu_model_get(connection,
+ self->m_busName.toLatin1(),
+ self->m_objectPath.toLatin1()));
+ self->setMenuModel(model);
+ if (model) {
+ Q_EMIT self->connected();
+ } else {
+ Q_EMIT self->connectionError("Fail to retrieve menu model");
+ self->disconnect();
+ }
+}
+
+void QDBusMenuModel::onServiceFanished(GDBusConnection *, const gchar *, gpointer data)
+{
+ qDebug() << "Service fanished";
+ QDBusMenuModel *self = reinterpret_cast<QDBusMenuModel*>(data);
+ Q_EMIT self->connectionError("Menu model disapear");
+ self->disconnect();
+}
diff --git a/src/QMenuModel/qdbusmenumodel.h b/src/QMenuModel/qdbusmenumodel.h
new file mode 100644
index 0000000..e9d2461
--- /dev/null
+++ b/src/QMenuModel/qdbusmenumodel.h
@@ -0,0 +1,65 @@
+#ifndef QDBUSMENUMODEL_H
+#define QDBUSMENUMODEL_H
+
+#include "qmenumodel.h"
+
+#include <gio/gio.h>
+
+class QDBusMenuModel : public QMenuModel
+{
+ 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)
+
+public:
+ enum BusType {
+ None = 0,
+ SessionBus,
+ SystemBus,
+ LastBusType
+ };
+
+ QDBusMenuModel(QObject *parent=0);
+ ~QDBusMenuModel();
+
+ BusType busType() const;
+ void setBusType(BusType type);
+
+ QString busName() const;
+ void setBusName(const QString &busName);
+
+ QString objectPath() const;
+ void setObjectPath(const QString &busName);
+
+ bool isConnected() const;
+
+public Q_SLOTS:
+ void connect();
+ void disconnect();
+
+
+Q_SIGNALS:
+ void busTypeChanged(BusType type);
+ void busNameChanged(const QString &busNameChanged);
+ void objectPathChanged(const QString &objectPath);
+
+ void connected();
+ void disconnected();
+ void connectionError(const QString &errorMessage);
+
+private:
+ guint m_watchId;
+ BusType m_busType;
+ QString m_busName;
+ QString m_objectPath;
+
+ // workaround to support busType as int
+ void setIntBusType(int busType);
+
+ // glib slots
+ static void onServiceAppeared(GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer data);
+ static void onServiceFanished(GDBusConnection *connection, const gchar *name, gpointer data);
+};
+
+#endif
diff --git a/src/QMenuModel/qmenumodel.cpp b/src/QMenuModel/qmenumodel.cpp
new file mode 100644
index 0000000..173dbbe
--- /dev/null
+++ b/src/QMenuModel/qmenumodel.cpp
@@ -0,0 +1,163 @@
+#include "qmenumodel.h"
+#include <QDebug>
+
+QMenuModel::QMenuModel(QObject *parent, GMenuModel *other)
+ : 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";
+ }
+ setRoleNames(rolesNames);
+ setMenuModel(other);
+}
+
+QMenuModel::~QMenuModel()
+{
+ setMenuModel(NULL);
+}
+
+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;
+
+ endResetModel();
+
+ if (m_menuModel) {
+ qDebug() << "Menu size:" << g_menu_model_get_n_items(m_menuModel);
+ m_signalChangedId = g_signal_connect(m_menuModel,
+ "items-changed",
+ G_CALLBACK(QMenuModel::onItemsChanged),
+ this);
+ }
+}
+
+GMenuModel *QMenuModel::menuModel() const
+{
+ return m_menuModel;
+}
+
+/* QAbstractItemModel */
+int QMenuModel::columnCount(const QModelIndex &) const
+{
+ return 1;
+}
+
+QVariant QMenuModel::data(const QModelIndex &index, int role) const
+{
+ QVariant attribute;
+ int rowCountValue = rowCount();
+
+ if ((rowCountValue > 0) && (index.row() >= 0) && (index.row() < rowCountValue)) {
+ qDebug() << "GetData: " << index.row() << role;
+ 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;
+ default:
+ break;
+ }
+ }
+ }
+ qDebug() << "GetData done" << attribute;
+ return attribute;
+}
+
+QModelIndex QMenuModel::parent(const QModelIndex &index) const
+{
+ return QModelIndex();
+}
+
+int QMenuModel::rowCount(const QModelIndex &) const
+{
+ if (m_menuModel) {
+ return g_menu_model_get_n_items(m_menuModel);
+ }
+ return 0;
+}
+
+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;
+}
+
+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) {
+ qDebug() << "link: " << (void*)link;
+ QMenuModel *other = new QMenuModel(const_cast<QMenuModel*>(this), link);
+ qDebug() << "link created: " << (void*)link;
+ return QVariant::fromValue<QObject*>(other);
+ }
+
+ return QVariant();
+}
+
+void QMenuModel::onItemsChanged(GMenuModel *,
+ gint position,
+ gint removed,
+ gint added,
+ gpointer data)
+{
+ QMenuModel *self = reinterpret_cast<QMenuModel*>(data);
+
+ qDebug() << "model changed" << position << removed << added;
+
+ if (removed > 0) {
+ self->beginRemoveRows(QModelIndex(), position, position + removed - 1);
+ self->endRemoveRows();
+ }
+
+ if (added > 0) {
+ self->beginInsertRows(QModelIndex(), position, position + added - 1);
+ self->endInsertRows();
+ }
+ qDebug() << "model size: " << self->rowCount();
+}
+
diff --git a/src/QMenuModel/qmenumodel.h b/src/QMenuModel/qmenumodel.h
new file mode 100644
index 0000000..91b0eb9
--- /dev/null
+++ b/src/QMenuModel/qmenumodel.h
@@ -0,0 +1,44 @@
+#ifndef QMENUMODEL_H
+#define QMENUMODEL_H
+
+#include <QAbstractListModel>
+#include <gio/gio.h>
+
+
+class QMenuModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ enum MenuRoles {
+ Action = 0,
+ Label,
+ LinkSection,
+ LinkSubMenu
+ };
+
+ ~QMenuModel();
+
+ /* QAbstractItemModel */
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ 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(QObject *parent=0, GMenuModel *other=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;
+
+ static void onItemsChanged(GMenuModel *model, gint position, gint removed, gint added, gpointer data);
+
+};
+
+#endif
diff --git a/src/QMenuModel/qmldir b/src/QMenuModel/qmldir
new file mode 100644
index 0000000..c8f525f
--- /dev/null
+++ b/src/QMenuModel/qmldir
@@ -0,0 +1 @@
+plugin qmenumodel