Skip to content
Permalink
Browse files

Port selection actions to layout

  • Loading branch information
nyalldawson committed Oct 6, 2017
1 parent de96530 commit b494a71febed84598aea6a7aa63985d1c950c486
@@ -171,6 +171,29 @@ class QgsLayoutView: QGraphicsView

void emitZoomLevelChanged();


void selectAll();
%Docstring
Selects all items in the view.
.. seealso:: deselectAll()
.. seealso:: invertSelection()
%End

void deselectAll();
%Docstring
Deselects all items in the view.
.. seealso:: selectAll()
.. seealso:: invertSelection()
%End

void invertSelection();
%Docstring
Inverts the current selection, selecting deselected items
and deselecting and selected items.
.. seealso:: selectAll()
.. seealso:: deselectAll()
%End

void viewChanged();
%Docstring
Updates associated rulers and other widgets after view extent or zoom has changed.
@@ -191,6 +191,10 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
connect( mActionZoomActual, &QAction::triggered, mView, &QgsLayoutView::zoomActual );
connect( mActionZoomToWidth, &QAction::triggered, mView, &QgsLayoutView::zoomWidth );

connect( mActionSelectAll, &QAction::triggered, mView, &QgsLayoutView::selectAll );
connect( mActionDeselectAll, &QAction::triggered, mView, &QgsLayoutView::deselectAll );
connect( mActionInvertSelection, &QAction::triggered, mView, &QgsLayoutView::invertSelection );

connect( mActionAddPages, &QAction::triggered, this, &QgsLayoutDesignerDialog::addPages );

//create status bar labels
@@ -278,6 +278,81 @@ void QgsLayoutView::emitZoomLevelChanged()
emit zoomLevelChanged();
}

void QgsLayoutView::selectAll()
{
if ( !currentLayout() )
{
return;
}

//select all items in layout
QgsLayoutItem *focusedItem = nullptr;
const QList<QGraphicsItem *> itemList = currentLayout()->items();
for ( QGraphicsItem *graphicsItem : itemList )
{
QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem );
if ( item && !paperItem )
{
if ( !item->isLocked() )
{
item->setSelected( true );
if ( !focusedItem )
focusedItem = item;
}
else
{
//deselect all locked items
item->setSelected( false );
}
}
}
emit itemFocused( focusedItem );
}

void QgsLayoutView::deselectAll()
{
if ( !currentLayout() )
{
return;
}

currentLayout()->deselectAll();
}

void QgsLayoutView::invertSelection()
{
if ( !currentLayout() )
{
return;
}

QgsLayoutItem *focusedItem = nullptr;
//check all items in layout
const QList<QGraphicsItem *> itemList = currentLayout()->items();
for ( QGraphicsItem *graphicsItem : itemList )
{
QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem );
if ( item && !paperItem )
{
//flip selected state for items (and deselect any locked items)
if ( item->isSelected() || item->isLocked() )
{
item->setSelected( false );
}
else
{
item->setSelected( true );
if ( !focusedItem )
focusedItem = item;
}
}
}
if ( focusedItem )
emit itemFocused( focusedItem );
}

