[rkward/frameworks] /: Merge branch 'master' into frameworks

Thomas Friedrichsmeier thomas.friedrichsmeier at ruhr-uni-bochum.de
Mon Jan 11 20:25:59 UTC 2016


Git commit 924ea47cb379497e8bf3d43b0b509f68b9178b27 by Thomas Friedrichsmeier.
Committed on 11/01/2016 at 20:25.
Pushed by tfry into branch 'frameworks'.

Merge branch 'master' into frameworks

M  +8    -0    ChangeLog
M  +20   -20   rkward/core/rkvariable.cpp
M  +0    -2    rkward/core/rkvariable.h
M  +1    -1    rkward/core/robject.h
M  +19   -4    rkward/dataeditor/twintable.cpp
M  +5    -1    rkward/dataeditor/twintable.h
M  +111  -45   rkward/plugin/rkpreviewbox.cpp
M  +21   -7    rkward/plugin/rkpreviewbox.h
M  +11   -3    rkward/plugin/rkstandardcomponent.cpp
M  +3    -1    rkward/plugin/rkstandardcomponent.h
M  +169  -39   rkward/plugin/rkstandardcomponentgui.cpp
M  +3    -1    rkward/rbackend/rinterface.cpp
M  +2    -0    rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
M  +5    -25   rkward/settings/rksettingsmoduleplugins.cpp
M  +6    -3    rkward/settings/rksettingsmoduleplugins.h
M  +73   -5    rkward/windows/rkmdiwindow.cpp
M  +13   -1    rkward/windows/rkmdiwindow.h
M  +8    -43   rkward/windows/rkwindowcatcher.cpp
M  +1    -14   rkward/windows/rkwindowcatcher.h
M  +126  -1    rkward/windows/rkworkplace.cpp
M  +28   -1    rkward/windows/rkworkplace.h
M  +3    -2    rkward/windows/robjectbrowser.cpp

http://commits.kde.org/rkward/924ea47cb379497e8bf3d43b0b509f68b9178b27

diff --cc ChangeLog
index 779d187,9bcc43f..a219040
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,9 -1,11 +1,17 @@@
 +- File selection fields in plugin dialogs remember the last used directory (per session), and check for a valid selection
 +- Better handling of text drag-and-drop inside the R console window
 +
 +--- Version 0.6.5 - XXXXXXXXXXXXXXX
 +
 +
