Skip to content

Commit f04d438

Browse files
committed
Some undo/redo fixes for multiframe items
1 parent c6eaf1f commit f04d438

13 files changed

+146
-68
lines changed

python/core/layout/qgslayoutmultiframe.sip

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -184,35 +184,6 @@ class QgsLayoutMultiFrame: QgsLayoutObject, QgsLayoutUndoObjectInterface
184184
:rtype: bool
185185
%End
186186

187-
QList<QgsLayoutFrame *> frames() const;
188-
%Docstring
189-
Returns a list of all child frames for this multiframe.
190-
.. seealso:: frameCount()
191-
:rtype: list of QgsLayoutFrame
192-
%End
193-
194-
int frameCount() const;
195-
%Docstring
196-
Returns the number of frames associated with this multiframe.
197-
.. seealso:: frames()
198-
:rtype: int
199-
%End
200-
201-
QgsLayoutFrame *frame( int index ) const;
202-
%Docstring
203-
Returns the child frame at a specified ``index`` from the multiframe.
204-
.. seealso:: frameIndex()
205-
:rtype: QgsLayoutFrame
206-
%End
207-
208-
int frameIndex( QgsLayoutFrame *frame ) const;
209-
%Docstring
210-
Returns the index of a ``frame`` within the multiframe.
211-
:return: index for frame if found, -1 if frame not found in multiframe
212-
.. seealso:: frame()
213-
:rtype: int
214-
%End
215-
216187
QgsLayoutFrame *createNewFrame( QgsLayoutFrame *currentFrame, QPointF pos, QSizeF size );
217188
%Docstring
218189
Creates a new frame and adds it to the multi frame and layout.

python/core/layout/qgslayoutundostack.sip

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,31 @@ class QgsLayoutUndoStack : QObject
9292
Notifies the stack that an undo or redo action occurred for a specified ``item``.
9393
%End
9494

95+
void blockCommands( bool blocked );
96+
%Docstring
97+
Sets whether undo commands for the layout should be temporarily blocked.
98+
99+
If ``blocked`` is true, subsequent undo commands will be blocked until a follow-up
100+
call to blockCommands( false ) is made.
101+
102+
Note that calls to blockCommands are stacked, so two calls blocking the commands
103+
will take two calls unblocking commands in order to release the block.
104+
105+
.. seealso:: isBlocked()
106+
%End
107+
108+
bool isBlocked() const;
109+
%Docstring
110+
Returns true if undo commands are currently blocked.
111+
.. seealso:: blockCommands()
112+
:rtype: bool
113+
%End
114+
115+
void push( QUndoCommand *command /Transfer/ );
116+
%Docstring
117+
Manually pushes a ``command`` to the stack, and takes ownership of the command.
118+
%End
119+
95120
signals:
96121

97122
void undoRedoOccurredForItems( const QSet< QString > itemUuids );

src/app/layout/qgslayouthtmlwidget.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ QgsLayoutHtmlWidget::QgsLayoutHtmlWidget( QgsLayoutFrame *frame )
4141
connect( mRadioUrlSource, &QRadioButton::clicked, this, &QgsLayoutHtmlWidget::mRadioUrlSource_clicked );
4242
connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mInsertExpressionButton_clicked );
4343
connect( mReloadPushButton, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mReloadPushButton_clicked );
44-
connect( mReloadPushButton2, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mReloadPushButton2_clicked );
44+
connect( mReloadPushButton2, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mReloadPushButton_clicked );
4545
connect( mAddFramePushButton, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mAddFramePushButton_clicked );
4646
connect( mEmptyFrameCheckBox, &QCheckBox::toggled, this, &QgsLayoutHtmlWidget::mEmptyFrameCheckBox_toggled );
4747
connect( mHideEmptyBgCheckBox, &QCheckBox::toggled, this, &QgsLayoutHtmlWidget::mHideEmptyBgCheckBox_toggled );
@@ -296,7 +296,6 @@ void QgsLayoutHtmlWidget::mRadioManualSource_clicked( bool checked )
296296
blockSignals( true );
297297
mHtml->beginCommand( tr( "Change HTML Source" ) );
298298
mHtml->setContentMode( checked ? QgsLayoutItemHtml::ManualHtml : QgsLayoutItemHtml::Url );
299-
mHtml->endCommand();
300299
blockSignals( false );
301300

