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
|