void QgsLayoutView::mousePressEvent( QMouseEvent *event )
{
mSnapMarker->setVisible( false );
@@ -210,6 +210,33 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
// methods also adds noise to the API.
void emitZoomLevelChanged();

// Why are these select methods in the view and not in the scene (QgsLayout)?
// Well, in my opinion selections are purely a GUI concept. Ideally
// NONE of the selection handling would be done in core, but we're restrained
// by the QGraphicsScene API here.

/**
* Selects all items in the view.
* \see deselectAll()
* \see invertSelection()
*/
void selectAll();

/**
* Deselects all items in the view.
* \see selectAll()
* \see invertSelection()
*/
void deselectAll();

/**
* Inverts the current selection, selecting deselected items
* and deselecting and selected items.
* \see selectAll()
* \see deselectAll()
*/
void invertSelection();

/**
* Updates associated rulers and other widgets after view extent or zoom has changed.
* This should be called after calling any of the QGraphicsView
@@ -144,6 +144,12 @@
</property>
<addaction name="mActionUndo"/>
<addaction name="mActionRedo"/>
<addaction name="separator"/>
<addaction name="mActionSelectAll"/>
<addaction name="mActionDeselectAll"/>
<addaction name="mActionInvertSelection"/>
<addaction name="mActionSelectNextBelow"/>
<addaction name="mActionSelectNextAbove"/>
</widget>
<addaction name="mLayoutMenu"/>
<addaction name="menuEdit"/>
@@ -466,6 +472,70 @@
<string>Ctrl+Alt+;</string>
</property>
</action>
<action name="mActionDeselectAll">
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/mActionDeselectAll.svg</normaloff>:/images/themes/default/mActionDeselectAll.svg</iconset>
</property>
<property name="text">
<string>D&amp;eselect All</string>
</property>
<property name="toolTip">
<string>Deselect all</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+A</string>
</property>
</action>
<action name="mActionSelectAll">
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSelectAll.svg</normaloff>:/images/themes/default/mActionSelectAll.svg</iconset>
</property>
<property name="text">
<string>&amp;Select All</string>
</property>
<property name="toolTip">
<string>Select all items</string>
</property>
<property name="shortcut">
<string>Ctrl+A</string>
</property>
</action>
<action name="mActionInvertSelection">
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/mActionInvertSelection.svg</normaloff>:/images/themes/default/mActionInvertSelection.svg</iconset>
</property>
<property name="text">
<string>&amp;Invert Selection</string>
</property>
<property name="toolTip">
<string>Invert selection</string>
</property>
</action>
<action name="mActionSelectNextBelow">
<property name="text">
<string>Select Next Item &amp;Below</string>
</property>
<property name="toolTip">
<string>Select next item below</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+[</string>
</property>
</action>
<action name="mActionSelectNextAbove">
<property name="text">
<string>Select Next Item &amp;Above</string>
</property>
<property name="toolTip">
<string>Select next item above</string>
</property>
<property name="shortcut">
<string>Ctrl+Alt+]</string>
</property>
</action>
</widget>
<resources>
<include location="../../../images/images.qrc"/>
@@ -14,10 +14,14 @@

import qgis # NOQA

from qgis.core import QgsProject, QgsLayout, QgsUnitTypes
from qgis.core import (QgsProject,
QgsLayout,
QgsUnitTypes,
QgsLayoutItemMap)
from qgis.gui import QgsLayoutView
from qgis.PyQt.QtCore import QRectF
from qgis.PyQt.QtGui import QTransform
from qgis.PyQt.QtTest import QSignalSpy

from qgis.testing import start_app, unittest

@@ -71,6 +75,110 @@ def testLayoutScalePixels(self):
view.setZoomLevel(0.5)
self.assertEqual(view.transform().m11(), 0.5)

def testSelectAll(self):
p = QgsProject()
l = QgsLayout(p)

# add some items
item1 = QgsLayoutItemMap(l)
l.addItem(item1)
item2 = QgsLayoutItemMap(l)
l.addItem(item2)
item3 = QgsLayoutItemMap(l)
item3.setLocked(True)
l.addItem(item3)

view = QgsLayoutView()
# no layout, no crash
view.selectAll()

view.setCurrentLayout(l)

focused_item_spy = QSignalSpy(view.itemFocused)

view.selectAll()
self.assertTrue(item1.isSelected())
self.assertTrue(item2.isSelected())
self.assertFalse(item3.isSelected()) # locked

self.assertEqual(len(focused_item_spy), 1)

item3.setSelected(True) # locked item selection should be cleared
view.selectAll()
self.assertTrue(item1.isSelected())
self.assertTrue(item2.isSelected())
self.assertFalse(item3.isSelected()) # locked

def testDeselectAll(self):
p = QgsProject()
l = QgsLayout(p)

# add some items
item1 = QgsLayoutItemMap(l)
l.addItem(item1)
item2 = QgsLayoutItemMap(l)
l.addItem(item2)
item3 = QgsLayoutItemMap(l)
item3.setLocked(True)
l.addItem(item3)

view = QgsLayoutView()
# no layout, no crash
view.deselectAll()

view.setCurrentLayout(l)

focused_item_spy = QSignalSpy(view.itemFocused)

view.deselectAll()
self.assertFalse(item1.isSelected())
self.assertFalse(item2.isSelected())
self.assertFalse(item3.isSelected())

self.assertEqual(len(focused_item_spy), 1)

item1.setSelected(True)
item2.setSelected(True)
item3.setSelected(True)
view.deselectAll()
self.assertFalse(item1.isSelected())
self.assertFalse(item2.isSelected())
self.assertFalse(item3.isSelected())

def testInvertSelection(self):
p = QgsProject()
l = QgsLayout(p)

# add some items
item1 = QgsLayoutItemMap(l)
l.addItem(item1)
item2 = QgsLayoutItemMap(l)
l.addItem(item2)
item3 = QgsLayoutItemMap(l)
item3.setLocked(True)
l.addItem(item3)

view = QgsLayoutView()
# no layout, no crash
view.invertSelection()

view.setCurrentLayout(l)

focused_item_spy = QSignalSpy(view.itemFocused)

view.invertSelection()
self.assertTrue(item1.isSelected())
self.assertTrue(item2.isSelected())
self.assertFalse(item3.isSelected()) # locked

self.assertEqual(len(focused_item_spy), 1)

item3.setSelected(True) # locked item selection should be cleared
view.invertSelection()
self.assertFalse(item1.isSelected())
self.assertFalse(item2.isSelected())
self.assertFalse(item3.isSelected()) # locked


if __name__ == '__main__':
unittest.main()

0 comments on commit b494a71

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