Skip to content

Commit 0da0e7d

Browse files
author
wonder
committedJun 14, 2009
[FEATURE] Added undo/redo functionality for vector layer editing.
There are undo/redo actions in Edit menu, in Advanced digitizing toolbar and there is a new dock widget displaying undo stack of active layer. git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@10921 c8812cc2-4d05-0410-92ff-de0c093fc19c

23 files changed

+383
-13
lines changed
 

‎images/themes/default/mActionRedo.png

511 Bytes
Loading

‎images/themes/default/mActionUndo.png

502 Bytes
Loading

‎src/app/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ SET(QGIS_APP_SRCS
6060
qgsshortcutsmanager.cpp
6161
qgssinglesymboldialog.cpp
6262
qgssnappingdialog.cpp
63+
qgsundowidget.cpp
6364
qgsuniquevaluedialog.cpp
6465
qgsvectorlayerproperties.cpp
6566

@@ -148,6 +149,7 @@ SET (QGIS_APP_MOC_HDRS
148149
qgsvectorlayerproperties.h
149150
qgsdbtablemodel.h
150151
qgsspatialitetablemodel.h
152+
qgsundowidget.h
151153

152154
composer/qgscomposer.h
153155
composer/qgscomposeritemwidget.h

‎src/app/attributetable/qgsattributetablememorymodel.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ bool QgsAttributeTableMemoryModel::setData( const QModelIndex &index, const QVar
120120
// QgsDebugMsg(mFeatureMap[rowToId(index.row())].id());
121121
mFeatureMap[rowToId( index.row() )].changeAttribute( mAttributes[ index.column()], value );
122122
// propagate back to the layer
123+
mLayer->beginEditCommand( tr("Attribute changed") );
123124
mLayer->changeAttributeValue( rowToId( index.row() ), mAttributes[ index.column()], value, true );
125+
mLayer->endEditCommand();
124126
}
125127

126128
if ( !mLayer->isModified() )

‎src/app/attributetable/qgsattributetablemodel.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,9 @@ bool QgsAttributeTableModel::setData( const QModelIndex &index, const QVariant &
393393
{
394394
mLastRowId = rowToId( index.row() );
395395
mLastRow = ( QgsAttributeMap * )( &( mFeat.attributeMap() ) );
396-
396+
mLayer->beginEditCommand( tr("Attribute changed") );
397397
mLayer->changeAttributeValue( rowToId( index.row() ), mAttributes[ index.column()], value, true );
398+
mLayer->endEditCommand();
398399
}
399400

400401
if ( !mLayer->isModified() )

‎src/app/qgisapp.cpp

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
#include "qgsrenderer.h"
133133
#include "qgsserversourceselect.h"
134134
#include "qgsshortcutsmanager.h"
135+
#include "qgsundowidget.h"
135136
#include "qgsvectordataprovider.h"
136137
#include "qgsvectorlayer.h"
137138
#include "ogr/qgsopenvectorlayerdialog.h"
@@ -363,6 +364,11 @@ QgisApp::QgisApp( QSplashScreen *splash, QWidget * parent, Qt::WFlags fl )
363364
mInternalClipboard = new QgsClipboard; // create clipboard
364365
mQgisInterface = new QgisAppInterface( this ); // create the interfce
365366

367+
// create undo widget
368+
mUndoWidget = new QgsUndoWidget( NULL, mMapCanvas);
369+
addDockWidget(Qt::LeftDockWidgetArea, mUndoWidget);
370+
mUndoWidget->hide();
371+
366372
// set application's icon
367373
setWindowIcon( QPixmap( qgis_xpm ) );
368374

@@ -583,11 +589,6 @@ void QgisApp::createActions()
583589
// Edit Menu Items
584590

585591
#if 0
586-
mActionUndo = new QAction( tr( "&Undo" ), this );
587-
shortcuts->registerAction( mActionUndo, tr( "Ctrl+Z" ) );
588-
mActionUndo->setStatusTip( tr( "Undo the last operation" ) );
589-
connect( mActionUndo, SIGNAL( triggered ), this, SLOT( undo() ) );
590-
591592
mActionCut = new QAction( tr( "Cu&t" ), this );
592593
shortcuts->registerAction( mActionCut, tr( "Ctrl+X" ) );
593594
mActionCut->setStatusTip( tr( "Cut the current selection's contents to the clipboard" ) );
@@ -604,6 +605,18 @@ void QgisApp::createActions()
604605
connect( mActionPaste, SIGNAL( triggered ), this, SLOT( paste() ) );
605606
#endif
606607

608+
mActionUndo = new QAction( getThemeIcon( "mActionUndo.png"), tr( "&Undo" ), this );
609+
shortcuts->registerAction( mActionUndo, tr( "Ctrl+Z" ) );
610+
mActionUndo->setStatusTip( tr( "Undo the last operation" ) );
611+
mActionUndo->setEnabled( false );
612+
// action connected to mUndoWidget::undo slot in setupConnections()
613+
614+
mActionRedo = new QAction( getThemeIcon( "mActionRedo.png"), tr( "&Redo" ), this );
615+
shortcuts->registerAction( mActionRedo, tr( "Ctrl+Shift+Z" ) );
616+
mActionRedo->setStatusTip( tr( "Redo the last operation" ) );
617+
mActionRedo->setEnabled( false );
618+
// action connected to mUndoWidget::redo slot in setupConnections()
619+
607620
mActionCutFeatures = new QAction( getThemeIcon( "mActionEditCut.png" ), tr( "Cut Features" ), this );
608621
shortcuts->registerAction( mActionCutFeatures, tr( "Ctrl+X" ) );
609622
mActionCutFeatures->setStatusTip( tr( "Cut selected features" ) );
@@ -1132,11 +1145,14 @@ void QgisApp::createMenus()
11321145
mEditMenu = menuBar()->addMenu( tr( "&Edit" ) );
11331146

11341147
#if 0
1135-
mEditMenu->addAction( mActionUndo );
11361148
mEditMenu->addAction( mActionCut );
11371149
mEditMenu->addAction( mActionCopy );
11381150
mEditMenu->addAction( mActionPaste );
11391151
#endif
1152+
mEditMenu->addAction( mActionUndo );
1153+
mEditMenu->addAction( mActionRedo );
1154+
mActionEditSeparator0 = mEditMenu->addSeparator();
1155+
11401156
mEditMenu->addAction( mActionCutFeatures );
11411157
mEditMenu->addAction( mActionCopyFeatures );
11421158
mEditMenu->addAction( mActionPasteFeatures );
@@ -1360,6 +1376,8 @@ void QgisApp::createToolBars()
13601376
mAdvancedDigitizeToolBar = addToolBar( tr( "Advanced Digitizing" ) );
13611377
mAdvancedDigitizeToolBar->setIconSize( myIconSize );
13621378
mAdvancedDigitizeToolBar->setObjectName( "Advanced Digitizing" );
1379+
mAdvancedDigitizeToolBar->addAction( mActionUndo );
1380+
mAdvancedDigitizeToolBar->addAction( mActionRedo );
13631381
mAdvancedDigitizeToolBar->addAction( mActionSimplifyFeature );
13641382
mAdvancedDigitizeToolBar->addAction( mActionAddRing );
13651383
mAdvancedDigitizeToolBar->addAction( mActionAddIsland );
@@ -1638,6 +1656,8 @@ void QgisApp::setupConnections()
16381656
mMapLegend, SLOT( addLayer( QgsMapLayer * ) ) );
16391657
connect( mMapLegend, SIGNAL( currentLayerChanged( QgsMapLayer* ) ),
16401658
this, SLOT( activateDeactivateLayerRelatedActions( QgsMapLayer* ) ) );
1659+
connect( mMapLegend, SIGNAL( currentLayerChanged( QgsMapLayer* ) ),
1660+
mUndoWidget, SLOT( layerChanged( QgsMapLayer* ) ) );
16411661

16421662

16431663
//signal when mouse moved over window (coords display in status bar)
@@ -1664,7 +1684,12 @@ void QgisApp::setupConnections()
16641684

16651685
connect( QgsProject::instance(), SIGNAL( layerLoaded( int, int ) ), this, SLOT( showProgress( int, int ) ) );
16661686

1687+
// setup undo/redo actions
1688+
connect( mActionUndo, SIGNAL( triggered() ), mUndoWidget, SLOT( undo() ) );
1689+
connect( mActionRedo, SIGNAL( triggered() ), mUndoWidget, SLOT( redo() ) );
1690+
connect( mUndoWidget, SIGNAL( undoStackChanged() ), this, SLOT(updateUndoActions()) );
16671691
}
1692+
16681693
void QgisApp::createCanvas()
16691694
{
16701695
// "theMapCanvas" used to find this canonical instance later
@@ -4083,13 +4108,14 @@ void QgisApp::deleteSelected()
40834108
return;
40844109
}
40854110

4086-
4111+
vlayer->beginEditCommand( tr("Features deleted") );
40874112
if ( !vlayer->deleteSelectedFeatures() )
40884113
{
40894114
QMessageBox::information( this, tr( "Problem deleting features" ),
40904115
tr( "A problem occured during deletion of features" ) );
40914116
}
40924117

4118+
vlayer->endEditCommand();
40934119
// notify the project we've made a change
40944120
QgsProject::instance()->dirty( true );
40954121
}
@@ -4228,6 +4254,8 @@ void QgisApp::mergeSelectedFeatures()
42284254
}
42294255
}
42304256

