[education/rkward] /: Finish the import assistant dialog.
Thomas Friedrichsmeier
null at kde.org
Thu Apr 28 17:35:26 BST 2022
Git commit fdaed27ed31cfbcc143aee56f8564b640e15dc19 by Thomas Friedrichsmeier.
Committed on 28/04/2022 at 16:34.
Pushed by tfry into branch 'master'.
Finish the import assistant dialog.
As part of this, allow "Paste special" to be used stand-alone for pasting objects.
M +2 -0 ChangeLog
M +91 -20 rkward/dialogs/rkimportdialog.cpp
M +11 -4 rkward/dialogs/rkimportdialog.h
M +33 -5 rkward/misc/rkspecialactions.cpp
M +7 -2 rkward/misc/rkspecialactions.h
M +1 -1 rkward/pages/rkward_welcome.rkh
M +2 -0 rkward/windows/rkhtmlwindow.cpp
M +13 -3 rkward/windows/robjectbrowser.cpp
M +2 -1 rkward/windows/robjectbrowser.h
https://invent.kde.org/education/rkward/commit/fdaed27ed31cfbcc143aee56f8564b640e15dc19
diff --git a/ChangeLog b/ChangeLog
index a2cc13b0..1baddbb4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,8 @@
TODOs:
- More tolerant handshake on Windows? Simply a matter of allowing more time?
+- (Re-)added improved "Import Assistant" to help getting started with importing data
+- "Paste special" can now also paste data.frames with labels, and is available in the Workspace Browser context menu
- Fixed: Windows: Issues with some shiny apps due to a too small stack size
- "Paste special" action gains option to format as data.frame, optionally with labels
- Add "rio"-based generic import plugin
diff --git a/rkward/dialogs/rkimportdialog.cpp b/rkward/dialogs/rkimportdialog.cpp
index 767af421..ed8fb5e2 100644
--- a/rkward/dialogs/rkimportdialog.cpp
+++ b/rkward/dialogs/rkimportdialog.cpp
@@ -18,12 +18,15 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include "../plugin/rkcomponentmap.h"
#include "../plugin/rkcomponentcontext.h"
#include "../misc/rkcommonfunctions.h"
+#include "../misc/rkspecialactions.h"
#include "../debug.h"
RKImportDialog::RKImportDialog(const QString &context_id, QWidget *parent) : KAssistantDialog(parent) {
RK_TRACE (DIALOGS);
+ setWindowTitle(i18n("Import Data Assistant"));
+ rio_handle = RKComponentMap::getComponentHandle("rkward::import_generic_rio");
context = RKComponentMap::getContext(context_id);
if (context) {
component_ids = context->components();
@@ -45,9 +48,12 @@ RKImportDialog::RKImportDialog(const QString &context_id, QWidget *parent) : KAs
filters.append (elabel + " [" + filter + "] (" + filter + ')');
}
- QWidget *page1 = new QWidget();
- QVBoxLayout *layout = new QVBoxLayout(page1);
+ QWidget *page = new QWidget();
+ QVBoxLayout *layout = new QVBoxLayout(page);
layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("For certain formats, RKWard provides specialized import dialogs, and those generally provide the most options. Is the file you wish to import in one of the following formats?")));
+ if (filters.isEmpty()) {
+ layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("<b>Note:</b> RKWard comes with several import dialogs, but none seem to be loaded, at present. Check your settings.")));
+ }
QGroupBox *box = new QGroupBox();
layout->addWidget(box);
select_format_group = new QButtonGroup(this);
@@ -55,36 +61,101 @@ RKImportDialog::RKImportDialog(const QString &context_id, QWidget *parent) : KAs
for (int i = 0; i < filters.size(); ++i) {
auto *button = new QRadioButton(filters[i]);
sublayout->addWidget(button);
- select_format_group->addButton(button);
+ select_format_group->addButton(button, i);
}
- auto *button = new QRadioButton("None of the above / try another method");
+ auto *button = new QRadioButton(i18n("None of the above / try another method"));
sublayout->addWidget(button);
select_format_group->addButton(button);
button->setChecked(true);
- select_format = addPage(page1, i18n("Select format"));
+ connect(select_format_group, QOverload<QAbstractButton *, bool>::of(&QButtonGroup::buttonToggled), this, &RKImportDialog::updateState);
+ layout->addStretch();
+ select_format = addPage(page, i18n("Select format"));
+
+ page = new QWidget();
+ layout = new QVBoxLayout(page);
+ layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("The 'rio' package offers generic support for importing many different file formats, but requires a number of additional R pacakges to be installed (you will be prompted for missing packages). Do you want to give that a try?")));
+ if (!rio_handle) {
+ layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("<b>Note:</b> The generic import plugin (shipped with RKWard) is not presently loaded. Check your settings.")));
+ }
+ box = new QGroupBox();
+ layout->addWidget(box);
+ select_rio_group = new QButtonGroup(this);
+ sublayout = new QVBoxLayout(box);
+ button = new QRadioButton(i18n("Use 'rio'-based importer"));
+ button->setEnabled(rio_handle != nullptr);
+ sublayout->addWidget(button);
+ select_rio_group->addButton(button, 0);
+ button = new QRadioButton(i18n("Try another method"));
+ sublayout->addWidget(button);
+ select_rio_group->addButton(button);
+ button->setChecked(true);
+ connect(select_rio_group, QOverload<QAbstractButton *, bool>::of(&QButtonGroup::buttonToggled), this, &RKImportDialog::updateState);
+ layout->addStretch();
+ select_rio = addPage(page, i18n("Generic 'rio'-based importer"));
+
+ page = new QWidget();
+ layout = new QVBoxLayout(page);
+ layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("If your data is moderate in size, and you can open/view it in another application on your system, importing it from clipboard (copy and paste) may be viable.")));
+ box = new QGroupBox();
+ layout->addWidget(box);
+ select_clipboard_group = new QButtonGroup(this);
+ sublayout = new QVBoxLayout(box);
+ button = new QRadioButton(i18n("Import from clipboard"));
+ sublayout->addWidget(button);
+ select_clipboard_group->addButton(button, 0);
+ button = new QRadioButton(i18n("Try another method"));
+ sublayout->addWidget(button);
+ select_clipboard_group->addButton(button);
+ button->setChecked(true);
+ connect(select_clipboard_group, QOverload<QAbstractButton *, bool>::of(&QButtonGroup::buttonToggled), this, &RKImportDialog::updateState);
+ layout->addStretch();
+ select_clipboard = addPage(page, i18n("Import from clipboard"));
+
+ page = new QWidget();
+ layout = new QVBoxLayout(page);
+ layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("<b>Ready to go</b><p>Click \"Finish\" to start the selected import dialog, or \"Back\" to explore other options.</p>")));
+ layout->addStretch();
+ end_with_selection = addPage(page, i18n("Start import dialog"));
+
+ page = new QWidget();
+ layout = new QVBoxLayout(page);
+ layout->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("No further import methods are available at this time. Things you can try, include: <ul><li>Check for the availability of additional import plugins</li><li>Save your data to a different format in the original application</li><li>Ask for advice on rkward-users at kde.org</li></ul>")));
+ layout->addStretch();
+ end_without_selection = addPage(page, i18n("No import method found"));
+
+ updateState();
}
RKImportDialog::~RKImportDialog() {
RK_TRACE(DIALOGS);
}
-/*
+void RKImportDialog::updateState() {
+ RK_TRACE(DIALOGS);
+ bool do_format = (select_format_group->checkedId() >= 0);
+ bool do_rio = !do_format && (select_rio_group->checkedId() == 0);
+ bool do_clipboard = !(do_format || do_rio) && (select_clipboard_group->checkedId() == 0);
+
+ setAppropriate(select_format, true);
+ setAppropriate(select_rio, !do_format);
+ setAppropriate(select_clipboard, !(do_format || do_rio));
+ setAppropriate(end_with_selection, do_format || do_rio || do_clipboard);
+ setAppropriate(end_without_selection, !isAppropriate(end_with_selection));
+}
+
void RKImportDialog::accept () {
RK_TRACE (DIALOGS);
- int index = filters.indexOf (selectedNameFilter ());
- QString cid = component_ids.value (index);
- RKComponentHandle *handle = RKComponentMap::getComponentHandle (cid);
- RKContextHandler *chandler = context->makeContextHandler (this, false);
-
- if (!(handle && chandler)) {
- RK_ASSERT (false);
- } else {
- RKComponentPropertyBase *filename = new RKComponentPropertyBase (chandler, false);
- filename->setValue (selectedFiles ().value (0));
- chandler->addChild ("filename", filename);
-
- chandler->invokeComponent (handle);
+ hide();
+ int index = select_format_group->checkedId();
+ if (index >= 0) {
+ RKComponentMap::invokeComponent(component_ids.value(index), QStringList());
+ } else if (rio_handle && (select_rio_group->checkedId() == 0)) {
+ rio_handle->invoke(nullptr, nullptr);
+ } else if (select_clipboard_group->checkedId() == 0) {
+ RKPasteSpecialDialog dia(this, true);
+ dia.exec();
}
+ deleteLater();
+ KAssistantDialog::accept();
}
-*/
diff --git a/rkward/dialogs/rkimportdialog.h b/rkward/dialogs/rkimportdialog.h
index 175a25c4..492cb491 100644
--- a/rkward/dialogs/rkimportdialog.h
+++ b/rkward/dialogs/rkimportdialog.h
@@ -14,6 +14,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
class RKComponentGUIXML;
class KPageWidgetitem;
class QButtonGroup;
+class RKComponentHandle;
/** This dialog is designed to allow the user to select a file, and file format. After that a suitable plugin
is opened automatically to deal with this type of file . */
@@ -26,16 +27,22 @@ public:
RKImportDialog (const QString &context_id, QWidget *parent);
/** dtor */
~RKImportDialog ();
+ void accept() override;
private:
+ void updateState();
+
QStringList filters;
QStringList component_ids;
+ RKComponentHandle *rio_handle;
RKComponentGUIXML *context;
KPageWidgetItem *select_format;
QButtonGroup *select_format_group;
- KPageWidgetItem *do_format;
- KPageWidgetItem *select_rio_or_clipboard;
- KPageWidgetItem *do_rio;
- KPageWidgetItem *do_clipboard;
+ KPageWidgetItem *select_rio;
+ QButtonGroup *select_rio_group;
+ KPageWidgetItem *select_clipboard;
+ QButtonGroup *select_clipboard_group;
+ KPageWidgetItem *end_with_selection;
+ KPageWidgetItem *end_without_selection;
};
#endif
diff --git a/rkward/misc/rkspecialactions.cpp b/rkward/misc/rkspecialactions.cpp
index ed8b3655..9b82c448 100644
--- a/rkward/misc/rkspecialactions.cpp
+++ b/rkward/misc/rkspecialactions.cpp
@@ -8,6 +8,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include "rkspecialactions.h"
#include <KLocalizedString>
+#include <KMessageBox>
+
+#include "../rkward.h"
#include "../debug.h"
@@ -50,13 +53,21 @@ void RKPasteSpecialAction::doSpecialPaste() {
#include "../dataeditor/rktextmatrix.h"
#include "../core/robject.h"
+#include "rksaveobjectchooser.h"
+#include "../rbackend/rkrinterface.h"
+#include "../misc/rkprogresscontrol.h"
-RKPasteSpecialDialog::RKPasteSpecialDialog (QWidget* parent) : QDialog (parent) {
+RKPasteSpecialDialog::RKPasteSpecialDialog(QWidget* parent, bool standalone) : QDialog(parent) {
RK_TRACE (MISC);
setWindowTitle (i18n ("Paste Special..."));
QVBoxLayout *pagelayout = new QVBoxLayout (this);
+ objectname = standalone ? new RKSaveObjectChooser(this, QStringLiteral("pasted.data")) : nullptr;
+ if (objectname) {
+ connect(objectname, &RKSaveObjectChooser::changed, this, &RKPasteSpecialDialog::updateState);
+ pagelayout->addWidget(objectname);
+ }
QHBoxLayout *rowlayout = new QHBoxLayout ();
pagelayout->addLayout (rowlayout);
@@ -138,9 +149,9 @@ RKPasteSpecialDialog::RKPasteSpecialDialog (QWidget* parent) : QDialog (parent)
// Labels
box = new QGroupBox(i18n("Labels"), this);
group_layout = new QVBoxLayout (box);
- names_box = new QCheckBox(i18n("First column contains labels"), box);
+ names_box = new QCheckBox(i18n("First row contains labels"), box);
group_layout->addWidget(names_box);
- rownames_box = new QCheckBox(i18n("First row contains labels"), box);
+ rownames_box = new QCheckBox(i18n("First column contains labels"), box);
group_layout->addWidget(rownames_box);
rowlayout->addWidget(box);
@@ -159,8 +170,9 @@ RKPasteSpecialDialog::RKPasteSpecialDialog (QWidget* parent) : QDialog (parent)
rowlayout->addWidget (box);
QDialogButtonBox *buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
- connect (buttons->button (QDialogButtonBox::Ok), &QPushButton::clicked, this, &QDialog::accept);
- connect (buttons->button (QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject);
+ ok_button = buttons->button(QDialogButtonBox::Ok);
+ connect(ok_button, &QPushButton::clicked, this, &QDialog::accept);
+ connect(buttons->button (QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QDialog::reject);
pagelayout->addWidget (buttons);
updateState (); // initialize
@@ -184,6 +196,7 @@ void RKPasteSpecialDialog::updateState () {
rownames_box->setEnabled(dimensionality == DimDataFrame);
separator_freefield->setEnabled ((dimensionality != DimSingleString) && (separator_group->checkedId () == SepCustom));
+ ok_button->setEnabled((objectname == nullptr) || objectname->isOk());
}
QString RKPasteSpecialDialog::resultingText () {
@@ -284,3 +297,18 @@ QString RKPasteSpecialDialog::prepString(const QString& src, const Quoting quot)
return src;
}
+void RKPasteSpecialDialog::accept() {
+ RK_TRACE(MISC);
+ if (objectname) {
+ RCommand *command = new RCommand(objectname->currentFullName() + " <- " + resultingText(), RCommand::App | RCommand::ObjectListUpdate);
+ connect(command->notifier(), &RCommandNotifier::commandFinished, [](RCommand *c) {
+ if (c->failed()) {
+ QString msg = c->fullOutput();
+ if (msg.isEmpty()) msg = i18n("Command failed to parse. Try using <i>Edit->Paste special...</i> in the R Console window for better diagnostics.");
+ KMessageBox::detailedError(RKWardMainWindow::getMain(), i18n("Pasting object from clipboard data failed."), msg, i18n("Paste failed"));
+ }
+ });
+ RInterface::issueCommand(command);
+ }
+ QDialog::accept();
+}
diff --git a/rkward/misc/rkspecialactions.h b/rkward/misc/rkspecialactions.h
index fd4e59ee..c1d317e4 100644
--- a/rkward/misc/rkspecialactions.h
+++ b/rkward/misc/rkspecialactions.h
@@ -32,12 +32,14 @@ signals:
class QButtonGroup;
class QLineEdit;
class QCheckBox;
+class RKSaveObjectChooser;
-/** Dialog used in RKPasteSpecialAction */
+/** Dialog used in RKPasteSpecialAction
+ TODO: move to separate file, now that it can be used standalone */
class RKPasteSpecialDialog : public QDialog {
Q_OBJECT
public:
- explicit RKPasteSpecialDialog (QWidget* parent);
+ explicit RKPasteSpecialDialog(QWidget* parent, bool standalone=false);
~RKPasteSpecialDialog ();
enum Dimensionality {
@@ -60,6 +62,7 @@ public:
};
QString resultingText ();
+ void accept() override;
public slots:
void updateState ();
private:
@@ -75,6 +78,8 @@ private:
QCheckBox* insert_nas_box;
QCheckBox* names_box;
QCheckBox* rownames_box;
+ RKSaveObjectChooser *objectname;
+ QPushButton *ok_button;
};
#endif
diff --git a/rkward/pages/rkward_welcome.rkh b/rkward/pages/rkward_welcome.rkh
index 2a1944a3..e536a0dd 100644
--- a/rkward/pages/rkward_welcome.rkh
+++ b/rkward/pages/rkward_welcome.rkh
@@ -11,7 +11,7 @@
<section title="Import or enter data" id="import-create">
<ul>
<li><link href="rkward://actions/new_data_frame">Enter new data</link></li>
- <li>Import data</li>
+ <li><link href="rkward://actions/import_assistant">Import data</link></li>
</ul>
</section>
diff --git a/rkward/windows/rkhtmlwindow.cpp b/rkward/windows/rkhtmlwindow.cpp
index f81920dd..37b00da4 100644
--- a/rkward/windows/rkhtmlwindow.cpp
+++ b/rkward/windows/rkhtmlwindow.cpp
@@ -605,6 +605,8 @@ bool RKHTMLWindow::handleRKWardURL (const QUrl &url, RKHTMLWindow *window) {
RKWardMainWindow::getMain()->slotNewDataFrame();
} else if (action == "rpackage_install") {
RKWardMainWindow::getMain()->slotFileLoadLibs();
+ } else if (action == "import_assistant") {
+ RKWardMainWindow::getMain()->importData();
} else {
RK_ASSERT(false);
}
diff --git a/rkward/windows/robjectbrowser.cpp b/rkward/windows/robjectbrowser.cpp
index 79e3a3e2..94bdff34 100644
--- a/rkward/windows/robjectbrowser.cpp
+++ b/rkward/windows/robjectbrowser.cpp
@@ -1,17 +1,19 @@
/*
robjectbrowser - This file is part of RKWard (https://rkward.kde.org). Created: Thu Aug 19 2004
-SPDX-FileCopyrightText: 2004-2017 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileCopyrightText: 2004-2022 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
*/
#include "robjectbrowser.h"
-#include <qlayout.h>
-#include <qpushbutton.h>
+#include <QPushButton>
#include <QFocusEvent>
#include <QVBoxLayout>
#include <QMenu>
#include <QInputDialog>
+#include <QApplication>
+#include <QMimeData>
+#include <QClipboard>
#include <KLocalizedString>
#include <kmessagebox.h>
@@ -26,6 +28,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
#include "../misc/rkdummypart.h"
#include "../misc/rkstandardicons.h"
#include "../misc/rkstandardactions.h"
+#include "../misc/rkspecialactions.h"
#include "rkworkplace.h"
#include "../dataeditor/rkeditor.h"
@@ -121,6 +124,8 @@ RObjectBrowserInternal::RObjectBrowserInternal (QWidget *parent, RObjectBrowser
connect (actions[CopyToGlobalEnv], &QAction::triggered, this, &RObjectBrowserInternal::popupCopyToGlobalEnv);
actions.insert (Delete, new QAction (i18n ("Delete"), this));
connect (actions[Delete], &QAction::triggered, this, &RObjectBrowserInternal::popupDelete);
+ actions.insert(NewFromClipboard, new QAction(QIcon::fromTheme("edit-paste"), i18n("New object from clipboard"), this));
+ connect (actions[NewFromClipboard], &QAction::triggered, this, []() { RKPasteSpecialDialog dia(RKWardMainWindow::getMain(), true); dia.exec(); });
actions.insert (Unload, new QAction (i18n ("Unload Package"), this));
connect (actions[Unload], &QAction::triggered, this, &RObjectBrowserInternal::popupUnload);
actions.insert (LoadUnloadPackages, new QAction (i18n ("Load / Unload Packages"), this));
@@ -253,6 +258,11 @@ void RObjectBrowserInternal::contextMenuCallback (RObject *, bool *) {
actions[Copy]->setVisible (object->canRead () && (!object->isType (RObject::ToplevelEnv)));
actions[CopyToGlobalEnv]->setVisible (object->canRead () && (!object->isInGlobalEnv()) && (!object->isType (RObject::ToplevelEnv)));
actions[Delete]->setVisible (object->canRemove ());
+ {
+ const QClipboard *clipboard = QApplication::clipboard();
+ const QMimeData *mime_data = clipboard->mimeData();
+ actions[NewFromClipboard]->setEnabled(mime_data->hasText());
+ }
actions[Unload]->setVisible (object->isType (RObject::PackageEnv));
actions[LoadUnloadPackages]->setVisible (object == RObjectList::getObjectList ());
}
diff --git a/rkward/windows/robjectbrowser.h b/rkward/windows/robjectbrowser.h
index d01dc358..6e26d592 100644
--- a/rkward/windows/robjectbrowser.h
+++ b/rkward/windows/robjectbrowser.h
@@ -1,6 +1,6 @@
/*
robjectbrowser - This file is part of the RKWard project. Created: Thu Aug 19 2004
-SPDX-FileCopyrightText: 2004-2016 by Thomas Friedrichsmeier <thomas.friedrichsmeier at kdemail.net>
+SPDX-FileCopyrightText: 2004-2022 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
*/
@@ -83,6 +83,7 @@ private:
Copy,
CopyToGlobalEnv,
Delete,
+ NewFromClipboard,
Unload,
LoadUnloadPackages,
ActionCount
More information about the rkward-tracker
mailing list