Skip to content
Permalink
Browse files

[GRASS] fixed multilayer editing

  • Loading branch information
blazek committed Oct 20, 2015
1 parent b99ef2c commit f5a93ef95f341c67860576f4ba8cc3f5f58a1223
@@ -322,7 +322,6 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
// TODO should be numLines before editing started (?), but another layer
// where editing started later mest have different, because its buffer does not have previous changes
// -> editing of more layers must be synchronized or not allowed
//if ( mNextLid > mSource->mLayer->map()->numOldLines() )
if ( mNextLid > mSource->mLayer->map()->numLines() )
{
QgsDebugMsgLevel( "mNextLid > numLines()", 3 );
@@ -339,12 +338,14 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
if ( oldLid < 0 )
{
QgsDebugMsg( QString( "skip new feature oldLid = %1" ).arg( oldLid ) );
mNextCidx = 0;
mNextLid++;
continue;
}

if ( !Vect_line_alive( mSource->map(), mNextLid ) ) // should not be necessary for rewritten lines
{
mNextCidx = 0;
mNextLid++;
continue;
}
@@ -356,8 +357,9 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
lid = mNextLid;
type = tmpType;
cat = 0;

featureId = makeFeatureId( oldLid, cat );
int layer = 0;
featureId = makeFeatureId( oldLid, cat, layer );
mNextCidx = 0;
mNextLid++;
}
else
@@ -366,24 +368,18 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
{
mNextCidx = 0;
mNextLid++;
Vect_destroy_cats_struct( cats );
continue;
}
else
{
// Show only cats of currently edited layer
if ( cats->field[mNextCidx] != mSource->mLayer->field() )
{
mNextCidx++;
continue;
}
else
{
lid = mNextLid;
type = tmpType;
cat = cats->cat[mNextCidx];
featureId = makeFeatureId( oldLid, cat );
mNextCidx++;
}
lid = mNextLid;
type = tmpType;
cat = cats->cat[mNextCidx];
int layer = cats->field[mNextCidx];
QgsDebugMsgLevel( QString( "lid = %1 layer = %2 cat = %3" ).arg( lid ).arg( layer ).arg( cat ), 3 );
featureId = makeFeatureId( oldLid, cat, layer );
mNextCidx++;
}
}
Vect_destroy_cats_struct( cats );
@@ -612,11 +608,23 @@ void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, i
feature.setGeometry( new QgsGeometry( geometry ) );
}

QgsFeatureId QgsGrassFeatureIterator::makeFeatureId( int grassId, int cat )
QgsFeatureId QgsGrassFeatureIterator::makeFeatureId( int grassId, int cat, int layer )
{
// Because GRASS object id and category are both int and QgsFeatureId is qint64
// we can create unique QgsFeatureId from GRASS id and cat
return ( QgsFeatureId )grassId * 1000000000 + cat;
// we can create unique QgsFeatureId from GRASS id and cat.
// Max supported layer number is 92 (max 64bit int is 9,223,372,036,854,775,807).
QgsFeatureId fid = ( QgsFeatureId )layer * 100000000000000000 + ( QgsFeatureId )grassId * 1000000000 + cat;
QgsDebugMsgLevel( QString( "grassId = %1 cat = %2 layer = %3 fid = %4" ).arg( grassId ).arg( cat ).arg( layer ).arg( fid ), 3 );
return fid;
}

int QgsGrassFeatureIterator::layerFromFid( QgsFeatureId fid )
{
if ( FID_IS_NEW( fid ) )
{
return 0;
}
return fid / 100000000000000000;
}

int QgsGrassFeatureIterator::lidFromFid( QgsFeatureId fid )
@@ -627,7 +635,8 @@ int QgsGrassFeatureIterator::lidFromFid( QgsFeatureId fid )
{
return fid;
}
return fid / 1000000000;
qint64 lidCat = fid % 100000000000000000;
return lidCat / 1000000000;
}

int QgsGrassFeatureIterator::catFromFid( QgsFeatureId fid )
@@ -664,21 +673,51 @@ void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature
QgsDebugMsgLevel( QString( "setFeatureAttributes cat = %1 symbol = %2" ).arg( cat ).arg( symbol ), 3 );
feature->initAttributes( mSource->mLayer->fields().size() );

bool isEditedLayer = true;
int layerNumber = 0;
if ( mSource->mEditing )
{
layerNumber = layerFromFid( feature->id() );
if ( layerNumber != mSource->mLayer->field() )
{
isEditedLayer = false;
}
}

