Browse Source

added support for list entries

pull/2/head
Skycoder42 7 years ago
parent
commit
d2f90cc3c4
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 3
      src/mvvmcore/mvvmcore.pro
  2. 31
      src/mvvmcore/settingsentry.cpp
  3. 423
      src/mvvmcore/settingsentry.h
  4. 2
      src/mvvmdatasynccore/datasyncsettingsentry.cpp
  5. 17
      tests/auto/mvvmcore/settingsgenerator/generatortest.xml
  6. 2
      tests/auto/mvvmcore/settingsgenerator/test_de.ts
  7. 7
      tests/auto/mvvmcore/settingsgenerator/testbackend.cpp
  8. 51
      tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp
  9. 19
      tools/settingsgenerator/qsettingsgenerator.xsd
  10. 45
      tools/settingsgenerator/settingsgenerator.cpp
  11. 4
      tools/settingsgenerator/settingsgenerator.h

3
src/mvvmcore/mvvmcore.pro

@ -38,7 +38,8 @@ SOURCES += \
settingssetuploader.cpp \ settingssetuploader.cpp \
settingsviewmodel.cpp \ settingsviewmodel.cpp \
isettingsaccessor.cpp \ isettingsaccessor.cpp \
qsettingsaccessor.cpp qsettingsaccessor.cpp \
settingsentry.cpp
TRANSLATIONS += \ TRANSLATIONS += \
translations/qtmvvmcore_de.ts \ translations/qtmvvmcore_de.ts \

31
src/mvvmcore/settingsentry.cpp

@ -0,0 +1,31 @@
#include "settingsentry.h"
using namespace QtMvvm;
template<>
void QtMvvm::SettingsEntry<QVariant>::set(const QVariant &value)
{
_accessor->save(_key, value);
}
template<>
QVariant QtMvvm::SettingsEntry<QVariant>::get() const
{
return _accessor->load(_key, _default);
}
template<>
void QtMvvm::SettingsEntry<QVariant>::addChangeCallback(QObject *scope, const std::function<void (QVariant)> &callback)
{
auto mKey = _key;
auto mDefault = _default;
QObject::connect(_accessor, &ISettingsAccessor::entryChanged,
scope, [mKey, callback](const QString &key, const QVariant &value) {
if(key == mKey)
callback(value);
});
QObject::connect(_accessor, &ISettingsAccessor::entryRemoved,
scope, [mKey, mDefault, callback](const QString &key) {
if(key == mKey)
callback(mDefault);
});
}

423
src/mvvmcore/settingsentry.h

