Browse Source

completed generator doc

pull/2/head 1.1.0
Skycoder42 6 years ago
parent
commit
d1e76ac0b9
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 5
      deploy.json
  2. 4
      doc/Doxyfile
  3. 336
      doc/qsettingsgenerator.dox
  4. 38
      doc/settingsxml.dox
  5. 86
      doc/snippets/generatortest.xml
  6. 2
      mkspecs/features/qsettingstranslator.prf
  7. 2
      src/mvvmcore/mvvmcore.pro
  8. 4
      tools/settingsgenerator/qsettingsgenerator.xsd

5
deploy.json

@ -20,5 +20,8 @@
"installs": {
"ProjectTemplate": "Tools/QtCreator/share/qtcreator/templates/wizards/projects/qtmvvm",
"qbs/Qt/settingsgenerator": "Tools/QtCreator/share/qtcreator/qbs/share/qbs/modules/Qt/settingsgenerator"
}
},
"hostbuilds": [
"bin/qsettingsgenerator*"
]
}

4
doc/Doxyfile

@ -999,7 +999,9 @@ EXCLUDE_SYMBOLS = QtMvvm::__helpertypes \
# command).
EXAMPLE_PATH = ../examples \
./snippets
./snippets \
../src/settingsconfig \
../tools/settingsgenerator
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and

336
doc/qsettingsgenerator.dox

