Skip to content

Commit 9a3b547

Browse files
authored
Merge pull request #5330 from nyalldawson/layout_next
[layouts] Port group handling
2 parents f6ee7cb + 7b6156e commit 9a3b547

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1986
-154
lines changed

python/core/core_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@
403403
%Include layout/qgslayout.sip
404404
%Include layout/qgslayoutguidecollection.sip
405405
%Include layout/qgslayoutitem.sip
406+
%Include layout/qgslayoutitemgroup.sip
406407
%Include layout/qgslayoutitemmap.sip
407408
%Include layout/qgslayoutitempage.sip
408409
%Include layout/qgslayoutitemregistry.sip

python/core/layout/qgslayout.sip

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,25 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb
397397
virtual QgsAbstractLayoutUndoCommand *createCommand( const QString &text, int id = 0, QUndoCommand *parent = 0 ) /Factory/;
398398

399399

400+
QgsLayoutItemGroup *groupItems( const QList<QgsLayoutItem *> &items );
401+
%Docstring
402+
Creates a new group from a list of layout ``items`` and adds the group to the layout.
403+
If grouping was not possible, a None will be returned.
404+
.. seealso:: ungroupItems()
405+
:rtype: QgsLayoutItemGroup
406+
%End
407+
408+
QList<QgsLayoutItem *> ungroupItems( QgsLayoutItemGroup *group );
409+
%Docstring
410+
Ungroups items by removing them from an item ``group`` and removing the group from the
411+
layout. Child items will remain in the layout and will not be deleted.
412+
413+
Returns a list of the items removed from the group, or an empty list if ungrouping
414+
was not successful.
415+
416+
.. seealso:: groupItems()
417+
:rtype: list of QgsLayoutItem
418+
%End
400419

401420
public slots:
402421

python/core/layout/qgslayoutitem.sip

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,29 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
150150
:rtype: bool
151151
%End
152152

153+
bool isGroupMember() const;
154+
%Docstring
155+
Returns true if the item is part of a QgsLayoutItemGroup group.
156+
.. seealso:: parentGroup()
157+
.. seealso:: setParentGroup()
158+
:rtype: bool
159+
%End
160+
161+
QgsLayoutItemGroup *parentGroup() const;
162+
%Docstring
163+
Returns the item's parent group, if the item is part of a QgsLayoutItemGroup group.
164+
.. seealso:: isGroupMember()
165+
.. seealso:: setParentGroup()
166+
:rtype: QgsLayoutItemGroup
167+
%End
168+
169+
void setParentGroup( QgsLayoutItemGroup *group );
170+
%Docstring
171+
Sets the item's parent ``group``.
172+
.. seealso:: isGroupMember()
173+
.. seealso:: parentGroup()
174+
%End
175+
153176
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget );
154177

155178
%Docstring
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/layout/qgslayoutitemgroup.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
class QgsLayoutItemGroup: QgsLayoutItem
12+
{
13+
%Docstring
14+
A container for grouping several QgsLayoutItems.
15+
.. versionadded:: 3.0
16+
%End
17+
18+
%TypeHeaderCode
19+
#include "qgslayoutitemgroup.h"
20+
%End
21+
public:
22+
23+
explicit QgsLayoutItemGroup( QgsLayout *layout );
24+
%Docstring
25+
Constructor for QgsLayoutItemGroup, belonging to the specified ``layout``.
26+
%End
27+
~QgsLayoutItemGroup();
28+
29+
virtual int type() const;
30+
31+
virtual QString stringType() const;
32+
33+
virtual QString displayName() const;
34+
35+
36+
static QgsLayoutItemGroup *create( QgsLayout *layout, const QVariantMap &settings ) /Factory/;
37+
%Docstring
38+
Returns a new group item for the specified ``layout``.
39+
40+
The caller takes responsibility for deleting the returned object.
41+
:rtype: QgsLayoutItemGroup
42+
%End
43+
44+
void addItem( QgsLayoutItem *item /Transfer/ );
45+
%Docstring
46+
Adds an ``item`` to the group. Ownership of the item
47+
is transferred to the group.
48+
%End
49+
50+
void removeItems();
51+
%Docstring
52+
Removes all items from the group (but does not delete them).
53+
Items remain in the scene but are no longer grouped together
54+
%End
55+
56+
QList<QgsLayoutItem *> items() const;
57+
%Docstring
58+
Returns a list of items contained by the group.
59+
:rtype: list of QgsLayoutItem
60+
%End
61+
62+
virtual void setVisibility( const bool visible );
63+
64+
65+
virtual void attemptMove( const QgsLayoutPoint &point );
66+
67+
virtual void attemptResize( const QgsLayoutSize &size );
68+
69+
70+
virtual bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;
71+
72+
virtual bool readXml( const QDomElement &itemElement, const QDomDocument &document, const QgsReadWriteContext &context );
73+
74+
75+
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget );
76+
77+
78+
protected:
79+
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );
80+
81+
82+
};
83+
84+
85+
86+
87+
/************************************************************************
88+
* This file has been generated automatically from *
89+
* *
90+
* src/core/layout/qgslayoutitemgroup.h *
91+
* *
92+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
93+
************************************************************************/

