Browse Source

completed list node implementation for qml

with tests
pull/2/head
Skycoder42 7 years ago
parent
commit
29d4a84647
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 3
      src/mvvmcore/settingsentry.h
  2. 3
      tests/auto/auto.pro
  3. 30
      tests/auto/qml/qmlsettingsgenerator/generatortest.xml
  4. 100
      tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qml
  5. BIN
      tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qmlc
  6. 237
      tools/settingsgenerator/qmlsettingsgenerator.cpp
  7. 12
      tools/settingsgenerator/qmlsettingsgenerator.h
  8. 11
      tools/settingsgenerator/qsettingsgenerator.xsd
  9. 16
      tools/settingsgenerator/settingsgeneratorimpl.cpp

3
src/mvvmcore/settingsentry.h

@ -176,6 +176,7 @@ public:
// internal // internal
void setup(QString key, ISettingsAccessor *accessor, std::function<void(int, TType&)> setupFn); void setup(QString key, ISettingsAccessor *accessor, std::function<void(int, TType&)> setupFn);
void commit(int index);
private: private:
struct ElementHolder { struct ElementHolder {
@ -189,8 +190,6 @@ private:
ISettingsAccessor *_accessor = nullptr; ISettingsAccessor *_accessor = nullptr;
std::function<void(int, TType&)> _setupFn; std::function<void(int, TType&)> _setupFn;
mutable QHash<int, ElementHolder> _cache; mutable QHash<int, ElementHolder> _cache;
void commit(int index);
}; };
// ------------- Generic Implementation ------------- // ------------- Generic Implementation -------------

3
tests/auto/auto.pro

@ -1,4 +1,5 @@
TEMPLATE = subdirs TEMPLATE = subdirs
SUBDIRS += cmake mvvmcore \ SUBDIRS += cmake \
mvvmcore \
qml qml

30
tests/auto/qml/qmlsettingsgenerator/generatortest.xml

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

100
tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qml

