diff options
Diffstat (limited to 'libqmenumodel/src')
-rw-r--r-- | libqmenumodel/src/CMakeLists.txt | 46 | ||||
-rw-r--r-- | libqmenumodel/src/converter.cpp | 118 | ||||
-rw-r--r-- | libqmenumodel/src/converter.h | 34 | ||||
-rw-r--r-- | libqmenumodel/src/dbus-enums.h | 53 | ||||
-rw-r--r-- | libqmenumodel/src/qdbusactiongroup.cpp | 232 | ||||
-rw-r--r-- | libqmenumodel/src/qdbusactiongroup.h | 85 | ||||
-rw-r--r-- | libqmenumodel/src/qdbusmenumodel.cpp | 109 | ||||
-rw-r--r-- | libqmenumodel/src/qdbusmenumodel.h | 61 | ||||
-rw-r--r-- | libqmenumodel/src/qdbusobject.cpp | 188 | ||||
-rw-r--r-- | libqmenumodel/src/qdbusobject.h | 75 | ||||
-rw-r--r-- | libqmenumodel/src/qmenumodel.cpp | 225 | ||||
-rw-r--r-- | libqmenumodel/src/qmenumodel.h | 66 | ||||
-rw-r--r-- | libqmenumodel/src/qstateaction.cpp | 145 | ||||
-rw-r--r-- | libqmenumodel/src/qstateaction.h | 61 |
14 files changed, 1498 insertions, 0 deletions
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..a060618 --- /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(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; +} + +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 |