From 19b36bcece44e3390fbaab6f5a5744f0c4a36c41 Mon Sep 17 00:00:00 2001 From: Skycoder42 Date: Fri, 27 Jul 2018 00:49:30 +0200 Subject: [PATCH] modified cpp settings gen part for list entries --- src/mvvmcore/settingsentry.h | 398 ++++++------------ .../settingsgenerator/generatortest.xml | 30 +- .../mvvmcore/settingsgenerator/test_de.ts | 2 +- .../settingsgenerator/testbackend.cpp | 4 +- .../tst_settingsgenerator.cpp | 115 +++-- .../cppsettingsgenerator.cpp | 99 +++-- .../settingsgenerator/cppsettingsgenerator.h | 22 +- .../settingsgenerator/qsettingsgenerator.xsd | 9 + 8 files changed, 311 insertions(+), 368 deletions(-) diff --git a/src/mvvmcore/settingsentry.h b/src/mvvmcore/settingsentry.h index b0b4269..c58bc85 100644 --- a/src/mvvmcore/settingsentry.h +++ b/src/mvvmcore/settingsentry.h @@ -1,8 +1,12 @@ #ifndef QTMVVM_SETTINGSENTRY_H #define QTMVVM_SETTINGSENTRY_H +#include + #include #include +#include +#include #include "QtMvvmCore/qtmvvmcore_global.h" #include "QtMvvmCore/isettingsaccessor.h" @@ -52,71 +56,40 @@ public: }; template -class SettingsListEntry +class SettingsListNode { - Q_DISABLE_COPY(SettingsListEntry) + Q_DISABLE_COPY(SettingsListNode) public: - class ListElement + class Deferred { - Q_DISABLE_COPY(ListElement) - - public: - inline ListElement(ListElement &&other) noexcept = default; - inline ListElement &operator=(ListElement &&other) noexcept = default; - - TType get() const && { return _self->getAt(_index); } - void set(const TType &value) && { _self->setAt(_index, value); } - - inline ListElement &operator=(const TType &value) && { _self->setAt(_index, value); return *this; } - inline operator TType() const && { return _self->getAt(_index); } - - private: - friend class SettingsListEntry; - inline ListElement(SettingsListEntry *self, int index) : _self{self}, _index{index} {} - - SettingsListEntry *_self; - int _index; - }; - - template - class iterator_base; + Q_DISABLE_COPY(Deferred) - class iterator_value - { public: - TType get() const { return _self->getAt(_index); } - void set(const TType &value) { _self->setAt(_index, value); } - - inline iterator_value &operator=(const TType &value) { _self->setAt(_index, value); return *this; } - inline operator TType() const { return _self->getAt(_index); } + inline Deferred(Deferred &&other) noexcept = default; + inline Deferred &operator=(Deferred &&other) noexcept = default; + inline ~Deferred() { commit(); } - inline friend void swap(iterator_value& lhs, iterator_value& rhs) { qSwap(lhs._self, rhs._self); qSwap(lhs._index, rhs._index); } + inline TType &element() { return _element; } - inline friend bool operator==(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index == rhs._index; } - inline friend bool operator!=(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index != rhs._index; } - inline friend bool operator<(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index < rhs._index; } - inline friend bool operator>(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index > rhs._index; } - inline friend bool operator<=(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index <= rhs._index; } - inline friend bool operator>=(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index >= rhs._index; } + inline TType &operator*() { return _element; } + inline TType *operator->() { return &_element; } - inline friend iterator_value operator+(const iterator_value &value, int delta) { return iterator_value{value._self, value._index + delta}; } - inline friend iterator_value operator+(int delta, const iterator_value &value) { return iterator_value{value._self, value._index + delta}; } - inline friend iterator_value operator-(const iterator_value &value, int delta) { return iterator_value{value._self, value._index - delta}; } - inline friend int operator-(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index - rhs._index; } + inline void commit() { if(!_commited) { _commited = true; _node->commit(_index);} } private: - template - friend class SettingsListEntry::iterator_base; - - inline iterator_value(SettingsListEntry *self, int index) : _self{self}, _index{index} {} - inline iterator_value(const iterator_value &other) = default; - inline iterator_value &operator=(const iterator_value &other) = default; - inline iterator_value(iterator_value &&other) noexcept = default; - inline iterator_value &operator=(iterator_value &&other) noexcept = default; + friend class SettingsListNode; - SettingsListEntry *_self; + SettingsListNode *_node; + TType &_element; + bool _commited = false; int _index; + + inline Deferred(SettingsListNode *node, TType &element, int index) : + _node{node}, + _element{element}, + _index{index} + {} }; template @@ -129,73 +102,67 @@ public: using pointer = value_type*; using reference = value_type&; + inline iterator_base() = default; inline iterator_base(const iterator_base &other) = default; inline iterator_base &operator=(const iterator_base &other) = default; inline iterator_base(iterator_base &&other) noexcept = default; inline iterator_base &operator=(iterator_base &&other) noexcept = default; - inline iterator_base &operator++() { ++_value._index; return *this; } - inline iterator_base operator++(int) { return iterator_base{_value._self, _value._index++}; } - inline iterator_base &operator--() { --_value._index; return *this; } - inline iterator_base operator--(int) { return iterator_base{_value._self, _value._index--}; } - - inline const value_type &operator*() const { return _value; } - inline value_type &operator*() { return _value; } - inline const value_type *operator->() const { return &_value; } - inline value_type *operator->() { return &_value; } - inline friend void swap(iterator_base &lhs, iterator_base &rhs) { swap(lhs._value, rhs._value); } - - inline friend bool operator==(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value == rhs._value; } - inline friend bool operator!=(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value != rhs._value; } - inline friend bool operator<(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value < rhs._value; } - inline friend bool operator>(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value > rhs._value; } - inline friend bool operator<=(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value <= rhs._value; } - inline friend bool operator>=(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value >= rhs._value; } - - inline iterator_base &operator+=(difference_type delta) { _value._index += delta; return *this; } - inline friend iterator_base operator+(const iterator_base &iter, difference_type delta) { return iterator_base{iter._value + delta}; } - inline friend iterator_base operator+(difference_type delta, const iterator_base &iter) { return iterator_base{iter._value + delta}; } - inline iterator_base &operator-=(difference_type delta) { _value._index -= delta; return *this; } - inline friend iterator_base operator-(const iterator_base &iter, difference_type delta) { return iterator_base{iter._value - delta}; } - inline friend difference_type operator-(const iterator_base &lhs, const iterator_base &rhs) { return lhs._value - rhs._value; } - - inline value_type operator[](difference_type delta) const { return iterator_value{_value._self, _value._index + delta}; } + inline iterator_base &operator++() { ++_index; return *this; } + inline iterator_base operator++(int) { return iterator_base{_node, _index++}; } + inline iterator_base &operator--() { --_index; return *this; } + inline iterator_base operator--(int) { return iterator_base{_node, _index--}; } + + inline reference operator*() const { return _node->at(_index); } + inline pointer operator->() const { return &_node->at(_index); } + inline friend void swap(iterator_base &lhs, iterator_base &rhs) noexcept { std::swap(lhs._node, rhs._node); std::swap(lhs._index, rhs._index); } + + inline friend bool operator==(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index == rhs._index; } + inline friend bool operator!=(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index != rhs._index; } + inline friend bool operator<(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index < rhs._index; } + inline friend bool operator>(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index > rhs._index; } + inline friend bool operator<=(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index <= rhs._index; } + inline friend bool operator>=(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index >= rhs._index; } + + inline iterator_base &operator+=(difference_type delta) { _index += delta; return *this; } + inline friend iterator_base operator+(const iterator_base &iter, difference_type delta) { return iterator_base{iter._node, iter._index + delta}; } + inline friend iterator_base operator+(difference_type delta, const iterator_base &iter) { return iterator_base{iter._node, iter._index + delta}; } + inline iterator_base &operator-=(difference_type delta) { _index -= delta; return *this; } + inline friend iterator_base operator-(const iterator_base &iter, difference_type delta) { return iterator_base{iter._node, iter._index - delta}; } + inline friend difference_type operator-(const iterator_base &lhs, const iterator_base &rhs) { assert(lhs._node == rhs._node); return lhs._index - rhs._index; } + + inline reference operator[](difference_type delta) const { return _node->at(_index + delta); } private: - friend class SettingsListEntry; + friend class SettingsListNode; + + SettingsListNode *_node; + int _index; - inline iterator_base(SettingsListEntry *self, int index) : _value{self, index} {} - inline iterator_base(iterator_value value) : _value{std::move(value)} {} - iterator_value _value; + inline iterator_base(SettingsListNode *node, int index) : + _node{node}, + _index{index} + {} }; - using iterator = iterator_base; - using const_iterator = iterator_base; + using iterator = iterator_base; + using const_iterator = iterator_base; - SettingsListEntry() = default; + SettingsListNode() = default; bool isSet() const; QString key() const; + int size() const; + const TType &at(int index) const; + TType &at(int index); - QList get() const; - void set(const QList &value); - void reset(bool reInit = true); - - SettingsListEntry &operator=(const QList &value); - operator QList() const; + TType &push(); + Deferred push_deferred(); + void pop(int count = 1); + void reset(); - int size() const; - TType getAt(int index) const; - void setAt(int index, const TType &value); - void push(const TType &value); - void push(const QList &values); - TType pop(); - void chop(int count); - - ListElement operator[](int index); - const ListElement operator[](int index) const; - SettingsListEntry &operator+=(const TType &value); - SettingsListEntry &operator+=(const QList &values); + TType &operator[](int index); + const TType &operator[](int index) const; iterator begin(); iterator end(); @@ -204,22 +171,26 @@ public: const_iterator constBegin() const; const_iterator constEnd() const; - void addChangeCallback(const std::function)> &callback); - void addChangeCallback(QObject *scope, const std::function)> &callback); - void addChangeCallback(const std::function &callback); // index, value - void addChangeCallback(QObject *scope, const std::function &callback); - void addSizeChangeCallback(const std::function &callback); // size - void addSizeChangeCallback(QObject *scope, const std::function &callback); + void addChangeCallback(const std::function &callback); // size + void addChangeCallback(QObject *scope, const std::function &callback); // internal - void setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue = {}); - void setupInit(QList init); + void setup(QString key, ISettingsAccessor *accessor, std::function setupFn); private: + struct ElementHolder { + bool __initialized = false; + QSharedPointer _element; + inline ElementHolder() : _element{new TType{}} {} + }; + QString _key; + QString _sizeKey; ISettingsAccessor *_accessor = nullptr; - QVariant _default; - QList _init; + std::function _setupFn; + mutable QHash _cache; + + void commit(int index); }; // ------------- Generic Implementation ------------- @@ -308,259 +279,164 @@ void SettingsEntry::setup(QString key, ISettingsAccessor *accessor, QVariant _default = std::move(defaultValue); } - -// ------------- Generic Implementation ListEntry ------------- +// ------------- Generic Implementation ListNode ------------- template -bool SettingsListEntry::isSet() const +bool SettingsListNode::isSet() const { - return _accessor->contains(_key + QStringLiteral("/size")); + return _accessor->contains(_sizeKey); } template -QString SettingsListEntry::key() const +QString SettingsListNode::key() const { return _key; } template -QList SettingsListEntry::get() const -{ - auto mSize = size(); - QList resList; - resList.reserve(mSize); - for(auto i = 0; i < mSize; ++i) - resList.append(getAt(i)); - return resList; -} - -template -void SettingsListEntry::set(const QList &value) -{ - reset(false); - push(value); -} - -template -void SettingsListEntry::reset(bool reInit) -{ - _accessor->remove(_key); - if(reInit && !_init.isEmpty()) - push(_init); -} - -template -SettingsListEntry &SettingsListEntry::operator=(const QList &value) -{ - set(value); - return *this; -} - -template -SettingsListEntry::operator QList() const -{ - return get(); -} - -template -int SettingsListEntry::size() const -{ - return _accessor->load(_key + QStringLiteral("/size"), 0).toInt(); -} - -template -TType SettingsListEntry::getAt(int index) const +int SettingsListNode::size() const { - return _accessor->load(_key + QStringLiteral("/%1/value").arg(index), _default).template value(); + return _accessor->load(_sizeKey, 0).toInt(); } template -void SettingsListEntry::setAt(int index, const TType &value) +const TType &SettingsListNode::at(int index) const { - _accessor->save(_key + QStringLiteral("/%1/value").arg(index), QVariant::fromValue(value)); + auto &value = _cache[index]; + if(!value.__initialized) { + _setupFn(index, *(value._element)); + value.__initialized = true; + } + return *(value._element); } template -void SettingsListEntry::push(const TType &value) +TType &SettingsListNode::at(int index) { - push(QList{value}); + auto &value = _cache[index]; + if(!value.__initialized) { + _setupFn(index, *(value._element)); + value.__initialized = true; + } + return *(value._element); } template -void SettingsListEntry::push(const QList &values) +TType &SettingsListNode::push() { auto cIndex = size(); - for(const auto &value : values) - setAt(cIndex++, value); - _accessor->save(_key + QStringLiteral("/size"), cIndex); + _accessor->save(_sizeKey, cIndex + 1); + return at(cIndex); } template -TType QtMvvm::SettingsListEntry::pop() +typename SettingsListNode::Deferred SettingsListNode::push_deferred() { - auto res = getAt(size() - 1); - chop(1); - return res; + auto cIndex = size(); + return {this, at(cIndex), cIndex}; } template -void QtMvvm::SettingsListEntry::chop(int count) +void SettingsListNode::pop(int count) { auto cSize = size(); auto nSize = qMax(size() - count, 0); for(auto i = cSize - 1; i >= nSize; --i) - _accessor->remove(_key + QStringLiteral("/%1/value").arg(i)); - _accessor->save(_key + QStringLiteral("/size"), nSize); + _accessor->remove(_key + QStringLiteral("/%1").arg(i)); + _accessor->save(_sizeKey, nSize); } template -const typename SettingsListEntry::ListElement SettingsListEntry::operator[](int index) const +void SettingsListNode::reset() { - return ListElement{this, index}; + _accessor->remove(_key); } - template -typename SettingsListEntry::ListElement SettingsListEntry::operator[](int index) +const TType &SettingsListNode::operator[](int index) const { - return ListElement{this, index}; + return at(index); } -template -SettingsListEntry &SettingsListEntry::operator+=(const TType &value) -{ - push(value); - return *this; -} template -SettingsListEntry &SettingsListEntry::operator+=(const QList &values) +TType &SettingsListNode::operator[](int index) { - push(values); - return *this; + return at(index); } template -typename SettingsListEntry::iterator SettingsListEntry::begin() +typename SettingsListNode::iterator SettingsListNode::begin() { return iterator{this, 0}; } template -typename SettingsListEntry::iterator QtMvvm::SettingsListEntry::end() +typename SettingsListNode::iterator SettingsListNode::end() { return iterator{this, size()}; } template -typename SettingsListEntry::const_iterator SettingsListEntry::begin() const +typename SettingsListNode::const_iterator SettingsListNode::begin() const { return constBegin(); } template -typename SettingsListEntry::const_iterator SettingsListEntry::end() const +typename SettingsListNode::const_iterator SettingsListNode::end() const { return constEnd(); } template -typename SettingsListEntry::const_iterator SettingsListEntry::constBegin() const +typename SettingsListNode::const_iterator SettingsListNode::constBegin() const { - return const_iterator{const_cast*>(this), 0}; + return const_iterator{const_cast*>(this), 0}; } template -typename SettingsListEntry::const_iterator SettingsListEntry::constEnd() const +typename SettingsListNode::const_iterator SettingsListNode::constEnd() const { - return const_iterator{const_cast*>(this), size()}; + return const_iterator{const_cast*>(this), size()}; } template -void SettingsListEntry::addChangeCallback(const std::function)> &callback) +void SettingsListNode::addChangeCallback(const std::function &callback) { addChangeCallback(_accessor, callback); } template -void SettingsListEntry::addChangeCallback(QObject *scope, const std::function)> &callback) +void SettingsListNode::addChangeCallback(QObject *scope, const std::function &callback) { - QObject::connect(_accessor, &ISettingsAccessor::entryChanged, - scope, [this, callback](const QString &key, const QVariant &) { - if(key.startsWith(_key)) - callback(get()); - }); - QObject::connect(_accessor, &ISettingsAccessor::entryRemoved, - scope, [this, callback](const QString &key) { - if(key.startsWith(_key)) - callback(get()); - }); -} - -template -void SettingsListEntry::addChangeCallback(const std::function &callback) -{ - addChangeCallback(_accessor, callback); -} - -template -void SettingsListEntry::addChangeCallback(QObject *scope, const std::function &callback) -{ - QRegularExpression mKey {QStringLiteral("^%1\\/\\d+\\/value$").arg(QRegularExpression::escape(_key))}; - mKey.optimize(); - auto mDefault = _default; - QObject::connect(_accessor, &ISettingsAccessor::entryChanged, - scope, [mKey, callback](const QString &key, const QVariant &value) { - auto match = mKey.match(key); - if(match.hasMatch()) - callback(match.captured(1).toInt(), value.template value()); - }); - QObject::connect(_accessor, &ISettingsAccessor::entryRemoved, - scope, [mKey, mDefault, callback](const QString &key) { - auto match = mKey.match(key); - if(match.hasMatch()) - callback(match.captured(1).toInt(), mDefault.template value()); - }); -} - -template -void SettingsListEntry::addSizeChangeCallback(const std::function &callback) -{ - addSizeChangeCallback(_accessor, callback); -} - -template -void SettingsListEntry::addSizeChangeCallback(QObject *scope, const std::function &callback) -{ - QString mKey = _key + QStringLiteral("/size"); - auto mInit = _init; + QString mKey = _sizeKey; QObject::connect(_accessor, &ISettingsAccessor::entryChanged, scope, [mKey, callback](const QString &key, const QVariant &value) { if(key == mKey) callback(value.toInt()); }); QObject::connect(_accessor, &ISettingsAccessor::entryRemoved, - scope, [mKey, mInit, callback](const QString &key) { + scope, [mKey, callback](const QString &key) { if(key == mKey) - callback(0); //is ok, as in case of a "reinit", the entry changed will be emitted next + callback(0); }); } template -void SettingsListEntry::setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue) +void SettingsListNode::setup(QString key, ISettingsAccessor *accessor, std::function setupFn) { Q_ASSERT_X(accessor, Q_FUNC_INFO, "You must set a valid accessor before initializing the settings!"); _key = std::move(key); + _sizeKey = _key + QStringLiteral("/size"); _accessor = accessor; - _default = std::move(defaultValue); + _setupFn = std::move(setupFn); } template -void QtMvvm::SettingsListEntry::setupInit(QList init) +void SettingsListNode::commit(int index) { - _init = std::move(init); - if(!isSet()) - push(_init); + _accessor->save(_sizeKey, qMax(size(), index + 1)); } } diff --git a/tests/auto/mvvmcore/settingsgenerator/generatortest.xml b/tests/auto/mvvmcore/settingsgenerator/generatortest.xml index 53779ef..1c681f6 100644 --- a/tests/auto/mvvmcore/settingsgenerator/generatortest.xml +++ b/tests/auto/mvvmcore/settingsgenerator/generatortest.xml @@ -62,15 +62,25 @@ {42} - - + - "Hello World" - { - "test1", - "test2", - "test3" - } - + + + + + + + + + + diff --git a/tests/auto/mvvmcore/settingsgenerator/test_de.ts b/tests/auto/mvvmcore/settingsgenerator/test_de.ts index 1d6c479..2303444 100644 --- a/tests/auto/mvvmcore/settingsgenerator/test_de.ts +++ b/tests/auto/mvvmcore/settingsgenerator/test_de.ts @@ -4,7 +4,7 @@ SettingsGeneratorTest - + somet translated text... diff --git a/tests/auto/mvvmcore/settingsgenerator/testbackend.cpp b/tests/auto/mvvmcore/settingsgenerator/testbackend.cpp index 8927dcc..9b525d8 100644 --- a/tests/auto/mvvmcore/settingsgenerator/testbackend.cpp +++ b/tests/auto/mvvmcore/settingsgenerator/testbackend.cpp @@ -1,4 +1,5 @@ #include "testbackend.h" +#include TestBackend::TestBackend(QString name, int code, QObject *parent) : ISettingsAccessor{parent}, @@ -26,8 +27,9 @@ void TestBackend::remove(const QString &key) { for(auto it = _data.begin(); it != _data.end();) { if(it.key().startsWith(key + QLatin1Char('/'))) { + auto rmKey = it.key(); it = _data.erase(it); - emit entryRemoved(key); + emit entryRemoved(rmKey); } else ++it; } diff --git a/tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp b/tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp index 8f8de83..9fd71f2 100644 --- a/tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp +++ b/tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp @@ -41,8 +41,7 @@ void SettingsGeneratorTest::testSettingsGenerator() QCOMPARE(settings->parentNode.parentEntry.leafEntry.key(), QStringLiteral("tests/parentNode/parentEntry/leafEntry")); QCOMPARE(settings->variantEntry.key(), QStringLiteral("tests/variantEntry")); QCOMPARE(settings->simpleListEntry.key(), QStringLiteral("tests/simpleListEntry")); - QCOMPARE(settings->listEntry.key(), QStringLiteral("tests/listEntry")); - QCOMPARE(settings->listEntry.dummyChild.key(), QStringLiteral("tests/listEntry/dummyChild")); + QCOMPARE(settings->listNode.key(), QStringLiteral("tests/listNode")); //verify defaults QCOMPARE(settings->emptyEntry.get(), false); @@ -54,9 +53,6 @@ void SettingsGeneratorTest::testSettingsGenerator() QCOMPARE(settings->parentNode.parentEntry.leafEntry.get(), QStringLiteral("translate me")); QCOMPARE(settings->variantEntry.get(), QVariant{}); QCOMPARE(settings->simpleListEntry.get(), QList{42}); - QByteArrayList iList{"test1", "test2", "test3"}; - QCOMPARE(settings->listEntry.get(), iList); - QCOMPARE(settings->listEntry.dummyChild.get(), false); //verify read/write (just on a single entry, they work all the same) auto tKey = QStringLiteral("tests/advancedEntry"); @@ -74,44 +70,79 @@ void SettingsGeneratorTest::testSettingsGenerator() QCOMPARE(settings->advancedEntry, tValue); //verify list stuff - QVERIFY(settings->listEntry.isSet()); - QCOMPARE(settings->listEntry.size(), 3); - QCOMPARE(settings->listEntry.getAt(0), "test1"); - QCOMPARE(settings->listEntry[1].get(), "test2"); - QCOMPARE(static_cast(settings->listEntry[2]), "test3"); - QCOMPARE(settings->listEntry.getAt(3), "Hello World"); - - settings->listEntry.push("baum"); - QCOMPARE(settings->listEntry.size(), 4); - QCOMPARE(settings->listEntry.getAt(3), "baum"); - settings->listEntry.setAt(1, "tree"); - settings->listEntry[2] = "eetr"; - QCOMPARE(settings->listEntry.size(), 4); - QCOMPARE(settings->listEntry.getAt(1), "tree"); - QCOMPARE(settings->listEntry.getAt(2), "eetr"); - settings->listEntry += "baum42"; - QCOMPARE(settings->listEntry.size(), 5); - QCOMPARE(settings->listEntry.getAt(4), "baum42"); - QCOMPARE(settings->listEntry.pop(), "baum42"); - QCOMPARE(settings->listEntry.size(), 4); - QCOMPARE(settings->listEntry.getAt(4), "Hello World"); - settings->listEntry.chop(10); - QCOMPARE(settings->listEntry.size(), 0); - QVERIFY(settings->listEntry.isSet()); - - settings->listEntry.reset(false); - QVERIFY(!settings->listEntry.isSet()); - QCOMPARE(settings->listEntry.size(), 0); - settings->listEntry.reset(true); - QVERIFY(settings->listEntry.isSet()); - QCOMPARE(settings->listEntry.size(), 3); - - for(const auto &elem : qAsConst(settings->listEntry)) - qDebug() << elem.get() << static_cast(elem); - for(auto &elem : settings->listEntry) { - elem = "test1"; - elem.set("test2"); + QVERIFY(!settings->listNode.isSet()); + QCOMPARE(settings->listNode.size(), 0); + settings->listNode.push(); + QVERIFY(settings->listNode.isSet()); + QCOMPARE(settings->listNode.size(), 1); + + QCOMPARE(settings->listNode.at(0).simpleChild.key(), QStringLiteral("tests/listNode/0/simpleChild")); + QCOMPARE(settings->listNode[0].someNode.deepChild.key(), QStringLiteral("tests/listNode/0/someNode/deepChild")); + QCOMPARE(settings->listNode[0].someNode.deepParent.key(), QStringLiteral("tests/listNode/0/someNode/deepParent")); + QCOMPARE(settings->listNode[0].someNode.deepParent.simpleChild.key(), QStringLiteral("tests/listNode/0/someNode/deepParent/simpleChild")); + QCOMPARE(settings->listNode[0].childList.key(), QStringLiteral("tests/listNode/0/childList")); + + QCOMPARE(settings->listNode.at(0).simpleChild, false); + QCOMPARE(settings->listNode[0].someNode.deepChild, 22); + QCOMPARE(settings->listNode[0].someNode.deepParent, QStringLiteral("___")); + QCOMPARE(settings->listNode[0].someNode.deepParent.simpleChild, true); + QVERIFY(!settings->listNode[0].childList.isSet()); + QCOMPARE(settings->listNode[0].childList.size(), 0); + + int resVal = -1; + settings->listNode[0].someNode.deepChild.addChangeCallback([&](int val){ + resVal = val; + }); + settings->listNode[0].someNode.deepChild = 47; + QCOMPARE(resVal, 47); + resVal = -1; + + { + auto &newEntry = settings->listNode.push(); + QCOMPARE(settings->listNode.size(), 2); + QCOMPARE(newEntry.simpleChild, false); + QCOMPARE(settings->listNode[1].simpleChild.key(), QStringLiteral("tests/listNode/1/simpleChild")); + QCOMPARE(settings->listNode[1].simpleChild, false); + newEntry.simpleChild = true; + QCOMPARE(newEntry.simpleChild, true); + QCOMPARE(settings->listNode[1].simpleChild, true); + QCOMPARE(settings->listNode[0].simpleChild, false); + } + + { + auto newEntry = settings->listNode.push_deferred(); + QCOMPARE(settings->listNode.size(), 2); + QCOMPARE(newEntry.element().someNode.deepChild, 22); + QCOMPARE(settings->listNode[2].simpleChild.key(), QStringLiteral("tests/listNode/2/simpleChild")); + QCOMPARE(settings->listNode[2].someNode.deepChild, 22); + newEntry->someNode.deepChild = 44; + QCOMPARE((*newEntry).someNode.deepChild, 44); + QCOMPARE(settings->listNode[2].someNode.deepChild, 44); + QCOMPARE(settings->listNode.size(), 2); } + QCOMPARE(settings->listNode.size(), 3); + QCOMPARE(resVal, -1); //should be unchanged + + for(const auto &elem : qAsConst(settings->listNode)) + qDebug() << elem.simpleChild.get(); + for(auto &elem : settings->listNode) + elem.simpleChild = true; + + auto sizeChanged = false; + settings->listNode.addChangeCallback([&](int size) { + sizeChanged = (size == 1); + }); + + settings->listNode.pop(2); + QVERIFY(sizeChanged); + QCOMPARE(settings->listNode.size(), 1); + QCOMPARE(settings->listNode[1].simpleChild, false); + QCOMPARE(settings->listNode[2].someNode.deepChild, 22); + + settings->listNode.reset(); + QVERIFY(!settings->listNode.isSet()); + QCOMPARE(settings->listNode.size(), 0); + QCOMPARE(resVal, 22); //should be resetted } void SettingsGeneratorTest::testImportedSettings() diff --git a/tools/settingsgenerator/cppsettingsgenerator.cpp b/tools/settingsgenerator/cppsettingsgenerator.cpp index ba78080..404d6c1 100644 --- a/tools/settingsgenerator/cppsettingsgenerator.cpp +++ b/tools/settingsgenerator/cppsettingsgenerator.cpp @@ -18,6 +18,8 @@ void CppSettingsGenerator::process(const QString &inPath) settings.name = QFileInfo{inPath}.baseName(); fixTrContext(settings, QFileInfo{inPath}.fileName()); + _typeMappings = settings.typeMappings; + if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) throw FileException{_hdrFile}; writeHeader(settings); @@ -63,7 +65,7 @@ void CppSettingsGenerator::writeHeader(const SettingsType &settings) << "\tstatic " << settings.name.value() << " *instance();\n\n" << "\tQtMvvm::ISettingsAccessor *accessor() const;\n\n"; - writeNodeElementDeclarations(settings, settings.typeMappings); + writeNodeElementDeclarations(settings); _hdr << "\nprivate:\n" << "\tQtMvvm::ISettingsAccessor *_accessor;\n" @@ -71,55 +73,48 @@ void CppSettingsGenerator::writeHeader(const SettingsType &settings) << "#endif //" << incGuard << '\n'; } -void CppSettingsGenerator::writeNodeElementDeclarations(const NodeContentGroup &node, const QHash &typeMappings, int intendent) +void CppSettingsGenerator::writeNodeElementDeclarations(const NodeContentGroup &node, int intendent) { for(const auto &cNode : node.contentNodes) { if(nonstd::holds_alternative(cNode)) - writeNodeDeclaration(nonstd::get(cNode), typeMappings, intendent); + writeNodeDeclaration(nonstd::get(cNode), intendent); else if(nonstd::holds_alternative(cNode)) - writeEntryDeclaration(nonstd::get(cNode), typeMappings, intendent); - else if(nonstd::holds_alternative(cNode)) - writeListEntryDeclaration(nonstd::get(cNode), typeMappings, intendent); + writeEntryDeclaration(nonstd::get(cNode), intendent); + else if(nonstd::holds_alternative(cNode)) + writeListNodeDeclaration(nonstd::get(cNode), intendent); else if(nonstd::holds_alternative(cNode)) - writeNodeElementDeclarations(nonstd::get(cNode), typeMappings, intendent); + writeNodeElementDeclarations(nonstd::get(cNode), intendent); else Q_UNREACHABLE(); } } -void CppSettingsGenerator::writeNodeDeclaration(const NodeType &node, const QHash &typeMappings, int intendent) +void CppSettingsGenerator::writeNodeDeclaration(const NodeType &node, int intendent) { _hdr << TABS << "struct { //" << node.key << "\n"; - writeNodeElementDeclarations(node, typeMappings, intendent + 1); + writeNodeElementDeclarations(node, intendent + 1); _hdr << TABS << "} " << node.key << ";\n"; } -void CppSettingsGenerator::writeEntryDeclaration(const EntryType &entry, const QHash &typeMappings, int intendent) +void CppSettingsGenerator::writeEntryDeclaration(const EntryType &entry, int intendent) { if(entry.contentNodes.isEmpty()) - _hdr << TABS << "QtMvvm::SettingsEntry<" << typeMappings.value(entry.type, entry.type) << "> " << entry.key << ";\n"; + _hdr << TABS << "QtMvvm::SettingsEntry<" << _typeMappings.value(entry.type, entry.type) << "> " << entry.key << ";\n"; else { - const auto &mType = typeMappings.value(entry.type, entry.type); + const auto &mType = _typeMappings.value(entry.type, entry.type); _hdr << TABS << "struct : QtMvvm::SettingsEntry<" << mType << "> { //" << entry.key << "\n"; - writeNodeElementDeclarations(entry, typeMappings, intendent + 1); + writeNodeElementDeclarations(entry, intendent + 1); _hdr << TABS << "\tinline auto &operator=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator=(__value); return *this; }\n"; _hdr << TABS << "} " << entry.key << ";\n"; } } -void CppSettingsGenerator::writeListEntryDeclaration(const SettingsGeneratorBase::ListEntryType &entry, const QHash &typeMappings, int intendent) +void CppSettingsGenerator::writeListNodeDeclaration(const ListNodeType &node, int intendent) { - if(entry.contentNodes.isEmpty()) - _hdr << TABS << "QtMvvm::SettingsListEntry<" << typeMappings.value(entry.type, entry.type) << "> " << entry.key << ";\n"; - else { - const QString mType = typeMappings.value(entry.type, entry.type); - _hdr << TABS << "struct : QtMvvm::SettingsListEntry<" << mType << "> { //" << entry.key << "\n"; - writeNodeElementDeclarations(entry, typeMappings, intendent + 1); - _hdr << TABS << "\tinline auto &operator=(const QList<" << mType << "> &__value) { SettingsListEntry<" << mType << ">::operator=(__value); return *this; }\n"; - _hdr << TABS << "\tinline auto &operator+=(const QList<" << mType << "> &__value) { SettingsListEntry<" << mType << ">::operator+=(__value); return *this; }\n"; - _hdr << TABS << "\tinline auto &operator+=(const " << mType << " &__value) { SettingsListEntry<" << mType << ">::operator+=(__value); return *this; }\n"; - _hdr << TABS << "} " << entry.key << ";\n"; - } + _hdr << TABS << "struct " << node.key << "_element {\n"; + writeNodeElementDeclarations(node, intendent + 1); + _hdr << TABS << "};\n"; + _hdr << TABS << "QtMvvm::SettingsListNode<" << node.key << "_element> " << node.key << ";\n"; } void CppSettingsGenerator::writeSource(const SettingsType &settings) @@ -188,7 +183,7 @@ void CppSettingsGenerator::writeSource(const SettingsType &settings) << "\tQObject{parent},\n" << "\t_accessor{accessor}\n" << "{\n"; - writeNodeElementDefinitions(settings, settings.typeMappings, settings.baseKey); + writeNodeElementDefinitions(settings, settings.baseKey ? QStringList{settings.baseKey.value()} : QStringList{}); _src << "}\n\n"; _src << settings.name.value() << " *" << settings.name.value() << "::instance()\n" @@ -202,50 +197,62 @@ void CppSettingsGenerator::writeSource(const SettingsType &settings) << "}\n\n"; } -void CppSettingsGenerator::writeNodeElementDefinitions(const SettingsGeneratorBase::NodeContentGroup &node, const QHash &typeMappings, const optional &baseKey, const QStringList &keyChain) +void CppSettingsGenerator::writeNodeElementDefinitions(const SettingsGeneratorBase::NodeContentGroup &node, const QStringList &keyChain, const QStringList &entryChain, int intendent, const QStringList &listTypeChain) { for(const auto &cNode : node.contentNodes) { if(nonstd::holds_alternative(cNode)) { const auto &xNode = nonstd::get(cNode); - writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key); + writeNodeElementDefinitions(xNode, QStringList{keyChain} << xNode.key, QStringList{entryChain} << xNode.key, intendent, listTypeChain); } else if(nonstd::holds_alternative(cNode)) - writeEntryDefinition(nonstd::get(cNode), typeMappings, baseKey, keyChain); - else if(nonstd::holds_alternative(cNode)) - writeListEntryDefinition(nonstd::get(cNode), typeMappings, baseKey, keyChain); + writeEntryDefinition(nonstd::get(cNode), keyChain, entryChain, intendent, listTypeChain); + else if(nonstd::holds_alternative(cNode)) + writeListNodeDefinition(nonstd::get(cNode), keyChain, entryChain, intendent, listTypeChain); else if(nonstd::holds_alternative(cNode)) - writeNodeElementDefinitions(nonstd::get(cNode), typeMappings, baseKey, keyChain); + writeNodeElementDefinitions(nonstd::get(cNode), keyChain, entryChain, intendent, listTypeChain); else Q_UNREACHABLE(); } } -void CppSettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain, bool skipChildren) +void CppSettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, QStringList keyChain, QStringList entryChain, int intendent, const QStringList &listTypeChain) { + entryChain.append(entry.key); keyChain.append(entry.key); - _src << "\t" << keyChain.join(QLatin1Char('.')) - << ".setup(QStringLiteral(\"" << (baseKey ? QStringList{baseKey.value()} + keyChain : keyChain).join(QLatin1Char('/')) << "\"), _accessor"; + _src << TABS << entryChain.join(QLatin1Char('.')) + << ".setup(" << concatKeys(keyChain, intendent) << ", _accessor"; if(entry.code) - _src << ", QVariant::fromValue<" << typeMappings.value(entry.type, entry.type) << ">(" << entry.code.value().trimmed() << ")"; + _src << ", QVariant::fromValue<" << _typeMappings.value(entry.type, entry.type) << ">(" << entry.code.value().trimmed() << ")"; else if(entry.defaultValue) { _src << ", QVariant{"; if(entry.tr) _src << "QCoreApplication::translate(\"" << entry.trContext.value() << "\", \"" << entry.defaultValue.value() << "\")"; else _src << "QStringLiteral(\"" << entry.defaultValue.value() << "\")"; - _src << "}.value<" << typeMappings.value(entry.type, entry.type) << ">()"; + _src << "}.value<" << _typeMappings.value(entry.type, entry.type) << ">()"; } _src << ");\n"; - if(!skipChildren) - writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain); + writeNodeElementDefinitions(entry, keyChain, entryChain, intendent, listTypeChain); } -void CppSettingsGenerator::writeListEntryDefinition(const SettingsGeneratorBase::ListEntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain) +void CppSettingsGenerator::writeListNodeDefinition(const ListNodeType &node, QStringList keyChain, QStringList entryChain, int intendent, QStringList listTypeChain) { - writeEntryDefinition(entry, typeMappings, baseKey, keyChain, entry.init.has_value()); - if(entry.init) { - keyChain.append(entry.key); - _src << "\t" << keyChain.join(QLatin1Char('.')) << ".setupInit(" << entry.init.value().trimmed() << ");\n"; - writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain); - } + keyChain.append(node.key); + entryChain.append(node.key); + listTypeChain.append(node.key + QStringLiteral("_element")); + _src << TABS << entryChain.join(QLatin1Char('.')) + << ".setup(" << concatKeys(keyChain, intendent) << ", _accessor, [=](int __index_" << intendent << ", " << listTypeChain.join(QStringLiteral("::")) << " &__entry) {\n"; + + keyChain.append(QLatin1Char('%') + QString::number(intendent)); + entryChain = QStringList{QStringLiteral("__entry")}; + writeNodeElementDefinitions(node, keyChain, entryChain, intendent + 1, listTypeChain); + _src << TABS << "});\n"; +} + +QString CppSettingsGenerator::concatKeys(const QStringList &keyChain, int intendet) const +{ + QString res = QStringLiteral("QStringLiteral(\"") + keyChain.join(QLatin1Char('/')) + QStringLiteral("\")"); + for(auto i = 1; i < intendet; i++) + res.append(QStringLiteral(".arg(__index_%1)").arg(i)); + return res; } diff --git a/tools/settingsgenerator/cppsettingsgenerator.h b/tools/settingsgenerator/cppsettingsgenerator.h index 9e39e8b..fb3c3ba 100644 --- a/tools/settingsgenerator/cppsettingsgenerator.h +++ b/tools/settingsgenerator/cppsettingsgenerator.h @@ -18,16 +18,24 @@ private: QTextStream _hdr; QTextStream _src; + QHash _typeMappings; + void writeHeader(const SettingsType &settings); - void writeNodeElementDeclarations(const NodeContentGroup &node, const QHash &typeMappings, int intendent = 1); - void writeNodeDeclaration(const NodeType &node, const QHash &typeMappings, int intendent = 1); - void writeEntryDeclaration(const EntryType &entry, const QHash &typeMappings, int intendent = 1); - void writeListEntryDeclaration(const ListEntryType &entry, const QHash &typeMappings, int intendent = 1); + void writeNodeElementDeclarations(const NodeContentGroup &node, int intendent = 1); + void writeNodeDeclaration(const NodeType &node, int intendent = 1); + void writeEntryDeclaration(const EntryType &entry, int intendent = 1); + void writeListNodeDeclaration(const ListNodeType &node, int intendent = 1); void writeSource(const SettingsType &settings); - void writeNodeElementDefinitions(const NodeContentGroup &node, const QHash &typeMappings, const optional &baseKey, const QStringList &keyChain = {}); - void writeEntryDefinition(const EntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain, bool skipChildren = false); - void writeListEntryDefinition(const ListEntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain); + void writeNodeElementDefinitions(const NodeContentGroup &node, + const QStringList &keyChain, + const QStringList &entryChain = {}, + int intendent = 1, + const QStringList &listTypeChain = {}); + void writeEntryDefinition(const EntryType &entry, QStringList keyChain, QStringList entryChain, int intendent, const QStringList &listTypeChain); + void writeListNodeDefinition(const ListNodeType &node, QStringList keyChain, QStringList entryChain, int intendent, QStringList listTypeChain); + + QString concatKeys(const QStringList &keyChain, int intendet) const; }; #endif // CPPSETTINGSGENERATOR_H diff --git a/tools/settingsgenerator/qsettingsgenerator.xsd b/tools/settingsgenerator/qsettingsgenerator.xsd index 5ba393d..b8be4cc 100644 --- a/tools/settingsgenerator/qsettingsgenerator.xsd +++ b/tools/settingsgenerator/qsettingsgenerator.xsd @@ -88,6 +88,7 @@ + @@ -98,6 +99,14 @@ + + + + + + + +