@ -1,6 +1,10 @@
#ifndef QTMVVM_SETTINGSENTRY_H #ifndef QTMVVM_SETTINGSENTRY_H
#define QTMVVM_SETTINGSENTRY_H #define QTMVVM_SETTINGSENTRY_H
#include <QtCore/qlist.h>
#include <QtCore/qregularexpression.h>
#include "QtMvvmCore/qtmvvmcore_global.h"
#include "QtMvvmCore/isettingsaccessor.h" #include "QtMvvmCore/isettingsaccessor.h"
namespace QtMvvm { namespace QtMvvm {
@ -35,6 +39,175 @@ private:
QVariant _default; QVariant _default;
}; };
template <typename TType>
class SettingsEntry<QList<TType>>
{
Q_DISABLE_COPY(SettingsEntry)
public:
class ListElement
{
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 SettingsEntry<QList<TType>>;
inline ListElement(SettingsEntry<QList<TType>> *self, int index) : _self{self}, _index{index} {}
SettingsEntry<QList<TType>> *_self;
int _index;
};
template <typename T>
class iterator_base;
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 friend void swap(iterator_value& lhs, iterator_value& rhs) { qSwap(lhs._self, rhs._self); qSwap(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 friend bool operator>=(const iterator_value &lhs, const iterator_value &rhs) { assert(lhs._self == rhs._self); return lhs._index >= rhs._index; }
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; }
private:
template <typename T>
friend class SettingsEntry<QList<TType>>::iterator_base;
inline iterator_value(SettingsEntry<QList<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;
SettingsEntry<QList<TType>> *_self;
int _index;
};
template <typename T>
class iterator_base
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = int;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
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}; }
private:
friend class SettingsEntry<QList<TType>>;
inline iterator_base(SettingsEntry<QList<TType>> *self, int index) : _value{self, index} {}
inline iterator_base(iterator_value value) : _value{std::move(value)} {}
iterator_value _value;
};
using iterator = iterator_base<iterator_value>;
using const_iterator = iterator_base<const iterator_value>;
SettingsEntry() = default;
bool isSet() const;
QString key() const;
QList<TType> get() const;
void set(const QList<TType> &value);
void reset(bool reInit = true);
SettingsEntry<QList<TType>> &operator=(const QList<TType> &value);
operator QList<TType>() const;
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;
SettingsEntry<QList<TType>> &operator+=(const TType &value);
SettingsEntry<QList<TType>> &operator+=(const QList<TType> &values);
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator constBegin() const;
const_iterator constEnd() const;
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);
// internal
void setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue = {});
void setupInit(QList<TType> init);
private:
QString _key;
ISettingsAccessor *_accessor = nullptr;
QVariant _default;
QList<TType> _init;
};
template <> template <>
class SettingsEntry<void> class SettingsEntry<void>
{ {
@ -47,7 +220,6 @@ public:
inline void setup(const QString &, ISettingsAccessor *, const QVariant & = {}) {} inline void setup(const QString &, ISettingsAccessor *, const QVariant & = {}) {}
}; };
// ------------- Generic Implementation ------------- // ------------- Generic Implementation -------------
template<typename T> template<typename T>
@ -68,12 +240,18 @@ T SettingsEntry<T>::get() const
return _accessor->load(_key, _default).template value<T>(); return _accessor->load(_key, _default).template value<T>();
} }
template<>
Q_MVVMCORE_EXPORT QVariant SettingsEntry<QVariant>::get() const;
template<typename T> template<typename T>
void SettingsEntry<T>::set(const T &value) void SettingsEntry<T>::set(const T &value)
{ {
_accessor->save(_key, QVariant::fromValue(value)); _accessor->save(_key, QVariant::fromValue(value));
} }
template<>
Q_MVVMCORE_EXPORT void SettingsEntry<QVariant>::set(const QVariant &value);
template<typename T> template<typename T>
void SettingsEntry<T>::reset() void SettingsEntry<T>::reset()
{ {
@ -87,6 +265,12 @@ SettingsEntry<T> &SettingsEntry<T>::operator=(const T &value)
return (*this); return (*this);
} }
template<typename T>
SettingsEntry<T>::operator T() const
{
return get();
}
template<typename T> template<typename T>
void SettingsEntry<T>::addChangeCallback(const std::function<void (T)> &callback) void SettingsEntry<T>::addChangeCallback(const std::function<void (T)> &callback)
{ {
@ -110,14 +294,237 @@ void SettingsEntry<T>::addChangeCallback(QObject *scope, const std::function<voi
}); });
} }
template<>
Q_MVVMCORE_EXPORT void SettingsEntry<QVariant>::addChangeCallback(QObject *scope, const std::function<void (QVariant)> &callback);
template<typename T> template<typename T>
SettingsEntry<T>::operator T() const void SettingsEntry<T>::setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue)
{
Q_ASSERT_X(accessor, Q_FUNC_INFO, "You must set a valid accessor before initializing the settings!");
_key = std::move(key);
_accessor = accessor;
_default = std::move(defaultValue);
}
// ------------- Generic Implementation ListEntry -------------
template<typename TType>
bool SettingsEntry<QList<TType>>::isSet() const
{
return _accessor->contains(_key + QStringLiteral("/size"));
}
template<typename TType>
QString SettingsEntry<QList<TType>>::key() const
{
return _key;
}
template<typename TType>
QList<TType> SettingsEntry<QList<TType>>::get() const
{
auto mSize = size();
QList<TType> resList;
resList.reserve(mSize);
for(auto i = 0; i < mSize; ++i)
resList.append(getAt(i));
return resList;
}
template<typename TType>
void SettingsEntry<QList<TType>>::set(const QList<TType> &value)
{
reset(false);
push(value);
}
template<typename TType>
void SettingsEntry<QList<TType>>::reset(bool reInit)
{
_accessor->remove(_key);
if(reInit && !_init.isEmpty())
push(_init);
}
template<typename TType>
SettingsEntry<QList<TType>> &SettingsEntry<QList<TType>>::operator=(const QList<TType> &value)
{
set(value);
return *this;
}
template<typename TType>
SettingsEntry<QList<TType>>::operator QList<TType>() const
{ {
return get(); return get();
} }
template<typename T> template<typename TType>
void SettingsEntry<T>::setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue) int SettingsEntry<QList<TType>>::size() const
{
return _accessor->load(_key + QStringLiteral("/size"), 0).toInt();
}
template<typename TType>
TType SettingsEntry<QList<TType>>::getAt(int index) const
{
return _accessor->load(_key + QStringLiteral("/%1/value").arg(index), _default).template value<TType>();
}
template<typename TType>
void SettingsEntry<QList<TType>>::setAt(int index, const TType &value)
{
_accessor->save(_key + QStringLiteral("/%1/value").arg(index), QVariant::fromValue(value));
}
template<typename TType>
void SettingsEntry<QList<TType>>::push(const TType &value)
{
push(QList<TType>{value});
}
template<typename TType>
void SettingsEntry<QList<TType>>::push(const QList<TType> &values)
{
auto cIndex = size();
for(const auto &value : values)
setAt(cIndex++, value);
_accessor->save(_key + QStringLiteral("/size"), cIndex);
}
template<typename TType>
TType QtMvvm::SettingsEntry<QList<TType>>::pop()
{
auto res = getAt(size() - 1);
chop(1);
return res;
}
template<typename TType>
void QtMvvm::SettingsEntry<QList<TType>>::chop(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);
}
template<typename TType>
const typename SettingsEntry<QList<TType>>::ListElement SettingsEntry<QList<TType>>::operator[](int index) const
{
return ListElement{this, index};
}
template<typename TType>
typename SettingsEntry<QList<TType>>::ListElement SettingsEntry<QList<TType>>::operator[](int index)
{
return ListElement{this, index};
}
template<typename TType>
SettingsEntry<QList<TType>> &SettingsEntry<QList<TType>>::operator+=(const TType &value)
{
push(value);
return *this;
}
template<typename TType>
SettingsEntry<QList<TType>> &SettingsEntry<QList<TType>>::operator+=(const QList<TType> &values)
{
push(values);
return *this;
}
template<typename TType>
typename SettingsEntry<QList<TType>>::iterator SettingsEntry<QList<TType>>::begin()
{
return iterator{this, 0};
}
template<typename TType>
typename SettingsEntry<QList<TType>>::iterator QtMvvm::SettingsEntry<QList<TType>>::end()
{
return iterator{this, size()};
}
template<typename TType>
typename SettingsEntry<QList<TType>>::const_iterator SettingsEntry<QList<TType>>::begin() const
{
return constBegin();
}
template<typename TType>
typename SettingsEntry<QList<TType>>::const_iterator SettingsEntry<QList<TType>>::end() const
{
return constEnd();
}
template<typename TType>
typename SettingsEntry<QList<TType>>::const_iterator SettingsEntry<QList<TType>>::constBegin() const
{
return const_iterator{const_cast<SettingsEntry<QList<TType>>*>(this), 0};
}
template<typename TType>
typename SettingsEntry<QList<TType>>::const_iterator SettingsEntry<QList<TType>>::constEnd() const
{
return const_iterator{const_cast<SettingsEntry<QList<TType>>*>(this), size()};
}
template<typename TType>
void SettingsEntry<QList<TType>>::addChangeCallback(const std::function<void (int, TType)> &callback)
{
addChangeCallback(_accessor, callback);
}
template<typename TType>
void SettingsEntry<QList<TType>>::addChangeCallback(QObject *scope, const std::function<void (int, TType)> &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<typename TType>
void SettingsEntry<QList<TType>>::addSizeChangeCallback(const std::function<void (int)> &callback)
{
addSizeChangeCallback(_accessor, callback);
}
template<typename TType>
void SettingsEntry<QList<TType>>::addSizeChangeCallback(QObject *scope, const std::function<void (int)> &callback)
{
QString mKey = _key + QStringLiteral("/size");
auto mInit = _init;
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) {
if(key == mKey)
callback(0); //is ok, as in case of a "reinit", the entry changed will be emitted next
});
}
template<typename TType>
void SettingsEntry<QList<TType>>::setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue)
{ {
Q_ASSERT_X(accessor, Q_FUNC_INFO, "You must set a valid accessor before initializing the settings!"); Q_ASSERT_X(accessor, Q_FUNC_INFO, "You must set a valid accessor before initializing the settings!");
_key = std::move(key); _key = std::move(key);
@ -125,6 +532,14 @@ void SettingsEntry<T>::setup(QString key, ISettingsAccessor *accessor, QVariant
_default = std::move(defaultValue); _default = std::move(defaultValue);
} }
template<typename TType>
void QtMvvm::SettingsEntry<QList<TType> >::setupInit(QList<TType> init)
{
_init = std::move(init);
if(!isSet())
push(_init);
}
} }

