File: configobject.hh

package info (click to toggle)
qdmr 0.13.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 22,420 kB
  • sloc: cpp: 95,929; xml: 10,749; python: 1,108; makefile: 78; sh: 9
file content (408 lines) | stat: -rw-r--r-- 15,942 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
#ifndef CONFIGOBJECT_HH
#define CONFIGOBJECT_HH

#include <QObject>
#include <QString>
#include <QHash>
#include <QVector>
#include <QMetaProperty>

#include <yaml-cpp/yaml.h>

#include "errorstack.hh"

// Forward declaration
class Config;
class ConfigObject;
class ConfigExtension;

/** Helper function to test property type. */
template <class T>
bool propIsInstance(const QMetaProperty &prop) {
  if (QMetaType::UnknownType == prop.typeId())
    return false;
  QMetaType type = prop.metaType();
  if (! (QMetaType::PointerToQObject & type.flags()))
    return false;
  return type.metaObject()->inherits(&T::staticMetaObject);
}


/** Base class for all configuration objects (channels, zones, contacts, etc).
 *
 * @ingroup conf */
class ConfigItem : public QObject
{
  Q_OBJECT

public:
  /** Parse context for config objects. During serialization, each config object gets an
   * ID assigned. When reading the config, these IDs must be matched back to the corresponding
   * objects. This is done using this context. */
  class Context
  {
  public:
    /** Empty constructor. */
    Context();
    /** Destructor. */
    virtual ~Context();

    /** Returns the read version string. */
    const QString &version() const;
    /** Sets the version string. */
    void setVersion(const QString &ver);

    /** Returns @c true, if the context contains the given object. */
    virtual bool contains(ConfigObject *obj) const;
    /** Returns @c true, if the context contains the given ID. */
    virtual bool contains(const QString &id) const;

    /** Returns ID of the given object. */
    virtual QString getId(ConfigObject *obj) const;
    /** Returns the object for the given ID. */
    virtual ConfigObject *getObj(const QString &id) const;

    /** Associates the given object with the given ID. */
    virtual bool add(const QString &id, ConfigObject *);

    /** Returns @c true if the property of the class has the specified tag associated. */
    static bool hasTag(const QString &className, const QString &property, const QString &tag);
    /** Returns @c true if the property of the class has the specified object as a tag associated. */
    static bool hasTag(const QString &className, const QString &property, ConfigObject *obj);
    /** Returns the object associated with the tag for the property of the class. */
    static ConfigObject *getTag(const QString &className, const QString &property, const QString &tag);
    /** Returns the tag associated with the object for the property of the class. */
    static QString getTag(const QString &className, const QString &property, ConfigObject *obj);
    /** Associates the given object with the tag for the property of the given class. */
    static void setTag(const QString &className, const QString &property, const QString &tag, ConfigObject *obj);

  protected:
    /** The version string. */
    QString _version;
    /** ID->OBJ look-up table. */
    QHash<QString, ConfigObject *> _objects;
    /** OBJ->ID look-up table. */
    QHash<ConfigObject*, QString> _ids;
    /** Maps tags to singleton objects. */
    static QHash<QString, QHash<QString, ConfigObject *>> _tagObjects;
    /** Maps singleton objects to tags. */
    static QHash<QString, QHash<ConfigObject *, QString>> _tagNames;
  };

protected:
  /** Hidden constructor.
   * @param parent Specifies the QObject parent. */
  explicit ConfigItem(QObject *parent = nullptr);

public:
  /** Copies the given item into this one.
   * @returns @c true if copying was successful and false otherwise. The two items must be of the
   *          same type (obviously). */
  virtual bool copy(const ConfigItem &other);

  /** Clones this item. */
  virtual ConfigItem *clone() const = 0;