+ - Fixed: Numerical (display) precision setting was not honored in data editor
+ - Fix several window activation quirks in "Focus follows mouse" mode
+ - File selectors in "Import XYZ" plugins now filter for standard file extensions, by default
+ - Add previews for CSV, SPSS, and Stata import plugins
+ - Allow previews for data, (HTML) output, and custom types of previews
+ - Allow previews to be docked to the dialog window
+ - Implicitly save code preview visibility and size (instead of the former explicit settings)
+ - data.frame objects outside of globalenv() can be opened read-only in an editor window
  - Show a warning screen when invoking plugins from the command line (or from clicking an rkward://-link in an external application)
  
  --- Version 0.6.4 - Dec-20-2015
diff --cc rkward/dataeditor/twintable.cpp
index 2d78d98,ecfab36..99a504e
--- a/rkward/dataeditor/twintable.cpp
+++ b/rkward/dataeditor/twintable.cpp
@@@ -193,9 -190,21 +195,21 @@@ void TwinTable::initTable (RKVarEditMod
  	addNotificationType (RObjectListener::MetaChanged);
  	listenForObject (object);
  	objectMetaChanged (object);
 -	connect (model, SIGNAL (hasDuplicates(QStringList)), this, SLOT (containsDuplicates(QStringList)));
 +	connect (model, &RKVarEditModel::hasDuplicates, this, &TwinTable::containsDuplicates);
  }
  
+ void TwinTable::setWindowStyleHint (const QString& hint) {
+ 	RK_TRACE (EDITOR);
+ 	if (hint == "preview") { // preview skin: Squeeze header as much as possible
+ 		metaview->horizontalHeader ()->hide ();
+ 		metaview->setMinimumHeight (metaview->rowHeight (0));
+ 		// Now, I just don't understand QSplitter sizing, here... Despite stretch factors being set, metaview continues to be the first to grow.
+ 		// Forcing minimum heigt of dataview help allocating initial size to the dataview, though.
+ 		dataview->setMinimumHeight (dataview->rowHeight (0) * 5);
+ 	}
+ 	RKMDIWindow::setWindowStyleHint (hint);
+ }
+ 
  void TwinTable::containsDuplicates (const QStringList& dupes) {
  	RK_TRACE (EDITOR);
  
diff --cc rkward/dataeditor/twintable.h
index 014e417,a43f566..bb12b42
--- a/rkward/dataeditor/twintable.h
+++ b/rkward/dataeditor/twintable.h
@@@ -30,7 -30,8 +30,8 @@@
  class TwinTableMember;
  class RKVarEditModel;
  class QActionGroup;
 -class KAction;
 +class QAction;
+ class QSplitter;
  
  /**
    *@author Thomas Friedrichsmeier
diff --cc rkward/plugin/rkpreviewbox.cpp
index 4702917,7ffa5bb..919f6c5
--- a/rkward/plugin/rkpreviewbox.cpp
+++ b/rkward/plugin/rkpreviewbox.cpp
@@@ -55,9 -60,9 +60,9 @@@ RKPreviewBox::RKPreviewBox (const QDomE
  	toggle_preview_box = new QCheckBox (xml->i18nStringAttribute (element, "label", i18n ("Preview"), DL_INFO), this);
  	vbox->addWidget (toggle_preview_box);
  	toggle_preview_box->setChecked (preview_active);
 -	connect (toggle_preview_box, SIGNAL (stateChanged(int)), this, SLOT (changedState(int)));
 +	connect (toggle_preview_box, &QCheckBox::stateChanged, this, &RKPreviewBox::changedStateFromUi);
  
- 	// status lable
+ 	// status label
  	status_label = new QLabel (QString (), this);
  	vbox->addWidget (status_label);
  
diff --cc rkward/plugin/rkpreviewbox.h
index 89ba0c1,c5028c9..24222a0
--- a/rkward/plugin/rkpreviewbox.h
+++ b/rkward/plugin/rkpreviewbox.h
@@@ -41,9 -41,9 +41,9 @@@ public
  	~RKPreviewBox ();
  	int type () { return ComponentPreviewBox; };
  	RKComponentPropertyBool *state;
- 	QVariant value (const QString &modifier=QString ()) { return (state->value (modifier)); };
+ 	QVariant value (const QString &modifier=QString ()) override;
  public slots:
 -	void changedState (int);
 +	void changedStateFromUi ();
  	void changedState (RKComponentPropertyBase *);
  	void changedCode (RKComponentPropertyBase *);
  	void tryPreviewNow ();
diff --cc rkward/plugin/rkstandardcomponentgui.cpp
index 543afe4,6678f40..ee180df
--- a/rkward/plugin/rkstandardcomponentgui.cpp
+++ b/rkward/plugin/rkstandardcomponentgui.cpp
@@@ -18,14 -18,12 +18,12 @@@
  #include "rkstandardcomponentgui.h"
  
  #include <klocale.h>
 -#include <kaction.h>
 +#include <QAction>
  #include <kactioncollection.h>
 -#include <kurl.h>
 +#include <QUrl>
  #include <kvbox.h>
- #include <khbox.h>
  
  #include <qtimer.h>
- #include <qlayout.h>
  #include <qpushbutton.h>
  #include <qlabel.h>
  #include <QCloseEvent>
@@@ -58,9 -64,14 +64,14 @@@ RKStandardComponentGUI::RKStandardCompo
  	// code update timer
  	code_update_timer = new QTimer (this);
  	code_update_timer->setSingleShot (true);
 -	connect (code_update_timer, SIGNAL (timeout()), this, SLOT (updateCodeNow()));
 +	connect (code_update_timer, &QTimer::timeout, this, &RKStandardComponentGUI::updateCodeNow);
  
  	if (!enslaved) {
+ 		// code display
+ 		code_display = new RKCommandEditorWindow (0, true, false);
+ 		code_display->setReadOnly (true);
+ 		addDockedPreview (code_display, &code_display_visibility, i18n ("Code Preview"), RKSettingsModulePlugins::defaultCodeHeight ());
+ 
  		KActionCollection *action_collection = new KActionCollection (this);
  		action_collection->addAction (KStandardAction::Copy, this, SLOT (copyCode()));
  	}
@@@ -120,26 -148,68 +148,68 @@@ void RKStandardComponentGUI::createDial
  	}
  	vbox->addStretch (2);
  	
- 	toggle_code_button = new QPushButton (i18n ("Code"), upper_widget);
- 	toggle_code_button->setCheckable (true);
- 	connect (toggle_code_button, &QPushButton::clicked, this, &RKStandardComponentGUI::toggleCode);
- 	vbox->addWidget (toggle_code_button);
- 	if (enslaved) toggle_code_button->hide ();
- 	
- 	// code display
- 	code_display = new RKCommandEditorWindow (this, true, false);
- 	code_display->setReadOnly (true);
- 	code_display->setMinimumHeight (RKSettingsModulePlugins::defaultCodeHeight ());
- 	code_display->hide ();
+ 	toggle_code_box = new QCheckBox (i18n ("Code Preview"), upper_widget);
 -	connect (toggle_code_box, SIGNAL (clicked()), this, SLOT (toggleCode()));
++	connect (toggle_code_box, &QCheckBox::clicked, this, &RKStandardComponentGUI::toggleCode);
+ 	vbox->addWidget (toggle_code_box);
+ 	if (enslaved) toggle_code_box->hide ();
  
- 	main_vbox->addWidget (upper_widget);
- 	main_vbox->addWidget (code_display);
+ 	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.
  
  	if (!enslaved && RKSettingsModulePlugins::showCodeByDefault ()) {
- 		toggle_code_button->setChecked (true);	// will trigger showing the code along with the dialog
+ 		toggle_code_box->setChecked (true);	// will trigger showing the code along with the dialog
+ 	}
+ }
+ 
+ void RKStandardComponentGUI::finalize () {
+ 	RK_TRACE (PLUGIN);
+ 
+ 	for (int i = 0; i < previews.size (); ++i) {
+ 		// Add preview to splitter. Also add a title bar to each preview.
+ 		QWidget *dummy = new QWidget ();
+ 		QVBoxLayout *vl = new QVBoxLayout (dummy);
+ 		vl->setContentsMargins (0, 0, 0, 0);
+ 		QFrame *line = new QFrame (dummy);
+ 		line->setFrameShape (QFrame::HLine);
+ 		vl->addWidget (line);
+ 		QHBoxLayout *hl = new QHBoxLayout ();
+ 		vl->addLayout (hl);
+ 		QLabel *lab = new QLabel (i18n ("<b>%1</b>", previews[i].label), dummy);
+ 		lab->setAlignment (Qt::AlignCenter);
+ 		QToolButton *tb = new QToolButton (dummy);
+ 		tb->setAutoRaise (true);
+ 		tb->setIcon (RKStandardIcons::getIcon (RKStandardIcons::ActionDelete));
+ 		tb->setProperty ("preview_area", QVariant::fromValue (dummy));
 -		connect (tb, SIGNAL (clicked()), this, SLOT (previewCloseButtonClicked()));
++		connect (tb, &QAbstractButton::clicked, this, &RKStandardComponentGUI::previewCloseButtonClicked);
+ 		hl->addStretch ();
+ 		hl->addWidget (lab);
+ 		hl->addWidget (tb);
+ 		hl->addStretch ();
+ 
+ 		vl->addWidget (previews[i].area);
+ 		previews[i].area->show ();
+ 		previews[i].area = dummy;
+ 		if (!(previews[i].controller->boolValue ())) dummy->hide ();
+ 		splitter->insertWidget (i+1, previews[i].area);
+ 		splitter->setStretchFactor (i+1, 1);
  	}
  }
  
+ void RKStandardComponentGUI::addDockedPreview (QWidget *area, RKComponentPropertyBool *controller, const QString& label, int sizehint) {
+ 	RK_TRACE (PLUGIN);
+ 
+ 	PreviewArea parea;
+ 	parea.area = area;
+ 	parea.controller = controller;
+ 	parea.sizehint = sizehint;
+ 	parea.label = label;
+ 	previews.insert (0, parea);
+ 
 -	connect (controller, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (previewVisibilityChanged(RKComponentPropertyBase*)));
++	connect (controller, &RKComponentPropertyBase::valueChanged, this, &RKStandardComponentGUI::previewVisibilityChanged);
+ };
+ 
  void RKStandardComponentGUI::showEvent (QShowEvent *e) {
  	RK_TRACE (PLUGIN);
  
diff --cc rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
index 4a3b9ba,693fccb..775f05e
--- a/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
+++ b/rkward/rbackend/rkwarddevice/rkgraphicsdevice_frontendtransmitter.cpp
@@@ -187,9 -187,11 +187,11 @@@ void RKGraphicsDeviceFrontendTransmitte
  			streamer.instream >> width >> height >> title >> antialias;
  			device = RKGraphicsDevice::newDevice (devnum, width, height, title, antialias);
  			RKWorkplace::mainWorkplace ()->newRKWardGraphisWindow (device, devnum+1);
 -			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()));
 +			connect (device, &RKGraphicsDevice::locatorDone, this, &RKGraphicsDeviceFrontendTransmitter::locatorDone);
 +			connect (device, &RKGraphicsDevice::newPageConfirmDone, this, &RKGraphicsDeviceFrontendTransmitter::newPageConfirmDone);
 +			connect (this, &RKGraphicsDeviceFrontendTransmitter::stopInteraction, device, &RKGraphicsDevice::stopInteraction);
+ 			streamer.outstream << (qint32) 1;  // dummy reply
+ 			streamer.writeOutBuffer ();
  			continue;
  		} else {
  			if (devnum) device = RKGraphicsDevice::devices.value (devnum);
diff --cc rkward/settings/rksettingsmoduleplugins.cpp
index e020b14,ca3a98c..c9e2a77
--- a/rkward/settings/rksettingsmoduleplugins.cpp
+++ b/rkward/settings/rksettingsmoduleplugins.cpp
@@@ -78,31 -79,9 +79,9 @@@ RKSettingsModulePlugins::RKSettingsModu
  	button_group->addButton (button, PreferWizard);
  	if ((button = button_group->button (interface_pref))) button->setChecked (true);
  
 -	connect (button_group, SIGNAL (buttonClicked(int)), this, SLOT (settingChanged()));
 +	connect (button_group, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &RKSettingsModulePlugins::settingChanged);
  	main_vbox->addWidget (button_box);
  
- 
- 	main_vbox->addSpacing (2*RKGlobals::spacingHint ());
- 
- 
- 	QGroupBox *code_frame = new QGroupBox (i18n ("R syntax display (in dialogs)"), this);
- 	group_layout = new QVBoxLayout (code_frame);
- 
- 	show_code_box = new QCheckBox (i18n ("Code shown by default"), code_frame);
- 	show_code_box->setChecked (show_code);
- 	connect (show_code_box, &QCheckBox::stateChanged, this, &RKSettingsModulePlugins::settingChanged);
- 	group_layout->addWidget (show_code_box);
- 
- 	KHBox *code_size_hbox = new KHBox (code_frame);
- 	new QLabel (i18n ("Default height of code display (pixels)"), code_size_hbox);
- 	code_size_box = new RKSpinBox (code_size_hbox);
- 	code_size_box->setIntMode (20, 5000, code_size);
- 	connect (code_size_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKSettingsModulePlugins::settingChanged);
- 	group_layout->addWidget (code_size_hbox);
- 
- 	main_vbox->addWidget (code_frame);
- 
- 
  	main_vbox->addSpacing (2*RKGlobals::spacingHint ());
  
  	QPushButton *pluginmap_config_button = new QPushButton (i18n ("Configure Active Plugins"), this);
diff --cc rkward/windows/rkmdiwindow.cpp
index 6c7576e,17be69c..1f08015
--- a/rkward/windows/rkmdiwindow.cpp
+++ b/rkward/windows/rkmdiwindow.cpp
@@@ -22,12 -22,13 +22,13 @@@
  #include <qtimer.h>
  #include <QEvent>
  #include <QPaintEvent>
++#include <QAction>
  
 -#include <kparts/event.h>
 +#include <kparts/partactivateevent.h>
  #include <kxmlguifactory.h>
  #include <kactioncollection.h>
  #include <klocale.h>
- #include <QAction>
 -#include <kaction.h>
+ #include <kpassivepopup.h>
  
  #include "rkworkplace.h"
  #include "rkworkplaceview.h"
@@@ -254,20 -259,44 +259,47 @@@ void RKMDIWindow::paintEvent (QPaintEve
  	}
  }
  
 -void RKMDIWindow::windowActivationChange (bool) {
 +void RKMDIWindow::changeEvent (QEvent *event) {
  	RK_TRACE (APP);
  
 -	// NOTE: active is NOT the same as isActive(). Active just means that this window *would* be active, if its toplevel window is active.
 -	if (active || (!isAttached ())) update ();
 +	if (event->type () == QEvent::ActivationChange) {
 +		// NOTE: active is NOT the same as isActive(). Active just means that this window *would* be active, if its toplevel window is active.
 +		if (active || (!isAttached ())) update ();
 +	}
 +	QFrame::changeEvent (event);
  }
  
- void RKMDIWindow::slotActivate () {
+ void RKMDIWindow::slotActivateForFocusFollowsMouse () {
  	RK_TRACE (APP);
  
+ 	if (!underMouse ()) return;
+ 
+ 	// we can't do without activateWindow(), below. Unfortunately, this has the side effect of raising the window (in some cases). This is not always what we want, e.g. if a 
+ 	// plot window is stacked above this window. (And since this is activation by mouse hover, this window is already visible, by definition!)
+ 	// So we try a heuristic (imperfect) to find, if there are any other windows stacked above this one, in order to re-raise them above this.
+ 	QWidgetList toplevels = qApp->topLevelWidgets ();
+ 	QWidgetList overlappers;
+ 	QWidget *window = topLevelWidget ();
+ 	QRect rect = window->frameGeometry ();
+ 	for (int i = toplevels.size () - 1; i >= 0; --i) {
+ 		QWidget *tl = toplevels[i];
+ 		if (!tl->isWindow ()) continue;
+ 		if (tl == window) continue;
+ 		if (tl->isHidden ()) continue;
+ 
+ 		QRect tlrect = tl->geometry ();
+ 		QRect intersected = tlrect.intersected (rect);
+ 		if (!intersected.isEmpty ()) {
+ 			QWidget *above = qApp->topLevelAt ((intersected.left () +intersected.right ()) / 2, (intersected.top () +intersected.bottom ()) / 2);
+ 			if (above && (above != window) && (above->isWindow ()) && (!above->isHidden ()) && (overlappers.indexOf (above) < 0)) overlappers.append (above);
+ 		}
+ 	}
+ 
  	activate (true);
+ 
+ 	for (int i = 0; i < overlappers.size (); ++i) {
+ 		overlappers[i]->raise ();
+ 	}
  }
  
  void RKMDIWindow::enterEvent (QEvent *event) {
@@@ -288,7 -322,37 +325,38 @@@
  	QFrame::enterEvent (event);
  }
  
+ void RKMDIWindow::setStatusMessage (const QString& message, RCommand *command) {
+ 	RK_TRACE (MISC);
+ 
+ 	if (!status_popup) {
+ 		status_popup = new KPassivePopup (this);
+ 		status_popup->setTimeout (0);
 -		disconnect (status_popup, SIGNAL (clicked()), status_popup, SLOT (hide()));   // no auto-hiding, please
++		disconnect (status_popup, SIGNAL (clicked()), status_popup, SLOT (hide()));   // no auto-hiding, please, either SIGNAL / SLOT mechanism
++		disconnect (status_popup, static_cast<void (KPassivePopup::*)()>(&KPassivePopup::clicked), status_popup, &QWidget::hide);
+ 	}
+ 
 -	if (command) connect (command->notifier (), SIGNAL (commandFinished (RCommand*)), this, SLOT (clearStatusMessage()));
++	if (command) connect (command->notifier (), &RCommandNotifier::commandFinished, this, &RKMDIWindow::clearStatusMessage);
+ 	if (!message.isEmpty ()) {
+ 		status_popup->setView (QString (), message);
+ 		status_popup->show (this->mapToGlobal (QPoint (20, 20)));
+ 	} else {
+ 		status_popup->hide ();
+ 	}
+ }
+ 
+ void RKMDIWindow::clearStatusMessage () {
+ 	RK_TRACE (APP);
+ 
+ 	setStatusMessage (QString ());
+ }
+ 
+ void RKMDIWindow::setWindowStyleHint (const QString& hint) {
+ 	RK_TRACE (APP);
+ 
+ 	if (hint == "preview") no_border_when_active = true;
+ }
+ 
 -void RKMDIWindow::setMetaInfo (const QString& _generic_window_name, const QString& _help_url, RKSettings::SettingsPage _settings_page) {
 +void RKMDIWindow::setMetaInfo (const QString& _generic_window_name, const QUrl& _help_url, RKSettings::SettingsPage _settings_page) {
  	RK_TRACE (APP);
  
  	// only meant to be called once
diff --cc rkward/windows/rkmdiwindow.h
index 20c357c,dfa2d4f..8243ec8
--- a/rkward/windows/rkmdiwindow.h
+++ b/rkward/windows/rkmdiwindow.h
@@@ -102,8 -103,14 +104,14 @@@ public
  	virtual void prepareToBeDetached ();
  /** Tool windows will only hide themselves, and ignore the also_delete flag */
  	virtual bool close (bool also_delete);
+ /** Set a status message to be shown in a popup inside the window. The message persists until the given R command has finished, or until this function is called with an empty string.
+ This should be used, when the information shown is currently out-of-date (e.g. when refreshing a preview / loading a plot from history), _not_ when the window
+ is simply busy (e.g. when saving the current plot to history). */
+ 	void setStatusMessage (const QString& message, RCommand* command=0);
+ /** Set a style hint for the window. So far the only interpreted style hint is "preview", and not all windows implement it. Base implements hiding of "active" indicator border for "preview"s. */
+ 	virtual void setWindowStyleHint (const QString& hint);
  
 -	bool eventFilter (QObject *watched, QEvent *e);
 +	bool eventFilter (QObject *watched, QEvent *e) override;
  	bool acceptsEventsFor (QObject *object);
  /** Whether the window is active. This seems to be more reliable than hasFocus () */
  	bool isActive ();
@@@ -120,15 -127,16 +128,16 @@@ signals
  protected slots:
  	void showWindowHelp ();
  	void showWindowSettings ();
+ 	void clearStatusMessage ();
  protected:
  	void setPart (KParts::Part *p) { part = p; };
 -	void setMetaInfo (const QString& generic_window_name, const QString& help_url, RKSettings::SettingsPage settings_page=RKSettings::NoPage);
 +	void setMetaInfo (const QString& generic_window_name, const QUrl& help_url, RKSettings::SettingsPage settings_page=RKSettings::NoPage);
  	void initializeActivationSignals ();
 -	void paintEvent (QPaintEvent *e);
 -	void windowActivationChange (bool);
 +	void paintEvent (QPaintEvent *e) override;
 +	void changeEvent (QEvent *event) override;
  
  /** reimplemented from QWidget to emulate focus-follows-mouse behavior */
 -	void enterEvent (QEvent *event);
 +	void enterEvent (QEvent *event) override;
  /** @see globalContextProperty() */
  	void setGlobalContextProperty (const QString& property, const QString& value) { global_context_properties.insert (property, value); };
  friend class RKWorkplace;
@@@ -147,8 -156,10 +157,10 @@@ friend class RKToolWindowBar
  /** @see globalContextProperty() */
  	QMap<QString, QString> global_context_properties;
  	QString generic_window_name;
 -	QString help_url;
 +	QUrl help_url;
  	RKSettings::SettingsPage settings_page;
+ 
+ 	KPassivePopup* status_popup;
  };
  
  #endif
diff --cc rkward/windows/rkwindowcatcher.cpp
index f90c452,dfbb613..021e04d
--- a/rkward/windows/rkwindowcatcher.cpp
+++ b/rkward/windows/rkwindowcatcher.cpp
@@@ -289,14 -240,16 +284,16 @@@ void RKCaughtX11Window::doEmbed () 
  #elif defined Q_WS_X11
  		capture = new QX11EmbedContainer (xembed_container);
  		capture->embedClient (embedded);
 -		connect (capture, SIGNAL (clientClosed()), this, SLOT (deleteLater()));
 +		connect (capture, &QWidget::clientClosed, this, &RKCaughtX11Window::deleteLater);
  
 -		RKWardApplication::getApp ()->registerNameWatcher (embedded, this);
 +		RKWindowCatcher::registerNameWatcher (embedded, this);
  #endif
  	}
