[rkward-cvs] SF.net SVN: rkward:[3526] trunk/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Mon Apr 25 09:28:52 UTC 2011


Revision: 3526
          http://rkward.svn.sourceforge.net/rkward/?rev=3526&view=rev
Author:   tfry
Date:     2011-04-25 09:28:51 +0000 (Mon, 25 Apr 2011)

Log Message:
-----------
Add stack-based window switching using Ctrl+(Shift)+Tab

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/rkward/rkward.cpp
    trunk/rkward/rkward/rkwardui.rc
    trunk/rkward/rkward/windows/rkmdiwindow.cpp
    trunk/rkward/rkward/windows/rktoplevelwindowgui.cpp
    trunk/rkward/rkward/windows/rktoplevelwindowgui.h
    trunk/rkward/rkward/windows/rktoplevelwindowgui.rc
    trunk/rkward/rkward/windows/rkworkplace.cpp
    trunk/rkward/rkward/windows/rkworkplace.h

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/ChangeLog	2011-04-25 09:28:51 UTC (rev 3526)
@@ -1,3 +1,6 @@
+- Added stack-based window switching using Ctrl+(Shift)+Tab; this replaces the old "Next Window" and "Previous Window" actions
+- Fixed: Graphics device windows would disappear when trying to attach them to the main window with some versions of Qt
+- Fixed: tcl/tk widgets would locki up after running commands in the R Console
 - Provide a template for bug reports, containing standardized information on the RKWard setup in Help->Report Bug...
 - When loading a (local) workspace, change the working directory to the directory of the workspace (configurable)
 - Include the sidebar position of tool windows when saving / restoring the workplace layout

Modified: trunk/rkward/rkward/rkward.cpp
===================================================================
--- trunk/rkward/rkward/rkward.cpp	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/rkward.cpp	2011-04-25 09:28:51 UTC (rev 3526)
@@ -125,7 +125,7 @@
 	initStatusBar();
 
 	new RKWorkplace (this);
-	RKWorkplace::mainWorkplace ()->initActions (actionCollection (), "prev_window", "next_window", "left_window", "right_window");
+	RKWorkplace::mainWorkplace ()->initActions (actionCollection (), "left_window", "right_window");
 	setCentralWidget (RKWorkplace::mainWorkplace ());
 	connect (RKWorkplace::mainWorkplace ()->view (), SIGNAL (captionChanged (const QString &)), this, SLOT (setCaption (const QString &)));
 

Modified: trunk/rkward/rkward/rkwardui.rc
===================================================================
--- trunk/rkward/rkward/rkwardui.rc	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/rkwardui.rc	2011-04-25 09:28:51 UTC (rev 3526)
@@ -1,5 +1,5 @@
 <!DOCTYPE kpartgui>
-<kpartgui name="rkward_main" version="560">
+<kpartgui name="rkward_main" version="561">
 <MenuBar>
 	<!-- The Main Window ui.rc is the only one, where merging happens, reliably. That is, why we need to define
 	     a lot of merge points, here, which can then be used be mdi windows and their children.
@@ -66,9 +66,6 @@
 		<Action name="close_all_editors"/>
 		<Separator/>
 		<Menu name="window_activate"><text>&Activate</text>
-			<Action name="prev_window"/>
-			<Action name="next_window"/>
-			<Separator/>
 			<Action name="left_window"/>
 			<Action name="right_window"/>
 			<Separator/>

Modified: trunk/rkward/rkward/windows/rkmdiwindow.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkmdiwindow.cpp	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/windows/rkmdiwindow.cpp	2011-04-25 09:28:51 UTC (rev 3526)
@@ -119,7 +119,11 @@
 
 	if (isToolWindow ()) {
 		if (tool_window_bar) tool_window_bar->showWidget (this);
-		else RKWorkplace::mainWorkplace ()->detachWindow (this, true);
+		else if (!isVisible ()) RKWorkplace::mainWorkplace ()->detachWindow (this, true);
+		else {
+			topLevelWidget ()->show ();
+			topLevelWidget ()->raise ();
+		}
 	} else {
 		if (isAttached ()) RKWorkplace::mainWorkplace ()->view ()->setActivePage (this);
 		else {
@@ -128,6 +132,7 @@
 		}
 	}
 