  /** Compares the items.
   *
   * This method returns 0 if the two items are equivalent and -1, 1 otherwise. The established
   * order is somewhat arbitrary.
   *
   * @returns 0 if the two items are equivalent, -1 or 1 otherwise.*/
  virtual int compare(const ConfigItem &other) const;

public:
  /** Recursively labels the config object.
   * Does not assign a label if the @c idBase passed to the constructor is empty. */
  virtual bool label(Context &context, const ErrorStack &err=ErrorStack());
  /** Recursively serializes the configuration to YAML nodes.
   * The complete configuration must be labeled first. */
  virtual YAML::Node serialize(const Context &context, const ErrorStack &err=ErrorStack());

  /** Allocates an instance for the given property on the given YAML node.
   * This is usually done automatically based on the meta-type of the property. To be able to
   * instantiate the item, its default constructor must be Q_INVOKABLE. */
  virtual ConfigItem *allocateChild(QMetaProperty &prop, const YAML::Node &node,
                                    const Context &ctx, const ErrorStack &err=ErrorStack());
  /** Parses the given YAML node, updates the given object and updates the given context (IDs). */
  virtual bool parse(const YAML::Node &node, Context &ctx, const ErrorStack &err=ErrorStack());
  /** Links the given object to the rest of the codeplug using the given context. */
  virtual bool link(const YAML::Node &node, const Context &ctx, const ErrorStack &err=ErrorStack());

  /** Clears the config object. */
  virtual void clear();

  /** Returns the config, the item belongs to or @c nullptr if not part of a config. */
  virtual const Config *config() const;
  /** Searches the config tree to find all instances of the given type names. */
  virtual void findItemsOfTypes(const QStringList &typeNames, QSet<ConfigItem*> &items) const;

  /** Returns @c true if this object is of class @c Object. */
  template <class Object>
  bool is() const {
    return nullptr != qobject_cast<const Object*>(this);
  }

  /** Casts this object to the given type. */
  template <class Object>
  const Object *as() const {
    return qobject_cast<const Object*>(this);
  }

  /** Casts this object to the given type. */
  template <class Object>
  Object *as() {
    return qobject_cast<Object *>(this);
  }

  /** Returns @c true if there is a class info "description" for this instance. */
  bool hasDescription() const;
  /** Returns @c true if there is a class info "longDescription" for this instance. */
  bool hasLongDescription() const;
  /** Returns @c true if there is a class info "[PropertyName]Description" for the given property. */
  bool hasDescription(const QMetaProperty &prop) const;
  /** Returns @c true if there is a class info "[PropertyName]LongDescription" for the given property. */
  bool hasLongDescription(const QMetaProperty &prop) const;
  /** Returns the description of this instance if set by a class info. */
  QString description() const;
  /** Returns the long description of this instance if set by a class info. */
  QString longDescription() const;
  /** Returns the description of property if set by a class info. */
  QString description(const QMetaProperty &prop) const;
  /** Returns the long description of property if set by a class info. */
  QString longDescription(const QMetaProperty &prop) const;

protected:
  /** Recursively serializes the configuration to YAML nodes.
   * The complete configuration must be labeled first. */
  virtual bool populate(YAML::Node &node, const Context &context, const ErrorStack &err=ErrorStack());

signals:
  /** Gets emitted once the config object is modified.
   * The instance passed is the modified item, this event is passed up the config tree. */
  void modified(ConfigItem *obj);
  /** Gets emitted before clearing the item. */
  void beginClear();
  /** Gets emitted after clearing the item. */
  void endClear();
};


/** Base class of all labeled and named objects.
 * @ingroup config */
class ConfigObject: public ConfigItem
{
  Q_OBJECT

  /** The name of the object. */
  Q_PROPERTY(QString name READ name WRITE setName)

  /** Specifies the prefix for every ID assigned to every object during serialization. */
  Q_CLASSINFO("IdPrefix", "obj")

protected:
  /** Hidden constructor.
   * @param parent Specifies the QObject parent. */
  ConfigObject(QObject *parent = nullptr);

