Unsolved QtDBus: how to use enumeration?
-
Hello,
I have tried, for almost two days, to make enumeration work with QtDBus. In the following source files,getColor()
andsetColor()
work but notgetMode()
andsetMode()
.dbus/DBusLedInterface.hpp:
#include "dbus/DBusIndexableInterface.hpp" // just provides a getIndex() method #include "dbus/EnumDBus.hpp" #include <QDBusMetaType> struct Color { uint32_t red; uint32_t green; uint32_t blue; }; Q_DECLARE_METATYPE(Color) QDBusArgument& operator<<(QDBusArgument& argument, const Color& color); const QDBusArgument& operator>>(const QDBusArgument& argument, Color& color); enum Modes : quint32 { Off = 0, Constant = 1, ColorSet = 2, Breathing = 3 }; Q_DECLARE_METATYPE(Modes) enum ColorDepth : quint32 { ZeroBits = 0, EightBits = 1, OneBit = 2 }; Q_DECLARE_METATYPE(ColorDepth) class DBusLedInterface final : public DBusIndexableInterface { Q_OBJECT public: DBusLedInterface(const QString& obj) noexcept : DBusIndexableInterface("Led", obj) { qDBusRegisterMetaType<Color>(); qDBusRegisterMetaType<Modes>(); } Q_PROPERTY(Modes Mode READ getMode WRITE setMode) Modes getMode() const; void setMode(const Modes mode); Q_PROPERTY(Color Color READ getColor WRITE setColor) Color getColor() const; void setColor(const Color color); //… };
DBusLedInterface.cpp:
#include "dbus/DBusLedInterface.hpp" Modes DBusLedInterface::getMode() const { return getPropertyAndCheck<Modes>("Mode"); } void DBusLedInterface::setMode(const Modes mode) { setPropertyAndCheck("Mode", mode); } Color DBusLedInterface::getColor() const { return getPropertyAndCheck<Color>("Color"); } void DBusLedInterface::setColor(const Color color) { setPropertyAndCheck("Color", color); } // … QDBusArgument& operator<<(QDBusArgument& argument, const Color& color) { argument.beginStructure(); argument << color.red << color.green << color.blue; argument.endStructure(); return argument; } const QDBusArgument& operator>>(const QDBusArgument& argument, Color& color) { argument.beginStructure(); argument >> color.red >> color.green >> color.blue; argument.endStructure(); return argument; }
dbus/DBusAbstractInterface.hpp:
#include <QtDBus/QDBusInterface> #include <QtDBus/QDBusReply> class DBusPropertyException final : public std::runtime_error { public: DBusPropertyException(const char* name, const std::string& suffix = ".") : std::runtime_error("Unable to get or set the property " + std::string(name) + suffix) {} DBusPropertyException(const char* name, const char* desc) : DBusPropertyException(name, ": " + std::string(desc) + '.') {} }; class DBusAbstractInterface : public QDBusInterface { public: // … template<class T> T getPropertyAndCheck(const char* name) const; template<class T> void setPropertyAndCheck(const char* name, T value); // … }; template<class T> T DBusAbstractInterface::getPropertyAndCheck(const char* name) const { QVariant ret = property(name); if (!ret.isValid()) { throw DBusPropertyException(name, "The QVariant is not valid"); } else { return qvariant_cast<T>(ret); } } template<class T> void DBusAbstractInterface::setPropertyAndCheck(const char* name, T value) { if (!setProperty(name, QVariant::fromValue(value))) throw DBusPropertyException(name); }
dbus/EnumDBus.hpp (inspired by https://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes#enumDBus.hpp/):
#include <QtDBus/QDBusArgument> template<typename T, bool isEnum> class QDBusEnumMarshal; template<typename T> class QDBusEnumMarshal<T, true> { public: using enum_t = typename std::underlying_type<T>::type; static QDBusArgument& marshal(QDBusArgument& arg, const T& src) { arg.beginStructure(); arg << static_cast<enum_t>(src); arg.endStructure(); return arg; } static const QDBusArgument& unmarshal(const QDBusArgument& arg, T& src) { enum_t tmp; arg.beginStructure(); arg >> tmp; arg.endStructure(); src = static_cast<T>(tmp); return arg; } }; template<typename T> QDBusArgument& operator<<(QDBusArgument& arg, const T& src) { return QDBusEnumMarshal<T, std::is_enum<T>::value>::marshal(arg, src); } template<typename T> const QDBusArgument& operator>>(const QDBusArgument& arg, T& src) { return QDBusEnumMarshal<T, std::is_enum<T>::value>::unmarshal(arg, src); }
-
I have found a workaround by creating a private
Q_PROPERTY
of typequint32
(the original type of myMode
property), and I cast then to my custom enumeration typeModes
. But, if someone has a better solution, I'm still a taker…dbus/DBusLedInterface.hpp:
#include "dbus/DBusIndexableInterface.hpp" // just provides a `getIndex()` method // … class DBusLedInterface : public DBusIndexableInterface { Q_OBJECT Q_PROPERTY(quint32 Mode READ getMode_ WRITE setMode_) public: enum Modes { Off = 0, Constant = 1, Cycles = 2, Breathing = 3 }; public: // … Modes getMode() const; void setMode(const Modes mode); // … private: quint32 getMode_() const; void setMode_(const quint32 mode); };
dbus/DBusLedInterface.cpp:
#include "dbus/DBusLedInterface.hpp" // … DBusLedInterface::Modes DBusLedInterface::getMode() const { return static_cast<Modes>(getMode_()); } void DBusLedInterface::setMode(const Modes mode) { setMode_(static_cast<quint32>(mode)); } quint32 DBusLedInterface::getMode_() const { return getPropertyAndCheck<quint32>("Mode"); } void DBusLedInterface::setMode_(const quint32 mode) { setPropertyAndCheck("Mode", mode); } // …