[education/rkward/devel/workspace_output] rkward: Work on output directories now compiles. On to debugging...

Thomas Friedrichsmeier null at kde.org
Sat Oct 24 19:36:03 BST 2020


Git commit b3781c5474a727c321be5031a9da1ef232288c83 by Thomas Friedrichsmeier.
Committed on 24/10/2020 at 18:35.
Pushed by tfry into branch 'devel/workspace_output'.

Work on output directories now compiles. On to debugging...

M  +7    -7    rkward/dialogs/rksavemodifieddialog.cpp
M  +1    -0    rkward/misc/rkcommonfunctions.cpp
M  +54   -21   rkward/misc/rkoutputdirectory.cpp
M  +4    -2    rkward/misc/rkoutputdirectory.h
M  +1    -0    rkward/rbackend/rkrinterface.cpp
M  +2    -1    rkward/rbackend/rpackages/rkward/R/internal.R
M  +10   -9    rkward/rbackend/rpackages/rkward/R/rk.output.R
M  +1    -5    rkward/windows/rkhtmlwindow.h

https://invent.kde.org/education/rkward/commit/b3781c5474a727c321be5031a9da1ef232288c83

diff --git a/rkward/dialogs/rksavemodifieddialog.cpp b/rkward/dialogs/rksavemodifieddialog.cpp
index 6d523f60..4023400f 100644
--- a/rkward/dialogs/rksavemodifieddialog.cpp
+++ b/rkward/dialogs/rksavemodifieddialog.cpp
@@ -93,16 +93,16 @@ project = true;
 		header->addChild (save_project_check);
 		save_project_check->setCheckState (0, Qt::Checked);
 
-		QStringList modified_outputs = RKOutputDirectory::modifiedOutputDirectories();
-		if (!modified_outputs.isEmpty ()) {
+		auto modified_outputs = RKOutputDirectory::modifiedOutputDirectories();
+		if (!modified_outputs.isEmpty()) {
 			QTreeWidgetItem *header = makeHeaderItem (i18n ("Output files"), tree);
 			for (int i = 0; i < modified_outputs.size (); ++i) {
 				QTreeWidgetItem *item = new QTreeWidgetItem();
-				item->setText(0, RKOutputWindowManager::self()->outputCaption(modified_outputs[i]));
-				item->setFirstColumnSpanned (true);
-				header->addChild (item);
-				item->setCheckState (0, Qt::Checked);
-				outputdir_checklist.insert (item, modified_outputs[i]);
+				item->setText(0, modified_outputs[i]->caption());
+				item->setFirstColumnSpanned(true);
+				header->addChild(item);
+				item->setCheckState(0, Qt::Checked);
+				outputdir_checklist.insert(item, modified_outputs[i]->getId());
 			}
 		}
 	}
