From 29d4a846475bde6b167796c5052fa87b521a235b Mon Sep 17 00:00:00 2001 From: Skycoder42 Date: Fri, 27 Jul 2018 18:42:33 +0200 Subject: [PATCH] completed list node implementation for qml with tests --- src/mvvmcore/settingsentry.h | 3 +- tests/auto/auto.pro | 5 +- .../qmlsettingsgenerator/generatortest.xml | 30 ++- .../tst_qmlsettingsgenerator.qml | 100 +++++--- .../tst_qmlsettingsgenerator.qmlc | Bin 3816 -> 5868 bytes .../qmlsettingsgenerator.cpp | 241 ++++++++---------- .../settingsgenerator/qmlsettingsgenerator.h | 12 +- .../settingsgenerator/qsettingsgenerator.xsd | 11 - .../settingsgeneratorimpl.cpp | 16 +- 9 files changed, 207 insertions(+), 211 deletions(-) diff --git a/src/mvvmcore/settingsentry.h b/src/mvvmcore/settingsentry.h index c58bc85..7f875d1 100644 --- a/src/mvvmcore/settingsentry.h +++ b/src/mvvmcore/settingsentry.h @@ -176,6 +176,7 @@ public: // internal void setup(QString key, ISettingsAccessor *accessor, std::function setupFn); + void commit(int index); private: struct ElementHolder { @@ -189,8 +190,6 @@ private: ISettingsAccessor *_accessor = nullptr; std::function _setupFn; mutable QHash _cache; - - void commit(int index); }; // ------------- Generic Implementation ------------- diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 4e1bf1a..7e7eed6 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs -SUBDIRS += cmake mvvmcore \ - qml +SUBDIRS += cmake \ + mvvmcore \ + qml diff --git a/tests/auto/qml/qmlsettingsgenerator/generatortest.xml b/tests/auto/qml/qmlsettingsgenerator/generatortest.xml index 42ee0fe..1ea7015 100644 --- a/tests/auto/qml/qmlsettingsgenerator/generatortest.xml +++ b/tests/auto/qml/qmlsettingsgenerator/generatortest.xml @@ -64,15 +64,25 @@ {42} - - + - "Hello World" - { - "test1", - "test2", - "test3" - } - + + + + + + + + + + diff --git a/tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qml b/tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qml index ba1e524..33469f2 100644 --- a/tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qml +++ b/tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qml @@ -5,9 +5,21 @@ import de.skycoder42.QtMvvm.Core.test 4.2 Item { id: root - Component { - id: listElement - TestSettings_ListElement_8 {} + property string changeData: "" + Connections { + 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 { @@ -28,39 +40,65 @@ Item { compare(TestSettings.parentNode.parentEntryGroup.leafEntry, qsTr("translate me")); compare(TestSettings.variantEntry, undefined); 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 - compare(TestSettings.listEntry.length, 3); - verify(TestSettings.listEntry[0]); - compare(TestSettings.listEntry[0].value, "test1"); - verify(TestSettings.listEntry[1]); - compare(TestSettings.listEntry[1].value, "test2"); - verify(TestSettings.listEntry[2]); - compare(TestSettings.listEntry[2].value, "test3"); - verify(!TestSettings.listEntry[3]); + compare(TestSettings.listNode.length, 0); + verify(TestSettings.listNode_push()); + compare(TestSettings.listNode.length, 1); + + compare(TestSettings.listNode[0].simpleChild, false); + verify(TestSettings.listNode[0].someNode) + compare(TestSettings.listNode[0].someNode.deepChild, 22); + 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 elem = listElement.createObject(root, {value: "baum42"}); - verify(elem); - compare(elem.value, "baum42"); - TestSettings.listEntry.push(elem); - compare(TestSettings.listEntry.length, 4); - verify(TestSettings.listEntry[3]); - compare(TestSettings.listEntry[3].value, "baum42"); - verify(!TestSettings.listEntry[4]); + var newEntry2 = TestSettings.listNode_push_deferred(); + verify(newEntry2); + compare(TestSettings.listNode.length, 2); + verify(!TestSettings.listNode[2]); + compare(newEntry2.simpleChild, false); + newEntry2.simpleChild = true; + compare(newEntry2.simpleChild, true); + compare(TestSettings.listNode[0].simpleChild, false); + compare(TestSettings.listNode.length, 2); + TestSettings.listNode.push(newEntry2); + compare(TestSettings.listNode.length, 3); + compare(TestSettings.listNode[2], newEntry2); + compare(deepData, 0); - // test resetting - var elem2 = TestSettings.create_listEntry_element("newElem"); - verify(elem2); - 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]); + TestSettings.listNode = []; + compare(TestSettings.listNode.length, 0); + verify(!TestSettings.listNode[0]); } } diff --git a/tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qmlc b/tests/auto/qml/qmlsettingsgenerator/tst_qmlsettingsgenerator.qmlc index 6d97e5ffdbef38c33cd1d2129f4cb2192e2977e2..3be7102bc5687a34514c944742c8310793815008 100644 GIT binary patch literal 5868 zcmb`LOKe?78OP`P`aX|M?Z%ioK8bHqw{G0nzVR#0qcmw8LW^4(5=cr@T*vo1iQ>eL zeH}HTl`M#mkg~`ERRLuQ5(tDq%A$)Pv515~5eo!TL6PVJBtR@sMSIhf`2G5R7S7%si+c$sxhj;&a`^KrUl|RlOJ+s_=_^0px z>^DDr<;3BUJG=gNxch}1T+f4lHW`zL{v4=%V1FGgCi-RM_z&&Vj0tJ*Ucs0~s1YMg zJh#9T4aVFAEil~z@56L6<9M{PSD(vi11l|Uo)w{Qn;(awwjH02C|laT3(|OcA-yGu8@%h$nfDWbx-nj=;=2 zwIbdmNuHy0IkjS6`Iiq0||QM9;?GDv#zpGWjA!NAaPSlw0R}zblT0H!1fpypnqqD6aPc#lRSl z%=^JnZ~%M>90arAIq-F$n2^6!yMGK0fqUQu@C$GR{0fYN2S9s$2tEV;4UPd7-WMT{ zL0^Jyg?ei^b62$KuV!q>2_C{3+avmLKO4U zU3-g?JSj!a?a_=t?lW3txANKrg`N?TE6AXGrmlNFaeO}25d?)Mx1e)0v)T-SrW3Yl z>>ABDrlbmWrsUvSqaw;diIPPWC8TpwLX={@p`&=(nXGd(TNi{gv#$TB?bq*D=y|S? zIH{0Sy1^gtN)#7|&+c{P&HRtcL<(ObqCLeM^kQl`a@sjo(8M}0S* zwxg~Vh$jty3-NiH3*|51EsBcjL?+@>eblG&PiuWGTIO4A+5S4JnyS9eJj73iy|bnS z;{EdURkyqxE%ck|dwE-)k2#!~V1|&=S1`bY6Ud?NF;rsl55X zu6H9jE2sO`8>eL9`^MzzGHL8_=7qTB>N;qwgE=ADA~#`ASuwVwc)T4qqOye_zsa{` zQ^QSYnXSwHDY^mm-@pBI9~o-)dx4V^#>f zk3buWbb|`0f$QKlxC`!sk3ct%(OK{|_!hVe8c`qwyTJsgf!p9dSOLQba0A=}yE%LU zRKN{z8{7f+!2_@Ynz)#|!8oXZx4|9oTd)G!cnBT@CqWHd2j2yE!JohiXyh@{4aUJ4 zPy^S&kH9^!0vg+``u0b5I&NxU$z0%eyBJN$h8jP~4Yvs0PQSu;KfR0Q8k}>szrYJ* zkWulz%nR|VxkT>>vkR8H7Oj_WUWBL0yqfw8aLqBMrr4h5#l#)zMI*_)j?Ti3hP~CPvwa0T18^7GedQ`#-lk&bAcCG<$sdv<92a! zcwZkux<$@alb8x&d4G@=jJcSZB-bYGydp@RosM>Ke?P~3 zd*G85X5d<4?^=C7LOQYEAbiOvIl=DdtbDW43eqmYKLr0QJUT!2EG+!pX3STKx`O?e z+|zrZ#M`$-JWsL160#kLxZlxo`}dHy*IG;T<4Z+k70GJ6WL>7L9*w0r2Im|n%-elc zBV)PNM#jTsDzh$*s}k?@QayLq%ja$4WqTb@y(Lh&EuhKiP%s*RBh9Y^P#xi|C1mXMzm5A*CS{i~~_b@F-* z6{Sg;B(d(!%bczVJjJOxTUA~CB(L<6?5k_1d!wn2%36z724#E6`b+z(u3TZ}WaJOY zE8EI%TC-LnowLNas}iz8)!J6|Mm1jkk{lC!ug`XWPq?}?%$=n;5x;7ebkiGjZJbTA z=MuY}XHNc2o)g=g37X{d*_xbFocZxrt$sSQX5UPcR44tNsU|%(;#*xE+&QXN?k@1! zy8kP9xct7lDlZfj6>I-kJLTs3I6RNPm0yZL-T4E&&Qz<;@v9r*5>m*11NQcpENAVE zd?-u1asMh%G&}oiMs?mr_Z9Y;WyDe4JIPx`ZvpvQCyIXoPTdYQEVtPe{Sl|^{9i%# BoR0ti literal 3816 zcmb7`O>9(E6vyw(bUxm^mbTDBO9!Y(=}@Gd7OE|N&`1cHh(aL3LT#th89=7(&`v8P zE=*9vvI|2<+%z$MB*vtP3yCWhE?Ah@7#F%BE?lrO#1)B)`uo58-pp&M3Eb(w=bd}c zJ@O^y_bCANB_{8#F?#I1YF-+tBH_r?A5|8_;c`~3RK**`uRESN&) z+y5ky8Um|4#GrS9#?O{`R5Ggo6HJPKYm7mj1?^dm8`A)N0M+O~W*Iz+THgMTnLa&y z6!Y|G=Ru#B4$VtPZ5_T59sHTB<{1^x0UE_HPFvzp?G-QEQqUHY^H(1y-Z}ns3sih7 zklw9eJJ<$h;QX!{5=Fz3$K8k;1uWr?|}?h1iQe;U^lo0wD(KU4XhuTt!~mWslIJdIn(AQTie}$ z+YYy*#&u*mGdmHE1j`+nF4$FbU-HAT<3$+o>U?pdjHj)m6u zWqO#iHc@2VB>N_y%)JqgtNae)s`b537}veXDz5v0a@qqlw;#L!dcjGc8haNU0MkIV zdIP9NKLh>XdoTcg06Fjz&>i>%=nmZnhr!?A2x!2UVQ4#a1iBA83e7@~LWiL*LSKcx z1U&FJX)WLO99C*Q=*b_;*PLD~t>DEJTV`F2J3~h4V-shZX+KppW zyek{Wm_s22PH(>xiPv0-ht1sJODb?Cyg!|4s2RWoby{<7x_7{dq}>DuCc3f-J7**0 zI*p0+u}FH)elI>=^b(;XH=Gz8h|YS16+PeMq#+$1AVw`t_dG(!(Y$z#Kql(Xdp(YM z)uLo#%s--EE+t^7{nJ2eehc;b2kg4u@_)Sa>28QFfjGJorkf`XYp;E#e={%CM-p4= zqlq;k7!e+P6Y(kXRCZ~v?9!+Jo$J)@ZL$_Ct*4n6G}OQCP#0ZW({rHbX=tF&@wM5m zytXEP13mBfYnxHoAIyKq^TxO+-pajw3wjU6g>1o(EnX(<+-)3M26w?z(}i*($6bDY&VPrB;w*L`>$nWEQ`?fsZTYL+<-!sP9mrn+X$ z401Exirg<_nQS=0llBK|+NXC(VB=Xb!e9 z1Fuswbp9E*ve~HJTQ<#*z{hcFW!yVm*5 zdqrf9*lUpTn*Ezuru;2(!W{OL*du@Q*dvSP`6)jdlpZsRdKIY?UetAl>OwizO5V$* zr0sW79@`gd{!N8;*?7H%#xlQIdc=9}q%u3~P@aR@sh?)QiAvb23?Jpqte;MAT<3-LBdj-Ut2|Mj zHeWwUv}QTEA~Em#Z^pOjJXXkd-459p)~UG2_dHgI=apw=UDY)2*{W*muGOdR)m2u` z`T3N*a-+O!k8Vx4ZgkE9Gq(B^#UjtPKIhq^e9Mmd%?af{Etoy8bn&O0Me%C{h zxBdn9xUN%ms`GSX6&t-XWq%nRx`E<@`=#%*Ft6{lFt6`5`Cq_$MN<3TGLz>q6wz?g*M{7l%+1qjzJ!NJrReuZj#*6T> WS0_q-4oP*PDjnxZcl7&`^7B98fV^J- diff --git a/tools/settingsgenerator/qmlsettingsgenerator.cpp b/tools/settingsgenerator/qmlsettingsgenerator.cpp index 5d60e16..b336054 100644 --- a/tools/settingsgenerator/qmlsettingsgenerator.cpp +++ b/tools/settingsgenerator/qmlsettingsgenerator.cpp @@ -23,14 +23,12 @@ void QmlSettingsGenerator::process(const QString &inPath) if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) throw FileException{_hdrFile}; - _listTypes.clear(); auto typeNum = writeHeader(settings, QFileInfo{inPath}.completeBaseName() + QStringLiteral(".h")); _hdrFile.close(); if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text)) throw FileException{_srcFile}; writeSource(settings, typeNum); - _listTypes.clear(); _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" << "{\n" << "\tQ_OBJECT\n\n" + << "\tusing SelfType = " << _name << ";\n" + << "\t" << _cppName << " *_settings;\n" + << "\tQList _indexMap;\n\n" << "\tQ_PROPERTY(QtMvvm::ISettingsAccessor *accessor READ accessor CONSTANT FINAL)\n\n"; QList> childConstructs; QList listEntries; writeProperties(settings, keyList, childOffsets, listEntries, childConstructs); - _hdr << "\t" << _cppName << " *_settings;\n\n" - << "public:\n" + _hdr << "public:\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); - _hdr << "\t\t_settings{settings}\n" - << "\t{\n"; + _hdr << "\t{\n"; writeEntryPropertySignalConnects(settings, keyList, -1, listEntries); _hdr << "\t}\n\n" << "\texplicit " << _name << "(QObject *parent = nullptr) :\n" @@ -103,109 +103,67 @@ int QmlSettingsGenerator::writeHeader(const SettingsType &settings, const QStrin void QmlSettingsGenerator::writeListTypeBaseClass() { // write the generic variant - _hdr << "template \n" - << "class " << _name << "_ListType : public QObject\n" + _hdr << "template \n" + << "struct " << _name << "_ListData\n" << "{\n" - << "public:\n" - << "\ttemplate \n" - << "\tstruct ListData {\n" - << "\t\tstatic_assert(std::is_base_of<" << _name << "_ListType, TList>::value, \"TList must extend " << _name << "_ListType\");\n" - << "\t\tQtMvvm::SettingsListEntry &entry;\n" - << "\t\tQList 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" + << "\tTNodeValue &node;\n" + << "\tQList elements;\n\n" - << "\ttemplate \n" - << "\tstatic void adjust(ListData *data, QObject *parent, int size) {\n" + << "\tstatic void adjust(" << _name << "_ListData *data, QObject *parent, int size) {\n" << "\t\twhile(data->elements.size() > size)\n" << "\t\t\tdata->elements.takeLast()->deleteLater();\n" - << "\t\tfor(auto index = data->elements.size(); index < size; index++) {\n" - << "\t\t\tauto elem = new TList{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\tfor(auto index = data->elements.size(); index < size; index++)\n" + << "\t\t\tdata->elements.append(new TList{static_cast(parent)->_settings, static_cast(parent)->_indexMap, index, parent});\n" << "\t}\n\n" - << "\ttemplate \n" << "\tstatic void append(QQmlListProperty *list, TList *element) {\n" - << "\t\tconst auto data = reinterpret_cast*>(list->data);\n" - << "\t\tconst auto maxIndex = data->entry.size();\n" - << "\t\tadjust(data, list->object, maxIndex);\n" + << "\t\tconst auto data = reinterpret_cast<" << _name << "_ListData*>(list->data);\n" + << "\t\tconst auto maxIndex = data->node.size();\n" + << "\t\tadjust(data, list->object, maxIndex);\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\tif(copyDefault)\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\tdata->node.commit(maxIndex);\n" << "\t}\n\n" - << "\ttemplate \n" << "\tstatic TList *at(QQmlListProperty *list, int index) {\n" - << "\t\tconst auto data = reinterpret_cast*>(list->data);\n" + << "\t\tconst auto data = reinterpret_cast<" << _name << "_ListData*>(list->data);\n" << "\t\treturn data->elements.size() > index ? data->elements.value(index) : nullptr;\n" << "\t}\n\n" - << "\ttemplate \n" << "\tstatic int count(QQmlListProperty *list) {\n" - << "\t\treturn reinterpret_cast*>(list->data)->elements.size();\n" + << "\t\treturn reinterpret_cast<" << _name << "_ListData*>(list->data)->elements.size();\n" << "\t}\n\n" - << "\ttemplate \n" << "\tstatic void clear(QQmlListProperty *list) {\n" - << "\t\tconst auto data = reinterpret_cast*>(list->data);\n" + << "\t\tconst auto data = reinterpret_cast<" << _name << "_ListData*>(list->data);\n" << "\t\tfor(auto elem : qAsConst(data->elements))\n" << "\t\t\telem->deleteLater();\n" << "\t\tdata->elements.clear();\n" - << "\t\tdata->entry.reset(false);\n" + << "\t\tdata->node.reset();\n" << "\t}\n\n" - << "private:\n" - << "\tQtMvvm::SettingsListEntry *_entry = nullptr;\n" - << "\tint _index = -1;\n" - << "\tT _buffer{};\n" << "};\n\n"; } -std::tuple> QmlSettingsGenerator::writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset) +std::tuple> QmlSettingsGenerator::writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset, int listDepth) { QList offsetList; for(const auto &cNode : node.contentNodes) { if(nonstd::holds_alternative(cNode)) { - offset = writeNodeClass(nonstd::get(cNode), keyList, offset); + offset = writeNodeClass(nonstd::get(cNode), keyList, offset, listDepth); offsetList.append(offset - 1); } else if(nonstd::holds_alternative(cNode)) { if(!nonstd::get(cNode).contentNodes.isEmpty()) { - offset = writeNodeClass(nonstd::get(cNode), keyList, offset); - offsetList.append(offset - 1); - } else - offsetList.append(-1); - } else if(nonstd::holds_alternative(cNode)) { - offset = writeListEntryElementClass(nonstd::get(cNode), keyList, offset); - offsetList.append(offset - 1); //double offset!!! - if(!nonstd::get(cNode).contentNodes.isEmpty()) { - offset = writeNodeClass(nonstd::get(cNode), keyList, offset); + offset = writeNodeClass(nonstd::get(cNode), keyList, offset, listDepth); offsetList.append(offset - 1); } else offsetList.append(-1); + } else if(nonstd::holds_alternative(cNode)) { + offset = writeListNodeClass(nonstd::get(cNode), keyList, offset, listDepth); + offsetList.append(offset - 1); } else if(nonstd::holds_alternative(cNode)) { QList subList; - std::tie(offset, subList) = writeNodeContentClasses(nonstd::get(cNode), keyList, offset); + std::tie(offset, subList) = writeNodeContentClasses(nonstd::get(cNode), keyList, offset, listDepth); offsetList.append(subList); } else Q_UNREACHABLE(); @@ -213,27 +171,30 @@ std::tuple> QmlSettingsGenerator::writeNodeContentClasses(const 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); QList 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" << "{\n" - << "\tQ_OBJECT\n\n"; + << "\tQ_OBJECT\n\n" + << "\tusing SelfType = " << _name << "_" << offset << ";\n" + << "\t" << _cppName << " *_settings;\n" + << "\tconst QList &_indexMap;\n\n"; QList> childConstructs; QList listEntries; writeProperties(node, keyList, childOffsets, listEntries, childConstructs); - _hdr << "\t" << _cppName << " *_settings;\n\n" - << "public:\n" - << "\t" << _name << "_" << offset << "(" << _cppName << " *settings, QObject *parent) : \n" - << "\t\tQObject{parent},\n"; + _hdr << "public:\n" + << "\t" << _name << "_" << offset << "(" << _cppName << " *settings, const QList &indexMap, QObject *parent) : \n" + << "\t\tQObject{parent}\n" + << "\t\t,_settings{settings}\n" + << "\t\t,_indexMap{indexMap}\n"; writeMemberInits(keyList, childConstructs); - _hdr << "\t\t_settings{settings}\n" - << "\t{\n"; + _hdr << "\t{\n"; writeEntryPropertySignalConnects(node, keyList, offset, listEntries); _hdr << "\t}\n" << "};\n\n"; @@ -241,25 +202,32 @@ int QmlSettingsGenerator::writeNodeClass(const NodeType &node, QStringList keyLi 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); - const auto &mType = _typeMappings.value(entry.type, entry.type); - _hdr << "class " << _name << "_" << offset << " : public " << _name << "_ListType<" << mType << "> // " << keyList.join(QLatin1Char('/')) << " (list-element)\n" + keyList.append({node.key, QStringLiteral("at(_indexMap.at(%1))").arg(listDepth++)}); + QList childOffsets; + std::tie(offset, childOffsets) = writeNodeContentClasses(node, keyList, offset, listDepth); + + _hdr << "class " << _name << "_" << offset << " : public QObject // " << keyList.join(QLatin1Char('/')) << "\n" << "{\n" << "\tQ_OBJECT\n\n" - << "\tQ_PROPERTY(" << mType << " value READ value WRITE setValue NOTIFY valueChanged)\n\n" - << "public:\n" - << "\texplicit " << _name << "_" << offset << "(QObject *parent = nullptr) : \n" - << "\t\t" << _name << "_ListType{parent}\n" - << "\t{}\n\n" - << "\texplicit " << _name << "_" << offset << "(const " << mType << " &value, QObject *parent = nullptr) : \n" - << "\t\t" << _name << "_" << offset << "{parent}\n" - << "\t{\n" - << "\t\tsetValue(value);\n" - << "\t}\n\n" - << "Q_SIGNALS:\n" - << "\tvoid valueChanged(const " << mType << " &value);\n" + << "\tusing SelfType = " << _name << "_" << offset << ";\n" + << "\t" << _cppName << " *_settings;\n" + << "\tQList _indexMap;\n\n"; + + QList> childConstructs; + QList listEntries; + writeProperties(node, keyList, childOffsets, listEntries, childConstructs); + + _hdr << "public:\n" + << "\t" << _name << "_" << offset << "(" << _cppName << " *settings, const QList &indexMap, int index, QObject *parent) : \n" + << "\t\tQObject{parent}\n" + << "\t\t,_settings{settings}\n" + << "\t\t,_indexMap{QList{indexMap} << index}\n"; + writeMemberInits(keyList, childConstructs); + _hdr << "\t{\n"; + writeEntryPropertySignalConnects(node, keyList, offset, listEntries); + _hdr << "\t}\n" << "};\n\n"; return ++offset; @@ -272,11 +240,9 @@ void QmlSettingsGenerator::writeProperties(const NodeContentGroup &node, const Q writeNodeProperty(nonstd::get(cNode), childOffsets.takeFirst(), childConstructs); else if(nonstd::holds_alternative(cNode)) writeEntryProperty(nonstd::get(cNode), keyList, childOffsets.takeFirst(), childConstructs); - else if(nonstd::holds_alternative(cNode)) { - auto lIndex = childOffsets.takeFirst(); //done seperately because of undefine param call order - writeListEntryProperty(nonstd::get(cNode), keyList, lIndex, childOffsets.takeFirst(), childConstructs); - listEntries.append(lIndex); - _listTypes.insert(lIndex); + else if(nonstd::holds_alternative(cNode)) { + listEntries.append(childOffsets.first()); + writeListNodeProperty(nonstd::get(cNode), keyList, childOffsets.takeFirst(), childConstructs); } else if(nonstd::holds_alternative(cNode)) writeProperties(nonstd::get(cNode), keyList, childOffsets, listEntries, childConstructs); else @@ -301,12 +267,12 @@ void QmlSettingsGenerator::writeEntryProperty(const EntryType &entry, QStringLis _hdr << "\tQ_PROPERTY(" << mType << " " << entry.key << " READ get_" << 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" << "\tvoid set_" << entry.key << "(const " << mType << " &value) { _settings->" << keyList.join(QLatin1Char('.')) << ".set(value); }\n" << "Q_SIGNALS:\n" - << "\tvoid " << entry.key << "_changed(const " << mType << " &value);\n" + << "\tvoid " << entry.key << "Changed(const " << mType << " &value);\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"))); } -void QmlSettingsGenerator::writeListEntryProperty(const ListEntryType &entry, QStringList keyList, int listIndex, int classIndex, QList> &childConstructs) +void QmlSettingsGenerator::writeListNodeProperty(const ListNodeType &node, QStringList keyList, int classIndex, QList> &childConstructs) { - keyList.append(entry.key); - _hdr << "\tQ_PROPERTY(QQmlListProperty<" << _name << "_" << listIndex << "> " << entry.key - << " READ get_" << entry.key << " CONSTANT)\n" - << "\t" << _name << "_" << listIndex << "::ListData<" << _name << "_" << listIndex << "> _" << entry.key << ";\n" - << "\tQQmlListProperty<" << _name << "_" << listIndex << "> get_" << entry.key << "() {\n" + keyList.append(node.key); + _hdr << "\tusing ListData_" << classIndex << " = " << _name << "_ListData<" << _name << "_" << classIndex << ", SelfType, typename std::decay" << keyList.join(QLatin1Char('.')) << ")>::type>;\n" + << "\tfriend ListData_" << classIndex << ";\n" + << "\tQ_PROPERTY(QQmlListProperty<" << _name << "_" << classIndex << "> " << node.key + << " READ get_" << node.key << " CONSTANT)\n" + << "\tListData_" << classIndex << " _" << node.key << ";\n" + << "\tQQmlListProperty<" << _name << "_" << classIndex << "> get_" << node.key << "() {\n" << "\t\treturn {\n" - << "\t\t\tthis, &_" << entry.key << ",\n" - << "\t\t\t&" << _name << "_" << listIndex << "::append<" << _name << "_" << listIndex << ">,\n" - << "\t\t\t&" << _name << "_" << listIndex << "::count<" << _name << "_" << listIndex << ">,\n" - << "\t\t\t&" << _name << "_" << listIndex << "::at<" << _name << "_" << listIndex << ">,\n" - << "\t\t\t&" << _name << "_" << listIndex << "::clear<" << _name << "_" << listIndex << ">\n" + << "\t\t\tthis, &_" << node.key << ",\n" + << "\t\t\t&ListData_" << classIndex << "::append,\n" + << "\t\t\t&ListData_" << classIndex << "::count,\n" + << "\t\t\t&ListData_" << classIndex << "::at,\n" + << "\t\t\t&ListData_" << classIndex << "::clear\n" << "\t\t};\n" << "\t}\n" << "public:\n" - << "\tQ_INVOKABLE " << _name << "_" << listIndex << " *create_" << entry.key << "_element(const " << _typeMappings.value(entry.type, entry.type) << " &value) {\n" - << "\t\treturn new " << _name << "_" << listIndex << "{value, this};\n" + << "\tQ_INVOKABLE " << _name << "_" << classIndex << " *" << node.key << "_push_deferred() {\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" << "private:\n\n"; - childConstructs.append({entry.key, -1}); - - if(!entry.contentNodes.isEmpty()) - writeNodeProperty(entry, classIndex, childConstructs, entry.qmlGroupKey.value_or(entry.key + QStringLiteral("Group"))); + childConstructs.append({node.key, -1}); } void QmlSettingsGenerator::writeMemberInits(const QStringList &keyList, const QList> &childConstructs) { for(const auto &info : childConstructs) { 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 - _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 else if(nonstd::holds_alternative(cNode)) writeEntryPropertySignalConnect(nonstd::get(cNode), keyList, classIndex); - else if(nonstd::holds_alternative(cNode)) - writeListEntryPropertySignalConnect(nonstd::get(cNode), keyList, listEntries); + else if(nonstd::holds_alternative(cNode)) + writeListNodePropertySignalConnect(nonstd::get(cNode), keyList, listEntries); else if(nonstd::holds_alternative(cNode)) writeEntryPropertySignalConnects(nonstd::get(cNode), keyList, classIndex, listEntries); else @@ -376,19 +347,18 @@ void QmlSettingsGenerator::writeEntryPropertySignalConnect(const EntryType &entr << ".addChangeCallback(this, std::bind(&" << _name; if(classIndex >= 0) _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 &listEntries) +void QmlSettingsGenerator::writeListNodePropertySignalConnect(const ListNodeType &entry, QStringList keyList, QList &listEntries) { auto classIndex = listEntries.takeFirst(); keyList.append(entry.key); _hdr << "\t\t_settings->" << keyList.join(QLatin1Char('.')) - << ".addSizeChangeCallback(this, std::bind(&" - << _name << "_" << classIndex << "::adjust<" << _name << "_" << classIndex - << ">, &_" << entry.key << ", this, std::placeholders::_1));\n" - << "\t\t"<< _name << "_" << classIndex << "::adjust<" << _name << "_" << classIndex - << ">(&_" << entry.key << ", this, _settings->" << keyList.join(QLatin1Char('.')) << ".size());\n"; + << ".addChangeCallback(this, std::bind(&" + << "ListData_" << classIndex << "::adjust, &_" << entry.key << ", this, std::placeholders::_1));\n" + << "\t\t" << "ListData_" << classIndex << "::adjust" + << "(&_" << entry.key << ", this, _settings->" << keyList.join(QLatin1Char('.')) << ".size());\n"; } 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" << "{\n" << "\tconst QString msg{QStringLiteral(\"Settings-Helpertypes cannot be created\")};\n\n"; - 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"; - } + for(auto i = 0; i < typeNum; i++) + _src << "\tqmlRegisterUncreatableType<" << _name << "_" << i << ">(uri, major, minor, \"" << _name << "_" << i << "\", msg);\n"; + switch(mode) { case Singleton: _src << "\n\tqmlRegisterSingletonType<" << _name << ">(uri, major, minor, \"" << _cppName << "\", __create_qml_singleton);\n"; diff --git a/tools/settingsgenerator/qmlsettingsgenerator.h b/tools/settingsgenerator/qmlsettingsgenerator.h index c2388dd..72e17fc 100644 --- a/tools/settingsgenerator/qmlsettingsgenerator.h +++ b/tools/settingsgenerator/qmlsettingsgenerator.h @@ -25,15 +25,13 @@ private: QString _prefixName; QHash _typeMappings; - QSet _listTypes; - int writeHeader(const SettingsType &settings, const QString &inHdrPath); void writeListTypeBaseClass(); - std::tuple> writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset = 0); - int writeNodeClass(const NodeType &node, QStringList keyList, int offset); - int writeListEntryElementClass(const ListEntryType &entry, QStringList keyList, int offset); + std::tuple> writeNodeContentClasses(const NodeContentGroup &node, const QStringList &keyList, int offset = 0, int listDepth = 0); + int writeNodeClass(const NodeType &node, QStringList keyList, int offset, int listDepth); + int writeListNodeClass(const ListNodeType &entry, QStringList keyList, int offset, int listDepth); void writeProperties(const NodeContentGroup &node, const QStringList &keyList, @@ -42,12 +40,12 @@ private: QList> &childConstructs); void writeNodeProperty(const NodeType &entry, int classIndex, QList> &childConstructs, const QString &overwriteName = {}); void writeEntryProperty(const EntryType &entry, QStringList keyList, int classIndex, QList> &childConstructs); - void writeListEntryProperty(const ListEntryType &entry, QStringList keyList, int listIndex, int classIndex, QList> &childConstructs); + void writeListNodeProperty(const ListNodeType &entry, QStringList keyList, int classIndex, QList> &childConstructs); void writeMemberInits(const QStringList &keyList, const QList> &childConstructs); void writeEntryPropertySignalConnects(const NodeContentGroup &node, const QStringList &keyList, int classIndex, QList &listEntries); void writeEntryPropertySignalConnect(const EntryType &entry, QStringList keyList, int classIndex); - void writeListEntryPropertySignalConnect(const ListEntryType &entry, QStringList keyList, QList &listEntries); + void writeListNodePropertySignalConnect(const ListNodeType &entry, QStringList keyList, QList &listEntries); void writeSource(const SettingsType &settings, int typeNum); diff --git a/tools/settingsgenerator/qsettingsgenerator.xsd b/tools/settingsgenerator/qsettingsgenerator.xsd index b8be4cc..8d7ce02 100644 --- a/tools/settingsgenerator/qsettingsgenerator.xsd +++ b/tools/settingsgenerator/qsettingsgenerator.xsd @@ -87,7 +87,6 @@ - @@ -122,16 +121,6 @@ - - - - - - - - - - diff --git a/tools/settingsgenerator/settingsgeneratorimpl.cpp b/tools/settingsgenerator/settingsgeneratorimpl.cpp index d5f1b5b..036e8ad 100644 --- a/tools/settingsgenerator/settingsgeneratorimpl.cpp +++ b/tools/settingsgenerator/settingsgeneratorimpl.cpp @@ -170,12 +170,9 @@ SettingsGeneratorBase::NodeContentGroup *SettingsGeneratorImpl::findContentGroup *isEntry = true; return &(nonstd::get(cNode)); } - } else if(nonstd::holds_alternative(cNode)) { - if(nonstd::get(cNode).key == key) { - if(isEntry) - *isEntry = true; - return &(nonstd::get(cNode)); - } + } else if(nonstd::holds_alternative(cNode)) { + if(nonstd::get(cNode).key == key) + return &(nonstd::get(cNode)); } else if(nonstd::holds_alternative(cNode)) { auto res = findContentGroup(&(nonstd::get(cNode)), key); if(res) @@ -214,11 +211,8 @@ void SettingsGeneratorImpl::fixTrContext(NodeContentGroup &group, const QString if(!entry.trContext) entry.trContext = context; fixTrContext(entry, context); - } else if(nonstd::holds_alternative(node)) { - auto &entry = nonstd::get(node); - if(!entry.trContext) - entry.trContext = context; - fixTrContext(entry, context); + } else if(nonstd::holds_alternative(node)) { + fixTrContext(nonstd::get(node), context); } else if(nonstd::holds_alternative(node)) fixTrContext(nonstd::get(node), context); }