@ -0,0 +1,336 @@
/*!
@page settings_generator The qsettingsgenerator Tool
@brief A tool to generate static, typesafe settings access without having to type key strings
@tableofcontents
The general idea is that instead of this:
@code{.cpp}
QSettins settings;
int value = settings.value("my/key", 42).toInt();
@endcode
You create a settings file like this:
@code{.xml}
<Settings name="Settings">
<Node key="my">
<Entry key="key" type="int" default="42"/>
</Node>
</Settings>
@endcode
And can now access the data like this:
@code{.cpp}
int value = Settings::instance()->my.key;
@endcode
So in summary: First, using QSettings requires you to type in
strings as keys - which cannot be checked by the compiler. With this tool you get a c++ member
hirachie instead - which is checked by the compiler and thus typo free. Also, the values in
the settings are made statically typed by using this generator. The second point was to support
multiple backends, not only QSettings, without having to change the frontend code.
@section settings_generator_features Features
- Access settings via code - no more typos and redundant strings!
- Static typing gives additionl saftey and is easier to use (no `.toType()` calls needed)
- Default values in one single, central place - less error prone and easier to maintain
- Can be specified as strings in the xml
- Can be specified as C++ code in the xml
- Use as a global single instance or create local instances
- Support for custom settings backends instead of QSettings alone
- QtMvvm::QSettingsAccessor for usage with QSettings (the default)
- QtMvvm::DataSyncSettingsAccessor to sync settings via [QtDataSync](https://github.com/Skycoder42/QtDataSync)
- QtMvvm::AndroidSettingsAccessor (android only) to access the SharedPreferences
- Can be used as an injectable service
@section settings_generator_usage Usage
Using QtMvvmCore adds a custom qmake compiler to you project. All you need to do is to create the settings xml
definition and then add it to the pro file as `SETTINGS_DEFINITIONS += mysettings.xml`. This will create a header
named "mysettings.h" you can include. That header contains the C++ generated settings class to access the settings.
@subsection settings_generator_usage_example Example
Create a pro file with and add the lines:
@code{.pro}
QT += mvvmcore
SETTINGS_DEFINITIONS += mysettings.xml
@endcode
Create a file named `mysettings.xml` and fill it:
@code{.xml}
<?xml version="1.0" encoding="UTF-8" ?>
<Settings name="MySettings">
<Node key="my">
<Entry key="key" type="int" default="42"/>
</Node>
</Settings>
@endcode
Finally, adjust you main to look like this:
@code{.cpp}
#include <QCoreApplication>
#include <QDebug>
#include "mysettings.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int myKey = MySettings::instance()->my.key;
qDebug() << myKey;
return 0;
}
@endcode
@section settings_generator_qml QML-Bindings
The tool can also generate QML-Bindings, so you can access the settings in the same way from
QML. To do so, add to your pro file (in addition to `SETTINGS_DEFINITIONS`):
@code{.pro}
QML_SETTINGS_DEFINITIONS += mysettings.xml
@endcode
And also add some QML metadata using the Qml element in the settings
@code{.xml}
<?xml version="1.0" encoding="UTF-8" ?>
<Settings name="MySettings">
<Qml uri="com.example.settings"
major="1"
minor="0"/>
<!-- ... -->
</Settings>
@endcode
And with that, you can use the specified uri to access the settings from QML:
@code{.qml}
import com.example.settings 1.0
SomeItem {
someProperty: MySettings.my.key
}
@endcode
@section settings_generator_format XML-Format Documentation
The following sections document the different elements and attributes in the XML format used
by the generator.
@subsection settings_generator_elements Elements
The possible elements of such a file.
@subsubsection settings_generator_elements_Settings Settings
The root Element of the XML document. It defines meta-stuff and the actual nodes and entries.
@paragraph settings_generator_elements_Settings_attributes Attributes
Name | Type | Default/Required | Description
------------|-----------------------------------------------|-----------------------|-------------
name | string | _filename_ | The C++ class name of the generated class
prefix | string | _empty_ | Specify an export macro. The value is put before the class definition, if you want to export the generated class from a dynamic library
baseKey | string | _empty_ | A base settings key that is prepended to all keys
scope | @ref settings_generator_values_InstanceScope | DestroyOnAppDestroy | The destruction scope of the create service instance
@paragraph settings_generator_elements_Settings_children Child elements
Name | XML-Type | Limits | Description
----------------|-----------------------------------------------|-----------|-------------
Include | @ref settings_generator_elements_Include | 0 - ∞ | A header file to be included
Backend | @ref settings_generator_elements_Backend | 0 - 1 | The definition of the settings backend to use
Qml | @ref settings_generator_elements_Qml | 0 - 1 | Special configuration parameters for the QML bindings
TypeMapping | @ref settings_generator_elements_TypeMapping | 0 - ∞ | Type mappings to map abstract type names to C++ types
&lt;node&gt; | @ref settings_generator_elements_NodeContent | 0 - ∞ | General "node-like" elements, that can be inside any node-like element
@subsubsection settings_generator_elements_Include Include
Describes a file to be included via a c++ include directive. You can use them if you want to
make use of special classes in your generated classes. Both global includes (#include <header>)
and local includes (#include "header") are supported.<br/>
@paragraph settings_generator_elements_Include_attributes Attributes
Name | Type | Default/Required | Description
--------|-------|-------------------|-------------
local | bool | false | Specifies whether the include is a global or a local include
@paragraph settings_generator_elements_Include_children Content
The content of this element must be a string. More specific the header to be included. It
becomes the content of the include directive. Specifiy it without the braces or quores, as thoes
are added automatically.
@subsubsection settings_generator_elements_Backend Backend
The backend element can be used to select a different QtMvvm::ISettingsAccessor instead of the
standard QtMvvm::QSettingsAccessor.
@paragraph settings_generator_elements_Backend_attributes Attributes
Name | Type | Default/Required | Description
--------|-----------|-------------------|-------------
class | string | _required_ | The C++ class name of the backend to be used. Must be a class that implements QtMvvm::ISettingsAccessor
@paragraph settings_generator_elements_Backend_children Child elements
Name | XML-Type | Limits | Description
--------|-------------------------------------------|-----------|-------------
Param | @ref settings_generator_elements_Param | 0 - ∞ | A parameter to be passed to the backends constructor, before the QObject* parent
@subsubsection settings_generator_elements_Param Param
A generic parameter to be passed to C++ method.
@paragraph settings_generator_elements_Param_attributes Attributes
Name | Type | Default/Required | Description
--------|-----------|-------------------|-------------
type | string | _required_ | The C++ class name of type of the parameter.
asStr | bool | false | Specify how the element content should be interpreted
@paragraph settings_generator_elements_Param_children Content
The content of a param represents the value of the parameter. How the content is interpreted
depends on the asStr attribute.
If it is set to false (the default), the content must be c++ code and is copied to the generated
class as is. The code must be an expression that evalutes to a single value that is implicitly
convertible to the given type. If type was for example int, valid expressions could be:
@code{.xml}
<Param type="int">-1</Param>
<Param type="int">10 + 20</Param>
<Param type="int">qRand()</Param>
@endcode
If set to true, the content is assumed to be a string. You don't need to specify quotation
marks around the string. That string is used to initialize a QVariant that is then converted to
type - in other words, the type you use must be variant convertible from a string. This can be
used to, for example, create a QDate from a string with the value of
`<Param type="QDate" asStr="true">2018-05-09</Param>`.<br/>
@subsubsection settings_generator_elements_Qml Qml
The Qml element contains special properties that are only used for QML binding generation.
@paragraph settings_generator_elements_Qml_attributes Attributes
Name | Type | Default/Required | Description
------------|-------------------------------------------------------|-------------------|-------------
uri | string | _required_ | The QML-Import URI for the QML module
major | int | 1 | The major version of the generated module
minor | int | 0 | The minor version of the generated module
type | @ref settings_generator_values_QmlRegistrationMode | Singleton | The mode on how to register the instance in QML
register | bool | true | Specify, if the type should be registered automatically
header | string | _empty_ | A custom path to the generate C++-Code of the settings generator, if it can't be the default path
@subsubsection settings_generator_elements_TypeMapping TypeMapping
Type mappings allow you to specify the C++-type of an arbitrary type to be replaced by in the
generated code. This can be useful when importing a @ref settings_xml "Settings-XML" file.
@paragraph settings_generator_elements_TypeMapping_attributes Attributes
Name | Type | Default/Required | Description
--------|-----------|-------------------|-------------
key | string | _required_ | The fake type name
type | string | _required_ | The C++-type to replace it with
@subsubsection settings_generator_elements_NodeContent NodeContent Elements
Elements that have the NodeContent as child type can have a combination of the following
actual child elements. Can can be unordered and mixed in any way:
- @ref settings_generator_elements_Node
- @ref settings_generator_elements_Entry
- @ref settings_generator_elements_ListNode
- @ref settings_generator_elements_Import
@subsubsection settings_generator_elements_Node Node
The node represents a sub-group within the settings. All elements within the node will have
the node's key prepended to their key (seperated by a `/`)
@paragraph settings_generator_elements_Node_attributes Attributes
Name | Type | Default/Required | Description
--------|-----------|-------------------|-------------
key | string | _required_ | The name (and group key) of the node
@paragraph settings_generator_elements_Node_children Child elements
Name | XML-Type | Limits | Description
----------------|-----------------------------------------------|-----------|-------------
&lt;node&gt; | @ref settings_generator_elements_NodeContent | 0 - ∞ | General "node-like" elements, that can be inside any node-like element
@subsubsection settings_generator_elements_Entry Entry
The Entry element is an extension of the @ref settings_generator_elements_Node type. This
means it's the same as a Node, but with additional properties.
The entry represents a leaf entry in the settings, with a value that can be loaded and stored
from the settings via the entry's key (within the node subgroups). Entries themselves can also
be used as a node as well, and thus contain child elements, too.
The default value can be specified in 2 ways. Either as a string (via the attribute) that is
converted to the target type using QVariant, or via the `<Code>` child element, that contains
actual C++-Code that evaluates to a default value.
@sa QtMvvm::SettingsEntry
@paragraph settings_generator_elements_Entry_attributes Attributes
Name | Type | Default/Required | Description
------------|-----------|-------------------|-------------
type | string | _required_ | The C++-type that this entry saves and loads. Can be a virtual type, that is resolved by a @ref settings_generator_elements_TypeMapping
qmlGroupKey | string | `<key>Group` | The name the property that holds the entries sub-nodes for the QML binding
default | string | _empty_ | A default value (as string) to be returned if the entry is not stored in the settings
tr | bool | false | Specify whether the default value should be translated
trContext | string | _filename_ | A custom translation context to use instead of the filename
@paragraph settings_generator_elements_Entry_children Additional Child elements
Name | XML-Type | Limits | Description
--------|---------------------------------------|-----------|-------------
Code | @ref settings_generator_elements_Code | 0 - 1 | C++-Code to create a default value
@subsubsection settings_generator_elements_ListNode ListNode
The ListNode element is an extension of the @ref settings_generator_elements_Node type. This
means it's the same as a Node, but with additional properties.
The ListNode is a special node that allows you to easily store lists of elements. All children
that are defined within a listnode are part of the "array elements", so you will access
elements in a list node via `listNode[2].group.entry` and can append and remove elements from
that list.
@sa QtMvvm::SettingsListNode
@subsubsection settings_generator_elements_ImportType ImportType
The Imports allow you to include other files within this one as sub elements. You can include
either a Settings-Generator-XML (this file) or a @ref settings_xml "Settings-XML". The
imported file is then treated like it's contents where simply defined instead of the import
element, allowing seemless combination of different files.
You can use the rootNode to instead of importing the root element in the importet file, go
down to the node that matches the key defined by rootNode and only import that part.
@paragraph settings_generator_elements_ImportType_attributes Attributes
Name | Type | Default/Required | Description
------------|-----------|-------------------|-------------
required | bool | true | Specify, if the import is required or optional
rootNode | string | _empty_ | A root node withing the imported file to use as a starting point
@paragraph settings_generator_elements_ImportType_children Content
The content of the element is a string - the path to the file to be imported. If the path is
a relative path, it is resolved relative to the file that is importing it, aka "this" file.
@subsection settings_generator_values XML-Types
The XML-Types are not elements, but values of attributes etc. that have been defined for the
file.
@subsubsection settings_generator_values_InstanceScope InstanceScope
InstanceScope is a simple enum with the following allowed values:
Name | Description
----------------------------|-------------
DestroyOnAppQuit | Sets the scope of the created mvvm service to QtMvvm::ServiceRegistry::DestroyOnAppQuit
DestroyOnAppDestroy | Sets the scope of the created mvvm service to QtMvvm::ServiceRegistry::DestroyOnAppDestroy
DestroyOnRegistryDestroy | Sets the scope of the created mvvm service to QtMvvm::ServiceRegistry::DestroyOnRegistryDestroy
DestroyNever | Sets the scope of the created mvvm service to QtMvvm::ServiceRegistry::DestroyNever
@subsubsection settings_generator_values_QmlRegistrationMode QmlRegistrationMode
InstanceScope is a simple enum with the following allowed values:
Name | Description
----------------|-------------
Singleton | Register the QML type as a singleton instance
Uncreatable | Register the QML type as a uncreatable type
Creatable | Register the QML type as a normal, constructable type
@section settings_generator_sample Sample settings generator XML file
The following code block is a sample of a settings generator XML file. It's a little bigger to
show of the capabilities
@include generatortest.xml
@section settings_xml_xsd The XSD for the settings files
The following file is the XSD the parser operates on. You can use it to verify your settings
xml files.
@include qsettingsgenerator.xsd
*/

