Skip to content

Commit

Permalink
Port selection handling code from composer
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Oct 6, 2017
1 parent 51efa19 commit bb12951
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 0 deletions.
19 changes: 19 additions & 0 deletions python/core/layout/qgslayout.sip
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb
:rtype: list of QgsLayoutItem
%End

void setSelectedItem( QgsLayoutItem *item );
%Docstring
Clears any selected items and sets ``item`` as the current selection.
%End

void deselectAll();
%Docstring
Clears any selected items in the layout.

Call this method rather than QGraphicsScene.clearSelection, as the latter does
not correctly emit signals to allow the layout's model to update.
%End

QgsLayoutItem *itemByUuid( const QString &uuid );
%Docstring
Returns the layout item with matching ``uuid`` unique identifier, or a None
Expand Down Expand Up @@ -302,6 +315,12 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb
Emitted whenever the expression variables stored in the layout have been changed.
%End

void selectedItemChanged( QgsLayoutItem *selected );
%Docstring
Emitted whenever the selected item changes.
If None, no item is selected.
%End

};


Expand Down
27 changes: 27 additions & 0 deletions src/core/layout/qgslayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,33 @@ QList<QgsLayoutItem *> QgsLayout::selectedLayoutItems( const bool includeLockedI
return layoutItemList;
}

void QgsLayout::setSelectedItem( QgsLayoutItem *item )
{
whileBlocking( this )->deselectAll();
if ( item )
{
item->setSelected( true );
}
emit selectedItemChanged( item );
}

void QgsLayout::deselectAll()
{
//we can't use QGraphicsScene::clearSelection, as that emits no signals
//and we don't know which items are being deselected
//accordingly, we can't inform the layout model of selection changes
//instead, do the clear selection manually...
const QList<QGraphicsItem *> selectedItemList = selectedItems();
for ( QGraphicsItem *item : selectedItemList )
{
if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
{
layoutItem->setSelected( false );
}
}
emit selectedItemChanged( nullptr );
}

QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid )
{
QList<QgsLayoutItem *> itemList;
Expand Down
19 changes: 19 additions & 0 deletions src/core/layout/qgslayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,19 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
*/
QList<QgsLayoutItem *> selectedLayoutItems( const bool includeLockedItems = true );

/**
* Clears any selected items and sets \a item as the current selection.
*/
void setSelectedItem( QgsLayoutItem *item );

/**
* Clears any selected items in the layout.
*
* Call this method rather than QGraphicsScene::clearSelection, as the latter does
* not correctly emit signals to allow the layout's model to update.
*/
void deselectAll();

/**
* Returns the layout item with matching \a uuid unique identifier, or a nullptr
* if a matching item could not be found.
Expand Down Expand Up @@ -358,6 +371,12 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
*/
void variablesChanged();

/**
* Emitted whenever the selected item changes.
* If nullptr, no item is selected.
*/
void selectedItemChanged( QgsLayoutItem *selected );

private:

QgsProject *mProject = nullptr;
Expand Down
38 changes: 38 additions & 0 deletions tests/src/python/test_qgslayout.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,44 @@ def testSelectedItems(self):
self.assertEqual(set(l.selectedLayoutItems(False)), set([item1, item2]))
self.assertEqual(set(l.selectedLayoutItems(True)), set([item1, item2, item3]))

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

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

select_changed_spy = QSignalSpy(l.selectedItemChanged)
l.setSelectedItem(None)
self.assertFalse(l.selectedLayoutItems())
self.assertEqual(len(select_changed_spy), 1)
self.assertEqual(select_changed_spy[-1][0], None)

l.setSelectedItem(item1)
self.assertEqual(l.selectedLayoutItems(), [item1])
self.assertEqual(len(select_changed_spy), 2)
self.assertEqual(select_changed_spy[-1][0], item1)

l.setSelectedItem(None)
self.assertFalse(l.selectedLayoutItems())
self.assertEqual(len(select_changed_spy), 3)
self.assertEqual(select_changed_spy[-1][0], None)

l.setSelectedItem(item2)
self.assertEqual(l.selectedLayoutItems(), [item2])
self.assertEqual(len(select_changed_spy), 4)
self.assertEqual(select_changed_spy[-1][0], item2)

l.deselectAll()
self.assertFalse(l.selectedLayoutItems())
self.assertEqual(len(select_changed_spy), 5)
self.assertEqual(select_changed_spy[-1][0], None)


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

0 comments on commit bb12951

Please sign in to comment.