2
src/mvvmdatasynccore/datasyncsettingsentry.cpp

@ -1,6 +1,6 @@
#include "datasyncsettingsentry.h" #include "datasyncsettingsentry.h"
#include <QtCore/QDataStream> #include <QtCore/QDataStream>
#if QT_HAS_INCLUDE(<optional>) #if QT_HAS_INCLUDE(<optional>) && __cplusplus >= 201703L
#include <optional> #include <optional>
#define QTMVVM_HAS_OPTIONAL #define QTMVVM_HAS_OPTIONAL
#endif #endif

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

@ -51,4 +51,21 @@
tr="true"/> tr="true"/>
</Entry> </Entry>
</Node> </Node>
<Entry key="voidEntry"
type="void"/>
<Entry key="variantEntry"
type="QVariant"/>
<ListEntry key="listEntry"
type="QByteArray">
<Entry key="dummyChild"
type="bool"/>
<Code>&quot;Hello World&quot;</Code>
<Init> {
&quot;test1&quot;,
&quot;test2&quot;,
&quot;test3&quot;
} </Init>
</ListEntry>
</Settings> </Settings>

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

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

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

@ -24,6 +24,13 @@ void TestBackend::save(const QString &key, const QVariant &value)
void TestBackend::remove(const QString &key) void TestBackend::remove(const QString &key)
{ {
for(auto it = _data.begin(); it != _data.end();) {
if(it.key().startsWith(key + QLatin1Char('/'))) {
it = _data.erase(it);
emit entryRemoved(key);
} else
++it;
}
_data.remove(key); _data.remove(key);
emit entryRemoved(key); emit entryRemoved(key);
} }