- 	// make xembed_container resizable, again, now that it actually has a content
- 	dynamic_size_action->setChecked (true);
- 	fixedSizeToggled ();
+ 	if (!isAttached ()) {
+ 		// make xembed_container resizable, again, now that it actually has a content
+ 		dynamic_size_action->setChecked (true);
+ 		fixedSizeToggled ();
+ 	}
  
  	// try to be helpful when the window is too large to fit on screen
  	QRect dims = window ()->frameGeometry ();
@@@ -313,10 -266,9 +310,9 @@@ RKCaughtX11Window::~RKCaughtX11Window (
  
  	close (false);
  #ifdef Q_WS_X11
 -	if (embedded) RKWardApplication::getApp ()->unregisterNameWatcher (embedded);
 +	if (embedded) RKWindowCatcher::unregisterNameWatcher (embedded);
  #endif
  	error_dialog->autoDeleteWhenDone ();
- 	delete status_popup;
  }
  
  void RKCaughtX11Window::forceClose () {
diff --cc rkward/windows/rkwindowcatcher.h
index 096ef51,632148d..32b2a02
--- a/rkward/windows/rkwindowcatcher.h
+++ b/rkward/windows/rkwindowcatcher.h
@@@ -205,20 -181,17 +195,17 @@@ private
  
  	bool dynamic_size;
  	KToggleAction *dynamic_size_action;
 -	KAction *plot_prev_action;
 -	KAction *plot_next_action;
 -	KAction *plot_first_action;
 -	KAction *plot_last_action;
 -	KAction *plot_force_append_action;
 -	KAction *plot_remove_action;
 -	KAction *plot_clear_history_action;
 -	KAction *plot_properties_action;
 +	QAction *plot_prev_action;
 +	QAction *plot_next_action;
 +	QAction *plot_first_action;
 +	QAction *plot_last_action;
 +	QAction *plot_force_append_action;
 +	QAction *plot_remove_action;
 +	QAction *plot_clear_history_action;
 +	QAction *plot_properties_action;
  	KSelectAction *plot_list_action;
 -	KAction *stop_interaction;
 +	QAction *stop_interaction;
  
- 	KPassivePopup* status_popup;
- 	RCommand* status_change_command;
- 
  	int history_length;
  	int history_position;
  };
