Skip to content
Permalink
Browse files

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
  • Loading branch information
nyalldawson committed Oct 6, 2016
1 parent fbdc414 commit 37e3dd76c44b0a8f9247541ad87ad6d8987dde42
@@ -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.
@@ -50,14 +50,17 @@ 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 );
}

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() );
@@ -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.
@@ -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)
@@ -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()

0 comments on commit 37e3dd7

Please sign in to comment.
You can’t perform that action at this time.