Hello,

I am trying to have a generic save/restore for QObject which contain QObject derived pointer, as shown in the example, the "Parent" has "Object", but I can't use
Q_PROPERTY( QObject *object READ object WRITE setObject )

I would like to use
Q_PROPERTY( Object *object READ object WRITE setObject )

In this way, I don't need to cast from QObject to Object. Is there a way for that? Thanks!

Qt Code:
  1. #include <QObject>
  2. #include <QString>
  3. #include <QFile>
  4. #include <QDebug>
  5. #include <QMap>
  6. #include <QDataStream>
  7. #include <QMetaObject>
  8. #include <QByteArray>
  9. #include <QVariant>
  10. #include <QMetaProperty>
  11. #include <QList>
  12. #include <QMetaType>
  13. #include <QBuffer>
  14. #include <iostream>
  15.  
  16. class Object : public QObject
  17. {
  18. Q_OBJECT
  19. Q_PROPERTY(QString string READ string WRITE setString)
  20.  
  21. public:
  22.  
  23. Object() {
  24. }
  25.  
  26. const QString& string() const {
  27. return str;
  28. }
  29.  
  30. void setString(const QString &ss) {
  31. str = ss;
  32. }
  33.  
  34. void dump() const {
  35. std::cout << str.toStdString() << std::endl;
  36. }
  37.  
  38. private:
  39.  
  40. QString str;
  41.  
  42. };
  43.  
  44.  
  45. class Parent : public QObject
  46. {
  47. Q_OBJECT
  48. Q_PROPERTY(QObject *object READ object WRITE setObject)
  49.  
  50. public:
  51.  
  52. Parent() {
  53. }
  54.  
  55. QObject * object() const {
  56. return obj;
  57. }
  58.  
  59. void setObject(QObject * oo) {
  60. Q_ASSERT(!oo || qobject_cast<Object*>(oo));
  61. obj = qobject_cast<Object*>(oo);
  62. }
  63.  
  64. private:
  65.  
  66. Object *obj;
  67.  
  68. };
  69.  
  70. class BaseInterface
  71. {
  72. public:
  73.  
  74. virtual ~BaseInterface() {}
  75. virtual QObject *create( const QString &objectName) const = 0;
  76.  
  77. };
  78.  
  79. template <typename T>
  80. class Creator : public BaseInterface
  81. {
  82. public:
  83.  
  84. QObject *create( const QString &objectName) const {
  85. T *ret = new T;
  86. ret->setObjectName(objectName);
  87. return ret;
  88. }
  89. };
  90.  
  91. class Factory
  92. {
  93. public:
  94.  
  95. static QObject *create(const QString &className, const QString &objectName) {
  96. BaseInterface *i = interfaces.value(className, 0);
  97. assert (i);
  98. return i->create(objectName);
  99. }
  100.  
  101. static void registerClass(const QString &className, BaseInterface *interface) {
  102. if (!interface) {
  103. delete interfaces.value(className, 0);
  104. interfaces.remove(className);
  105. } else {
  106. interfaces[className] = interface;
  107. }
  108. }
  109.  
  110. static QMap<QString, BaseInterface*> interfaces;
  111.  
  112. };
  113.  
  114. QMap<QString, BaseInterface*> Factory::interfaces;
  115.  
  116. static void save(QObject *o, QIODevice *dev)
  117. {
  118. const QMetaObject *mo = o->metaObject();
  119. QMap<QByteArray, QVariant> properties;
  120. QMap<QByteArray, QByteArray> objectStarProperties;
  121. QMap<QByteArray, QVariantList> listProp;;
  122.  
  123. const int props = mo->propertyCount();
  124. for (int i=0; i<props; ++i) {
  125. const QMetaProperty prop = mo->property(i);
  126. if (prop.userType() == QMetaType::QObjectStar) {
  127. QObject *obj = qVariantValue<QObject*>(prop.read(o));
  128. if (obj) {
  129. QBuffer buf;
  130. buf.open(QIODevice::WriteOnly);
  131. save(obj, &buf);
  132. objectStarProperties[prop.name()] = buf.buffer();
  133. }
  134. } else if (prop.userType() == QMetaType::QVariantList) {
  135. listProp[prop.name()] = prop.read(o).toList();
  136. } else {
  137. properties[prop.name()] = prop.read(o);
  138. }
  139. }
  140.  
  141. QDataStream ds(dev);
  142. ds << QString::fromLatin1(mo->className());
  143. ds << properties;
  144. ds << objectStarProperties;
  145.  
  146. ds << listProp.size();
  147. QMapIterator<QByteArray, QVariantList> it1( listProp );
  148. while( it1.hasNext() ) {
  149. it1.next();
  150. QVariantList vlist = it1.value();
  151. ds << vlist.size() << it1.key();
  152. }
  153.  
  154. }
  155. static QObject *read(QIODevice *dev, QObject *parent = 0)
  156. {
  157. QString className;
  158. QMap<QByteArray, QVariant> properties;
  159. QMap<QByteArray, QByteArray> objectStarProperties;
  160.  
  161. QDataStream ds(dev);
  162.  
  163. ds >> className;
  164. ds >> properties;
  165. ds >> objectStarProperties;
  166.  
  167. int nlists;
  168. ds >> nlists;
  169.  
  170. QList<int> iList;
  171. QList<QByteArray> propNameList;
  172. for ( int idx=0; idx<nlists; idx++ ) {
  173. int il;
  174. ds >> il >> pnl;
  175. iList.append( il );
  176. propNameList.append( pnl );
  177. }
  178.  
  179. QObject *o = Factory::create(className,
  180. properties.value("objectName").toString());
  181. if (!o) {
  182. qWarning() << "Can't create object of type" << className;
  183. return 0;
  184. }
  185.  
  186. for (QMap<QByteArray, QVariant>::const_iterator it = properties.begin();
  187. it != properties.end(); ++it) {
  188. if (!o->setProperty(it.key().constData(), it.value())) {
  189. qWarning() << "Can't set" << it.key();
  190. }
  191. }
  192.  
  193. for (QMap<QByteArray, QByteArray>::const_iterator it =
  194. objectStarProperties.begin();
  195. it != objectStarProperties.end(); ++it) {
  196. QBuffer buf;
  197. buf.setData(it.value());
  198. buf.open(QIODevice::ReadOnly);
  199. QObject *obj = read(&buf, 0);
  200. o->setProperty(it.key(), qVariantFromValue<QObject*>(obj));
  201. }
  202.  
  203. for ( int idx=0; idx<nlists; idx++ ) {
  204. QVariantList objList;
  205. for (int ii=0; ii<iList[idx]; ++ii) {
  206. QObject* oo = read(dev, o);
  207. objList << qVariantFromValue<QObject*>( oo );
  208. }
  209. o->setProperty( propNameList[idx], objList );
  210. }
  211.  
  212. return o;
  213.  
  214. }
  215.  
  216. #include "main.moc"
  217.  
  218. int main()
  219. {
  220. Factory::registerClass("Parent", new Creator<Parent>());
  221. Factory::registerClass("Object", new Creator<Object>());
  222.  
  223. Object *o = new Object;
  224. o->setString("foobar");
  225.  
  226. Parent *p = new Parent;
  227. p->setObject(o);
  228.  
  229. qobject_cast<Object*>( p->object() )->dump();
  230.  
  231. QFile file("tt.ss");
  232. file.open(QIODevice::WriteOnly);
  233.  
  234. save(p, &file);
  235. file.close();
  236.  
  237. file.open(QIODevice::ReadOnly);
  238.  
  239. QObject *root = read(&file);
  240. Q_ASSERT(root);
  241. Parent *pp = qobject_cast<Parent*>(root);
  242.  
  243. qobject_cast<Object*>( pp->object() )->dump();
  244.  
  245. return 0;
  246. }
To copy to clipboard, switch view to plain text mode