diff --cc rkward/windows/rkworkplace.cpp
index 6a9aedd,f16f8a0..8c3a4f5
--- a/rkward/windows/rkworkplace.cpp
+++ b/rkward/windows/rkworkplace.cpp
@@@ -220,10 -212,62 +221,62 @@@ void RKWorkplace::detachWindow (RKMDIWi
  void RKWorkplace::addWindow (RKMDIWindow *window, bool attached) {
  	RK_TRACE (APP);
  
+ 	// first handle placement overrides
+ 	if (window_placement_override == RKMDIWindow::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.
+ 		                                                        // TODO: Create third state: NotManaged
+ 		attached = true;
+ 	} else if (window_placement_override == RKMDIWindow::Detached) {
+ 		attached = false;
+ 	}
+ 
+ 	// style override. Windows may or may not handle this
+ 	if (!window_style_override.isEmpty ()) window->setWindowStyleHint (window_style_override);
+ 
+ 	// next handle name overrides, if any
+ 	if (!window_name_override.isEmpty ()) {
+ 		int pos = -1;
+ 		for (int i = 0; i < named_windows.size (); ++i) {
+ 			if (named_windows[i].id == window_name_override) {
+ 				pos = i;
+ 				break;
+ 			}
+ 		}
+ 		if (pos < 0) {   // not yet known: implicit registration -> create corresponing named_window_spec on the fly.
+ 			registerNamedWindow (window_name_override, 0, attached ? RKWardMainWindow::getMain () : 0);
+ 			pos = named_windows.size () - 1;
+ 		}
+ 
+ 		NamedWindow &nw = named_windows[pos];
+ 		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*)));
++				disconnect (nw.window, &QObject::destroyed, this, &RKWorkplace::namedWindowDestroyed);
+ 				nw.window->deleteLater ();
+ 			}
+ 			nw.window = window;
 -			connect (nw.window, SIGNAL (destroyed(QObject*)), this, SLOT (namedWindowDestroyed(QObject*)));
