[education/rkward] /: Keep kate plugin actions active whenever a ktexteditor _or_ the corresponding plugin tool window is active.

Thomas Friedrichsmeier null at kde.org
Sun Nov 1 07:30:37 GMT 2020


Git commit 1235f217cc8fa94487c015a1b888f73241e61216 by Thomas Friedrichsmeier.
Committed on 01/11/2020 at 07:30.
Pushed by tfry into branch 'master'.

Keep kate plugin actions active whenever a ktexteditor _or_ the corresponding plugin tool window is active.

M  +3    -0    ChangeLog
M  +28   -21   rkward/rkward.cpp
M  +1    -0    rkward/rkward.h
M  +3    -2    rkward/windows/detachedwindowcontainer.cpp
M  +27   -9    rkward/windows/katepluginintegration.cpp
M  +4    -0    rkward/windows/katepluginintegration.h
M  +1    -0    rkward/windows/rkcommandeditorwindow.cpp
M  +11   -5    rkward/windows/rkmdiwindow.cpp
M  +7    -0    rkward/windows/rkmdiwindow.h
M  +13   -6    rkward/windows/rkworkplace.cpp
M  +3    -1    rkward/windows/rkworkplace.h

https://invent.kde.org/education/rkward/commit/1235f217cc8fa94487c015a1b888f73241e61216

diff --git a/ChangeLog b/ChangeLog
index 0210df6e..542ccc4e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+- kate plugin related actions are now active whenever a script window is active (not only the corresponding tool window)
+  - TODO: support kate plugins in detached windows
+
 --- Version 0.7.2 - Oct-16-2020
 - Script preview keeps vertical scroll position when updating
 - Python development scripts have been ported to python3
diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index ec83c94f..7787cea5 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -125,8 +125,9 @@ RKWardMainWindow::RKWardMainWindow () : KParts::MainWindow ((QWidget *)0, (Qt::W
 	workspace_modified = false;
 	merge_loads = false;
 	rkward_mainwin = this;
-	katepluginintegration = 0;
-	RKGlobals::rinter = 0;
+	katepluginintegration = nullptr;
+	active_ui_buddy = nullptr;
+	RKGlobals::rinter = nullptr;
 	RKCommonFunctions::getRKWardDataDir(); // call this before any forking, in order to avoid potential race conditions during initialization of data dir
 	RKSettings::settings_tracker = new RKSettingsTracker (this);
 
@@ -651,38 +652,44 @@ void updateEmptyMenuIndicator (QAction* indicator, const QMenu *menu) {
 	indicator->setVisible (true);
 }
 
-void RKWardMainWindow::partChanged (KParts::Part *part) {
+void RKWardMainWindow::partChanged(KParts::Part *part) {
 	RK_TRACE (APP);
 
 	if (gui_rebuild_locked) return;
 	if (!part) return;
-	createGUI (part);
+	createGUI(part);
 
-	if (!guiFactory ()) {
+	if (!guiFactory()) {
 		RK_ASSERT (false);
 		return;
 	}
+	// Check for additional "buddy" that should be loaded
+	RKMDIWindow *w = RKWorkplace::mainWorkplace()->windowForPart(part);
+	KXMLGUIClient* buddy = w->uiBuddy();
+	// NOTE: Even if the buddy stays the same, we have to remove and re-add it to keep the order of menu actions stable
+	if (active_ui_buddy) factory()->removeClient(active_ui_buddy);
+	if (buddy) factory()->addClient(buddy);
+	active_ui_buddy = buddy;
 
-	updateEmptyMenuIndicator (edit_menu_dummy, dynamic_cast<QMenu*>(guiFactory ()->container ("edit", this)));
-	updateEmptyMenuIndicator (view_menu_dummy, dynamic_cast<QMenu*>(guiFactory ()->container ("view", this)));
+	updateEmptyMenuIndicator(edit_menu_dummy, dynamic_cast<QMenu*>(guiFactory()->container("edit", this)));
+	updateEmptyMenuIndicator(view_menu_dummy, dynamic_cast<QMenu*>(guiFactory()->container("view", this)));
 
 	// plug save file actions into the toolbar collections
-	RK_ASSERT (save_any_action);
-	for (int i = 0; i < plugged_save_actions.size (); ++i) {
-		QAction* a = plugged_save_actions[i].data ();
-		if (a) save_any_action->removeAction (a);
+	RK_ASSERT(save_any_action);
+	for (int i = 0; i < plugged_save_actions.size(); ++i) {
+		QAction* a = plugged_save_actions[i].data();
+		if (a) save_any_action->removeAction(a);
 	}
-	plugged_save_actions.clear ();
-
-	RKMDIWindow *w = RKWorkplace::mainWorkplace ()->activeWindow (RKMDIWindow::Attached);
-	if (w && (w->isType (RKMDIWindow::CommandEditorWindow))) {
-		QAction *a = static_cast<RKCommandEditorWindow*>(w)->fileSaveAction ();
-		if (a) plugged_save_actions.append (a);
-		a = static_cast<RKCommandEditorWindow*>(w)->fileSaveAsAction ();
-		if (a) plugged_save_actions.append (a);
+	plugged_save_actions.clear();
+
+	if (w && (w->isType(RKMDIWindow::CommandEditorWindow))) {
+		QAction *a = static_cast<RKCommandEditorWindow*>(w)->fileSaveAction();
+		if (a) plugged_save_actions.append(a);
+		a = static_cast<RKCommandEditorWindow*>(w)->fileSaveAsAction();
+		if (a) plugged_save_actions.append(a);
 	}
-	for (int i = 0; i < plugged_save_actions.size (); ++i) {
-		save_any_action->insertAction (save_actions_plug_point, plugged_save_actions[i]);
+	for (int i = 0; i < plugged_save_actions.size(); ++i) {
+		save_any_action->insertAction(save_actions_plug_point, plugged_save_actions[i]);
 	}
 /*
 	// debug code: prints out all current actions
diff --git a/rkward/rkward.h b/rkward/rkward.h
index 88ebd05e..b851648f 100644
--- a/rkward/rkward.h
+++ b/rkward/rkward.h
@@ -200,6 +200,7 @@ private:
 	bool merge_loads;
 
 	KatePluginIntegrationApp *katepluginintegration;
+	KXMLGUIClient *active_ui_buddy;
 };
 
 #endif // RKWARD_H
diff --git a/rkward/windows/detachedwindowcontainer.cpp b/rkward/windows/detachedwindowcontainer.cpp
index ce0966d4..19113a56 100644
--- a/rkward/windows/detachedwindowcontainer.cpp
+++ b/rkward/windows/detachedwindowcontainer.cpp
@@ -2,7 +2,7 @@
                           detachedwindowcontainer  -  description
                              -------------------
     begin                : Wed Oct 21 2005
-    copyright            : (C) 2005-2016 by Thomas Friedrichsmeier
+    copyright            : (C) 2005-2020 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -76,7 +76,8 @@ DetachedWindowContainer::DetachedWindowContainer (RKMDIWindow *widget_to_capture
 	widget_to_capture->setParent (this);
 	setCentralWidget (widget_to_capture);
 	widget_to_capture->show ();
-	createGUI (widget_to_capture->getPart ());
+	createGUI(widget_to_capture->getPart());
+//	if (widget_to_capture->uiBuddy()) factory()->addClient(widget_to_capture->uiBuddy());
 	captured = widget_to_capture;
 
 	hideEmptyMenus ();
diff --git a/rkward/windows/katepluginintegration.cpp b/rkward/windows/katepluginintegration.cpp
index 66dc2e8c..c49d6a30 100644
--- a/rkward/windows/katepluginintegration.cpp
+++ b/rkward/windows/katepluginintegration.cpp
@@ -146,8 +146,18 @@ void KatePluginIntegrationApp::loadPlugins(const QStringList& plugins) {
 	}
 
 	if (!changes) return;
-	RKWardMainWindow::getMain()->factory()->removeClient(mainWindow());
-	RKWardMainWindow::getMain()->factory()->addClient(mainWindow());
+
+	auto w = mainWindow();
+	auto pf = w->persistentGuiClient()->factory();
+	if (pf) {
+		pf->removeClient(w->persistentGuiClient());
+		pf->addClient(w->persistentGuiClient());
+	}
+	auto df = w->dynamicGuiClient()->factory();
+	if (df) {
+		df->removeClient(w->dynamicGuiClient());
+		df->addClient(w->dynamicGuiClient());
+	}
 }
 
 void KatePluginIntegrationApp::unloadPlugin(const QString &identifier) {
@@ -176,7 +186,7 @@ void KatePluginIntegrationApp::saveConfigAndUnload() {
 	RK_TRACE (APP);
 
 	for (auto it = known_plugins.constBegin(); it != known_plugins.constEnd(); ++it) {
-		unloadPlugin (it.key());
+		unloadPlugin(it.key());
 	}
 	known_plugins.clear();
 }
@@ -300,18 +310,25 @@ KTextEditor::Plugin *KatePluginIntegrationApp::plugin(const QString &name) {
 ///  BEGIN  KTextEditor::MainWindow interface
 
 
-KatePluginIntegrationWindow::KatePluginIntegrationWindow (KatePluginIntegrationApp *parent) : QObject (parent), KXMLGUIClient () {
-	RK_TRACE (APP);
+KatePluginIntegrationWindow::KatePluginIntegrationWindow(KatePluginIntegrationApp *parent) : QObject(parent), KXMLGUIClient() {
+	RK_TRACE(APP);
 
 	// This one is passed to each created plugin
 	main = new KTextEditor::MainWindow(this);
 	// While this one may be accessed from plugins via KTextEditor::Editor::instance()->application()
 	app = parent;
-	active_plugin = 0;
+	active_plugin = nullptr;
+	dynamic_actions_client = new KXMLGUIClient();
 
 	connect(RKWorkplace::getHistory(), &RKMDIWindowHistory::activeWindowChanged, this, &KatePluginIntegrationWindow::activeWindowChanged);
 }
 
+KatePluginIntegrationWindow::~KatePluginIntegrationWindow() {
+	RK_TRACE(APP);
+	delete dynamic_actions_client;
+}
+
+
 class KatePluginToolWindow : public RKMDIWindow {
 	Q_OBJECT
 public:
@@ -508,13 +525,12 @@ bool KatePluginIntegrationWindow::viewsInSameSplitView(KTextEditor::View* view1,
 void KatePluginIntegrationWindow::fixUpPluginUI(const QString &id, const PluginResources &resources) {
 	RK_TRACE (APP);
 
-	KXMLGUIClient* hacked_parent = this;
 	// KF6 TODO: In KF6, plugins will probably be limited to one UI client, in the first place.
 	for (int i = 0; i < resources.clients.size(); ++i) {
 		KXMLGUIClient* client = resources.clients[i];
 		RKMDIWindow* window = resources.windows.value(i);
 		if (window) {
-			hacked_parent = window->getPart();;
+			window->addUiBuddy(dynamic_actions_client);
 		}
 		factory()->removeClient(client);
 
@@ -534,10 +550,12 @@ void KatePluginIntegrationWindow::fixUpPluginUI(const QString &id, const PluginR
 			// TODO: Rename "Search more" to something sensible. These actions should still be accessible, globally.
 		} else if (i == 0 && id == QStringLiteral("kateprojectplugin")) {
 			RKCommonFunctions::moveContainer(client, "Menu", "projects", "view", true, false);
+		} else if (i == 0 && id == QStringLiteral("katectagsplugin")) {
+			RKCommonFunctions::moveContainer(client, "Menu", "CTags Menubar", "view", true, false);
 		}
 
 		RKCommonFunctions::moveContainer(client, "Menu", "tools", "edit", true, true);
-		hacked_parent->insertChildClient(client);
+		dynamic_actions_client->insertChildClient(client);
 	}
 
 /* TODO: Ok, I guess we need even more specialization.
diff --git a/rkward/windows/katepluginintegration.h b/rkward/windows/katepluginintegration.h
index c07547ef..98c4b038 100644
--- a/rkward/windows/katepluginintegration.h
+++ b/rkward/windows/katepluginintegration.h
@@ -78,7 +78,10 @@ class KatePluginIntegrationWindow : public QObject, public KXMLGUIClient {
 	Q_OBJECT
 public:
 	KatePluginIntegrationWindow(KatePluginIntegrationApp *parent);
+	~KatePluginIntegrationWindow();
 	KTextEditor::MainWindow *mainWindow() const { return main; };
+	KXMLGUIClient* persistentGuiClient() { return this; }
+	KXMLGUIClient* dynamicGuiClient() const { return dynamic_actions_client; }
 private slots:
 	// These are the implementations of the KTextEditor::MainWindow interface.
 	// NOTE that they are not technically overrides, but get invoked via QMetaObject::invokeMethod()
@@ -117,6 +120,7 @@ friend class KatePluginIntegrationApp;
 	QHash<KTextEditor::Plugin*, PluginResources> plugin_resources;
 
 	KatePluginIntegrationApp *app;
+	KXMLGUIClient *dynamic_actions_client;
 private slots:
 	void catchXMLGUIClientsHack(KXMLGUIClient* client);
 	void activeWindowChanged(RKMDIWindow *window);
diff --git a/rkward/windows/rkcommandeditorwindow.cpp b/rkward/windows/rkcommandeditorwindow.cpp
index a682fba5..d99e099b 100644
--- a/rkward/windows/rkcommandeditorwindow.cpp
+++ b/rkward/windows/rkcommandeditorwindow.cpp
@@ -113,6 +113,7 @@ RKCommandEditorWindow::RKCommandEditorWindow (QWidget *parent, const QUrl _url,
 	m_doc = 0;
 	preview_dir = 0;
 	visible_to_kateplugins = flags & RKCommandEditorFlags::VisibleToKTextEditorPlugins;
+	if (visible_to_kateplugins) addUiBuddy(RKWardMainWindow::getMain()->katePluginIntegration()->mainWindow()->dynamicGuiClient());
 	bool use_r_highlighting = (flags & RKCommandEditorFlags::ForceRHighlighting) || (url.isEmpty() && (flags & RKCommandEditorFlags::DefaultToRHighlighting)) || RKSettingsModuleCommandEditor::matchesScriptFileFilter (url.fileName ());
 
 	// Lookup of existing text editor documents: First, if no url is given at all, create a new document, and register an id, in case this window will get split, later
diff --git a/rkward/windows/rkmdiwindow.cpp b/rkward/windows/rkmdiwindow.cpp
index 3d8c95e1..fd54f637 100644
--- a/rkward/windows/rkmdiwindow.cpp
+++ b/rkward/windows/rkmdiwindow.cpp
@@ -65,13 +65,14 @@ RKMDIWindow::RKMDIWindow (QWidget *parent, int type, bool tool_window, const cha
 	}
 	RKMDIWindow::type = type;
 	state = Attached;
-	tool_window_bar = 0;
-	part = 0;
+	tool_window_bar = nullptr;
+	part = nullptr;
 	active = false;
 	no_border_when_active = false;
-	standard_client = 0;
-	status_popup = 0;
-	status_popup_container = 0;
+	standard_client = nullptr;
+	status_popup = nullptr;
+	status_popup_container = nullptr;
+	ui_buddy = nullptr;
 
 	if (!(type & KatePluginWindow)) setWindowIcon (RKStandardIcons::iconForWindow (this));
 }
@@ -428,4 +429,9 @@ void RKMDIWindow::showWindowSettings () {
 	RKSettings::configureSettings (settings_page, this);
 }
 
+void RKMDIWindow::addUiBuddy(KXMLGUIClient* buddy) {
+	RK_TRACE(APP);
+	RK_ASSERT(!ui_buddy);
+	ui_buddy = buddy;
+}
 
diff --git a/rkward/windows/rkmdiwindow.h b/rkward/windows/rkmdiwindow.h
index 051472e1..ec20a0cb 100644
--- a/rkward/windows/rkmdiwindow.h
+++ b/rkward/windows/rkmdiwindow.h
@@ -122,6 +122,11 @@ is simply busy (e.g. when saving the current plot to history). */
 	KActionCollection *standardActionCollection ();
 /** plugin-accessible properties of this object in the global context. Currently used only by RKEditorDataFrame to give information on the currently active data.frame. NOTE: ATM, you cannot set arbitrary properties. Only those supported in RKStandardComponent will have an effect. */
 	QString globalContextProperty (const QString& property) { return global_context_properties.value (property); };
+
+/** Add an xml client that should be active, whenever this window is active. Noteably the KatePluginIntegrationWindow for kate related windows.
+ *  For the time being, only a single buddy is allowed, and it must outlive all mdi windows. */
+	void addUiBuddy(KXMLGUIClient* buddy);
+	KXMLGUIClient* uiBuddy() const { return ui_buddy; };
 signals:
 /** This signal is emitted, whenever the window caption was changed.
 @param RKMDIWindow* a pointer to this window */
@@ -138,6 +143,7 @@ protected:
 	void initializeActivationSignals ();
 	void paintEvent (QPaintEvent *e) override;
 	void changeEvent (QEvent *event) override;
+	void removeUiBuddy(QObject* buddy);
 
 /** reimplemented from QWidget to emulate focus-follows-mouse behavior */
 	void enterEvent (QEvent *event) override;
@@ -167,6 +173,7 @@ friend class RKToolWindowBar;
 	QString generic_window_name;
 	QUrl help_url;
 	RKSettings::SettingsPage settings_page;
+	KXMLGUIClient* ui_buddy;
 };
 
 #endif
diff --git a/rkward/windows/rkworkplace.cpp b/rkward/windows/rkworkplace.cpp
index 46a66535..74f8bccd 100644
--- a/rkward/windows/rkworkplace.cpp
+++ b/rkward/windows/rkworkplace.cpp
@@ -738,20 +738,27 @@ void RKWorkplace::windowRemoved () {
 	// give up
 }
 
-RKMDIWindow *RKWorkplace::activeWindow (RKMDIWindow::State state) {
+RKMDIWindow *RKWorkplace::activeWindow(RKMDIWindow::State state) const {
 	RK_TRACE (APP);
 
-	RKMDIWindow *ret = 0;
-	for (RKWorkplaceObjectList::const_iterator it = windows.constBegin (); it != windows.constEnd (); ++it) {
+	for (auto it = windows.constBegin (); it != windows.constEnd (); ++it) {
 		if (!(state & ((*it)->state))) continue;
 
 		if ((*it)->isActive ()) {
-			ret = *it;
-			break;
+			return *it;
 		}
 	}
+	return nullptr;
+}
 
-	return (ret);
+RKMDIWindow * RKWorkplace::windowForPart(KParts::Part* part) const {
+	RKMDIWindow *ret = 0;
+	for (auto it = windows.constBegin(); it != windows.constEnd(); ++it) {
+		if ((*it)->getPart() == part) {
+			return *it;
+		}
+	}
+	return nullptr;
 }
 
 QUrl checkAdjustRestoredUrl (const QString &_url, const QString old_base) {
diff --git a/rkward/windows/rkworkplace.h b/rkward/windows/rkworkplace.h
index 6eeddce4..c49d5bc3 100644
--- a/rkward/windows/rkworkplace.h
+++ b/rkward/windows/rkworkplace.h
@@ -110,7 +110,9 @@ public:
 /** Detouch a window (it is removed from the view (), and placed in a top-level DetachedWindowContainer instead. */
 	void detachWindow (RKMDIWindow *window, bool was_attached=true);
 /** @returns a pointer to the current window. state specifies, which windows should be considered. */
-	RKMDIWindow *activeWindow (RKMDIWindow::State state);
+	RKMDIWindow *activeWindow (RKMDIWindow::State state) const;
+/** @returns the RKMDIWindow holding the given part */
+	RKMDIWindow *windowForPart(KParts::Part *part) const;
 
 /** Opens the given url in the appropriate way. */
 	bool openAnyUrl (const QUrl &url, const QString &known_mimetype = QString (), bool force_external=false);




More information about the rkward-tracker mailing list