Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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() and setColor() work but not getMode() and setMode().

    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 type quint32 (the original type of my Mode property), and I cast then to my custom enumeration type Modes. 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);
    }
    
    // …
    

Log in to reply