+	emit (windowActivated (this));
 	if (with_focus) {
 		if (old_focus) old_focus->clearFocus ();
 		topLevelWidget ()->activateWindow ();

Modified: trunk/rkward/rkward/windows/rktoplevelwindowgui.cpp
===================================================================
--- trunk/rkward/rkward/windows/rktoplevelwindowgui.cpp	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/windows/rktoplevelwindowgui.cpp	2011-04-25 09:28:51 UTC (rev 3526)
@@ -39,6 +39,7 @@
 #include "../windows/rkmdiwindow.h"
 #include "../misc/rkstandardicons.h"
 #include "../misc/rkprogresscontrol.h"
+#include "../misc/rkcommonfunctions.h"
 #include "../plugin/rkcomponentmap.h"
 #include "../rbackend/rinterface.h"
 #include "../rkglobals.h"
@@ -70,6 +71,16 @@
 	show_rkward_help->setStatusTip (i18n ("Show help on RKWard"));
 
 	// window menu
+	// NOTE: enabling / disabling the prev/next actions is not a good idea. It will cause the script windows to "accept" their shortcuts, when disabled
+	prev_action = actionCollection ()->addAction ("prev_window", this, SLOT (previousWindow()));
+	prev_action->setText (i18n ("Previous Window"));
+	prev_action->setIcon (QIcon (RKCommonFunctions::getRKWardDataDir () + "icons/window_back.png"));
+	prev_action->setShortcut (Qt::ControlModifier + Qt::Key_Tab);
+	next_action = actionCollection ()->addAction ("next_window", this, SLOT (nextWindow()));
+	next_action->setText (i18n ("Next Window"));
+	next_action->setIcon (QIcon (RKCommonFunctions::getRKWardDataDir () + "icons/window_forward.png"));
+	next_action->setShortcut (Qt::ControlModifier + Qt::ShiftModifier + Qt::Key_Tab);
+
 	KAction *action;
 	foreach (RKToolWindowList::ToolWindowRepresentation rep, RKToolWindowList::registeredToolWindows ()) {
 		action = actionCollection ()->addAction ("window_show_" + rep.id, this, SLOT (toggleToolView()));
@@ -222,4 +233,17 @@
 	RKWorkplace::mainWorkplace ()->openOutputWindow (KUrl ());
 }
 
+void RKTopLevelWindowGUI::nextWindow () {
+	RK_TRACE (APP);
+
+	// well, this is sort of cumbersome, but the switcher widget gets keyboard focus, and so we need to register the window switching actions with it.
+	RKWorkplace::getHistory ()->next (prev_action, next_action);
+}
+
+void RKTopLevelWindowGUI::previousWindow () {
+	RK_TRACE (APP);
+
+	RKWorkplace::getHistory ()->prev (prev_action, next_action);
+}
+
 #include "rktoplevelwindowgui.moc"

Modified: trunk/rkward/rkward/windows/rktoplevelwindowgui.h
===================================================================
--- trunk/rkward/rkward/windows/rktoplevelwindowgui.h	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/windows/rktoplevelwindowgui.h	2011-04-25 09:28:51 UTC (rev 3526)
@@ -24,6 +24,7 @@
 
 class KXmlGuiWindow;
 class RKMDIWindow;
+class KAction;
 
 /** represents the common portions of the GUI for top level windows: The help menu, and the windows menu */
 class RKTopLevelWindowGUI : public QObject, public KXMLGUIClient {
@@ -59,8 +60,12 @@
 	void configureToolbars ();
 private slots:
 	void toggleToolView ();
+	void previousWindow ();
+	void nextWindow ();
 private:
 	KXmlGuiWindow *for_window;
+	KAction *prev_action;
+	KAction *next_action;
 	void toggleToolView (RKMDIWindow *tool_window);
 };
 

Modified: trunk/rkward/rkward/windows/rktoplevelwindowgui.rc
===================================================================
--- trunk/rkward/rkward/windows/rktoplevelwindowgui.rc	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/windows/rktoplevelwindowgui.rc	2011-04-25 09:28:51 UTC (rev 3526)
@@ -1,5 +1,5 @@
 <!DOCTYPE kpartgui>
-<kpartgui name="rkward_toplevel" version="54">
+<kpartgui name="rkward_toplevel" version="560">
 	<MenuBar>
 		<Merge/>
 		<Menu name="window"><text>&Window</text>
@@ -7,6 +7,9 @@
 			<Action name="output_show"/>
 			<Separator/>
 			<Menu name="window_activate"><text>&Activate</text>
+				<Action name="prev_window"/>
+				<Action name="next_window"/>
+				<Separator/>
 				<Action name="window_show_workspace"/>
 				<Action name="window_show_filebrowser"/>
 				<Action name="window_show_commandlog"/>

Modified: trunk/rkward/rkward/windows/rkworkplace.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkworkplace.cpp	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/windows/rkworkplace.cpp	2011-04-25 09:28:51 UTC (rev 3526)
@@ -114,10 +114,9 @@
 	for (int i = 0; i < TOOL_WINDOW_BAR_COUNT; ++i) tool_window_bars[i]->saveSize (toolbar_config);
 }
 
