Skip to content

Commit

Permalink
After a undo/redo action occurs, select the affected items
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 7, 2017
1 parent 48a45b3 commit 72a1f77
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 6 deletions.
16 changes: 15 additions & 1 deletion python/core/layout/qgslayoutundostack.sip
Expand Up @@ -10,7 +10,8 @@



class QgsLayoutUndoStack

class QgsLayoutUndoStack : QObject
{
%Docstring
An undo stack for QgsLayouts.
Expand Down Expand Up @@ -86,6 +87,19 @@ class QgsLayoutUndoStack
:rtype: QUndoStack
%End

void notifyUndoRedoOccurred( QgsLayoutItem *item );
%Docstring
Notifies the stack that an undo or redo action occurred for a specified ``item``.
%End

signals:

void undoRedoOccurredForItems( const QSet< QString > itemUuids );
%Docstring
Emitted when an undo or redo action has occurred, which affected a
set of layout ``itemUuids``.
%End

private:
QgsLayoutUndoStack( const QgsLayoutUndoStack &other );
};
Expand Down
25 changes: 25 additions & 0 deletions src/app/layout/qgslayoutdesignerdialog.cpp
Expand Up @@ -581,6 +581,7 @@ void QgsLayoutDesignerDialog::setCurrentLayout( QgsLayout *layout )
mLayoutToolbar->addAction( mUndoAction );
mLayoutToolbar->addAction( mRedoAction );