for ( QgsAttributeList::const_iterator iter = attlist.begin(); iter != attlist.end(); ++iter )
{
if ( *iter == mSource->mSymbolAttributeIndex )
{
continue;
}
QVariant value = mSource->mLayer->attribute( cat, *iter );
if ( value.type() == QVariant::ByteArray )
QVariant value;
if ( isEditedLayer )
{
value = QVariant( mSource->mEncoding->toUnicode( value.toByteArray() ) );
value = mSource->mLayer->attribute( cat, *iter );
if ( value.type() == QVariant::ByteArray )
{
value = QVariant( mSource->mEncoding->toUnicode( value.toByteArray() ) );
}
}
else
{
// TODO: use real layer keyColumn(), but to get it the layer must be first opened and attributes loaded
int keyColumn = 0;
if ( *iter == keyColumn )
{
value = QVariant( cat );
}
else
{
value = tr( "<not editable (layer %1)>" ).arg( layerNumber );
}
}
QgsDebugMsgLevel( QString( "iter = %1 value = %2" ).arg( *iter ).arg( value.toString() ), 3 );

feature->setAttribute( *iter, value );
}


if ( mSource->mEditing && attlist.contains( mSource->mSymbolAttributeIndex ) )
{
QgsDebugMsgLevel( QString( "set attribute %1 to symbol %2" ).arg( mSource->mSymbolAttributeIndex ).arg( symbol ), 3 );
@@ -84,8 +84,11 @@ class GRASS_LIB_EXPORT QgsGrassFeatureIterator : public QObject, public QgsAbstr
//! end of iterating: free the resources / lock
virtual bool close() override;

// create QgsFeatureId from GRASS geometry object id and cat
static QgsFeatureId makeFeatureId( int grassId, int cat );
// create QgsFeatureId from GRASS geometry object id, cat and layer number (editing)
static QgsFeatureId makeFeatureId( int grassId, int cat, int layer = 0 );

// Get layer number from QGIS fid
static int layerFromFid( QgsFeatureId fid );

// Get GRASS line id from QGIS fid
static int lidFromFid( QgsFeatureId fid );
@@ -625,6 +625,15 @@ bool QgsGrassProvider::closeEdit( bool newMap, QgsVectorLayer *vectorLayer )

mEditBuffer = 0;
mEditLayer = 0;
// drivers must be closed in reversed order in which were opened
// TODO: close driver order for simultaneous editing of multiple vector maps
for ( int i = mOtherEditLayers.size() - 1; i >= 0; i-- )
{
QgsGrassVectorMapLayer *layer = mOtherEditLayers[i];
layer->closeEdit();
mLayer->map()->closeLayer( layer );
}
mOtherEditLayers.clear();
mLayer->closeEdit();
if ( mLayer->map()->closeEdit( newMap ) )
{
@@ -1372,6 +1381,7 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
int oldLid = lid;
realLine = oldLid;
int realCat = cat;
int layerField = QgsGrassFeatureIterator::layerFromFid( fid );
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
{
realLine = mLayer->map()->newLids().value( oldLid );
@@ -1380,8 +1390,8 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
{
realCat = mLayer->map()->newCats().value( fid );
}
QgsDebugMsg( QString( "fid = %1 lid = %2 realLine = %3 cat = %4 realCat = %5" )
.arg( fid ).arg( lid ).arg( realLine ).arg( cat ).arg( realCat ) );
QgsDebugMsg( QString( "fid = %1 lid = %2 realLine = %3 cat = %4 realCat = %5 layerField = %6" )
.arg( fid ).arg( lid ).arg( realLine ).arg( cat ).arg( realCat ).arg( layerField ) );

if ( realLine > 0 )
{
@@ -1422,28 +1432,35 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
setPoints( mPoints, geometry );
}

// TODO: orig field, maybe different?
int field = mLayerField;
QgsDebugMsg( QString( "field = %1 realCat = %2" ).arg( field ).arg( realCat ) );
if ( realCat > 0 )
QgsDebugMsg( QString( "layerField = %1 realCat = %2" ).arg( layerField ).arg( realCat ) );
if ( realCat > 0 && layerField > 0 )
{
Vect_cat_set( mCats, field, realCat );
}
Vect_cat_set( mCats, layerField, realCat );

// restore attributes
if ( realCat > 0 )
{
QString error;
bool recordExists = mLayer->recordExists( realCat, error );
QgsDebugMsg( QString( "recordExists = %1 error = %2" ).arg( recordExists ).arg( error ) );
if ( !recordExists && error.isEmpty() )
// restore attributes
QgsGrassVectorMapLayer *layer = mLayer;
if ( layerField != mLayer->field() )
{
QgsDebugMsg( "record does not exist -> restore attributes" );
error.clear();
mLayer->reinsertAttributes( realCat, error );
if ( !error.isEmpty() )
layer = otherEditLayer( layerField );
}
if ( !layer )
{
QgsDebugMsg( "Cannot get layer" );
}
else
{
QString error;
bool recordExists = layer->recordExists( realCat, error );
QgsDebugMsg( QString( "recordExists = %1 error = %2" ).arg( recordExists ).arg( error ) );
if ( !recordExists && error.isEmpty() )
{
QgsGrass::warning( tr( "Cannot restore record with cat %1" ).arg( realCat ) );
QgsDebugMsg( "record does not exist -> restore attributes" );
error.clear();
layer->reinsertAttributes( realCat, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( tr( "Cannot restore record with cat %1" ).arg( realCat ) );
}
}
}
}
@@ -1490,6 +1507,7 @@ void QgsGrassProvider::onFeatureDeleted( QgsFeatureId fid )

int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
int cat = QgsGrassFeatureIterator::catFromFid( fid );
int layerField = QgsGrassFeatureIterator::layerFromFid( fid );
int realLine = oldLid;
int realCat = cat;
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
@@ -1501,8 +1519,8 @@ void QgsGrassProvider::onFeatureDeleted( QgsFeatureId fid )
realCat = mLayer->map()->newCats().value( fid );
}

QgsDebugMsg( QString( "fid = %1 oldLid = %2 realLine = %3 cat = %4 realCat = %5" )
.arg( fid ).arg( oldLid ).arg( realLine ).arg( cat ).arg( realCat ) );
QgsDebugMsg( QString( "fid = %1 oldLid = %2 realLine = %3 cat = %4 realCat = %5 layerField = %6" )
.arg( fid ).arg( oldLid ).arg( realLine ).arg( cat ).arg( realCat ).arg( layerField ) );

int type = 0;
mLayer->map()->lockReadWrite();
@@ -1531,9 +1549,9 @@ void QgsGrassProvider::onFeatureDeleted( QgsFeatureId fid )
}
}

