Skip to content

Commit

Permalink
[GRASS] enable to attache attributes to geom without cat, fixes #13739
Browse files Browse the repository at this point in the history
  • Loading branch information
blazek committed Nov 6, 2015
1 parent 9f3bd1d commit 5f3954a
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/providers/grass/CMakeLists.txt
Expand Up @@ -46,6 +46,7 @@ MACRO(ADD_GRASSLIB GRASS_BUILD_VERSION)
../qgsgrassoptions.cpp
../qgsgrassprovider.cpp
../qgsgrassrasterprovider.cpp
../qgsgrassundocommand.cpp
../qgsgrassvector.cpp
../qgsgrassvectormap.cpp
../qgsgrassvectormaplayer.cpp
Expand Down
27 changes: 23 additions & 4 deletions src/providers/grass/qgsgrassfeatureiterator.cpp
Expand Up @@ -411,6 +411,7 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
}
else // standard layer
{
QgsDebugMsgLevel( "standard layer", 3 );
if ( mNextCidx >= mSource->mLayer->cidxFieldNumCats() )
{
break;
Expand All @@ -423,10 +424,16 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
QgsDebugMsg( QString( "cidxFieldIndex %1 out of range (0,%2)" ).arg( cidxFieldIndex ).arg( numFields - 1 ) );
break;
}
#if 0
// debug
Vect_topo_dump( mSource->map(), stderr );
Vect_cidx_dump( mSource->map(), stderr );
#endif
Vect_cidx_get_cat_by_index( mSource->map(), cidxFieldIndex, mNextCidx++, &tmpCat, &tmpType, &tmpLid );
// Warning: selection array is only of type line/area of current layer -> check type first
if ( !( tmpType & mSource->mGrassType ) )
{
QgsDebugMsgLevel( QString( "tmpType = %1 does not match mGrassType = %2" ).arg( tmpType ).arg( mSource->mGrassType ), 3 );
continue;
}

Expand All @@ -436,6 +443,8 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
lid = tmpLid;
cat = tmpCat;
type = tmpType;
QgsDebugMsgLevel( QString( "lid = %1 field = %2 cat = %3 type= %4" )
.arg( lid ).arg( mSource->mLayer->field() ).arg( cat ).arg( type ), 3 );
featureId = makeFeatureId( lid, cat );
}

