Qt Variable Library (QVL)

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.

Features

Intention

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.

Developing process improvements

Speed up

QVL significantly reduces time for developing QML applications because:

Less C++ code

It becomes much more time for a developer to implement something more sophisticated that a data model.

JS Interface

Terminology

Notes

DMBModel

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.

Example

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 + "'");

                }

        }

}

Properties

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.

Functions

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

Signals

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

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.

Properties

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

Functions

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

Signals

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

VLObjectVarModel

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.

Properties

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"

Functions

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

  • the object with typeId has not been found,
  • this object has no owner.

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.

Signals

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:

  • Call instantiate with given arguments,
  • Call instantiate with its own arguments,
  • Reject instantiation (do nothing)

instantiateRefused

QString error

Called when some error occurred during processing instantiate call. The reasons are:

  • Type with passed protoId is not found
  • Can’t generate a suggested id for the new instance

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

VLListVarModel

Properties

Type

Name

Description

QVariant

listModel

Returns ListModel containing all child models of this

Functions                        

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

Signals

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:

  • Type with passed protoId is not found

VLListModelInterface

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).

Roles

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)

Properties

Type

Name

Description

int

size

Returns its child elements count

VLVarModel

parent

Returns its parent container to which this model belongs

Functions

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

Signals                        

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

VLListModel

Represents a ListModel with an ordered list of properties. Serves as a storage for child elements of VLListVarModel.

Roles

All inherited from VLListModelInterface.

Properties

Only inherited from VLListModelInterface.

Functions

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)

Signals

Only inherited from VLListModelInterface.

VLCollectionModel

Represents a ListModel with associative collection of properties. Serves as a storage for properties of VLObjectVarModel.

Roles

Role

Access

Description

name

R/W

String Id of a property

Properties

Only inherited from VLListModelInterface

Functions

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

Signals

Name

Parameters

Description

nameAlreadyTaken

-

Called when tring to change name

Usage

Declare a database

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 + "'");

                }

        }

}

Application using QVL example

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

Output

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).

main.qml

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

        }

}

QVLTestUI.qml

import QtQuick

import QVLTestUI 1.0

Import QVL

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 () {

Create a variable

                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);

 

Set a property

                fruit.set("isFruit", true);

                fruit.set("color", color);

                fruit.set("size", size);

                fruit.set("title", "Fruit");

 

Register a type

                fruit = dmbModel.typesModel.set("fruit", fruit);

 

Set a prototype

                var pear = dmbModel.createObject();

                pear.setPrototype(fruit);

                orange.setPrototype("fruit");

 

Override a property

                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");

 

Add to a list

                fruit = fruitList.add(fruit);

                pear = fruitList.add(pear);

                orange = fruitList.add(orange);

 

Add to the content

                fruitList = contentModel.set("fruitList", fruitList);

                fruitListModel = fruitList.listModel;

 

Get a property

                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")

                                );

 

Store a database

                if (dmbModel.store("database.json"))

                        console.log("Database successfully stored")

                else

                        console.log("Error! Can’t store the model");

 

Load a database

                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

        }

}

Screen01.ui.qml

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

}

 

Generated database.json

{

    "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": {}

}

Projects using QVL

DataModelBuilder

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

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.