-void RKWorkplace::initActions (KActionCollection *ac, const char *prev_id, const char *next_id, const char *left_id, const char *right_id) {
+void RKWorkplace::initActions (KActionCollection *ac, const char *left_id, const char *right_id) {
 	RK_TRACE (APP);
 
-	history->initActions (ac, prev_id, next_id);
 	wview->initActions (ac, left_id, right_id);
 }
 
@@ -164,6 +163,7 @@
 
 	DetachedWindowContainer *detached = new DetachedWindowContainer (window);
 	detached->show ();
+	if (!was_attached) window->activate ();
 }
 
 void RKWorkplace::addWindow (RKMDIWindow *window, bool attached) {
@@ -182,6 +182,7 @@
 
 	foreach (const RKToolWindowList::ToolWindowRepresentation rep, RKToolWindowList::registeredToolWindows ()) {
 		placeInToolWindowBar (rep.window, rep.default_placement);
+		getHistory ()->popLastWindow (rep.window);	// windows send a spurious activation signal triggered from KPartsManager::addPart(), so we pop them, again
 	}
 }
 
@@ -456,12 +457,10 @@
 	}
 
 	// some document window in the history? Try that.
-	if (history->haveNext ()) {
-		history->next ();
+	window = history->previousDocumentWindow ();
+	if (window) {
+		window->activate (true);
 		return;
-	} else if (history->havePrev ()) {
-		history->prev ();
-		return;
 	}
 
 	// now try to activate an attached (tool) window, if one is visible
@@ -662,110 +661,193 @@
 ///////////////////////// END RKWorkplace ////////////////////////////
 ///////////////////// BEGIN RKMDIWindowHistory ///////////////////////
 
+#include "../misc/rkstandardicons.h"
+#include <QListWidget>
+
+class RKMDIWindowHistoryWidget : public QListWidget {
+public:
+	RKMDIWindowHistoryWidget () : QListWidget (0) {
+		RK_TRACE (APP);
+
+		current = 0;
+		setFocusPolicy (Qt::StrongFocus);
+		setWindowFlags (Qt::Popup);
+	}
+
+	~RKMDIWindowHistoryWidget () {
+		RK_TRACE (APP);
+	}
+
+	void update (const QList<RKMDIWindow*> windows) {
+		RK_TRACE (APP);
+
+		clear ();
+		_windows = windows;
+		for (int i = windows.count () - 1; i >= 0; --i) {		// most recent top
+			RKMDIWindow *win = windows[i];
+			QListWidgetItem *item = new QListWidgetItem (this);
+			item->setIcon (RKStandardIcons::iconForWindow (win));
+			item->setText (win->windowTitle ());
+		}
+		if (current >= count ()) current = count () - 1;
+		if (current < 0) {
+			hide ();
+			return;
+		}
+		setCurrentRow (current);
+	}
+
+	void next () {
+		RK_TRACE (APP);
+
+		if (--current < 0) current = count () - 1;
+		setCurrentRow (current);
+	}
+
+	void prev () {
+		RK_TRACE (APP);
+
+		if (++current >= count ()) current = 0;
+		setCurrentRow (current);
+	}
+
+private:
+	void focusOutEvent (QFocusEvent *) {
+		RK_TRACE (APP);
+
+		deleteLater ();
+	}
+
+	void keyReleaseEvent (QKeyEvent *ev) {
+		RK_TRACE (APP);
+
+		if (ev->modifiers () == Qt::NoModifier) {
+			commit ();
+		}
+	}
+
+	void mouseReleaseEvent (QMouseEvent *ev) {
+		RK_TRACE (APP);
+
+		// HACK to get by without slots, and the associated moc'ing
+		QListWidget::mouseReleaseEvent (ev);
+		commit ();
+	}
+
+	void commit () {
+		RK_TRACE (APP);
+
+		current = currentRow ();
+		if ((current > 0) && (current < count ())) {
+			RKMDIWindow *win = _windows.value (count () - 1 - current);
+			RK_ASSERT (win);
+			win->activate (true);
+		}
+		deleteLater ();
+	}
+
+	int current;
+	QList<RKMDIWindow*> _windows;
+};
+
 RKMDIWindowHistory::RKMDIWindowHistory (QObject *parent) : QObject (parent) {
 	RK_TRACE (APP);
 
-	current = 0;
-	prev_action = next_action = 0;
+	switcher = 0;
 }
 
 RKMDIWindowHistory::~RKMDIWindowHistory () {
 	RK_TRACE (APP);
 
-	RK_DO (qDebug ("Remaining windows in history: forward: %d, backward: %d", forward_list.count (), back_list.count ()), APP, DL_DEBUG);
+	RK_DO (qDebug ("Remaining windows in history: %d", recent_windows.count ()), APP, DL_DEBUG);
 }
 
-void RKMDIWindowHistory::initActions (KActionCollection *ac, const char *prev_id, const char *next_id) {
-	RK_TRACE (APP);
-
-	prev_action = (KAction*) ac->addAction (prev_id, this, SLOT (prev()));
-	prev_action->setText (i18n ("Previous Window"));
-	prev_action->setIcon (QIcon (RKCommonFunctions::getRKWardDataDir () + "icons/window_back.png"));
-	prev_action->setShortcut (KShortcut (Qt::AltModifier + Qt::Key_Less, Qt::AltModifier + Qt::Key_Comma));
-
-	next_action = (KAction*) ac->addAction (next_id, this, SLOT (next()));
-	next_action->setText (i18n ("Next Window"));
-	next_action->setIcon (QIcon (RKCommonFunctions::getRKWardDataDir () + "icons/window_forward.png"));
-	next_action->setShortcut (KShortcut (Qt::AltModifier + Qt::Key_Greater, Qt::AltModifier + Qt::Key_Period));
-
-	updateActions ();
-}
-
 void RKMDIWindowHistory::windowActivated (RKMDIWindow *window) {
 	RK_TRACE (APP);
 
 	if (!window) return;
-	if (window == current) return;
-	if (window->isToolWindow ()) return;		// exclude tool windows for now. Make configurable?
+	if (!recent_windows.isEmpty () && (window == recent_windows.last ())) return;
 
 	// update lists
-	back_list.removeAll (window);		// remove dupes
-	forward_list.clear ();
-	if (current) back_list.append (current);
-	current = window;
+	recent_windows.removeAll (window);		// remove dupes
+	recent_windows.append (window);
 
-	updateActions ();
+	updateSwitcher ();
 }
 
-void RKMDIWindowHistory::next () {
+void RKMDIWindowHistory::next (KAction* prev_action, KAction *next_action) {
 	RK_TRACE (APP);
 
-	if (!haveNext ()) return;
-	if (current) back_list.append (current);
-	current = forward_list.first ();
-	forward_list.pop_front ();
+	if (recent_windows.isEmpty ()) return;
+	getSwitcher (prev_action, next_action)->next ();
+}
 
-	updateActions ();
+void RKMDIWindowHistory::prev (KAction* prev_action, KAction *next_action) {
+	RK_TRACE (APP);
 
-	RK_ASSERT (current);
-	current->activate ();
+	if (recent_windows.isEmpty ()) return;
+	getSwitcher (prev_action, next_action)->prev ();
 }
 
-void RKMDIWindowHistory::prev () {
+RKMDIWindow* RKMDIWindowHistory::previousDocumentWindow () {
 	RK_TRACE (APP);
 
-	if (!havePrev ()) return;
-	if (current) forward_list.push_front (current);
-	current = back_list.last ();
-	back_list.pop_back ();
-
-	updateActions ();
-
-	RK_ASSERT (current);
-	current->activate ();
+	for (int i = recent_windows.count () - 1; i >= 0; --i) {
+		if (!recent_windows[i]->isToolWindow ()) return (recent_windows[i]);
+	}
+	return 0;
 }
 
-bool RKMDIWindowHistory::haveNext () {
+void RKMDIWindowHistory::updateSwitcher () {
 	RK_TRACE (APP);
 
-	return (!forward_list.isEmpty ());
+	if (switcher) switcher->update (recent_windows);
 }
 
-bool RKMDIWindowHistory::havePrev () {
+void RKMDIWindowHistory::removeWindow (RKMDIWindow *window) {
 	RK_TRACE (APP);
 
-	return (!back_list.isEmpty ());
+	recent_windows.removeAll (window);
+	updateSwitcher ();
 }
 
-void RKMDIWindowHistory::updateActions () {
+RKMDIWindowHistoryWidget* RKMDIWindowHistory::getSwitcher (KAction* prev_action, KAction *next_action) {
 	RK_TRACE (APP);
 
-	if (next_action) {
-		next_action->setEnabled (haveNext ());
+	if (switcher) return switcher;
+
+	switcher = new RKMDIWindowHistoryWidget ();
+	connect (switcher, SIGNAL (destroyed(QObject*)), this, SLOT (switcherDestroyed()));
+	switcher->addAction (prev_action);
+	switcher->addAction (next_action);
+	switcher->update (recent_windows);
+	switcher->show ();
+	QWidget *act = QApplication::activeWindow ();
+	if (act) {
+		int center_x = act->x () + act->width () / 2;
+		int center_y = act->y () + act->height () / 2;
+		switcher->move (center_x - switcher->width () / 2, center_y - switcher->height () / 2);
+	} else {
+		RK_ASSERT (false);
 	}
+	switcher->setFocus ();
 
-	if (prev_action) {
-		prev_action->setEnabled (havePrev ());
-	}
+	return switcher;
 }
 
-void RKMDIWindowHistory::removeWindow (QObject *window) {
+void RKMDIWindowHistory::switcherDestroyed () {
 	RK_TRACE (APP);
 
-	back_list.removeAll (static_cast<RKMDIWindow *> (window));
-	forward_list.removeAll (static_cast<RKMDIWindow *> (window));
-	if (current == window) current = 0;
-	updateActions ();
+	RK_ASSERT (switcher);
+	switcher = 0;
 }
 
+void RKMDIWindowHistory::popLastWindow (RKMDIWindow* match) {
+	RK_TRACE (APP);
+
+	if (recent_windows.isEmpty ()) return;
+	else if (recent_windows.last () == match) recent_windows.removeLast ();
+	updateSwitcher ();
+}
+
 #include "rkworkplace.moc"

Modified: trunk/rkward/rkward/windows/rkworkplace.h
===================================================================
--- trunk/rkward/rkward/windows/rkworkplace.h	2011-04-25 09:23:54 UTC (rev 3525)
+++ trunk/rkward/rkward/windows/rkworkplace.h	2011-04-25 09:28:51 UTC (rev 3526)
@@ -35,6 +35,7 @@
 class KActionCollection;
 class KAction;
 class RKToolWindowBar;
+class RKMDIWindowHistoryWidget;
 
 #define TOOL_WINDOW_BAR_COUNT 4
 
@@ -45,22 +46,21 @@
 	RKMDIWindowHistory (QObject *parent);
 	~RKMDIWindowHistory ();
 
-	void initActions (KActionCollection *ac, const char *prev_id, const char *next_id);
-	bool haveNext ();
-	bool havePrev ();
-	void removeWindow (QObject *window);
+	void removeWindow (RKMDIWindow *window);
+/** pops the last window from the list, if it matches the given pointer */
+	void popLastWindow (RKMDIWindow *match);
+	RKMDIWindow *previousDocumentWindow ();
+	void next (KAction *prev_action, KAction *next_action);
+	void prev (KAction *prev_action, KAction *next_action);
 public slots:
-	void next ();
-	void prev ();
 	void windowActivated (RKMDIWindow *window);
+private slots:
+	void switcherDestroyed ();
 private:
-	void updateActions ();
-
-	RKMDIWindow *current;
-	QList<RKMDIWindow *> back_list;
-	QList<RKMDIWindow *> forward_list;
-	KAction *next_action;
-	KAction *prev_action;
+	void updateSwitcher ();
+	QList<RKMDIWindow *> recent_windows;
+	RKMDIWindowHistoryWidget *switcher;
+	RKMDIWindowHistoryWidget *getSwitcher (KAction *prev_action, KAction *next_action);
 };
 
 /** This class (only one instance will probably be around) keeps track of which windows are opened in the workplace, which are detached, etc. Also it is responsible for creating and manipulating those windows.
@@ -72,7 +72,7 @@
 @param parent: The parent widget for the workspace view (see view ()) */
 	explicit RKWorkplace (QWidget *parent);
 	~RKWorkplace ();
-	void initActions (KActionCollection *ac, const char *prev_id, const char *next_id, const char *left_id, const char *right_id);
+	void initActions (KActionCollection *ac, const char *left_id, const char *right_id);
 
 /** @returns a pointer to the view of the workplace. Since possibly the workplace layout might change, better not rely on this pointer being valid for long */
 	RKWorkplaceView *view () { return wview; };
@@ -153,6 +153,7 @@
 /** In the current design there is only ever one workplace. Use this static function to reference it.
 @returns a pointer to the workplace */
 	static RKWorkplace *mainWorkplace () { return main_workplace; };
+	static RKMDIWindowHistory *getHistory () { return main_workplace->history; };
 	void placeToolWindows ();
 signals:
 /** TODO: For future expansion. This signal is neither emitted nor used so far. It could be used to deactivate some options in the "Window" menu. Or maybe it can be removed? */


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list