Skip to content

Commit a213b03

Browse files
committedOct 6, 2015
[GRASS] multi cat editing fixes
1 parent dc04314 commit a213b03

File tree

5 files changed

+432
-253
lines changed

5 files changed

+432
-253
lines changed
 

‎src/providers/grass/qgsgrassfeatureiterator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
473473
return false;
474474
}
475475
}
476-
QgsDebugMsgLevel( QString( "lid = %1 type = %2 cat = %3 fatureId = %4" ).arg( lid ).arg( type ).arg( cat ).arg( featureId ), 3 );
476+
QgsDebugMsgLevel( QString( "lid = %1 type = %2 cat = %3 featureId = %4" ).arg( lid ).arg( type ).arg( cat ).arg( featureId ), 3 );
477477

478478
feature.setFeatureId( featureId );
479479
//feature.initAttributes( mSource->mFields.count() );

‎src/providers/grass/qgsgrassprovider.cpp

Lines changed: 298 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,11 +1154,21 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
11541154

11551155
int lid = QgsGrassFeatureIterator::lidFromFid( fid );
11561156
int cat = QgsGrassFeatureIterator::catFromFid( fid );
1157+
11571158
QgsDebugMsg( QString( "fid = %1 lid = %2 cat = %3" ).arg( fid ).arg( lid ).arg( cat ) );
11581159

