[education/rkward/devel/workspace_output] rkward: Allow opening output files from file window.

Thomas Friedrichsmeier null at kde.org
Wed Mar 2 16:55:52 GMT 2022


Git commit 4c0de2abf17a218e6cb84e2cdd69b2e6fd9ae87d by Thomas Friedrichsmeier.
Committed on 02/03/2022 at 16:55.
Pushed by tfry into branch 'devel/workspace_output'.

Allow opening output files from file window.

This needed some fixes around canonicalFilePath().

M  +1    -1    rkward/dialogs/rksavemodifieddialog.cpp
M  +27   -15   rkward/misc/rkoutputdirectory.cpp
M  +5    -4    rkward/misc/rkoutputdirectory.h
M  +1    -1    rkward/windows/rkhtmlwindow.cpp
M  +14   -3    rkward/windows/rkworkplace.cpp

https://invent.kde.org/education/rkward/commit/4c0de2abf17a218e6cb84e2cdd69b2e6fd9ae87d

diff --git a/rkward/dialogs/rksavemodifieddialog.cpp b/rkward/dialogs/rksavemodifieddialog.cpp
index 5eefe7dd..03fc674b 100644
--- a/rkward/dialogs/rksavemodifieddialog.cpp
+++ b/rkward/dialogs/rksavemodifieddialog.cpp
@@ -155,7 +155,7 @@ void RKSaveModifiedDialog::saveSelected() {
 
 	for (auto it = outputdir_checklist.constBegin(); it != outputdir_checklist.constEnd(); ++it) {
 		if (it.key ()->checkState (0) != Qt::Checked) continue;
-		RKOutputDirectory *dir = RKOutputDirectory::getOutputById(it.value());
+		RKOutputDirectory *dir = RKOutputDirectory::findOutputById(it.value());
 		if (dir) {
 			if (dir->save().failed()) all_ok = false;
 		}
diff --git a/rkward/misc/rkoutputdirectory.cpp b/rkward/misc/rkoutputdirectory.cpp
index cd122da5..c0b959e7 100644
--- a/rkward/misc/rkoutputdirectory.cpp
+++ b/rkward/misc/rkoutputdirectory.cpp
@@ -78,13 +78,13 @@ RKOutputDirectory::~RKOutputDirectory() {
 	RK_TRACE(APP);
 }
 
-RKOutputDirectory* RKOutputDirectory::getOutputById(const QString& id) {
+RKOutputDirectory* RKOutputDirectory::findOutputById(const QString& id) {
 	RK_TRACE (APP);
 
 	return outputs.value(id);
 }
 
-RKOutputDirectory* RKOutputDirectory::getOutputByWorkPath(const QString& workpath) {
+RKOutputDirectory* RKOutputDirectory::findOutputByWorkPath(const QString& workpath) {
 	RK_TRACE (APP);
 
 	if (workpath.endsWith("index.html")) {
@@ -94,10 +94,9 @@ RKOutputDirectory* RKOutputDirectory::getOutputByWorkPath(const QString& workpat
 	return nullptr;
 }
 
-RKOutputDirectory* RKOutputDirectory::getOutputBySaveUrl(const QString& _dest) {
+RKOutputDirectory* RKOutputDirectory::findOutputBySaveUrl(const QString& dest) {
 	RK_TRACE (APP);
 
-	QString dest = QFileInfo(_dest).canonicalFilePath();
 	for (auto it = outputs.constBegin(); it != outputs.constEnd(); ++it) {
 		if (it.value()->save_filename == dest) {
 			return(it.value());
@@ -106,7 +105,7 @@ RKOutputDirectory* RKOutputDirectory::getOutputBySaveUrl(const QString& _dest) {
 	return nullptr;
 }
 
-RKOutputDirectory* RKOutputDirectory::getOutputByWindow(const RKMDIWindow *window) {
+RKOutputDirectory* RKOutputDirectory::findOutputByWindow(const RKMDIWindow *window) {
 	RK_TRACE (APP);
 
 	if (!window) return nullptr;
@@ -129,7 +128,7 @@ GenericRRequestResult RKOutputDirectory::save(const QString& _dest, RKOutputDire
 	}
 	GenericRRequestResult res = exportAs(dest, overwrite);
 	if (!res.failed()) {
-		save_filename = res.ret.toString();  // might by different from dest, notably, if dest was empty
+		save_filename = res.ret.toString();  // might by different from dest, notably, if dest was empty or not yet normalized
 		known_modified = true;  // dirty trick to ensure that updateSavedHash() will trigger a stateChange()->update caption in views, even if using SaveAs on an unmodified directory
 		updateSavedHash();
 	}
@@ -495,19 +494,32 @@ RKOutputDirectoryCallResult RKOutputDirectory::get(const QString &_filename, boo
 		} else {
 			return (getCurrentOutput(chain));
 		}
-	} else {
-		QString filename = QFileInfo(_filename).canonicalFilePath();
-		ret.setDir(getOutputBySaveUrl(filename));
+	} else {  // filename not empty
+		QFileInfo fi(_filename);
+		bool file_exists = fi.exists();
+		QString filename = file_exists ? fi.canonicalFilePath() : _filename;
+		RKOutputDirectory *dir = file_exists ? findOutputBySaveUrl(filename) : nullptr;
+		// NOTE: annoyingly QFileInfo::canonicalFilePath() returns an empty string, if the file does not exist
 		if (create) {
-			if (ret.dir()) return GenericRRequestResult::makeError(i18n("Output '1%' is already loaded in this session. Cannot create it.", filename));
-			if (QFileInfo(filename).exists()) return GenericRRequestResult::makeError(i18n("A file named '1%' already exists. Cannot create it.", filename));
+			if (dir) return GenericRRequestResult::makeError(i18n("Output '1%' is already loaded in this session. Cannot create it.", filename));
+			if (file_exists) return GenericRRequestResult::makeError(i18n("A file named '1%' already exists. Cannot create it.", filename));
+
 			ret.setDir(createOutputDirectoryInternal());
-			ret.addMessages(ret.dir()->import(filename));
+			ret.addMessages(dir->save(filename));  // NOTE: save() takes care of normalizing
 		} else {
+			if (!file_exists) return GenericRRequestResult::makeError(i18n("File '%1' does not exist.", filename));
+
+			ret.setDir(findOutputBySaveUrl(filename));
 			if (!ret.dir()) {
-				ret.setDir(createOutputDirectoryInternal());
-				ret.addMessages(ret.dir()->import(filename));
+				auto dir = createOutputDirectoryInternal();
+				ret.addMessages(dir->import(filename));
+				if (ret.failed()) {
+					dir->purge(Force);
+				} else {
+					ret.setDir(dir);
+				}
 			}
+			// else we have already set the loaded dir as ret.dir()
 		}
 	}
 	return ret;
@@ -533,7 +545,7 @@ GenericRRequestResult RKOutputDirectory::handleRCall(const QStringList& params,
 	} else {
 		// all other commands pass the output id as second parameter. Look that up, first
 		QString id = params.value(1);
-		auto out = getOutputById(id);
+		auto out = findOutputById(id);
 		if (!out) {
 			return GenericRRequestResult::makeError(i18n("The output identified by '%1' is not loaded in this session.", id));
 		}
diff --git a/rkward/misc/rkoutputdirectory.h b/rkward/misc/rkoutputdirectory.h
index 7015f62e..f4b6aea2 100644
--- a/rkward/misc/rkoutputdirectory.h
+++ b/rkward/misc/rkoutputdirectory.h
@@ -69,10 +69,9 @@ public:
 	QString workPath() const;
 	QString caption() const;
 	static GenericRRequestResult handleRCall(const QStringList& params, RCommandChain *chain);
-	static RKOutputDirectory* getOutputById(const QString& id);
-	static RKOutputDirectory* getOutputByWorkPath(const QString& workpath);
-	static RKOutputDirectory* getOutputBySaveUrl(const QString& dest);
-	static RKOutputDirectory* getOutputByWindow(const RKMDIWindow* window);
+	static RKOutputDirectory* findOutputById(const QString& id);
+	static RKOutputDirectory* findOutputByWorkPath(const QString& workpath);
+	static RKOutputDirectory* findOutputByWindow(const RKMDIWindow* window);
 /** Return a list of all current output directories that have been modified. Used for asking for save during shutdown. */
 	static QList<RKOutputDirectory*> modifiedOutputDirectories();
 
@@ -94,6 +93,8 @@ private:
 	void updateSavedHash();
 	/** Currently active output. Could be nullptr in corner cases! */
 	RKOutputDirectory* activeOutput();
+	/** Note dest must be normalized. Hiding as private to avoid mis-use. */
+	static RKOutputDirectory* findOutputBySaveUrl(const QString& dest);
 
 	QString saved_hash;
 	QDateTime save_timestamp;
diff --git a/rkward/windows/rkhtmlwindow.cpp b/rkward/windows/rkhtmlwindow.cpp
index 0c9d4408..b9a53229 100644
--- a/rkward/windows/rkhtmlwindow.cpp
+++ b/rkward/windows/rkhtmlwindow.cpp
@@ -567,7 +567,7 @@ bool RKHTMLWindow::openURL (const QUrl &url) {
 
 			current_url = url;	// needs to be set before registering
 			RKOutputWindowManager::self ()->registerWindow (this);
-			dir = RKOutputDirectory::getOutputByWorkPath(url.toLocalFile());
+			dir = RKOutputDirectory::findOutputByWorkPath(url.toLocalFile());
 			part->setOutputDirectoryActionsEnabled(dir != nullptr);
 			if (dir) {
 				connect(dir, &RKOutputDirectory::stateChange, this, &RKHTMLWindow::updateState);
diff --git a/rkward/windows/rkworkplace.cpp b/rkward/windows/rkworkplace.cpp
index 886a512c..54ae864c 100644
--- a/rkward/windows/rkworkplace.cpp
+++ b/rkward/windows/rkworkplace.cpp
@@ -424,10 +424,21 @@ bool RKWorkplace::openAnyUrl (const QUrl &url, const QString &known_mimetype, bo
 			openHelpWindow (url, true);
 			return true;	// TODO
 		}
-		if (url.fileName ().toLower ().endsWith (QLatin1String (".rdata")) || url.fileName ().toLower ().endsWith (QLatin1String (".rda"))) {
-			RKWardMainWindow::getMain ()->askOpenWorkspace (url);
+		QString lname = url.fileName().toLower();
+		if (lname.endsWith(QLatin1String(".rdata")) || lname.endsWith(QLatin1String(".rda"))) {
+			RKWardMainWindow::getMain()->askOpenWorkspace(url);
 			return true;	// TODO
 		}
+		if (lname.endsWith(".rko")) {
+			auto ret = RKOutputDirectory::get(url.toLocalFile(), false);
+			if (!ret.failed()) {
+				ret.dir()->view(true);
+				return true;
+			} else {
+				KMessageBox::sorry(this, i18n("Failed to open output file. Error message was '%1'", ret.error));
+				return false;
+			}
+		}
 		if (mimetype.inherits ("text/plain")) {
 			return (openScriptEditor (url, QString ()));
 		}
@@ -805,7 +816,7 @@ QString RKWorkplace::makeItemDescription (RKMDIWindow *win) const {
 		specification = static_cast<RKCommandEditorWindow*> (win)->url ().url ();
 		if (specification.isEmpty ()) specification = static_cast<RKCommandEditorWindow*> (win)->id ();
 	} else if (win->isType (RKMDIWindow::OutputWindow)) {
-		RKOutputDirectory *dir = RKOutputDirectory::getOutputByWindow(win);
+		RKOutputDirectory *dir = RKOutputDirectory::findOutputByWindow(win);
 		if (dir) {
 			type = "rkoutput";
 			specification = QUrl::fromLocalFile(dir->filename()).url();


More information about the rkward-tracker mailing list