[education/rkward] rkward: Some more restructuring, and start adding backend selection page.
Thomas Friedrichsmeier
null at kde.org
Sat Jun 8 23:21:01 BST 2024
Git commit bf2760fb7f1f004fff1cae539e258b1ba91caa91 by Thomas Friedrichsmeier.
Committed on 08/06/2024 at 22:10.
Pushed by tfry into branch 'master'.
Some more restructuring, and start adding backend selection page.
M +60 -36 rkward/dialogs/rksetupwizard.cpp
M +0 -4 rkward/dialogs/rksetupwizard.h
M +3 -14 rkward/misc/rkprogresscontrol.cpp
M +0 -1 rkward/misc/rkprogresscontrol.h
M +19 -0 rkward/misc/rkstandardicons.cpp
M +4 -1 rkward/misc/rkstandardicons.h
https://invent.kde.org/education/rkward/-/commit/bf2760fb7f1f004fff1cae539e258b1ba91caa91
diff --git a/rkward/dialogs/rksetupwizard.cpp b/rkward/dialogs/rksetupwizard.cpp
index 15724be59..37af06084 100644
--- a/rkward/dialogs/rksetupwizard.cpp
+++ b/rkward/dialogs/rksetupwizard.cpp
@@ -18,6 +18,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include <QTimer>
#include <QFileInfo>
#include <QStandardPaths>
+#include <QRadioButton>
+#include <QGroupBox>
#include <KLocalizedString>
#include <KMessageBox>
@@ -85,15 +87,18 @@ public:
bool RKSetupWizard::has_been_run = false;
-void RKSetupWizardItem::createWidget(QGridLayout *layout, int row) {
+static auto iconForStatus(RKSetupWizardItem::Status status) {
QString icon_id;
- if (status == Good) icon_id = QLatin1String("dialog-positive");
- else if (status == Warning) icon_id = QLatin1String("dialog-warning");
+ if (status == RKSetupWizardItem::Good) icon_id = QLatin1String("dialog-positive");
+ else if (status == RKSetupWizardItem::Warning) icon_id = QLatin1String("dialog-warning");
else icon_id = QLatin1String("dialog-error");
+ return (QIcon::fromTheme(icon_id).pixmap(32, 32)); // TODO: Correct way to not hardcode size?
+}
+
+void RKSetupWizardItem::createWidget(QGridLayout *layout, int row) {
auto label = new QLabel();
- label->setPixmap(QIcon::fromTheme(icon_id).pixmap(32, 32)); // TODO: Correct way to not hardcode size?
+ label->setPixmap(iconForStatus(status));
layout->addWidget(label, row, 0);
-
layout->addWidget(new QLabel(shortlabel + ": " + shortstatuslabel), row, 1);
if (options.isEmpty()) {
@@ -165,8 +170,8 @@ RKSetupWizard::RKSetupWizard(QWidget* parent, InvokationReason reason, const QLi
RK_TRACE (DIALOGS);
// Cover page
- auto firstpage = new RKSetupWizardPage(this, i18n("RKWard Setup Assistant"));
- auto l = new QVBoxLayout(firstpage);
+ auto page = new RKSetupWizardPage(this, i18n("RKWard Setup Assistant"));
+ auto l = new QVBoxLayout(page);
QString intro = i18n("<p>This dialog will guide you through a quick check of the basic setup of the required (or recommended) components.</p>");
if (reason == NewVersionRKWard) {
intro += i18n("<p>The setup assistant has been invoked, automatically, because a new version of RKWard has been detected.</p>");
@@ -177,13 +182,10 @@ RKSetupWizard::RKSetupWizard(QWidget* parent, InvokationReason reason, const QLi
intro += i18n("<p>The setup assistant has been invoked, automatically, because a problem has been detected in your setup.</p>");
}
l->addWidget(RKCommonFunctions::wordWrappedLabel(intro));
- waiting_to_start_label = RKCommonFunctions::wordWrappedLabel(i18n("<b>Waiting for R backend...</b>") + "<p> </p><p> </p>");
- l->addWidget(waiting_to_start_label);
- firstpageref = firstpage->ref;;
- setValid(firstpageref, false);
+ l->addStretch();
// Basic installation page
- auto page = new RKSetupWizardPage(this, i18n("Basic installation"));
+ page = new RKSetupWizardPage(this, i18n("Basic installation"));
reinstallation_required = false;
auto idir = new RKSetupWizardItem(i18n("Installation directory"));
if (RKCommonFunctions::getRKWardDataDir ().isEmpty ()) {
@@ -239,13 +241,56 @@ RKSetupWizard::RKSetupWizard(QWidget* parent, InvokationReason reason, const QLi
page->addStretch();
// The following pages need the R backend, and are thus initialized lazily
-
// R backend page
page = new RKSetupWizardPage(this, i18n("R Backend"));
- page->lazyInitOnce([](RKSetupWizardPage *p) {
+ page->lazyInitOnce([this](RKSetupWizardPage *p) {
auto l = new QVBoxLayout(p);
- l->addWidget(new QLabel(i18n("R backend info, here")));
+ l->addWidget(new QLabel(i18n("RKWard is currently using the R installation at <nobr>%1</nobr>.", RKSessionVars::RBinary())));
+ auto h = new QHBoxLayout();
+ l->addLayout(h);
+ auto rstatus_label = RKCommonFunctions::wordWrappedLabel(i18n("<b>Waiting for R backend...</b>"));
+ auto rstatus_icon = new QLabel();
+ auto anim = RKStandardIcons::busyAnimation(rstatus_icon, [rstatus_icon](const QIcon& icon) {
+ rstatus_icon->setPixmap(icon.pixmap(32, 32));
+ });
+ h->addWidget(rstatus_icon);
+ h->addWidget(rstatus_label);
+ h->setStretch(1, 2);
l->addStretch();
+ auto pageref = p->ref;
+ setValid(pageref, false);
+ auto statuslambda = [this, pageref, rstatus_label, rstatus_icon, anim, l]() {
+ if (!(RInterface::instance()->backendIsDead() || RInterface::instance()->backendIsIdle())) return;
+
+ anim->stop();
+ if (RInterface::instance()->backendIsDead()) {
+ rstatus_icon->setPixmap(iconForStatus(RKSetupWizardItem::Error));
+ rstatus_label->setText(i18n("<b>R backend has crashed.</b>"));
+ } else {
+ RK_ASSERT(RInterface::instance()->backendIsIdle());
+ QString statustext = i18n("<b>R version %1 started, successfully.</b>", RKSessionVars::RVersion(false));
+ if (RKSessionVars::isPathInAppImage(RKSessionVars::RBinary())) {
+ rstatus_icon->setPixmap(iconForStatus(RKSetupWizardItem::Warning));
+ statustext.append(i18n("<p>You are using the R version bundled inside the RKWard AppImage.</p>"
+ "<p>This version comes with several technical limitations. Importantly, "
+ "yu will not be able to install most R addon packages. "
+ "In general, it is therefore recommended to select a system-installed "
+ "version of R, instead, below.</p>"));
+ } else {
+ rstatus_icon->setPixmap(iconForStatus(RKSetupWizardItem::Good));
+ }
+ rstatus_label->setText(statustext);
+ setValid(pageref, true);
+ }
+
+ auto box = new QGroupBox(i18n("R version to use"));
+ l->addWidget(box);
+ auto bl = new QVBoxLayout(box);
+ auto button = new QRadioButton(i18n("Keep current version"), box); bl->addWidget(button);
+ button = new QRadioButton(i18n("Some dummy option, TODO"), box); bl->addWidget(button);
+ };
+ connect(RInterface::instance(), &RInterface::backendStatusChanged, this, statuslambda);
+ statuslambda();
});
// R packages page
@@ -312,27 +357,6 @@ RKSetupWizard::RKSetupWizard(QWidget* parent, InvokationReason reason, const QLi
int new_height = qMax(height(), spare_height+last_page_label->minimumSizeHint().height());
resize(width(), new_height);
});
-
- // Next we'll want to wait for the R backend to start up. Previous solution was to set Qt::ApplicationModal, and wait, calling processEvents().
- // This does not seem to work well on mac, however, so instead we return, here, so exec will be called from outside, then fire a timer to finish constuction.
- QTimer::singleShot(10, this, &RKSetupWizard::setupWizardPhase2);
-}
-
-void RKSetupWizard::setupWizardPhase2() {
- // Wait for R Interface, then enable dialog
- if (!RInterface::instance()->backendIsIdle()) {
- if (RInterface::instance()->backendIsDead()) {
- // TODO
- waiting_to_start_label->setText(i18n("<b>R backend has crashed. Click \"Cancel\" to exit setup assistant.</b>"));
- } else {
- QTimer::singleShot(100, this, &RKSetupWizard::setupWizardPhase2);
- }
- return;
- }
- RK_TRACE(APP);
-
- waiting_to_start_label->setText(i18n("<b>R backend has started. Click \"Next\" to continue.</b>"));
- setValid(firstpageref, true);
}
RKSetupWizard::~RKSetupWizard() {
diff --git a/rkward/dialogs/rksetupwizard.h b/rkward/dialogs/rksetupwizard.h
index fad6831c3..aa0494a01 100644
--- a/rkward/dialogs/rksetupwizard.h
+++ b/rkward/dialogs/rksetupwizard.h
@@ -37,10 +37,6 @@ public:
void markSoftwareForInstallation(const QString &name, const QString &download_url, bool install);
void markRPackageForInstallation(const QString &name, bool install);
private:
- void setupWizardPhase2();
- KPageWidgetItem* firstpageref;
- QLabel* waiting_to_start_label;
-
QStringList software_to_install;
QStringList software_to_install_urls;
QStringList packages_to_install;
diff --git a/rkward/misc/rkprogresscontrol.cpp b/rkward/misc/rkprogresscontrol.cpp
index d4c1e9bd5..2cd30d03e 100644
--- a/rkward/misc/rkprogresscontrol.cpp
+++ b/rkward/misc/rkprogresscontrol.cpp
@@ -1,6 +1,6 @@
/*
rkprogresscontol - This file is part of RKWard (https://rkward.kde.org). Created: Sun Sep 10 2006
-SPDX-FileCopyrightText: 2006-2011 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileCopyrightText: 2006-2024 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -503,20 +503,9 @@ void RKInlineProgressControl::show(int delay_ms) {
} else {
wrapper->show();
}
- animation_step = 0;
- message_widget->setIcon(RKStandardIcons::getIcon(RKStandardIcons::RKWardIcon));
- auto t = new QTimer(this);
- t->setInterval(750);
- connect(t, &QTimer::timeout, this, [this]() {
- if (is_done) return;
- animation_step = (animation_step + 1) % 2;
- if (animation_step) {
- message_widget->setIcon(QIcon::fromTheme("computer-symbolic"));
- } else {
- message_widget->setIcon(RKStandardIcons::getIcon(RKStandardIcons::RKWardIcon));
- }
+ RKStandardIcons::busyAnimation(this, [this](const QIcon &icon) {
+ if (!is_done) message_widget->setIcon(icon);
});
- t->start();
}
bool RKInlineProgressControl::eventFilter(QObject *w, QEvent *e) {
diff --git a/rkward/misc/rkprogresscontrol.h b/rkward/misc/rkprogresscontrol.h
index 81bf250a5..c1b184577 100644
--- a/rkward/misc/rkprogresscontrol.h
+++ b/rkward/misc/rkprogresscontrol.h
@@ -125,7 +125,6 @@ private:
bool allow_cancel;
bool is_done;
bool any_failed;
- int animation_step;
QWidget* wrapper;
QWidget* display_area;
KMessageWidget *message_widget;
diff --git a/rkward/misc/rkstandardicons.cpp b/rkward/misc/rkstandardicons.cpp
index 58f6099a4..a63fd3d23 100644
--- a/rkward/misc/rkstandardicons.cpp
+++ b/rkward/misc/rkstandardicons.cpp
@@ -186,3 +186,22 @@ QIcon RKStandardIcons::iconForWindow (const RKMDIWindow* window) {
RK_ASSERT (false);
return QIcon ();
}
+
+QTimer *RKStandardIcons::busyAnimation(QObject *parent, std::function<void (const QIcon &)> setter) {
+ RK_TRACE (APP);
+
+ setter(getIcon(RKWardIcon));
+ auto t = new QTimer(parent);
+ t->setInterval(750);
+ int animation_step = 0;
+ QObject::connect(t, &QTimer::timeout, parent, [setter, animation_step]() mutable {
+ animation_step = (animation_step + 1) % 2;
+ if (animation_step) {
+ setter(QIcon::fromTheme("computer-symbolic"));
+ } else {
+ setter(getIcon(RKWardIcon));
+ }
+ });
+ t->start();
+ return t;
+}
diff --git a/rkward/misc/rkstandardicons.h b/rkward/misc/rkstandardicons.h
index 610476c8f..0c7078018 100644
--- a/rkward/misc/rkstandardicons.h
+++ b/rkward/misc/rkstandardicons.h
@@ -1,6 +1,6 @@
/*
rkstandardicons - This file is part of the RKWard project. Created: Wed Oct 24 2007
-SPDX-FileCopyrightText: 2007-2018 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileCopyrightText: 2007-2024 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
SPDX-FileContributor: The RKWard Team <rkward-devel at kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
@@ -120,6 +120,9 @@ public:
/** convenience function to get the icon most suited for the given RKMDIWindow */
static QIcon iconForWindow (const RKMDIWindow* window);
+
+ /** create a "busy" animation that will cycle through appropriate items using the "setter" function */
+ static QTimer* busyAnimation(QObject *parent, std::function<void(const QIcon &)> setter);
private:
// NOTE: Using a static array of QIcons lead to crashes on exit (Qt 5.4.1). Moving that inside a class instance seems to fix the issue.
QIcon icons[Last];
More information about the rkward-tracker
mailing list