1159-
const QgsAbstractGeometryV2 *geometry = 0;
1160+
Vect_reset_cats( mCats );
1161+
int realLine = 0; // number of line to be rewritten if exists
1162+
int newCat = 0;
1163+
1164+
// TODO: get also old type if it is feature previously deleted
1165+
int type = 0;
1166+
11601167
if ( FID_IS_NEW( fid ) )
11611168
{
1169+
type = mNewFeatureType == GV_AREA ? GV_BOUNDARY : mNewFeatureType;
1170+
// geometry
1171+
const QgsAbstractGeometryV2 *geometry = 0;
11621172
if ( !mEditBuffer->addedFeatures().contains( fid ) )
11631173
{
11641174
#ifdef QGISDEBUG
@@ -1180,171 +1190,245 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
11801190
{
11811191
QgsDebugMsg( "feature does not have geometry" );
11821192
}
1183-
}
1184-
else // old deleted feature undo
1185-
{
1186-
// If it is not new feature, we should have the geometry in oldGeometries
1187-
if ( mLayer->map()->oldGeometries().contains( lid ) )
1188-
{
1189-
geometry = mLayer->map()->oldGeometries().value( lid );
1190-
}
1191-
else
1193+
if ( !geometry )
11921194
{
1193-
QgsDebugMsg( "geometry of old, previously deleted feature not found" );
1195+
QgsDebugMsg( "geometry is null" );
1196+
return;
11941197
}
1195-
}
1196-
1197-
if ( !geometry )
1198-
{
1199-
QgsDebugMsg( "geometry is null" );
1200-
}
1201-
else
1202-
{
1203-
int newCat = 0;
12041198

12051199
setPoints( mPoints, geometry );
1206-
// TODO: get also old type if it is feature previously deleted
1207-
int type = mNewFeatureType == GV_AREA ? GV_BOUNDARY : mNewFeatureType;
12081200

1209-
if ( FID_IS_NEW( fid ) )
1201+
QgsFeatureMap& addedFeatures = const_cast<QgsFeatureMap&>( mEditBuffer->addedFeatures() );
1202+
1203+
// change polygon to linestring
1204+
QgsWKBTypes::Type wkbType = QgsWKBTypes::flatType( geometry->wkbType() );
1205+
if ( wkbType == QgsWKBTypes::Polygon )
12101206
{
1211-
// add new category
1212-
// TODO: add category also to boundary if user defined at least one attribute?
1213-
if ( type != GV_BOUNDARY )
1207+
const QgsPolygonV2* polygon = dynamic_cast<const QgsPolygonV2*>( addedFeatures[fid].geometry()->geometry() );
1208+
if ( polygon )
12141209
{
1215-
// TODO: redo of deleted new features - save new cats somewhere,
1216-
// resetting fid probably is not possible because it is stored in undo commands and used in buffer maps
1210+
QgsLineStringV2* lineString = polygon->exteriorRing()->curveToLine();
1211+
addedFeatures[fid].setGeometry( new QgsGeometry( lineString ) );
1212+
}
1213+
// TODO: create also centroid and add it to undo
1214+
}
12171215

1218-
// It may be that user manualy entered cat value
1219-
const QgsFeature &feature = mEditBuffer->addedFeatures()[fid];
1220-
int catIndex = feature.fields()->indexFromName( mLayer->keyColumnName() );
1221-
if ( catIndex != -1 )
1216+
// add new category
1217+
// TODO: add category also to boundary if user defined at least one attribute?
1218+
if ( type != GV_BOUNDARY )
1219+
{
1220+
// TODO: redo of deleted new features - save new cats somewhere,
1221+
// resetting fid probably is not possible because it is stored in undo commands and used in buffer maps
1222+
1223+
// It may be that user manualy entered cat value
1224+
const QgsFeature &feature = mEditBuffer->addedFeatures()[fid];
1225+
int catIndex = feature.fields()->indexFromName( mLayer->keyColumnName() );
1226+
if ( catIndex != -1 )
1227+
{
1228+
QVariant userCatVariant = feature.attributes().value( catIndex );
1229+
if ( !userCatVariant.isNull() )
12221230
{
1223-
QVariant userCatVariant = feature.attributes().value( catIndex );
1224-
if ( !userCatVariant.isNull() )
1225-
{
1226-
newCat = userCatVariant.toInt();
1227-
QgsDebugMsg( QString( "user defined newCat = %1" ).arg( newCat ) );
1228-
}
1231+
newCat = userCatVariant.toInt();
1232+
QgsDebugMsg( QString( "user defined newCat = %1" ).arg( newCat ) );
12291233
}
1230-
if ( newCat == 0 )
1234+
}
1235+
if ( newCat == 0 )
1236+
{
1237+
QgsDebugMsg( QString( "get new cat for mCidxFieldIndex = %1" ).arg( mCidxFieldIndex ) );
1238+
if ( mCidxFieldIndex == -1 )
12311239
{
1232-
QgsDebugMsg( QString( "get new cat for mCidxFieldIndex = %1" ).arg( mCidxFieldIndex ) );
1233-
if ( mCidxFieldIndex == -1 )
1234-
{
1235-
// No features with this field yet in map
1236-
newCat = 1;
1237-
}
1238-
else
1239-
{
1240-
newCat = cidxGetMaxCat( mCidxFieldIndex ) + 1;
1241-
}
1240+
// No features with this field yet in map
1241+
newCat = 1;
12421242
}
1243-
QgsDebugMsg( QString( "newCat = %1" ).arg( newCat ) );
1244-
Vect_reset_cats( mCats );
1245-
Vect_cat_set( mCats, mLayerField, newCat );
1246-
QString error;
1243+
else
1244+
{
1245+
newCat = cidxGetMaxCat( mCidxFieldIndex ) + 1;
1246+
}
1247+
}
1248+
QgsDebugMsg( QString( "newCat = %1" ).arg( newCat ) );
1249+
Vect_cat_set( mCats, mLayerField, newCat );
12471250

1248-
// if the cat is user defined, the record may alredy exist
1249-
if ( mLayer->attributes().contains( newCat ) )
1251+
if ( mLayer->hasTable() )
1252+
{
1253+
addedFeatures[fid].setAttribute( mLayer->keyColumn(), newCat );
1254+
}
1255+
else
1256+
{
1257+
addedFeatures[fid].setAttribute( 0, newCat );
1258+
}
1259+
mLayer->map()->newCats()[fid] = newCat;
1260+
QgsDebugMsg( QString( "newCats[%1] = %2" ).arg( fid ).arg( newCat ) );
1261+
1262+
QString error;
1263+
// if the cat is user defined, the record may alredy exist
1264+
if ( mLayer->attributes().contains( newCat ) )
1265+
{
1266+
QgsDebugMsg( "record exists" );
1267+
// TODO: open warning dialog?
1268+
// For now we are expecting that user knows what he is doing.
1269+
// We update existing record by non null values and set feature null values to existing values
1270+
mLayer->updateAttributes( newCat, feature, error ); // also updates feature by existing non null attributes
1271+
1272+
// There may be other new features with the same cat which we have to update
1273+
QgsFeatureMap& addedFeatures = const_cast<QgsFeatureMap&>( mEditBuffer->addedFeatures() );
1274+
Q_FOREACH ( QgsFeatureId addedFid, addedFeatures.keys() )
12501275
{
1251-
QgsDebugMsg( "record exists" );
1252-
// TODO: open warning dialog?
1253-
// For now we are expecting that user knows what he is doing.
1254-
// We update existing record by non null values and set feature null values to existing values
1255-
mLayer->updateAttributes( newCat, feature, error ); // also updates feature by existing non null attributes
1256-
1257-
// There may be other new features with the same cat which we have to update
1258-
QgsFeatureMap& addedFeatures = const_cast<QgsFeatureMap&>( mEditBuffer->addedFeatures() );
1259-
Q_FOREACH ( QgsFeatureId addedFid, addedFeatures.keys() )
1276+
if ( addedFid == fid )
12601277
{
1261-
if ( addedFid == fid )
1262-
{
1263-
continue;
1264-
}
1265-
int addedCat = mLayer->map()->newCats().value( addedFid ); // it should always exist
1266-
QgsDebugMsg( QString( "addedFid = %1 addedCat = %2" ).arg( addedFid ).arg( addedCat ) );
1267-
if ( addedCat == newCat )
1278+
continue;
1279+
}
1280+
int addedCat = mLayer->map()->newCats().value( addedFid ); // it should always exist
1281+
QgsDebugMsg( QString( "addedFid = %1 addedCat = %2" ).arg( addedFid ).arg( addedCat ) );
1282+
if ( addedCat == newCat )
1283+
{
1284+
QgsFeature addedFeature = addedFeatures[addedFid];
1285+
// TODO: better to update form mLayer->attributes() ?
1286+
for ( int i = 0; i < feature.fields()->size(); i++ )
12681287
{
1269-
QgsFeature addedFeature = addedFeatures[addedFid];
1270-
// TODO: better to update form mLayer->attributes() ?
1271-
for ( int i = 0; i < feature.fields()->size(); i++ )
1288+
if ( feature.fields()->field( i ).name() == QgsGrassVectorMap::topoSymbolFieldName() )
1289+
{
1290+
continue;
1291+
}
1292+
if ( feature.attributes()[i].isNull() )
12721293
{
1273-
if ( feature.fields()->field( i ).name() == QgsGrassVectorMap::topoSymbolFieldName() )
1274-
{
1275-
continue;
1276-
}
1277-
if ( feature.attributes()[i].isNull() )
1278-
{
1279-
continue;
1280-
}
1281-
addedFeature.setAttribute( i, feature.attributes()[i] );
1294+
continue;
12821295
}
1283-
addedFeatures[addedFid] = addedFeature;
1296+
addedFeature.setAttribute( i, feature.attributes()[i] );
12841297
}
1298+
addedFeatures[addedFid] = addedFeature;
12851299
}
1300+
}
12861301

1287-
// Update all changed attributes
1288-
// TODO: table does not get refreshed immediately
1289-
QgsChangedAttributesMap &changedAttributes = const_cast<QgsChangedAttributesMap &>( mEditBuffer->changedAttributeValues() );
1290-
Q_FOREACH ( QgsFeatureId changedFid, changedAttributes.keys() )
1302+
// Update all changed attributes
1303+
// TODO: table does not get refreshed immediately
1304+
QgsChangedAttributesMap &changedAttributes = const_cast<QgsChangedAttributesMap &>( mEditBuffer->changedAttributeValues() );
1305+
Q_FOREACH ( QgsFeatureId changedFid, changedAttributes.keys() )
1306+
{
1307+
int changedCat = QgsGrassFeatureIterator::catFromFid( changedFid );
1308+
int realChangedCat = changedCat;
1309+
if ( mLayer->map()->newCats().contains( changedFid ) )
1310+
{
1311+
realChangedCat = mLayer->map()->newCats().value( changedFid );
1312+
}
1313+
QgsDebugMsg( QString( "changedFid = %1 changedCat = %2 realChangedCat = %3" )
1314+
.arg( changedFid ).arg( changedCat ).arg( realChangedCat ) );
1315+
if ( realChangedCat == newCat )
12911316
{
1292-
int changedCat = QgsGrassFeatureIterator::catFromFid( changedFid );
1293-
int realChangedCat = changedCat;
1294-
if ( mLayer->map()->newCats().contains( changedFid ) )
1317+
QgsAttributeMap attributeMap = changedAttributes[changedFid];
1318+
Q_FOREACH ( int index, attributeMap.keys() )
12951319
{
1296-
realChangedCat = mLayer->map()->newCats().value( changedFid );
1297-
}
1298-
QgsDebugMsg( QString( "changedFid = %1 changedCat = %2 realChangedCat = %3" )
1299-
.arg( changedFid ).arg( changedCat ).arg( realChangedCat ) );
1300-
if ( realChangedCat == newCat )
1301-
{
1302-
QgsAttributeMap attributeMap = changedAttributes[changedFid];
1303-
Q_FOREACH ( int index, attributeMap.keys() )
1304-
{
1305-
attributeMap[index] = feature.attributes().value( index );
1306-
}
1307-
changedAttributes[changedFid] = attributeMap;
1320+
attributeMap[index] = feature.attributes().value( index );
13081321
}
1322+
changedAttributes[changedFid] = attributeMap;
13091323
}
13101324
}
1311-
else
1325+
}
1326+
else
1327+
{
1328+
mLayer->insertAttributes( newCat, feature, error );
1329+
if ( !error.isEmpty() )
13121330
{
1313-
mLayer->insertAttributes( newCat, feature, error );
1314-
if ( !error.isEmpty() )
1315-
{
1316-
QgsGrass::warning( error );
1317-
}
1331+
QgsGrass::warning( error );
13181332
}
13191333
}
13201334
}
1335+
}
1336+
else
1337+
{
1338+
QgsDebugMsg( "undo of old deleted feature" );
1339+
int oldLid = lid;
1340+
realLine = oldLid;
1341+
int realCat = cat;
1342+
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
1343+
{
1344+
realLine = mLayer->map()->newLids().value( oldLid );
1345+
}
1346+
if ( mLayer->map()->newCats().contains( fid ) )
1347+
{
1348+
realCat = mLayer->map()->newCats().value( fid );
1349+
}
1350+
QgsDebugMsg( QString( "fid = %1 lid = %2 realLine = %3 cat = %4 realCat = %5" )
1351+
.arg( fid ).arg( lid ).arg( realLine ).arg( cat ).arg( realCat ) );
1352+
1353+
if ( realLine > 0 )
1354+
{
1355+
QgsDebugMsg( QString( "reading realLine = %1" ).arg( realLine ) );
1356+
int realType = readLine( mPoints, mCats, realLine );
1357+
if ( realType > 0 )
1358+
{
1359+
QgsDebugMsg( QString( "the line exists realType = %1, add the cat to that line" ).arg( realType ) );
1360+
type = realType;
1361+
}
1362+
else // should not happen
1363+
{
1364+
QgsDebugMsg( "cannot read realLine" );
1365+
return;
1366+
}
1367+
}
13211368
else
13221369
{
1323-
// Old feature delete undo
1324-
if ( cat > 0 )
1370+
QgsDebugMsg( QString( "the line does not exist -> restore old geometry" ) );
1371+
const QgsAbstractGeometryV2 *geometry = 0;
1372+
1373+
// If it is not new feature, we should have the geometry in oldGeometries
1374+
if ( mLayer->map()->oldGeometries().contains( lid ) )
1375+
{
1376+
geometry = mLayer->map()->oldGeometries().value( lid );
1377+
type = mLayer->map()->oldTypes().value( lid );
1378+
}
1379+
else
1380+
{
1381+
QgsDebugMsg( "geometry of old, previously deleted feature not found" );
1382+
return;
1383+
}
1384+
if ( !geometry )
13251385
{
1326-
// TODO: orig field, maybe different
1327-
int field = mLayerField;
1328-
Vect_reset_cats( mCats );
1329-
Vect_cat_set( mCats, field, cat );
1386+
QgsDebugMsg( "geometry is null" );
1387+
return;
13301388
}
1389+
setPoints( mPoints, geometry );
13311390
}
13321391

1333-
if ( type > 0 && mPoints->n_points > 0 )
1392+
// TODO: orig field, maybe different?
1393+
int field = mLayerField;
1394+
QgsDebugMsg( QString( "field = %1 realCat = %2" ).arg( field ).arg( realCat ) );
1395+
if ( realCat > 0 )
13341396
{
1335-
mLayer->map()->lockReadWrite();
1336-
int newLid = Vect_write_line( map(), type, mPoints, mCats );
1337-
mLayer->map()->unlockReadWrite();
1338-
1339-
QgsDebugMsg( QString( "newLine = %1" ).arg( newLid ) );
1397+
Vect_cat_set( mCats, field, realCat );
1398+
}
13401399

1341-
if ( mCidxFieldIndex == -1 && type != GV_BOUNDARY )
1400+
// restore attributes
1401+
if ( realCat > 0 )
1402+
{
1403+
QString error;
1404+
bool recordExists = mLayer->recordExists( realCat, error );
1405+
QgsDebugMsg( QString( "recordExists = %1 error = %2" ).arg( recordExists ).arg( error ) );
1406+
if ( !recordExists && error.isEmpty() )
13421407
{
1343-
// first feature in this layer
1344-
mCidxFieldIndex = Vect_cidx_get_field_index( map(), mLayerField );
1345-
QgsDebugMsg( QString( "new mCidxFieldIndex = %1" ).arg( mCidxFieldIndex ) );
1408+
QgsDebugMsg( "record does not exist -> restore attributes" );
1409+
error.clear();
1410+
mLayer->reinsertAttributes( realCat, error );
1411+
if ( !error.isEmpty() )
1412+
{
1413+
QgsGrass::warning( tr( "Cannot restore record with cat %1" ).arg( realCat ) );
1414+
}
13461415
}
1416+
}
1417+
}
13471418

1419+
QgsDebugMsg( QString( "type = %1 mPoints->n_points = %2" ).arg( type ).arg( mPoints->n_points ) );
1420+
if ( type > 0 && mPoints->n_points > 0 )
1421+
{
1422+
int newLid = 0;
1423+
mLayer->map()->lockReadWrite();
1424+
if ( realLine > 0 )
1425+
{
1426+
newLid = rewriteLine( realLine, type, mPoints, mCats );
1427+
}
1428+
else
1429+
{
1430+
// TODO: use writeLine() and move setting oldLids, newLids there
1431+
newLid = Vect_write_line( map(), type, mPoints, mCats );
13481432
// fid may be new (negative) or old, if this is delete undo
13491433
int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
13501434

@@ -1356,50 +1440,19 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
13561440
mLayer->map()->oldLids()[newLid] = oldLid;
13571441
QgsDebugMsg( QString( "newLids : %1 -> %2" ).arg( oldLid ).arg( newLid ) );
13581442
mLayer->map()->newLids()[oldLid] = newLid;
1443+
}
1444+
mLayer->map()->unlockReadWrite();
13591445

1360-
if ( FID_IS_NEW( fid ) )
1361-
{
1362-
// Set topo symbol attribute
1363-
int symbol = mLayer->map()->topoSymbol( newLid );
1364-
QgsDebugMsg( QString( "symbol = %1" ).arg( symbol ) );
1365-
// TODO attribute index
1366-
int idx = mLayer->fields().size() - 1;
1367-
QgsFeatureMap & addedFeatures = const_cast<QgsFeatureMap&>( mEditBuffer->addedFeatures() );
1368-
addedFeatures[fid].setAttribute( idx, QVariant( symbol ) );
1369-
1370-
QgsWKBTypes::Type wkbType = QgsWKBTypes::flatType( geometry->wkbType() );
1371-
if ( wkbType == QgsWKBTypes::Polygon )
1372-
{
1373-
// change polygon to linestring
1374-
const QgsPolygonV2* polygon = dynamic_cast<const QgsPolygonV2*>( addedFeatures[fid].geometry()->geometry() );
1375-
if ( polygon )
1376-
{
1377-
QgsLineStringV2* lineString = polygon->exteriorRing()->curveToLine();
1378-
addedFeatures[fid].setGeometry( new QgsGeometry( lineString ) );
1379-
}
1380-
// TODO: create also centroid and add it to undo
1381-
}
1382-
1383-
if ( newCat > 0 )
1384-
{
1385-
if ( mLayer->hasTable() )
1386-
{
1387-
addedFeatures[fid].setAttribute( mLayer->keyColumn(), newCat );
1388-
}
1389-
else
1390-
{
1391-
addedFeatures[fid].setAttribute( 0, newCat );
1392-
}
1393-
mLayer->map()->newCats()[fid] = newCat;
1394-
QgsDebugMsg( QString( "newCats[%1] = %2" ).arg( fid ).arg( newCat ) );
1395-
}
1396-
}
1446+
QgsDebugMsg( QString( "newLine = %1" ).arg( newLid ) );
13971447

1398-
if ( type == GV_BOUNDARY || type == GV_CENTROID )
1399-
{
1400-
setAddedFeaturesSymbol();
1401-
}
1448+
if ( mCidxFieldIndex == -1 && type != GV_BOUNDARY )
1449+
{
1450+
// first feature in this layer
1451+
mCidxFieldIndex = Vect_cidx_get_field_index( map(), mLayerField );
1452+
QgsDebugMsg( QString( "new mCidxFieldIndex = %1" ).arg( mCidxFieldIndex ) );
14021453
}
1454+
1455+
setAddedFeaturesSymbol();
14031456
}
14041457
}
14051458

