diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/QMenuModel/CMakeLists.txt | 43 | ||||
-rw-r--r-- | src/QMenuModel/plugin.cpp | 15 | ||||
-rw-r--r-- | src/QMenuModel/plugin.h | 14 | ||||
-rw-r--r-- | src/QMenuModel/qdbusmenumodel.cpp | 125 | ||||
-rw-r--r-- | src/QMenuModel/qdbusmenumodel.h | 65 | ||||
-rw-r--r-- | src/QMenuModel/qmenumodel.cpp | 163 | ||||
-rw-r--r-- | src/QMenuModel/qmenumodel.h | 44 | ||||
-rw-r--r-- | src/QMenuModel/qmldir | 1 |
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 |