QVL is a Qt QML plugin that provides facilities for using, creating and modifying external data models for an end Qt QML application. QVL is based on VL and DMBCore libraries and inherit all their features.
It is generally accepted that data level should be separated from business logic, but not everyone knows the best way of doing that. In Qt data level is supported in different ways, but if you want a custom and complex data structure then you should write it with C++. Using a high-level programming language is considered as not the best solution for implementing data level of an application because all you need to do is to declare data structures, use them in your app, modify and store.
As you can note the operation list with data is constant. The only variable is the data itself so it looks like a task for an ordinary database system, however sometimes developers consider it as an overcomplicated solution to use database with SQL query mechanism and then the question arises: how to use the data directly in QML? Writing a new class which inherits QAbstractListModel or QObject for every new collection of items you want to represent on the screen sometimes take a majority of the development time and it becomes harder and harder to maintain such data level as it contains most of the whole C++ code of the project. On top of that it starts to look like not a task for a developer as it demands to write the same code over and over with the only difference in class and property names. This task should be automated and it is exactly what QVL does.
QVL takes the data from a JSON file, or from a model generated in the memory (not stored yet) and gives to the user:
thereby the step of creating a new data model C++ class is automated.
QVL significantly reduces time for developing QML applications because:
It becomes much more time for a developer to implement something more sophisticated that a data model.
Represents a database with interface to make basic operations with it and access its data.
Creatable type. Supposed to be declared and created in QML.
Item {
id: root
DMBModel {
id: dmbModel
loadFrom: "esources/database.json"
onModelLoaded: function(f) {
console.log("Database loaded from '" + currentFile + "'");
}
onModelLoadError: function(f, e) {
console.log("Database load error: '" + e + "'");
}
}
}
Type | Name | Description |
VLObjectVarModel | contentModel | Returns ListModel stored in the “content” field of DB |
VLObjectVarModel | typesModel | Returns ListModel stored in the “types” field of DB |
bool | isLoaded | Checks whether |
QString | currentFile | Returns a currently openned file name |
- (Only write) | loadFrom | Allows to load a model directly from declaration. Receives a path to a JSON file to load. |
Note: creator functions (createFromData, createObject, createList) create a standalone variable models.
Return type | Name | Parameters | Description |
bool | store | QString filePath = "", bool pretty = true | Store the model to a filePath. Use formatted output if true is passed to the second parameter |
bool | storeContent | QString filePath = "", bool pretty = true | Write only content without types sections. All types used as proto references will be expanded to objects containing all its properties |
bool | load | QString filePath | Load a model from a filePath |
VLVarModel | createFromData | QVariant data | Creates a standalone variable from the passed data. Any supported type is allowed. In case of objects and lists it will create a new one with the same (shared) data |
VLObjectVarModel | createObject | - | Creates an empty standalone Object |
VLListVarModel | createList | - | Creates an empty standalone List |
void | clear | - | Clear the model. All included models will be destroyed. Before destruction every model emits beforeRemove() signal and notifies its corresponding container model about changes |
bool | hasChanges | - | Check whether some changes in the whole data have occured |
Name | Parameters | Description |
contentModelChanged | - | Called when there are some changes in the data stored in the “content” field |
typesModelChanged | - | Called when there are some changes in the data stored in the “types” field |
currentFileChanged | - | Called when the data of currentFile property has been changed because of loading from a new file |
modelLoaded | QString filePath | Called when a model is successfully loaded using Load() function |
modelLoadError | QString filePath, QString error | Called when a model has not been loaded using Load() function because of an error |
modelStored | QString filePath | Called when a model is successfully stored using Store() function |
modelStoreError | QString filePath, QString error | Called when a model has not been stored using Store() function because of an error |
VLVarModel is both a base class for any variable model and a class representing variables of primitive types. The interface is common for every variable type through inheritance.
Type | Name | Description |
QString | id | Returns a parent’s object property id in which this variable is stored. If there is no parent then empty string will be returned |
QString | name | The same as id(). For convenience |
QVariant | value | For primitive types returns its value. For containers returns itself (pointer to “this” from C++ object) |
QVariant | valueStr | Returns value as a string. For objects it will return “{}”. For lists “[]” |
QVariant | typeStr | Returns string representation of a variable’s type. Variants are: "String", "Int", "Bool", "Object", "List", "Null" |
QVariant | parent | Returns a container variable model to which this variable belongs or null if it is a root or a standalone model. |
Type | type | Returns variable’s type. Types belong to ObjectProperty namespace are convirtible to Int. Variants are: ObjectProperty.String, ObjectProperty.Int, ObjectProperty.Bool, ObjectProperty.Object, ObjectProperty.List, ObjectProperty.Null |
QVariant | owner | Returns a DMBModel to which this variable belongs |
Return type | Name | Parameters | Description |
bool | remove | - | Destroys this variable and removes it from its parent |
bool | detachFromParent | - | Unlink this variable from its parent and turns it into a standalone model |
QVariant | copy | - | Returns a deep-copy of this variable. Return it as a standalone model |
Name | Parameters | Description |
idChanged | - | Called when id or name property is changed |
typeChanged | - | Called when type property is changed |
valueChanged | - | Called when value property is changed |
ownerChanged | DMBModel newOwner | Called when owner property is changed |
beforeRemove | - | Called before this variable is going to be destroyed |
removed | - | Called from the destructor of this variable when it is no longer belongs to its parent and if it is a container then its state is no longer valid |
parentChanged | - | Called when parent property is changed |
Represents a vl::Object type - associative container that stores its properties as pairs key-value when the key is a property’s id (or name) with String type. Inherits VLVarModel.
Type | Name | Description |
VLCollectionModel | propListModel | Returns properties its own as a ListModel |
QVariant | protoPropListModel | Returns its prototype properties as ListModel if this variable has a prototype in “proto” field |
QVariant | allProps | Returns all properties of this object including these inherited from the proto chain as a ListModel |
QVariant | protoId | Returns prototype string id if this object has such one. |
QVariant | typeId | Returns string id of this object in “types” collection if this object belongs to it (is a registered type). Otherwise the full path from the root node to this will be returned. Example of a path: "content.skillLibrary.[0]" Example of a type id: "fruit" |
Return type | Name | Parameters | Description |
void | add | QString propId, ObjectProperty.Type type | Adds a new model with propId and type. If the passed id is already taken then a suggested free id will be used instead |
bool | removeProp | QString propName | Removes a property with id propName from this object |
bool | removeAt | Int index | Removes a property with index (order) index from this object |
bool | has | QString propId | Checks wheter this object has a property with id propId in its allProps collection |
bool | hasOwn | QString propId | Checks wheter this object has a property with id propId in its propListModel collection |
QVariant | at | Int index | Returns a model stored at index. Creates a model on first call with index. If the index is out of range - null is returned. |
QVariant | get | QString propId | Returns a model stored with propId in allProps collection. Creates a model on first call with propId. If no property with such id exists - null is returned. |
QVariant | getOwn | QString propId | Returns a model stored with propId in propListModel. Creates a model on first call with propId. If no property with such id exists - null is returned. |
QVariant | set | QString propId, QVariant data | Creates or overwrites an own property with id propId passing a data as a value. Data can be of any primitive type or a model of any variable type (VLVarModel, VLObjectVarModel, VLListModel). Returns the newly created model |
void | instantiate | QString typeId, QString instanceName = "" | Creates an instance of a type typeId with name instanceName. If instanceName is not set then instantiateRequested signal with generated suggested name is called |
bool | setPrototype | QString protoId | Stores a reference to a prototype with id protoId into the “proto” property of this object. Returns false if
|
bool | setPrototype | VLObjectVarModel model | Stores the given model to the “proto” property of this object. Tries to copy data of model to the property “proto” on the data level. Returns false if a not suitable model has been passed. |
int | sizeOwn | - | Returns own property count (of propListModel) |
int | sizeAll | - | Returns all property count including inherited (of allProps) |
QString | freeId | QString desiredId | Finds a suggested id for given desiredId if such id is already occupied. If there is no such id among own properties then it is returned without changes. |
Name | Parameters | Description |
nameChanged | - | Called when name property is changed |
propListChanged | - | Called when the model returned by the property propListModel is changed |
protoPropListChanged | - | Called when the model returned by the property protoPropListModel is changed |
allPropListChanged | - | Called when the model returned by the property allProps is changed |
instantiateRequested | QString instId, QString protoId | Called after instantiate function is successfully invoked (a type with id protoId exists and a suggested instance id is successfully generated). instId holds a suggested (generated) or a desired (passed to instantiate) new instance id. Receiver should choose and do either:
|
instantiateRefused | QString error | Called when some error occurred during processing instantiate call. The reasons are:
|
instantiated | QString instId, QString protoId | Called from a successful call to instantiate function |
protoIdChanged | - | Called when the value returned by property protoId is changed |
typeIdChanged | - | Called when the value returned by property typeId is changed |
propAdded | QString propId | Called when a new property is added to this object |
propRemoved | QString propId | Called when a property is removed from this object |
Type | Name | Description |
QVariant | listModel | Returns ListModel containing all child models of this |
Return type | Name | Parameters | Description |
QVariant | at | int index | Returns a model stored at index. Creates a model on first call with index. If the index is out of range - null is returned |
QVariant | add | ObjectProperty.Type type, int indexBefore = -1 | Adds a new element of the given type to the end or at a custom position passed through indexBefore. Returns the newly created model |
QVariant | add | QVariant data, int indexBefore = -1 | Adds a new element with the given data to the end or at a custom position passed through indexBefore. Type is determined by the data type. Returns the newly created model |
bool | removeAt | int index | Removes a child element stored at index both from this model and from the data level (vl::List). Returns false if the given index is out of range |
QVariant | find | QVariant data | Searches for the given data in the list. The data can be of any supported type. If a model is passed then it will be found only if it is exactly that model (not a copy) |
void | instantiate | QString typeId | Creates an instance of a type typeId |
int | size | - | Returns count of all child elements |
Name | Parameters | Description |
listChanged | - | Called when the model returned by the property listModel is changed |
instantiated | QString instId | Called from a successful call to instantiate function |
instantiateRefused | QString error | Called when some error occurred during processing instantiate call. The reasons are:
|
It is a abstract C++ class that is inherited by VLCollectionModel, VLListModel. It does not represent a particular JavaScript model as it cannot be instantiated, but it declares and implements properties, functions and signals which are common for all of the derived classes.
Represents an interface of a storage of child elements or properties for container-type models (VLObjectVarModel, VLListVarModel).
Role | Access | Description |
id | R/W | String Id of an element if it is an object. Empty string is returned otherwise |
type | R/W | Type of a property. Variants are: ObjectProperty.String, ObjectProperty.Int, ObjectProperty.Bool, ObjectProperty.Object, ObjectProperty.List, ObjectProperty.Null |
typeStr | R | String representation of a variable’s type. Variants are: "String", "Int", "Bool", "Object", "List", "Null" |
value | R/W | For primitive types returns its value. For containers returns itself (pointer to “this” from C++ object) |
valueStr | R | Value as a string. For objects it will return “{}”. For lists “[]” |
parentModel | R | Reference to a parent container model (VLObjectVarModel or VLListVarModel) |
Type | Name | Description |
int | size | Returns its child elements count |
VLVarModel | parent | Returns its parent container to which this model belongs |
Return type | Name | Parameters | Description |
QVariant | at | int index | Returns a model stored at index. Creates a model on first call with index. If the index is out of range - null is returned |
bool | removeAt | int index | Removes a child element stored at index both from this model and from the data level (vl::List). Returns false if the given index is out of range |
Name | Parameters | Description |
onNameChanged | - | Called when the property id is changed |
onValueChanged | - | Called when the variable value is changed |
onTypeChanged | - | Called when the variable type is changed |
onModelChanged | int indexFirst, int indexLast = -1 | Called when models in range {indexFirst - indexLast} have been completely changed or shifted so the ListModel’s view should fully update them |
Represents a ListModel with an ordered list of properties. Serves as a storage for child elements of VLListVarModel.
All inherited from VLListModelInterface.
Only inherited from VLListModelInterface.
Return type | Name | Parameters | Description |
QVariant | add | ObjectProperty.Type type, int indexBefore = -1 | Adds a new element of the given type to the end or at a custom position passed through indexBefore. Returns the newly created model |
QVariant | add | QVariant data, int indexBefore = -1 | Adds a new element with the given data to the end or at a custom position passed through indexBefore. Type is determined by the data type. Returns the newly created model |
QVariant | find | QVariant data | Searches for the given data in the list. The data can be of any supported type. If a model is passed then it will be found only if it is exactly that model (not a copy) |
Only inherited from VLListModelInterface.
Represents a ListModel with associative collection of properties. Serves as a storage for properties of VLObjectVarModel.
Role | Access | Description |
name | R/W | String Id of a property |
Only inherited from VLListModelInterface
Return type | Name | Parameters | Description |
bool | has | QString propId | Checks wheter this collection has a property with id propId among its properties |
QVariant | get | QString propId | Returns a model stored with propId in this collection. Creates a model on first call with propId. If no property with such id exists - null is returned. |
QVariant | set | QString propId, QVariant data | Creates or overwrites a property with id propId passing a data as a value. Data can be of any primitive type or a model of any variable type (VLVarModel, VLObjectVarModel, VLListModel). Returns the newly created model |
QVariant | add | QString propId, ObjectProperty.Type type | Adds a new model with propId and type, and return it. If the passed id is already taken then a suggested free id wil be used instead |
QVariant | add | ObjectProperty.Type type | Adds a new model with desired name “New prop”. If this name exists then a suggested free id will be taken |
bool | remove | QString propId | Removes a property with id propId from this collection |
bool | removeAt | int index | Removes a property with the given index (order) from this object |
Name | Parameters | Description |
nameAlreadyTaken | - | Called when tring to change name |
Item {
id: root
DMBModel {
id: dmbModel
loadFrom: "resources/database.json"
onModelLoaded: function(f) {
console.log("Database loaded from '" + currentFile + "'");
}
onModelLoadError: function(f, e) {
console.log("Database load error: '" + e + "'");
}
}
}
Lets look how to use QVL on a real example. In the section below we demonstrate a ready QVL app which you can create according to video instructions.
The full example project is available for clone and download on GitHub
This test application creates a model using QVL JavaScript interface, then stores that model and load it from the same file.
The app declares a view through which it displays fruitList variable content and orange object property list (as on the following screen).
import QtQuick
import QtQuick.Window
import QVLTestUI 1.0
Window {
width: 640
height: 480
visible: true
QVLTestUI {
id: uiRoot
width: root.width
height: root.height
}
}
import QtQuick
import QVLTestUI 1.0
import QVL 1.0
Item {
width: Constants.width
height: Constants.height
property var contentModel: null
property var typesModel: null
property var orange: null
property var fruitListModel: null
property var test: function () {
contentModel = dmbModel.contentModel;
typesModel = dmbModel.typesModel;
orange = dmbModel.createObject();
var fruit = dmbModel.createObject();
var fruitList = dmbModel.createList();
var color = dmbModel.createFromData("green");
var size = dmbModel.createFromData(2.4);
fruit.set("isFruit", true);
fruit.set("color", color);
fruit.set("size", size);
fruit.set("title", "Fruit");
fruit = dmbModel.typesModel.set("fruit", fruit);
var pear = dmbModel.createObject();
pear.setPrototype(fruit);
orange.setPrototype("fruit");
pear.set("color", "yellow");
pear.set("size", 3.2);
pear.set("title", "Pear");
orange.set("title", "Orange");
orange.set("color", "orange");
orange.set("size", "4.1");
fruit = fruitList.add(fruit);
pear = fruitList.add(pear);
orange = fruitList.add(orange);
fruitList = contentModel.set("fruitList", fruitList);
fruitListModel = fruitList.listModel;
var color = fruit.get("color").value;
console.log("Fruit color: " + color
+ ", size: " + fruit.get("size").value);
console.log("Pear color: " + pear.get("color").value
+ ", size: " + pear.get("size").value
+ ", is fruit? " + (pear.get("isFruit").value ? "yes" : "no")
);
if (dmbModel.store("database.json"))
console.log("Database successfully stored")
else
console.log("Error! Can’t store the model");
if (dmbModel.load("database.json"))
console.log("Database successfully loaded")
else
console.log("Error! Can’t load the model");
// Update local variables after reload the model
contentModel = dmbModel.contentModel;
typesModel = dmbModel.typesModel;
fruitList = contentModel.get("fruitList");
fruitListModel = fruitList.listModel;
orange = fruitList.at(2);
screen.update();
}
// Declare a database
DMBModel {
id: dmbModel
}
// Run the test
Component.onCompleted: function() {
test();
}
// Declare a screen with visual example
Screen01 {
id: screen
}
}
import QtQuick
import QtQuick.Controls
import QVLTestUI 1.0
import QVL 1.0
Rectangle {
width: Constants.width
height: Constants.height
color: Constants.backgroundColor
Text {
anchors.centerIn: parent
font.family: Constants.font.family
}
// Create a ListView of a list
Row
{
ListView {
id: fruitListView
height: 200
width: 100
model: null
delegate: Row {
width: parent.width;
height: 20
Text {
id: fruitTitle
text: value.get("title").value
}
Item {
id: spacer
width: 10
height: 10
}
Rectangle {
id: fruitColor
width: 20
height: 20
color: value.get("color").value
}
}
}
// Create a ListView of an object
ListView {
id: orangePropListView
height: 200
width: 100
model: null
delegate: Row {
width: parent.width;
height: 20
Text {
id: propId
text: name
}
Item {
id: spacer2
width: 10
height: 10
}
Text {
id: propValue
text: valueStr
}
}
}
}
property var update: function() {;
orangePropListView.model = orange.allProps;
fruitListView.model = fruitListModel;
}
Component.onCompleted: update
}
{
"content": {
"fruitList": [
{
"title": "Fruit",
"isFruit": true,
"color": "green",
"size": 2.0
},
{
"proto": "fruit",
"title": "Pear",
"color": "yellow",
"size": 3.0
},
{
"proto": "fruit",
"title": "Orange",
"color": "orange",
"size": "4.1"
}
]
},
"types": {
"fruit": {
"title": "Fruit",
"isFruit": true,
"color": "green",
"size": 2.0
}
},
"private": {}
}
DataModelBuilder is a graphical application based on Qt in conjunction with QVL plugin which serves as a GUI client for database and data model design. All VL usage for DataModelBuilder is encapsulated into QVL library and there is no need to use C++, but only for few functions written especially for this application for working with URLs.
SkillBuilder is an example of end application that uses QVL for working with data models and has no C++ code, but has a rich functional implemented for its purposes using Qt’s QML in conjunction with QVL.