Qt IVI Generator Addressbook Example

This example shows how to generate models using the Qt IVI Generator.

Introduction

This example shows how to generate a model using the model type in a qface file with the Qt IVI Generator.

It will only explain the details on how to use the model type and how it works internally. For a general introduction to the Qt IVI Generator, please have a look at the Qt IVI Generator Climate Example.

Walkthrough

The IDL file used in the example represents an addressbook API. It contains a single interface providing the contacts as a model and a struct definition for the actual contact.

interface AddressBook {
    model<Contact> contacts;

    void insertContact(int index, Contact contact);
}

struct Contact {
    string forename;
    string name;
    int phone;
}

The contact property is defined to be of type model<Contact>. The frontend template will create a C++ property of type QIviPagingModel*. The getter function of this property returns a valid instance once a backend is connected and the properties are initialized. This QIviPagingModel instance can be used from C++, as well as from QML and already provides the basic functionality for retrieving its data in an optimized fashion using the so called Pagination concept.

For the backend interface the property type is different and will be a QIviPagingModelInterface pointer. This is needed as the QIviPagingModel is also a QtIvi feature and, like all features, it uses a backend interface for the frontend-backend separation. For more information, see Concepts and Architecture.

The backend plugin needs to implement the QIviPagingModelInterface class for every exposed property. The backend_simulator template already takes care of this and generates all the needed code.

Configuring the Simulation Backend Plugin

By default the generated simulation backend does not populate any data for the model, as the template doesn't know what content it should provide.

For this use-case the default annotation can be used to configure the simulator to provide static simulation data.

This is done in the example-ivi-addressbook.yaml file:

Example.IVI.AddressBook:
    config_simulator:
        simulationFile: "qrc:/plugin_resource/simulation.qml"

Example.IVI.AddressBook.AddressBook#contacts:
    config_simulator:
        default: [[ "John", "Doe", "12345" ], [ "Jane", "Doe", "67890" ]]

The JSON fragment assigned to the default variable is parsed by the Qt IVI Generator and will be used to generate a simulation backend which creates two Contact instances and returns them as content for the contacts model.

Demo Application

The demo application is not autogenerated, but a standard QQmlEngine setup for an application similar to other examples.

ListView {
    Layout.fillWidth: true
    Layout.fillHeight: true
    model: addressBook.contacts
    clip: true

    delegate: ItemDelegate {
        width: parent.width
        height: 100
        text: model.item.forename + " " + model.item.name
    }
}

The model is retrieved from the addressbook object using the contacts property and passed to the ListView. The delegate can access the actual contact using the ItemRole of the QIviPagingModel, which is exposed to QML through model.item.

Extended Simulation Behavior

Because the backend_simulator template can only generated a stub, it doesn't know what behavior it should implement for the insertContact function of the qface file. The ivigenerator will simply generate a stub implementation printing a message that this function is not implemented.

This limitation is fixed by using the simulationFile annotation to tell the autogenerator we want to provide our own simulation QML file.

In the example the simulationFile annotation points to a QML file in a resource file. The resource file is added to the project file as usual like this:

RESOURCES += plugin_resource.qrc
Providing the simulation behavior in QML

The autogenerated simulation backend code loads the simulation behavior from a QML file using a QIviSimulationEngine. This special engine makes sure the autogenerated backend interfaces are provided to the QML file and they can be extended from there. It also makes sure that the interfaces are available only to this engine instance and to no other engine running in the same process (e.g. in the frontend). See the QIviSimulationEngine documentation for more information about how the engine works.

Using the ivigenerator for the simulation backend, the simulation interfaces are provided in the example.ivi.addressbook.simulation uri. The provided types are named after the backend interfaces implemented by the simulation backend. For our example two types are registered:

  • AddressBookBackend
  • ContactsModelBackend

Our simulation QML file looks like this:

import QtQuick 2.0
import Example.IVI.AddressBook.simulation 1.0

Item {
    AddressBookBackend {
        id: backend
        property var settings : IviSimulator.findData(IviSimulator.simulationData, "AddressBook")

        function initialize() {
            print("AddressBookSimulation INITIALIZE")
            IviSimulator.initializeDefault(settings, backend)
            Base.initialize()
        }

        function insertContact(reply, index, contact) {
            print("BACKEND SIMULATION INSERT CONTACT")
            contacts.insert(index, contact);
            reply.setSuccess(true);
        }

        Component.onCompleted: {
            console.log("BACKEND SIMULATION CREATED")
        }
    }
}

It creates an AddressBookBackend instance and prints a message once the QML code is loaded by using the Component.onCompleted handler.

To implement the behavior for the insertContact function, a JS function is added to the AddressBookBackend object in QML. This function takes three arguments, the first one is an PendingReply object used to notify the frontend once the request was successful or failed. The other arguments are as defined in the IDL file.

To insert the provided contact to our list we use the contacts property which hold the implementation of the QIviPagingModelInterface for the contacts property. This implementation provides some extra convenience functions which can be used by the simulation to modify the model in an easy way. In our case we just call the insert() function and let the autogenerated implementation do the rest.

Example project @ code.qt.io

© 2020 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.