mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
[GRASS] new feature attributes fixes
This commit is contained in:
parent
d6b8b3c022
commit
c531b2dbaf
@ -1132,11 +1132,26 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
|
||||
if ( FID_IS_NEW( fid ) )
|
||||
{
|
||||
// add new category
|
||||
// TODO: add category also to boundary if user defined at least one attribute?
|
||||
if ( type != GV_BOUNDARY )
|
||||
{
|
||||
// TODO: redo of deleted new features - save new cats somewhere,
|
||||
// resetting fid probably is not possible because it is stored in undo commands and used in buffer maps
|
||||
|
||||
// It may be that user manualy entered cat value
|
||||
const QgsFeature &feature = mEditBuffer->addedFeatures()[fid];
|
||||
int catIndex = feature.fields()->indexFromName( mLayer->keyColumnName() );
|
||||
if ( catIndex != -1 )
|
||||
{
|
||||
QVariant userCatVariant = feature.attributes().value( catIndex );
|
||||
if ( !userCatVariant.isNull() )
|
||||
{
|
||||
newCat = userCatVariant.toInt();
|
||||
QgsDebugMsg( QString( "user defined newCat = %1" ).arg( newCat ) );
|
||||
}
|
||||
}
|
||||
if ( newCat == 0 )
|
||||
{
|
||||
QgsDebugMsg( QString( "get new cat for mCidxFieldIndex = %1" ).arg( mCidxFieldIndex ) );
|
||||
if ( mCidxFieldIndex == -1 )
|
||||
{
|
||||
@ -1147,16 +1162,84 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
|
||||
{
|
||||
newCat = cidxGetMaxCat( mCidxFieldIndex ) + 1;
|
||||
}
|
||||
}
|
||||
QgsDebugMsg( QString( "newCat = %1" ).arg( newCat ) );
|
||||
Vect_cat_set( cats, mLayerField, newCat );
|
||||
QString error;
|
||||
mLayer->insertAttributes( newCat, error );
|
||||
|
||||
// if the cat is user defined, the record may alredy exist
|
||||
if ( mLayer->attributes().contains( newCat ) )
|
||||
{
|
||||
QgsDebugMsg( "record exists" );
|
||||
// TODO: open warning dialog?
|
||||
// For now we are expecting that user knows what he is doing.
|
||||
// We update existing record by non null values and set feature null values to existing values
|
||||
mLayer->updateAttributes( newCat, feature, error ); // also updates feature by existing non null attributes
|
||||
|
||||
// There may be other new features with the same cat which we have to update
|
||||
QgsFeatureMap& addedFeatures = const_cast<QgsFeatureMap&>( mEditBuffer->addedFeatures() );
|
||||
Q_FOREACH ( QgsFeatureId addedFid, addedFeatures.keys() )
|
||||
{
|
||||
if ( addedFid == fid )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int addedCat = mLayer->map()->newCats().value( addedFid ); // it should always exist
|
||||
QgsDebugMsg( QString( "addedFid = %1 addedCat = %2" ).arg( addedFid ).arg( addedCat ) );
|
||||
if ( addedCat == newCat )
|
||||
{
|
||||
QgsFeature addedFeature = addedFeatures[addedFid];
|
||||
// TODO: better to update form mLayer->attributes() ?
|
||||
for ( int i = 0; i < feature.fields()->size(); i++ )
|
||||
{
|
||||
if ( feature.fields()->field( i ).name() == QgsGrassVectorMap::topoSymbolFieldName() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( feature.attributes()[i].isNull() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
addedFeature.setAttribute( i, feature.attributes()[i] );
|
||||
}
|
||||
addedFeatures[addedFid] = addedFeature;
|
||||
}
|
||||
}
|
||||
|
||||
// Update all changed attributes
|
||||
// TODO: table does not get refreshed immediately
|
||||
QgsChangedAttributesMap &changedAttributes = const_cast<QgsChangedAttributesMap &>( mEditBuffer->changedAttributeValues() );
|
||||
Q_FOREACH ( QgsFeatureId changedFid, changedAttributes.keys() )
|
||||
{
|
||||
int changedCat = QgsGrassFeatureIterator::catFromFid( changedFid );
|
||||
int realChangedCat = changedCat;
|
||||
if ( mLayer->map()->newCats().contains( changedFid ) )
|
||||
{
|
||||
realChangedCat = mLayer->map()->newCats().value( changedFid );
|
||||
}
|
||||
QgsDebugMsg( QString( "changedFid = %1 changedCat = %2 realChangedCat = %3" )
|
||||
.arg( changedFid ).arg( changedCat ).arg( realChangedCat ) );
|
||||
if ( realChangedCat == newCat )
|
||||
{
|
||||
QgsAttributeMap attributeMap = changedAttributes[changedFid];
|
||||
Q_FOREACH ( int index, attributeMap.keys() )
|
||||
{
|
||||
attributeMap[index] = feature.attributes().value( index );
|
||||
}
|
||||
changedAttributes[changedFid] = attributeMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLayer->insertAttributes( newCat, feature, error );
|
||||
if ( !error.isEmpty() )
|
||||
{
|
||||
QgsGrass::warning( error );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old feature delete undo
|
||||
@ -1228,6 +1311,8 @@ void QgsGrassProvider::onFeatureAdded( QgsFeatureId fid )
|
||||
{
|
||||
addedFeatures[fid].setAttribute( 0, newCat );
|
||||
}
|
||||
mLayer->map()->newCats()[fid] = newCat;
|
||||
QgsDebugMsg( QString( "newCats[%1] = %2" ).arg( fid ).arg( newCat ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1365,11 +1450,17 @@ void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const
|
||||
int oldLid = QgsGrassFeatureIterator::lidFromFid( fid );
|
||||
int cat = QgsGrassFeatureIterator::catFromFid( fid );
|
||||
int realLine = oldLid;
|
||||
int realCat = cat;
|
||||
if ( mLayer->map()->newLids().contains( oldLid ) ) // if it was changed already
|
||||
{
|
||||
realLine = mLayer->map()->newLids().value( oldLid );
|
||||
}
|
||||
QgsDebugMsg( QString( "fid = %1 oldLid = %2 realLine = %3 cat = %4" ).arg( fid ).arg( oldLid ).arg( realLine ).arg( cat ) );
|
||||
if ( mLayer->map()->newCats().contains( 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 ) );
|
||||
|
||||
// index is for current fields
|
||||
if ( idx < 0 || idx > mEditLayer->fields().size() )
|
||||
@ -1379,10 +1470,10 @@ void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const
|
||||
}
|
||||
QgsField field = mEditLayer->fields()[idx];
|
||||
|
||||
if ( cat > 0 )
|
||||
if ( realCat > 0 )
|
||||
{
|
||||
QString error;
|
||||
mLayer->changeAttributeValue( cat, field, value, error );
|
||||
mLayer->changeAttributeValue( realCat, field, value, error );
|
||||
if ( !error.isEmpty() )
|
||||
{
|
||||
QgsGrass::warning( error );
|
||||
|
@ -318,6 +318,7 @@ bool QgsGrassVectorMap::closeEdit( bool newMap )
|
||||
mOldLids.clear();
|
||||
mNewLids.clear();
|
||||
mOldGeometries.clear();
|
||||
mNewCats.clear();
|
||||
|
||||
// Mapset must be set before Vect_close()
|
||||
QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() );
|
||||
|
@ -78,6 +78,7 @@ class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
|
||||
QHash<int, int> & oldLids() { return mOldLids; }
|
||||
QHash<int, int> & newLids() { return mNewLids; }
|
||||
QHash<int, QgsAbstractGeometryV2*> & oldGeometries() { return mOldGeometries; }
|
||||
QHash<int, int> & newCats() { return mNewCats; }
|
||||
|
||||
/** Get geometry of line.
|
||||
* @return geometry (point,line or polygon(GV_FACE)) or 0 */
|
||||
@ -183,6 +184,9 @@ class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
|
||||
QHash<int, int> mNewLids;
|
||||
// Hash of original lines' geometries of lines which were changed, keys are GRASS lid
|
||||
QHash<int, QgsAbstractGeometryV2*> mOldGeometries;
|
||||
// New categories attached to new features or old features without category
|
||||
// fid -> cat, the fid may be old fid without category or new (negative) feature id
|
||||
QHash<int, int> mNewCats;
|
||||
|
||||
// Mutex used to avoid concurrent read/write, used only in editing mode
|
||||
QMutex mReadWriteMutex;
|
||||
|
@ -772,7 +772,8 @@ void QgsGrassVectorMapLayer::insertCats( QString &error )
|
||||
{
|
||||
int cat;
|
||||
Vect_cidx_get_cat_by_index( map()->map(), cidxIndex, i, &cat, 0, 0 );
|
||||
insertAttributes( cat, error );
|
||||
QgsFeature feature;
|
||||
insertAttributes( cat, feature, error );
|
||||
if ( !error.isEmpty() )
|
||||
{
|
||||
QgsDebugMsg( error );
|
||||
@ -782,13 +783,38 @@ void QgsGrassVectorMapLayer::insertCats( QString &error )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::insertAttributes( int cat, QString &error )
|
||||
void QgsGrassVectorMapLayer::insertAttributes( int cat, const QgsFeature &feature, QString &error )
|
||||
{
|
||||
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
|
||||
|
||||
if ( mHasTable )
|
||||
{
|
||||
QString query = QString( "INSERT INTO %1 ( %2 ) VALUES ( %3 )" ).arg( mFieldInfo->table ).arg( mFieldInfo->key ).arg( cat );
|
||||
QStringList names;
|
||||
QStringList values;
|
||||
|
||||
names << mFieldInfo->key;
|
||||
values << QString::number( cat );
|
||||
|
||||
if ( feature.isValid() && feature.fields() )
|
||||
{
|
||||
// append feature attributes if not null
|
||||
for ( int i = 0; i < feature.fields()->size(); i++ )
|
||||
{
|
||||
QString name = feature.fields()->at( i ).name();
|
||||
if ( name == mFieldInfo->key )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QVariant valueVariant = feature.attributes().value( i );
|
||||
if ( !valueVariant.isNull() )
|
||||
{
|
||||
names << name;
|
||||
values << quotedValue( valueVariant );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString query = QString( "INSERT INTO %1 ( %2 ) VALUES ( %3 )" ).arg( mFieldInfo->table ).arg( names.join( ", " ) ).arg( values.join( "," ) );
|
||||
executeSql( query, error );
|
||||
if ( error.isEmpty() )
|
||||
{
|
||||
@ -802,6 +828,77 @@ void QgsGrassVectorMapLayer::insertAttributes( int cat, QString &error )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::updateAttributes( int cat, const QgsFeature &feature, QString &error, bool nullValues )
|
||||
{
|
||||
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
|
||||
|
||||
if ( !mHasTable )
|
||||
{
|
||||
error = tr( "Table does not exit" );
|
||||
return;
|
||||
}
|
||||
if ( !feature.isValid() || !feature.fields() )
|
||||
{
|
||||
error = tr( "Feature invalid" );
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList updates;
|
||||
QMap<int, QVariant> cacheUpdates;
|
||||
// append feature attributes if not null
|
||||
for ( int i = 0; i < feature.fields()->size(); i++ )
|
||||
{
|
||||
QString name = feature.fields()->at( i ).name();
|
||||
if ( name == mFieldInfo->key )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QVariant valueVariant = feature.attributes().value( i );
|
||||
|
||||
int cacheIndex = mAttributeFields.indexFromName( name );
|
||||
|
||||
if ( valueVariant.isNull() && !nullValues )
|
||||
{
|
||||
// update feature null values by existing values
|
||||
if ( cacheIndex != -1 )
|
||||
{
|
||||
feature.attributes()[i] = mAttributes[cat][cacheIndex];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
updates << name + " = " + quotedValue( valueVariant );
|
||||
|
||||
|
||||
if ( cacheIndex == -1 )
|
||||
{
|
||||
QgsDebugMsg( "cannot find cache index for attribute " + name );
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheUpdates[cacheIndex] = valueVariant;
|
||||
}
|
||||
}
|
||||
|
||||
if ( updates.isEmpty() )
|
||||
{
|
||||
QgsDebugMsg( "nothing to update" );
|
||||
return;
|
||||
}
|
||||
|
||||
QString query = QString( "UPDATE %1 SET %2 WHERE %3 = %4" ).arg( mFieldInfo->table )
|
||||
.arg( updates.join( ", " ) ).arg( mFieldInfo->key ).arg( cat );
|
||||
|
||||
executeSql( query, error );
|
||||
if ( error.isEmpty() )
|
||||
{
|
||||
Q_FOREACH ( int index, cacheUpdates.keys() )
|
||||
{
|
||||
mAttributes[cat][index] = cacheUpdates[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::deleteAttribute( int cat, QString &error )
|
||||
{
|
||||
QgsDebugMsg( QString( "mField = %1 cat = %2" ).arg( mField ).arg( cat ) );
|
||||
@ -913,5 +1010,7 @@ void QgsGrassVectorMapLayer::changeAttributeValue( int cat, QgsField field, QVar
|
||||
}
|
||||
db_free_string( &dbstr );
|
||||
|
||||
// TODO: update cached attributes because another feature may share the same cat
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <QPair>
|
||||
|
||||
#include "qgsfield.h"
|
||||
#include "qgsfeature.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@ -65,6 +66,7 @@ class GRASS_LIB_EXPORT QgsGrassVectorMapLayer : public QObject
|
||||
|
||||
bool hasTable() { return mHasTable; }
|
||||
int keyColumn() { return mKeyColumn; }
|
||||
QString keyColumnName() { return mFieldInfo ? mFieldInfo->key : QString(); }
|
||||
QList< QPair<double, double> > minMax() { return mMinMax; }
|
||||
int userCount() { return mUsers; }
|
||||
void addUser();
|
||||
@ -96,7 +98,13 @@ class GRASS_LIB_EXPORT QgsGrassVectorMapLayer : public QObject
|
||||
|
||||
/** Insert new attributes to the table (it does not check if attributes already exists)
|
||||
* @param cat */
|
||||
void insertAttributes( int cat, QString &error );
|
||||
void insertAttributes( int cat, const QgsFeature &feature, QString &error );
|
||||
|
||||
/** Update existing record by values from feature.
|
||||
* @param cat
|
||||
* @param nullValues override all values, if false, only non empty values are used for update
|
||||
*/
|
||||
void updateAttributes( int cat, const QgsFeature &feature, QString &error, bool nullValues = false );
|
||||
|
||||
/** Delete attributes from the table
|
||||
* @param cat
|
||||
|
Loading…
x
Reference in New Issue
Block a user