  /** Hidden constructor.
   * @param name Name of the object.
   * @param parent Specifies the QObject parent. */
  ConfigObject(const QString &name, QObject *parent = nullptr);

public:
  /** Returns the name of the object. */
  virtual const QString &name() const;
  /** Sets the name of the object. */
  virtual void setName(const QString &name);

public:
  /** Returns the ID prefix for this object. */
  QString idPrefix() const;
  bool label(Context &context, const ErrorStack &err=ErrorStack());
  bool parse(const YAML::Node &node, Context &ctx, const ErrorStack &err=ErrorStack());

protected:
  virtual bool populate(YAML::Node &node, const Context &context, const ErrorStack &err=ErrorStack());

  /** Helper to find the @c IdPrefix class info in the class hierarchy. */
  static QString findIdPrefix(const QMetaObject* meta);

protected:
  /** Holds the name of the object. */
  QString _name;
};


/** Base class of all device/vendor specific configuration extensions.
 * This class already implements the serialization of all @c QMetaObject
 * properties. */
class ConfigExtension : public ConfigItem
{
  Q_OBJECT

protected:
  /** Hidden constructor. */
  explicit ConfigExtension(QObject *parent=nullptr);
};


/** Generic list class for config objects.
 * @ingroup config */
class AbstractConfigObjectList: public QObject
{
  Q_OBJECT

protected:
  /** Hidden constructor. */
  explicit AbstractConfigObjectList(const QMetaObject &elementTypes=ConfigObject::staticMetaObject, QObject *parent = nullptr);
  /** Hidden constructor from initializer list. */
  AbstractConfigObjectList(const std::initializer_list<QMetaObject> &elementTypes, QObject *parent=nullptr);

public:
  /** Copies all elements from @c other to this list. */
  virtual bool copy(const AbstractConfigObjectList &other);

  /** Recursively labels the config object. */
  virtual bool label(ConfigItem::Context &context, const ErrorStack &err=ErrorStack()) = 0;
  /** Recursively serializes the configuration to YAML nodes.
   * The complete configuration must be labeled first. */
  virtual YAML::Node serialize(const ConfigItem::Context &context, const ErrorStack &err=ErrorStack()) = 0;

  /** Returns the number of elements in the list. */
  virtual int count() const;
  /** Returns the index of the given object within the list. */
  virtual int indexOf(ConfigObject *obj) const;
  /** Clears the list. */
  virtual void clear();

  /** Returns the config object, this list belongs to. */
  virtual const Config *config() const;
  /** Searches the config tree to find all instances of the given type names. */
  virtual void findItemsOfTypes(const QStringList &typeNames, QSet<ConfigItem*> &items) const;
  /** Searches the list for objects with the given name. */
  virtual QList<ConfigObject *> findItemsByName(const QString name) const;

  /** Returns @c true, if the list contains the given object. */
  virtual bool has(ConfigObject *obj) const;
  /** Returns the list element at the given index or @c nullptr if out of bounds. */
  virtual ConfigObject *get(int idx) const;
  /** Adds an element to the list. */
  virtual int add(ConfigObject *obj, int row=-1, bool unique=true);
  /** Replaces an element in the list. */
  virtual int replace(ConfigObject *obj, int row, bool unique=true);
  /** Removes an element from the list. */
  virtual bool take(ConfigObject *obj);
  /** Removes an element from the list (and deletes it if owned). */
  virtual bool del(ConfigObject *obj);

  /** Moves an object at index @c idx one step up. */
  virtual bool moveUp(int idx);
  /** Moves objects at [first, last] one step up. */
  virtual bool moveUp(int first, int last);
  /** Moves an object at index @c idx one step down. */
  virtual bool moveDown(int idx);
  /** Moves objects [first, last] one step down. */
  virtual bool moveDown(int first, int last);
  /** Moves the given source range to the destination index.
   * The destination index is given before the movement. That is, if elements 0 & 1 are moved to
   * indices 1 & 2, call @c move(0,2, 2) */
  virtual bool move(int source, int count, int destination);