302301
mHtmlEditor->setEnabled( checked );
@@ -305,6 +304,7 @@ void QgsLayoutHtmlWidget::mRadioManualSource_clicked( bool checked )
305304
mFileToolButton->setEnabled( !checked );
306305

307306
mHtml->loadHtml();
307+
mHtml->endCommand();
308308
}
309309

310310
void QgsLayoutHtmlWidget::mRadioUrlSource_clicked( bool checked )
@@ -317,7 +317,6 @@ void QgsLayoutHtmlWidget::mRadioUrlSource_clicked( bool checked )
317317
blockSignals( true );
318318
mHtml->beginCommand( tr( "Change HTML Source" ) );
319319
mHtml->setContentMode( checked ? QgsLayoutItemHtml::Url : QgsLayoutItemHtml::ManualHtml );
320-
mHtml->endCommand();
321320
blockSignals( false );
322321

323322
mHtmlEditor->setEnabled( !checked );
@@ -326,6 +325,7 @@ void QgsLayoutHtmlWidget::mRadioUrlSource_clicked( bool checked )
326325
mFileToolButton->setEnabled( checked );
327326

328327
mHtml->loadHtml();
328+
mHtml->endCommand();
329329
}
330330

331331
void QgsLayoutHtmlWidget::mInsertExpressionButton_clicked()
@@ -390,17 +390,11 @@ void QgsLayoutHtmlWidget::mReloadPushButton_clicked()
390390
return;
391391
}
392392

393+
if ( mHtml->layout() )
394+
mHtml->layout()->undoStack()->blockCommands( true );
393395
mHtml->loadHtml();
394-
}
395-
396-
void QgsLayoutHtmlWidget::mReloadPushButton2_clicked()
397-
{
398-
if ( !mHtml )
399-
{
400-
return;
401-
}
402-
403-
mHtml->loadHtml();
396+
if ( mHtml->layout() )
397+
mHtml->layout()->undoStack()->blockCommands( false );
404398
}
405399

406400
void QgsLayoutHtmlWidget::mAddFramePushButton_clicked()

src/app/layout/qgslayouthtmlwidget.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class QgsLayoutHtmlWidget: public QgsLayoutItemBaseWidget, private Ui::QgsLayout
5353
void mInsertExpressionButton_clicked();
5454

5555
void mReloadPushButton_clicked();
56-
void mReloadPushButton2_clicked();
5756
void mAddFramePushButton_clicked();
5857
void mEmptyFrameCheckBox_toggled( bool checked );
5958
void mHideEmptyBgCheckBox_toggled( bool checked );

src/core/layout/qgslayout.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ QgsLayout::QgsLayout( QgsProject *project )
4242
QgsLayout::~QgsLayout()
4343
{
4444
// no need for undo commands when we're destroying the layout
45-
mBlockUndoCommandCount++;
45+
mUndoStack->blockCommands( true );
4646

4747
deleteAndRemoveMultiFrames();
4848

@@ -410,22 +410,22 @@ void QgsLayout::addLayoutItem( QgsLayoutItem *item )
410410
{
411411
undoText = tr( "Create Item" );
412412
}
413-
if ( mBlockUndoCommandCount == 0 )
414-
mUndoStack->stack()->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
413+
if ( !mUndoStack->isBlocked() )
414+
mUndoStack->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
415415
}
416416

417417
void QgsLayout::removeLayoutItem( QgsLayoutItem *item )
418418
{
419419
std::unique_ptr< QgsLayoutItemDeleteUndoCommand > deleteCommand;
420-
if ( mBlockUndoCommandCount == 0 )
420+
if ( !mUndoStack->isBlocked() )
421421
{
422422
mUndoStack->beginMacro( tr( "Delete Items" ) );
423423
deleteCommand.reset( new QgsLayoutItemDeleteUndoCommand( item, tr( "Delete Item" ) ) );
424424
}
425425
removeLayoutItemPrivate( item );
426426
if ( deleteCommand )
427427
{
428-
mUndoStack->stack()->push( deleteCommand.release() );
428+
mUndoStack->push( deleteCommand.release() );
429429
mUndoStack->endMacro();
430430
}
431431
}
@@ -518,7 +518,7 @@ QgsLayoutItemGroup *QgsLayout::groupItems( const QList<QgsLayoutItem *> &items )
518518
addLayoutItem( itemGroup.release() );
519519