@@ -1408,48 +1461,101 @@ void QgsGrassProvider::onFeatureDeleted( QgsFeatureId fid )
14081461
QgsDebugMsg( QString( "fid = %1" ).arg( fid ) );
14091462

14101463
int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
1464+
int cat = QgsGrassFeatureIterator::catFromFid( fid );
14111465
int realLine = oldLid;
1466+
int realCat = cat;
14121467
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
14131468
{
14141469
realLine = mLayer->map()->newLids().value( oldLid );
14151470
}
1416-
QgsDebugMsg( QString( "fid = %1 oldLid = %2 realLine = %3" ).arg( fid ).arg( oldLid ).arg( realLine ) );
1417-
1418-
// store only the first original geometry if it is not new feature, changed geometries are stored in the buffer
1419-
if ( oldLid > 0 && !mLayer->map()->oldGeometries().contains( oldLid ) )
1471+
if ( mLayer->map()->newCats().contains( fid ) )
14201472
{
1421-
QgsAbstractGeometryV2 *geometry = mLayer->map()->lineGeometry( oldLid );
1422-
if ( geometry )
1423-
{
1424-
QgsDebugMsg( QString( "save old geometry of oldLid = %1" ).arg( oldLid ) );
1425-
mLayer->map()->oldGeometries().insert( oldLid, geometry );
1426-
}
1427-
else
1428-
{
1429-
QgsDebugMsg( QString( "cannot read geometry of oldLid = %1" ).arg( oldLid ) );
1430-
}
1473+
realCat = mLayer->map()->newCats().value( fid );
14311474
}
14321475