connect( mLayout->undoStack(), &QgsLayoutUndoStack::undoRedoOccurredForItems, this, &QgsLayoutDesignerDialog::undoRedoOccurredForItems );
connect( mActionClearGuides, &QAction::triggered, &mLayout->guides(), [ = ]
{
mLayout->guides().clear();
Expand Down Expand Up @@ -620,6 +621,9 @@ void QgsLayoutDesignerDialog::setIconSizes( int size )

void QgsLayoutDesignerDialog::showItemOptions( QgsLayoutItem *item, bool bringPanelToFront )
{
if ( mBlockItemOptions )
return;

if ( !item )
{
delete mItemPropertiesStack->takeMainPanel();
Expand Down Expand Up @@ -1073,6 +1077,27 @@ void QgsLayoutDesignerDialog::dockVisibilityChanged( bool visible )
}
}

void QgsLayoutDesignerDialog::undoRedoOccurredForItems( const QSet<QString> itemUuids )
{
mBlockItemOptions = true;

mLayout->deselectAll();
QgsLayoutItem *focusItem = nullptr;
for ( const QString &uuid : itemUuids )
{
QgsLayoutItem *item = mLayout->itemByUuid( uuid );
if ( !item )
continue;

item->setSelected( true );
focusItem = item;
}
mBlockItemOptions = false;

if ( focusItem )
showItemOptions( focusItem );
}

QgsLayoutView *QgsLayoutDesignerDialog::view()
{
return mView;
Expand Down
3 changes: 3 additions & 0 deletions src/app/layout/qgslayoutdesignerdialog.h
Expand Up @@ -245,6 +245,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
void addPages();
void statusMessageReceived( const QString &message );
void dockVisibilityChanged( bool visible );
void undoRedoOccurredForItems( const QSet< QString > itemUuids );

private:

Expand Down Expand Up @@ -312,6 +313,8 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
};
QMap< QString, PanelStatus > mPanelStatus;

bool mBlockItemOptions = false;

//! Save window state
void saveWindowState();

Expand Down
2 changes: 1 addition & 1 deletion src/core/CMakeLists.txt
Expand Up @@ -742,6 +742,7 @@ SET(QGIS_CORE_MOC_HDRS
layout/qgslayoutmodel.h
layout/qgslayoutpagecollection.h
layout/qgslayoutobject.h
layout/qgslayoutundostack.h

symbology/qgscptcityarchive.h
symbology/qgssvgcache.h
Expand Down Expand Up @@ -1001,7 +1002,6 @@ SET(QGIS_CORE_HDRS
layout/qgslayoutsize.h
layout/qgslayoutsnapper.h
layout/qgslayoutundocommand.h
layout/qgslayoutundostack.h
layout/qgslayoututils.h

metadata/qgslayermetadata.h
Expand Down
2 changes: 1 addition & 1 deletion src/core/layout/qgslayoutitempicture.cpp
Expand Up @@ -682,7 +682,7 @@ QString QgsLayoutItemPicture::picturePath() const
return mSourcePath;
}

bool QgsLayoutItemPicture::writePropertiesToElement( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const
bool QgsLayoutItemPicture::writePropertiesToElement( QDomElement &elem, QDomDocument &, const QgsReadWriteContext &context ) const
{
QString imagePath = mSourcePath;

Expand Down
1 change: 1 addition & 0 deletions src/core/layout/qgslayoutitemundocommand.cpp
Expand Up @@ -72,6 +72,7 @@ void QgsLayoutItemUndoCommand::restoreState( QDomDocument &stateDoc )

item->readXml( stateDoc.documentElement().firstChild().toElement(), stateDoc, QgsReadWriteContext() );
mLayout->project()->setDirty( true );
mLayout->undoStack()->notifyUndoRedoOccurred( item );
}

QgsLayoutItem *QgsLayoutItemUndoCommand::recreateItem( int itemType, QgsLayout *layout )
Expand Down
19 changes: 17 additions & 2 deletions src/core/layout/qgslayoutundostack.cpp
Expand Up @@ -21,10 +21,11 @@
#include <QUndoStack>

QgsLayoutUndoStack::QgsLayoutUndoStack( QgsLayout *layout )
: mLayout( layout )
: QObject()
, mLayout( layout )
, mUndoStack( new QUndoStack( layout ) )
{

connect( mUndoStack.get(), &QUndoStack::indexChanged, this, &QgsLayoutUndoStack::indexChanged );
}

void QgsLayoutUndoStack::beginMacro( const QString &commandText )
Expand Down Expand Up @@ -76,3 +77,17 @@ QUndoStack *QgsLayoutUndoStack::stack()
return mUndoStack.get();

}

void QgsLayoutUndoStack::notifyUndoRedoOccurred( QgsLayoutItem *item )
{
mUndoRedoOccurredItemUuids.insert( item->uuid() );
}

void QgsLayoutUndoStack::indexChanged()
{
if ( mUndoRedoOccurredItemUuids.empty() )
return;

emit undoRedoOccurredForItems( mUndoRedoOccurredItemUuids );
mUndoRedoOccurredItemUuids.clear();
}
25 changes: 24 additions & 1 deletion src/core/layout/qgslayoutundostack.h
Expand Up @@ -21,6 +21,8 @@
#include "qgis.h"
#include "qgis_core.h"
#include "qgslayoutundocommand.h"
#include "qgslayoutitem.h"

#include <memory>

class QgsLayout;
Expand All @@ -31,8 +33,10 @@ class QUndoStack;
* An undo stack for QgsLayouts.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutUndoStack
class CORE_EXPORT QgsLayoutUndoStack : public QObject
{
Q_OBJECT

public:

/**
Expand Down Expand Up @@ -98,6 +102,23 @@ class CORE_EXPORT QgsLayoutUndoStack
*/
QUndoStack *stack();

/**
* Notifies the stack that an undo or redo action occurred for a specified \a item.
*/
void notifyUndoRedoOccurred( QgsLayoutItem *item );

signals:

/**
* Emitted when an undo or redo action has occurred, which affected a
* set of layout \a itemUuids.
*/
void undoRedoOccurredForItems( const QSet< QString > itemUuids );

private slots:

void indexChanged();

private:

QgsLayout *mLayout = nullptr;
Expand All @@ -106,6 +127,8 @@ class CORE_EXPORT QgsLayoutUndoStack

std::vector< std::unique_ptr< QgsAbstractLayoutUndoCommand > > mActiveCommands;

QSet< QString > mUndoRedoOccurredItemUuids;

#ifdef SIP_RUN
QgsLayoutUndoStack( const QgsLayoutUndoStack &other );
#endif
Expand Down
50 changes: 50 additions & 0 deletions tests/src/core/testqgslayout.cpp
Expand Up @@ -41,6 +41,7 @@ class TestQgsLayout: public QObject
void addItem();
void layoutItems();
void layoutItemByUuid();
void undoRedoOccurred();

private:
QString mReport;
Expand Down Expand Up @@ -419,6 +420,55 @@ void TestQgsLayout::layoutItemByUuid()
QCOMPARE( l.itemByUuid( map1->uuid() ), map1 );
}

void TestQgsLayout::undoRedoOccurred()
{
// test emitting undo/redo occurred signal
QgsProject proj;
QgsLayout l( &proj );

QSignalSpy spyOccurred( l.undoStack(), &QgsLayoutUndoStack::undoRedoOccurredForItems );

QgsLayoutItemShape *item = new QgsLayoutItemShape( &l );
l.addLayoutItem( item );

QCOMPARE( spyOccurred.count(), 0 );
//adds a new undo command
item->setId( "test" );
QCOMPARE( spyOccurred.count(), 0 );

QgsLayoutItemShape *item2 = new QgsLayoutItemShape( &l );
l.addLayoutItem( item2 );
item2->setId( "test2" );
QCOMPARE( spyOccurred.count(), 0 );

l.undoStack()->stack()->undo();
QCOMPARE( spyOccurred.count(), 1 );
QSet< QString > items = qvariant_cast< QSet< QString > >( spyOccurred.at( 0 ).at( 0 ) );
QCOMPARE( items, QSet< QString >() << item2->uuid() );

l.undoStack()->stack()->redo();
QCOMPARE( spyOccurred.count(), 2 );
items = qvariant_cast< QSet< QString> >( spyOccurred.at( 1 ).at( 0 ) );
QCOMPARE( items, QSet< QString >() << item2->uuid() );

// macro undo
l.undoStack()->beginMacro( QString() );
item->setId( "new id" );
item2->setId( "new id2" );
l.undoStack()->endMacro();
QCOMPARE( spyOccurred.count(), 2 );

l.undoStack()->stack()->undo();
QCOMPARE( spyOccurred.count(), 3 );
items = qvariant_cast< QSet< QString > >( spyOccurred.at( 2 ).at( 0 ) );
QCOMPARE( items, QSet< QString >() << item->uuid() << item2->uuid() );
l.undoStack()->stack()->redo();
QCOMPARE( spyOccurred.count(), 4 );
items = qvariant_cast< QSet< QString > >( spyOccurred.at( 3 ).at( 0 ) );
QCOMPARE( items, QSet< QString >() << item->uuid() << item2->uuid() );

}


QGSTEST_MAIN( TestQgsLayout )
#include "testqgslayout.moc"

0 comments on commit 72a1f77

Please sign in to comment.