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

View file

@ -19,6 +19,10 @@
#include <QDebug>
#include <QNetworkAccessManager>
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QFileInfo>
class TransferSignalHolder : public QObject
{
@ -43,8 +47,11 @@ void FGQCanvasImageLoader::onDownloadFinished()
if (!pm.loadFromData(reply->readAll())) {
qWarning() << "image loading failed";
} else {
qDebug() << "did download:" << reply->property("image").toByteArray();
m_cache.insert(reply->property("image").toByteArray(), pm);
QByteArray imagePath = reply->property("image").toByteArray();
m_cache.insert(imagePath, pm);
// cache on disk also, so snapshots work
writeToDiskCache(imagePath, reply);
TransferSignalHolder* signalHolder = reply->findChild<TransferSignalHolder*>("holder");
if (signalHolder) {
@ -57,6 +64,23 @@ void FGQCanvasImageLoader::onDownloadFinished()
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)
{
m_hostName = hostName;
@ -70,6 +94,15 @@ QPixmap FGQCanvasImageLoader::getImage(const QByteArray &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;
url.setScheme("http");
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));
reply->setProperty("image", imagePath);

View file

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

View file

@ -20,6 +20,18 @@
#include <QJsonValue>
#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)
{
if (path.isEmpty()) {
@ -119,6 +131,41 @@ void LocalProp::changeValue(const char *path, QVariant 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)
{

View file

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

View file

@ -27,6 +27,9 @@
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QQuickItem>
#include <QAction>
#include <QFileDialog>
#include "fgqcanvasfontcache.h"
#include "fgqcanvasimageloader.h"
@ -49,6 +52,16 @@ TemporaryWidget::TemporaryWidget(QWidget *parent) :
connect(ui->canvasSelectCombo, SIGNAL(activated(int)),
this, SLOT(onCanvasSelected(int)));
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()
@ -117,13 +130,59 @@ void TemporaryWidget::onFinishedGetCanvasList()
}
}
void TemporaryWidget::onWebSocketConnected()
void TemporaryWidget::onSave()
{
connect(&m_webSocket, &QWebSocket::textMessageReceived,
this, &TemporaryWidget::onTextMessageReceived);
qDebug() << "should save";
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->stack->setCurrentIndex(1);
@ -136,6 +195,16 @@ void TemporaryWidget::onWebSocketConnected()
ui->elementData->setModel(m_elementModel);
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(),
ui->portEdit->text().toInt());

View file

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