python/core/layout/qgslayoutitemmap.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ class QgsLayoutItemMap : QgsLayoutItem
2525
Constructor for QgsLayoutItemMap, with the specified parent ``layout``.
2626
%End
2727
virtual int type() const;
28+
2829
virtual QString stringType() const;
2930

31+
3032
protected:
3133

3234
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );

python/core/layout/qgslayoutitemregistry.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class QgsLayoutItemRegistry : QObject
9898
enum ItemType
9999
{
100100
LayoutItem,
101+
LayoutGroup,
101102

102103
// known
103104
LayoutPage,

python/gui/layout/qgslayoutview.sip

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,18 @@ class QgsLayoutView: QGraphicsView
314314
Deletes all selected items.
315315
%End
316316

317+
void groupSelectedItems();
318+
%Docstring
319+
Groups all selected items.
320+
.. seealso:: ungroupSelectedItems()
321+
%End
322+
323+
void ungroupSelectedItems();
324+
%Docstring
325+
Ungroups all selected items.
326+
.. seealso:: groupSelectedItems()
327+
%End
328+
317329
void viewChanged();
318330
%Docstring
319331
Updates associated rulers and other widgets after view extent or zoom has changed.

src/app/layout/qgslayoutappmenuprovider.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "qgslayoutappmenuprovider.h"
1717
#include "qgslayoutitempage.h"
18+
#include "qgslayoutitemgroup.h"
1819
#include "qgslayoutdesignerdialog.h"
1920
#include "qgslayout.h"
2021
#include <QMenu>
@@ -31,6 +32,52 @@ QMenu *QgsLayoutAppMenuProvider::createContextMenu( QWidget *parent, QgsLayout *
3132
{
3233
QMenu *menu = new QMenu( parent );
3334

35+
//undo/redo
36+
menu->addAction( layout->undoStack()->stack()->createUndoAction( menu ) );
37+
menu->addAction( layout->undoStack()->stack()->createRedoAction( menu ) );
38+
menu->addSeparator();
39+
40+
41+
const QList< QgsLayoutItem * > selectedItems = layout->selectedLayoutItems();
42+
if ( !selectedItems.empty() )
43+
{
44+
bool addedGroupAction = false;
45+
if ( selectedItems.count() > 1 )
46+
{
47+
QAction *groupAction = new QAction( tr( "Group" ), menu );
48+
connect( groupAction, &QAction::triggered, this, [this]()
49+
{
50+
mDesigner->view()->groupSelectedItems();
51+
} );
52+
menu->addAction( groupAction );
53+
addedGroupAction = true;
54+
}
55+
bool foundSelectedGroup = false;
56+
QList< QgsLayoutItemGroup * > groups;
57+
layout->layoutItems( groups );
58+
for ( QgsLayoutItemGroup *group : qgsAsConst( groups ) )
59+
{
60+
if ( group->isSelected() )
61+
{
62+
foundSelectedGroup = true;
63+
break;
64+
}
65+
}
66+
if ( foundSelectedGroup )
67+
{
68+
QAction *ungroupAction = new QAction( tr( "Ungroup" ), menu );
69+
connect( ungroupAction, &QAction::triggered, this, [this]()
70+
{
71+
mDesigner->view()->ungroupSelectedItems();
72+
} );
73+
menu->addAction( ungroupAction );
74+
addedGroupAction = true;
75+
}
76+
77+
if ( addedGroupAction )
78+
menu->addSeparator();
79+
}
80+
3481
// is a page under the mouse?
3582
QgsLayoutItemPage *page = layout->pageCollection()->pageAtPoint( layoutPoint );
3683
if ( page )

src/app/layout/qgslayoutdesignerdialog.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,14 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
372372
{
373373
mView->deleteSelectedItems();
374374
} );
375+
connect( mActionGroupItems, &QAction::triggered, this, [ = ]
376+
{
377+
mView->groupSelectedItems();
378+
} );
379+
connect( mActionUngroupItems, &QAction::triggered, this, [ = ]
380+
{
381+
mView->ungroupSelectedItems();
382+
} );
375383

376384
//create status bar labels
377385
mStatusCursorXLabel = new QLabel( mStatusBar );
@@ -518,9 +526,6 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
518526
mGeneralDock->show();
519527
mItemsDock->show();
520528

521-
mActionUndo->setEnabled( false );
522-
mActionRedo->setEnabled( false );
523-
524529
tabifyDockWidget( mGeneralDock, mUndoDock );
525530
tabifyDockWidget( mItemDock, mUndoDock );
526531
tabifyDockWidget( mGeneralDock, mItemDock );
@@ -547,6 +552,20 @@ void QgsLayoutDesignerDialog::setCurrentLayout( QgsLayout *layout )
547552
mLayout = layout;
548553
mView->setCurrentLayout( layout );
549554

555+
// add undo/redo actions which apply to the correct layout undo stack
556+
delete mUndoAction;
557+
delete mRedoAction;
558+
mUndoAction = layout->undoStack()->stack()->createUndoAction( this );
559+
mUndoAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionUndo.svg" ) ) );
560+
mUndoAction->setShortcuts( QKeySequence::Undo );
561+
mRedoAction = layout->undoStack()->stack()->createRedoAction( this );
562+
mRedoAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRedo.svg" ) ) );
563+
mRedoAction->setShortcuts( QKeySequence::Redo );
564+
menuEdit->insertAction( menuEdit->actions().at( 0 ), mRedoAction );
565+
menuEdit->insertAction( mRedoAction, mUndoAction );
566+
mLayoutToolbar->addAction( mUndoAction );
567+
mLayoutToolbar->addAction( mRedoAction );
568+
550569
connect( mActionClearGuides, &QAction::triggered, &mLayout->guides(), [ = ]
551570
{
552571
mLayout->guides().clear();
@@ -560,10 +579,6 @@ void QgsLayoutDesignerDialog::setCurrentLayout( QgsLayout *layout )
560579
mActionShowBoxes->setChecked( mLayout->context().boundingBoxesVisible() );
561580
mActionShowPage->setChecked( mLayout->context().pagesVisible() );
562581

563-
connect( mLayout->undoStack()->stack(), &QUndoStack::canUndoChanged, mActionUndo, &QAction::setEnabled );
564-
connect( mLayout->undoStack()->stack(), &QUndoStack::canRedoChanged, mActionRedo, &QAction::setEnabled );
565-
connect( mActionUndo, &QAction::triggered, mLayout->undoStack()->stack(), &QUndoStack::undo );
566-
connect( mActionRedo, &QAction::triggered, mLayout->undoStack()->stack(), &QUndoStack::redo );
567582
mUndoView->setStack( mLayout->undoStack()->stack() );
568583

569584
mSelectTool->setLayout( layout );
@@ -981,7 +996,7 @@ void QgsLayoutDesignerDialog::addPages()
981996
}
982997

983998
if ( dlg.numberPages() > 1 )
984-
mLayout->undoStack()->beginMacro( tr( "Add pages" ) );
999+
mLayout->undoStack()->beginMacro( tr( "Add Pages" ) );
9851000
for ( int i = 0; i < dlg.numberPages(); ++i )
9861001
{
9871002
QgsLayoutItemPage *page = new QgsLayoutItemPage( mLayout );

src/app/layout/qgslayoutdesignerdialog.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
283283
QgsDockWidget *mItemsDock = nullptr;
284284
QTreeView *mItemsTreeView = nullptr;
285285

286+
QAction *mUndoAction = nullptr;
287+
QAction *mRedoAction = nullptr;
288+
286289
struct PanelStatus
287290
{
288291
PanelStatus( bool visible = true, bool active = false )

src/app/layout/qgslayoutguidewidget.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void QgsLayoutGuideWidget::addVerticalGuide()
7272

7373
void QgsLayoutGuideWidget::deleteHorizontalGuide()
7474
{
75-
mLayout->undoStack()->beginMacro( tr( "Remove horizontal guides" ) );
75+
mLayout->undoStack()->beginMacro( tr( "Remove Horizontal Guides" ) );
7676
Q_FOREACH ( const QModelIndex &index, mHozGuidesTableView->selectionModel()->selectedIndexes() )
7777
{
7878
mHozGuidesTableView->closePersistentEditor( index );
@@ -84,7 +84,7 @@ void QgsLayoutGuideWidget::deleteHorizontalGuide()
8484

8585
void QgsLayoutGuideWidget::deleteVerticalGuide()
8686
{
87-
mLayout->undoStack()->beginMacro( tr( "Remove vertical guides" ) );
87+
mLayout->undoStack()->beginMacro( tr( "Remove Vertical Guides" ) );
8888
Q_FOREACH ( const QModelIndex &index, mVertGuidesTableView->selectionModel()->selectedIndexes() )
8989
{
9090
mVertGuidesTableView->closePersistentEditor( index );
@@ -127,7 +127,7 @@ void QgsLayoutGuideWidget::clearAll()
127127
mVertGuidesTableView->closePersistentEditor( index );
128128
}
129129

130-
mLayout->undoStack()->beginMacro( tr( "Remove all guides" ) );
130+
mLayout->undoStack()->beginMacro( tr( "Remove All Guides" ) );
131131
mVertProxyModel->removeRows( 0, mVertProxyModel->rowCount() );
132132
mHozProxyModel->removeRows( 0, mHozProxyModel->rowCount() );
133133
mLayout->undoStack()->endMacro();

src/app/layout/qgslayoutpagepropertieswidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ void QgsLayoutPagePropertiesWidget::orientationChanged( int )
128128

129129
void QgsLayoutPagePropertiesWidget::updatePageSize()
130130
{
131-
mPage->layout()->undoStack()->beginCommand( mPage, tr( "Changed page size" ), 1 + mPage->layout()->pageCollection()->pageNumber( mPage ) );
131+
mPage->layout()->undoStack()->beginCommand( mPage, tr( "Change Page Size" ), 1 + mPage->layout()->pageCollection()->pageNumber( mPage ) );
132132
mPage->setPageSize( QgsLayoutSize( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() ) );
133133
mPage->layout()->undoStack()->endCommand();
134134
mPage->layout()->pageCollection()->reflow();

src/core/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ SET(QGIS_CORE_SRCS
365365
layout/qgslayoutgridsettings.cpp
366366
layout/qgslayoutguidecollection.cpp
367367
layout/qgslayoutitem.cpp
368+
layout/qgslayoutitemgroup.cpp
369+
layout/qgslayoutitemgroupundocommand.cpp
368370
layout/qgslayoutitemmap.cpp
369371
layout/qgslayoutitempage.cpp
370372
layout/qgslayoutitemregistry.cpp
@@ -714,6 +716,8 @@ SET(QGIS_CORE_MOC_HDRS
714716
layout/qgslayout.h
715717
layout/qgslayoutguidecollection.h
716718
layout/qgslayoutitem.h
719+
layout/qgslayoutitemgroup.h
720+
layout/qgslayoutitemgroupundocommand.h
717721
layout/qgslayoutitemmap.h
718722
layout/qgslayoutitempage.h
719723
layout/qgslayoutitemregistry.h

0 commit comments

Comments
 (0)