520520
std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Grouped, returnGroup, this, tr( "Group Items" ) ) );
521-
mUndoStack->stack()->push( c.release() );
521+
mUndoStack->push( c.release() );
522522
mProject->setDirty( true );
523523

524524
#if 0
@@ -542,7 +542,7 @@ QList<QgsLayoutItem *> QgsLayout::ungroupItems( QgsLayoutItemGroup *group )
542542
// Call this before removing group items so it can keep note
543543
// of contents
544544
std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Ungrouped, group, this, tr( "Ungroup Items" ) ) );
545-
mUndoStack->stack()->push( c.release() );
545+
mUndoStack->push( c.release() );
546546

547547
mProject->setDirty( true );
548548

src/core/layout/qgslayout.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,6 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
559559
std::unique_ptr< QgsLayoutUndoStack > mUndoStack;
560560
QgsLayoutExporter mExporter;
561561

562-
int mBlockUndoCommandCount = 0;
563-
564562
//! List of multiframe objects
565563
QSet<QgsLayoutMultiFrame *> mMultiFrames;
566564

src/core/layout/qgslayoutitem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ void QgsLayoutItem::setVisibility( const bool visible )
163163
if ( command )
164164
{
165165
command->saveAfterState();
166-
mLayout->undoStack()->stack()->push( command.release() );
166+
mLayout->undoStack()->push( command.release() );
167167
}
168168

169169
//inform model that visibility has changed

src/core/layout/qgslayoutitemgroup.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ void QgsLayoutItemGroup::attemptMove( const QgsLayoutPoint &point, bool useRefer
168168
if ( command )
169169
{
170170
command->saveAfterState();
171-
mLayout->undoStack()->stack()->push( command.release() );
171+
mLayout->undoStack()->push( command.release() );
172172
}
173173
}
174174
//lastly move group item itself
@@ -220,7 +220,7 @@ void QgsLayoutItemGroup::attemptResize( const QgsLayoutSize &size, bool includes
220220
if ( command )
221221
{
222222
command->saveAfterState();
223-
mLayout->undoStack()->stack()->push( command.release() );
223+
mLayout->undoStack()->push( command.release() );
224224
}
225225
}
226226
QgsLayoutItem::attemptResize( size );

src/core/layout/qgslayoutmultiframe.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ void QgsLayoutMultiFrame::setResizeMode( ResizeMode mode )
7474
{
7575
if ( mode != mResizeMode )
7676
{
77+
mLayout->undoStack()->beginMacro( tr( "Change Resize Mode" ) );
7778
mResizeMode = mode;
7879
recalculateFrameSizes();
80+
mLayout->undoStack()->endMacro();
7981
emit changed();
8082
}
8183
}
@@ -101,7 +103,7 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
101103
}
102104

103105
if ( mBlockUndoCommands )
104-
mLayout->mBlockUndoCommandCount++;
106+
mLayout->undoStack()->blockCommands( true );
105107

106108
double currentY = 0;
107109
double currentHeight = 0;
@@ -213,7 +215,7 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
213215
}
214216

215217
if ( mBlockUndoCommands )
216-
mLayout->mBlockUndoCommandCount--;
218+
mLayout->undoStack()->blockCommands( false );
217219
}
218220