1476+
QgsDebugMsg( QString( "fid = %1 oldLid = %2 realLine = %3 cat = %4 realCat = %5" )
1477+
.arg( fid ).arg( oldLid ).arg( realLine ).arg( cat ).arg( realCat ) );
1478+
14331479
int type = 0;
14341480
mLayer->map()->lockReadWrite();
14351481
G_TRY
14361482
{
1437-
type = Vect_read_line( map(), 0, 0, realLine ); // to know if symbols have to be updated
1438-
1439-
Vect_delete_line( map(), realLine );
1440-
// oldLids are maping to the very first, original version (used by undo)
1441-
int oldestLid = oldLid;
1442-
if ( mLayer->map()->oldLids().contains( oldLid ) )
1483+
int type = readLine( mPoints, mCats, realLine );
1484+
if ( type <= 0 )
14431485
{
1444-
oldestLid = mLayer->map()->oldLids().value( oldLid );
1486+
QgsDebugMsg( "cannot read line" );
1487+
}
1488+
else
1489+
{
1490+
// store only the first original geometry if it is not new feature, changed geometries are stored in the buffer
1491+
if ( oldLid > 0 && !mLayer->map()->oldGeometries().contains( oldLid ) )
1492+
{
1493+
QgsAbstractGeometryV2 *geometry = mLayer->map()->lineGeometry( oldLid );
1494+
if ( geometry )
1495+
{
1496+
QgsDebugMsg( QString( "save old geometry of oldLid = %1" ).arg( oldLid ) );
1497+
mLayer->map()->oldGeometries().insert( oldLid, geometry );
1498+
mLayer->map()->oldTypes().insert( oldLid, type );
1499+
}
1500+
else
1501+
{
1502+
QgsDebugMsg( QString( "cannot read geometry of oldLid = %1" ).arg( oldLid ) );
1503+
}
1504+
}
1505+
1506+
if ( realCat > 0 )
1507+
{
1508+
if ( Vect_field_cat_del( mCats, mLayerField, realCat ) == 0 )
1509+
{
1510+
// should not happen
1511+
QgsDebugMsg( "the line does not have old category" );
1512+
}
1513+
}
1514+
QgsDebugMsg( QString( "mCats->n_cats = %1" ).arg( mCats->n_cats ) );
1515+
if ( mCats->n_cats > 0 )
1516+
{
1517+
QgsDebugMsg( "the line has more cats -> rewrite" );
1518+
int newLid = rewriteLine( realLine, type, mPoints, mCats );
1519+
Q_UNUSED( newLid )
1520+
}
1521+
else
1522+
{
1523+
QgsDebugMsg( "no more cats on the line -> delete" );
1524+
1525+
Vect_delete_line( map(), realLine );
1526+
// oldLids are maping to the very first, original version (used by undo)
1527+
int oldestLid = oldLid;
1528+
if ( mLayer->map()->oldLids().contains( oldLid ) )
1529+
{
1530+
oldestLid = mLayer->map()->oldLids().value( oldLid );
1531+
}
1532+
QgsDebugMsg( QString( "oldLid = %1 oldestLid = %2" ).arg( oldLid ).arg( oldestLid ) );
1533+
QgsDebugMsg( QString( "newLids : %1 -> 0" ).arg( oldestLid ) );
1534+
mLayer->map()->newLids()[oldestLid] = 0;
1535+
}
1536+
1537+
// Delete record if orphan
1538+
if ( realCat > 0 )
1539+
{
1540+
QString error;
1541+
bool orphan = mLayer->isOrphan( realCat, error );
1542+
QgsDebugMsg( QString( "orphan = %1 error = %2" ).arg( orphan ).arg( error ) );
1543+
if ( orphan && error.isEmpty() )
1544+
{
1545+
QgsDebugMsg( QString( "realCat = %1 is orphan -> delete record" ).arg( realCat ) );
1546+
error.clear();
1547+
mLayer->deleteAttribute( realCat, error );
1548+
if ( !error.isEmpty() )
1549+
{
1550+
QgsGrass::warning( tr( "Cannot delete orphan record with cat %1" ).arg( realCat ) );
1551+
}
1552+
}
1553+
}
14451554
}
1446-
QgsDebugMsg( QString( "oldLid = %1 oldestLid = %2" ).arg( oldLid ).arg( oldestLid ) );
1447-
QgsDebugMsg( QString( "newLids : %1 -> 0" ).arg( oldestLid ) );
1448-
mLayer->map()->newLids()[oldestLid] = 0;
14491555
}
14501556
G_CATCH( QgsGrass::Exception &e )
14511557
{
1452-
QgsDebugMsg( QString( "Cannot delete line : %1" ).arg( e.what() ) );
1558+
QgsDebugMsg( QString( "Cannot rewrite/delete line : %1" ).arg( e.what() ) );
14531559
}
14541560
mLayer->map()->unlockReadWrite();
14551561

