Browse Source

modified cpp settings gen part for list entries

pull/2/head
Skycoder42 7 years ago
parent
commit
19b36bcece
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 394
      src/mvvmcore/settingsentry.h
  2. 30
      tests/auto/mvvmcore/settingsgenerator/generatortest.xml
  3. 2
      tests/auto/mvvmcore/settingsgenerator/test_de.ts
  4. 4
      tests/auto/mvvmcore/settingsgenerator/testbackend.cpp
  5. 115
      tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp
  6. 97
      tools/settingsgenerator/cppsettingsgenerator.cpp
  7. 22
      tools/settingsgenerator/cppsettingsgenerator.h
  8. 9
      tools/settingsgenerator/qsettingsgenerator.xsd

394
src/mvvmcore/settingsentry.h

@ -1,8 +1,12 @@
#ifndef QTMVVM_SETTINGSENTRY_H
#define QTMVVM_SETTINGSENTRY_H
#include <functional>
#include <QtCore/qlist.h>
#include <QtCore/qregularexpression.h>
#include <QtCore/qhash.h>
#include <QtCore/qsharedpointer.h>
#include "QtMvvmCore/qtmvvmcore_global.h"
#include "QtMvvmCore/isettingsaccessor.h"
@ -52,71 +56,40 @@ public:
};
template <typename TType>
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<TType>;
inline ListElement(SettingsListEntry<TType> *self, int index) : _self{self}, _index{index} {}
SettingsListEntry<TType> *_self;
int _index;
};
template <typename T>
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 <typename T>
friend class SettingsListEntry<TType>::iterator_base;
friend class SettingsListNode<TType>;
inline iterator_value(SettingsListEntry<TType> *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;
SettingsListEntry<TType> *_self;
SettingsListNode<TType> *_node;
TType &_element;
bool _commited = false;
int _index;
inline Deferred(SettingsListNode<TType> *node, TType &element, int index) :
_node{node},
_element{element},
_index{index}
{}
};
template <typename T>
@ -129,73 +102,67 @@ public:
using pointer = value_type*;
using reference = value_type&;
inline iterator_base() = default;
inline iterator_base(const iterator_base<T> &other) = default;
inline iterator_base &operator=(const iterator_base<T> &other) = default;
inline iterator_base(iterator_base<T> &&other) noexcept = default;
inline iterator_base &operator=(iterator_base<T> &&other) noexcept = default;
inline iterator_base<T> &operator++() { ++_value._index; return *this; }
inline iterator_base<T> operator++(int) { return iterator_base<T>{_value._self, _value._index++}; }
inline iterator_base<T> &operator--() { --_value._index; return *this; }
inline iterator_base<T> operator--(int) { return iterator_base<T>{_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<T> &lhs, iterator_base<T> &rhs) { swap(lhs._value, rhs._value); }
inline friend bool operator==(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { return lhs._value == rhs._value; }
inline friend bool operator!=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { return lhs._value != rhs._value; }
inline friend bool operator<(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { return lhs._value < rhs._value; }
inline friend bool operator>(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { return lhs._value > rhs._value; }
inline friend bool operator<=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { return lhs._value <= rhs._value; }
inline friend bool operator>=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { return lhs._value >= rhs._value; }
inline iterator_base<T> &operator+=(difference_type delta) { _value._index += delta; return *this; }
inline friend iterator_base<T> operator+(const iterator_base<T> &iter, difference_type delta) { return iterator_base<T>{iter._value + delta}; }
inline friend iterator_base<T> operator+(difference_type delta, const iterator_base<T> &iter) { return iterator_base<T>{iter._value + delta}; }
inline iterator_base<T> &operator-=(difference_type delta) { _value._index -= delta; return *this; }
inline friend iterator_base<T> operator-(const iterator_base<T> &iter, difference_type delta) { return iterator_base<T>{iter._value - delta}; }
inline friend difference_type operator-(const iterator_base<T> &lhs, const iterator_base<T> &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<T> &operator++() { ++_index; return *this; }
inline iterator_base<T> operator++(int) { return iterator_base<T>{_node, _index++}; }
inline iterator_base<T> &operator--() { --_index; return *this; }
inline iterator_base<T> operator--(int) { return iterator_base<T>{_node, _index--}; }
inline reference operator*() const { return _node->at(_index); }
inline pointer operator->() const { return &_node->at(_index); }
inline friend void swap(iterator_base<T> &lhs, iterator_base<T> &rhs) noexcept { std::swap(lhs._node, rhs._node); std::swap(lhs._index, rhs._index); }
inline friend bool operator==(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index == rhs._index; }
inline friend bool operator!=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index != rhs._index; }
inline friend bool operator<(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index < rhs._index; }
inline friend bool operator>(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index > rhs._index; }
inline friend bool operator<=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index <= rhs._index; }
inline friend bool operator>=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index >= rhs._index; }
inline iterator_base<T> &operator+=(difference_type delta) { _index += delta; return *this; }
inline friend iterator_base<T> operator+(const iterator_base<T> &iter, difference_type delta) { return iterator_base<T>{iter._node, iter._index + delta}; }
inline friend iterator_base<T> operator+(difference_type delta, const iterator_base<T> &iter) { return iterator_base<T>{iter._node, iter._index + delta}; }
inline iterator_base<T> &operator-=(difference_type delta) { _index -= delta; return *this; }
inline friend iterator_base<T> operator-(const iterator_base<T> &iter, difference_type delta) { return iterator_base<T>{iter._node, iter._index - delta}; }
inline friend difference_type operator-(const iterator_base<T> &lhs, const iterator_base<T> &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<TType>;
friend class SettingsListNode<TType>;
inline iterator_base(SettingsListEntry<TType> *self, int index) : _value{self, index} {}
inline iterator_base(iterator_value value) : _value{std::move(value)} {}
iterator_value _value;
SettingsListNode<TType> *_node;
int _index;
inline iterator_base(SettingsListNode<TType> *node, int index) :
_node{node},
_index{index}
{}
};
using iterator = iterator_base<iterator_value>;
using const_iterator = iterator_base<const iterator_value>;
using iterator = iterator_base<TType>;
using const_iterator = iterator_base<const TType>;
SettingsListEntry() = default;
SettingsListNode() = default;
bool isSet() const;
QString key() const;
int size() const;
const TType &at(int index) const;
TType &at(int index);
QList<TType> get() const;
void set(const QList<TType> &value);
void reset(bool reInit = true);
SettingsListEntry<TType> &operator=(const QList<TType> &value);
operator QList<TType>() 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<TType> &values);
TType pop();
void chop(int count);
ListElement operator[](int index);
const ListElement operator[](int index) const;
SettingsListEntry<TType> &operator+=(const TType &value);
SettingsListEntry<TType> &operator+=(const QList<TType> &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<void(QList<TType>)> &callback);
void addChangeCallback(QObject *scope, const std::function<void(QList<TType>)> &callback);
void addChangeCallback(const std::function<void(int, TType)> &callback); // index, value
void addChangeCallback(QObject *scope, const std::function<void(int, TType)> &callback);
void addSizeChangeCallback(const std::function<void(int)> &callback); // size
void addSizeChangeCallback(QObject *scope, const std::function<void(int)> &callback);
void addChangeCallback(const std::function<void(int)> &callback); // size
void addChangeCallback(QObject *scope, const std::function<void(int)> &callback);
// internal
void setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue = {});
void setupInit(QList<TType> init);
void setup(QString key, ISettingsAccessor *accessor, std::function<void(int, TType&)> setupFn);
private:
struct ElementHolder {
bool __initialized = false;
QSharedPointer<TType> _element;
inline ElementHolder() : _element{new TType{}} {}
};
QString _key;
QString _sizeKey;
ISettingsAccessor *_accessor = nullptr;
QVariant _default;
QList<TType> _init;
std::function<void(int, TType&)> _setupFn;
mutable QHash<int, ElementHolder> _cache;
void commit(int index);
};
// ------------- Generic Implementation -------------
@ -308,259 +279,164 @@ void SettingsEntry<T>::setup(QString key, ISettingsAccessor *accessor, QVariant
_default = std::move(defaultValue);
}
// ------------- Generic Implementation ListEntry -------------
// ------------- Generic Implementation ListNode -------------
template<typename TType>
bool SettingsListEntry<TType>::isSet() const
bool SettingsListNode<TType>::isSet() const
{
return _accessor->contains(_key + QStringLiteral("/size"));
return _accessor->contains(_sizeKey);
}
template<typename TType>
QString SettingsListEntry<TType>::key() const
QString SettingsListNode<TType>::key() const
{
return _key;
}
template<typename TType>
QList<TType> SettingsListEntry<TType>::get() const
int SettingsListNode<TType>::size() const
{
auto mSize = size();
QList<TType> resList;
resList.reserve(mSize);
for(auto i = 0; i < mSize; ++i)
resList.append(getAt(i));
return resList;
return _accessor->load(_sizeKey, 0).toInt();
}
template<typename TType>
void SettingsListEntry<TType>::set(const QList<TType> &value)
const TType &SettingsListNode<TType>::at(int index) const
{
reset(false);
push(value);
auto &value = _cache[index];
if(!value.__initialized) {
_setupFn(index, *(value._element));
value.__initialized = true;
}
template<typename TType>
void SettingsListEntry<TType>::reset(bool reInit)
{
_accessor->remove(_key);
if(reInit && !_init.isEmpty())
push(_init);
return *(value._element);
}
template<typename TType>
SettingsListEntry<TType> &SettingsListEntry<TType>::operator=(const QList<TType> &value)
TType &SettingsListNode<TType>::at(int index)
{
set(value);
return *this;
auto &value = _cache[index];
if(!value.__initialized) {
_setupFn(index, *(value._element));
value.__initialized = true;
}
template<typename TType>
SettingsListEntry<TType>::operator QList<TType>() const
{
return get();
return *(value._element);
}
template<typename TType>
int SettingsListEntry<TType>::size() const
{
return _accessor->load(_key + QStringLiteral("/size"), 0).toInt();
}
template<typename TType>
TType SettingsListEntry<TType>::getAt(int index) const
{
return _accessor->load(_key + QStringLiteral("/%1/value").arg(index), _default).template value<TType>();
}
template<typename TType>
void SettingsListEntry<TType>::setAt(int index, const TType &value)
{
_accessor->save(_key + QStringLiteral("/%1/value").arg(index), QVariant::fromValue(value));
}
template<typename TType>
void SettingsListEntry<TType>::push(const TType &value)
{
push(QList<TType>{value});
}
template<typename TType>
void SettingsListEntry<TType>::push(const QList<TType> &values)
TType &SettingsListNode<TType>::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<typename TType>
TType QtMvvm::SettingsListEntry<TType>::pop()
typename SettingsListNode<TType>::Deferred SettingsListNode<TType>::push_deferred()
{
auto res = getAt(size() - 1);
chop(1);
return res;
auto cIndex = size();
return {this, at(cIndex), cIndex};
}
template<typename TType>
void QtMvvm::SettingsListEntry<TType>::chop(int count)
void SettingsListNode<TType>::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<typename TType>
const typename SettingsListEntry<TType>::ListElement SettingsListEntry<TType>::operator[](int index) const
void SettingsListNode<TType>::reset()
{
return ListElement{this, index};
_accessor->remove(_key);
}
template<typename TType>
typename SettingsListEntry<TType>::ListElement SettingsListEntry<TType>::operator[](int index)
const TType &SettingsListNode<TType>::operator[](int index) const
{
return ListElement{this, index};
return at(index);
}
template<typename TType>
SettingsListEntry<TType> &SettingsListEntry<TType>::operator+=(const TType &value)
{
push(value);
return *this;
}
template<typename TType>
SettingsListEntry<TType> &SettingsListEntry<TType>::operator+=(const QList<TType> &values)
TType &SettingsListNode<TType>::operator[](int index)
{
push(values);
return *this;
return at(index);
}
template<typename TType>
typename SettingsListEntry<TType>::iterator SettingsListEntry<TType>::begin()
typename SettingsListNode<TType>::iterator SettingsListNode<TType>::begin()
{
return iterator{this, 0};
}
template<typename TType>
typename SettingsListEntry<TType>::iterator QtMvvm::SettingsListEntry<TType>::end()
typename SettingsListNode<TType>::iterator SettingsListNode<TType>::end()
{
return iterator{this, size()};
}
template<typename TType>
typename SettingsListEntry<TType>::const_iterator SettingsListEntry<TType>::begin() const
typename SettingsListNode<TType>::const_iterator SettingsListNode<TType>::begin() const
{
return constBegin();
}
template<typename TType>
typename SettingsListEntry<TType>::const_iterator SettingsListEntry<TType>::end() const
typename SettingsListNode<TType>::const_iterator SettingsListNode<TType>::end() const
{
return constEnd();
}
template<typename TType>
typename SettingsListEntry<TType>::const_iterator SettingsListEntry<TType>::constBegin() const
{
return const_iterator{const_cast<SettingsListEntry<TType>*>(this), 0};
}
template<typename TType>
typename SettingsListEntry<TType>::const_iterator SettingsListEntry<TType>::constEnd() const
{
return const_iterator{const_cast<SettingsListEntry<TType>*>(this), size()};
}
template<typename TType>
void SettingsListEntry<TType>::addChangeCallback(const std::function<void (QList<TType>)> &callback)
typename SettingsListNode<TType>::const_iterator SettingsListNode<TType>::constBegin() const
{
addChangeCallback(_accessor, callback);
return const_iterator{const_cast<SettingsListNode<TType>*>(this), 0};
}
template<typename TType>
void SettingsListEntry<TType>::addChangeCallback(QObject *scope, const std::function<void (QList<TType>)> &callback)
typename SettingsListNode<TType>::const_iterator SettingsListNode<TType>::constEnd() const
{
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());
});
return const_iterator{const_cast<SettingsListNode<TType>*>(this), size()};
}
template<typename TType>
void SettingsListEntry<TType>::addChangeCallback(const std::function<void (int, TType)> &callback)
void SettingsListNode<TType>::addChangeCallback(const std::function<void (int)> &callback)
{
addChangeCallback(_accessor, callback);
}
template<typename TType>
void SettingsListEntry<TType>::addChangeCallback(QObject *scope, const std::function<void (int, TType)> &callback)
void SettingsListNode<TType>::addChangeCallback(QObject *scope, const std::function<void (int)> &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<TType>());
});
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<TType>());
});
}
template<typename TType>
void SettingsListEntry<TType>::addSizeChangeCallback(const std::function<void (int)> &callback)
{
addSizeChangeCallback(_accessor, callback);
}
template<typename TType>
void SettingsListEntry<TType>::addSizeChangeCallback(QObject *scope, const std::function<void (int)> &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<typename TType>
void SettingsListEntry<TType>::setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue)
void SettingsListNode<TType>::setup(QString key, ISettingsAccessor *accessor, std::function<void(int, TType&)> 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<typename TType>
void QtMvvm::SettingsListEntry<TType>::setupInit(QList<TType> init)
void SettingsListNode<TType>::commit(int index)
{
_init = std::move(init);
if(!isSet())
push(_init);
_accessor->save(_sizeKey, qMax(size(), index + 1));
}
}

