When taking main widget from QgsPanelWidgetStack, auto accept

all open child panel widgets

Avoids the stack state becoming inconsistent because child
panel widgets from a different main panel are still present

And add unit tests for QgsPanelWidgetStack
This commit is contained in:
Nyall Dawson 2016-10-06 08:09:54 +10:00
parent fbdc414957
commit 37e3dd76c4
5 changed files with 225 additions and 3 deletions

View File

@ -53,15 +53,29 @@ class QgsPanelWidgetStack: public QWidget
*/
void clear();
/**
* Returns the panel currently shown in the stack.
* @note added in QGIS 3.0
*/
QgsPanelWidget* currentPanel();
public slots:
/**
* Accept the current active widget in the stack.
*
* Calls the panelAccepeted signal on the active widget.
* @see acceptAllPanels()
*/
void acceptCurrentPanel();
/**
* Accepts all panel widgets open in the stack in turn until until only the mainPanel()
* remains.
* @see acceptCurrentPanel();
* @note added in QGIS 3.0
*/
void acceptAllPanels();
/**
* Show a panel in the stack widget. Will connect to the panels showPanel event to handle
* nested panels. Auto switches the the given panel for the user.

View File

@ -50,6 +50,9 @@ QgsPanelWidget *QgsPanelWidgetStack::mainPanel()
QgsPanelWidget *QgsPanelWidgetStack::takeMainPanel()
{
// clear out the current stack
acceptAllPanels();
QWidget* widget = mStackedWidget->widget( 0 );
mStackedWidget->removeWidget( widget );
return qobject_cast<QgsPanelWidget*>( widget );
@ -57,7 +60,7 @@ QgsPanelWidget *QgsPanelWidgetStack::takeMainPanel()
void QgsPanelWidgetStack::clear()
{
for ( int i = mStackedWidget->count(); i >= 0; i-- )
for ( int i = mStackedWidget->count() - 1; i >= 0; i-- )
{
if ( QgsPanelWidget* panelWidget = qobject_cast<QgsPanelWidget*>( mStackedWidget->widget( i ) ) )
{
@ -79,16 +82,38 @@ void QgsPanelWidgetStack::clear()
this->updateBreadcrumb();
}
QgsPanelWidget* QgsPanelWidgetStack::currentPanel()
{
return qobject_cast<QgsPanelWidget*>( mStackedWidget->currentWidget() );
}
void QgsPanelWidgetStack::acceptCurrentPanel()
{
// You can't accept the main panel.
if ( mStackedWidget->currentIndex() == 0 )
if ( mStackedWidget->currentIndex() <= 0 )
return;
QgsPanelWidget* widget = qobject_cast<QgsPanelWidget*>( mStackedWidget->currentWidget() );
QgsPanelWidget* widget = currentPanel();
widget->acceptPanel();
}
void QgsPanelWidgetStack::acceptAllPanels()
{
//avoid messy multiple redraws
setUpdatesEnabled( false );
mStackedWidget->setUpdatesEnabled( false );
for ( int i = mStackedWidget->count() - 1; i > 0; --i )
{
if ( QgsPanelWidget* panelWidget = qobject_cast<QgsPanelWidget*>( mStackedWidget->widget( i ) ) )
{
panelWidget->acceptPanel();
}
}
setUpdatesEnabled( true );
mStackedWidget->setUpdatesEnabled( true );
}
void QgsPanelWidgetStack::showPanel( QgsPanelWidget *panel )
{
mTitles.push( panel->panelTitle() );

View File

@ -66,6 +66,8 @@ class GUI_EXPORT QgsPanelWidgetStack : public QWidget, private Ui::QgsRendererWi
* Removes the main panel widget from the stack and transfers ownsership to the
* caller.
* @return The main widget that is set in the stack.
* @note Calling this will clear out any current stacked panels by accepting
* each panel in turn.
* @see mainPanel()
* @see setMainPanel()
*/
@ -77,14 +79,29 @@ class GUI_EXPORT QgsPanelWidgetStack : public QWidget, private Ui::QgsRendererWi
*/
void clear();
/**
* Returns the panel currently shown in the stack.
* @note added in QGIS 3.0
*/
QgsPanelWidget* currentPanel();
public slots:
/**
* Accept the current active widget in the stack.
*
* Calls the panelAccepeted signal on the active widget.
* @see acceptAllPanels()
*/
void acceptCurrentPanel();
/**
* Accepts all panel widgets open in the stack in turn until until only the mainPanel()
* remains.
* @see acceptCurrentPanel();
* @note added in QGIS 3.0
*/
void acceptAllPanels();
/**
* Show a panel in the stack widget. Will connect to the panels showPanel event to handle
* nested panels. Auto switches the the given panel for the user.

View File

@ -69,6 +69,7 @@ ADD_PYTHON_TEST(PyQgsPalLabelingCanvas test_qgspallabeling_canvas.py)
ADD_PYTHON_TEST(PyQgsPalLabelingComposer test_qgspallabeling_composer.py)
ADD_PYTHON_TEST(PyQgsPalLabelingPlacement test_qgspallabeling_placement.py)
ADD_PYTHON_TEST(PyQgsPanelWidget test_qgspanelwidget.py)
ADD_PYTHON_TEST(PyQgsPanelWidgetStack test_qgspanelwidgetstack.py)
ADD_PYTHON_TEST(PyQgsPoint test_qgspoint.py)
ADD_PYTHON_TEST(PyQgsPointClusterRenderer test_qgspointclusterrenderer.py)
ADD_PYTHON_TEST(PyQgsPointDisplacementRenderer test_qgspointdisplacementrenderer.py)

View File

@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsPanelWidgetStack.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '05/10/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.PyQt.QtWidgets import QWidget
from qgis.gui import QgsPanelWidget, QgsPanelWidgetStack
from qgis.testing import start_app, unittest
from qgis.PyQt.QtTest import QSignalSpy
start_app()
class TestQgsPanelWidgetStack(unittest.TestCase):
def testMainPanel(self):
""" test mainPanel methods """
s = QgsPanelWidgetStack()
# no main panel
self.assertFalse(s.mainPanel())
self.assertFalse(s.takeMainPanel())
# set main panel
p1 = QgsPanelWidget()
s.setMainPanel(p1)
self.assertEqual(s.mainPanel(), p1)
# takeMainPanel()
self.assertEqual(s.takeMainPanel(), p1)
self.assertFalse(s.mainPanel())
self.assertFalse(s.takeMainPanel())
def testAddingPanels(self):
""" test adding panels to stack """
s = QgsPanelWidgetStack()
mp = QgsPanelWidget()
s.setMainPanel(mp)
p1 = QgsPanelWidget()
s.showPanel(p1)
self.assertEqual(s.currentPanel(), p1)
p2 = QgsPanelWidget()
s.showPanel(p2)
self.assertEqual(s.currentPanel(), p2)
def testAcceptCurrentPanel(self):
""" test accepting current panel """
s = QgsPanelWidgetStack()
# call on empty stack
s.acceptCurrentPanel()
mp = QgsPanelWidget()
s.setMainPanel(mp)
# call on main panel - should be no effect
s.acceptCurrentPanel()
self.assertEqual(s.mainPanel(), mp)
self.assertEqual(s.currentPanel(), mp)
# add panels
p1 = QgsPanelWidget()
s.showPanel(p1)
p2 = QgsPanelWidget()
s.showPanel(p2)
# accept them
self.assertEqual(s.currentPanel(), p2)
p2_accept_spy = QSignalSpy(p2.panelAccepted)
s.acceptCurrentPanel()
self.assertEqual(s.currentPanel(), p1)
self.assertEqual(len(p2_accept_spy), 1)
p1_accept_spy = QSignalSpy(p1.panelAccepted)
s.acceptCurrentPanel()
self.assertEqual(s.currentPanel(), mp)
self.assertEqual(len(p1_accept_spy), 1)
def testAcceptAllPanel(self):
""" test accepting all panels """
s = QgsPanelWidgetStack()
# call on empty stack
s.acceptAllPanels()
mp = QgsPanelWidget()
s.setMainPanel(mp)
# call on main panel - should be no effect
s.acceptAllPanels()
self.assertEqual(s.mainPanel(), mp)
self.assertEqual(s.currentPanel(), mp)
# add panels
p1 = QgsPanelWidget()
s.showPanel(p1)
p1_accept_spy = QSignalSpy(p1.panelAccepted)
p2 = QgsPanelWidget()
s.showPanel(p2)
p2_accept_spy = QSignalSpy(p2.panelAccepted)
p3 = QgsPanelWidget()
s.showPanel(p3)
p3_accept_spy = QSignalSpy(p3.panelAccepted)
# accept all
s.acceptAllPanels()
self.assertEqual(s.currentPanel(), mp)
self.assertEqual(len(p1_accept_spy), 1)
self.assertEqual(len(p2_accept_spy), 1)
self.assertEqual(len(p3_accept_spy), 1)
def testClear(self):
""" test clearing stack """
s = QgsPanelWidgetStack()
# call on empty stack
s.clear()
# add panels
mp = QgsPanelWidget()
s.setMainPanel(mp)
p1 = QgsPanelWidget()
s.showPanel(p1)
p2 = QgsPanelWidget()
s.showPanel(p2)
p3 = QgsPanelWidget()
s.showPanel(p3)
# clear
s.clear()
self.assertFalse(s.currentPanel())
self.assertFalse(s.mainPanel())
def testTakeMainAcceptsAll(self):
""" test that taking the main panel accepts all open child panels"""
s = QgsPanelWidgetStack()
mp = QgsPanelWidget()
s.setMainPanel(mp)
p1 = QgsPanelWidget()
s.showPanel(p1)
p1_accept_spy = QSignalSpy(p1.panelAccepted)
p2 = QgsPanelWidget()
s.showPanel(p2)
p2_accept_spy = QSignalSpy(p2.panelAccepted)
p3 = QgsPanelWidget()
s.showPanel(p3)
p3_accept_spy = QSignalSpy(p3.panelAccepted)
# take main
s.takeMainPanel()
self.assertEqual(len(p1_accept_spy), 1)
self.assertEqual(len(p2_accept_spy), 1)
self.assertEqual(len(p3_accept_spy), 1)
if __name__ == '__main__':
unittest.main()