Expand All @@ -455,9 +464,11 @@ bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
}
if ( !oldGeometry )
{
if ( lid == 0 || lid > mSource->mLayer->map()->numLines() )
int numLinesOrAreas = ( mSource->mGrassType == GV_AREA && !mSource->mEditing ) ?
mSource->mLayer->map()->numAreas() : mSource->mLayer->map()->numLines();
if ( lid == 0 || lid > numLinesOrAreas )
{
QgsDebugMsg( QString( "lid = %1 -> close" ).arg( lid ) );
QgsDebugMsg( QString( "lid = %1 > numLinesOrAreas = %2 -> close" ).arg( lid ).arg( numLinesOrAreas ) );
close();
mSource->mLayer->map()->unlockReadWrite();
return false; // No more features
Expand Down Expand Up @@ -651,7 +662,15 @@ int QgsGrassFeatureIterator::catFromFid( QgsFeatureId fid )

QVariant QgsGrassFeatureIterator::nonEditableValue( int layerNumber )
{
return tr( "<not editable (layer %1)>" ).arg( layerNumber );
if ( layerNumber > 0 )
{
return tr( "<not editable (layer %1)>" ).arg( layerNumber );
}
else
{
// attributes of features without cat (layer = 0) may be edited -> cat created
return QVariant();
}
}

void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature, QgsGrassVectorMap::TopoSymbol symbol )
Expand Down Expand Up @@ -711,7 +730,7 @@ void QgsGrassFeatureIterator::setFeatureAttributes( int cat, QgsFeature *feature
{
value = QVariant( cat );
}
else
else if ( layerNumber > 0 )
{
value = nonEditableValue( layerNumber );
}
Expand Down
64 changes: 55 additions & 9 deletions src/providers/grass/qgsgrassprovider.cpp
Expand Up @@ -36,6 +36,7 @@
#include "qgsgrassprovider.h"
#include "qgsgrassfeatureiterator.h"
#include "qgsgrassvector.h"
#include "qgsgrassundocommand.h"

#include "qgsapplication.h"
#include "qgscoordinatereferencesystem.h"
Expand Down Expand Up @@ -797,7 +798,8 @@ int QgsGrassProvider::rewriteLine( int oldLid, int type, struct line_pnts *Point
oldestLid = mLayer->map()->oldLids().value( oldLid );
}

QgsDebugMsg( QString( "oldLid = %1 oldestLid = %2 newLine = %3" ).arg( oldLid ).arg( oldestLid ).arg( newLid ) );
QgsDebugMsg( QString( "oldLid = %1 oldestLid = %2 newLine = %3 numLines = %4" )
.arg( oldLid ).arg( oldestLid ).arg( newLid ).arg( mLayer->map()->numLines() ) );
QgsDebugMsg( QString( "oldLids : %1 -> %2" ).arg( newLid ).arg( oldestLid ) );
mLayer->map()->oldLids()[newLid] = oldestLid;
QgsDebugMsg( QString( "newLids : %1 -> %2" ).arg( oldestLid ).arg( newLid ) );
Expand Down Expand Up @@ -1725,7 +1727,7 @@ void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const
int cat = QgsGrassFeatureIterator::catFromFid( fid );
QgsDebugMsg( QString( "layerField = %1" ).arg( layerField ) );

if ( !FID_IS_NEW( fid ) && layerField != mLayerField )
if ( !FID_IS_NEW( fid ) && ( layerField > 0 && layerField != mLayerField ) )
{
QgsDebugMsg( "changing attributes in different layer is not allowed" );
// reset the value
Expand Down Expand Up @@ -1802,6 +1804,7 @@ void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const
mLayer->map()->lockReadWrite();
int newLid = rewriteLine( realLine, type, mPoints, mCats );
Q_UNUSED( newLid )
mLayer->map()->newCats()[fid] = newCat;

// TODO: - store the new cat somewhere for cats mapping
// - insert record if does not exist
Expand All @@ -1813,15 +1816,27 @@ void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const
}
else
{

int undoIndex = mEditLayer->undoStack()->index();
QgsDebugMsg( QString( "undoIndex = %1" ).arg( undoIndex ) );
if ( realCat > 0 )
{
QString error;
bool recordExists = mLayer->recordExists( realCat, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( error );
}
error.clear();
mLayer->changeAttributeValue( realCat, field, value, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( error );
}
if ( !recordExists )
{
mLayer->map()->undoCommands()[undoIndex]
<< new QgsGrassUndoCommandChangeAttribute( this, fid, realLine, mLayerField, realCat, false, true );
}
}
else
{
Expand All @@ -1837,17 +1852,26 @@ void QgsGrassProvider::onAttributeValueChanged( QgsFeatureId fid, int idx, const
Vect_cat_set( mCats, mLayerField, newCat );
mLayer->map()->lockReadWrite();
int newLid = rewriteLine( realLine, type, mPoints, mCats );
Q_UNUSED( newLid )
Q_UNUSED( newLid );
mLayer->map()->newCats()[fid] = newCat;

// TODO: - store the new cat somewhere for cats mapping
QString error;
bool recordExists = mLayer->recordExists( newCat, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( error );
}
error.clear();
// it does insert new record if it doesn't exist
mLayer->changeAttributeValue( newCat, field, value, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( error );
}

mLayer->map()->undoCommands()[undoIndex]
<< new QgsGrassUndoCommandChangeAttribute( this, fid, newLid, mLayerField, newCat, true, !recordExists );

mLayer->map()->unlockReadWrite();
}
}
Expand Down Expand Up @@ -1933,12 +1957,33 @@ void QgsGrassProvider::setAddedFeaturesSymbol()
}
}

void QgsGrassProvider::onUndoIndexChanged( int index )
void QgsGrassProvider::onUndoIndexChanged( int currentIndex )
{
Q_UNUSED( index )
QgsDebugMsg( QString( "index = %1" ).arg( index ) );
}
QgsDebugMsg( QString( "currentIndex = %1" ).arg( currentIndex ) );
// multiple commands maybe undone with single undoIndexChanged signal
QList<int> indexes = mLayer->map()->undoCommands().keys();
qSort( indexes );
for ( int i = indexes.size() - 1; i >= 0; i-- )
{
int index = indexes[i];
if ( index < currentIndex )
{
break;
}
QgsDebugMsg( QString( "index = %1" ).arg( index ) );
if ( mLayer->map()->undoCommands().contains( index ) )
{
QgsDebugMsg( QString( "%1 undo commands" ).arg( mLayer->map()->undoCommands()[index].size() ) );

for ( int j = 0; j < mLayer->map()->undoCommands()[index].size(); j++ )
{
mLayer->map()->undoCommands()[index][j]->undo();
delete mLayer->map()->undoCommands()[index][j];
}
mLayer->map()->undoCommands().remove( index );
}
}
}

