Skip to content

Commit

Permalink
Update undo/redo widget and vector layer rollback
Browse files Browse the repository at this point in the history
- Allows for any number of undo/redo commands with only one refresh
- Significantly decreases time needed to cancel or redo many edits
- Disable undo/redo dock's widgets and toolbar actions when layer not in editing mode
  • Loading branch information
dakcarto committed Dec 15, 2012
1 parent 051fe31 commit 9069f3b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 22 deletions.
8 changes: 7 additions & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -5238,7 +5238,8 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
res = false;
}

vlayer->triggerRepaint();
// canvas refreshes handled in QgsUndoWidget::indexChanged
//vlayer->triggerRepaint();
break;

default:
Expand Down Expand Up @@ -7215,11 +7216,16 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionToggleEditing->setEnabled( canChangeAttributes && !vlayer->isReadOnly() );
mActionToggleEditing->setChecked( vlayer->isEditable() );
mActionSaveEdits->setEnabled( canChangeAttributes && vlayer->isEditable() );
mUndoWidget->dockContents()->setEnabled( vlayer->isEditable() );
updateUndoActions();
}
else
{
mActionToggleEditing->setEnabled( false );
mActionSaveEdits->setEnabled( false );
mUndoWidget->dockContents()->setEnabled( false );
mActionUndo->setEnabled( false );
mActionRedo->setEnabled( false );
}

if ( dprovider->capabilities() & QgsVectorDataProvider::AddFeatures )
Expand Down
41 changes: 27 additions & 14 deletions src/app/qgsundowidget.cpp
Expand Up @@ -37,6 +37,8 @@ QgsUndoWidget::QgsUndoWidget( QWidget * parent, QgsMapCanvas * mapCanvas )
mMapCanvas = mapCanvas;
mUndoView = NULL;
mUndoStack = NULL;
mPreviousIndex = 0;
mPreviousCount = 0;
}


Expand Down Expand Up @@ -80,13 +82,25 @@ void QgsUndoWidget::redoChanged( bool value )
emit undoStackChanged();
}


void QgsUndoWidget::indexChanged( int value )
void QgsUndoWidget::indexChanged( int curIndx )
{
Q_UNUSED( value );
//redoButton->setDisabled( !value );
//canvas refresh
mMapCanvas->refresh();
// this is called twice when a non-current command is clicked in QUndoView
// first call has offset, second call will have offset of 0
int curCount = 0;
if ( mUndoStack )
{
curCount = mUndoStack->count();
}
bool cmdAdded = ( curIndx == curCount && mPreviousCount == ( curCount - 1 ) );
int offset = qAbs( mPreviousIndex - curIndx );
// avoid refresh when only a command was added to stack (i.e. no undo/redo action)
if ( offset > 1 || ( offset == 1 && !cmdAdded ) )
{
mMapCanvas->refresh();
}

mPreviousIndex = curIndx;
mPreviousCount = curCount;
}

void QgsUndoWidget::undo( )
Expand All @@ -111,20 +125,19 @@ void QgsUndoWidget::setUndoStack( QUndoStack* undoStack )
}

mUndoStack = undoStack;
mPreviousIndex = mUndoStack->index();
mPreviousCount = mUndoStack->count();

mUndoView = new QUndoView( dockWidgetContents );
mUndoView->setStack( undoStack );
mUndoView->setObjectName( "undoView" );
gridLayout->addWidget( mUndoView, 0, 0, 1, 2 );
setWidget( dockWidgetContents );
connect( mUndoStack, SIGNAL( canUndoChanged( bool ) ), this, SLOT( undoChanged( bool ) ) );
connect( mUndoStack, SIGNAL( canRedoChanged( bool ) ), this, SLOT( redoChanged( bool ) ) );

// indexChanged() triggers a refresh. but it gets triggered also when a new action
// is done, resulting in two refreshes. For now let's trigger the refresh from
// vector layer: it causes potentially multiple refreshes when moving more commands
// back, but avoids double refresh in common case when adding commands to the stack
//connect(mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(indexChanged(int)));
connect( mUndoStack, SIGNAL( canUndoChanged( bool ) ), this, SLOT( undoChanged( bool ) ) );
connect( mUndoStack, SIGNAL( canRedoChanged( bool ) ), this, SLOT( redoChanged( bool ) ) );

// gets triggered also when a new command is added to stack, and twice when clicking a command in QUndoView
connect( mUndoStack, SIGNAL( indexChanged( int ) ), this, SLOT( indexChanged( int ) ) );

undoButton->setDisabled( !mUndoStack->canUndo() );
redoButton->setDisabled( !mUndoStack->canRedo() );
Expand Down
10 changes: 9 additions & 1 deletion src/app/qgsundowidget.h
Expand Up @@ -58,6 +58,12 @@ class QgsUndoWidget : public QDockWidget
*/
void destroyStack();

/**
* Access to dock's contents
* @note added in 1.9
*/
QWidget* dockContents() { return dockWidgetContents; }

public slots:
/**
* Changes undo stack which is displayed by undo view
Expand All @@ -77,7 +83,7 @@ class QgsUndoWidget : public QDockWidget
/**
* Slot to handle index changed signal
*/
void indexChanged( int value );
void indexChanged( int curIndx );

/**
* Undo operation called from button push
Expand All @@ -97,6 +103,8 @@ class QgsUndoWidget : public QDockWidget
QUndoStack * mUndoStack;
QgsMapCanvas* mMapCanvas;

int mPreviousIndex;
int mPreviousCount;
};


Expand Down
13 changes: 7 additions & 6 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -4256,10 +4256,9 @@ bool QgsVectorLayer::rollBack()

if ( isModified() )
{
while ( undoStack()->canUndo() )
{
undoStack()->undo();
}
// new undo stack roll back method
// old method of calling every undo could cause many canvas refreshes
undoStack()->setIndex( 0 );

Q_ASSERT( mAddedAttributeIds.isEmpty() );
Q_ASSERT( mDeletedAttributeIds.isEmpty() );
Expand Down Expand Up @@ -5240,7 +5239,8 @@ void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
setModified( true );

// it's not ideal to trigger refresh from here
triggerRepaint();
// canvas refreshes handled in QgsUndoWidget::indexChanged
//triggerRepaint();
}

void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
Expand Down Expand Up @@ -5363,7 +5363,8 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
setModified( true );

// it's not ideal to trigger refresh from here
triggerRepaint();
// canvas refreshes handled in QgsUndoWidget::indexChanged
//triggerRepaint();
}

void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked )
Expand Down

0 comments on commit 9069f3b

Please sign in to comment.