[rkward/work/split_views] rkward: Implement the actual splitting of the view area, and add corresponding actions.

Thomas Friedrichsmeier null at kde.org
Mon Jun 19 15:32:50 UTC 2017


Git commit c13032356a183607069281093b4d9ef2abdd2376 by Thomas Friedrichsmeier.
Committed on 19/06/2017 at 15:28.
Pushed by tfry into branch 'work/split_views'.

Implement the actual splitting of the view area, and add corresponding actions.

This is enough to start playing with, but not a useful implementation, yet, as so
far the document window is _moved_ to the new pane, instead of duplicated. Also,
opening several views for the same document is still not possible.

M  +4    -1    rkward/rkwardui.rc
M  +112  -32   rkward/windows/rkworkplaceview.cpp
M  +9    -2    rkward/windows/rkworkplaceview.h

https://commits.kde.org/rkward/c13032356a183607069281093b4d9ef2abdd2376

diff --git a/rkward/rkwardui.rc b/rkward/rkwardui.rc
index 6df03aa9..3be48bcd 100644
--- a/rkward/rkwardui.rc
+++ b/rkward/rkwardui.rc
@@ -1,5 +1,5 @@
 <!DOCTYPE kpartgui>
-<kpartgui name="rkward_main" version="640">
+<kpartgui name="rkward_main" version="700">
 <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.
@@ -67,6 +67,9 @@
 		<Action name="window_close_all"/>
 		<Action name="close_all_editors"/>
 		<Separator/>
+		<Action name="view_split_vert"/>
+		<Action name="view_split_horiz"/>
+		<Separator/>
 		<Menu name="window_activate"><text>&Activate</text>
 			<Action name="left_window"/>
 			<Action name="right_window"/>
diff --git a/rkward/windows/rkworkplaceview.cpp b/rkward/windows/rkworkplaceview.cpp
index 7d86d27c..98e38bcd 100644
--- a/rkward/windows/rkworkplaceview.cpp
+++ b/rkward/windows/rkworkplaceview.cpp
@@ -37,7 +37,7 @@
 
 #include "../debug.h"
 
