mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Some undo/redo fixes for multiframe items
This commit is contained in:
parent
c6eaf1f7fd
commit
f04d438572
@ -184,35 +184,6 @@ class QgsLayoutMultiFrame: QgsLayoutObject, QgsLayoutUndoObjectInterface
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
QList<QgsLayoutFrame *> frames() const;
|
||||
%Docstring
|
||||
Returns a list of all child frames for this multiframe.
|
||||
.. seealso:: frameCount()
|
||||
:rtype: list of QgsLayoutFrame
|
||||
%End
|
||||
|
||||
int frameCount() const;
|
||||
%Docstring
|
||||
Returns the number of frames associated with this multiframe.
|
||||
.. seealso:: frames()
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
QgsLayoutFrame *frame( int index ) const;
|
||||
%Docstring
|
||||
Returns the child frame at a specified ``index`` from the multiframe.
|
||||
.. seealso:: frameIndex()
|
||||
:rtype: QgsLayoutFrame
|
||||
%End
|
||||
|
||||
int frameIndex( QgsLayoutFrame *frame ) const;
|
||||
%Docstring
|
||||
Returns the index of a ``frame`` within the multiframe.
|
||||
:return: index for frame if found, -1 if frame not found in multiframe
|
||||
.. seealso:: frame()
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
QgsLayoutFrame *createNewFrame( QgsLayoutFrame *currentFrame, QPointF pos, QSizeF size );
|
||||
%Docstring
|
||||
Creates a new frame and adds it to the multi frame and layout.
|
||||
|
@ -92,6 +92,31 @@ class QgsLayoutUndoStack : QObject
|
||||
Notifies the stack that an undo or redo action occurred for a specified ``item``.
|
||||
%End
|
||||
|
||||
void blockCommands( bool blocked );
|
||||
%Docstring
|
||||
Sets whether undo commands for the layout should be temporarily blocked.
|
||||
|
||||
If ``blocked`` is true, subsequent undo commands will be blocked until a follow-up
|
||||
call to blockCommands( false ) is made.
|
||||
|
||||
Note that calls to blockCommands are stacked, so two calls blocking the commands
|
||||
will take two calls unblocking commands in order to release the block.
|
||||
|
||||
.. seealso:: isBlocked()
|
||||
%End
|
||||
|
||||
bool isBlocked() const;
|
||||
%Docstring
|
||||
Returns true if undo commands are currently blocked.
|
||||
.. seealso:: blockCommands()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void push( QUndoCommand *command /Transfer/ );
|
||||
%Docstring
|
||||
Manually pushes a ``command`` to the stack, and takes ownership of the command.
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void undoRedoOccurredForItems( const QSet< QString > itemUuids );
|
||||
|
@ -41,7 +41,7 @@ QgsLayoutHtmlWidget::QgsLayoutHtmlWidget( QgsLayoutFrame *frame )
|
||||
connect( mRadioUrlSource, &QRadioButton::clicked, this, &QgsLayoutHtmlWidget::mRadioUrlSource_clicked );
|
||||
connect( mInsertExpressionButton, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mInsertExpressionButton_clicked );
|
||||
connect( mReloadPushButton, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mReloadPushButton_clicked );
|
||||
connect( mReloadPushButton2, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mReloadPushButton2_clicked );
|
||||
connect( mReloadPushButton2, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mReloadPushButton_clicked );
|
||||
connect( mAddFramePushButton, &QPushButton::clicked, this, &QgsLayoutHtmlWidget::mAddFramePushButton_clicked );
|
||||
connect( mEmptyFrameCheckBox, &QCheckBox::toggled, this, &QgsLayoutHtmlWidget::mEmptyFrameCheckBox_toggled );
|
||||
connect( mHideEmptyBgCheckBox, &QCheckBox::toggled, this, &QgsLayoutHtmlWidget::mHideEmptyBgCheckBox_toggled );
|
||||
@ -296,7 +296,6 @@ void QgsLayoutHtmlWidget::mRadioManualSource_clicked( bool checked )
|
||||
blockSignals( true );
|
||||
mHtml->beginCommand( tr( "Change HTML Source" ) );
|
||||
mHtml->setContentMode( checked ? QgsLayoutItemHtml::ManualHtml : QgsLayoutItemHtml::Url );
|
||||
mHtml->endCommand();
|
||||
blockSignals( false );
|
||||
|
||||
mHtmlEditor->setEnabled( checked );
|
||||
@ -305,6 +304,7 @@ void QgsLayoutHtmlWidget::mRadioManualSource_clicked( bool checked )
|
||||
mFileToolButton->setEnabled( !checked );
|
||||
|
||||
mHtml->loadHtml();
|
||||
mHtml->endCommand();
|
||||
}
|
||||
|
||||
void QgsLayoutHtmlWidget::mRadioUrlSource_clicked( bool checked )
|
||||
@ -317,7 +317,6 @@ void QgsLayoutHtmlWidget::mRadioUrlSource_clicked( bool checked )
|
||||
blockSignals( true );
|
||||
mHtml->beginCommand( tr( "Change HTML Source" ) );
|
||||
mHtml->setContentMode( checked ? QgsLayoutItemHtml::Url : QgsLayoutItemHtml::ManualHtml );
|
||||
mHtml->endCommand();
|
||||
blockSignals( false );
|
||||
|
||||
mHtmlEditor->setEnabled( !checked );
|
||||
@ -326,6 +325,7 @@ void QgsLayoutHtmlWidget::mRadioUrlSource_clicked( bool checked )
|
||||
mFileToolButton->setEnabled( checked );
|
||||
|
||||
mHtml->loadHtml();
|
||||
mHtml->endCommand();
|
||||
}
|
||||
|
||||
void QgsLayoutHtmlWidget::mInsertExpressionButton_clicked()
|
||||
@ -390,17 +390,11 @@ void QgsLayoutHtmlWidget::mReloadPushButton_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
if ( mHtml->layout() )
|
||||
mHtml->layout()->undoStack()->blockCommands( true );
|
||||
mHtml->loadHtml();
|
||||
}
|
||||
|
||||
void QgsLayoutHtmlWidget::mReloadPushButton2_clicked()
|
||||
{
|
||||
if ( !mHtml )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mHtml->loadHtml();
|
||||
if ( mHtml->layout() )
|
||||
mHtml->layout()->undoStack()->blockCommands( false );
|
||||
}
|
||||
|
||||
void QgsLayoutHtmlWidget::mAddFramePushButton_clicked()
|
||||
|
@ -53,7 +53,6 @@ class QgsLayoutHtmlWidget: public QgsLayoutItemBaseWidget, private Ui::QgsLayout
|
||||
void mInsertExpressionButton_clicked();
|
||||
|
||||
void mReloadPushButton_clicked();
|
||||
void mReloadPushButton2_clicked();
|
||||
void mAddFramePushButton_clicked();
|
||||
void mEmptyFrameCheckBox_toggled( bool checked );
|
||||
void mHideEmptyBgCheckBox_toggled( bool checked );
|
||||
|
@ -42,7 +42,7 @@ QgsLayout::QgsLayout( QgsProject *project )
|
||||
QgsLayout::~QgsLayout()
|
||||
{
|
||||
// no need for undo commands when we're destroying the layout
|
||||
mBlockUndoCommandCount++;
|
||||
mUndoStack->blockCommands( true );
|
||||
|
||||
deleteAndRemoveMultiFrames();
|
||||
|
||||
@ -410,14 +410,14 @@ void QgsLayout::addLayoutItem( QgsLayoutItem *item )
|
||||
{
|
||||
undoText = tr( "Create Item" );
|
||||
}
|
||||
if ( mBlockUndoCommandCount == 0 )
|
||||
mUndoStack->stack()->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
|
||||
if ( !mUndoStack->isBlocked() )
|
||||
mUndoStack->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
|
||||
}
|
||||
|
||||
void QgsLayout::removeLayoutItem( QgsLayoutItem *item )
|
||||
{
|
||||
std::unique_ptr< QgsLayoutItemDeleteUndoCommand > deleteCommand;
|
||||
if ( mBlockUndoCommandCount == 0 )
|
||||
if ( !mUndoStack->isBlocked() )
|
||||
{
|
||||
mUndoStack->beginMacro( tr( "Delete Items" ) );
|
||||
deleteCommand.reset( new QgsLayoutItemDeleteUndoCommand( item, tr( "Delete Item" ) ) );
|
||||
@ -425,7 +425,7 @@ void QgsLayout::removeLayoutItem( QgsLayoutItem *item )
|
||||
removeLayoutItemPrivate( item );
|
||||
if ( deleteCommand )
|
||||
{
|
||||
mUndoStack->stack()->push( deleteCommand.release() );
|
||||
mUndoStack->push( deleteCommand.release() );
|
||||
mUndoStack->endMacro();
|
||||
}
|
||||
}
|
||||
@ -518,7 +518,7 @@ QgsLayoutItemGroup *QgsLayout::groupItems( const QList<QgsLayoutItem *> &items )
|
||||
addLayoutItem( itemGroup.release() );
|
||||
|
||||
std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Grouped, returnGroup, this, tr( "Group Items" ) ) );
|
||||
mUndoStack->stack()->push( c.release() );
|
||||
mUndoStack->push( c.release() );
|
||||
mProject->setDirty( true );
|
||||
|
||||
#if 0
|
||||
@ -542,7 +542,7 @@ QList<QgsLayoutItem *> QgsLayout::ungroupItems( QgsLayoutItemGroup *group )
|
||||
// Call this before removing group items so it can keep note
|
||||
// of contents
|
||||
std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Ungrouped, group, this, tr( "Ungroup Items" ) ) );
|
||||
mUndoStack->stack()->push( c.release() );
|
||||
mUndoStack->push( c.release() );
|
||||
|
||||
mProject->setDirty( true );
|
||||
|
||||
|
@ -559,8 +559,6 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
||||
std::unique_ptr< QgsLayoutUndoStack > mUndoStack;
|
||||
QgsLayoutExporter mExporter;
|
||||
|
||||
int mBlockUndoCommandCount = 0;
|
||||
|
||||
//! List of multiframe objects
|
||||
QSet<QgsLayoutMultiFrame *> mMultiFrames;
|
||||
|
||||
|
@ -163,7 +163,7 @@ void QgsLayoutItem::setVisibility( const bool visible )
|
||||
if ( command )
|
||||
{
|
||||
command->saveAfterState();
|
||||
mLayout->undoStack()->stack()->push( command.release() );
|
||||
mLayout->undoStack()->push( command.release() );
|
||||
}
|
||||
|
||||
//inform model that visibility has changed
|
||||
|
@ -168,7 +168,7 @@ void QgsLayoutItemGroup::attemptMove( const QgsLayoutPoint &point, bool useRefer
|
||||
if ( command )
|
||||
{
|
||||
command->saveAfterState();
|
||||
mLayout->undoStack()->stack()->push( command.release() );
|
||||
mLayout->undoStack()->push( command.release() );
|
||||
}
|
||||
}
|
||||
//lastly move group item itself
|
||||
@ -220,7 +220,7 @@ void QgsLayoutItemGroup::attemptResize( const QgsLayoutSize &size, bool includes
|
||||
if ( command )
|
||||
{
|
||||
command->saveAfterState();
|
||||
mLayout->undoStack()->stack()->push( command.release() );
|
||||
mLayout->undoStack()->push( command.release() );
|
||||
}
|
||||
}
|
||||
QgsLayoutItem::attemptResize( size );
|
||||
|
@ -74,8 +74,10 @@ void QgsLayoutMultiFrame::setResizeMode( ResizeMode mode )
|
||||
{
|
||||
if ( mode != mResizeMode )
|
||||
{
|
||||
mLayout->undoStack()->beginMacro( tr( "Change Resize Mode" ) );
|
||||
mResizeMode = mode;
|
||||
recalculateFrameSizes();
|
||||
mLayout->undoStack()->endMacro();
|
||||
emit changed();
|
||||
}
|
||||
}
|
||||
@ -101,7 +103,7 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
|
||||
}
|
||||
|
||||
if ( mBlockUndoCommands )
|
||||
mLayout->mBlockUndoCommandCount++;
|
||||
mLayout->undoStack()->blockCommands( true );
|
||||
|
||||
double currentY = 0;
|
||||
double currentHeight = 0;
|
||||
@ -213,7 +215,7 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
|
||||
}
|
||||
|
||||
if ( mBlockUndoCommands )
|
||||
mLayout->mBlockUndoCommandCount--;
|
||||
mLayout->undoStack()->blockCommands( false );
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrame::recalculateFrameRects()
|
||||
@ -376,14 +378,14 @@ void QgsLayoutMultiFrame::removeFrame( int i, const bool removeEmptyPages )
|
||||
mIsRecalculatingSize = true;
|
||||
int pageNumber = frameItem->page();
|
||||
//remove item, but don't create undo command
|
||||
mLayout->mBlockUndoCommandCount++;
|
||||
mLayout->undoStack()->blockCommands( true );
|
||||
mLayout->removeLayoutItem( frameItem );
|
||||
//if frame was the only item on the page, remove the page
|
||||
if ( removeEmptyPages && mLayout->pageCollection()->pageIsEmpty( pageNumber ) )
|
||||
{
|
||||
mLayout->pageCollection()->deletePage( pageNumber );
|
||||
}
|
||||
mLayout->mBlockUndoCommandCount--;
|
||||
mLayout->undoStack()->blockCommands( false );
|
||||
mIsRecalculatingSize = false;
|
||||
}
|
||||
mFrameItems.removeAt( i );
|
||||
@ -402,12 +404,12 @@ void QgsLayoutMultiFrame::deleteFrames()
|
||||
mBlockUpdates = true;
|
||||
ResizeMode bkResizeMode = mResizeMode;
|
||||
mResizeMode = UseExistingFrames;
|
||||
mLayout->mBlockUndoCommandCount++;
|
||||
mLayout->undoStack()->blockCommands( true );
|
||||
for ( QgsLayoutFrame *frame : qgis::as_const( mFrameItems ) )
|
||||
{
|
||||
mLayout->removeLayoutItem( frame );
|
||||
}
|
||||
mLayout->mBlockUndoCommandCount--;
|
||||
mLayout->undoStack()->blockCommands( false );
|
||||
mFrameItems.clear();
|
||||
mResizeMode = bkResizeMode;
|
||||
mBlockUpdates = false;
|
||||
@ -460,6 +462,7 @@ bool QgsLayoutMultiFrame::readXml( const QDomElement &element, const QDomDocumen
|
||||
}
|
||||
|
||||
mBlockUndoCommands = true;
|
||||
mLayout->undoStack()->blockCommands( true );
|
||||
|
||||
readObjectPropertiesFromElement( element, doc, context );
|
||||
|
||||
@ -491,6 +494,7 @@ bool QgsLayoutMultiFrame::readXml( const QDomElement &element, const QDomDocumen
|
||||
bool result = readPropertiesFromElement( element, doc, context );
|
||||
|
||||
mBlockUndoCommands = false;
|
||||
mLayout->undoStack()->blockCommands( false );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -29,12 +29,14 @@ QgsLayoutUndoStack::QgsLayoutUndoStack( QgsLayout *layout )
|
||||
|
||||
void QgsLayoutUndoStack::beginMacro( const QString &commandText )
|
||||
{
|
||||
mUndoStack->beginMacro( commandText );
|
||||
if ( mBlockedCommands == 0 )
|
||||
mUndoStack->beginMacro( commandText );
|
||||
}
|
||||
|
||||
void QgsLayoutUndoStack::endMacro()
|
||||
{
|
||||
mUndoStack->endMacro();
|
||||
if ( mBlockedCommands == 0 )
|
||||
mUndoStack->endMacro();
|
||||
}
|
||||
|
||||
void QgsLayoutUndoStack::beginCommand( QgsLayoutUndoObjectInterface *object, const QString &commandText, int id )
|
||||
@ -54,13 +56,13 @@ void QgsLayoutUndoStack::endCommand()
|
||||
return;
|
||||
|
||||
mActiveCommands.back()->saveAfterState();
|
||||
if ( mActiveCommands.back()->containsChange() ) //protect against empty commands
|
||||
if ( mBlockedCommands == 0 && mActiveCommands.back()->containsChange() ) //protect against empty commands
|
||||
{
|
||||
mUndoStack->push( mActiveCommands.back().release() );
|
||||
mActiveCommands.pop_back();
|
||||
|
||||
mLayout->project()->setDirty( true );
|
||||
}
|
||||
|
||||
mActiveCommands.pop_back();
|
||||
}
|
||||
|
||||
void QgsLayoutUndoStack::cancelCommand()
|
||||
@ -81,6 +83,32 @@ void QgsLayoutUndoStack::notifyUndoRedoOccurred( QgsLayoutItem *item )
|
||||
mUndoRedoOccurredItemUuids.insert( item->uuid() );
|
||||
}
|
||||
|
||||
void QgsLayoutUndoStack::blockCommands( bool blocked )
|
||||
{
|
||||
if ( blocked )
|
||||
{
|
||||
mBlockedCommands++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mBlockedCommands > 0 )
|
||||
mBlockedCommands--;
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsLayoutUndoStack::isBlocked() const
|
||||
{
|
||||
return mBlockedCommands > 0;
|
||||
}
|
||||
|
||||
void QgsLayoutUndoStack::push( QUndoCommand *cmd )
|
||||
{
|
||||
if ( mBlockedCommands > 0 )
|
||||
delete cmd;
|
||||
else
|
||||
mUndoStack->push( cmd );
|
||||
}
|
||||
|
||||
void QgsLayoutUndoStack::indexChanged()
|
||||
{
|
||||
if ( mUndoRedoOccurredItemUuids.empty() )
|
||||
|
@ -107,6 +107,30 @@ class CORE_EXPORT QgsLayoutUndoStack : public QObject
|
||||
*/
|
||||
void notifyUndoRedoOccurred( QgsLayoutItem *item );
|
||||
|
||||
/**
|
||||
* Sets whether undo commands for the layout should be temporarily blocked.
|
||||
*
|
||||
* If \a blocked is true, subsequent undo commands will be blocked until a follow-up
|
||||
* call to blockCommands( false ) is made.
|
||||
*
|
||||
* Note that calls to blockCommands are stacked, so two calls blocking the commands
|
||||
* will take two calls unblocking commands in order to release the block.
|
||||
*
|
||||
* \see isBlocked()
|
||||
*/
|
||||
void blockCommands( bool blocked );
|
||||
|
||||
/**
|
||||
* Returns true if undo commands are currently blocked.
|
||||
* \see blockCommands()
|
||||
*/
|
||||
bool isBlocked() const;
|
||||
|
||||
/**
|
||||
* Manually pushes a \a command to the stack, and takes ownership of the command.
|
||||
*/
|
||||
void push( QUndoCommand *command SIP_TRANSFER );
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
@ -129,6 +153,8 @@ class CORE_EXPORT QgsLayoutUndoStack : public QObject
|
||||
|
||||
QSet< QString > mUndoRedoOccurredItemUuids;
|
||||
|
||||
int mBlockedCommands = 0;
|
||||
|
||||
#ifdef SIP_RUN
|
||||
QgsLayoutUndoStack( const QgsLayoutUndoStack &other );
|
||||
#endif
|
||||
|
@ -616,7 +616,7 @@ void QgsLayoutMouseHandles::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
|
||||
item->attemptMove( itemPos );
|
||||
|
||||
command->saveAfterState();
|
||||
mLayout->undoStack()->stack()->push( command.release() );
|
||||
mLayout->undoStack()->push( command.release() );
|
||||
}
|
||||
mLayout->undoStack()->endMacro();
|
||||
}
|
||||
@ -662,7 +662,7 @@ void QgsLayoutMouseHandles::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
|
||||
item->attemptMove( itemPos, false, true );
|
||||
|
||||
command->saveAfterState();
|
||||
mLayout->undoStack()->stack()->push( command.release() );
|
||||
mLayout->undoStack()->push( command.release() );
|
||||
}
|
||||
mLayout->undoStack()->endMacro();
|
||||
}
|
||||
|
@ -469,6 +469,39 @@ void TestQgsLayout::undoRedoOccurred()
|
||||
items = qvariant_cast< QSet< QString > >( spyOccurred.at( 3 ).at( 0 ) );
|
||||
QCOMPARE( items, QSet< QString >() << item->uuid() << item2->uuid() );
|
||||
|
||||
// blocking undo
|
||||
int before = l.undoStack()->stack()->count();
|
||||
item->setId( "xxx" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 1 );
|
||||
l.undoStack()->blockCommands( true );
|
||||
QVERIFY( l.undoStack()->isBlocked() );
|
||||
item->setId( "yyy" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 1 ); // no new command
|
||||
l.undoStack()->blockCommands( true ); // second stacked command
|
||||
QVERIFY( l.undoStack()->isBlocked() );
|
||||
item->setId( "ZZZ" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 1 ); // no new command
|
||||
l.undoStack()->blockCommands( false ); // one stacked command left
|
||||
QVERIFY( l.undoStack()->isBlocked() );
|
||||
item->setId( "sss" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 1 ); // no new command
|
||||
l.undoStack()->blockCommands( false ); // unblocked
|
||||
QVERIFY( !l.undoStack()->isBlocked() );
|
||||
item->setId( "ttt" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 2 ); // new command
|
||||
l.undoStack()->blockCommands( false ); // don't allow negative stack size
|
||||
QVERIFY( !l.undoStack()->isBlocked() );
|
||||
item->setId( "uuu" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 3 ); // new command
|
||||
l.undoStack()->blockCommands( true ); // should be blocked again
|
||||
QVERIFY( l.undoStack()->isBlocked() );
|
||||
item->setId( "vvv" );
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 3 ); // no new command
|
||||
// blocked macro
|
||||
l.undoStack()->beginMacro( "macro" );
|
||||
item->setId( "lll" );
|
||||
l.undoStack()->endMacro();
|
||||
QCOMPARE( l.undoStack()->stack()->count(), before + 3 ); // no new command
|
||||
}
|
||||
|
||||
void TestQgsLayout::itemsOnPage()
|
||||
|
Loading…
x
Reference in New Issue
Block a user