1
0
Fork 0

Working on snapshot save/loading

This commit is contained in:
James Turner 2017-05-10 08:54:21 +01:00
parent 2a95e09a09
commit 78b0d9c91e
7 changed files with 177 additions and 9 deletions

View file

@ -137,8 +137,8 @@ void FGQCanvasFontCache::lookupFile(QByteArray name)
reply->setProperty("font", name); reply->setProperty("font", name);
connect(reply, &QNetworkReply::finished, this, &FGQCanvasFontCache::onFontDownloadFinished); connect(reply, &QNetworkReply::finished, this, &FGQCanvasFontCache::onFontDownloadFinished);
// connect(reply, &QNetworkReply::error, this, &FGQCanvasFontCache::onFontDownloadError); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(onFontDownloadError(QNetworkReply::NetworkError)));
m_transfers.append(reply); m_transfers.append(reply);
} }

View file

@ -19,6 +19,10 @@
#include <QDebug> #include <QDebug>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
class TransferSignalHolder : public QObject class TransferSignalHolder : public QObject
{ {
@ -43,8 +47,11 @@ void FGQCanvasImageLoader::onDownloadFinished()
if (!pm.loadFromData(reply->readAll())) { if (!pm.loadFromData(reply->readAll())) {
qWarning() << "image loading failed"; qWarning() << "image loading failed";
} else { } else {
qDebug() << "did download:" << reply->property("image").toByteArray(); QByteArray imagePath = reply->property("image").toByteArray();
m_cache.insert(reply->property("image").toByteArray(), pm); m_cache.insert(imagePath, pm);
// cache on disk also, so snapshots work
writeToDiskCache(imagePath, reply);
TransferSignalHolder* signalHolder = reply->findChild<TransferSignalHolder*>("holder"); TransferSignalHolder* signalHolder = reply->findChild<TransferSignalHolder*>("holder");
if (signalHolder) { if (signalHolder) {
@ -57,6 +64,23 @@ void FGQCanvasImageLoader::onDownloadFinished()
reply->deleteLater(); reply->deleteLater();
} }
void FGQCanvasImageLoader::writeToDiskCache(QByteArray imagePath, QNetworkReply* reply)
{
QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
QString absPath = cacheDir.absoluteFilePath(imagePath);
QFileInfo finfo(imagePath);
cacheDir.mkpath(finfo.dir().path());
QFile f(absPath);
if (!f.open(QIODevice::WriteOnly)) {
qWarning() << "failed to open cache file" << f.fileName();
}
f.write(reply->readAll());
f.close();
}
void FGQCanvasImageLoader::setHost(QString hostName, int portNumber) void FGQCanvasImageLoader::setHost(QString hostName, int portNumber)
{ {
m_hostName = hostName; m_hostName = hostName;
@ -70,6 +94,15 @@ QPixmap FGQCanvasImageLoader::getImage(const QByteArray &imagePath)
return m_cache.value(imagePath); return m_cache.value(imagePath);
} }
QString diskCachePath = QStandardPaths::locate(QStandardPaths::CacheLocation, imagePath);
if (!diskCachePath.isEmpty()) {
QPixmap pix;
pix.load(diskCachePath);
m_cache.insert(imagePath, pix);
qDebug() << "loaded from on-disk cache:" << imagePath;
return pix;
}
QUrl url; QUrl url;
url.setScheme("http"); url.setScheme("http");
url.setHost(m_hostName); url.setHost(m_hostName);
@ -82,7 +115,6 @@ QPixmap FGQCanvasImageLoader::getImage(const QByteArray &imagePath)
} }
} }
qDebug() << "requesting image" << url;
QNetworkReply* reply = m_downloader->get(QNetworkRequest(url)); QNetworkReply* reply = m_downloader->get(QNetworkRequest(url));
reply->setProperty("image", imagePath); reply->setProperty("image", imagePath);

View file

@ -50,6 +50,7 @@ signals:
private: private:
void onDownloadFinished(); void onDownloadFinished();
void writeToDiskCache(QByteArray imagePath, QNetworkReply *reply);
private: private:
QNetworkAccessManager* m_downloader; QNetworkAccessManager* m_downloader;