-RKWorkplaceViewPane::RKWorkplaceViewPane (RKWorkplaceView* parent) : QTabWidget (parent) {
+RKWorkplaceViewPane::RKWorkplaceViewPane (RKWorkplaceView* parent) : QTabWidget () {
 	RK_TRACE (APP);
 
 	workplace_view = parent;
@@ -58,6 +58,7 @@ RKWorkplaceViewPane::RKWorkplaceViewPane (RKWorkplaceView* parent) : QTabWidget
 	connect (tabBar (), &QWidget::customContextMenuRequested, this, &RKWorkplaceViewPane::showContextMenu);
 
 	KAcceleratorManager::setNoAccel (tabBar ());	// TODO: This is a WORKAROUND for a bug in kdelibs where tabs named "a0.txt", "a1.txt", etc. will steal the Alt+0/1... shortcuts
+	tabBar ()->hide ();  // initially
 	connect (this, &QTabWidget::currentChanged, workplace_view, &RKWorkplaceView::currentPageChanged);
 }
 
@@ -112,7 +113,16 @@ void RKWorkplaceViewPane::closePage (QWidget* page) {
 void RKWorkplaceViewPane::tabRemoved (int index) {
 	RK_TRACE (APP);
 	QTabWidget::tabRemoved (index);
+	if (count () < 2) tabBar ()->hide ();
 	if (count () < 1) emit (becameEmpty (this));
+	workplace_view->updateActions ();
+}
+
+void RKWorkplaceViewPane::tabInserted (int index) {
+	RK_TRACE (APP);
+	QTabWidget::tabInserted (index);
+	if (count () > 1) tabBar ()->show ();
+	workplace_view->updateActions ();
 }
 
 void RKWorkplaceViewPane::contextMenuClosePage () {
@@ -145,9 +155,20 @@ void RKWorkplaceViewPane::contextMenuDetachWindow () {
 
 
 
+RKWorkplaceViewPane* RKWorkplaceView::createPane () {
+	RK_TRACE (APP);
+	RKWorkplaceViewPane *pane = new RKWorkplaceViewPane (this);
+	QObject::connect (pane, &RKWorkplaceViewPane::becameEmpty, this, &RKWorkplaceView::purgePane);
+	return pane;
+}
+
 RKWorkplaceView::RKWorkplaceView (QWidget *parent) : QSplitter (parent) {
 	RK_TRACE (APP);
-	newPane (0);
+
+	RKWorkplaceViewPane *pane = createPane ();
+	addWidget (pane);
+	panes.append (pane);
+	setChildrenCollapsible (false);
 }
 
 RKWorkplaceView::~RKWorkplaceView () {
@@ -160,8 +181,14 @@ RKWorkplaceViewPane* RKWorkplaceView::activePane () const {
 	for (int i = 0; i < panes.size (); ++i) {
 		if (panes[i]->isActive ()) return panes[i];
 	}
-	if (!panes.isEmpty ()) return panes.first ();
-	return 0;
+
+	// Esp. when switching between console and script window, consider the previous window active
+	RKWorkplaceViewPane *pane = findWindow (RKWorkplace::mainWorkplace ()->getHistory ()->previousDocumentWindow ());
+	if (pane) return pane;
+
+	// As a last resort, return top-left pane
+	RK_ASSERT (!panes.isEmpty ());
+	return panes.first ();
 }
 
 void RKWorkplaceView::initActions (KActionCollection *ac) {
@@ -175,13 +202,28 @@ void RKWorkplaceView::initActions (KActionCollection *ac) {
 	action_page_right->setText (i18n ("Window Right"));
 	ac->setDefaultShortcuts (action_page_right, QList<QKeySequence>() << Qt::ControlModifier + Qt::Key_Greater << Qt::ControlModifier + Qt::Key_Period);
 
+	// NOTE: Icons, shortcuts, action names for split view actions as in kate
+	QAction *action = ac->addAction (QStringLiteral ("view_split_vert"));
+	action->setIcon (QIcon::fromTheme(QStringLiteral ("view-split-left-right")));
+	action->setText (i18n("Split Ve&rtical"));
+	ac->setDefaultShortcut (action, Qt::CTRL + Qt::SHIFT + Qt::Key_L);
+	connect (action, &QAction::triggered, this, &RKWorkplaceView::splitViewVert);
+	action->setWhatsThis (i18n ("Split the currently active view into two views, vertically."));
+
+	action = ac->addAction (QStringLiteral ("view_split_horiz"));
+	action->setIcon (QIcon::fromTheme(QStringLiteral ("view-split-top-bottom")));
+	action->setText (i18n ("Split &Horizontal"));
+	ac->setDefaultShortcut (action, Qt::CTRL + Qt::SHIFT + Qt::Key_T);
+	connect (action, &QAction::triggered, this, &RKWorkplaceView::splitViewHoriz);
+	action->setWhatsThis (i18n ("Split the currently active view into two views, horizontally."));
+
 	updateActions ();
 }
 
 void RKWorkplaceView::updateActions () {
 	RK_TRACE (APP);
 
-	bool several_pages = panes.count () > 1 || (panes.count () > 0 && panes.first()->count () > 1);
+	bool several_pages = panes.count () > 1 || (panes.count () > 0 && panes.first ()->count () > 1);
 	action_page_left->setEnabled (several_pages);
 	action_page_right->setEnabled (several_pages);
 }
@@ -190,11 +232,6 @@ void RKWorkplaceView::pageLeft () {
 	RK_TRACE (APP);
 
 	RKWorkplaceViewPane *current = activePane ();
-	if (!current) {
-		RK_ASSERT (current);  // can this happen? It should not, as long as the action does not get called on an empty workplace view
-		return;
-	}
-
 	int index = current->currentIndex ();
 	if (index > 0) {
 		current->setCurrentIndex (index - 1);
@@ -203,7 +240,7 @@ void RKWorkplaceView::pageLeft () {
 		if (pindex > 0) --pindex;
 		else pindex = panes.size () - 1;
 		if (panes[pindex]->count () < 1) {
-			RK_ASSERT (false); // it should have been purged.
+			RK_ASSERT (false); // action should have been disabled on an empty workplaceview
 			return;
 		}
 		panes[pindex]->setCurrentIndex (panes[pindex]->count () - 1);
@@ -214,11 +251,6 @@ void RKWorkplaceView::pageRight () {
 	RK_TRACE (APP);
 
 	RKWorkplaceViewPane *current = activePane ();
-	if (!current) {
-		RK_ASSERT (current);  // can this happen? It should not, as long as the action does not get called on an empty workplace view
-		return;
-	}
-
 	int index = current->currentIndex ();
 	if (index < current->count () - 1) {
 		current->setCurrentIndex (index + 1);
@@ -227,22 +259,74 @@ void RKWorkplaceView::pageRight () {
 		if (pindex < panes.count () - 1) ++pindex;
 		else pindex = 0;
 		if (panes[pindex]->count () < 1) {
-			RK_ASSERT (false); // it should have been purged.
+			RK_ASSERT (false); // action should have been disabled on an empty workplaceview
 			return;
 		}
 		panes[pindex]->setCurrentIndex (0);
 	}
 }
 
-RKWorkplaceViewPane* RKWorkplaceView::newPane (int index) {
+void RKWorkplaceView::splitViewHoriz () {
 	RK_TRACE (APP);
+	splitView (Qt::Vertical, activePane ());
+}
 
-	if (index < 0) index = count ();
-	RKWorkplaceViewPane *pane = new RKWorkplaceViewPane (this);
-	addWidget (pane);
-	connect (pane, &RKWorkplaceViewPane::becameEmpty, this, &RKWorkplaceView::purgePane);
-	panes.append (pane);
-	return pane;
+void RKWorkplaceView::splitViewVert () {
+	RK_TRACE (APP);
+	splitView (Qt::Horizontal, activePane ());
+}
+
+// NOTE: Some of this function taken from kate's kateviewmanager.cpp
+void RKWorkplaceView::splitView (Qt::Orientation orientation, RKWorkplaceViewPane *pane) {
+	RK_TRACE (APP);
+
+	RKMDIWindow *active = activePage ();
+	RK_ASSERT (pane);
+	QSplitter *splitter = qobject_cast<QSplitter *> (pane->parentWidget ());
+    if (!splitter) {
+		RK_ASSERT (splitter);
+		return;
+	}
+
+	setUpdatesEnabled (false);
+	QList<int> sizes = splitter->sizes ();
+
+	// index where to insert new splitter/viewspace
+	const int index = splitter->indexOf (pane);
+	const int lindex = panes.indexOf (pane);
+
+	RKWorkplaceViewPane *newpane = createPane ();
+	panes.insert (lindex + 1, newpane);
+
+	// If there is only one child (left) in the current splitter, we can just set the orientation as needed.
+	if (splitter->count () == 1) {
+		splitter->setOrientation (orientation);
+	}
+	if (splitter->orientation () == orientation) {  // not the same as above: Also, if an existing larger splitter is suitably oriented, arleady
+		// First calculate the size of the new and the old elements.
+		// This is not pixel perfect, but reasonably close.
+		for (int i = sizes.count () - 1; i >= 0; --i) {
+			sizes[i] = sizes[i] * sizes.count () / (sizes.count () + 1);
+		}
+		sizes.insert (index + 1, (orientation == Qt::Horizontal ? splitter->width () : splitter->height ()) / (splitter->count () + 1) - splitter->handleWidth ());
+
+		splitter->insertWidget (index + 1, newpane);
+	} else {
+		QSplitter *newsplitter = new QSplitter (orientation);
+		newsplitter->setChildrenCollapsible (false);
+		newsplitter->addWidget (pane);
+		newsplitter->addWidget (newpane);
+		splitter->insertWidget (index, newsplitter);
+		QList<int> subsizes = newsplitter->sizes ();
+		subsizes[0] = subsizes[1] = (subsizes[0] + subsizes[1]) / 2;
+		newsplitter->setSizes (subsizes);
+	}
+	newpane->show ();
+	newpane->addTab (active, "Test");
+	newpane->currentWidget ()->setFocus ();
+
+	splitter->setSizes (sizes);
+	setUpdatesEnabled (true);
 }
 
 void RKWorkplaceView::addWindow (RKMDIWindow *widget) {
@@ -255,10 +339,7 @@ void RKWorkplaceView::addWindow (RKMDIWindow *widget) {
 	if (icon.isNull ()) RK_ASSERT (false);
 
 	RKWorkplaceViewPane *pane = activePane ();
-	if (!pane) {
-		RK_ASSERT (count () == 0);
-		pane = newPane (0);
-	}
+	RK_ASSERT (pane);
 	id = pane->addTab (widget, icon, widget->shortCaption ());
 
 	connect (widget, &RKMDIWindow::captionChanged, this, &RKWorkplaceView::childCaptionChanged);
@@ -300,7 +381,7 @@ void RKWorkplaceView::purgePane (RKWorkplaceViewPane* pane) {
 	RK_TRACE (APP);
 	RK_ASSERT (pane);
 	if (pane->count () > 0) return;
-	if (count () == 1 && pane->parentWidget () == this) return;  // keep at least one pane around for layout purposes
+	if (panes.count () < 2) return;  // keep at least one pane around for layout purposes
 
 	QSplitter* split = static_cast<QSplitter*> (pane->parentWidget ());
 	pane->hide ();
@@ -319,8 +400,8 @@ RKMDIWindow *RKWorkplaceView::activePage () const {
 	RK_TRACE (APP);
 
 	RKWorkplaceViewPane *pane = activePane ();
-	if (pane) return (dynamic_cast<RKMDIWindow *> (pane->currentWidget ()));
-	return 0;
+	RK_ASSERT (pane);
+	return (dynamic_cast<RKMDIWindow *> (pane->currentWidget ()));
 }
 
 void RKWorkplaceView::childCaptionChanged (RKMDIWindow *widget) {
@@ -354,7 +435,6 @@ void RKWorkplaceView::currentPageChanged (int) {
 	} else {
 		setCaption (QString ());
 	}
-	updateActions ();
 }
 
 
diff --git a/rkward/windows/rkworkplaceview.h b/rkward/windows/rkworkplaceview.h
index 39b088bc..0a204ee3 100644
--- a/rkward/windows/rkworkplaceview.h
+++ b/rkward/windows/rkworkplaceview.h
@@ -2,7 +2,7 @@
                           rkworkplaceview  -  description
                              -------------------
     begin                : Tue Sep 26 2006
-    copyright            : (C) 2006 - 017 by Thomas Friedrichsmeier
+    copyright            : (C) 2006 - 2017 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -42,6 +42,7 @@ private:
 	bool isActive ();
 protected:
 	void tabRemoved (int index) override;
+	void tabInserted (int index) override;
 signals:
 	void becameEmpty (RKWorkplaceViewPane* pane);
 private slots:
@@ -99,10 +100,16 @@ private slots:
 	void pageRight ();
 /** Purge the given pane (if it is empty) */
 	void purgePane (RKWorkplaceViewPane *pane);
+/** Split current view vertically */
+	void splitViewVert ();
+/** Split current view horizontally */
+	void splitViewHoriz ();
 private:
 	void updateActions ();
+	void splitView (Qt::Orientation horiz, RKWorkplaceViewPane *pane);
+	RKWorkplaceViewPane *createPane ();
 	RKWorkplaceViewPane *findWindow (RKMDIWindow *window) const;
-	RKWorkplaceViewPane *newPane (int index);
+	RKWorkplaceViewPane *addNewPane (int index);
 
 	QAction *action_page_left;
 	QAction *action_page_right;



More information about the rkward-tracker mailing list