++			connect (nw.window, &QObject::destroyed, this, &RKWorkplace::namedWindowDestroyed);
+ 		}
+ 		named_windows[pos] = nw;
+ 
+ 		// add window in the correct area
+ 		if (nw.parent == RKWardMainWindow::getMain ()) attached = true;
+ 		else if (nw.parent == 0) attached = false;
+ 		else { // custom parent
+ 			window->prepareToBeAttached ();
+ 			window->setParent (nw.parent);
+ 			// TODO: do this is somewhat inconsistent. But such windows are not attached to the main workplace view, which makes them rather behave detached.
+ 			window->state = RKMDIWindow::Detached;
+ 			// NOTE: The window is _not_ added to the window list/window history in this case.
+ 			return;
+ 		}
+ 	}
+ 
  	windows.append (window);
 -	connect (window, SIGNAL (destroyed(QObject*)), this, SLOT (removeWindow(QObject*)));
 -	connect (window, SIGNAL (windowActivated(RKMDIWindow*)), history, SLOT (windowActivated(RKMDIWindow*)));
 +	connect (window, &QObject::destroyed, this, &RKWorkplace::removeWindow);
 +	connect (window, &RKMDIWindow::windowActivated, history, &RKMDIWindowHistory::windowActivated);
  	if (window->isToolWindow () && !window->tool_window_bar) return;