51
tests/auto/mvvmcore/settingsgenerator/tst_settingsgenerator.cpp

@ -39,6 +39,9 @@ void SettingsGeneratorTest::testSettingsGenerator()
QCOMPARE(settings->parentNode.parentEntry.key(), QStringLiteral("tests/parentNode/parentEntry")); QCOMPARE(settings->parentNode.parentEntry.key(), QStringLiteral("tests/parentNode/parentEntry"));
QCOMPARE(settings->parentNode.parentEntry.nodeWithCodeEntry.key(), QStringLiteral("tests/parentNode/parentEntry/nodeWithCodeEntry")); QCOMPARE(settings->parentNode.parentEntry.nodeWithCodeEntry.key(), QStringLiteral("tests/parentNode/parentEntry/nodeWithCodeEntry"));
QCOMPARE(settings->parentNode.parentEntry.leafEntry.key(), QStringLiteral("tests/parentNode/parentEntry/leafEntry")); QCOMPARE(settings->parentNode.parentEntry.leafEntry.key(), QStringLiteral("tests/parentNode/parentEntry/leafEntry"));
QCOMPARE(settings->variantEntry.key(), QStringLiteral("tests/variantEntry"));
QCOMPARE(settings->listEntry.key(), QStringLiteral("tests/listEntry"));
QCOMPARE(settings->listEntry.dummyChild.key(), QStringLiteral("tests/listEntry/dummyChild"));
//verify defaults //verify defaults
QCOMPARE(settings->emptyEntry.get(), false); QCOMPARE(settings->emptyEntry.get(), false);
@ -48,21 +51,65 @@ void SettingsGeneratorTest::testSettingsGenerator()
QCOMPARE(settings->parentNode.parentEntry.get(), true); QCOMPARE(settings->parentNode.parentEntry.get(), true);
QCOMPARE(settings->parentNode.parentEntry.nodeWithCodeEntry.get(), 43); QCOMPARE(settings->parentNode.parentEntry.nodeWithCodeEntry.get(), 43);
QCOMPARE(settings->parentNode.parentEntry.leafEntry.get(), QStringLiteral("translate me")); QCOMPARE(settings->parentNode.parentEntry.leafEntry.get(), QStringLiteral("translate me"));
QCOMPARE(settings->variantEntry.get(), QVariant{});
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) //verify read/write (just on a single entry, they work all the same)
Q_ASSERT(tBackend->_data.isEmpty()); auto tKey = QStringLiteral("tests/advancedEntry");
QVERIFY(!tBackend->_data.contains(tKey));
QString cValue; QString cValue;
settings->advancedEntry.addChangeCallback([&](QString value) { settings->advancedEntry.addChangeCallback([&](QString value) {
cValue = std::move(value); cValue = std::move(value);
}); });
QString tValue = QStringLiteral("test42"); QString tValue = QStringLiteral("test42");
auto tKey = QStringLiteral("tests/advancedEntry");
QCOMPARE(settings->advancedEntry.key(), tKey); QCOMPARE(settings->advancedEntry.key(), tKey);
settings->advancedEntry = tValue; settings->advancedEntry = tValue;
QCOMPARE(tBackend->_data.value(tKey).toString(), tValue); QCOMPARE(tBackend->_data.value(tKey).toString(), tValue);
QCOMPARE(cValue, tValue); QCOMPARE(cValue, tValue);
QVERIFY(settings->advancedEntry.isSet()); QVERIFY(settings->advancedEntry.isSet());
QCOMPARE(settings->advancedEntry, tValue); 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");
}
} }
void SettingsGeneratorTest::testImportedSettings() void SettingsGeneratorTest::testImportedSettings()