219221
void QgsLayoutMultiFrame::recalculateFrameRects()
@@ -376,14 +378,14 @@ void QgsLayoutMultiFrame::removeFrame( int i, const bool removeEmptyPages )
376378
mIsRecalculatingSize = true;
377379
int pageNumber = frameItem->page();
378380
//remove item, but don't create undo command
379-
mLayout->mBlockUndoCommandCount++;
381+
mLayout->undoStack()->blockCommands( true );
380382
mLayout->removeLayoutItem( frameItem );
381383
//if frame was the only item on the page, remove the page
382384
if ( removeEmptyPages && mLayout->pageCollection()->pageIsEmpty( pageNumber ) )
383385
{
384386
mLayout->pageCollection()->deletePage( pageNumber );
385387
}
386-
mLayout->mBlockUndoCommandCount--;
388+
mLayout->undoStack()->blockCommands( false );
387389
mIsRecalculatingSize = false;
388390
}
389391
mFrameItems.removeAt( i );
@@ -402,12 +404,12 @@ void QgsLayoutMultiFrame::deleteFrames()
402404
mBlockUpdates = true;
403405
ResizeMode bkResizeMode = mResizeMode;
404406
mResizeMode = UseExistingFrames;
405-
mLayout->mBlockUndoCommandCount++;
407+
mLayout->undoStack()->blockCommands( true );
406408
for ( QgsLayoutFrame *frame : qgis::as_const( mFrameItems ) )
407409
{
408410
mLayout->removeLayoutItem( frame );
409411
}
410-
mLayout->mBlockUndoCommandCount--;
412+
mLayout->undoStack()->blockCommands( false );
411413
mFrameItems.clear();
412414
mResizeMode = bkResizeMode;
413415
mBlockUpdates = false;
@@ -460,6 +462,7 @@ bool QgsLayoutMultiFrame::readXml( const QDomElement &element, const QDomDocumen
460462
}
461463

462464
mBlockUndoCommands = true;
465+
mLayout->undoStack()->blockCommands( true );
463466

464467
readObjectPropertiesFromElement( element, doc, context );
465468

@@ -491,6 +494,7 @@ bool QgsLayoutMultiFrame::readXml( const QDomElement &element, const QDomDocumen
491494
bool result = readPropertiesFromElement( element, doc, context );
492495

493496
mBlockUndoCommands = false;
497+
mLayout->undoStack()->blockCommands( false );
494498
return result;
495499
}
496500

src/core/layout/qgslayoutundostack.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ QgsLayoutUndoStack::QgsLayoutUndoStack( QgsLayout *layout )
2929

3030
void QgsLayoutUndoStack::beginMacro( const QString &commandText )
3131
{
32-
mUndoStack->beginMacro( commandText );
32+
if ( mBlockedCommands == 0 )
33+
mUndoStack->beginMacro( commandText );
3334
}
3435

3536
void QgsLayoutUndoStack::endMacro()
3637
{
37-
mUndoStack->endMacro();
38+
if ( mBlockedCommands == 0 )
39+
mUndoStack->endMacro();
3840
}
3941

4042
void QgsLayoutUndoStack::beginCommand( QgsLayoutUndoObjectInterface *object, const QString &commandText, int id )
@@ -54,13 +56,13 @@ void QgsLayoutUndoStack::endCommand()
5456
return;
5557

5658
mActiveCommands.back()->saveAfterState();
57-
if ( mActiveCommands.back()->containsChange() ) //protect against empty commands
59+
if ( mBlockedCommands == 0 && mActiveCommands.back()->containsChange() ) //protect against empty commands
5860
{
5961
mUndoStack->push( mActiveCommands.back().release() );
60-
mActiveCommands.pop_back();
61-
6262
mLayout->project()->setDirty( true );
6363
}
64+
65+
mActiveCommands.pop_back();
6466
}
6567

6668
void QgsLayoutUndoStack::cancelCommand()
@@ -81,6 +83,32 @@ void QgsLayoutUndoStack::notifyUndoRedoOccurred( QgsLayoutItem *item )
8183
mUndoRedoOccurredItemUuids.insert( item->uuid() );
8284
}
8385

86+
void QgsLayoutUndoStack::blockCommands( bool blocked )
87+
{
88+
if ( blocked )
89+
{
90+
mBlockedCommands++;
91+
}
92+
else
93+
{
94+
if ( mBlockedCommands > 0 )
95+
mBlockedCommands--;
96+
}
97+
}
98+
99+
bool QgsLayoutUndoStack::isBlocked() const
100+
{
101+
return mBlockedCommands > 0;
102+
}
103+
104+
void QgsLayoutUndoStack::push( QUndoCommand *cmd )
105+
{
106+
if ( mBlockedCommands > 0 )
107+
delete cmd;
108+
else
109+
mUndoStack->push( cmd );
110+
}
111+
84112
void QgsLayoutUndoStack::indexChanged()
85113
{
86114
if ( mUndoRedoOccurredItemUuids.empty() )

0 commit comments

Comments
 (0)