4257+
vl->beginEditCommand( tr("Merged features") );
4258+
42314259
//create new feature
42324260
QgsFeature newFeature;
42334261
newFeature.setGeometry(unionGeom);
@@ -4241,6 +4269,8 @@ void QgisApp::mergeSelectedFeatures()
42414269

42424270
vl->addFeature(newFeature, false);
42434271

4272+
vl->endEditCommand();;
4273+
42444274
if(mapCanvas())
42454275
{
42464276
mapCanvas()->refresh();
@@ -4361,7 +4391,9 @@ void QgisApp::editCut( QgsMapLayer * layerContainingSelection )
43614391
{
43624392
QgsFeatureList features = selectionVectorLayer->selectedFeatures();
43634393
clipboard()->replaceWithCopyOf( selectionVectorLayer->dataProvider()->fields(), features );
4394+
selectionVectorLayer->beginEditCommand( tr("Features cut") );
43644395
selectionVectorLayer->deleteSelectedFeatures();
4396+
selectionVectorLayer->endEditCommand();
43654397
}
43664398
}
43674399
}
@@ -4410,7 +4442,9 @@ void QgisApp::editPaste( QgsMapLayer * destinationLayer )
44104442

44114443
if ( pasteVectorLayer != 0 )
44124444
{
4445+
pasteVectorLayer->beginEditCommand( tr("Features pasted") );
44134446
pasteVectorLayer->addFeatures( clipboard()->copyOf() );
4447+
pasteVectorLayer->endEditCommand();
44144448
mMapCanvas->refresh();
44154449
}
44164450
}
@@ -5420,6 +5454,8 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
54205454
mActionLayerProperties->setEnabled( false );
54215455
mActionAddToOverview->setEnabled( false );
54225456
mActionCopyFeatures->setEnabled( false );
5457+
mActionUndo->setEnabled( false );
5458+
mActionRedo->setEnabled( false );
54235459
return;
54245460
}
54255461