bool QgsGrassProvider::addAttributes( const QList<QgsField> &attributes )
{
Expand All @@ -1959,6 +2004,7 @@ bool QgsGrassProvider::deleteAttributes( const QgsAttributeIds &attributes )
void QgsGrassProvider::onBeforeCommitChanges()
{
QgsDebugMsg( "entered" );
mLayer->map()->clearUndoCommands();
}

void QgsGrassProvider::onBeforeRollBack()
Expand Down
3 changes: 2 additions & 1 deletion src/providers/grass/qgsgrassprovider.h
Expand Up @@ -391,7 +391,7 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
void onBeforeCommitChanges();
void onBeforeRollBack();
void onEditingStopped();
void onUndoIndexChanged( int index );
void onUndoIndexChanged( int currentIndex );

void onDataChanged();

Expand Down Expand Up @@ -486,6 +486,7 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider

friend class QgsGrassFeatureSource;
friend class QgsGrassFeatureIterator;
friend class QgsGrassUndoCommandChangeAttribute;
};

#endif // QGSGRASSPROVIDER_H
76 changes: 76 additions & 0 deletions src/providers/grass/qgsgrassundocommand.cpp
@@ -0,0 +1,76 @@
/***************************************************************************
qgsgrassundocommand.cpp
-------------------
begin : November, 2015
copyright : (C) 2015 by Radim Blazek
email : radim.blazek@gmail.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsgrassundocommand.h"

#include "qgsgrassprovider.h"
#include "qgslogger.h"

QgsGrassUndoCommandChangeAttribute::QgsGrassUndoCommandChangeAttribute( QgsGrassProvider * provider, int fid, int lid, int field, int cat, bool deleteCat, bool deleteRecord )
: mProvider( provider )
, mFid(fid)
, mLid(lid)
, mField(field)
, mCat(cat)
, mDeleteCat(deleteCat)
, mDeleteRecord( deleteRecord )
{
}

void QgsGrassUndoCommandChangeAttribute::undo()
{
QgsDebugMsg( QString("mLid = %1 mField = %2, mCat = %3").arg(mLid).arg(mField).arg(mCat) );
if ( mDeleteCat )
{
int realLine = mLid;
if ( mProvider->mLayer->map()->newLids().contains( mLid ) )
{
realLine = mProvider->mLayer->map()->newLids().value( mLid );
}
QgsDebugMsg( QString("realLine = %1").arg(realLine) );

int type = mProvider->readLine( mProvider->mPoints, mProvider->mCats, realLine );
if ( type <= 0 )
{
QgsDebugMsg( "cannot read line" );
}
else
{
if ( Vect_field_cat_del( mProvider->mCats, mProvider->mLayerField, mCat ) == 0 )
{
// should not happen
QgsDebugMsg( "the line does not have the category" );
}
else
{
mProvider->mLayer->map()->lockReadWrite();
int newLid = mProvider->rewriteLine( realLine, type, mProvider->mPoints, mProvider->mCats );
Q_UNUSED( newLid );
mProvider->mLayer->map()->newCats().remove(mFid);
mProvider->mLayer->map()->unlockReadWrite();
}
}
}
if ( mDeleteRecord )
{
QString error;
mProvider->mLayer->deleteAttribute( mCat, error );
if ( !error.isEmpty() )
{
QgsGrass::warning( error );
}
}
}

46 changes: 46 additions & 0 deletions src/providers/grass/qgsgrassundocommand.h
@@ -0,0 +1,46 @@
/***************************************************************************
qgsgrassundocommand.h
-------------------
begin : November, 2015
copyright : (C) 2015 by Radim Blazek
email : radim.blazek@gmail.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSGRASSUNDOCOMMAND_H
#define QGSGRASSUNDOCOMMAND_H

class QgsGrassProvider;

class GRASS_LIB_EXPORT QgsGrassUndoCommand
{
public:
virtual ~QgsGrassUndoCommand() {}
virtual void undo() {}
};

// This class is used to store information that a new cat was attached to a line
// when attribute was changed.
class GRASS_LIB_EXPORT QgsGrassUndoCommandChangeAttribute : public QgsGrassUndoCommand
{
public:
QgsGrassUndoCommandChangeAttribute( QgsGrassProvider * provider, int fid, int lid, int field, int cat, bool deleteCat, bool deleteRecord );
~QgsGrassUndoCommandChangeAttribute() {}
void undo() override;
private:
QgsGrassProvider *mProvider;
int mFid;
int mLid;
int mField;
int mCat;
bool mDeleteCat;
bool mDeleteRecord;
};

#endif // QGSGRASSUNDOCOMMAND_H

0 comments on commit 5f3954a

Please sign in to comment.