  /** Returns the element type for this list. */
  const QList<QMetaObject> &elementTypes() const;
  /** Returns a list of all class names. */
  QStringList classNames() const;

signals:
  /** Gets emitted if an element was added to the list. */
  void elementAdded(int idx);
  /** Gets emitted if one of the lists elements gets modified. */
  void elementModified(int idx);
  /** Gets emitted if one of the lists elements gets deleted. */
  void elementRemoved(int idx);

private slots:
  /** Internal used callback to handle modified elements. */
  void onElementModified(ConfigItem *obj);
  /** Internal used callback to handle deleted elements. */
  void onElementDeleted(QObject *obj);

protected:
  /** Holds the static QMetaObject of the element type. */
  QList<QMetaObject> _elementTypes;
  /** Holds the list items. */
  QVector<ConfigObject *> _items;
};


/** List class for config objects.
 * This list owns the config objects it contains. See @c ConfigObjectRefList for a list of weak
 * references.
 * @ingroup config */
class ConfigObjectList: public AbstractConfigObjectList
{
  Q_OBJECT

protected:
  /** Hidden constructor. */
  explicit ConfigObjectList(const QMetaObject &elementTypes=ConfigItem::staticMetaObject, QObject *parent = nullptr);
  /** Hidden constructor from initializer list. */
  ConfigObjectList(const std::initializer_list<QMetaObject> &elementTypes, QObject *parent=nullptr);

public:
  int add(ConfigObject *obj, int row=-1, bool unique=true);
  bool take(ConfigObject *obj);
  bool del(ConfigObject *obj);
  void clear();
  bool copy(const AbstractConfigObjectList &other);

  /** Compares the object lists.
   *
   * This method returns 0 if the two lists are equivalent and -1, 1 otherwise. The established
   * order is somewhat arbitrary.
   *
   * @returns 0 if the two lists are equivalent, -1 or 1 otherwise.*/
  virtual int compare(const ConfigObjectList &other) const;

  /** Allocates a member objects for the given YAML node. */
  virtual ConfigItem *allocateChild(const YAML::Node &node, ConfigItem::Context &ctx, const ErrorStack &err=ErrorStack()) = 0;
  /** Parses the list from the YAML node. */
  virtual bool parse(const YAML::Node &node, ConfigItem::Context &ctx, const ErrorStack &err=ErrorStack());
  /** Links the list from the given YAML node. */
  virtual bool link(const YAML::Node &node, const ConfigItem::Context &ctx, const ErrorStack &err=ErrorStack());

  bool label(ConfigItem::Context &context, const ErrorStack &err=ErrorStack());
  YAML::Node serialize(const ConfigItem::Context &context, const ErrorStack &err=ErrorStack());
};


/** List class for config objects.
 * This list only references the config objects, see @c ConfigObjectList for a list that owns the
 * config objects.
 * @ingroup config */
class ConfigObjectRefList: public AbstractConfigObjectList
{
  Q_OBJECT

protected:
  /** Hidden constructor. */
  explicit ConfigObjectRefList(const QMetaObject &elementTypes=ConfigObject::staticMetaObject, QObject *parent = nullptr);
  /** Hidden constructor from initializer list. */
  ConfigObjectRefList(const std::initializer_list<QMetaObject> &elementTypes, QObject *parent=nullptr);

public:
  bool label(ConfigItem::Context &context, const ErrorStack &err=ErrorStack());
  YAML::Node serialize(const ConfigItem::Context &context, const ErrorStack &err=ErrorStack());

  /** Compares the object ref lists.
   *
   * This method returns 0 if the two lists are equivalent and -1, 1 otherwise. The established
   * order is somewhat arbitrary.
   *
   * @returns 0 if the two lists are equivalent, -1 or 1 otherwise.*/
  virtual int compare(const ConfigObjectRefList &other) const;
};


#endif // CONFIGOBJECT_HH