@@ -1484,6 +1590,7 @@ void QgsGrassProvider::onGeometryChanged( QgsFeatureId fid, QgsGeometry &geom )
14841590
{
14851591
QgsDebugMsg( QString( "save old geometry of oldLid = %1" ).arg( oldLid ) );
14861592
mLayer->map()->oldGeometries().insert( oldLid, geometry );
1593+
mLayer->map()->oldTypes().insert( oldLid, type );
14871594
}
14881595
else
14891596
{

‎src/providers/grass/qgsgrassvectormap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
7878
QHash<int, int> & oldLids() { return mOldLids; }
7979
QHash<int, int> & newLids() { return mNewLids; }
8080
QHash<int, QgsAbstractGeometryV2*> & oldGeometries() { return mOldGeometries; }
81+
QHash<int, int> & oldTypes() { return mOldTypes; }
8182
QHash<int, int> & newCats() { return mNewCats; }
8283

8384
/** Get geometry of line.
@@ -186,6 +187,8 @@ class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
186187
QHash<int, int> mNewLids;
187188
// Hash of original lines' geometries of lines which were changed, keys are GRASS lid
188189
QHash<int, QgsAbstractGeometryV2*> mOldGeometries;
190+
// Hash of original lines' geometries GRASS types of lines which were changed, keys are GRASS lid
191+
QHash<int, int> mOldTypes;
189192
// New categories attached to new features or old features without category
190193
// fid -> cat, the fid may be old fid without category or new (negative) feature id
191194
QHash<int, int> mNewCats;

‎src/providers/grass/qgsgrassvectormaplayer.cpp

Lines changed: 114 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -481,17 +481,16 @@ void QgsGrassVectorMapLayer::closeEdit()
481481

482482
QVariant QgsGrassVectorMapLayer::attribute( int cat, int index )
483483
{
484+
// It may happen that the table exists but record for the cat is missing
485+
if (( !hasTable() && index == 0 ) || ( hasTable() && index == keyColumn() ) )
486+
{
487+
QgsDebugMsgLevel( QString( "set attribute %1 to cat %2" ).arg( index ).arg( cat ), 3 );
488+
return QVariant( cat );
489+
}
490+
484491
if ( !hasTable() )
485492
{
486-
if ( index == 0 )
487-
{
488-
QgsDebugMsgLevel( QString( "no table, set attribute 0 to cat %1" ).arg( cat ), 3 );
489-
return QVariant( cat );
490-
}
491-
else
492-
{
493-
return QVariant();
494-
}
493+
return QVariant();
495494
}
496495
else
497496
{
@@ -804,25 +803,79 @@ void QgsGrassVectorMapLayer::insertAttributes( int cat, const QgsFeature &featur
804803
{
805804
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
806805

807-
if ( mHasTable )
806+
if ( !mHasTable )
807+
{
808+
error = tr( "no table" );
809+
return;
810+
}
811+
QStringList names;
812+
QStringList values;
813+
814+
names << mFieldInfo->key;
815+
values << QString::number( cat );
816+
817+
if ( feature.isValid() && feature.fields() )
818+
{
819+
// append feature attributes if not null
820+
for ( int i = 0; i < feature.fields()->size(); i++ )
821+
{
822+
QString name = feature.fields()->at( i ).name();
823+
if ( name == mFieldInfo->key )
824+
{
825+
continue;
826+
}
827+
QVariant valueVariant = feature.attributes().value( i );
828+
if ( !valueVariant.isNull() )
829+
{
830+
names << name;
831+
values << quotedValue( valueVariant );
832+
}
833+
}
834+
}
835+
836+
QString query = QString( "INSERT INTO %1 ( %2 ) VALUES ( %3 )" ).arg( mFieldInfo->table ).arg( names.join( ", " ) ).arg( values.join( "," ) );
837+
executeSql( query, error );
838+
if ( error.isEmpty() )
839+
{
840+
QList<QVariant> values;
841+
values.reserve( mAttributeFields.size() );
842+
for ( int i = 0; i < mAttributeFields.size(); ++i )
843+
{
844+
values << QVariant();
845+
}
846+
mAttributes[cat] = values;
847+
}
848+
}
849+
850+
void QgsGrassVectorMapLayer::reinsertAttributes( int cat, QString &error )
851+
{
852+
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
853+
854+
if ( !mHasTable )
855+
{
856+
error = tr( "no table" );
857+
return;
858+
}
859+
860+
if ( mAttributes.contains( cat ) )
808861
{
809862
QStringList names;
810863
QStringList values;
811864

812865
names << mFieldInfo->key;
813866
values << QString::number( cat );
814867

815-
if ( feature.isValid() && feature.fields() )
868+
if ( mAttributes.contains( cat ) )
816869
{
817-
// append feature attributes if not null
818-
for ( int i = 0; i < feature.fields()->size(); i++ )
870+
for ( int i = 0; i < mTableFields.size(); i++ )
819871
{
820-
QString name = feature.fields()->at( i ).name();
872+
QString name = mTableFields.at( i ).name();
821873
if ( name == mFieldInfo->key )
822874
{
823875
continue;
824876
}
825-
QVariant valueVariant = feature.attributes().value( i );
877+
int index = mAttributeFields.indexFromName( name );
878+
QVariant valueVariant = mAttributes.value( cat ).value( index );
826879
if ( !valueVariant.isNull() )
827880
{
828881
names << name;
@@ -833,16 +886,10 @@ void QgsGrassVectorMapLayer::insertAttributes( int cat, const QgsFeature &featur
833886

834887
QString query = QString( "INSERT INTO %1 ( %2 ) VALUES ( %3 )" ).arg( mFieldInfo->table ).arg( names.join( ", " ) ).arg( values.join( "," ) );
835888
executeSql( query, error );
836-
if ( error.isEmpty() )
837-
{
838-
QList<QVariant> values;
839-
values.reserve( mAttributeFields.size() );
840-
for ( int i = 0; i < mAttributeFields.size(); ++i )
841-
{
842-
values << QVariant();
843-
}
844-
mAttributes[cat] = values;
845-
}
889+
}
890+
else
891+
{
892+
QgsDebugMsg( "cat not found in mAttributes -> don't restore" );
846893
}
847894
}
848895

@@ -925,32 +972,15 @@ void QgsGrassVectorMapLayer::deleteAttribute( int cat, QString &error )
925972
executeSql( query, error );
926973
}
927974

928-
void QgsGrassVectorMapLayer::isOrphan( int cat, int &orphan, QString &error )
975+
bool QgsGrassVectorMapLayer::recordExists( int cat, QString &error )
929976
{
930977
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
931-
orphan = false;
932-
933-
// Check first if anothe return "Cannot open database";r line with such cat exists
934-
int fieldIndex = Vect_cidx_get_field_index( mMap->map(), mField );
935-
if ( fieldIndex >= 0 )
936-
{
937-
int t, id;
938-
int ret = Vect_cidx_find_next( mMap->map(), fieldIndex, cat,
939-
GV_POINTS | GV_LINES | GV_FACE, 0, &t, &id );
940-
941-
if ( ret >= 0 )
942-
{
943-
// Category exists
944-
orphan = false;
945-
return;
946-
}
947-
}
948-
978+
bool exists = false;
949979
if ( !mDriver )
950980
{
951981
error = tr( "Driver is not open" );
952982
QgsDebugMsg( error );
953-
return;
983+
return false;
954984
}
955985

956986
QgsDebugMsg( "Database opened -> select record" );
@@ -968,21 +998,49 @@ void QgsGrassVectorMapLayer::isOrphan( int cat, int &orphan, QString &error )
968998
{
969999
error = tr( "Cannot query database: %1" ).arg( query );
9701000
}
971-
972-
int more;
973-
if ( db_fetch( &cursor, DB_NEXT, &more ) != DB_OK )
974-
{
975-
error = tr( "Cannot fetch DB record" );
976-
}
9771001
else
9781002
{
979-
dbValue *value = db_get_column_value( 0 );
980-
int count = db_get_value_int( value );
981-
QgsDebugMsg( QString( "count = %1" ).arg( count ) );
982-
orphan = count == 0;
1003+
int more;
1004+
if ( db_fetch( &cursor, DB_NEXT, &more ) != DB_OK )
1005+
{
1006+
error = tr( "Cannot fetch DB record" );
1007+
}
1008+
else
1009+
{
1010+
dbTable *table = db_get_cursor_table( &cursor );
1011+
dbColumn *column = db_get_table_column( table, 0 );
1012+
dbValue *value = db_get_column_value( column );
1013+
int count = db_get_value_int( value );
1014+
QgsDebugMsg( QString( "count = %1" ).arg( count ) );
1015+
exists = count > 0;
1016+
}
1017+
db_close_cursor( &cursor );
9831018
}
984-
db_close_cursor( &cursor );
9851019
db_free_string( &dbstr );
1020+
return exists;
1021+
}
1022+
1023+
bool QgsGrassVectorMapLayer::isOrphan( int cat, QString &error )
1024+
{
1025+
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
1026+
1027+
1028+
// Check first if anothe return "Cannot open database";r line with such cat exists
1029+
int fieldIndex = Vect_cidx_get_field_index( mMap->map(), mField );
1030+
if ( fieldIndex >= 0 )
1031+
{
1032+
int t, id;
1033+
int ret = Vect_cidx_find_next( mMap->map(), fieldIndex, cat,
1034+
GV_POINTS | GV_LINES | GV_FACE, 0, &t, &id );
1035+
1036+
if ( ret >= 0 )
1037+
{
1038+
QgsDebugMsg( "category exists" );
1039+
return false;
1040+
}
1041+
}
1042+
1043+
return recordExists( cat, error );
9861044
}
9871045

9881046
void QgsGrassVectorMapLayer::changeAttributeValue( int cat, QgsField field, QVariant value, QString &error )

‎src/providers/grass/qgsgrassvectormaplayer.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ class GRASS_LIB_EXPORT QgsGrassVectorMapLayer : public QObject
104104
* @param cat */
105105
void insertAttributes( int cat, const QgsFeature &feature, QString &error );
106106

107+
/** Restore previously deleted table record using data from mAttributes, if exists.
108+
* If there the cat is not in mAttributes, nothing is inserted (to keep previous state).
109+
* @param cat */
110+
void reinsertAttributes( int cat, QString &error );
111+
107112
/** Update existing record by values from feature.
108113
* @param cat
109114
* @param nullValues override all values, if false, only non empty values are used for update
@@ -115,13 +120,19 @@ class GRASS_LIB_EXPORT QgsGrassVectorMapLayer : public QObject
115120
*/
116121
void deleteAttribute( int cat, QString &error );
117122

118-
/** Check if a database row exists and it is orphan (no more lines with
119-
* that category)
123+
/** Check if a database row exists
124+
* @param cat
125+
* @param error set to error if happens
126+
* @return true if cat is orphan
127+
*/
128+
bool recordExists( int cat, QString &error );
129+
130+
/** Check if a database row exists and it is orphan (no more lines with that category)
120131
* @param cat
121-
* @param orphan set to true if a record exits and it is orphan
122-
* @return empty string or error message
132+
* @param error set to error if happens
133+
* @return true if cat is orphan
123134
*/
124-
void isOrphan( int cat, int &orphan, QString &error );
135+
bool isOrphan( int cat, QString &error );
125136

126137
/** Create table and link vector to this table
127138
* @param fields fields to be created without cat (id) field

0 commit comments

Comments
 (0)
Please sign in to comment.