diff options
-rw-r--r-- | src/QMenuModel/plugin.cpp | 5 | ||||
-rw-r--r-- | src/common/converter.cpp | 53 | ||||
-rw-r--r-- | src/common/converter.h | 5 | ||||
-rw-r--r-- | src/common/qdbusactiongroup.cpp | 121 | ||||
-rw-r--r-- | src/common/qdbusactiongroup.h | 21 | ||||
-rw-r--r-- | src/common/qmenumodel.cpp | 2 | ||||
-rw-r--r-- | src/common/qstateaction.cpp | 52 | ||||
-rw-r--r-- | src/common/qstateaction.h | 23 | ||||
-rw-r--r-- | tests/client/CMakeLists.txt | 22 | ||||
-rw-r--r-- | tests/client/actiongrouptest.cpp | 7 | ||||
-rw-r--r-- | tests/client/convertertest.cpp | 91 |
11 files changed, 277 insertions, 125 deletions
diff --git a/src/QMenuModel/plugin.cpp b/src/QMenuModel/plugin.cpp index fbd943c..494dd2c 100644 --- a/src/QMenuModel/plugin.cpp +++ b/src/QMenuModel/plugin.cpp @@ -30,9 +30,12 @@ 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"); + qmlRegisterType<QDBusMenuModel>(uri, 0, 1, "QDBusMenuModel"); qmlRegisterType<QDBusActionGroup>(uri, 0, 1, "QDBusActionGroup"); - qmlRegisterType<QStateAction>(uri, 0, 1, "QStateAction"); + } Q_EXPORT_PLUGIN2(qmenumodel, QMenuModelQmlPlugin) diff --git a/src/common/converter.cpp b/src/common/converter.cpp index c5cdade..54d4665 100644 --- a/src/common/converter.cpp +++ b/src/common/converter.cpp @@ -3,7 +3,7 @@ #include <QDebug> /*! \internal */ -QVariant Converter::toGVariant(GVariant *value) +QVariant Converter::toQVariant(GVariant *value) { QVariant result; if (value == NULL) { @@ -59,3 +59,54 @@ QVariant Converter::toGVariant(GVariant *value) return result; } + +GVariant* Converter::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/src/common/converter.h b/src/common/converter.h index 6ad4b2c..3029b0d 100644 --- a/src/common/converter.h +++ b/src/common/converter.h @@ -26,11 +26,14 @@ class Converter { public: - static QVariant toGVariant(GVariant *value); + static QVariant toQVariant(GVariant *value); + static GVariant* toGVariant(const QVariant &value); private: Converter(); Converter(const Converter &other); + + static GVariant* toGVariant(const QString &typeName, const QVariant &value); }; #endif diff --git a/src/common/qdbusactiongroup.cpp b/src/common/qdbusactiongroup.cpp index b6f52f5..305e12e 100644 --- a/src/common/qdbusactiongroup.cpp +++ b/src/common/qdbusactiongroup.cpp @@ -73,15 +73,24 @@ QStateAction *QDBusActionGroup::action(const QString &name) { QStateAction *act = actionImpl(name); if (act == 0) { - return addAction(name.toLatin1(), true); + return new QStateAction(this, name); } else { return act; } } +bool QDBusActionGroup::hasAction(const QString &actionName) +{ + if (m_actionGroup) { + return g_action_group_has_action(m_actionGroup, actionName.toLatin1()); + } else { + return false; + } +} + QStateAction *QDBusActionGroup::actionImpl(const QString &name) { - Q_FOREACH(QStateAction *act, m_actions) { + Q_FOREACH(QStateAction *act, this->findChildren<QStateAction*>()) { if (act->text() == name) { return act; } @@ -89,19 +98,10 @@ QStateAction *QDBusActionGroup::actionImpl(const QString &name) return 0; } -/*! - \qmlproperty int QDBusActionGroup::count - This property holds the number of actions inside of \l QDBusActionGroup -*/ -int QDBusActionGroup::count() const -{ - return m_actions.count(); -} - /*! \internal */ void QDBusActionGroup::serviceVanish(GDBusConnection *) { - clear(); + setActionGroup(NULL); } /*! \internal */ @@ -147,8 +147,8 @@ void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag) 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; - g_object_unref(m_actionGroup); + m_signalActionAddId = m_signalActionRemovedId = m_signalStateChangedId = 0; + clear(); } m_actionGroup = reinterpret_cast<GActionGroup*>(ag); @@ -169,93 +169,32 @@ void QDBusActionGroup::setActionGroup(GDBusActionGroup *ag) G_CALLBACK(QDBusActionGroup::onActionStateChanged), this); - gchar **actionNames = g_action_group_list_actions(m_actionGroup); - for(int i=0; actionNames[i] != NULL; i++) { - addAction(actionNames[i], true); + gchar **actions = g_action_group_list_actions(m_actionGroup); + for(int i=0; i < g_strv_length(actions); i++) { + Q_EMIT actionAppear(actions[i]); } - g_strfreev(actionNames); + g_strfreev(actions); } } /*! \internal */ -QStateAction *QDBusActionGroup::addAction(const char *actionName, bool create) -{ - bool isNew = false; - QStateAction *act = actionImpl(actionName); - if (act == 0) { - if (create) { - act = new QStateAction(actionName, this); - isNew = true; - } else { - return 0; - } - } - - if (g_action_group_has_action(m_actionGroup, actionName)) { - act->setEnabled(g_action_group_get_action_enabled(m_actionGroup, actionName)); - - GVariant *actState = g_action_group_get_action_state(m_actionGroup, actionName); - if (actState) { - act->setState(Converter::toGVariant(actState)); - } - act->setValid(true); - } else { - act->setValid(false); - } - - if (isNew) { - QObject::connect(act, SIGNAL(triggered()), this, SLOT(onActionTriggered())); - m_actions.insert(act); - Q_EMIT countChanged(m_actions.count()); - } - return act; -} - -/*! \internal */ -void QDBusActionGroup::onActionTriggered() -{ - QStateAction *act = qobject_cast<QStateAction*>(QObject::sender()); - if (act->isValid()) { - g_action_group_activate_action(m_actionGroup, act->text().toLatin1(), NULL); - } -} - -/*! \internal */ -void QDBusActionGroup::removeAction(const char *actionName, bool erase) +void QDBusActionGroup::clear() { - Q_FOREACH(QStateAction *act, m_actions) { - if (act->text() == actionName) { - if (erase) { - m_actions.remove(act); - delete act; - } else { - act->setValid(false); - } - break; - } + Q_FOREACH(QStateAction *act, this->findChildren<QStateAction*>()) { + Q_EMIT actionVanish(act->text()); } -} -/*! \internal */ -void QDBusActionGroup::updateAction(const char *actionName, GVariant *state) -{ - QStateAction *action = this->action(actionName); - if ((action != NULL) && (state != NULL)) { - action->setState(Converter::toGVariant(state)); + if (m_actionGroup != NULL) { + g_object_unref(m_actionGroup); + m_actionGroup = NULL; } } /*! \internal */ -void QDBusActionGroup::clear() +void QDBusActionGroup::updateActionState(const QString &actionName, const QVariant &state) { - Q_FOREACH(QAction *act, m_actions) { - delete act; - } - m_actions.clear(); - if (m_actionGroup != NULL) { - g_object_unref(m_actionGroup); - m_actionGroup = NULL; + g_action_group_activate_action(m_actionGroup, actionName.toLatin1(), Converter::toGVariant(state)); } } @@ -263,19 +202,19 @@ void QDBusActionGroup::clear() void QDBusActionGroup::onActionAdded(GDBusActionGroup *, gchar *actionName, gpointer data) { QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data); - self->addAction(actionName, true); + Q_EMIT self->actionAppear(actionName); } /*! \internal */ void QDBusActionGroup::onActionRemoved(GDBusActionGroup *, gchar *actionName, gpointer data) { QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data); - self->removeAction(actionName, false); + Q_EMIT self->actionVanish(actionName); } /*! \internal */ -void QDBusActionGroup::onActionStateChanged(GDBusActionGroup *ag, gchar *actionName, GVariant *value, gpointer data) +void QDBusActionGroup::onActionStateChanged(GDBusActionGroup *, gchar *actionName, GVariant *value, gpointer data) { QDBusActionGroup *self = reinterpret_cast<QDBusActionGroup*>(data); - self->updateAction(actionName, value); + Q_EMIT self->actionStateChanged(actionName, Converter::toQVariant(value)); } diff --git a/src/common/qdbusactiongroup.h b/src/common/qdbusactiongroup.h index f2b2033..723094c 100644 --- a/src/common/qdbusactiongroup.h +++ b/src/common/qdbusactiongroup.h @@ -35,13 +35,13 @@ class QDBusActionGroup : public QObject, public QDBusObject Q_PROPERTY(QString busName READ busName WRITE setBusName NOTIFY busNameChanged) Q_PROPERTY(QString objectPath READ objectPath WRITE setObjectPath NOTIFY objectPathChanged) Q_PROPERTY(int status READ status NOTIFY statusChanged) - Q_PROPERTY(int count READ count NOTIFY countChanged) public: QDBusActionGroup(QObject *parent=0); ~QDBusActionGroup(); - int count() const; + void updateActionState(const QString &actionName, const QVariant &state); + bool hasAction(const QString &actionName); Q_INVOKABLE QStateAction *action(const QString &actionName); @@ -50,25 +50,20 @@ Q_SIGNALS: void busNameChanged(const QString &busNameChanged); void objectPathChanged(const QString &objectPath); void statusChanged(ConnectionStatus status); - void countChanged(int count); - + void actionAppear(const QString &actionName); + void actionVanish(const QString &actionName); + void actionStateChanged(const QString &actionName, QVariant state); public Q_SLOTS: void start(); void stop(); - protected: virtual void serviceAppear(GDBusConnection *connection); virtual void serviceVanish(GDBusConnection *connection); - -private Q_SLOTS: - void onActionTriggered(); - private: GActionGroup *m_actionGroup; - QSet<QStateAction*> m_actions; int m_signalActionAddId; int m_signalActionRemovedId; int m_signalStateChangedId; @@ -77,12 +72,10 @@ private: void setIntBusType(int busType); void setActionGroup(GDBusActionGroup *ag); - QStateAction *addAction(const char *actionName, bool create); - void removeAction(const char *actionName, bool erase); - void updateAction(const char *actionName, GVariant *state); - void clear(); QStateAction *actionImpl(const QString &actionName); + void clear(); + // glib slots static void onActionAdded(GDBusActionGroup *ag, gchar *actionName, gpointer data); static void onActionRemoved(GDBusActionGroup *ag, gchar *actionName, gpointer data); diff --git a/src/common/qmenumodel.cpp b/src/common/qmenumodel.cpp index f8d71ba..cc760c1 100644 --- a/src/common/qmenumodel.cpp +++ b/src/common/qmenumodel.cpp @@ -202,7 +202,7 @@ QVariant QMenuModel::getExtraProperties(const QModelIndex &index) const while (g_menu_attribute_iter_get_next (iter, &attrName, &value)) { if (strncmp("x-", attrName, 2) == 0) { extra.insert(parseExtraPropertyName(attrName), - Converter::toGVariant(value)); + Converter::toQVariant(value)); } } diff --git a/src/common/qstateaction.cpp b/src/common/qstateaction.cpp index 8e3c7c3..1369bfc 100644 --- a/src/common/qstateaction.cpp +++ b/src/common/qstateaction.cpp @@ -19,6 +19,8 @@ #include "qstateaction.h" +#include "qdbusactiongroup.h" + /*! \qmlclass QStateAction \inherits QAction @@ -44,9 +46,20 @@ */ /*! \internal */ -QStateAction::QStateAction(const QString &text, QObject *parent) - :QAction(text, parent) +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(actionStateUpdated(QString,QVariant)), + this, SLOT(onActionStateUpdate(QString,QVariant))); } /*! @@ -68,6 +81,11 @@ bool QStateAction::isValid() const return m_valid; } +void QStateAction::updateState(const QVariant &state) +{ + m_group->updateActionState(text(), state); +} + /*! \internal */ void QStateAction::setValid(bool valid) { @@ -85,3 +103,33 @@ void QStateAction::setState(const QVariant &state) Q_EMIT stateChanged(m_state); } } + +/*! \internal */ +void QStateAction::onTriggered() +{ + updateState(QVariant()); +} + +/*! \internal */ +void QStateAction::onActionAppear(const QString &actionName) +{ + if (text() == actionName) { + setValid(true); + } +} + +/*! \internal */ +void QStateAction::onActionVanish(const QString &actionName) +{ + if (text() == actionName) { + setValid(false); + } +} + +/*! \internal */ +void QStateAction::onActionStateUpdate(const QString &actionName, const QVariant &state) +{ + if (text() == actionName) { + setState(state); + } +} diff --git a/src/common/qstateaction.h b/src/common/qstateaction.h index 4019c64..c6bdcea 100644 --- a/src/common/qstateaction.h +++ b/src/common/qstateaction.h @@ -23,28 +23,37 @@ #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: - QStateAction(const QString &text="", QObject *parent=0); - - QVariant state() const; - void setState(const QVariant &state); - +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 &actionName); + void onActionVanish(const QString &actionName); + void onActionStateUpdate(const QString &actionNane, const QVariant &state); + void onTriggered(); + private: - QVariant m_state; + 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; }; diff --git a/tests/client/CMakeLists.txt b/tests/client/CMakeLists.txt index 473ebcd..c427f54 100644 --- a/tests/client/CMakeLists.txt +++ b/tests/client/CMakeLists.txt @@ -24,6 +24,27 @@ macro(declare_test testname) endmacro(declare_test testname)
+macro(declare_simple_test testname)
+ set(TEST_MOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/${testname}.moc)
+ qt4_generate_moc(${testname}.cpp ${TEST_MOC_FILE})
+
+ add_executable(${testname} ${testname}.cpp ${TEST_MOC_FILE})
+ target_link_libraries(${testname}
+ qmenumodelcommon
+ ${QT_QTTEST_LIBRARY}
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTGUI_LIBRARY}
+ ${QT_QTDBUS_LIBRARY}
+ ${GLIB_LDFLAGS}
+ ${GIO_LDFLAGS})
+
+ add_test(${testname}
+ ${CMAKE_CURRENT_BINARY_DIR}/${testname})
+
+ set_tests_properties(${testname} PROPERTIES
+ TIMEOUT ${CTEST_TESTING_TIMEOUT})
+endmacro(declare_simple_test testname)
+
include_directories(${qmenumodelcommon_SOURCE_DIR}
${dbusmenuscript_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
@@ -45,3 +66,4 @@ declare_test(servicetest) declare_test(menuchangestest)
declare_test(modeltest)
declare_test(actiongrouptest)
+declare_simple_test(convertertest)
diff --git a/tests/client/actiongrouptest.cpp b/tests/client/actiongrouptest.cpp index fa2dca5..c77c3d5 100644 --- a/tests/client/actiongrouptest.cpp +++ b/tests/client/actiongrouptest.cpp @@ -91,13 +91,11 @@ private Q_SLOTS: m_model.start(); m_actionGroup.start(); QCOMPARE(m_actionGroup.status(), QDBusObject::Connecting); - QCOMPARE(m_actionGroup.count(), 0); // Make menu available m_script.publishMenu(); QCOMPARE(m_actionGroup.status(), QDBusObject::Connected); - QCOMPARE(m_actionGroup.count(), 0); } /* @@ -108,7 +106,6 @@ private Q_SLOTS: { m_model.start(); m_actionGroup.start(); - QCOMPARE(m_actionGroup.count(), 0); // Make menu available m_script.publishMenu(); @@ -116,12 +113,10 @@ private Q_SLOTS: // Append menus m_script.walk(2); - QCOMPARE(m_actionGroup.count(), 2); // Remove menu from dbus m_script.unpublishMenu(); QCOMPARE(m_actionGroup.status(), QDBusObject::Connecting); - QCOMPARE(m_actionGroup.count(), 0); m_actionGroup.stop(); QCOMPARE(m_actionGroup.status(), QDBusObject::Disconnected); @@ -165,7 +160,6 @@ private Q_SLOTS: // Make menu available and append 2 menus m_script.publishMenu(); m_script.walk(2); - QCOMPARE(m_actionGroup.count(), 2); // Get Action QStateAction *act = m_actionGroup.action(QString("Menu1Act")); @@ -174,7 +168,6 @@ private Q_SLOTS: // Remove 1 menu m_script.walk(1); - QCOMPARE(m_actionGroup.count(), 2); //Check if action is invalid QVERIFY(!act->isValid()); diff --git a/tests/client/convertertest.cpp b/tests/client/convertertest.cpp new file mode 100644 index 0000000..496b62a --- /dev/null +++ b/tests/client/convertertest.cpp @@ -0,0 +1,91 @@ +/* + * 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 "converter.h" + +#include <QObject> +#include <QtTestGui> +#include <QDebug> + +class ConverterTest : public QObject +{ + Q_OBJECT + +private: + bool compare(const QVariant &qv, const GVariantType *type) + { + bool result; + GVariant *gv = Converter::toGVariant(qv); + result = g_variant_type_equal(g_variant_get_type(gv), type); + if (!result) { + qWarning() << "types are different: QVariant:" << qv.typeName() + << "Result:" << (const char*) g_variant_get_type(gv) + << "Expected:"<< (const char*) type; + } + g_variant_unref(gv); + return result; + } + +private Q_SLOTS: + + + /* + * Test converter QVariant to GVariant + */ + void testToGVariant() + { + // Boolean + QVERIFY(compare(QVariant(true), G_VARIANT_TYPE_BOOLEAN)); + + // Byte + QVERIFY(compare(QVariant::fromValue<uchar>(42), G_VARIANT_TYPE_BYTE)); + + // Int16 + QVERIFY(compare(QVariant::fromValue<short>(-42), G_VARIANT_TYPE_INT16)); + + // UInt16 + QVERIFY(compare(QVariant::fromValue<ushort>(-42), G_VARIANT_TYPE_UINT16)); + + // Int32 + QVERIFY(compare(QVariant(-42), G_VARIANT_TYPE_INT32)); + + // UInt32 + QVERIFY(compare(QVariant((uint)42), G_VARIANT_TYPE_UINT32)); + + // Int64 + QVERIFY(compare(QVariant::fromValue<long>(-42), G_VARIANT_TYPE_INT64)); + + // UInt64 + QVERIFY(compare(QVariant::fromValue<ulong>(42), G_VARIANT_TYPE_UINT64)); + + // Double + QVERIFY(compare(QVariant((double)42.42), G_VARIANT_TYPE_DOUBLE)); + + // String + QVERIFY(compare(QVariant(QString("42")), G_VARIANT_TYPE_STRING)); + + // ByteArray + QVERIFY(compare(QVariant(QByteArray("42")), G_VARIANT_TYPE_BYTESTRING)); + } + +}; + +QTEST_MAIN(ConverterTest) + +#include "convertertest.moc" |