30
tests/auto/mvvmcore/settingsgenerator/generatortest.xml

@ -62,15 +62,25 @@
<Code>{42}</Code>
</Entry>
<ListEntry key="listEntry"
type="QByteArray">
<Entry key="dummyChild"
<ListNode key="listNode">
<Entry key="simpleChild"
type="bool"/>
<Code>&quot;Hello World&quot;</Code>
<Init> {
&quot;test1&quot;,
&quot;test2&quot;,
&quot;test3&quot;
} </Init>
</ListEntry>
<Node key="someNode">
<Entry key="deepChild"
type="int"
default="22"/>
<Entry key="deepParent"
type="QString"
default="___">
<Entry key="simpleChild"
type="bool"
default="true"/>
</Entry>
</Node>
<ListNode key="childList">
<Entry key="valueEntry"
type="double"
default="4.2"/>
</ListNode>
</ListNode>
</Settings>

2
tests/auto/mvvmcore/settingsgenerator/test_de.ts

@ -4,7 +4,7 @@
<context>
<name>SettingsGeneratorTest</name>
<message>
<location filename="tst_settingsgenerator.cpp" line="+140"/>
<location filename="tst_settingsgenerator.cpp" line="+171"/>
<source>somet translated text...</source>
<translation type="unfinished"></translation>
</message>

