PDA

View Full Version : Serialize nested user defined class in Q_PROPERTY



EagleNN
1st February 2017, 19:06
I faced with following problem: I can't serialize user defined object from Q_PROPERTY
I try to serialize RegistersSettings class to QDataStream. The idea is to be able to serialize it to text file (using << operator) and later be able to read it (using >> operator). It should verify that fields that was readed from file are still valid. So I inspect property for that.
The issue is that Q_PROPERTY(QList<RegisterGroupSettings> groups MEMBER groups) is not work as expected.
It looks like it's possible to create such functionality, but it looks that it's not so easy.
Could anyone help with the common way how to serialize user defined class from Q_PROPERTY?

The code is simplifyed to be more readable, but the main idea is in place.


class RegisterGroupSettings:SettingsItem<RegisterGroupSettings>
{
private:
Q_GADGET
Q_PROPERTY(QString name MEMBER name)
Q_PROPERTY(int interval MEMBER interval)

public:
QString name;
int interval;
};
Q_DECLARE_METATYPE(RegisterGroupSettings)

class RegistersSettings:SettingsItem<RegistersSettings>
{
private:
Q_GADGET
Q_PROPERTY(QList<RegisterGroupSettings> groups MEMBER groups)
Q_PROPERTY(int code MEMBER code)

public:
QList<RegisterGroupSettings> groups;
int code;
};
Q_DECLARE_METATYPE(RegistersSettings)

SettingsItem is a helper fo unification


template <typename T> class SettingsItem
{
public:
friend QDataStream & operator << (QDataStream &arch, const T & object)
{
const QMetaObject &mo = object.staticMetaObject;
int cnt = mo.propertyCount();
QString prop_name;
QVariant prop_value;
arch << cnt;
while (cnt>0)
{
prop_name = mo.property(cnt-1).name();
prop_value = mo.property(cnt-1).readOnGadget(&object);
arch << prop_name;
arch << prop_value;
cnt--;
}
return arch;
}

friend QDataStream & operator >> (QDataStream &arch, T & object)
{
const QMetaObject &mo = object.staticMetaObject;
int cnt=0;
QString prop_name;
QVariant prop_value;
int prop_index;
arch >> cnt;
while (cnt>0)
{
arch >> prop_name;
arch >> prop_value;
prop_index = mo.indexOfProperty(prop_name.toStdString().c_str() );
if (prop_index > -1)
{
mo.property(prop_index).writeOnGadget(&object, prop_value);
}
cnt--;
}
return arch;
}

friend bool operator == (const T &first, const T &second)
{
const QMetaObject &mo = first.staticMetaObject;
int cnt = mo.propertyCount();
QString prop_name;
QVariant oProp_value;
QVariant dProp_value;
while (cnt>0)
{
prop_name = mo.property(cnt-1).name();
oProp_value = mo.property(cnt-1).readOnGadget(&first);
dProp_value = mo.property(cnt-1).readOnGadget(&second);
if (oProp_value == dProp_value)
{
cnt--;
continue;
}
return false;
}

return true;
}

friend bool operator != (const T &first, const T &second)
{
return !( first == second );
}
};

anda_skoa
2nd February 2017, 09:43
Can you give an indication of what you current problem is?

Does it not compile?
Are the operators not called?
Do they fail?

Cheers,
_

EagleNN
2nd February 2017, 16:11
It doesn't work.
But i have found the solution:

The solution is to extend template with constructor


SettingsItem()
{
qRegisterMetaType<T>();
qRegisterMetaTypeStreamOperators<T>(T::staticMetaObject.className());
}

and register nested type in class constructor


RegistersSettings()
{
qRegisterMetaTypeStreamOperators<QList<RegisterGroupSettings>>("QList<RegisterGroupSettings>");
}