Working on snapshot save/loading
This commit is contained in:
parent
2a95e09a09
commit
78b0d9c91e
7 changed files with 177 additions and 9 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue