diff --git a/python/core/layout/qgslayout.sip b/python/core/layout/qgslayout.sip index 9f22a125838..1161bdff91b 100644 --- a/python/core/layout/qgslayout.sip +++ b/python/core/layout/qgslayout.sip @@ -98,19 +98,6 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb not correctly emit signals to allow the layout's model to update. %End - void lockSelectedItems(); -%Docstring - Locks any selected items, preventing them from being interacted with - by mouse interactions. -.. seealso:: unlockAllItems() -%End - - void unlockAllItems(); -%Docstring - Unlocks all locked items in the layout. -.. seealso:: lockSelectedItems() -%End - bool raiseItem( QgsLayoutItem *item, bool deferUpdate = false ); %Docstring Raises an ``item`` up the z-order. @@ -122,6 +109,7 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb updating the scene for each one. .. seealso:: lowerItem() +.. seealso:: updateZValues() :rtype: bool %End @@ -136,6 +124,7 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb updating the scene for each one. .. seealso:: raiseItem() +.. seealso:: updateZValues() :rtype: bool %End @@ -150,6 +139,7 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb updating the scene for each one. .. seealso:: moveItemToBottom() +.. seealso:: updateZValues() :rtype: bool %End @@ -163,39 +153,15 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb updating the scene for each one. .. seealso:: moveItemToTop() +.. seealso:: updateZValues() :rtype: bool %End - void raiseSelectedItems(); + void updateZValues( const bool addUndoCommands = true ); %Docstring - Raises the selected items up the z-order. -.. seealso:: lowerSelectedItems() -.. seealso:: moveSelectedItemsToTop() -.. seealso:: moveSelectedItemsToBottom() -%End - - void lowerSelectedItems(); -%Docstring - Lowers the selected items down the z-order. -.. seealso:: raiseSelectedItems() -.. seealso:: moveSelectedItemsToTop() -.. seealso:: moveSelectedItemsToBottom() -%End - - void moveSelectedItemsToTop(); -%Docstring - Raises the selected items to the top of the z-order. -.. seealso:: raiseSelectedItems() -.. seealso:: lowerSelectedItems() -.. seealso:: moveSelectedItemsToBottom() -%End - - void moveSelectedItemsToBottom(); -%Docstring - Lowers the selected items to the bottom of the z-order. -.. seealso:: raiseSelectedItems() -.. seealso:: lowerSelectedItems() -.. seealso:: moveSelectedItemsToTop() + Resets the z-values of items based on their position in the internal + z order list. This should be called after any stacking changes + which deferred z-order updates. %End QgsLayoutItem *itemByUuid( const QString &uuid ); diff --git a/python/gui/layout/qgslayoutview.sip b/python/gui/layout/qgslayoutview.sip index aca319ee7b5..6227aaf9fd0 100644 --- a/python/gui/layout/qgslayoutview.sip +++ b/python/gui/layout/qgslayoutview.sip @@ -210,6 +210,51 @@ class QgsLayoutView: QGraphicsView .. seealso:: selectNextItemAbove() .. seealso:: selectAll() .. seealso:: deselectAll() +%End + + void raiseSelectedItems(); +%Docstring + Raises the selected items up the z-order. +.. seealso:: lowerSelectedItems() +.. seealso:: moveSelectedItemsToTop() +.. seealso:: moveSelectedItemsToBottom() +%End + + void lowerSelectedItems(); +%Docstring + Lowers the selected items down the z-order. +.. seealso:: raiseSelectedItems() +.. seealso:: moveSelectedItemsToTop() +.. seealso:: moveSelectedItemsToBottom() +%End + + void moveSelectedItemsToTop(); +%Docstring + Raises the selected items to the top of the z-order. +.. seealso:: raiseSelectedItems() +.. seealso:: lowerSelectedItems() +.. seealso:: moveSelectedItemsToBottom() +%End + + void moveSelectedItemsToBottom(); +%Docstring + Lowers the selected items to the bottom of the z-order. +.. seealso:: raiseSelectedItems() +.. seealso:: lowerSelectedItems() +.. seealso:: moveSelectedItemsToTop() +%End + + void lockSelectedItems(); +%Docstring + Locks any selected items, preventing them from being interacted with + by mouse interactions. +.. seealso:: unlockAllItems() +%End + + void unlockAllItems(); +%Docstring + Unlocks all locked items in the layout. +.. seealso:: lockSelectedItems() %End void viewChanged(); diff --git a/src/app/layout/qgslayoutdesignerdialog.cpp b/src/app/layout/qgslayoutdesignerdialog.cpp index 807b4fb80b3..731cd2855da 100644 --- a/src/app/layout/qgslayoutdesignerdialog.cpp +++ b/src/app/layout/qgslayoutdesignerdialog.cpp @@ -542,18 +542,12 @@ void QgsLayoutDesignerDialog::snapToItems( bool enabled ) void QgsLayoutDesignerDialog::unlockAllItems() { - if ( mLayout ) - { - mLayout->unlockAllItems(); - } + mView->unlockAllItems(); } void QgsLayoutDesignerDialog::lockSelectedItems() { - if ( mLayout ) - { - mLayout->lockSelectedItems(); - } + mView->lockSelectedItems(); } void QgsLayoutDesignerDialog::setPanelVisibility( bool hidden ) @@ -616,22 +610,22 @@ void QgsLayoutDesignerDialog::setPanelVisibility( bool hidden ) void QgsLayoutDesignerDialog::raiseSelectedItems() { - mLayout->raiseSelectedItems(); + mView->raiseSelectedItems(); } void QgsLayoutDesignerDialog::lowerSelectedItems() { - mLayout->lowerSelectedItems(); + mView->lowerSelectedItems(); } void QgsLayoutDesignerDialog::moveSelectedItemsToTop() { - mLayout->moveSelectedItemsToTop(); + mView->moveSelectedItemsToTop(); } void QgsLayoutDesignerDialog::moveSelectedItemsToBottom() { - mLayout->moveSelectedItemsToBottom(); + mView->moveSelectedItemsToBottom(); } void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * ) diff --git a/src/core/layout/qgslayout.cpp b/src/core/layout/qgslayout.cpp index c8e82aa935c..13248f458f3 100644 --- a/src/core/layout/qgslayout.cpp +++ b/src/core/layout/qgslayout.cpp @@ -113,47 +113,6 @@ void QgsLayout::deselectAll() emit selectedItemChanged( nullptr ); } -void QgsLayout::lockSelectedItems() -{ - mUndoStack->beginMacro( tr( "Items locked" ) ); - const QList selectionList = selectedLayoutItems(); - for ( QgsLayoutItem *item : selectionList ) - { - mUndoStack->beginCommand( item, QString() ); - item->setLocked( true ); - mUndoStack->endCommand(); - } - - deselectAll(); - mUndoStack->endMacro(); -} - -void QgsLayout::unlockAllItems() -{ - //unlock all items in composer - - mUndoStack->beginMacro( tr( "Items unlocked" ) ); - - //first, clear the selection - deselectAll(); - - const QList itemList = items(); - for ( QGraphicsItem *graphicItem : itemList ) - { - QgsLayoutItem *item = dynamic_cast( graphicItem ); - if ( item && item->isLocked() ) - { - mUndoStack->beginCommand( item, QString() ); - item->setLocked( false ); - //select unlocked items, same behavior as illustrator - item->setSelected( true ); - emit selectedItemChanged( item ); - mUndoStack->endCommand(); - } - } - mUndoStack->endMacro(); -} - bool QgsLayout::raiseItem( QgsLayoutItem *item, bool deferUpdate ) { //model handles reordering items @@ -206,86 +165,6 @@ bool QgsLayout::moveItemToBottom( QgsLayoutItem *item, bool deferUpdate ) return result; } -void QgsLayout::raiseSelectedItems() -{ - const QList selectedItems = selectedLayoutItems(); - bool itemsRaised = false; - for ( QgsLayoutItem *item : selectedItems ) - { - itemsRaised = itemsRaised | raiseItem( item, true ); - } - - if ( !itemsRaised ) - { - //no change - return; - } - - //update all positions - updateZValues(); - update(); -} - -void QgsLayout::lowerSelectedItems() -{ - const QList selectedItems = selectedLayoutItems(); - bool itemsLowered = false; - for ( QgsLayoutItem *item : selectedItems ) - { - itemsLowered = itemsLowered | lowerItem( item, true ); - } - - if ( !itemsLowered ) - { - //no change - return; - } - - //update all positions - updateZValues(); - update(); -} - -void QgsLayout::moveSelectedItemsToTop() -{ - const QList selectedItems = selectedLayoutItems(); - bool itemsRaised = false; - for ( QgsLayoutItem *item : selectedItems ) - { - itemsRaised = itemsRaised | moveItemToTop( item, true ); - } - - if ( !itemsRaised ) - { - //no change - return; - } - - //update all positions - updateZValues(); - update(); -} - -void QgsLayout::moveSelectedItemsToBottom() -{ - const QList selectedItems = selectedLayoutItems(); - bool itemsLowered = false; - for ( QgsLayoutItem *item : selectedItems ) - { - itemsLowered = itemsLowered | moveItemToBottom( item, true ); - } - - if ( !itemsLowered ) - { - //no change - return; - } - - //update all positions - updateZValues(); - update(); -} - QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid ) { QList itemList; diff --git a/src/core/layout/qgslayout.h b/src/core/layout/qgslayout.h index 7b47b011995..6b796b1c3f7 100644 --- a/src/core/layout/qgslayout.h +++ b/src/core/layout/qgslayout.h @@ -135,19 +135,6 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext */ void deselectAll(); - /** - * Locks any selected items, preventing them from being interacted with - * by mouse interactions. - * \see unlockAllItems() - */ - void lockSelectedItems(); - - /** - * Unlocks all locked items in the layout. - * \see lockSelectedItems() - */ - void unlockAllItems(); - /** * Raises an \a item up the z-order. * Returns true if the item was successfully raised. @@ -158,6 +145,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext * updating the scene for each one. * * \see lowerItem() + * \see updateZValues() */ bool raiseItem( QgsLayoutItem *item, bool deferUpdate = false ); @@ -171,6 +159,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext * updating the scene for each one. * * \see raiseItem() + * \see updateZValues() */ bool lowerItem( QgsLayoutItem *item, bool deferUpdate = false ); @@ -184,6 +173,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext * updating the scene for each one. * * \see moveItemToBottom() + * \see updateZValues() */ bool moveItemToTop( QgsLayoutItem *item, bool deferUpdate = false ); @@ -196,40 +186,16 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext * updating the scene for each one. * * \see moveItemToTop() + * \see updateZValues() */ bool moveItemToBottom( QgsLayoutItem *item, bool deferUpdate = false ); /** - * Raises the selected items up the z-order. - * \see lowerSelectedItems() - * \see moveSelectedItemsToTop() - * \see moveSelectedItemsToBottom() + * Resets the z-values of items based on their position in the internal + * z order list. This should be called after any stacking changes + * which deferred z-order updates. */ - void raiseSelectedItems(); - - /** - * Lowers the selected items down the z-order. - * \see raiseSelectedItems() - * \see moveSelectedItemsToTop() - * \see moveSelectedItemsToBottom() - */ - void lowerSelectedItems(); - - /** - * Raises the selected items to the top of the z-order. - * \see raiseSelectedItems() - * \see lowerSelectedItems() - * \see moveSelectedItemsToBottom() - */ - void moveSelectedItemsToTop(); - - /** - * Lowers the selected items to the bottom of the z-order. - * \see raiseSelectedItems() - * \see lowerSelectedItems() - * \see moveSelectedItemsToTop() - */ - void moveSelectedItemsToBottom(); + void updateZValues( const bool addUndoCommands = true ); /** * Returns the layout item with matching \a uuid unique identifier, or a nullptr @@ -523,9 +489,6 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext //! Reads only the layout settings (not member settings like grid settings, etc) from XML bool readXmlLayoutSettings( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context ); - //! Reset z-values of items based on position in z list - void updateZValues( const bool addUndoCommands = true ); - friend class QgsLayoutUndoCommand; friend class QgsLayoutModel; diff --git a/src/gui/layout/qgslayoutview.cpp b/src/gui/layout/qgslayoutview.cpp index 06d75f318c8..8a7323a5d9b 100644 --- a/src/gui/layout/qgslayoutview.cpp +++ b/src/gui/layout/qgslayoutview.cpp @@ -398,6 +398,130 @@ void QgsLayoutView::selectNextItemBelow() selectNextByZOrder( currentLayout(), false ); } +void QgsLayoutView::raiseSelectedItems() +{ + const QList selectedItems = currentLayout()->selectedLayoutItems(); + bool itemsRaised = false; + for ( QgsLayoutItem *item : selectedItems ) + { + itemsRaised = itemsRaised | currentLayout()->raiseItem( item, true ); + } + + if ( !itemsRaised ) + { + //no change + return; + } + + //update all positions + currentLayout()->updateZValues(); + currentLayout()->update(); +} + +void QgsLayoutView::lowerSelectedItems() +{ + const QList selectedItems = currentLayout()->selectedLayoutItems(); + bool itemsLowered = false; + for ( QgsLayoutItem *item : selectedItems ) + { + itemsLowered = itemsLowered | currentLayout()->lowerItem( item, true ); + } + + if ( !itemsLowered ) + { + //no change + return; + } + + //update all positions + currentLayout()->updateZValues(); + currentLayout()->update(); +} + +void QgsLayoutView::moveSelectedItemsToTop() +{ + const QList selectedItems = currentLayout()->selectedLayoutItems(); + bool itemsRaised = false; + for ( QgsLayoutItem *item : selectedItems ) + { + itemsRaised = itemsRaised | currentLayout()->moveItemToTop( item, true ); + } + + if ( !itemsRaised ) + { + //no change + return; + } + + //update all positions + currentLayout()->updateZValues(); + currentLayout()->update(); +} + +void QgsLayoutView::moveSelectedItemsToBottom() +{ + const QList selectedItems = currentLayout()->selectedLayoutItems(); + bool itemsLowered = false; + for ( QgsLayoutItem *item : selectedItems ) + { + itemsLowered = itemsLowered | currentLayout()->moveItemToBottom( item, true ); + } + + if ( !itemsLowered ) + { + //no change + return; + } + + //update all positions + currentLayout()->updateZValues(); + currentLayout()->update(); +} + +void QgsLayoutView::lockSelectedItems() +{ + currentLayout()->undoStack()->beginMacro( tr( "Items locked" ) ); + const QList selectionList = currentLayout()->selectedLayoutItems(); + for ( QgsLayoutItem *item : selectionList ) + { + currentLayout()->undoStack()->beginCommand( item, QString() ); + item->setLocked( true ); + currentLayout()->undoStack()->endCommand(); + } + + currentLayout()->deselectAll(); + currentLayout()->undoStack()->endMacro(); +} + +void QgsLayoutView::unlockAllItems() +{ + //unlock all items in layout + currentLayout()->undoStack()->beginMacro( tr( "Items unlocked" ) ); + + //first, clear the selection + currentLayout()->deselectAll(); + + QgsLayoutItem *focusItem = nullptr; + + const QList itemList = currentLayout()->items(); + for ( QGraphicsItem *graphicItem : itemList ) + { + QgsLayoutItem *item = dynamic_cast( graphicItem ); + if ( item && item->isLocked() ) + { + focusItem = item; + currentLayout()->undoStack()->beginCommand( item, QString() ); + item->setLocked( false ); + //select unlocked items, same behavior as illustrator + item->setSelected( true ); + currentLayout()->undoStack()->endCommand(); + } + } + currentLayout()->undoStack()->endMacro(); + + emit itemFocused( focusItem ); +} + void QgsLayoutView::mousePressEvent( QMouseEvent *event ) { mSnapMarker->setVisible( false ); diff --git a/src/gui/layout/qgslayoutview.h b/src/gui/layout/qgslayoutview.h index 717b1f43f8b..e0af0be540e 100644 --- a/src/gui/layout/qgslayoutview.h +++ b/src/gui/layout/qgslayoutview.h @@ -255,6 +255,51 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView */ void selectNextItemBelow(); + /** + * Raises the selected items up the z-order. + * \see lowerSelectedItems() + * \see moveSelectedItemsToTop() + * \see moveSelectedItemsToBottom() + */ + void raiseSelectedItems(); + + /** + * Lowers the selected items down the z-order. + * \see raiseSelectedItems() + * \see moveSelectedItemsToTop() + * \see moveSelectedItemsToBottom() + */ + void lowerSelectedItems(); + + /** + * Raises the selected items to the top of the z-order. + * \see raiseSelectedItems() + * \see lowerSelectedItems() + * \see moveSelectedItemsToBottom() + */ + void moveSelectedItemsToTop(); + + /** + * Lowers the selected items to the bottom of the z-order. + * \see raiseSelectedItems() + * \see lowerSelectedItems() + * \see moveSelectedItemsToTop() + */ + void moveSelectedItemsToBottom(); + + /** + * Locks any selected items, preventing them from being interacted with + * by mouse interactions. + * \see unlockAllItems() + */ + void lockSelectedItems(); + + /** + * Unlocks all locked items in the layout. + * \see lockSelectedItems() + */ + void unlockAllItems(); + /** * Updates associated rulers and other widgets after view extent or zoom has changed. * This should be called after calling any of the QGraphicsView diff --git a/tests/src/python/test_qgslayout.py b/tests/src/python/test_qgslayout.py index 933e4b05015..2a06d74ac41 100644 --- a/tests/src/python/test_qgslayout.py +++ b/tests/src/python/test_qgslayout.py @@ -179,40 +179,6 @@ class TestQgsLayout(unittest.TestCase): item2.setLocked(True) self.assertEqual(l.layoutItemAt(QPointF(9, 13), item3, True), item1) - def testLockActions(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) - - item1.setLocked(True) - item3.setLocked(True) - self.assertTrue(item1.isLocked()) - self.assertFalse(item2.isLocked()) - self.assertTrue(item3.isLocked()) - - l.unlockAllItems() - self.assertFalse(item1.isLocked()) - self.assertFalse(item2.isLocked()) - self.assertFalse(item3.isLocked()) - self.assertTrue(item1.isSelected()) - self.assertFalse(item2.isSelected()) - self.assertTrue(item3.isSelected()) - - l.lockSelectedItems() - self.assertTrue(item1.isLocked()) - self.assertFalse(item2.isLocked()) - self.assertTrue(item3.isLocked()) - self.assertFalse(item1.isSelected()) - self.assertFalse(item2.isSelected()) - self.assertFalse(item3.isSelected()) - def testStacking(self): p = QgsProject() l = QgsLayout(p) diff --git a/tests/src/python/test_qgslayoutview.py b/tests/src/python/test_qgslayoutview.py index f3385f19c1d..3f2826a30c4 100644 --- a/tests/src/python/test_qgslayoutview.py +++ b/tests/src/python/test_qgslayoutview.py @@ -251,6 +251,43 @@ class TestQgsLayoutView(unittest.TestCase): self.assertFalse(item3.isSelected()) self.assertEqual(len(focused_item_spy), 5) + def testLockActions(self): + p = QgsProject() + l = QgsLayout(p) + + view = QgsLayoutView() + view.setCurrentLayout(l) + + # add some items + item1 = QgsLayoutItemMap(l) + l.addItem(item1) + item2 = QgsLayoutItemMap(l) + l.addItem(item2) + item3 = QgsLayoutItemMap(l) + l.addItem(item3) + + item1.setLocked(True) + item3.setLocked(True) + self.assertTrue(item1.isLocked()) + self.assertFalse(item2.isLocked()) + self.assertTrue(item3.isLocked()) + + view.unlockAllItems() + self.assertFalse(item1.isLocked()) + self.assertFalse(item2.isLocked()) + self.assertFalse(item3.isLocked()) + self.assertTrue(item1.isSelected()) + self.assertFalse(item2.isSelected()) + self.assertTrue(item3.isSelected()) + + view.lockSelectedItems() + self.assertTrue(item1.isLocked()) + self.assertFalse(item2.isLocked()) + self.assertTrue(item3.isLocked()) + self.assertFalse(item1.isSelected()) + self.assertFalse(item2.isSelected()) + self.assertFalse(item3.isSelected()) + if __name__ == '__main__': unittest.main()