SailfishOS integration C++ with QML

How to integrate C++ objects with QML / QNetworkRequest with signals and slots

Introduction

My first development experience with Jolla (SailFishOS).

Warming up

Lately I got opportunity to became a happy owner of Jolla smartphone. Quickly I found SDK provided to develop own application and started researching it. It appearead that Jolla runs SailffishOS which uses extensively Qt with Qt-Quick / QML. Documentation provides an examples of first app: https://sailfishos.org/develop-firstapp-article.html worked well. However, I had a zero experience with QML itself so a following links were a good reading straight after:

Development

When I start develop my own application a first real problem which I have encountered was exchanging data between QML and Qt.  Here comes documentation of Qt:

and:

Quoting from the documentation:

Registering an Instantiable Object Type

Any QObject-derived C++ class can be registered as the definition of a QML object type. Once a class is registered with the QML type system, the class can be declared and instantiated like any other object type from QML code. Once created, a class instance can be manipulated from QML; as Exposing Attributes of C++ Types to QML explains, the properties, methods and signals of any QObject-derived class are accessible from QML code.

To register a QObject-derived class as an instantiable QML object type, call qmlRegisterType() to register the class as QML type into a particular type namespace. Clients can then import that namespace in order to use the type.

I have created a new type BusReader:

 Full header file:

#ifndef BUSREADER_H
#include <QObject>

#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif

#include <QGuiApplication>
#include <QQuickView>
#include <QtQml>
#define BUSREADER_H

class BusReader: public QObject {
    Q_OBJECT
    
public:
    Q_INVOKABLE bool postMessage(const QString &msg);
    Q_INVOKABLE QString getBus(const QString &msg);
    Q_PROPERTY(QString html   READ html   WRITE setHtml   NOTIFY htmlChanged)
    const QString html ( ) const;
    void setHtml(const QString &newHtml);

public slots:
    void refresh();
    void handleNetworkData(QNetworkReply *networkReply);

private:
    QNetworkAccessManager networkManager;
    QString s_html;

signals:
    void htmlChanged();

};
#endif // BUSREADER_H

Full source file:

#include "BusReader.h"

 bool BusReader::postMessage(const QString &msg) {
    qDebug() << "Called the C++ method with" << msg;
    return true;
}

 QString BusReader::getBus(const QString &msg) {
    //QString str = "Hello";
     QNetworkRequest newRequest("http://www.tmb.cat/piu/ca_ES/piuimodesolucio.jsp?parada="+msg);
     networkManager.get(newRequest);
     connect(&networkManager, SIGNAL(finished(QNetworkReply*)),
                 this, SLOT(handleNetworkData(QNetworkReply*)));
    return msg;
 }

 void BusReader::handleNetworkData(QNetworkReply *networkReply)
 {
     QUrl url = networkReply->url();
     if (!networkReply->error()) {

         QString response = QString::fromLatin1(networkReply->readAll());
         qDebug() << response;
         response = response.replace("bgcolor=\"#99CCFF\"","");
         setHtml(response);
     }

     networkReply->deleteLater();
 }


 const QString BusReader :: html ( ) const {
     return s_html;
 }

void BusReader::setHtml(const QString &newHtml)
{
     s_html = newHtml;
     emit htmlChanged ();
}

void BusReader::refresh() {
    qDebug() << "Called the C++ slot";
}

Registered it as following in a main source file:

int main(int argc, char *argv[])
{
    QGuiApplication * q_application = SailfishApp :: application ( argc, argv );
       QQuickView * q_view = SailfishApp :: createView ( );
       qmlRegisterType <BusReader> ( "com.saildev.components", 1, 0, "BusReader" );
       q_view -> setSource ( SailfishApp :: pathTo ( "qml/BarcelonaBus.qml" ));
       q_view -> showFullScreen ( );
       return q_application -> exec ( );
}

 Also, corresponding QML file:

import QtQuick 2.0
import Sailfish.Silica 1.0
import com.saildev.components 1.0

Page {
    property string code_txt
    id: page
    BusReader {
        id: test_BusReader
    }

    SilicaListView {
        id: listView
        model: 20
        anchors.fill: parent
        header: PageHeader {
            title: qsTr(test_BusReader.getBus(code_txt))
        }

        Column {
            id: column
            width: page.width
            spacing: Theme.paddingLarge

        Label {
            id:     busTable
            focus: true
            textFormat: Text.RichText
            text: test_BusReader.html
            VerticalScrollDecorator {}
        }
}
}

Full project can be found here: https://github.com/bluszcz/BarcelonaBus/

More documentation (for QObject but also for Signas and Slots mechanism):

Happy sailing!