View file

@ -20,6 +20,18 @@
#include <QJsonValue> #include <QJsonValue>
#include <QDebug> #include <QDebug>
QDataStream& operator<<(QDataStream& stream, const NameIndexTuple& nameIndex)
{
stream << nameIndex.name << nameIndex.index;
return stream;
}
QDataStream& operator>>(QDataStream& stream, NameIndexTuple& nameIndex)
{
stream >> nameIndex.name >> nameIndex.index;
return stream;
}
LocalProp *LocalProp::getOrCreateWithPath(const QByteArray &path) LocalProp *LocalProp::getOrCreateWithPath(const QByteArray &path)
{ {
if (path.isEmpty()) { if (path.isEmpty()) {
@ -119,6 +131,41 @@ void LocalProp::changeValue(const char *path, QVariant value)
p->valueChanged(value); p->valueChanged(value);
} }
void LocalProp::saveToStream(QDataStream &stream) const
{
stream << _id << _position << _value;
stream << static_cast<int>(_children.size());
for (auto child : _children) {
child->saveToStream(stream);
}
}
LocalProp* LocalProp::restoreFromStream(QDataStream &stream, LocalProp* parent)
{
NameIndexTuple id;
stream >> id;
LocalProp* prop = new LocalProp(parent, id);
stream >> prop->_position >> prop->_value;
int childCount;
stream >> childCount;
for (int c=0; c< childCount; ++c) {
prop->_children.push_back(restoreFromStream(stream, prop));
}
return prop;
}
void LocalProp::recursiveNotifyRestored()
{
emit valueChanged(_value);
for (auto child : _children) {
emit childAdded(child);
}
for (auto child : _children) {
child->recursiveNotifyRestored();
}
}
LocalProp *LocalProp::getOrCreateChildWithNameAndIndex(const NameIndexTuple& ni) LocalProp *LocalProp::getOrCreateChildWithNameAndIndex(const NameIndexTuple& ni)
{ {

View file

@ -22,12 +22,16 @@
#include <QVariant> #include <QVariant>
#include <QVector> #include <QVector>
#include <QObject> #include <QObject>
#include <QDataStream>
struct NameIndexTuple struct NameIndexTuple
{ {
QByteArray name; QByteArray name;
unsigned int index = 0; unsigned int index = 0;
NameIndexTuple()
{}
NameIndexTuple(const char* nm, unsigned int idx) : NameIndexTuple(const char* nm, unsigned int idx) :
name(nm), name(nm),
index(idx) index(idx)
@ -66,8 +70,12 @@ struct NameIndexTuple
return name < other.name; return name < other.name;
} }
}; };
QDataStream& operator<<(QDataStream& stream, const NameIndexTuple& nameIndex);
QDataStream& operator>>(QDataStream& stream, NameIndexTuple& nameIndex);
class LocalProp : public QObject class LocalProp : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -126,6 +134,12 @@ public:
bool hasChild(const char* name) const; bool hasChild(const char* name) const;
void changeValue(const char* path, QVariant value); void changeValue(const char* path, QVariant value);
void saveToStream(QDataStream& stream) const;
static LocalProp* restoreFromStream(QDataStream& stream, LocalProp *parent);
void recursiveNotifyRestored();
signals: signals:
void valueChanged(QVariant val); void valueChanged(QVariant val);

View file

@ -27,6 +27,9 @@
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
#include <QQuickItem>
#include <QAction>
#include <QFileDialog>
#include "fgqcanvasfontcache.h" #include "fgqcanvasfontcache.h"
#include "fgqcanvasimageloader.h" #include "fgqcanvasimageloader.h"
@ -49,6 +52,16 @@ TemporaryWidget::TemporaryWidget(QWidget *parent) :
connect(ui->canvasSelectCombo, SIGNAL(activated(int)), connect(ui->canvasSelectCombo, SIGNAL(activated(int)),
this, SLOT(onCanvasSelected(int))); this, SLOT(onCanvasSelected(int)));
ui->canvasSelectCombo->hide(); ui->canvasSelectCombo->hide();
QAction* saveTreeAction = new QAction("Save", this);
saveTreeAction->setShortcut(Qt::CTRL | Qt::Key_S);
connect(saveTreeAction, &QAction::triggered, this, &TemporaryWidget::onSave);
addAction(saveTreeAction);
QAction* openSnapshotAction = new QAction("Open snapshot", this);
openSnapshotAction->setShortcut(Qt::CTRL | Qt::Key_O);
connect(openSnapshotAction, &QAction::triggered, this, &TemporaryWidget::onLoadSnapshot);
addAction(openSnapshotAction);
} }
TemporaryWidget::~TemporaryWidget() TemporaryWidget::~TemporaryWidget()
@ -117,13 +130,59 @@ void TemporaryWidget::onFinishedGetCanvasList()
} }
} }
void TemporaryWidget::onWebSocketConnected() void TemporaryWidget::onSave()
{ {
connect(&m_webSocket, &QWebSocket::textMessageReceived, qDebug() << "should save";
this, &TemporaryWidget::onTextMessageReceived); if (!m_localPropertyRoot) {
return;
}
m_localPropertyRoot = new LocalProp(nullptr, NameIndexTuple("")); QString path = QFileDialog::getSaveFileName(this, tr("Choose name to save"));
if (path.isEmpty()) {
return;
}
QFile f(path);
f.open(QIODevice::ReadWrite);
{
QDataStream ds(&f);
m_localPropertyRoot->saveToStream(ds);
}
f.close();
}
void TemporaryWidget::onLoadSnapshot()
{
qDebug() << "should load";
QString path = QFileDialog::getOpenFileName(this, tr("Select a saved snapshot"));
if (path.isEmpty()) {
return;
}
QFile f(path);
f.open(QIODevice::ReadOnly);
{
QDataStream ds(&f);
m_localPropertyRoot = LocalProp::restoreFromStream(ds, nullptr);
createdRootProperty();
m_localPropertyRoot->recursiveNotifyRestored();
// this is needed for either QtQuick or QPainter drawing
ui->canvas->rootElement()->update();
// this is the widget re-draw request (QtQuick draws all the time)
ui->canvas->update();
}
}
void TemporaryWidget::createdRootProperty()
{
ui->canvas->setRootProperty(m_localPropertyRoot); ui->canvas->setRootProperty(m_localPropertyRoot);
ui->stack->setCurrentIndex(1); ui->stack->setCurrentIndex(1);
@ -136,6 +195,16 @@ void TemporaryWidget::onWebSocketConnected()
ui->elementData->setModel(m_elementModel); ui->elementData->setModel(m_elementModel);
connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TemporaryWidget::onTreeCurrentChanged); connect(ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TemporaryWidget::onTreeCurrentChanged);
}
void TemporaryWidget::onWebSocketConnected()
{
connect(&m_webSocket, &QWebSocket::textMessageReceived,
this, &TemporaryWidget::onTextMessageReceived);
m_localPropertyRoot = new LocalProp(nullptr, NameIndexTuple(""));
createdRootProperty();
FGQCanvasFontCache::instance()->setHost(ui->hostName->text(), FGQCanvasFontCache::instance()->setHost(ui->hostName->text(),
ui->portEdit->text().toInt()); ui->portEdit->text().toInt());

View file

@ -52,12 +52,17 @@ private Q_SLOTS:
void onCanvasSelected(int index); void onCanvasSelected(int index);
void onFinishedGetCanvasList(); void onFinishedGetCanvasList();
void onSave();
void onLoadSnapshot();
private: private:
void saveSettings(); void saveSettings();
void restoreSettings(); void restoreSettings();
LocalProp* propertyFromPath(QByteArray path) const; LocalProp* propertyFromPath(QByteArray path) const;
void createdRootProperty();
QNetworkAccessManager* m_netAccess; QNetworkAccessManager* m_netAccess;
QWebSocket m_webSocket; QWebSocket m_webSocket;
Ui::TemporaryWidget *ui; Ui::TemporaryWidget *ui;