[rkward/work/generalized_preview] rkward: Implement creating (named) docked preview regions, and fix some bugs regarding named windows placement.

Thomas Friedrichsmeier thomas.friedrichsmeier at ruhr-uni-bochum.de
Tue Jan 5 19:33:14 UTC 2016


Git commit 7b716b8c4940dea3cf70b45ce742063f1230e592 by Thomas Friedrichsmeier.
Committed on 05/01/2016 at 19:30.
Pushed by tfry into branch 'work/generalized_preview'.

Implement creating (named) docked preview regions, and fix some bugs regarding named windows placement.

With this commits, the basics for generalized previews should be in place, although there is quite some
polishing (and documenting) left to do.

M  +32   -29   rkward/plugin/rkpreviewbox.cpp
M  +7    -3    rkward/plugin/rkpreviewbox.h
M  +10   -2    rkward/plugin/rkstandardcomponent.cpp
M  +3    -1    rkward/plugin/rkstandardcomponent.h
M  +11   -10   rkward/plugin/rkstandardcomponentgui.cpp
M  +1    -1    rkward/plugin/rkstandardcomponentgui.h
M  +2    -0    rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
M  +11   -3    rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
M  +11   -5    rkward/windows/rkworkplace.cpp
M  +1    -1    rkward/windows/rkworkplace.h

http://commits.kde.org/rkward/7b716b8c4940dea3cf70b45ce742063f1230e592

diff --git a/rkward/plugin/rkpreviewbox.cpp b/rkward/plugin/rkpreviewbox.cpp
index 7bd8fc1..908fc55 100644
--- a/rkward/plugin/rkpreviewbox.cpp
+++ b/rkward/plugin/rkpreviewbox.cpp
@@ -2,7 +2,7 @@
                           rkpreviewbox  -  description
                              -------------------
     begin                : Wed Jan 24 2007
-    copyright            : (C) 2007, 2009, 2012 by Thomas Friedrichsmeier
+    copyright            : (C) 2007-2016 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -23,14 +23,16 @@
 #include <QTextDocument>
 
 #include <klocale.h>
+#include <kvbox.h>
 
 #include "../rkglobals.h"
 #include "../rbackend/rinterface.h"
 #include "../misc/xmlhelper.h"
 #include "../windows/rkwindowcatcher.h"
+#include "../windows/rkworkplace.h"
+#include "rkstandardcomponent.h"
 #include "../debug.h"
 