38
doc/settingsxml.dox

@ -9,18 +9,24 @@ QtMvvm::ISettingsSetupLoader. The files are read via that service and mapped to
QtMvvm::SettingsElements::Setup.
@section settings_xml_translator Translations
All the settings files you have can be easily translated via a standard ts/qm file. In order for
this to work, all you have to do is add the following lines to your pro file:
All the settings files you have can be easily translated via a standard ts/qm file. The following
explains how exactly.
The mvvm core module comes with a special make taget, called `lupdate` that will automatically
run lupdate when your sources change to update the TRANSLATIONS files. To not run this automatically,
call qmake with `qmake CONFIG+=no_auto_lupdate ...`. In both cases, you can always run `make lupdate`
to explicitly update the dependencies.
With this step enabled, the only thing left to do is to add the settings xml file to the translation
targets so it gets included as a source when running the lupdate target. To do so, simply add it
to the `SETTINGS_TRANSLATIONS` qmake variable:
@code{.pro}
QTMVVM_TS_SETTINGS += settings.xml
_never_true_condition: SOURCES += $$files($$PWD/.ts-dummy/*)
PRE_TARGETDEPS += qtmvvm-tsgen #optional
SETTINGS_TRANSLATIONS += settings.xml
@endcode
This will automatically generate a dummy cpp file in the `.ts-dummy` folder for each file
added to the `QTMVVM_TS_SETTINGS` variable. These files contain dummy code that will then be
read by lupdate automatically and added to all your ts files.
This will internally generate a cpp file that is parsed and included in lupdate when running it
via the builtin lupdate target.
@section settings_xml_elements Elements
The possible elements of such a file
@ -162,6 +168,7 @@ long as for the last two their type is `object`
key | string | <i>Required</i> | no | The key of the property
type | @ref settings_xml_types_type | <i>Required</i> | no | The type of the properties value
tr | bool | `false` | no | Specify whether the properties value (content) should be translated. Does not apply to `list` or `object` types
ztr | bool | `false` | no | Like tr, but does not translate the text, only generate the translation in the ts file
@subsubsection settings_xml_elements_property_elements Content
@ -185,6 +192,7 @@ same.
--------|-------------------------------|-------------------|---------------|-------------
type | @ref settings_xml_types_type | <i>Required</i> | no | The type of the list element
tr | bool | `false` | no | Specify whether the element value (content) should be translated. Does not apply to `list` or `object` types
ztr | bool | `false` | no | Like tr, but does not translate the text, only generate the translation in the ts file
@subsubsection settings_xml_elements_element_elements Content
The content depend on the `type` attribute. The following tables shows which type leads
@ -206,9 +214,11 @@ element must be a `<Group>` element (Each element that support includes as one c
marked as primary). It is possible to specify an include element in another included document.
@subsubsection settings_xml_elements_include_attribs Attributes
Name | Type | Default | Translated | Description
------------|-------|-----------|---------------|-------------
optional | bool | `false` | no | An optional include. If the file cannot be found it is skipped instead of aborting with an error
Name | Type | Default | Translated | Description
------------|---------------------------------------|---------------|---------------|-------------
optional | bool | `false` | no | An optional include. If the file cannot be found it is skipped instead of aborting with an error
frontends | @ref settings_xml_types_descriptor | <i>Empty</i> | no | @copybrief QtMvvm::SettingsElements::Entry::frontends
selectors | @ref settings_xml_types_descriptor | <i>Empty</i> | no | @copybrief QtMvvm::SettingsElements::Entry::selectors
@subsubsection settings_xml_elements_include_elements Content
The content of the include element must be a path to an XML file to be read as include. If the
@ -300,4 +310,10 @@ The following code block is a sample settings XML file. It is the same that is b
the example application.
@include settings.xml
@section settings_xml_xsd The XSD for the settings files
The following file is the XSD the parser operates on. You can use it to verify your settings
xml files.
@include settingsconfig.xsd
*/

86
doc/snippets/generatortest.xml

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Settings name="TestSettings"
prefix="SOME_EXPORT"
baseKey="tests"
scope="DestroyOnAppQuit">
<Include>QtCore/QDateTime</Include>
<Include local="false">QtCore/QUrl</Include>
<Include local="true">testbackend.h</Include>
<Backend class="TestBackend">
<Param type="QString" asStr="true">Test Backend</Param>
<Param type="int">42</Param>
</Backend>
<TypeMapping key="range" type="int"/>
<Node key="emptyNode"/>
<Entry key="emptyEntry"
type="bool"/>
<Entry key="advancedEntry"
type="QString"
qmlGroupKey="qmlAdvancedEntry"
default="Hello World"
tr="true"
trContext="some_context"/>
<Entry key="codeEntry"
type="QUrl">
<Code>QUrl::fromLocalFile(QStringLiteral("/path/to/something"))</Code>
</Entry>
<Node key="parentNode">
<Node key="emptyChildNode"/>
<Node key="fullChildNode">
<Entry key="replaceEntry"
type="range"
default="42"/>
</Node>
<Entry key="parentEntry"
type="bool"
default="true">
<Node key="subNode"/>
<Entry key="nodeWithCodeEntry"
type="int">
<Node key="someNode"/>
<Code>
qRound(42.8)
</Code>
</Entry>
<Entry key="leafEntry"
type="QString"
default="translate me"
tr="true"/>
</Entry>
</Node>
<Entry key="voidEntry"
type="void"/>
<Entry key="variantEntry"
type="QVariant"/>
<Entry key="simpleListEntry"
type="QList&lt;int&gt;">
<Code>{42}</Code>
</Entry>
<ListNode key="listNode">
<Entry key="simpleChild"
type="bool"/>
<Node key="someNode">
<Entry key="deepChild"
type="int"
default="22"/>
<Entry key="deepParent"
type="QString"
default="___">
<Entry key="simpleChild"
type="bool"
default="true"/>
</Entry>
</Node>
<ListNode key="childList">
<Entry key="valueEntry"
type="double"
default="4.2"/>
</ListNode>
</ListNode>
</Settings>

2
mkspecs/features/qsettingstranslator.prf

@ -31,7 +31,7 @@ QSETTINGSTRANSLATOR_DIR = $$QSETTINGSTRANSLATOR_DIR$$SUFFIX
lupdate_trcond_c.variable_out = TRANSLATIONS_CONDITION
lupdate_trcond_c.commands = echo created > ${QMAKE_FILE_OUT}
lupdate_trcond_c.output = $$QSETTINGSTRANSLATOR_DIR/trcond.cpp
lupdate_trcond_c.CONFIG += combine no_link
lupdate_trcond_c.CONFIG += combine no_link explicit_dependencies
QMAKE_EXTRA_COMPILERS += lupdate_trcond_c
lupdate_fakepri_c.name = fakepri ${QMAKE_FILE_IN}

2
src/mvvmcore/mvvmcore.pro

@ -42,7 +42,7 @@ SOURCES += \
settingsconfigloader.cpp
android {
#QT += androidextras
QT += androidextras
HEADERS += \
androidsettingsaccessor.h \

4
tools/settingsgenerator/qsettingsgenerator.xsd

@ -100,9 +100,7 @@
<xs:complexType name="ListNodeType" qxg:declare="true">
<xs:complexContent>
<xs:extension base="NodeType">
<xs:attribute name="listEntry" type="xs:boolean" default="false" use="optional"/>
</xs:extension>
<xs:extension base="NodeType"/>
</xs:complexContent>
</xs:complexType>

Loading…
Cancel
Save