diff --git a/rkward/misc/rkcommonfunctions.cpp b/rkward/misc/rkcommonfunctions.cpp
index 2aa05905..ad177e43 100644
--- a/rkward/misc/rkcommonfunctions.cpp
+++ b/rkward/misc/rkcommonfunctions.cpp
@@ -177,6 +177,7 @@ namespace RKCommonFunctions {
 		if (rkward_data_dir.isNull ()) {
 			QString inside_build_tree = QCoreApplication::applicationDirPath() + "/rkwardinstall/";
 			if (QFileInfo(inside_build_tree).isReadable()) {
+				RK_DEBUG(APP, DL_INFO, "Running from inside build tree");
 				rkward_data_dir = inside_build_tree;
 				return rkward_data_dir;
 			}
diff --git a/rkward/misc/rkoutputdirectory.cpp b/rkward/misc/rkoutputdirectory.cpp
index b2be6be2..2bad21e2 100644
--- a/rkward/misc/rkoutputdirectory.cpp
+++ b/rkward/misc/rkoutputdirectory.cpp
@@ -29,6 +29,7 @@
 #include "../rbackend/rkrinterface.h"
 #include "../windows/rkmdiwindow.h"
 #include "../windows/rkhtmlwindow.h"
+#include "../windows/rkworkplace.h"
 #include "../misc/rkcommonfunctions.h"
 #include "../agents/rkquitagent.h"
 #include "../rkglobals.h"
@@ -187,12 +188,9 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::exportAs (const QString
 	return GenericRCallResult(QVariant(dest));  // return effective destination path. Needed by save()
 }
 
-RKOutputDirectory::GenericRCallResult RKOutputDirectory::import(const QString& _dir) {
+RKOutputDirectory::GenericRCallResult RKOutputDirectory::importInternal(const QString &_dir) {
 	RK_TRACE (APP);
 
-	if (initialized) {
-		return GenericRCallResult::makeError(i18n("Output directory %1 is already in use.", work_dir));
-	}
 	QFileInfo fi(_dir);
 	if (!fi.isDir()) {
 		return GenericRCallResult::makeError(i18n("The path %1 does not exist or is not a directory.", _dir));
@@ -211,6 +209,35 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::import(const QString& _
 	return GenericRCallResult(QVariant(id));
 }
 
+RKOutputDirectory::GenericRCallResult RKOutputDirectory::import(const QString& _dir) {
+	RK_TRACE (APP);
+
+	if (initialized) {
+		return GenericRCallResult::makeError(i18n("Output directory %1 is already in use.", id));
+	}
+
+	return importInternal(_dir);
+}
+
+RKOutputDirectory::GenericRCallResult RKOutputDirectory::revert(OverwriteBehavior discard) {
+	RK_TRACE (APP);
+
+	if (save_dir.isEmpty()) {
+		return GenericRCallResult::makeError(i18n("Output directory %1 has not previously been saved. Cannot revert.", id));
+	}
+	if (!isModified()) return GenericRCallResult(id, i18n("Output directory %1 had no modifications. Nothing reverted.", id));
+	if (discard == Ask) {
+		if (KMessageBox::warningContinueCancel(RKWardMainWindow::getMain(), i18n("Reverting will destroy any changes, since the last time you saved (%1). Are you sure you want to proceed?"), save_timestamp.toString()) == KMessageBox::Continue) {
+			discard = Force;
+		}
+	}
+	if (discard != Force) {
+		return GenericRCallResult::makeError(i18n("User cancelled."));
+	}
+
+	return importInternal(save_dir);
+}
+
 RKOutputDirectory* RKOutputDirectory::createOutputDirectoryInternal() {
 	RK_TRACE (APP);
 
@@ -291,6 +318,12 @@ bool RKOutputDirectory::isModified() const {
 	return saved_hash == hashDirectoryState(work_dir);
 }
 
+QString RKOutputDirectory::caption() const {
+	RK_TRACE(APP);
+	if (!save_dir.isEmpty()) return QFileInfo(save_dir).fileName();
+	return i18n("Unsaved output");
+}
+
 RKOutputDirectory::GenericRCallResult RKOutputDirectory::purge(RKOutputDirectory::OverwriteBehavior discard, RCommandChain* chain) {
 	RK_TRACE(APP);
 
@@ -338,12 +371,12 @@ bool RKOutputDirectory::isActive() const {
 	return RKOutputWindowManager::self()->currentOutputPath() == workPath();
 }
 
-QStringList RKOutputDirectory::modifiedOutputDirectories() {
+QList<RKOutputDirectory*> RKOutputDirectory::modifiedOutputDirectories() {
 	RK_TRACE (APP);
 
-	QStringList ret;
-	for (auto it = outputs.constBegin (); it != outputs.constEnd (); ++it) {
-		if (it.value()->isModified()) ret.append(it.key());
+	QList<RKOutputDirectory*> ret;
+	for (auto it = outputs.constBegin(); it != outputs.constEnd(); ++it) {
+		if (it.value()->isModified()) ret.append(it.value());
 	}
 	return ret;
 }
@@ -407,7 +440,7 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::view(bool raise) {
 			list[0]->activate();
 		}
 	} else {
-		RKOutputWindowManager::self()->newOutputWindow(workPath());
+		RKWorkplace::mainWorkplace()->openOutputWindow(QUrl::fromLocalFile(workPath()));
 	}
 	return GenericRCallResult(id);
 }
@@ -415,9 +448,9 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::view(bool raise) {
 RKOutputDirectory::GenericRCallResult RKOutputDirectory::handleRCall(const QStringList& params, RCommandChain *chain) {
 	RK_TRACE(APP);
 
-	QString command = params.value(1);
+	QString command = params.value(0);
 	if (command == QStringLiteral("get")) {
-		if (params.value(2) == QStringLiteral("all")) {
+		if (params.value(1) == QStringLiteral("all")) {
 			QStringList ret;
 			auto all = allOutputs();
 			for (int i=0; i < all.size(); ++i) {
@@ -426,8 +459,8 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::handleRCall(const QStri
 			return GenericRCallResult(ret);
 		}
 
-		QString filename = params.value(4);
-		bool create = params.value(3) == QStringLiteral("create");
+		QString filename = params.value(3);
+		bool create = (params.value(2) == QStringLiteral("create"));
 		RKOutputDirectory *out = nullptr;
 		if (filename.isEmpty()) {
 			if (create) {
@@ -450,8 +483,8 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::handleRCall(const QStri
 		return GenericRCallResult(out->getId());
 	} else {
 		// all other commands pass the output id as second parameter. Look that up, first
-		QString id = params.value(2);
-		auto out = getOutputById(params.value(2));
+		QString id = params.value(1);
+		auto out = getOutputById(id);
 		if (!out) {
 			return GenericRCallResult::makeError(i18n("The output identified by '%1' is not loaded in this session.", id));
 		}
@@ -463,17 +496,17 @@ RKOutputDirectory::GenericRCallResult RKOutputDirectory::handleRCall(const QStri
 		} else if (command == QStringLiteral("isModified")) {
 			return GenericRCallResult(out->isModified());
 		} else if (command == QStringLiteral("revert")) {
-			return out->revert(parseOverwrite(params.value(3)));
+			return out->revert(parseOverwrite(params.value(2)));
 		} else if (command == QStringLiteral("save")) {
-			return out->save(params.value(3), parseOverwrite(params.value(4)));
+			return out->save(params.value(2), parseOverwrite(params.value(3)));
 		} else if (command == QStringLiteral("export")) {
-			return out->exportAs(params.value(3), parseOverwrite(params.value(4)));
+			return out->exportAs(params.value(2), parseOverwrite(params.value(3)));
 		} else if (command == QStringLiteral("clear")) {
-			return out->clear(parseOverwrite(params.value(3)));
+			return out->clear(parseOverwrite(params.value(2)));
 		} else if (command == QStringLiteral("close")) {
-			return out->purge(parseOverwrite(params.value(3)), chain);
+			return out->purge(parseOverwrite(params.value(2)), chain);
 		} else if (command == QStringLiteral("view")) {
-			return out->view(params.value(3) == QStringLiteral("raise"));
+			return out->view(params.value(2) == QStringLiteral("raise"));
 		} else if (command == QStringLiteral("workingDir")) {
 			return GenericRCallResult(out->workDir());
 		} else if (command == QStringLiteral("filename")) {
diff --git a/rkward/misc/rkoutputdirectory.h b/rkward/misc/rkoutputdirectory.h
index 56caa447..2bd3b263 100644
--- a/rkward/misc/rkoutputdirectory.h
+++ b/rkward/misc/rkoutputdirectory.h
@@ -54,7 +54,7 @@ public:
 		Fail
 	};
 	GenericRCallResult activate(RCommandChain* chain=0);
-	GenericRCallResult revert(bool ask);
+	GenericRCallResult revert(OverwriteBehavior discard=Ask);
 	GenericRCallResult save(const QString& dest=QString(), OverwriteBehavior overwrite=Ask);
 	GenericRCallResult exportAs(const QString& dest=QString(), OverwriteBehavior overwrite=Ask);
 	GenericRCallResult clear(OverwriteBehavior discard=Ask);
@@ -67,11 +67,12 @@ public:
 	QString filename() const { return save_dir; };
 	QString workDir() const { return work_dir; }
 	QString workPath() const;
+	QString caption() const;
 	static GenericRCallResult handleRCall(const QStringList& params, RCommandChain *chain);
 	static RKOutputDirectory* getOutputById(const QString& id);
 	static RKOutputDirectory* getOutputBySaveUrl(const QString& dest);
 /** Return a list of all current output directories that have been modified. Used for asking for save during shutdown. */
-	static QStringList modifiedOutputDirectories();
+	static QList<RKOutputDirectory*> modifiedOutputDirectories();
 
 	static RKOutputDirectory::GenericRCallResult R_rk_Output(const QString& filename=QString(), bool create=false, bool all=false);
 /** Returns the active output (in case there is one).
@@ -99,6 +100,7 @@ private:
 	GenericRCallResult import(const QString& from);
 	static RKOutputDirectory* createOutputDirectoryInternal();
 	static bool isRKWwardOutputDirectory (const QString &dir);
+	GenericRCallResult importInternal(const QString &dir);
 };
 
 #endif
diff --git a/rkward/rbackend/rkrinterface.cpp b/rkward/rbackend/rkrinterface.cpp
index a1b71fda..deb808ac 100644
--- a/rkward/rbackend/rkrinterface.cpp
+++ b/rkward/rbackend/rkrinterface.cpp
@@ -44,6 +44,7 @@
 #include "../plugin/rkcomponentmap.h"
 #include "../misc/rkcommonfunctions.h"
 #include "../misc/rkmessagecatalog.h"
+#include "../misc/rkoutputdirectory.h"
 #include "rksessionvars.h"
 
 #include "../windows/rkwindowcatcher.h"
diff --git a/rkward/rbackend/rpackages/rkward/R/internal.R b/rkward/rbackend/rpackages/rkward/R/internal.R
index 24d85d99..1dc0955b 100755
--- a/rkward/rbackend/rpackages/rkward/R/internal.R
+++ b/rkward/rbackend/rpackages/rkward/R/internal.R
@@ -125,7 +125,8 @@
 	ret <- .Call ("rk.do.command", c (x, args), PACKAGE="(embedding)");
 	if (!is.null (ret)) {
 		if (ret[1] == "warning") warning (ret[2])
-		else stop (ret[2])
+		else if (ret[1] == "error") stop (ret[2])
+		else ret[1:length(ret)]
 	}
 }
 
diff --git a/rkward/rbackend/rpackages/rkward/R/rk.output.R b/rkward/rbackend/rpackages/rkward/R/rk.output.R
index 5e7c979a..28d96378 100644
--- a/rkward/rbackend/rpackages/rkward/R/rk.output.R
+++ b/rkward/rbackend/rpackages/rkward/R/rk.output.R
@@ -55,30 +55,30 @@ RK.Output <- setRefClass(Class="RK.Output", fields=list(id="character"),
 		},
 		revert=function(discard=NULL) {
 "Revert this output to the last saved state. If no previous state is available (never saved, before), clears the output."
-			.rk.do.call("output", c ("revert", .checkId(), if (is.Null(discard)) "ask" else isTRUE(discard) ? "force" : "fail"))
+			.rk.do.call("output", c ("revert", .checkId(), if(is.null(discard)) "ask" else if(isTRUE(discard)) "force" else "fail"))
 		},
 		save=function(filename, overwrite=NULL) {
 "Save this output, either to the last known save location (if no filename is specified) or to a new location (\"save as\")."
-			.rk.do.call("output", c ("save", .checkId(), filename, if (is.Null(overwrite)) "ask" else isTRUE(overwrite) ? "force" : "fail"))
+			.rk.do.call("output", c ("save", .checkId(), filename, if(is.null(overwrite)) "ask" else if(isTRUE(overwrite)) "force" else "fail"))
 		},
 		export=function(filename, overwrite=NULL) {
 "Save this output, to the specified location, but keep it associated with the previous location (\"save a copy\")."
 			if (missing(filename)) stop("No file name specified")
-			.rk.do.call("output", c ("export", .checkId(), filename, if (is.Null(overwrite)) "ask" else isTRUE(overwrite) ? "force" : "fail"))
+			.rk.do.call("output", c ("export", .checkId(), filename, if(is.null(overwrite)) "ask" else if(isTRUE(overwrite)) "force" else "fail"))
 		},
 		clear=function(discard=NULL) {
 "Clear all content from this output. As with any function in this class, this affects the working copy, only, until you call save. Therefore, by default, the user will be prompted for confirmation
 if and only if there are unsaved changes pending."
-			.rk.do.call("output", c ("clear", .checkId(), if (is.Null(discard)) "ask" else isTRUE(discard) ? "force" : "fail"))
+			.rk.do.call("output", c ("clear", .checkId(), if(is.null(discard)) "ask" else if(isTRUE(discard)) "force" else "fail"))
 		},
 		close=function(discard=NULL) {
 "Forget about this output file, also closing any open views. Note: Trying to call any further methods on this object will fail."
-			.rk.do.call("output", c ("close", .checkId(), if (is.Null(discard)) "ask" else isTRUE(discard) ? "force" : "fail"))
+			.rk.do.call("output", c ("close", .checkId(), if(is.null(discard)) "ask" else if(isTRUE(discard)) "force" else "fail"))
 			id=NULL
 		},
 		view=function(raise=TRUE) {
 "Open this output for viewing in the frontend."
-			.rk.do.call("output", c ("view", .checkId(), isTRUE(raise) ? "raise" : ""))
+			.rk.do.call("output", c ("view", .checkId(), if(isTRUE(raise)) "raise" else ""))
 		},
 		.workingDir=function() {
 "The path of the working copy of this object. Please don't use this except for automated tests. The internals may be subject to change."
@@ -89,7 +89,7 @@ if and only if there are unsaved changes pending."
 Do not write anything to the target filename, directly! This is purely for information."
 			.rk.do.call("output", c ("filename", .checkId()))
 		},
-		.checkId=function(id) {
+		.checkId=function() {
 "For internal use: Throws an error, if the id parameter is NULL or too long, returns a length one character vector otherwise."
 			i <- as.character(id)
 			if (length(i) != 1) stop ("Invalid output id. Use rk.output() to obtain a valid output handle.")
@@ -100,6 +100,7 @@ Do not write anything to the target filename, directly! This is purely for infor
 #' @export
 #' @rdname RK.Output
 "rk.output" <- function(filename=NULL, create=FALSE, all=FALSE) {
-	if(all && (!is.Null(filename) || create)) stop("'all' cannot be combined with 'create' or 'filename'")
-	.rk.do.call("output", c ("get", isTRUE(all) ? "all" : "one", isTRUE(create) ? "create" : "get", as.character(filename)))
+	if(all && (!is.null(filename) || create)) stop("'all' cannot be combined with 'create' or 'filename'")
+	id <- .rk.do.call("output", c ("get", if(isTRUE(all)) "all" else "one", if(isTRUE(create)) "create" else "", if(is.null(filename)) "" else as.character(filename)))
+	RK.Output(id=id)
 }
diff --git a/rkward/windows/rkhtmlwindow.h b/rkward/windows/rkhtmlwindow.h
index 59496ea8..d109eb3c 100644
--- a/rkward/windows/rkhtmlwindow.h
+++ b/rkward/windows/rkhtmlwindow.h
@@ -196,7 +196,6 @@ private:
 #include <QMultiHash>
 
 #include <kdirwatch.h>
-#include "../misc/rkoutputdirectory.h"
 
 /** Takes care of showing / refreshing output windows as needed. */
 class RKOutputWindowManager : public QObject {
@@ -207,14 +206,11 @@ public:
 	void registerWindow (RKHTMLWindow *window);
 /** R may produce output while no output window is active. This allows to set the file that should be monitored for such changes (called from within rk.set.html.output.file()). */
 	void setCurrentOutputPath (const QString &path);
-	QString currentOutputPath() const;
+	QString currentOutputPath() const { return current_default_path; };
 /** returns a list (possibly empty) of pointers to existing output windows for the given path (for the current output path, if no path given). */
 	QList<RKHTMLWindow*> existingOutputWindows (const QString &path = QString ()) const;
 /** Create (and show) a new output window (for the current output path, unless path is specified), and @return the pointer */
 	RKHTMLWindow* newOutputWindow (const QString& path = QString ());
-
-/** Return the name / caption of the given output directory */
-	QString outputCaption (const QString &dir) const;
 private:
 	RKOutputWindowManager ();
 	~RKOutputWindowManager ();




More information about the rkward-tracker mailing list