+ 
  	if (attached) attachWindow (window);
  	else detachWindow (window, false);
  }
@@@ -256,10 -300,82 +309,82 @@@ void RKWorkplace::placeInToolWindowBar 
  	else if (needs_registration) attachWindow (window);
  }
  
+ void RKWorkplace::setWindowPlacementOverrides(const QString& placement, const QString& name, const QString& style) {
+ 	RK_TRACE (APP);
+ 
+ 	if (placement == "attached") window_placement_override = RKMDIWindow::Attached;
+ 	else if (placement == "detached") window_placement_override = RKMDIWindow::Attached;
+ 	else {
+ 		RK_ASSERT (placement.isEmpty ());
+ 		window_placement_override = RKMDIWindow::AnyWindowState;
+ 	}
+ 	window_name_override = name;
+ 	window_style_override = style;
+ }
+ 
+ void RKWorkplace::registerNamedWindow (const QString& id, QObject* owner, QWidget* parent, RKMDIWindow* window) {
+ 	RK_TRACE (APP);
+ 
+ 	NamedWindow nw;
+ 	nw.id = id;
+ 	nw.owner = owner;
+ 	nw.parent = parent;
+ 	nw.window = window;
+ 
+ 	for (int i = 0; i < named_windows.size (); ++i) {
+ 		RK_ASSERT (named_windows[i].id != id);
+ 	}
+ 
+ 	named_windows.append (nw);
 -	if (owner) connect (owner, SIGNAL (destroyed(QObject*)), this, SLOT (namedWindowOwnerDestroyed(QObject*)));
 -	if (window) connect (window, SIGNAL (destroyed(QObject*)), this, SLOT (namedWindowDestroyed(QObject*)));
++	if (owner) connect (owner, &QObject::destroyed, this, &RKWorkplace::namedWindowOwnerDestroyed);
++	if (window) connect (window, &QObject::destroyed, this, &RKWorkplace::namedWindowOwnerDestroyed);
+ }
+ 
+ RKMDIWindow* RKWorkplace::getNamedWindow (const QString& id) {
+ 	RK_TRACE (APP);
+ 
+ 	for (int i = 0; i < named_windows.size (); ++i) {
+ 		if (named_windows[i].id == id) {
+ 			return named_windows[i].window;
+ 		}
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ void RKWorkplace::namedWindowDestroyed (QObject* window) {
+ 	RK_TRACE (APP);
+ 
+ 	for (int i = 0; i < named_windows.size (); ++i) {
+ 		if (named_windows[i].window == window) {
+ 			if (!named_windows[i].owner) {
+ 				named_windows.removeAt (i);
+ 				return;
+ 			} else {
+ 				named_windows[i].window = 0;
+ 			}
+ 		}
+ 	}
+ }
+ 
+ void RKWorkplace::namedWindowOwnerDestroyed (QObject* owner) {
+ 	RK_TRACE (APP);
+ 
+ 	for (int i = 0; i < named_windows.size (); ++i) {
+ 		if (named_windows[i].owner == owner) {
+ 			if (named_windows[i].window) {
+ 				named_windows[i].window->deleteLater ();
+ 			}
+ 			named_windows.removeAt (i);
+ 			return;
+ 		}
+ 	}
+ }
+ 
 -bool RKWorkplace::openAnyUrl (const KUrl &url, const QString &known_mimetype, bool force_external) {
 +bool RKWorkplace::openAnyUrl (const QUrl &url, const QString &known_mimetype, bool force_external) {
  	RK_TRACE (APP);
  
 -	if (url.protocol () == "rkward") {
 +	if (url.scheme () == "rkward") {
  		if (RKHTMLWindow::handleRKWardURL (url)) return true;
  	}
  	KMimeType::Ptr mimetype;
diff --cc rkward/windows/rkworkplace.h
index b91e496,afd8258..6263847
--- a/rkward/windows/rkworkplace.h
+++ b/rkward/windows/rkworkplace.h
@@@ -22,9 -22,8 +22,10 @@@
  #include <qstring.h>
  #include <qtabwidget.h>
  #include <QSplitter>
++#include <QPointer>
  
 -#include <kurl.h>
 +#include <QUrl>
 +#include <kconfigbase.h>
  
  #include "rkmdiwindow.h"
  #include "rktoolwindowlist.h"
@@@ -159,19 -158,29 +160,29 @@@ Has no effect, if RKSettingsModuleGener
  	static RKMDIWindowHistory *getHistory () { return main_workplace->history; };
  	void placeToolWindows ();
  
 -	void setWorkspaceURL (const KUrl &url, bool keep_config=false);
 -	KUrl workspaceURL () const { return current_url; };
 +	void setWorkspaceURL (const QUrl &url, bool keep_config=false);
 +	QUrl workspaceURL () const { return current_url; };
  	KConfigBase *workspaceConfig ();
 -	QString portableUrl (const KUrl &url);
 +	QString portableUrl (const QUrl &url);
+ /** Register a named area where to place MDI windows. For directing preview windows to a specific location. */
+ 	void registerNamedWindow (const QString& id, QObject *owner, QWidget* parent, RKMDIWindow *window=0);
+ /** Return the window in the specified named area (can be 0). */
+ 	RKMDIWindow *getNamedWindow (const QString& id);
+ /** Make the next window to be created appear in a specific location (can be a named window). 
+  *  @note It is the caller's responsibility to clear the override (by calling setWindowPlacementOverride ()) after the window in question has been created. */
+ 	void setWindowPlacementOverrides (const QString& placement=QString (), const QString& name=QString (), const QString& style=QString ());
  signals:
  /** emitted when the workspace Url has changed */
 -	void workspaceUrlChanged (const KUrl& url);
 +	void workspaceUrlChanged (const QUrl &url);
  public slots:
  /** When windows are attached to the workplace, their QObject::destroyed () signal is connected to this slot. Thereby deleted objects are removed from the workplace automatically */
  	void removeWindow (QObject *window);
  	void saveSettings ();
+ private slots:
+ 	void namedWindowDestroyed (QObject *);
+ 	void namedWindowOwnerDestroyed (QObject *);
  private:
 -	KUrl current_url;
 +	QUrl current_url;
  	KConfig *_workspace_config;
  
  /** current list of windows. @See getObjectList () */ 



More information about the rkward-tracker mailing list