19
tools/settingsgenerator/qsettingsgenerator.xsd

@ -14,7 +14,7 @@
<xs:complexType name="IncludeType"> <xs:complexType name="IncludeType">
<xs:simpleContent> <xs:simpleContent>
<xs:extension base="xs:string" qxg:member="includePath"> <xs:extension base="xs:string" qxg:member="includePath">
<xs:attribute default="false" name="local" type="xs:boolean" use="optional"/> <xs:attribute name="local" type="xs:boolean" use="optional" default="false"/>
</xs:extension> </xs:extension>
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>
@ -22,7 +22,7 @@
<xs:complexType name="ImportType"> <xs:complexType name="ImportType">
<xs:simpleContent> <xs:simpleContent>
<xs:extension base="xs:string" qxg:member="importPath"> <xs:extension base="xs:string" qxg:member="importPath">
<xs:attribute default="true" name="required" type="xs:boolean" use="optional"/> <xs:attribute name="required" type="xs:boolean" use="optional" default="true"/>
<xs:attribute name="rootNode" type="xs:string" use="optional"/> <xs:attribute name="rootNode" type="xs:string" use="optional"/>
</xs:extension> </xs:extension>
</xs:simpleContent> </xs:simpleContent>
@ -43,7 +43,7 @@
<xs:simpleContent> <xs:simpleContent>
<xs:extension base="xs:string" qxg:member="value"> <xs:extension base="xs:string" qxg:member="value">
<xs:attribute name="type" type="xs:string" use="required"/> <xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute default="false" name="asStr" type="xs:boolean" use="optional"/> <xs:attribute name="asStr" type="xs:boolean" use="optional" default="false"/>
</xs:extension> </xs:extension>
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>
@ -53,7 +53,7 @@
<xs:element maxOccurs="unbounded" minOccurs="0" name="Param" type="ParamType"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="Param" type="ParamType"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="class" type="xs:string" use="required" qxg:member="className"/> <xs:attribute name="class" type="xs:string" use="required" qxg:member="className"/>
<xs:attribute name="scope" type="xs:string" use="optional"/> <xs:attribute name="scope" type="xs:string" use="optional"/> <!-- TODO make an enum -->
</xs:complexType> </xs:complexType>
<xs:group name="NodeContentGroup"> <xs:group name="NodeContentGroup">
@ -61,6 +61,7 @@
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:member="contentNodes"> <xs:choice maxOccurs="unbounded" minOccurs="0" qxg:member="contentNodes">
<xs:element name="Node" type="NodeType"/> <xs:element name="Node" type="NodeType"/>
<xs:element name="Entry" type="EntryType"/> <xs:element name="Entry" type="EntryType"/>
<xs:element name="ListEntry" type="ListEntryType"/>
<xs:element name="Import" type="ImportType" qxg:method="read_included_file"/> <xs:element name="Import" type="ImportType" qxg:method="read_included_file"/>
</xs:choice> </xs:choice>
</xs:sequence> </xs:sequence>
@ -86,6 +87,16 @@
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>
<xs:complexType name="ListEntryType" qxg:declare="true">
<xs:complexContent>
<xs:extension base="EntryType">
<xs:sequence>
<xs:element maxOccurs="1" minOccurs="0" name="Init" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="SettingsType"> <xs:complexType name="SettingsType">
<xs:sequence> <xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="Include" type="IncludeType" qxg:member="includes"/> <xs:element maxOccurs="unbounded" minOccurs="0" name="Include" type="IncludeType" qxg:member="includes"/>