@ -5,9 +5,21 @@ import de.skycoder42.QtMvvm.Core.test 4.2
Item { Item {
id: root id: root
Component { property string changeData: ""
id: listElement Connections {
TestSettings_ListElement_8 {} target: TestSettings.parentNode.parentEntryGroup
onLeafEntryChanged: {
changeData = value;
}
}
property bool ready: false
property int deepData: 0
Connections {
target: ready ? TestSettings.listNode[0].someNode : null
onDeepChildChanged: {
deepData = value;
}
} }
TestCase { TestCase {
@ -28,39 +40,65 @@ Item {
compare(TestSettings.parentNode.parentEntryGroup.leafEntry, qsTr("translate me")); compare(TestSettings.parentNode.parentEntryGroup.leafEntry, qsTr("translate me"));
compare(TestSettings.variantEntry, undefined); compare(TestSettings.variantEntry, undefined);
compare(TestSettings.simpleListEntry, [42]); compare(TestSettings.simpleListEntry, [42]);
compare(TestSettings.listEntryGroup.dummyChild, false);
} }
function test_2_listEntry() { function test_2_changeSignals() {
changeData = "";
TestSettings.parentNode.parentEntryGroup.leafEntry = "test44";
compare(TestSettings.parentNode.parentEntryGroup.leafEntry, "test44");
compare(changeData, "test44");
}
function test_3_listEntry() {
// test reading // test reading
compare(TestSettings.listEntry.length, 3); compare(TestSettings.listNode.length, 0);
verify(TestSettings.listEntry[0]); verify(TestSettings.listNode_push());
compare(TestSettings.listEntry[0].value, "test1"); compare(TestSettings.listNode.length, 1);
verify(TestSettings.listEntry[1]);
compare(TestSettings.listEntry[1].value, "test2"); compare(TestSettings.listNode[0].simpleChild, false);
verify(TestSettings.listEntry[2]); verify(TestSettings.listNode[0].someNode)
compare(TestSettings.listEntry[2].value, "test3"); compare(TestSettings.listNode[0].someNode.deepChild, 22);
verify(!TestSettings.listEntry[3]); compare(TestSettings.listNode[0].someNode.deepParent, "___");
verify(TestSettings.listNode[0].someNode.deepParentGroup)
compare(TestSettings.listNode[0].someNode.deepParentGroup.simpleChild, true);
compare(TestSettings.listNode[0].childList.length, 0);
ready = true;
deepData = 0;
TestSettings.listNode[0].someNode.deepChild = 99;
compare(TestSettings.listNode[0].someNode.deepChild, 99);
compare(deepData, 99);
deepData = 0;
compare(TestSettings.listNode.length, 1);
var newEntry = TestSettings.listNode_push();
verify(newEntry);
compare(TestSettings.listNode.length, 2);
compare(TestSettings.listNode[1], newEntry);
compare(newEntry.simpleChild, false);
compare(TestSettings.listNode[1].simpleChild, false);
newEntry.simpleChild = true;
compare(newEntry.simpleChild, true);
compare(TestSettings.listNode[1].simpleChild, true);
compare(TestSettings.listNode[0].simpleChild, false);
// test appending var newEntry2 = TestSettings.listNode_push_deferred();
var elem = listElement.createObject(root, {value: "baum42"}); verify(newEntry2);
verify(elem); compare(TestSettings.listNode.length, 2);
compare(elem.value, "baum42"); verify(!TestSettings.listNode[2]);
TestSettings.listEntry.push(elem); compare(newEntry2.simpleChild, false);
compare(TestSettings.listEntry.length, 4); newEntry2.simpleChild = true;
verify(TestSettings.listEntry[3]); compare(newEntry2.simpleChild, true);
compare(TestSettings.listEntry[3].value, "baum42"); compare(TestSettings.listNode[0].simpleChild, false);
verify(!TestSettings.listEntry[4]); compare(TestSettings.listNode.length, 2);
TestSettings.listNode.push(newEntry2);
compare(TestSettings.listNode.length, 3);
compare(TestSettings.listNode[2], newEntry2);
compare(deepData, 0);
// test resetting TestSettings.listNode = [];
var elem2 = TestSettings.create_listEntry_element("newElem"); compare(TestSettings.listNode.length, 0);
verify(elem2); verify(!TestSettings.listNode[0]);
compare(elem2.value, "newElem");
TestSettings.listEntry = [elem2]
compare(TestSettings.listEntry.length, 1);
verify(TestSettings.listEntry[0]);
compare(TestSettings.listEntry[0].value, "newElem");
verify(!TestSettings.listEntry[1]);
} }
} }

BIN
tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qmlc

Binary file not shown.

237
tools/settingsgenerator/qmlsettingsgenerator.cpp

@ -23,14 +23,12 @@ void QmlSettingsGenerator::process(const QString &inPath)
if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text))
throw FileException{_hdrFile}; throw FileException{_hdrFile};
_listTypes.clear();
auto typeNum = writeHeader(settings, QFileInfo{inPath}.completeBaseName() + QStringLiteral(".h")); auto typeNum = writeHeader(settings, QFileInfo{inPath}.completeBaseName() + QStringLiteral(".h"));
_hdrFile.close(); _hdrFile.close();
if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text)) if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text))
throw FileException{_srcFile}; throw FileException{_srcFile};
writeSource(settings, typeNum); writeSource(settings, typeNum);
_listTypes.clear();
_srcFile.close(); _srcFile.close();
} }
@ -71,19 +69,21 @@ int QmlSettingsGenerator::writeHeader(const SettingsType &settings, const QStrin
_hdr << "class " << (settings.prefix ? settings.prefix.value() + QLatin1Char(' ') : QString{}) << _name << " : public QObject\n" _hdr << "class " << (settings.prefix ? settings.prefix.value() + QLatin1Char(' ') : QString{}) << _name << " : public QObject\n"
<< "{\n" << "{\n"
<< "\tQ_OBJECT\n\n" << "\tQ_OBJECT\n\n"
<< "\tusing SelfType = " << _name << ";\n"
<< "\t" << _cppName << " *_settings;\n"
<< "\tQList<int> _indexMap;\n\n"
<< "\tQ_PROPERTY(QtMvvm::ISettingsAccessor *accessor READ accessor CONSTANT FINAL)\n\n"; << "\tQ_PROPERTY(QtMvvm::ISettingsAccessor *accessor READ accessor CONSTANT FINAL)\n\n";
QList<QPair<QString, int>> childConstructs; QList<QPair<QString, int>> childConstructs;
QList<int> listEntries; QList<int> listEntries;
writeProperties(settings, keyList, childOffsets, listEntries, childConstructs); writeProperties(settings, keyList, childOffsets, listEntries, childConstructs);
_hdr << "\t" << _cppName << " *_settings;\n\n" _hdr << "public:\n"
<< "public:\n"
<< "\texplicit " << _name << "(" << _cppName << " *settings, QObject *parent = nullptr) : \n" << "\texplicit " << _name << "(" << _cppName << " *settings, QObject *parent = nullptr) : \n"
<< "\t\tQObject{parent},\n"; << "\t\tQObject{parent}\n"
<< "\t\t,_settings{settings}\n";
writeMemberInits(keyList, childConstructs); writeMemberInits(keyList, childConstructs);
_hdr << "\t\t_settings{settings}\n" _hdr << "\t{\n";
<< "\t{\n";
writeEntryPropertySignalConnects(settings, keyList, -1, listEntries); writeEntryPropertySignalConnects(settings, keyList, -1, listEntries);
_hdr << "\t}\n\n" _hdr << "\t}\n\n"
<< "\texplicit " << _name << "(QObject *parent = nullptr) :\n" << "\texplicit " << _name << "(QObject *parent = nullptr) :\n"
@ -103,109 +103,67 @@ int QmlSettingsGenerator::writeHeader(const SettingsType &settings, const QStrin
void QmlSettingsGenerator::writeListTypeBaseClass() void QmlSettingsGenerator::writeListTypeBaseClass()
{ {
// write the generic variant // write the generic variant
_hdr << "template <typename T>\n" _hdr << "template <typename TList, typename TListParent, typename TNodeValue>\n"
<< "class " << _name << "_ListType : public QObject\n" << "struct " << _name << "_ListData\n"
<< "{\n" << "{\n"
<< "public:\n" << "\tTNodeValue &node;\n"
<< "\ttemplate <typename TList>\n" << "\tQList<TList*> elements;\n\n"
<< "\tstruct ListData {\n"
<< "\t\tstatic_assert(std::is_base_of<" << _name << "_ListType<T>, TList>::value, \"TList must extend " << _name << "_ListType<T>\");\n"
<< "\t\tQtMvvm::SettingsListEntry<T> &entry;\n"
<< "\t\tQList<TList*> elements;\n"
<< "\t};\n\n"
<< "\t" << _name << "_ListType(QObject *parent) : \n"
<< "\t\tQObject{parent}\n"
<< "\t{}\n"
<< "\tT value() const { return _entry ? _entry->getAt(_index) : _buffer; }\n"
<< "\tvoid setValue(const T &value) { if(_entry) _entry->setAt(_index, value); else { _index = -2; _buffer = value; } }\n\n"
<< "\ttemplate <typename TList>\n" << "\tstatic void adjust(" << _name << "_ListData<TList, TListParent, TNodeValue> *data, QObject *parent, int size) {\n"
<< "\tstatic void adjust(ListData<TList> *data, QObject *parent, int size) {\n"
<< "\t\twhile(data->elements.size() > size)\n" << "\t\twhile(data->elements.size() > size)\n"
<< "\t\t\tdata->elements.takeLast()->deleteLater();\n" << "\t\t\tdata->elements.takeLast()->deleteLater();\n"
<< "\t\tfor(auto index = data->elements.size(); index < size; index++) {\n" << "\t\tfor(auto index = data->elements.size(); index < size; index++)\n"
<< "\t\t\tauto elem = new TList{parent};\n" << "\t\t\tdata->elements.append(new TList{static_cast<TListParent*>(parent)->_settings, static_cast<TListParent*>(parent)->_indexMap, index, parent});\n"
<< "\t\t\telem->_index = index;\n"
<< "\t\t\telem->_entry = &data->entry;\n"
<< "\t\t\tdata->elements.append(elem);\n"
<< "\t\t\tdata->entry.addChangeCallback(elem, [index, elem](int i, const T &d) {\n"
<< "\t\t\t\tif(i == index)\n"
<< "\t\t\t\t\temit elem->valueChanged(d);\n"
<< "\t\t\t});\n"
<< "\t\t}\n"
<< "\t}\n\n" << "\t}\n\n"
<< "\ttemplate <typename TList>\n"
<< "\tstatic void append(QQmlListProperty<TList> *list, TList *element) {\n" << "\tstatic void append(QQmlListProperty<TList> *list, TList *element) {\n"
<< "\t\tconst auto data = reinterpret_cast<ListData<TList>*>(list->data);\n" << "\t\tconst auto data = reinterpret_cast<" << _name << "_ListData<TList, TListParent, TNodeValue>*>(list->data);\n"
<< "\t\tconst auto maxIndex = data->entry.size();\n" << "\t\tconst auto maxIndex = data->node.size();\n"
<< "\t\tadjust<TList>(data, list->object, maxIndex);\n" << "\t\tadjust(data, list->object, maxIndex);\n"
<< "\t\telement->setParent(list->object);\n" << "\t\telement->setParent(list->object);\n"
<< "\t\tconst auto copyDefault = element->_index == -2;\n"
<< "\t\telement->_index = maxIndex;\n"
<< "\t\telement->_entry = &data->entry;\n"
<< "\t\tdata->elements.append(element);\n" << "\t\tdata->elements.append(element);\n"
<< "\t\tif(copyDefault)\n" << "\t\tdata->node.commit(maxIndex);\n"
<< "\t\t\tdata->entry.push(T{std::move(element->_buffer)});\n"
<< "\t\telse\n"
<< "\t\t\tdata->entry.push(T{});\n"
<< "\t\tdata->entry.addChangeCallback(element, [maxIndex, element](int i, const T &d) {\n"
<< "\t\t\tif(i == maxIndex)\n"
<< "\t\t\t\temit element->valueChanged(d);\n"
<< "\t\t});\n"
<< "\t}\n\n" << "\t}\n\n"
<< "\ttemplate <typename TList>\n"
<< "\tstatic TList *at(QQmlListProperty<TList> *list, int index) {\n" << "\tstatic TList *at(QQmlListProperty<TList> *list, int index) {\n"
<< "\t\tconst auto data = reinterpret_cast<ListData<TList>*>(list->data);\n" << "\t\tconst auto data = reinterpret_cast<" << _name << "_ListData<TList, TListParent, TNodeValue>*>(list->data);\n"
<< "\t\treturn data->elements.size() > index ? data->elements.value(index) : nullptr;\n" << "\t\treturn data->elements.size() > index ? data->elements.value(index) : nullptr;\n"
<< "\t}\n\n" << "\t}\n\n"
<< "\ttemplate <typename TList>\n"
<< "\tstatic int count(QQmlListProperty<TList> *list) {\n" << "\tstatic int count(QQmlListProperty<TList> *list) {\n"
<< "\t\treturn reinterpret_cast<ListData<TList>*>(list->data)->elements.size();\n" << "\t\treturn reinterpret_cast<" << _name << "_ListData<TList, TListParent, TNodeValue>*>(list->data)->elements.size();\n"
<< "\t}\n\n" << "\t}\n\n"
<< "\ttemplate <typename TList>\n"
<< "\tstatic void clear(QQmlListProperty<TList> *list) {\n" << "\tstatic void clear(QQmlListProperty<TList> *list) {\n"
<< "\t\tconst auto data = reinterpret_cast<ListData<TList>*>(list->data);\n" << "\t\tconst auto data = reinterpret_cast<" << _name << "_ListData<TList, TListParent, TNodeValue>*>(list->data);\n"
<< "\t\tfor(auto elem : qAsConst(data->elements))\n" << "\t\tfor(auto elem : qAsConst(data->elements))\n"
<< "\t\t\telem->deleteLater();\n" << "\t\t\telem->deleteLater();\n"
<< "\t\tdata->elements.clear();\n" << "\t\tdata->elements.clear();\n"
<< "\t\tdata->entry.reset(false);\n" << "\t\tdata->node.reset();\n"
<< "\t}\n\n" << "\t}\n\n"
<< "private:\n"
<< "\tQtMvvm::SettingsListEntry<T> *_entry = nullptr;\n"
<< "\tint _index = -1;\n"
<< "\tT _buffer{};\n"
<< "};\n\n"; << "};\n\n";
} }
std::tuple<int, QList<int>> QmlSettingsGenerator::writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset) std::tuple<int, QList<int>> QmlSettingsGenerator::writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset, int listDepth)
{ {
QList<int> offsetList; QList<int> offsetList;
for(const auto &cNode : node.contentNodes) { for(const auto &cNode : node.contentNodes) {
if(nonstd::holds_alternative<NodeType>(cNode)) { if(nonstd::holds_alternative<NodeType>(cNode)) {
offset = writeNodeClass(nonstd::get<NodeType>(cNode), keyList, offset); offset = writeNodeClass(nonstd::get<NodeType>(cNode), keyList, offset, listDepth);
offsetList.append(offset - 1); offsetList.append(offset - 1);
} else if(nonstd::holds_alternative<EntryType>(cNode)) { } else if(nonstd::holds_alternative<EntryType>(cNode)) {
if(!nonstd::get<EntryType>(cNode).contentNodes.isEmpty()) { if(!nonstd::get<EntryType>(cNode).contentNodes.isEmpty()) {
offset = writeNodeClass(nonstd::get<EntryType>(cNode), keyList, offset); offset = writeNodeClass(nonstd::get<EntryType>(cNode), keyList, offset, listDepth);
offsetList.append(offset - 1); offsetList.append(offset - 1);
} else } else
offsetList.append(-1); offsetList.append(-1);
} else if(nonstd::holds_alternative<ListEntryType>(cNode)) { } else if(nonstd::holds_alternative<ListNodeType>(cNode)) {
offset = writeListEntryElementClass(nonstd::get<ListEntryType>(cNode), keyList, offset); offset = writeListNodeClass(nonstd::get<ListNodeType>(cNode), keyList, offset, listDepth);
offsetList.append(offset - 1); //double offset!!!
if(!nonstd::get<ListEntryType>(cNode).contentNodes.isEmpty()) {
offset = writeNodeClass(nonstd::get<ListEntryType>(cNode), keyList, offset);
offsetList.append(offset - 1); offsetList.append(offset - 1);
} else
offsetList.append(-1);
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) { } else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
QList<int> subList; QList<int> subList;
std::tie(offset, subList) = writeNodeContentClasses(nonstd::get<NodeContentGroup>(cNode), keyList, offset); std::tie(offset, subList) = writeNodeContentClasses(nonstd::get<NodeContentGroup>(cNode), keyList, offset, listDepth);
offsetList.append(subList); offsetList.append(subList);
} else } else
Q_UNREACHABLE(); Q_UNREACHABLE();
@ -213,27 +171,30 @@ std::tuple<int, QList<int>> QmlSettingsGenerator::writeNodeContentClasses(const
return std::make_tuple(offset, offsetList); return std::make_tuple(offset, offsetList);
} }
int QmlSettingsGenerator::writeNodeClass(const NodeType &node, QStringList keyList, int offset) int QmlSettingsGenerator::writeNodeClass(const NodeType &node, QStringList keyList, int offset, int listDepth)
{ {
keyList.append(node.key); keyList.append(node.key);
QList<int> childOffsets; QList<int> childOffsets;
std::tie(offset, childOffsets) = writeNodeContentClasses(node, keyList, offset); std::tie(offset, childOffsets) = writeNodeContentClasses(node, keyList, offset, listDepth);
_hdr << "class " << _name << "_" << offset << " : public QObject // " << keyList.join(QLatin1Char('/')) << "\n" _hdr << "class " << _name << "_" << offset << " : public QObject // " << keyList.join(QLatin1Char('/')) << "\n"
<< "{\n" << "{\n"
<< "\tQ_OBJECT\n\n"; << "\tQ_OBJECT\n\n"
<< "\tusing SelfType = " << _name << "_" << offset << ";\n"
<< "\t" << _cppName << " *_settings;\n"
<< "\tconst QList<int> &_indexMap;\n\n";
QList<QPair<QString, int>> childConstructs; QList<QPair<QString, int>> childConstructs;
QList<int> listEntries; QList<int> listEntries;
writeProperties(node, keyList, childOffsets, listEntries, childConstructs); writeProperties(node, keyList, childOffsets, listEntries, childConstructs);
_hdr << "\t" << _cppName << " *_settings;\n\n" _hdr << "public:\n"
<< "public:\n" << "\t" << _name << "_" << offset << "(" << _cppName << " *settings, const QList<int> &indexMap, QObject *parent) : \n"
<< "\t" << _name << "_" << offset << "(" << _cppName << " *settings, QObject *parent) : \n" << "\t\tQObject{parent}\n"
<< "\t\tQObject{parent},\n"; << "\t\t,_settings{settings}\n"
<< "\t\t,_indexMap{indexMap}\n";
writeMemberInits(keyList, childConstructs); writeMemberInits(keyList, childConstructs);
_hdr << "\t\t_settings{settings}\n" _hdr << "\t{\n";
<< "\t{\n";
writeEntryPropertySignalConnects(node, keyList, offset, listEntries); writeEntryPropertySignalConnects(node, keyList, offset, listEntries);
_hdr << "\t}\n" _hdr << "\t}\n"
<< "};\n\n"; << "};\n\n";
@ -241,25 +202,32 @@ int QmlSettingsGenerator::writeNodeClass(const NodeType &node, QStringList keyLi
return ++offset; return ++offset;
} }
int QmlSettingsGenerator::writeListEntryElementClass(const ListEntryType &entry, QStringList keyList, int offset) int QmlSettingsGenerator::writeListNodeClass(const ListNodeType &node, QStringList keyList, int offset, int listDepth)
{ {
keyList.append(entry.key); keyList.append({node.key, QStringLiteral("at(_indexMap.at(%1))").arg(listDepth++)});
const auto &mType = _typeMappings.value(entry.type, entry.type); QList<int> childOffsets;
_hdr << "class " << _name << "_" << offset << " : public " << _name << "_ListType<" << mType << "> // " << keyList.join(QLatin1Char('/')) << " (list-element)\n" std::tie(offset, childOffsets) = writeNodeContentClasses(node, keyList, offset, listDepth);
_hdr << "class " << _name << "_" << offset << " : public QObject // " << keyList.join(QLatin1Char('/')) << "\n"
<< "{\n" << "{\n"
<< "\tQ_OBJECT\n\n" << "\tQ_OBJECT\n\n"
<< "\tQ_PROPERTY(" << mType << " value READ value WRITE setValue NOTIFY valueChanged)\n\n" << "\tusing SelfType = " << _name << "_" << offset << ";\n"
<< "public:\n" << "\t" << _cppName << " *_settings;\n"
<< "\texplicit " << _name << "_" << offset << "(QObject *parent = nullptr) : \n" << "\tQList<int> _indexMap;\n\n";
<< "\t\t" << _name << "_ListType{parent}\n"
<< "\t{}\n\n" QList<QPair<QString, int>> childConstructs;
<< "\texplicit " << _name << "_" << offset << "(const " << mType << " &value, QObject *parent = nullptr) : \n" QList<int> listEntries;
<< "\t\t" << _name << "_" << offset << "{parent}\n" writeProperties(node, keyList, childOffsets, listEntries, childConstructs);
<< "\t{\n"
<< "\t\tsetValue(value);\n" _hdr << "public:\n"
<< "\t}\n\n" << "\t" << _name << "_" << offset << "(" << _cppName << " *settings, const QList<int> &indexMap, int index, QObject *parent) : \n"
<< "Q_SIGNALS:\n" << "\t\tQObject{parent}\n"
<< "\tvoid valueChanged(const " << mType << " &value);\n" << "\t\t,_settings{settings}\n"
<< "\t\t,_indexMap{QList<int>{indexMap} << index}\n";
writeMemberInits(keyList, childConstructs);
_hdr << "\t{\n";
writeEntryPropertySignalConnects(node, keyList, offset, listEntries);
_hdr << "\t}\n"
<< "};\n\n"; << "};\n\n";
return ++offset; return ++offset;
@ -272,11 +240,9 @@ void QmlSettingsGenerator::writeProperties(const NodeContentGroup &node, const Q
writeNodeProperty(nonstd::get<NodeType>(cNode), childOffsets.takeFirst(), childConstructs); writeNodeProperty(nonstd::get<NodeType>(cNode), childOffsets.takeFirst(), childConstructs);
else if(nonstd::holds_alternative<EntryType>(cNode)) else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryProperty(nonstd::get<EntryType>(cNode), keyList, childOffsets.takeFirst(), childConstructs); writeEntryProperty(nonstd::get<EntryType>(cNode), keyList, childOffsets.takeFirst(), childConstructs);
else if(nonstd::holds_alternative<ListEntryType>(cNode)) { else if(nonstd::holds_alternative<ListNodeType>(cNode)) {
auto lIndex = childOffsets.takeFirst(); //done seperately because of undefine param call order listEntries.append(childOffsets.first());
writeListEntryProperty(nonstd::get<ListEntryType>(cNode), keyList, lIndex, childOffsets.takeFirst(), childConstructs); writeListNodeProperty(nonstd::get<ListNodeType>(cNode), keyList, childOffsets.takeFirst(), childConstructs);
listEntries.append(lIndex);
_listTypes.insert(lIndex);
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) } else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeProperties(nonstd::get<NodeContentGroup>(cNode), keyList, childOffsets, listEntries, childConstructs); writeProperties(nonstd::get<NodeContentGroup>(cNode), keyList, childOffsets, listEntries, childConstructs);
else else
@ -301,12 +267,12 @@ void QmlSettingsGenerator::writeEntryProperty(const EntryType &entry, QStringLis
_hdr << "\tQ_PROPERTY(" << mType << " " << entry.key _hdr << "\tQ_PROPERTY(" << mType << " " << entry.key
<< " READ get_" << entry.key << " READ get_" << entry.key
<< " WRITE set_" << entry.key << " WRITE set_" << entry.key
<< " NOTIFY " << entry.key << "_changed)\n"; << " NOTIFY " << entry.key << "Changed)\n";
_hdr << "\t" << mType << " get_" << entry.key << "() const { return _settings->" << keyList.join(QLatin1Char('.')) << ".get(); }\n" _hdr << "\t" << mType << " get_" << entry.key << "() const { return _settings->" << keyList.join(QLatin1Char('.')) << ".get(); }\n"
<< "\tvoid set_" << entry.key << "(const " << mType << " &value) { _settings->" << keyList.join(QLatin1Char('.')) << ".set(value); }\n" << "\tvoid set_" << entry.key << "(const " << mType << " &value) { _settings->" << keyList.join(QLatin1Char('.')) << ".set(value); }\n"
<< "Q_SIGNALS:\n" << "Q_SIGNALS:\n"
<< "\tvoid " << entry.key << "_changed(const " << mType << " &value);\n" << "\tvoid " << entry.key << "Changed(const " << mType << " &value);\n"
<< "private:\n\n"; << "private:\n\n";
} }
@ -314,40 +280,45 @@ void QmlSettingsGenerator::writeEntryProperty(const EntryType &entry, QStringLis
writeNodeProperty(entry, classIndex, childConstructs, entry.qmlGroupKey.value_or(entry.key + QStringLiteral("Group"))); writeNodeProperty(entry, classIndex, childConstructs, entry.qmlGroupKey.value_or(entry.key + QStringLiteral("Group")));
} }
void QmlSettingsGenerator::writeListEntryProperty(const ListEntryType &entry, QStringList keyList, int listIndex, int classIndex, QList<QPair<QString, int>> &childConstructs) void QmlSettingsGenerator::writeListNodeProperty(const ListNodeType &node, QStringList keyList, int classIndex, QList<QPair<QString, int>> &childConstructs)
{ {
keyList.append(entry.key); keyList.append(node.key);
_hdr << "\tQ_PROPERTY(QQmlListProperty<" << _name << "_" << listIndex << "> " << entry.key _hdr << "\tusing ListData_" << classIndex << " = " << _name << "_ListData<" << _name << "_" << classIndex << ", SelfType, typename std::decay<decltype(_settings->" << keyList.join(QLatin1Char('.')) << ")>::type>;\n"
<< " READ get_" << entry.key << " CONSTANT)\n" << "\tfriend ListData_" << classIndex << ";\n"
<< "\t" << _name << "_" << listIndex << "::ListData<" << _name << "_" << listIndex << "> _" << entry.key << ";\n" << "\tQ_PROPERTY(QQmlListProperty<" << _name << "_" << classIndex << "> " << node.key
<< "\tQQmlListProperty<" << _name << "_" << listIndex << "> get_" << entry.key << "() {\n" << " READ get_" << node.key << " CONSTANT)\n"
<< "\tListData_" << classIndex << " _" << node.key << ";\n"
<< "\tQQmlListProperty<" << _name << "_" << classIndex << "> get_" << node.key << "() {\n"
<< "\t\treturn {\n" << "\t\treturn {\n"
<< "\t\t\tthis, &_" << entry.key << ",\n" << "\t\t\tthis, &_" << node.key << ",\n"
<< "\t\t\t&" << _name << "_" << listIndex << "::append<" << _name << "_" << listIndex << ">,\n" << "\t\t\t&ListData_" << classIndex << "::append,\n"
<< "\t\t\t&" << _name << "_" << listIndex << "::count<" << _name << "_" << listIndex << ">,\n" << "\t\t\t&ListData_" << classIndex << "::count,\n"
<< "\t\t\t&" << _name << "_" << listIndex << "::at<" << _name << "_" << listIndex << ">,\n" << "\t\t\t&ListData_" << classIndex << "::at,\n"
<< "\t\t\t&" << _name << "_" << listIndex << "::clear<" << _name << "_" << listIndex << ">\n" << "\t\t\t&ListData_" << classIndex << "::clear\n"
<< "\t\t};\n" << "\t\t};\n"
<< "\t}\n" << "\t}\n"
<< "public:\n" << "public:\n"
<< "\tQ_INVOKABLE " << _name << "_" << listIndex << " *create_" << entry.key << "_element(const " << _typeMappings.value(entry.type, entry.type) << " &value) {\n" << "\tQ_INVOKABLE " << _name << "_" << classIndex << " *" << node.key << "_push_deferred() {\n"
<< "\t\treturn new " << _name << "_" << listIndex << "{value, this};\n" << "\t\treturn new " << _name << "_" << classIndex << "{_settings, _indexMap, _" << node.key << ".node.size(), this};\n"
<< "\t}\n"
<< "\tQ_INVOKABLE " << _name << "_" << classIndex << " *" << node.key << "_push() {\n"
<< "\t\tauto data = " << node.key << "_push_deferred();\n"
<< "\t\tauto qmlList = get_" << node.key << "();\n"
<< "\t\tListData_" << classIndex << "::append(&qmlList, data);\n"
<< "\t\treturn data;\n"
<< "\t}\n" << "\t}\n"
<< "private:\n\n"; << "private:\n\n";
childConstructs.append({entry.key, -1}); childConstructs.append({node.key, -1});
if(!entry.contentNodes.isEmpty())
writeNodeProperty(entry, classIndex, childConstructs, entry.qmlGroupKey.value_or(entry.key + QStringLiteral("Group")));
} }
void QmlSettingsGenerator::writeMemberInits(const QStringList &keyList, const QList<QPair<QString, int>> &childConstructs) void QmlSettingsGenerator::writeMemberInits(const QStringList &keyList, const QList<QPair<QString, int>> &childConstructs)
{ {
for(const auto &info : childConstructs) { for(const auto &info : childConstructs) {
if(info.second < 0) if(info.second < 0)
_hdr << "\t\t_" << info.first << "{settings->" << (QStringList{keyList} << info.first).join(QLatin1Char('.')) << ", {}},\n"; _hdr << "\t\t,_" << info.first << "{_settings->" << (QStringList{keyList} << info.first).join(QLatin1Char('.')) << ", {}}\n";
else else
_hdr << "\t\t_" << info.first << "{new " << _name << "_" << info.second << "{settings, this}},\n"; _hdr << "\t\t,_" << info.first << "{new " << _name << "_" << info.second << "{_settings, _indexMap, this}}\n";
} }
} }
@ -358,8 +329,8 @@ void QmlSettingsGenerator::writeEntryPropertySignalConnects(const NodeContentGro
continue; //nothing to be set continue; //nothing to be set
else if(nonstd::holds_alternative<EntryType>(cNode)) else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryPropertySignalConnect(nonstd::get<EntryType>(cNode), keyList, classIndex); writeEntryPropertySignalConnect(nonstd::get<EntryType>(cNode), keyList, classIndex);
else if(nonstd::holds_alternative<ListEntryType>(cNode)) else if(nonstd::holds_alternative<ListNodeType>(cNode))
writeListEntryPropertySignalConnect(nonstd::get<ListEntryType>(cNode), keyList, listEntries); writeListNodePropertySignalConnect(nonstd::get<ListNodeType>(cNode), keyList, listEntries);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeEntryPropertySignalConnects(nonstd::get<NodeContentGroup>(cNode), keyList, classIndex, listEntries); writeEntryPropertySignalConnects(nonstd::get<NodeContentGroup>(cNode), keyList, classIndex, listEntries);
else else
@ -376,19 +347,18 @@ void QmlSettingsGenerator::writeEntryPropertySignalConnect(const EntryType &entr
<< ".addChangeCallback(this, std::bind(&" << _name; << ".addChangeCallback(this, std::bind(&" << _name;
if(classIndex >= 0) if(classIndex >= 0)
_hdr << "_" << classIndex; _hdr << "_" << classIndex;
_hdr << "::" << entry.key << "_changed, this, std::placeholders::_1));\n"; _hdr << "::" << entry.key << "Changed, this, std::placeholders::_1));\n";
} }
void QmlSettingsGenerator::writeListEntryPropertySignalConnect(const SettingsGeneratorBase::ListEntryType &entry, QStringList keyList, QList<int> &listEntries) void QmlSettingsGenerator::writeListNodePropertySignalConnect(const ListNodeType &entry, QStringList keyList, QList<int> &listEntries)
{ {
auto classIndex = listEntries.takeFirst(); auto classIndex = listEntries.takeFirst();
keyList.append(entry.key); keyList.append(entry.key);
_hdr << "\t\t_settings->" << keyList.join(QLatin1Char('.')) _hdr << "\t\t_settings->" << keyList.join(QLatin1Char('.'))
<< ".addSizeChangeCallback(this, std::bind(&" << ".addChangeCallback(this, std::bind(&"
<< _name << "_" << classIndex << "::adjust<" << _name << "_" << classIndex << "ListData_" << classIndex << "::adjust, &_" << entry.key << ", this, std::placeholders::_1));\n"
<< ">, &_" << entry.key << ", this, std::placeholders::_1));\n" << "\t\t" << "ListData_" << classIndex << "::adjust"
<< "\t\t"<< _name << "_" << classIndex << "::adjust<" << _name << "_" << classIndex << "(&_" << entry.key << ", this, _settings->" << keyList.join(QLatin1Char('.')) << ".size());\n";
<< ">(&_" << entry.key << ", this, _settings->" << keyList.join(QLatin1Char('.')) << ".size());\n";
} }
void QmlSettingsGenerator::writeSource(const SettingsType &settings, int typeNum) void QmlSettingsGenerator::writeSource(const SettingsType &settings, int typeNum)
@ -432,12 +402,9 @@ void QmlSettingsGenerator::writeQmlRegistration(QmlRegistrationMode mode, int ty
_src << "void " << _name << "::registerQmlTypes(const char *uri, int major, int minor)\n" _src << "void " << _name << "::registerQmlTypes(const char *uri, int major, int minor)\n"
<< "{\n" << "{\n"
<< "\tconst QString msg{QStringLiteral(\"Settings-Helpertypes cannot be created\")};\n\n"; << "\tconst QString msg{QStringLiteral(\"Settings-Helpertypes cannot be created\")};\n\n";
for(auto i = 0; i < typeNum; i++) { for(auto i = 0; i < typeNum; i++)
if(_listTypes.contains(i))
_src << "\tqmlRegisterType<" << _name << "_" << i << ">(uri, major, minor, \"" << _cppName << "_ListElement_" << i << "\");\n";
else
_src << "\tqmlRegisterUncreatableType<" << _name << "_" << i << ">(uri, major, minor, \"" << _name << "_" << i << "\", msg);\n"; _src << "\tqmlRegisterUncreatableType<" << _name << "_" << i << ">(uri, major, minor, \"" << _name << "_" << i << "\", msg);\n";
}
switch(mode) { switch(mode) {
case Singleton: case Singleton:
_src << "\n\tqmlRegisterSingletonType<" << _name << ">(uri, major, minor, \"" << _cppName << "\", __create_qml_singleton);\n"; _src << "\n\tqmlRegisterSingletonType<" << _name << ">(uri, major, minor, \"" << _cppName << "\", __create_qml_singleton);\n";

12
tools/settingsgenerator/qmlsettingsgenerator.h

@ -25,15 +25,13 @@ private:
QString _prefixName; QString _prefixName;
QHash<QString, QString> _typeMappings; QHash<QString, QString> _typeMappings;
QSet<int> _listTypes;
int writeHeader(const SettingsType &settings, const QString &inHdrPath); int writeHeader(const SettingsType &settings, const QString &inHdrPath);
void writeListTypeBaseClass(); void writeListTypeBaseClass();
std::tuple<int, QList<int>> writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset = 0); std::tuple<int, QList<int>> writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset = 0, int listDepth = 0);
int writeNodeClass(const NodeType &node, QStringList keyList, int offset); int writeNodeClass(const NodeType &node, QStringList keyList, int offset, int listDepth);
int writeListEntryElementClass(const ListEntryType &entry, QStringList keyList, int offset); int writeListNodeClass(const ListNodeType &entry, QStringList keyList, int offset, int listDepth);
void writeProperties(const NodeContentGroup &node, void writeProperties(const NodeContentGroup &node,
const QStringList &keyList, const QStringList &keyList,
@ -42,12 +40,12 @@ private:
QList<QPair<QString, int>> &childConstructs); QList<QPair<QString, int>> &childConstructs);
void writeNodeProperty(const NodeType &entry, int classIndex, QList<QPair<QString, int>> &childConstructs, const QString &overwriteName = {}); void writeNodeProperty(const NodeType &entry, int classIndex, QList<QPair<QString, int>> &childConstructs, const QString &overwriteName = {});
void writeEntryProperty(const EntryType &entry, QStringList keyList, int classIndex, QList<QPair<QString, int>> &childConstructs); void writeEntryProperty(const EntryType &entry, QStringList keyList, int classIndex, QList<QPair<QString, int>> &childConstructs);
void writeListEntryProperty(const ListEntryType &entry, QStringList keyList, int listIndex, int classIndex, QList<QPair<QString, int>> &childConstructs); void writeListNodeProperty(const ListNodeType &entry, QStringList keyList, int classIndex, QList<QPair<QString, int>> &childConstructs);
void writeMemberInits(const QStringList &keyList, const QList<QPair<QString, int>> &childConstructs); void writeMemberInits(const QStringList &keyList, const QList<QPair<QString, int>> &childConstructs);
void writeEntryPropertySignalConnects(const NodeContentGroup &node, const QStringList &keyList, int classIndex, QList<int> &listEntries); void writeEntryPropertySignalConnects(const NodeContentGroup &node, const QStringList &keyList, int classIndex, QList<int> &listEntries);
void writeEntryPropertySignalConnect(const EntryType &entry, QStringList keyList, int classIndex); void writeEntryPropertySignalConnect(const EntryType &entry, QStringList keyList, int classIndex);
void writeListEntryPropertySignalConnect(const ListEntryType &entry, QStringList keyList, QList<int> &listEntries); void writeListNodePropertySignalConnect(const ListNodeType &entry, QStringList keyList, QList<int> &listEntries);
void writeSource(const SettingsType &settings, int typeNum); void writeSource(const SettingsType &settings, int typeNum);

11
tools/settingsgenerator/qsettingsgenerator.xsd

@ -87,7 +87,6 @@
<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="ListNode" type="ListNodeType"/> <xs:element name="ListNode" type="ListNodeType"/>
<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>
@ -122,16 +121,6 @@
</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"/>

16
tools/settingsgenerator/settingsgeneratorimpl.cpp

@ -170,12 +170,9 @@ SettingsGeneratorBase::NodeContentGroup *SettingsGeneratorImpl::findContentGroup
*isEntry = true; *isEntry = true;
return &(nonstd::get<EntryType>(cNode)); return &(nonstd::get<EntryType>(cNode));
} }
} else if(nonstd::holds_alternative<ListEntryType>(cNode)) { } else if(nonstd::holds_alternative<ListNodeType>(cNode)) {
if(nonstd::get<ListEntryType>(cNode).key == key) { if(nonstd::get<ListNodeType>(cNode).key == key)
if(isEntry) return &(nonstd::get<ListNodeType>(cNode));
*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)
@ -214,11 +211,8 @@ void SettingsGeneratorImpl::fixTrContext(NodeContentGroup &group, const QString
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)) { } else if(nonstd::holds_alternative<ListNodeType>(node)) {
auto &entry = nonstd::get<ListEntryType>(node); fixTrContext(nonstd::get<ListNodeType>(node), context);
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);
} }

Loading…
Cancel
Save