QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsvectorlayerundocommand.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerundocommand.cpp
3  ---------------------
4  begin : June 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include "qgsgeometry.h"
19 #include "qgsfeature.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsgeometrycache.h"
23 
24 #include "qgslogger.h"
25 
26 
28  : QgsVectorLayerUndoCommand( buffer )
29 {
30  static int addedIdLowWaterMark = -1;
31 
32  //assign a temporary id to the feature (use negative numbers)
33  addedIdLowWaterMark--;
34 
35  QgsDebugMsg( "Assigned feature id " + QString::number( addedIdLowWaterMark ) );
36 
37  // Force a feature ID (to keep other functions in QGIS happy,
38  // providers will use their own new feature ID when we commit the new feature)
39  // and add to the known added features.
40  f.setFeatureId( addedIdLowWaterMark );
41 
42  mFeature = f;
43 }
44 
46 {
47 #ifdef QGISDEBUG
48  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.find( mFeature.id() );
49  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
50 #endif
51  mBuffer->mAddedFeatures.remove( mFeature.id() );
52 
53  if ( mFeature.geometry() )
55 
56  emit mBuffer->featureDeleted( mFeature.id() );
57 }
58 
60 {
62 
63  if ( mFeature.geometry() )
65 
66  emit mBuffer->featureAdded( mFeature.id() );
67 }
68 
69 
70 
72  : QgsVectorLayerUndoCommand( buffer )
73 {
74  mFid = fid;
75 
76  if ( FID_IS_NEW( mFid ) )
77  {
78  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.find( mFid );
79  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
80  mOldAddedFeature = it.value();
81  }
82 }
83 
85 {
86  if ( FID_IS_NEW( mFid ) )
87  {
89  }
90  else
91  {
92  mBuffer->mDeletedFeatureIds.remove( mFid );
93  }
94 
95  emit mBuffer->featureAdded( mFid );
96 }
97 
99 {
100  if ( FID_IS_NEW( mFid ) )
101  {
102  mBuffer->mAddedFeatures.remove( mFid );
103  }
104  else
105  {
106  mBuffer->mDeletedFeatureIds.insert( mFid );
107  }
108 
109  emit mBuffer->featureDeleted( mFid );
110 }
111 
112 
113 
115  : QgsVectorLayerUndoCommand( buffer )
116  , mFid( fid )
117 {
118  if ( FID_IS_NEW( mFid ) )
119  {
120  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.find( mFid );
121  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
122  mOldGeom = new QgsGeometry( *it.value().geometry() );
123  }
124  else
125  {
126  bool changedAlready = mBuffer->mChangedGeometries.contains( mFid );
127  QgsGeometry geom;
128  bool cachedGeom = cache()->geometry( mFid, geom );
129  mOldGeom = ( changedAlready && cachedGeom ) ? new QgsGeometry( geom ) : 0;
130  }
131 
132  mNewGeom = new QgsGeometry( *newGeom );
133 }
134 
136 {
137  return 1;
138 }
139 
140 bool QgsVectorLayerUndoCommandChangeGeometry::mergeWith( const QUndoCommand *other )
141 {
142  if ( other->id() != id() )
143  return false;
144 
145  const QgsVectorLayerUndoCommandChangeGeometry *merge = dynamic_cast<const QgsVectorLayerUndoCommandChangeGeometry *>( other );
146  if ( !merge )
147  return false;
148 
149  if ( merge->mFid != mFid )
150  return false;
151 
152  delete mNewGeom;
153  mNewGeom = merge->mNewGeom;
154  merge->mNewGeom = 0;
155 
156  return true;
157 }
158 
160 {
161  delete mOldGeom;
162  delete mNewGeom;
163 }
164 
166 {
167  if ( FID_IS_NEW( mFid ) )
168  {
169  // modify added features
170  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
171  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
172  it.value().setGeometry( *mOldGeom );
173 
176  }
177  else
178  {
179  // existing feature
180 
181  if ( !mOldGeom )
182  {
183  mBuffer->mChangedGeometries.remove( mFid );
184 
185  QgsFeature f;
186  if ( layer()->getFeatures( QgsFeatureRequest().setFilterFid( mFid ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.geometry() )
187  {
188  cache()->cacheGeometry( mFid, *f.geometry() );
189  emit mBuffer->geometryChanged( mFid, *f.geometry() );
190  }
191  }
192  else
193  {
197  }
198  }
199 
200 }
201 
203 {
204  if ( FID_IS_NEW( mFid ) )
205  {
206  // modify added features
207  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
208  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
209  it.value().setGeometry( *mNewGeom );
210  }
211  else
212  {
214  }
217 }
218 
219 
220 QgsVectorLayerUndoCommandChangeAttribute::QgsVectorLayerUndoCommandChangeAttribute( QgsVectorLayerEditBuffer* buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue )
221  : QgsVectorLayerUndoCommand( buffer )
222  , mFid( fid )
223  , mFieldIndex( fieldIndex )
224  , mOldValue( oldValue )
225  , mNewValue( newValue )
226  , mFirstChange( true )
227 {
228  if ( FID_IS_NEW( mFid ) )
229  {
230  // work with added feature
231  QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.find( mFid );
232  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
233  if ( it.value().attribute( mFieldIndex ).isValid() )
234  {
235  mOldValue = it.value().attribute( mFieldIndex );
236  mFirstChange = false;
237  }
238  }
239  else if ( mBuffer->mChangedAttributeValues.contains( mFid ) && mBuffer->mChangedAttributeValues[mFid].contains( mFieldIndex ) )
240  {
242  mFirstChange = false;
243  }
244 
245 }
246 
248 {
249  QVariant original = mOldValue;
250 
251  if ( FID_IS_NEW( mFid ) )
252  {
253  // added feature
254  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
255  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
256  it.value().setAttribute( mFieldIndex, mOldValue );
257  }
258  else if ( mFirstChange )
259  {
260  // existing feature
262  if ( mBuffer->mChangedAttributeValues[mFid].isEmpty() )
264 
265  if ( !mOldValue.isValid() )
266  {
267  // get old value from provider
268  QgsFeature tmp;
269  QgsFeatureRequest request;
270  request.setFilterFid( mFid );
273  QgsFeatureIterator fi = layer()->getFeatures( request );
274  if ( fi.nextFeature( tmp ) )
275  original = tmp.attribute( mFieldIndex );
276  }
277  }
278  else
279  {
281  }
282 
283  emit mBuffer->attributeValueChanged( mFid, mFieldIndex, original );
284 }
285 
287 {
288  if ( FID_IS_NEW( mFid ) )
289  {
290  // updated added feature
291  QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.find( mFid );
292  Q_ASSERT( it != mBuffer->mAddedFeatures.end() );
293  it.value().setAttribute( mFieldIndex, mNewValue );
294  }
295  else
296  {
297  // changed attribute of existing feature
298  if ( !mBuffer->mChangedAttributeValues.contains( mFid ) )
299  {
301  }
302 
304  }
305 
307 }
308 
309 
311  : QgsVectorLayerUndoCommand( buffer )
312  , mField( field )
313 {
314  const QgsFields &fields = layer()->pendingFields();
315  int i;
316  for ( i = 0; i < fields.count() && fields.fieldOrigin( i ) != QgsFields::OriginJoin; i++ )
317  ;
318  mFieldIndex = i;
319 }
320 
322 {
324 
325  mBuffer->mAddedAttributes.removeAt( index );
328 
330 }
331 
333 {
334  mBuffer->mAddedAttributes.append( mField );
337 
339 }
340 
341 
343  : QgsVectorLayerUndoCommand( buffer )
344  , mFieldIndex( fieldIndex )
345 {
346  const QgsFields& fields = layer()->pendingFields();
350 
351  if ( !mProviderField )
352  {
353  // need to store the field definition
355  }
356 
357  // save values of new features
358  for ( QgsFeatureMap::const_iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
359  {
360  const QgsFeature& f = it.value();
361  mDeletedValues.insert( f.id(), f.attribute( mFieldIndex ) );
362  }
363 
364  // save changed values
365  for ( QgsChangedAttributesMap::const_iterator it = mBuffer->mChangedAttributeValues.begin(); it != mBuffer->mChangedAttributeValues.end(); ++it )
366  {
367  const QgsAttributeMap& attrs = it.value();
368  if ( attrs.contains( mFieldIndex ) )
369  mDeletedValues.insert( it.key(), attrs[mFieldIndex] );
370  }
371 }
372 
374 {
375  if ( mProviderField )
376  {
378  }
379  else
380  {
381  // newly added attribute
383  }
384 
386  mBuffer->handleAttributeAdded( mFieldIndex ); // update changed attributes + new features
387 
388  // set previously used attributes of new features
389  for ( QgsFeatureMap::iterator it = mBuffer->mAddedFeatures.begin(); it != mBuffer->mAddedFeatures.end(); ++it )
390  {
391  QgsFeature& f = it.value();
392  f.setAttribute( mFieldIndex, mDeletedValues.value( f.id() ) );
393  }
394  // set previously used changed attributes
395  for ( QMap<QgsFeatureId, QVariant>::const_iterator it = mDeletedValues.begin(); it != mDeletedValues.end(); ++it )
396  {
397  if ( !FID_IS_NEW( it.key() ) )
398  {
399  QgsAttributeMap& attrs = mBuffer->mChangedAttributeValues[it.key()]; // also adds record if nonexistant
400  attrs.insert( mFieldIndex, it.value() );
401  }
402  }
403 
405 }
406 
408 {
409  if ( mProviderField )
410  {
412  qSort( mBuffer->mDeletedAttributeIds ); // keep it sorted
413  }
414  else
415  {
416  // newly added attribute
417  mBuffer->mAddedAttributes.removeAt( mOriginIndex ); // removing temporary attribute
418  }
419 
421  mBuffer->handleAttributeDeleted( mFieldIndex ); // update changed attributes + new features
423 }
QgsFeatureId id() const
Get the feature id for this feature.
Definition: qgsfeature.cpp:100
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
void handleAttributeDeleted(int index)
update added and changed features after removal of an attribute
QgsVectorLayerUndoCommandAddFeature(QgsVectorLayerEditBuffer *buffer, QgsFeature &f)
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:98
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void attributeDeleted(int idx)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:112
QgsVectorLayerEditBuffer * mBuffer
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
Definition: qgsfield.h:163
bool setAttribute(int field, const QVariant &attr)
Set an attribute by id.
Definition: qgsfeature.cpp:190
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not commited.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
QgsVectorLayerUndoCommandAddAttribute(QgsVectorLayerEditBuffer *buffer, const QgsField &field)
QgsVectorLayerUndoCommandDeleteAttribute(QgsVectorLayerEditBuffer *buffer, int fieldIndex)
void featureAdded(QgsFeatureId fid)
field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
Definition: qgsfield.h:170
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Set feature ID that should be fetched.
void removeGeometry(QgsFeatureId fid)
get rid of the cached geometry
void setFeatureId(QgsFeatureId id)
Set the feature id for this feature.
Definition: qgsfeature.cpp:128
QgsVectorLayerUndoCommandChangeAttribute(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, int fieldIndex, const QVariant &newValue, const QVariant &oldValue)
void attributeAdded(int idx)
void geometryChanged(QgsFeatureId fid, QgsGeometry &geom)
bool geometry(QgsFeatureId fid, QgsGeometry &geometry)
fetch geometry from cache, return true if successful
int fieldOriginIndex(int fieldIdx) const
Get field's origin index (its meaning is specific to each type of origin)
Definition: qgsfield.h:222
QgsGeometryMap mChangedGeometries
Changed geometries which are not commited.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
void handleAttributeAdded(int index)
update added and changed features after addition of an attribute
int count() const
Return number of items.
Definition: qgsfield.h:200
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not commited.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:33
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
QList< QgsField > mAddedAttributes
added attributes fields which are not commited
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &)
FieldOrigin fieldOrigin(int fieldIdx) const
Get field's origin (value from an enumeration)
Definition: qgsfield.h:220
void cacheGeometry(QgsFeatureId fid, const QgsGeometry &geom)
store a geometry in the cache
qint64 QgsFeatureId
Definition: qgsfeature.h:30
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:81
virtual bool mergeWith(const QUndoCommand *)
QgsVectorLayerUndoCommandChangeGeometry(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid, QgsGeometry *newGeom)
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfield.h:171
QgsVectorLayerUndoCommandDeleteFeature(QgsVectorLayerEditBuffer *buffer, QgsFeatureId fid)
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureMap mAddedFeatures
New features which are not commited.
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
QgsAttributeList mDeletedAttributeIds
deleted attributes fields which are not commited.
void featureDeleted(QgsFeatureId fid)