@@ -6139,3 +6175,20 @@ QPixmap QgisApp::getThemePixmap( const QString theName )
61396175
return QPixmap( myDefaultPath );
61406176
}
61416177
}
6178+
6179+
void QgisApp::updateUndoActions()
6180+
{
6181+
bool canUndo = false, canRedo = false;
6182+
QgsMapLayer* layer = this->activeLayer();
6183+
if (layer)
6184+
{
6185+
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>( layer );
6186+
if ( vlayer && vlayer->isEditable() )
6187+
{
6188+
canUndo = vlayer->undoStack()->canUndo();
6189+
canRedo = vlayer->undoStack()->canRedo();
6190+
}
6191+
}
6192+
mActionUndo->setEnabled( canUndo );
6193+
mActionRedo->setEnabled( canRedo );
6194+
}

‎src/app/qgisapp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class QgsPythonDialog;
5656
class QgsPythonUtils;
5757
class QgsRasterLayer;
5858
class QgsRectangle;
59+
class QgsUndoWidget;
5960
class QgsVectorLayer;
6061

6162
#include <QMainWindow>
@@ -341,6 +342,8 @@ class QgisApp : public QMainWindow
341342
//! Zoom to selected features
342343
void zoomToSelected();
343344

345+
void updateUndoActions();
346+
344347
//! cuts selected features on the active layer to the clipboard
345348
/**
346349
\param layerContainingSelection The layer that the selection will be taken from
@@ -710,6 +713,9 @@ class QgisApp : public QMainWindow
710713
QAction *mActionFileSeparator4;
711714
QAction *mActionExit;
712715

716+
QAction *mActionUndo;
717+
QAction *mActionRedo;
718+
QAction *mActionEditSeparator0;
713719
QAction *mActionCutFeatures;
714720
QAction *mActionCopyFeatures;
715721
QAction *mActionPasteFeatures;
@@ -958,6 +964,8 @@ class QgisApp : public QMainWindow
958964

959965
static QgisApp *smInstance;
960966

967+
QgsUndoWidget* mUndoWidget;
968+
961969
};
962970

963971
#endif

‎src/app/qgsmaptooladdfeature.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )
459459
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", false ).toBool();
460460
if ( isDisabledAttributeValuesDlg )
461461
{
462+
vlayer->beginEditCommand( tr("Feature added") );
462463
if ( vlayer->addFeature( *f ) )
463464
{
464465
//add points to other features to keep topology up-to-date
@@ -468,12 +469,14 @@ void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )
468469
vlayer->addTopologicalPoints( f->geometry() );
469470
}
470471
}
472+
vlayer->endEditCommand();
471473
}
472474
else
473475
{
474476
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
475477
if ( mypDialog->exec() )
476478
{
479+
vlayer->beginEditCommand( tr("Feature added") );
477480
if ( vlayer->addFeature( *f ) )
478481
{
479482
//add points to other features to keep topology up-to-date
@@ -483,6 +486,7 @@ void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )
483486
vlayer->addTopologicalPoints( f->geometry() );
484487
}
485488
}
489+
vlayer->endEditCommand();
486490
}
487491
delete mypDialog;
488492
}

‎src/app/qgsmaptooladdisland.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ void QgsMapToolAddIsland::canvasReleaseEvent( QMouseEvent * e )
101101

102102
//close polygon
103103
mCaptureList.push_back( *mCaptureList.begin() );
104-
104+
vlayer->beginEditCommand( tr("Island added") );
105105
int errorCode = vlayer->addIsland( mCaptureList );
106+
vlayer->endEditCommand();
106107
QString errorMessage;
107108

108109
if ( errorCode != 0 )

‎src/app/qgsmaptooladdring.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ void QgsMapToolAddRing::canvasReleaseEvent( QMouseEvent * e )
8181
//close polygon
8282
mCaptureList.push_back( *mCaptureList.begin() );
8383

84+
vlayer->beginEditCommand( tr("Ring added") );
8485
int addRingReturnCode = vlayer->addRing( mCaptureList );
86+
vlayer->endEditCommand();
8587
if ( addRingReturnCode != 0 )
8688
{
8789
QString errorMessage;

‎src/app/qgsmaptooladdvertex.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,12 @@ void QgsMapToolAddVertex::canvasReleaseEvent( QMouseEvent * e )
122122

123123
//and change the feature points
124124
QList<QgsSnappingResult>::iterator sr_it = mRecentSnappingResults.begin();
125+
vlayer->beginEditCommand( tr("Added vertex") );
125126
for ( ; sr_it != mRecentSnappingResults.end(); ++sr_it )
126127
{
127128
vlayer->insertVertex( snappedPointLayerCoord.x(), snappedPointLayerCoord.y(), sr_it->snappedAtGeometry, sr_it->afterVertexNr );
128129
}
130+
vlayer->endEditCommand();
129131
}
130132
}
131133

‎src/app/qgsmaptooldeletepart.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ void QgsMapToolDeletePart::deletePart( int fId, int beforeVertexNr, QgsVectorLay
106106

107107
if ( g->deletePart( partNum ) )
108108
{
109+
vlayer->beginEditCommand( tr("Part of multipart feature deleted") );
109110
vlayer->changeGeometry( fId, g );
111+
vlayer->endEditCommand();
110112
mCanvas->refresh();
111113
}
112114
else

‎src/app/qgsmaptooldeletering.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ void QgsMapToolDeleteRing::deleteRing( int fId, int beforeVertexNr, QgsVectorLay
111111

112112
if ( g->deleteRing( ringNum, partNum ) )
113113
{
114+
vlayer->beginEditCommand( tr("Ring deleted") );
114115
vlayer->changeGeometry( fId, g );
116+
vlayer->endEditCommand();
115117
mCanvas->refresh();
116118
}
117119

‎src/app/qgsmaptooldeletevertex.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@ void QgsMapToolDeleteVertex::canvasReleaseEvent( QMouseEvent * e )
7979
if ( vlayer && mRecentSnappingResults.size() > 0 )
8080
{
8181
QList<QgsSnappingResult>::iterator sr_it = mRecentSnappingResults.begin();
82+
vlayer->beginEditCommand( tr("Vertex deleted") );
8283
for ( ; sr_it != mRecentSnappingResults.end(); ++sr_it )
8384
{
8485
vlayer->deleteVertex( sr_it->snappedAtGeometry, sr_it->snappedVertexNr );
8586
}
87+
vlayer->endEditCommand();
8688
}
8789

8890
mCanvas->refresh();

‎src/app/qgsmaptoolidentify.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,17 +489,25 @@ void QgsMapToolIdentify::editFeature( QgsFeature &f )
489489

490490
QgsAttributeMap src = f.attributeMap();
491491

492+
layer->beginEditCommand( tr("Attribute changed") );
492493
QgsAttributeDialog *ad = new QgsAttributeDialog( layer, &f );
493494
if ( ad->exec() )
494495
{
495496
const QgsAttributeMap &dst = f.attributeMap();
496-
497497
for ( QgsAttributeMap::const_iterator it = dst.begin(); it != dst.end(); it++ )
498498
{
499499
if ( !src.contains( it.key() ) || it.value() != src[it.key()] )
500+
{
500501
layer->changeAttributeValue( f.id(), it.key(), it.value() );
502+
}
501503
}
504+
layer->endEditCommand();
502505
}
506+
else
507+
{
508+
layer->destroyEditCommand();
509+
}
510+
503511
delete ad;
504512
mCanvas->refresh();
505513
}

‎src/app/qgsmaptoolmovefeature.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,12 @@ void QgsMapToolMoveFeature::canvasReleaseEvent( QMouseEvent * e )
137137

138138
double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
139139
double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();
140-
140+
vlayer->beginEditCommand( tr("Feature moved") );
141141
vlayer->translateFeature( mMovedFeature, dx, dy );
142-
143142
delete mRubberBand;
144143
mRubberBand = 0;
145144
mCanvas->refresh();
145+
vlayer->endEditCommand();
146146
}
147147

148148
//! called when map tool is being deactivated

‎src/app/qgsmaptoolmovevertex.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ void QgsMapToolMoveVertex::canvasReleaseEvent( QMouseEvent * e )
164164

165165
snappedPointLayerCoord = toLayerCoordinates( vlayer, snappedPointMapCoord );
166166

167+
vlayer->beginEditCommand( tr("Vertex moved") );
167168
//and change the feature points
168169
QList<QgsSnappingResult>::iterator sr_it = mRecentSnappingResults.begin();
169170
for ( ; sr_it != mRecentSnappingResults.end(); ++sr_it )
@@ -173,6 +174,7 @@ void QgsMapToolMoveVertex::canvasReleaseEvent( QMouseEvent * e )
173174
//error
174175
}
175176
}
177+
vlayer->endEditCommand();
176178

177179
}
178180

‎src/app/qgsmaptoolnodetool.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,9 @@ void QgsMapToolNodeTool::canvasDoubleClickEvent( QMouseEvent * e )
438438
{
439439
QgsPoint coords = mCanvas->getCoordinateTransform()->toMapPoint( e->pos().x(), e->pos().y() );
440440
//add vertex
441+
vlayer->beginEditCommand( tr("Inserted vertex") );
441442
vlayer->insertVertex(coords.x(), coords.y(), mSelectionFeature->featureId(), snapResults.first().afterVertexNr );
443+
vlayer->endEditCommand();
442444

443445
mSelectionFeature->updateFromFeature();
444446
}
@@ -536,24 +538,33 @@ void SelectionFeature::setSelectedFeature( int featureId, QgsVectorLayer* vlaye
536538

537539
void SelectionFeature::deleteSelectedVertexes()
538540
{
541+
mVlayer->beginEditCommand( QObject::tr("Deleted vertices") );
542+
int count = 0;
539543
for (int i = mVertexMap.size() -1; i > -1 ; i--)
540544
{
541545
if (mVertexMap[i].selected)
542546
{
543547
mVlayer->deleteVertex(mFeatureId, i);
548+
count++;
544549

545550
if (mVertexMap[i].equals != -1 && !mVertexMap[mVertexMap[i].equals].selected)
546551
{
547552
//for polygon delete both
548553
}
549554
}
550555
}
556+
if (count)
557+
mVlayer->endEditCommand();
558+
else
559+
mVlayer->destroyEditCommand(); // no changes...
560+
551561
updateFromFeature();
552562
}
553563

554564

555565
void SelectionFeature::moveSelectedVertexes( double changeX, double changeY )
556566
{
567+
mVlayer->beginEditCommand( QObject::tr("Moved vertices") );
557568
for (int i = mVertexMap.size() -1; i > -1 ; i--)
558569
{
559570
if (mVertexMap[i].selected)
@@ -570,6 +581,7 @@ void SelectionFeature::moveSelectedVertexes( double changeX, double changeY )
570581
}
571582
}
572583
}
584+
mVlayer->endEditCommand();
573585
updateFeature();
574586
}
575587

‎src/app/qgsmaptoolsimplify.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ void QgsMapToolSimplify::storeSimplified()
111111
QgsSimplifyFeature::simplifyPolygon( mSelectedFeature, mTolerance );
112112
}
113113

114+
vlayer->beginEditCommand( tr("Geometry simplified") );
114115
vlayer->changeGeometry( mSelectedFeature.id(), mSelectedFeature.geometry() );
116+
vlayer->endEditCommand();
115117

116118
mCanvas->refresh();
117119
}

‎src/app/qgsmaptoolsplitfeatures.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ void QgsMapToolSplitFeatures::canvasReleaseEvent( QMouseEvent * e )
7979

8080
//bring up dialog if a split was not possible (polygon) or only done once (line)
8181
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
82+
vlayer->beginEditCommand( tr("Features split") );
8283
int returnCode = vlayer->splitFeatures( mCaptureList, topologicalEditing );
84+
vlayer->endEditCommand();
8385
if ( returnCode == 4 )
8486
{
8587
QMessageBox::warning( 0, tr( "No feature split done" ), tr( "If there are selected features, the split tool only applies to the selected ones. If you like to split all features under the split line, clear the selection" ) );

‎src/app/qgsundowidget.cpp

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#include "qgsundowidget.h"
2+
3+
#include "qgsmaplayer.h"
4+
#include "qgsmapcanvas.h"
5+
6+
#include "qgisapp.h"
7+
8+
QgsUndoWidget::QgsUndoWidget( QWidget * parent, QgsMapCanvas * mapCanvas )
9+
: QDockWidget( parent )
10+
{
11+
setupUi(this);
12+
setWidget(dockWidgetContents);
13+
connect( this->undoButton, SIGNAL( clicked() ),
14+
this, SLOT( undo( ) ) );
15+
16+
connect( this->redoButton, SIGNAL( clicked() ),
17+
this, SLOT( redo( ) ) );
18+
undoButton->setDisabled( true );
19+
redoButton->setDisabled( true );
20+
mMapCanvas = mapCanvas;
21+
mUndoView = NULL;
22+
mUndoStack = NULL;
23+
}
24+
25+
26+
void QgsUndoWidget::layerChanged( QgsMapLayer * layer)
27+
{
28+
if (layer != NULL)
29+
{
30+
setUndoStack( layer->undoStack() );
31+
}
32+
else
33+
{
34+
destroyStack();
35+
}
36+
emit undoStackChanged();
37+
}
38+
39+
40+
void QgsUndoWidget::destroyStack()
41+
{
42+
if (mUndoStack != NULL)
43+
{
44+
mUndoStack->clear();
45+
mUndoStack = NULL;
46+
}
47+
if (mUndoView != NULL)
48+
{
49+
mUndoView->close();
50+
mUndoView = NULL;
51+
}
52+
}
53+
54+
void QgsUndoWidget::undoChanged(bool value)
55+
{
56+
undoButton->setDisabled( !value );
57+
emit undoStackChanged();
58+
}
59+
60+
void QgsUndoWidget::redoChanged(bool value)
61+
{
62+
redoButton->setDisabled( !value );
63+
emit undoStackChanged();
64+
}
65+
66+
67+
void QgsUndoWidget::indexChanged(int value)
68+
{
69+
//redoButton->setDisabled( !value );
70+
//canvas refresh
71+
mMapCanvas->refresh();
72+
}
73+
74+
void QgsUndoWidget::undo( )
75+
{
76+
if (mUndoStack)
77+
mUndoStack->undo();
78+
}
79+
80+
void QgsUndoWidget::redo()
81+
{
82+
if (mUndoStack)
83+
mUndoStack->redo();
84+
}
85+
86+
void QgsUndoWidget::setUndoStack(QUndoStack* undoStack)
87+
{
88+
if (mUndoView != NULL)
89+
{
90+
mUndoView->close();
91+
delete mUndoView;
92+
mUndoView = NULL;
93+
}
94+
95+
mUndoStack = undoStack;
96+
97+
mUndoView = new QUndoView(dockWidgetContents);
98+
mUndoView->setStack(undoStack);
99+
mUndoView->setObjectName("undoView");
100+
gridLayout->addWidget(mUndoView, 0, 0, 1, 2);
101+
setWidget(dockWidgetContents);
102+
connect(this->mUndoStack, SIGNAL(canUndoChanged(bool)), this, SLOT(undoChanged(bool)));
103+
connect(this->mUndoStack, SIGNAL(canRedoChanged(bool)), this, SLOT(redoChanged(bool)));
104+
connect(this->mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(indexChanged(int)));
105+
106+
this->undoButton->setDisabled( !mUndoStack->canUndo() );
107+
this->redoButton->setDisabled( !mUndoStack->canRedo() );
108+
}
109+
110+
111+
112+
void QgsUndoWidget::setupUi(QDockWidget *UndoWidget)
113+
{
114+
if (UndoWidget->objectName().isEmpty())
115+
UndoWidget->setObjectName(QString::fromUtf8("UndoWidget"));
116+
UndoWidget->resize(350, 223);
117+
UndoWidget->setMinimumSize(QSize(346, 220));
118+
dockWidgetContents = new QWidget(UndoWidget);
119+
dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents"));
120+
gridLayout = new QGridLayout(dockWidgetContents);
121+
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
122+
gridLayout->setContentsMargins(0, 0, 0, 0);
123+
spacerItem = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
124+
125+
gridLayout->addItem(spacerItem, 0, 0, 1, 1);
126+
127+
undoButton = new QPushButton(dockWidgetContents);
128+
undoButton->setObjectName(QString::fromUtf8("undoButton"));
129+
undoButton->setIcon( QgisApp::instance()->getThemeIcon("mActionUndo.png") );
130+
undoButton->setIconSize(QSize(24, 24));
131+
132+
gridLayout->addWidget(undoButton, 1, 0, 1, 1);
133+
134+
redoButton = new QPushButton(dockWidgetContents);
135+
redoButton->setObjectName(QString::fromUtf8("redoButton"));
136+
redoButton->setIcon( QgisApp::instance()->getThemeIcon("mActionRedo.png") );
137+
redoButton->setIconSize(QSize(24, 24));
138+
139+
gridLayout->addWidget(redoButton, 1, 1, 1, 1);
140+
141+
spacerItem1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
142+
143+
gridLayout->addItem(spacerItem1, 0, 1, 1, 1);
144+
145+
UndoWidget->setWidget(dockWidgetContents);
146+
147+
retranslateUi(UndoWidget);
148+
149+
QMetaObject::connectSlotsByName(UndoWidget);
150+
} // setupUi
151+
152+
void QgsUndoWidget::retranslateUi(QDockWidget *UndoWidget)
153+
{
154+
UndoWidget->setWindowTitle(QApplication::translate("UndoWidget", "Undo/Redo", 0, QApplication::UnicodeUTF8));
155+
undoButton->setText(QApplication::translate("UndoWidget", "Undo", 0, QApplication::UnicodeUTF8));
156+
redoButton->setText(QApplication::translate("UndoWidget", "Redo", 0, QApplication::UnicodeUTF8));
157+
Q_UNUSED(UndoWidget);
158+
}
159+

‎src/app/qgsundowidget.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#ifndef QGSUNDOWIDGET_H
2+
#define QGSUNDOWIDGET_H
3+
4+
#include <QtCore/QVariant>
5+
#include <QtGui/QAction>
6+
#include <QtGui/QApplication>
7+
#include <QtGui/QButtonGroup>
8+
#include <QtGui/QDockWidget>
9+
#include <QtGui/QGridLayout>
10+
#include <QtGui/QPushButton>
11+
#include <QtGui/QSpacerItem>
12+
#include <QtGui/QWidget>
13+
#include <QUndoView>
14+
#include <QUndoStack>
15+
16+
class QgsMapCanvas;
17+
class QgsMapLayer;
18+
19+
/**
20+
* Class that handles undo display fo undo commands
21+
*/
22+
class QgsUndoWidget : public QDockWidget
23+
{
24+
Q_OBJECT
25+
public:
26+
QWidget *dockWidgetContents;
27+
QGridLayout *gridLayout;
28+
QSpacerItem *spacerItem;
29+
QPushButton *undoButton;
30+
QPushButton *redoButton;
31+
QSpacerItem *spacerItem1;
32+
33+
QgsUndoWidget(QWidget * parent, QgsMapCanvas* mapCanvas);
34+
void setupUi(QDockWidget *UndoWidget);
35+
void retranslateUi(QDockWidget *UndoWidget);
36+
37+
/**
38+
* Setting new undo stack for undo view
39+
*/
40+
void setUndoStack(QUndoStack * undoStack);
41+
42+
/**
43+
* Handles destroying of stack when active layer is changed
44+
*/
45+
void destroyStack();
46+
47+
public slots:
48+
/**
49+
* Changes undo stack which is displayed by undo view
50+
*/
51+
void layerChanged( QgsMapLayer * layer);
52+
53+
/**
54+
* Slot to handle undo changed signal
55+
*/
56+
void undoChanged(bool value);
57+
58+
/**
59+
* Slot to handle redo changed signal
60+
*/
61+
void redoChanged(bool value);
62+
63+
/**
64+
* Slot to handle index changed signal
65+
*/
66+
void indexChanged(int value);
67+
68+
/**
69+
* Undo operation called from button push
70+
*/
71+
void undo();
72+
73+
/**
74+
* Redo operation called from button push
75+
*/
76+
void redo();
77+
78+
signals:
79+
void undoStackChanged();
80+
81+
private:
82+
QUndoView * mUndoView;
83+
QUndoStack * mUndoStack;
84+
QgsMapCanvas* mMapCanvas;
85+
86+
};
87+
88+
89+
#endif // QGSUNDOWIDGET_H
90+

‎src/app/qgsvectorlayerproperties.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,17 @@ void QgsVectorLayerProperties::addAttribute()
272272
bool QgsVectorLayerProperties::addAttribute( const QgsField &field )
273273
{
274274
QgsDebugMsg( "inserting attribute " + field.name() + " of type " + field.typeName() );
275-
return layer->addAttribute( field );
275+
layer->beginEditCommand( tr("Added attribute") );
276+
if ( layer->addAttribute( field ) )
277+
{
278+
layer->endEditCommand();
279+
return true;
280+
}
281+
else
282+
{
283+
layer->destroyEditCommand();
284+
return false;
285+
}
276286
}
277287

278288
void QgsVectorLayerProperties::deleteAttribute()
@@ -287,7 +297,11 @@ void QgsVectorLayerProperties::deleteAttribute()
287297
}
288298

289299
for ( QList<int>::const_iterator it = idxs.begin(); it != idxs.end(); it++ )
300+
{
301+
layer->beginEditCommand( tr("Deleted attribute") );
290302
layer->deleteAttribute( *it );
303+
layer->endEditCommand();
304+
}
291305
}
292306

293307
void QgsVectorLayerProperties::editingToggled()

0 commit comments

Comments
 (0)
Please sign in to comment.