KeineAhnung
6th December 2015, 14:29
Hi,
I am really stuck with my code. My plan is to write a c++ class for my mobile app (Sailfish OS) that looks if a xml file is stored on the device, if so if is up to date by comparing it with one on a web server. When not up to date than to download it. The result shall be display with QML.
The class is done and does what I want but I have trouble to integrate it into QML. One thing is that some functions are accessible from QML and others are not and I do not see why. Accessible are load(), replyFinished() and getHeaders(). The other is that the return of load() is emitted before the network things are done. How can I change that?
.h
#ifndef XMLFILEHANDLER_H
#define XMLFILEHANDLER_H
#include <QObject>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QStandardPaths>
#include <QTextStream>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDateTime>
#include <QDebug>
class XmlFileHandler : public QObject
{
Q_OBJECT
public:
explicit XmlFileHandler(QObject *parent = 0);
Q_PROPERTY(int fileStat READ fileStat WRITE setFileStat NOTIFY fileStatChanged)
Q_INVOKABLE int load();
Q_INVOKABLE int fileStat();
Q_INVOKABLE QString filePath();
// Q_INVOKABLE bool setFilePath(const QString &file);
void setFileStat(int curStat);
QString fileName;
signals:
void fileStatChanged(int stat);
public slots:
void replyFinished (QNetworkReply *reply);
void getHeaders (QNetworkReply *reply);
private:
int stat;
QDir fileLocation;
QUrl url;
QFileInfo xmlInfo;
QNetworkAccessManager *manager;
QNetworkAccessManager *headManager;
};
#endif // XMLFILEHANDLER_H
.cpp
#include "xmlfilehandler.h"
XmlFileHandler::XmlFileHandler(QObject *parent) : QObject(parent){
fileLocation = QDir(QStandardPaths::writableLocation(QStandardPat hs::DataLocation));
url = QUrl("http://myURI/my.xml");
xmlInfo = QFileInfo(fileLocation.filePath("my.xml"));
stat = 0;
}
int XmlFileHandler::load(){
manager = new QNetworkAccessManager(this);
headManager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
connect(headManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(getHeaders(QNetworkReply*)));
if (xmlInfo.exists()) {
// Check if local file is up to date
headManager->head(QNetworkRequest(url));
} else {
qDebug() << "Need to download something here";
qDebug() << QDir().mkpath(fileLocation.path());
manager->get(QNetworkRequest(url));
}
qDebug() << stat;
return stat;
}
void XmlFileHandler::replyFinished(QNetworkReply *reply){
if(reply->error()) {
qDebug() << "ERROR!";
qDebug() << reply->errorString();
stat = -1;
fileStatChanged(stat);
}else{
QFile *file = new QFile(fileLocation.filePath(my.xml"));
if(file->open(QIODevice::ReadWrite | QIODevice::Truncate)){
QTextStream out(file);
out << reply->readAll();
qDebug() << out.status();
file->close();
stat = 2;
fileStatChanged(stat);
}else{
qDebug() << "Error opening file" << file->errorString();
stat = -1;
fileStatChanged(stat);
}
}
reply->deleteLater();
}
void XmlFileHandler::getHeaders(QNetworkReply *reply){
if (reply->operation() == QNetworkAccessManager::HeadOperation){
qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDate Time();
qDebug() << xmlInfo.lastModified().toLocalTime();
if(xmlInfo.lastModified().toLocalTime()>reply->header(QNetworkRequest::LastModifiedHeader).toDate Time()){
qDebug() << "No need for Update";
stat = 1;
fileStatChanged(stat);
}else{
qDebug() << "Update required";
manager->get(QNetworkRequest(url));
}
}else{
stat = -1;
fileStatChanged(stat);
}
reply->deleteLater();
}
QString XmlFileHandler::filePath(){
return fileLocation.filePath("ausbildung.xml");
}
int XmlFileHandler::fileStat(){
return stat;
}
void XmlFileHandler::setFileStat(const int curStat){
stat = curStat;
fileStatChanged(stat);
}
main.qml
import QtQuick 2.0
import Sailfish.Silica 1.0
import "pages"
import harbour.Test 1.0
ApplicationWindow
{
initialPage: Component { FirstPage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: Orientation.All
_defaultPageOrientations: Orientation.All
XmlFileHandler {
id: handler;
}
}
page.qml
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
// To enable PullDownMenu, place our content in a SilicaFlickable
SilicaFlickable {
anchors.fill: parent
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
PullDownMenu {
MenuItem {
text: qsTr("Check for Update")
onClicked: {
handler.load()
console.log(handler.fileStat()) //<- Not working
}
}
}
// Tell SilicaFlickable the height of its content.
contentHeight: column.height
// Place our content in a Column. The PageHeader is always placed at the top
// of the page, followed by our content.
Column {
id: column
width: page.width
spacing: Theme.paddingLarge
PageHeader {
title: qsTr("UI Template")
}
Text {
id: stat
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeSmall
width: parent.width-Theme.paddingLarge
wrapMode: Text.Wrap
text: "hier:"+handler.filePath() // <- not picked up by auto complete but works
}
}
}
}
Thanks
I am really stuck with my code. My plan is to write a c++ class for my mobile app (Sailfish OS) that looks if a xml file is stored on the device, if so if is up to date by comparing it with one on a web server. When not up to date than to download it. The result shall be display with QML.
The class is done and does what I want but I have trouble to integrate it into QML. One thing is that some functions are accessible from QML and others are not and I do not see why. Accessible are load(), replyFinished() and getHeaders(). The other is that the return of load() is emitted before the network things are done. How can I change that?
.h
#ifndef XMLFILEHANDLER_H
#define XMLFILEHANDLER_H
#include <QObject>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QStandardPaths>
#include <QTextStream>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDateTime>
#include <QDebug>
class XmlFileHandler : public QObject
{
Q_OBJECT
public:
explicit XmlFileHandler(QObject *parent = 0);
Q_PROPERTY(int fileStat READ fileStat WRITE setFileStat NOTIFY fileStatChanged)
Q_INVOKABLE int load();
Q_INVOKABLE int fileStat();
Q_INVOKABLE QString filePath();
// Q_INVOKABLE bool setFilePath(const QString &file);
void setFileStat(int curStat);
QString fileName;
signals:
void fileStatChanged(int stat);
public slots:
void replyFinished (QNetworkReply *reply);
void getHeaders (QNetworkReply *reply);
private:
int stat;
QDir fileLocation;
QUrl url;
QFileInfo xmlInfo;
QNetworkAccessManager *manager;
QNetworkAccessManager *headManager;
};
#endif // XMLFILEHANDLER_H
.cpp
#include "xmlfilehandler.h"
XmlFileHandler::XmlFileHandler(QObject *parent) : QObject(parent){
fileLocation = QDir(QStandardPaths::writableLocation(QStandardPat hs::DataLocation));
url = QUrl("http://myURI/my.xml");
xmlInfo = QFileInfo(fileLocation.filePath("my.xml"));
stat = 0;
}
int XmlFileHandler::load(){
manager = new QNetworkAccessManager(this);
headManager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
connect(headManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(getHeaders(QNetworkReply*)));
if (xmlInfo.exists()) {
// Check if local file is up to date
headManager->head(QNetworkRequest(url));
} else {
qDebug() << "Need to download something here";
qDebug() << QDir().mkpath(fileLocation.path());
manager->get(QNetworkRequest(url));
}
qDebug() << stat;
return stat;
}
void XmlFileHandler::replyFinished(QNetworkReply *reply){
if(reply->error()) {
qDebug() << "ERROR!";
qDebug() << reply->errorString();
stat = -1;
fileStatChanged(stat);
}else{
QFile *file = new QFile(fileLocation.filePath(my.xml"));
if(file->open(QIODevice::ReadWrite | QIODevice::Truncate)){
QTextStream out(file);
out << reply->readAll();
qDebug() << out.status();
file->close();
stat = 2;
fileStatChanged(stat);
}else{
qDebug() << "Error opening file" << file->errorString();
stat = -1;
fileStatChanged(stat);
}
}
reply->deleteLater();
}
void XmlFileHandler::getHeaders(QNetworkReply *reply){
if (reply->operation() == QNetworkAccessManager::HeadOperation){
qDebug() << reply->header(QNetworkRequest::LastModifiedHeader).toDate Time();
qDebug() << xmlInfo.lastModified().toLocalTime();
if(xmlInfo.lastModified().toLocalTime()>reply->header(QNetworkRequest::LastModifiedHeader).toDate Time()){
qDebug() << "No need for Update";
stat = 1;
fileStatChanged(stat);
}else{
qDebug() << "Update required";
manager->get(QNetworkRequest(url));
}
}else{
stat = -1;
fileStatChanged(stat);
}
reply->deleteLater();
}
QString XmlFileHandler::filePath(){
return fileLocation.filePath("ausbildung.xml");
}
int XmlFileHandler::fileStat(){
return stat;
}
void XmlFileHandler::setFileStat(const int curStat){
stat = curStat;
fileStatChanged(stat);
}
main.qml
import QtQuick 2.0
import Sailfish.Silica 1.0
import "pages"
import harbour.Test 1.0
ApplicationWindow
{
initialPage: Component { FirstPage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: Orientation.All
_defaultPageOrientations: Orientation.All
XmlFileHandler {
id: handler;
}
}
page.qml
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
// To enable PullDownMenu, place our content in a SilicaFlickable
SilicaFlickable {
anchors.fill: parent
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
PullDownMenu {
MenuItem {
text: qsTr("Check for Update")
onClicked: {
handler.load()
console.log(handler.fileStat()) //<- Not working
}
}
}
// Tell SilicaFlickable the height of its content.
contentHeight: column.height
// Place our content in a Column. The PageHeader is always placed at the top
// of the page, followed by our content.
Column {
id: column
width: page.width
spacing: Theme.paddingLarge
PageHeader {
title: qsTr("UI Template")
}
Text {
id: stat
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeSmall
width: parent.width-Theme.paddingLarge
wrapMode: Text.Wrap
text: "hier:"+handler.filePath() // <- not picked up by auto complete but works
}
}
}
}
Thanks