4
tests/auto/mvvmcore/settingsgenerator/testbackend.cpp

@ -1,4 +1,5 @@
#include "testbackend.h"
#include <QDebug>
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;
}

115
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<int>{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<QByteArray>(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<QByteArray>(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()

97
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<QString, QString> &typeMappings, int intendent)
void CppSettingsGenerator::writeNodeElementDeclarations(const NodeContentGroup &node, int intendent)
{
for(const auto &cNode : node.contentNodes) {
if(nonstd::holds_alternative<NodeType>(cNode))
writeNodeDeclaration(nonstd::get<NodeType>(cNode), typeMappings, intendent);
writeNodeDeclaration(nonstd::get<NodeType>(cNode), intendent);
else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDeclaration(nonstd::get<EntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDeclaration(nonstd::get<ListEntryType>(cNode), typeMappings, intendent);
writeEntryDeclaration(nonstd::get<EntryType>(cNode), intendent);
else if(nonstd::holds_alternative<ListNodeType>(cNode))
writeListNodeDeclaration(nonstd::get<ListNodeType>(cNode), intendent);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDeclarations(nonstd::get<NodeContentGroup>(cNode), typeMappings, intendent);
writeNodeElementDeclarations(nonstd::get<NodeContentGroup>(cNode), intendent);
else
Q_UNREACHABLE();
}
}
void CppSettingsGenerator::writeNodeDeclaration(const NodeType &node, const QHash<QString, QString> &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<QString, QString> &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<QString, QString> &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<QString, QString> &typeMappings, const optional<QString> &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<NodeType>(cNode)) {
const auto &xNode = nonstd::get<NodeType>(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<EntryType>(cNode))
writeEntryDefinition(nonstd::get<EntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDefinition(nonstd::get<ListEntryType>(cNode), typeMappings, baseKey, keyChain);
writeEntryDefinition(nonstd::get<EntryType>(cNode), keyChain, entryChain, intendent, listTypeChain);
else if(nonstd::holds_alternative<ListNodeType>(cNode))
writeListNodeDefinition(nonstd::get<ListNodeType>(cNode), keyChain, entryChain, intendent, listTypeChain);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDefinitions(nonstd::get<NodeContentGroup>(cNode), typeMappings, baseKey, keyChain);
writeNodeElementDefinitions(nonstd::get<NodeContentGroup>(cNode), keyChain, entryChain, intendent, listTypeChain);
else
Q_UNREACHABLE();
}
}
void CppSettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &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<QString, QString> &typeMappings, const optional<QString> &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;
}

22
tools/settingsgenerator/cppsettingsgenerator.h

@ -18,16 +18,24 @@ private:
QTextStream _hdr;
QTextStream _src;
QHash<QString, QString> _typeMappings;
void writeHeader(const SettingsType &settings);
void writeNodeElementDeclarations(const NodeContentGroup &node, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeNodeDeclaration(const NodeType &node, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeEntryDeclaration(const EntryType &entry, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeListEntryDeclaration(const ListEntryType &entry, const QHash<QString, QString> &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<QString, QString> &typeMappings, const optional<QString> &baseKey, const QStringList &keyChain = {});
void writeEntryDefinition(const EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain, bool skipChildren = false);
void writeListEntryDefinition(const ListEntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &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

9
tools/settingsgenerator/qsettingsgenerator.xsd

@ -88,6 +88,7 @@
<xs:element name="Node" type="NodeType"/>
<xs:element name="Entry" type="EntryType"/>
<xs:element name="ListEntry" type="ListEntryType"/>
<xs:element name="ListNode" type="ListNodeType"/>
<xs:element name="Import" type="ImportType" qxg:method="read_included_file"/>
</xs:choice>
</xs:sequence>
@ -98,6 +99,14 @@
<xs:attribute name="key" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="ListNodeType" qxg:declare="true">
<xs:complexContent>
<xs:extension base="NodeType">
<xs:attribute name="listEntry" type="xs:boolean" default="false" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="EntryType" qxg:declare="true">
<xs:complexContent>
<xs:extension base="NodeType">

Loading…
Cancel
Save