-#define START_DEVICE 101
 #define DO_PREVIEW 102
 
 RKPreviewBox::RKPreviewBox (const QDomElement &element, RKComponent *parent_component, QWidget *parent_widget) : RKComponent (parent_component, parent_widget) {
@@ -39,12 +41,12 @@ RKPreviewBox::RKPreviewBox (const QDomElement &element, RKComponent *parent_comp
 	preview_active = false;
 	prior_preview_done = true;
 	new_preview_pending = false;
-	dev_num = 0;
 
 	// get xml-helper
 	XMLHelper *xml = parent_component->xmlHelper ();
 
 	preview_mode = (PreviewMode) xml->getMultiChoiceAttribute (element, "mode", "plot;data;custom", 0, DL_INFO);
+	placement = (PreviewPlacement) xml->getMultiChoiceAttribute (element, "placement", "default;attached;detached;docked", (preview_mode == PlotPreview) ? 0 : 3, DL_INFO);
 	idprop = RObject::rQuote (QString ().sprintf ("%p", this));
 
 	// create and add property
@@ -60,10 +62,19 @@ RKPreviewBox::RKPreviewBox (const QDomElement &element, RKComponent *parent_comp
 	toggle_preview_box->setChecked (preview_active);
 	connect (toggle_preview_box, SIGNAL (stateChanged(int)), this, SLOT (changedState(int)));
 
-	// status lable
+	// status label
 	status_label = new QLabel (QString (), this);
 	vbox->addWidget (status_label);
 
+	if (placement == DockedPreview) {
+		RKStandardComponent *uicomp = topmostStandardComponent ();
+		if (uicomp) {
+			QWidget *container = new KVBox ();
+			RKWorkplace::mainWorkplace ()->registerNamedWindow (idprop, this, container);
+			uicomp->addDockedPreview (container, state, toggle_preview_box->text ());
+		}
+	}
+
 	// find and connect to code property of the parent
 	QString dummy;
 	RKComponentBase *cp = parentComponent ()->lookupComponent ("code", &dummy);
@@ -130,12 +141,6 @@ void RKPreviewBox::tryPreview () {
 	updateStatusLabel ();
 }
 
-void RKPreviewBox::previewWindowClosed () {
-	RK_TRACE (PLUGIN);
-
-	dev_num = 0;
-}
-
 void RKPreviewBox::tryPreviewNow () {
 	RK_TRACE (PLUGIN);
 
@@ -157,14 +162,19 @@ void RKPreviewBox::tryPreviewNow () {
 
 	preview_active = true;
 
+	QString placement_command;
+	if (placement == AttachedPreview) placement_command = "attached";
+	else if (placement == DetachedPreview) placement_command = "detached";
+	placement_command = ".rk.with.placement.hint (" + RObject::rQuote (placement_command + ':' + idprop) + ", {\n";
+	QString placement_end = "\n})";
+
+	setStatusMessage (i18n ("Preview updating"));
 	if (preview_mode == PlotPreview) {
-		RKGlobals::rInterface ()->issueCommand (".rk.startPreviewDevice (" + idprop + ')', RCommand::Plugin | RCommand::Sync | RCommand::GetIntVector, QString (), this, START_DEVICE);
-		setStatusMessage (i18n ("Preview updating"));
-		RKGlobals::rInterface ()->issueCommand ("local({\n" + code_property->preview () + "})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PREVIEW);
+		RKGlobals::rInterface ()->issueCommand (placement_command + ".rk.startPreviewDevice (" + idprop + ')' + placement_end + "\nlocal({\n" + code_property->preview () + "})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PREVIEW);
 	} else if (preview_mode == DataPreview) {
-		RKGlobals::rInterface ()->issueCommand ("local({\n" + code_property->preview () + "\nrk.assign.preview.data(" + idprop + ", preview_data)\nrk.edit(rkward::.rk.variables$.rk.preview.data[[" + idprop + "]])\n})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PREVIEW);
+		RKGlobals::rInterface ()->issueCommand ("local({\n" + code_property->preview () + "\nrk.assign.preview.data(" + idprop + ", preview_data)\n" + placement_command + "rk.edit(rkward::.rk.variables$.rk.preview.data[[" + idprop + "]])" + placement_end + "\n})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PREVIEW);
 	} else {
-		RKGlobals::rInterface ()->issueCommand ("local({\n" + code_property->preview () + "})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PREVIEW);
+		RKGlobals::rInterface ()->issueCommand ("local({\n" + placement_command + code_property->preview () + placement_end + "})\n", RCommand::Plugin | RCommand::Sync, QString (), this, DO_PREVIEW);
 	}
 
 	prior_preview_done = false;
@@ -176,8 +186,10 @@ void RKPreviewBox::tryPreviewNow () {
 void RKPreviewBox::setStatusMessage(const QString& status) {
 	RK_TRACE (PLUGIN);
 
+	RKMDIWindow *window = RKWorkplace::mainWorkplace ()->getNamedWindow (idprop);
+	if (!window) return;
 	if (preview_mode == PlotPreview) {
-		RKCaughtX11Window::setStatusMessage (dev_num, status);
+		static_cast<RKCaughtX11Window*> (window)->setStatusMessage (status);
 	} else {
 #warning TODO
 	}
@@ -204,19 +216,10 @@ void RKPreviewBox::rCommandDone (RCommand *command) {
 	prior_preview_done = true;
 	if (new_preview_pending) tryPreview ();
 
-	if (command->getFlags () == START_DEVICE) {
-		int old_devnum = dev_num;
-		dev_num = command->intVector ().value (0, 0);
-		if (dev_num != old_devnum) {
-			disconnect (this, SLOT (previewWindowClosed()));
-			RKCaughtX11Window *window = RKCaughtX11Window::getWindow (dev_num);
-			if (window) connect (window, SIGNAL (destroyed(QObject*)), this, SLOT(previewWindowClosed()));
-		}
-	} else if (command->getFlags () == DO_PREVIEW) {
-		QString warnings = command->warnings () + command->error ();
-		if (!warnings.isEmpty ()) warnings = QString ("<b>%1</b>\n<pre>%2</pre>").arg (i18n ("Warnings or Errors:")).arg (Qt::escape (warnings));
-		setStatusMessage (warnings);
-	}
+	QString warnings = command->warnings () + command->error ();
+	if (!warnings.isEmpty ()) warnings = QString ("<b>%1</b>\n<pre>%2</pre>").arg (i18n ("Warnings or Errors:")).arg (Qt::escape (warnings));
+	setStatusMessage (warnings);
+
 	updateStatusLabel ();
 }
 
diff --git a/rkward/plugin/rkpreviewbox.h b/rkward/plugin/rkpreviewbox.h
index 470049c..fa74f4a 100644
--- a/rkward/plugin/rkpreviewbox.h
+++ b/rkward/plugin/rkpreviewbox.h
@@ -2,7 +2,7 @@
                           rkpreviewbox  -  description
                              -------------------
     begin                : Wed Jan 24 2007
-    copyright            : (C) 2007, 2012 by Thomas Friedrichsmeier
+    copyright            : (C) 2007-2016 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -47,7 +47,6 @@ public slots:
 	void changedState (RKComponentPropertyBase *);
 	void changedCode (RKComponentPropertyBase *);
 	void tryPreviewNow ();
-	void previewWindowClosed ();
 protected:
 	void rCommandDone (RCommand *);
 private:
@@ -59,12 +58,17 @@ private:
 	void killPreview ();
 	void updateStatusLabel ();
 	void setStatusMessage (const QString& status);
-	int dev_num;
 	enum PreviewMode {
 		PlotPreview,
 		DataPreview,
 		CustomPreview
 	} preview_mode;
+	enum PreviewPlacement {
+		DefaultPreview,
+		AttachedPreview,
+		DetachedPreview,
+		DockedPreview
+	} placement;
 	QTimer *update_timer;
 	QCheckBox *toggle_preview_box;
 	QLabel *status_label;
diff --git a/rkward/plugin/rkstandardcomponent.cpp b/rkward/plugin/rkstandardcomponent.cpp
index 337f312..369ff94 100644
--- a/rkward/plugin/rkstandardcomponent.cpp
+++ b/rkward/plugin/rkstandardcomponent.cpp
@@ -2,7 +2,7 @@
                           rkstandardcomponent  -  description
                              -------------------
     begin                : Sun Feb 19 2006
-    copyright            : (C) 2006, 2007, 2009, 2010, 2011, 2012, 2014 by Thomas Friedrichsmeier
+    copyright            : (C) 2006-2016 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -362,6 +362,14 @@ void RKStandardComponent::buildAndInitialize (const QDomElement &doc_element, co
 	standardInitializationComplete ();
 }
 
+void RKStandardComponent::addDockedPreview (QWidget* area, RKComponentPropertyBool* controller, const QString& label) {
+	RK_TRACE (PLUGIN);
+
+	RK_ASSERT (gui);
+	if (!gui) return;
+	gui->addDockedPreview (area, controller, label);
+}
+
 RKComponentBase::ComponentStatus RKStandardComponent::recursiveStatus () {
 	RK_TRACE (PLUGIN);
 
@@ -375,7 +383,7 @@ bool RKStandardComponent::submit (RCommandChain *in_chain) {
 
 	if (!isSatisfied ()) return false;
 
-        RCommandChain *prev_chain = command_chain;
+	RCommandChain *prev_chain = command_chain;
 	command_chain = in_chain;
 	gui->ok ();
 	command_chain = prev_chain;
diff --git a/rkward/plugin/rkstandardcomponent.h b/rkward/plugin/rkstandardcomponent.h
index 3c17219..372c23d 100644
--- a/rkward/plugin/rkstandardcomponent.h
+++ b/rkward/plugin/rkstandardcomponent.h
@@ -2,7 +2,7 @@
                           rkstandardcomponent  -  description
                              -------------------
     begin                : Sun Feb 19 2006
-    copyright            : (C) 2006, 2007, 2009, 2010, 2012, 2014 by Thomas Friedrichsmeier
+    copyright            : (C) 2006-2016 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -82,6 +82,8 @@ public:
 
 /** Return the GUI-scripting handler (creating it, if needed) */
 	RKComponentScriptingProxy* scriptingProxy ();
+
+	void addDockedPreview (QWidget *area, RKComponentPropertyBool *controller, const QString& label);
 signals:
 	void standardInitializationComplete ();
 public slots:
diff --git a/rkward/plugin/rkstandardcomponentgui.cpp b/rkward/plugin/rkstandardcomponentgui.cpp
index 38fc80a..d7ff245 100644
--- a/rkward/plugin/rkstandardcomponentgui.cpp
+++ b/rkward/plugin/rkstandardcomponentgui.cpp
@@ -134,34 +134,35 @@ void RKStandardComponentGUI::createDialog (bool switchable) {
 	if (enslaved) toggle_code_box->hide ();
 	
 	// code display
-	KVBox *dummy = new KVBox ();
-	QLabel *lab = new QLabel (i18n ("<b>Code Preview</b> [optional status info]"), dummy);
-	lab->setStyleSheet ("background-color: rgb(100, 100, 255);");
-	code_display = new RKCommandEditorWindow (dummy, true, false);
+	code_display = new RKCommandEditorWindow (0, true, false);
 	code_display->setReadOnly (true);
 
 	splitter->addWidget (upper_widget);
 	splitter->setStretchFactor (0, 0);          // When resizing the dialog, *and* any preview is visible, effectively resize the preview. Dialog area can be resized via splitter.
 	splitter->setChildrenCollapsible (false);   // It's just too difficult to make this consistent, esp. for shrinking the dialog would _also_ be expected to collapse widgets. Besides, this makes it
 	                                            // easier to keep track of which expansions are currently visible.
-	addDockedPreview (dummy, &code_display_visibility, RKSettingsModulePlugins::defaultCodeHeight ());
+	addDockedPreview (code_display, &code_display_visibility, i18n ("Code Preview"), RKSettingsModulePlugins::defaultCodeHeight ());
 
 	if (!enslaved && RKSettingsModulePlugins::showCodeByDefault ()) {
 		toggle_code_box->setChecked (true);	// will trigger showing the code along with the dialog
 	}
 }
 
-void RKStandardComponentGUI::addDockedPreview (QWidget *area, RKComponentPropertyBool *controller, int sizehint) {
+void RKStandardComponentGUI::addDockedPreview (QWidget *area, RKComponentPropertyBool *controller, const QString& label, int sizehint) {
 	RK_TRACE (PLUGIN);
 
 	PreviewArea parea;
-	parea.area = area;
-	area->hide ();
+	KVBox *dummy = new KVBox ();
+	QLabel *lab = new QLabel (i18n ("<b>%1</b>", label), dummy);
+	lab->setStyleSheet ("background-color: rgb(100, 100, 255);");
+	area->setParent (dummy);
+	dummy->hide ();
+	parea.area = dummy;
 	parea.controller = controller;
 	parea.sizehint = sizehint;
 	previews.insert (0, parea);
 
-	splitter->insertWidget (1, area);
+	splitter->insertWidget (1, dummy);
 	splitter->setStretchFactor (1, 1);
 
 	connect (controller, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (previewVisibilityChanged(RKComponentPropertyBase*)));
@@ -310,7 +311,7 @@ void RKStandardComponentGUI::codeChanged (RKComponentPropertyBase *) {
 void RKStandardComponentGUI::updateCode () {
 	RK_TRACE (PLUGIN);
 
-	if (code_display->isHidden ()) return;
+	if (!code_display_visibility.boolValue ()) return;
 	code_update_timer->start (0);
 }
 
diff --git a/rkward/plugin/rkstandardcomponentgui.h b/rkward/plugin/rkstandardcomponentgui.h
index 9ae8cf1..9f76428 100644
--- a/rkward/plugin/rkstandardcomponentgui.h
+++ b/rkward/plugin/rkstandardcomponentgui.h
@@ -83,7 +83,7 @@ public:
 	virtual void updateCode ();
 /** reimplemented from QWidget to take care of showing the code display if needed */
 	void showEvent (QShowEvent *e);
-	void addDockedPreview (QWidget *area, RKComponentPropertyBool *controller, int sizehint = -1);
+	void addDockedPreview (QWidget *area, RKComponentPropertyBool *controller, const QString& label, int sizehint = -1);
 public slots:
 	void ok ();
 	void cancel ();
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
index dc853a5..693fccb 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
@@ -190,6 +190,8 @@ void RKGraphicsDeviceFrontendTransmitter::newData () {
 			connect (device, SIGNAL (locatorDone(bool,double,double)), this, SLOT (locatorDone(bool,double,double)));
 			connect (device, SIGNAL (newPageConfirmDone(bool)), this, SLOT (newPageConfirmDone(bool)));
 			connect (this, SIGNAL (stopInteraction()), device, SLOT (stopInteraction()));
+			streamer.outstream << (qint32) 1;  // dummy reply
+			streamer.writeOutBuffer ();
 			continue;
 		} else {
 			if (devnum) device = RKGraphicsDevice::devices.value (devnum);
diff --git a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
index 3c0cb47..c6c619a 100644
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_stubs.cpp
@@ -185,9 +185,17 @@ static void RKD_QueryResolution (int *dpix, int *dpiy) {
 }
 
 static void RKD_Create (double width, double height, pDevDesc dev, const char *title, bool antialias) {
-	RKGraphicsDataStreamWriteGuard guard;
-	WRITE_HEADER (RKDCreate, dev);
-	RKD_OUT_STREAM << width << height << QString::fromUtf8 (title) << antialias;
+	{
+		RKGraphicsDataStreamWriteGuard guard;
+		WRITE_HEADER (RKDCreate, dev);
+		RKD_OUT_STREAM << width << height << QString::fromUtf8 (title) << antialias;
+	}
+	{
+		// Reading a reply in order to force this to be synchronous. .rk.with.placement.hint() may run into race conditions, otherwise.
+		RKGraphicsDataStreamReadGuard rguard;
+		quint32 dummy;
+		RKD_IN_STREAM >> dummy;
+	}
 }
 
 static void RKD_Size (double *left, double *right, double *top, double *bottom, pDevDesc dev) {
diff --git a/rkward/windows/rkworkplace.cpp b/rkward/windows/rkworkplace.cpp
index d5f1429..b8bf426 100644
--- a/rkward/windows/rkworkplace.cpp
+++ b/rkward/windows/rkworkplace.cpp
@@ -214,7 +214,7 @@ void RKWorkplace::addWindow (RKMDIWindow *window, bool attached) {
 	// a placment override / named window exists
 	if (!placement_override_spec.isEmpty ()) {
 		QString hint = placement_override_spec.section (':', 0, 0);
-		QString name = placement_override_spec.section (':', 1, 1);
+		QString name = placement_override_spec.section (':', 1);
 
 		if (hint == "attached") {
 			if (!attached) window->state = RKMDIWindow::Detached;   // Ok, yeah. BAD style. But windows that would go to detached by default would not prepareToBeAttached(), without this.
@@ -241,12 +241,16 @@ void RKWorkplace::addWindow (RKMDIWindow *window, bool attached) {
 			}
 
 			NamedWindow &nw = named_windows[pos];
-			if (nw.window && nw.window != window) {   // kill existing window (going to be replaced)
-				// TODO: this is not really elegant, yet, as it will change tab-placement (for attached windows), and discard / recreate container (for detached windows)
-				disconnect (nw.window, SIGNAL (destroyed(QObject*)), this, SLOT (namedWindowDestroyed(QObject*)));
-				nw.window->deleteLater ();
+			if (nw.window != window) {
+				if (nw.window) {  // kill existing window (going to be replaced)
+					// TODO: this is not really elegant, yet, as it will change tab-placement (for attached windows), and discard / recreate container (for detached windows)
+					disconnect (nw.window, SIGNAL (destroyed(QObject*)), this, SLOT (namedWindowDestroyed(QObject*)));
+					nw.window->deleteLater ();
+				}
 				nw.window = window;
+				connect (nw.window, SIGNAL (destroyed(QObject*)), this, SLOT (namedWindowDestroyed(QObject*)));
 			}
+			named_windows[pos] = nw;
 
 			// add window in the correct area
 			if (nw.parent == RKWardMainWindow::getMain ()) attached = true;
@@ -337,6 +341,8 @@ void RKWorkplace::namedWindowDestroyed (QObject* window) {
 			if (!named_windows[i].owner) {
 				named_windows.removeAt (i);
 				return;
+			} else {
+				named_windows[i].window = 0;
 			}
 		}
 	}
diff --git a/rkward/windows/rkworkplace.h b/rkward/windows/rkworkplace.h
index 5a2d4ec..1062329 100644
--- a/rkward/windows/rkworkplace.h
+++ b/rkward/windows/rkworkplace.h
@@ -211,7 +211,7 @@ friend class RKToolWindowBar;
 		/** Where to place window, if it does not exist, yet. Can be one of 0: detached, RKWardMainWindow::getMain(): attached, any other: docked in a special region */
 		QPointer<QWidget> parent;
 		/** Pointer to window, if it exists, already */
-		QPointer<RKMDIWindow> window;
+		RKMDIWindow* window;
 		/** Identifier string */
 		QString id;
 	};



More information about the rkward-tracker mailing list