summaryrefslogtreecommitdiffstats
path: root/src/gui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui.cpp')
-rw-r--r--src/gui.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
new file mode 100644
index 0000000..e27086a
--- /dev/null
+++ b/src/gui.cpp
@@ -0,0 +1,217 @@
+#include "gui.h"
+#include "progress.h"
+
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QPushButton>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QMessageBox>
+#include <QTimer>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+static QString STATE_COPYING("COPYING"); // Still busy copying original file, new chunks are only accepted in already copied range
+static QString STATE_WAITING_FOR_UPLOAD_DONE("WAITING_FOR_UPLOAD_DONE"); // Copying done, just waiting for new chunks until client signals that it's done
+static QString STATE_WAITING_FOR_COPYING_DONE("WAITING_FOR_COPYING_DONE"); // Copying not done, but dnbd3-fuse already told us it's done, wait for copying
+static QString STATE_UPLOAD_DONE("UPLOAD_DONE"); // dnbd3-fuse signaled merge request, upload is thus done and no new chunks are accepted
+static QString STATE_PROCESSING("PROCESSING"); // Hashing, renaming, creating DB entry
+static QString STATE_ERROR("ERROR");
+static QString STATE_COMPLETELY_DONE("COMPLETELY_DONE");
+
+Gui::Gui(const char *urlbase, const char *uuid, QWidget *parent)
+ : QDialog(parent)
+ , _nam(new QNetworkAccessManager(this))
+ , _urlStatus(QString(urlbase).append("status/").append(uuid))
+ , _urlAbort(QString(urlbase).append("abort/").append(uuid))
+ , _urlFinish(QString(urlbase).append("finish/").append(uuid))
+ , _denyInteraction(false)
+ , _tmrStatus(new QTimer(this))
+ , _status(nullptr)
+{
+ _nam->setAutoDeleteReplies(true);
+ _nam->setTransferTimeout(5000);
+ setupUi();
+ auto flags = windowFlags();
+ setWindowFlags(flags & ~(Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint));
+ _tmrStatus->start(2500);
+ QObject::connect(_tmrStatus, &QTimer::timeout, [this]() {
+ QNetworkReply *reply = _nam->get(QNetworkRequest(_urlStatus));
+ QObject::connect(reply, &QNetworkReply::finished, [reply, this]() {
+ // JSON
+ auto repData = reply->readAll();
+ auto doc = QJsonDocument::fromJson(repData);
+ if (doc.isEmpty() || !doc.isObject()) {
+ QString str = QString::fromUtf8(repData);
+ int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ if (code == 404) {
+ _remoteState = STATE_ERROR;
+ _status->setText(tr("Sitzung dem Server nicht bekannt"));
+ updateButtons();
+ } else if (str.length() > 0 && str.length() < 160) {
+ _status->setText(QLatin1String("Server: ") + str);
+ } else {
+ _status->setText(tr("Fehler beim Statusabruf"));
+ }
+ return;
+ }
+ // Got JSON
+ auto outer = doc.object();
+ QJsonValue state = outer[QLatin1String("state")];
+ if (state.isString()) {
+ auto ns = state.toString();
+ if (ns != _remoteState) {
+ _status->setText(ns);
+ _remoteState = ns;
+ updateButtons();
+ }
+ }
+ QJsonValue tasks = outer[QLatin1String("tasks")];
+ if (tasks.isArray()) {
+ auto arr = tasks.toArray();
+ for (auto it : arr) {
+ if (!it.isObject())
+ continue;
+ auto o = it.toObject();
+ auto jt = o.value(QLatin1String("title"));
+ if (!jt.isString())
+ continue;
+ auto jp = o.value(QLatin1String("percent"));
+ auto je = o.value(QLatin1String("error"));
+ QString title = jt.toString();
+ QString err = je.isString() ? je.toString() : QLatin1String("");
+ int percent = err.isEmpty() && jp.isDouble() ? (int)jp.toDouble() : -1;
+ Progress *item = _items.value(title);
+ if (item == nullptr) {
+ if (_items.size() > 10)
+ continue;
+ item = new Progress(title, this);
+ _itemBox->addWidget(item);
+ _items.insert(title, item);
+ }
+ item->setProgress(percent);
+ item->setCaption(title + QLatin1String(" ") + err);
+ }
+ }
+ });
+ });
+}
+
+Gui::~Gui()
+{
+ _nam->blockSignals(true);
+}
+
+void Gui::setupUi()
+{
+ QVBoxLayout *outerVert = new QVBoxLayout(this);
+ outerVert->setMargin(3);
+
+ _itemBox = new QVBoxLayout;
+ _itemBox->setObjectName("ItemLayout");
+ outerVert->addLayout(_itemBox);
+
+ QLayout *buttons = new QHBoxLayout;
+ buttons->setObjectName("ButtonLayout");
+ outerVert->addLayout(buttons);
+
+ _status = new QLabel("-", this);
+ _itemBox->addWidget(_status);
+
+ _btnAbort = new QPushButton(tr("Abbrechen/Löschen"), this);
+ buttons->addWidget(_btnAbort);
+ QObject::connect(_btnAbort, &QPushButton::clicked, this, &Gui::pushedCancel);
+
+ _btnOk = new QPushButton(tr("Änderungen permanent behalten"), this);
+ buttons->addWidget(_btnOk);
+ QObject::connect(_btnOk, &QPushButton::clicked, this, &Gui::pushedOk);
+}
+
+void Gui::updateButtons()
+{
+ if (_remoteState == STATE_COMPLETELY_DONE || _remoteState == STATE_PROCESSING) {
+ if (_remoteState == STATE_COMPLETELY_DONE) {
+ _tmrStatus->stop();
+ }
+ _btnAbort->setEnabled(false);
+ _btnOk->setEnabled(true);
+ _btnOk->setText(tr("Schließen"));
+ } else if (_remoteState == STATE_UPLOAD_DONE) {
+ _btnAbort->setEnabled(true);
+ _btnOk->setEnabled(true);
+ } else if (_remoteState == STATE_ERROR) {
+ _btnAbort->setEnabled(true);
+ _btnOk->setEnabled(false);
+ _tmrStatus->stop();
+ _btnAbort->setText(tr("Schließen"));
+ } else {
+ _btnAbort->setEnabled(true);
+ _btnOk->setEnabled(false);
+ }
+}
+
+void Gui::pushedCancel(bool)
+{
+ if (_remoteState == STATE_ERROR) {
+ this->close();
+ return;
+ }
+ if (_denyInteraction)
+ return;
+ if (_remoteState != STATE_ERROR) {
+ int ret = QMessageBox::question(this, tr("Bestätigung"), tr("Wollen Sie diesen Bearbeitungsvorgang wirklich abbrechen?"));
+ if (ret == QMessageBox::No)
+ return;
+ }
+ if (_remoteState == STATE_COMPLETELY_DONE) {
+ _btnAbort->setEnabled(false);
+ return;
+ }
+ _denyInteraction = true;
+ QNetworkReply *reply = _nam->post(QNetworkRequest(_urlAbort), QByteArray());
+ connect(reply, &QNetworkReply::finished, [reply, this]() {
+ QString msg = QString::fromUtf8(reply->readAll());
+ if (reply->error() != QNetworkReply::NoError) {
+ QMessageBox::critical(this, tr("Fehler"), msg);
+ _denyInteraction = false;
+ } else {
+ _btnAbort->setEnabled(false);
+ _btnOk->setEnabled(false);
+ _remoteState = STATE_ERROR;
+ QMessageBox::information(this, tr("Ergebnis"), msg);
+ QTimer::singleShot(2000, [this]() {
+ this->close();
+ });
+ }
+ });
+}
+
+void Gui::pushedOk(bool)
+{
+ if (_remoteState == STATE_COMPLETELY_DONE || _remoteState == STATE_PROCESSING) {
+ this->close();
+ return;
+ }
+ if (_denyInteraction)
+ return;
+ if (_remoteState == STATE_UPLOAD_DONE) {
+ int ret = QMessageBox::question(this, tr("Bestätigung"), tr("Die Änderungen an der VM werden dauerhaft beibehalten. Fortfahren?"));
+ if (ret == QMessageBox::No)
+ return;
+ }
+ _denyInteraction = true;
+ QNetworkReply *reply = _nam->get(QNetworkRequest(_urlFinish));
+ connect(reply, &QNetworkReply::finished, [reply, this]() {
+ QString msg = QString::fromUtf8(reply->readAll());
+ int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ if (reply->error() != QNetworkReply::NoError || (code < 200 || code >= 300)) {
+ QMessageBox::critical(this, tr("Fehler"), msg);
+ _denyInteraction = false;
+ } else {
+ _remoteState = STATE_PROCESSING;
+ _status->setText(tr("Finalisiere..."));
+ updateButtons();
+ }
+ });
+}