diff options
Diffstat (limited to 'ui/qt5/runner/executepage.cc')
-rw-r--r-- | ui/qt5/runner/executepage.cc | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/ui/qt5/runner/executepage.cc b/ui/qt5/runner/executepage.cc new file mode 100644 index 0000000..817a61c --- /dev/null +++ b/ui/qt5/runner/executepage.cc @@ -0,0 +1,198 @@ +/* + * executepage.cc - Implementation of the UI.Perform page + * horizon-run-qt5, the Qt 5 executor user interface for + * Project Horizon + * + * Copyright (c) 2019 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#include "executepage.hh" + +#include <QAbstractButton> +#include <QGridLayout> +#include <QProcess> +#include <QTimer> +#include <QVBoxLayout> + +ExecutePage::ExecutePage(QWidget *parent) : HorizonWizardPage(parent) { + setTitle(tr("Installing Adélie Linux…")); + loadWatermark("intro"); + + QLabel *descLabel = new QLabel(tr("Please wait while System Installation performs the following tasks:")); + descLabel->setWordWrap(true); + + prepareStatus = new QLabel; + prepare = new QLabel(tr("Prepare installation")); + validateStatus = new QLabel; + validate = new QLabel(tr("Validate installation")); + diskStatus = new QLabel; + disk = new QLabel(tr("Configure hard disk(s)")); + preMetaStatus = new QLabel; + preMeta = new QLabel(tr("Initial configuration")); + netStatus = new QLabel; + net = new QLabel(tr("Networking configuration")); + pkgStatus = new QLabel; + pkg = new QLabel(tr("Install software")); + postMetaStatus = new QLabel; + postMeta = new QLabel(tr("Final configuration")); + + QGridLayout *progressLayout = new QGridLayout; + progressLayout->addWidget(prepareStatus, 0, 0); + progressLayout->addWidget(prepare, 0, 1); + progressLayout->addWidget(validateStatus, 1, 0); + progressLayout->addWidget(validate, 1, 1); + progressLayout->addWidget(diskStatus, 2, 0); + progressLayout->addWidget(disk, 2, 1); + progressLayout->addWidget(preMetaStatus, 3, 0); + progressLayout->addWidget(preMeta, 3, 1); + progressLayout->addWidget(netStatus, 4, 0); + progressLayout->addWidget(net, 4, 1); + progressLayout->addWidget(pkgStatus, 5, 0); + progressLayout->addWidget(pkg, 5, 1); + progressLayout->addWidget(postMetaStatus, 6, 0); + progressLayout->addWidget(postMeta, 6, 1); + progressLayout->setColumnStretch(1, 100); + + normalFont = validate->font(); + boldFont = normalFont; + boldFont.setBold(true); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(descLabel); + mainLayout->addStretch(); + mainLayout->addLayout(progressLayout); + mainLayout->addStretch(); + + setLayout(mainLayout); + + finishTimer = new QTimer(this); + finishTimer->setInterval(1500); + finishTimer->setSingleShot(true); + connect(finishTimer, &QTimer::timeout, [=]{ + wizard()->next(); + }); + + log.setFileName("/var/log/horizon/executor.log"); + Q_ASSERT(log.open(QFile::Append)); + + this->current = Prepare; + markRunning(this->current); + + executor = new QProcess(this); + executor->setProgram("../../tools/hscript-simulate/hscript-simulate"); + executor->setArguments({"/etc/horizon/installfile"}); + connect(executor, &QProcess::readyReadStandardError, + this, &ExecutePage::executorReady); + connect(executor, &QProcess::readyReadStandardOutput, + this, &ExecutePage::executorOutReady); + connect(executor, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), + this, &ExecutePage::executorFinished); + executor->start(); +} + +ExecutePage::Phase ExecutePage::stepToPhase(QString step) { + if(step == "validate") return Validate; + if(step == "disk") return Disk; + if(step == "pre-metadata") return PreMeta; + if(step == "net") return Net; + if(step == "pkgdb") return Pkg; + if(step == "post-metadata") return PostMeta; + Q_ASSERT(false); +} + +void ExecutePage::labelsForPhase(Phase phase, QLabel **icon, QLabel **text) { + switch(phase) { + case Prepare: + *icon = prepareStatus; + *text = prepare; + break; + case Validate: + *icon = validateStatus; + *text = validate; + break; + case Disk: + *icon = diskStatus; + *text = disk; + break; + case PreMeta: + *icon = preMetaStatus; + *text = preMeta; + break; + case Net: + *icon = netStatus; + *text = net; + break; + case Pkg: + *icon = pkgStatus; + *text = pkg; + break; + case PostMeta: + *icon = postMetaStatus; + *text = postMeta; + break; + } +} + +void ExecutePage::markRunning(Phase phase) { + QLabel *icon, *text; + labelsForPhase(phase, &icon, &text); + icon->setPixmap(loadDPIAwarePixmap("status-current", ".svg")); + text->setFont(boldFont); +} + +void ExecutePage::markFinished(Phase phase) { + QLabel *icon, *text; + labelsForPhase(phase, &icon, &text); + icon->setPixmap(loadDPIAwarePixmap("status-success", ".svg")); + text->setFont(normalFont); +} + +void ExecutePage::markFailed(Phase phase) { + QLabel *icon, *text; + labelsForPhase(phase, &icon, &text); + icon->setPixmap(loadDPIAwarePixmap("status-issue", ".svg")); + text->setFont(boldFont); +} + +void ExecutePage::executorReady() { + QByteArray msgs = executor->readAllStandardError(); + log.write(msgs); + + QStringList msgList = QString::fromUtf8(msgs).split("\n"); + for(auto &msg : msgList) { + QString msgType = msg.section('\t', 1, 1); + if(msgType == "step-start") { + this->current = stepToPhase(msg.section('\t', 2)); + /* validate means prepare is done */ + if(this->current == Validate) markFinished(Prepare); + markRunning(this->current); + } else if(msgType == "step-end") { + Q_ASSERT(stepToPhase(msg.section('\t', 2)) == this->current); + markFinished(this->current); + } else if(msgType == "log") { + QString severity = msg.section(": ", 1, 1); + if(severity == "error") { + markFailed(this->current); + } + } else { + /* !? */ + } + } +} + +void ExecutePage::executorOutReady() { + log.write(executor->readAllStandardOutput()); +} + +void ExecutePage::executorFinished(int code, QProcess::ExitStatus status) { + if(status != QProcess::NormalExit || code != 0) { + markFailed(this->current); + } + + wizard()->button(QWizard::CancelButton)->setEnabled(false); + finishTimer->start(); +} |