if ( realCat > 0 )
if ( realCat > 0 && layerField > 0 )
{
if ( Vect_field_cat_del( mCats, mLayerField, realCat ) == 0 )
if ( Vect_field_cat_del( mCats, layerField, realCat ) == 0 )
{
// should not happen
QgsDebugMsg( "the line does not have old category" );
@@ -1563,19 +1581,31 @@ void QgsGrassProvider::onFeatureDeleted( QgsFeatureId fid )
}

// Delete record if orphan
if ( realCat > 0 )
if ( realCat > 0 && layerField > 0 )
{
QString error;
bool orphan = mLayer->isOrphan( realCat, error );
QgsDebugMsg( QString( "orphan = %1 error = %2" ).arg( orphan ).arg( error ) );
if ( orphan && error.isEmpty() )
QgsGrassVectorMapLayer *layer = mLayer;
if ( layerField != mLayer->field() )
{
QgsDebugMsg( QString( "realCat = %1 is orphan -> delete record" ).arg( realCat ) );
error.clear();
mLayer->deleteAttribute( realCat, error );
if ( !error.isEmpty() )
layer = otherEditLayer( layerField );
}
if ( !layer )
{
QgsDebugMsg( "Cannot get layer" );
}
else
{
QString error;
bool orphan = layer->isOrphan( realCat, error );
QgsDebugMsg( QString( "orphan = %1 error = %2" ).arg( orphan ).arg( error ) );
if ( orphan && error.isEmpty() )
{
QgsGrass::warning( tr( "Cannot delete orphan record with cat %1" ).arg( realCat ) );
QgsDebugMsg( QString( "realCat = %1 is orphan -> delete record" ).arg( realCat ) );
error.clear();
layer->deleteAttribute( realCat, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( tr( "Cannot delete orphan record with cat %1" ).arg( realCat ) );
}
}
}
}
@@ -1945,6 +1975,24 @@ void QgsGrassProvider::setMapset()
QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() );
}

QgsGrassVectorMapLayer * QgsGrassProvider::otherEditLayer( int layerField )
{
Q_FOREACH ( QgsGrassVectorMapLayer *layer, mOtherEditLayers )
{
if ( layer->field() == layerField )
{
return layer;
}
}
QgsGrassVectorMapLayer *layer = mLayer->map()->openLayer( layerField );
if ( layer )
{
layer->startEdit();
mOtherEditLayers << layer;
}
return layer;
}

QString QgsGrassProvider::name() const
{
return GRASS_KEY;
@@ -454,6 +454,9 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider

void setPoints( struct line_pnts *points, const QgsAbstractGeometryV2 * geometry );

// Get other edited layer, returns 0 if layer does not exist
QgsGrassVectorMapLayer * otherEditLayer( int layerField );

/** Fields used for topo layers */
QgsFields mTopoFields;

@@ -468,6 +471,9 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
// Last version of layer fields during editing, updated after addAttribute and deleteAttribute
QgsFields mEditLayerFields;

// List of other layers opened for editing
QList<QgsGrassVectorMapLayer *> mOtherEditLayers;

// points and cats used only for editing
struct line_pnts *mPoints;
struct line_cats *mCats;
@@ -610,6 +610,13 @@ QgsAbstractGeometryV2 * QgsGrassVectorMap::lineGeometry( int id )
struct line_pnts *points = Vect_new_line_struct();

int type = Vect_read_line( mMap, points, 0, id );
QgsDebugMsgLevel( QString( "type = %1 n_points = %2" ).arg( type ).arg( points->n_points ), 3 );
if ( points->n_points == 0 )
{
Vect_destroy_line_struct( points );
return 0;
}

QList<QgsPointV2> pointList;
pointList.reserve( points->n_points );
for ( int i = 0; i < points->n_points; i++ )

0 comments on commit f5a93ef

Please sign in to comment.
You can’t perform that action at this time.