45
tools/settingsgenerator/settingsgenerator.cpp

@ -198,6 +198,12 @@ SettingsGeneratorBase::NodeContentGroup *SettingsGenerator::findContentGroup(Set
*isEntry = true; *isEntry = true;
return &(nonstd::get<EntryType>(cNode)); return &(nonstd::get<EntryType>(cNode));
} }
} else if(nonstd::holds_alternative<ListEntryType>(cNode)) {
if(nonstd::get<ListEntryType>(cNode).key == key) {
if(isEntry)
*isEntry = true;
return &(nonstd::get<ListEntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) { } else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = findContentGroup(&(nonstd::get<NodeContentGroup>(cNode)), key); auto res = findContentGroup(&(nonstd::get<NodeContentGroup>(cNode)), key);
if(res) if(res)
@ -236,6 +242,11 @@ void SettingsGenerator::fixTrContext(NodeContentGroup &group, const QString &con
if(!entry.trContext) if(!entry.trContext)
entry.trContext = context; entry.trContext = context;
fixTrContext(entry, context); fixTrContext(entry, context);
} else if(nonstd::holds_alternative<ListEntryType>(node)) {
auto &entry = nonstd::get<ListEntryType>(node);
if(!entry.trContext)
entry.trContext = context;
fixTrContext(entry, context);
} else if(nonstd::holds_alternative<NodeContentGroup>(node)) } else if(nonstd::holds_alternative<NodeContentGroup>(node))
fixTrContext(nonstd::get<NodeContentGroup>(node), context); fixTrContext(nonstd::get<NodeContentGroup>(node), context);
} }
@ -290,6 +301,8 @@ void SettingsGenerator::writeNodeElementDeclarations(const NodeContentGroup &nod
writeNodeDeclaration(nonstd::get<NodeType>(cNode), typeMappings, intendent); writeNodeDeclaration(nonstd::get<NodeType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<EntryType>(cNode)) else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDeclaration(nonstd::get<EntryType>(cNode), typeMappings, intendent); writeEntryDeclaration(nonstd::get<EntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDeclaration(nonstd::get<ListEntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDeclarations(nonstd::get<NodeContentGroup>(cNode), typeMappings, intendent); writeNodeElementDeclarations(nonstd::get<NodeContentGroup>(cNode), typeMappings, intendent);
} }
@ -315,6 +328,21 @@ void SettingsGenerator::writeEntryDeclaration(const EntryType &entry, const QHas
} }
} }
void SettingsGenerator::writeListEntryDeclaration(const SettingsGeneratorBase::ListEntryType &entry, const QHash<QString, QString> &typeMappings, int intendent)
{
if(entry.contentNodes.isEmpty())
_hdr << TABS << "QtMvvm::SettingsEntry<QList<" << typeMappings.value(entry.type, entry.type) << ">> " << entry.key << ";\n";
else {
const QString mType = QStringLiteral("QList<") + typeMappings.value(entry.type, entry.type) + QLatin1Char('>');
_hdr << TABS << "struct : QtMvvm::SettingsEntry<" << mType << "> { //" << entry.key << "\n";
writeNodeElementDeclarations(entry, typeMappings, intendent + 1);
_hdr << TABS << "\tinline auto &operator=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator=(__value); return *this; }\n";
_hdr << TABS << "\tinline auto &operator+=(const " << typeMappings.value(entry.type, entry.type) << " &__value) { SettingsEntry<" << mType << ">::operator+=(__value); return *this; }\n";
_hdr << TABS << "\tinline auto &operator+=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator+=(__value); return *this; }\n";
_hdr << TABS << "} " << entry.key << ";\n";
}
}
void SettingsGenerator::writeSource(const SettingsType &settings) void SettingsGenerator::writeSource(const SettingsType &settings)
{ {
_src << "#include \"" << _hdrFile.fileName() << "\"\n"; _src << "#include \"" << _hdrFile.fileName() << "\"\n";
@ -387,12 +415,14 @@ void SettingsGenerator::writeNodeElementDefinitions(const SettingsGeneratorBase:
writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key); writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key);
} else if(nonstd::holds_alternative<EntryType>(cNode)) } else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDefinition(nonstd::get<EntryType>(cNode), typeMappings, baseKey, keyChain); writeEntryDefinition(nonstd::get<EntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDefinition(nonstd::get<ListEntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDefinitions(nonstd::get<NodeContentGroup>(cNode), typeMappings, baseKey, keyChain); writeNodeElementDefinitions(nonstd::get<NodeContentGroup>(cNode), typeMappings, baseKey, keyChain);
} }
} }
void SettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain) void SettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain, bool skipChildren)
{ {
keyChain.append(entry.key); keyChain.append(entry.key);
_src << "\t" << keyChain.join(QLatin1Char('.')) _src << "\t" << keyChain.join(QLatin1Char('.'))
@ -408,5 +438,16 @@ void SettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryT
_src << "}.value<" << typeMappings.value(entry.type, entry.type) << ">()"; _src << "}.value<" << typeMappings.value(entry.type, entry.type) << ">()";
} }
_src << ");\n"; _src << ");\n";
writeNodeElementDefinitions(entry, typeMappings, baseKey, std::move(keyChain)); if(!skipChildren)
writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain);
}
void SettingsGenerator::writeListEntryDefinition(const SettingsGeneratorBase::ListEntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain)
{
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);
}
} }

4
tools/settingsgenerator/settingsgenerator.h

@ -41,10 +41,12 @@ private:
void writeNodeElementDeclarations(const NodeContentGroup &node, const QHash<QString, QString> &typeMappings, int intendent = 1); 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 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 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 writeSource(const SettingsType &settings); void writeSource(const SettingsType &settings);
void writeNodeElementDefinitions(const NodeContentGroup &node, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, const QStringList &keyChain = {}); 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); 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);
}; };
#endif // SETTINGSGENERATOR_H #endif // SETTINGSGENERATOR_H

Loading…
Cancel
Save