[FEATURE] attribute editing improvements:

- refactor attribute dialog calls to QgsFeatureAttribute
- add QgsVectorLayer::featureAdded signal
- improve interactive attribute editing in table (adding/deleting
  features, attribute update)
- allow adding of geometryless features
- fix attribute undo/redo

git-svn-id: http://svn.osgeo.org/qgis/trunk@14729 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
jef 2010-11-21 20:09:36 +00:00
parent 2c84b529d9
commit c3c979a0f2
23 changed files with 474 additions and 477 deletions

View File

@ -52,6 +52,19 @@ int QgsAttributeTableDelegate::fieldIdx( const QModelIndex &index ) const
return -1;
}
int QgsAttributeTableDelegate::featureId( const QModelIndex &index ) const
{
const QgsAttributeTableModel *tm = qobject_cast<const QgsAttributeTableModel *>( index.model() );
if ( tm )
return tm->rowToId( index.row() );
const QgsAttributeTableFilterModel *fm = dynamic_cast<const QgsAttributeTableFilterModel *>( index.model() );
if ( fm )
return fm->tableModel()->rowToId( index.row() );
return -1;
}
QWidget *QgsAttributeTableDelegate::createEditor(
QWidget *parent,
@ -87,11 +100,16 @@ void QgsAttributeTableDelegate::setModelData( QWidget *editor, QAbstractItemMode
if ( vl == NULL )
return;
int idx = fieldIdx( index );
int fid = featureId( index );
QVariant value;
if ( !QgsAttributeEditor::retrieveValue( editor, vl, fieldIdx( index ), value ) )
if ( !QgsAttributeEditor::retrieveValue( editor, vl, idx, value ) )
return;
model->setData( index, value );
vl->beginEditCommand( tr( "Attribute changed" ) );
vl->changeAttributeValue( fid, idx, value, true );
vl->endEditCommand();
}
void QgsAttributeTableDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const

View File

@ -32,6 +32,7 @@ class QgsAttributeTableDelegate : public QItemDelegate
QgsVectorLayer *layer( const QAbstractItemModel *model ) const;
int fieldIdx( const QModelIndex &index ) const;
int featureId( const QModelIndex &index ) const;
public:
/** Constructor

View File

@ -34,6 +34,7 @@
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsfieldcalculator.h"
#include "qgsfeatureaction.h"
class QgsAttributeTableDock : public QDockWidget
{
@ -99,6 +100,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
bool canDeleteFeatures = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures;
bool canAddAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes;
bool canDeleteAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteAttributes;
bool canAddFeatures = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures;
mToggleEditingButton->setCheckable( true );
mToggleEditingButton->setChecked( mLayer->isEditable() );
mToggleEditingButton->setEnabled( canChangeAttributes && !mLayer->isReadOnly() );
@ -106,6 +108,8 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
mDeleteSelectedButton->setEnabled( canDeleteFeatures && mLayer->isEditable() );
mAddAttribute->setEnabled( canAddAttributes && mLayer->isEditable() );
mRemoveAttribute->setEnabled( canDeleteAttributes && mLayer->isEditable() );
mAddFeature->setEnabled( canAddFeatures && mLayer->isEditable() && mLayer->geometryType() == QGis::NoGeometry );
mAddFeature->setHidden( !canAddFeatures || mLayer->geometryType() != QGis::NoGeometry );
// info from table to application
connect( this, SIGNAL( editingToggled( QgsMapLayer * ) ), QgisApp::instance(), SLOT( toggleEditing( QgsMapLayer * ) ) );
@ -114,6 +118,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
connect( searchButton, SIGNAL( clicked() ), this, SLOT( search() ) );
connect( mAddFeature, SIGNAL( clicked() ), this, SLOT( addFeature() ) );
connect( mLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelectionFromLayer() ) );
connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( close() ) );
@ -674,10 +679,12 @@ void QgsAttributeTableDialog::editingToggled()
bool canDeleteFeatures = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures;
bool canAddAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes;
bool canDeleteAttributes = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteAttributes;
bool canAddFeatures = mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures;
mOpenFieldCalculator->setEnabled( canChangeAttributes && mLayer->isEditable() );
mDeleteSelectedButton->setEnabled( canDeleteFeatures && mLayer->isEditable() );
mAddAttribute->setEnabled( canAddAttributes && mLayer->isEditable() );
mRemoveAttribute->setEnabled( canDeleteAttributes && mLayer->isEditable() );
mAddFeature->setEnabled( canAddFeatures && mLayer->isEditable() && mLayer->geometryType() == QGis::NoGeometry );
// (probably reload data if user stopped editing - possible revert)
mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
@ -775,9 +782,18 @@ void QgsAttributeTableDialog::on_mRemoveAttribute_clicked()
void QgsAttributeTableDialog::on_mOpenFieldCalculator_clicked()
{
QgsFieldCalculator calc( mLayer );
if ( calc.exec() == QDialog::Accepted )
calc.exec();
}
void QgsAttributeTableDialog::addFeature()
{
if ( !mLayer->isEditable() )
return;
QgsFeature f;
QgsFeatureAction action( tr( "Geometryless feature added" ), f, mLayer, -1, this );
if ( action.addFeature() )
{
// update model - a field has been added or updated
mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
}
}

View File

@ -151,6 +151,11 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
*/
void on_mDeleteSelectedButton_clicked();
/**
* add feature
*/
void addFeature();
void on_mHelpButton_clicked() { QgsContextHelp::run( metaObject()->className() ); }
signals:

View File

@ -60,7 +60,6 @@ bool QgsAttributeTableMemoryModel::featureAtId( int fid )
}
}
#if 0
void QgsAttributeTableMemoryModel::featureDeleted( int fid )
{
QgsDebugMsg( "entered." );
@ -76,7 +75,6 @@ void QgsAttributeTableMemoryModel::featureAdded( int fid )
mFeatureMap.insert( fid, f );
QgsAttributeTableModel::featureAdded( fid );
}
#endif
void QgsAttributeTableMemoryModel::layerDeleted()
{
@ -89,5 +87,5 @@ void QgsAttributeTableMemoryModel::attributeValueChanged( int fid, int idx, cons
{
QgsDebugMsg( "entered." );
mFeatureMap[fid].changeAttribute( idx, value );
reload( index( 0, 0 ), index( rowCount(), columnCount() ) );
QgsAttributeTableModel::attributeValueChanged( fid, idx, value );
}

View File

@ -40,7 +40,6 @@ class QgsAttributeTableMemoryModel : public QgsAttributeTableModel
QgsAttributeTableMemoryModel( QgsVectorLayer *theLayer );
protected slots:
#if 0
/**
* Launched when a feature has been deleted
* @param fid feature id
@ -51,7 +50,6 @@ class QgsAttributeTableMemoryModel : public QgsAttributeTableModel
* @param fid feature id
*/
virtual void featureAdded( int fid );
#endif
/**
* Launched when layer has been deleted
*/

View File

@ -22,14 +22,12 @@
#include "qgisapp.h"
#include "qgsattributeaction.h"
#include "qgsmapcanvas.h"
#include "qgsfeatureaction.h"
#include <QtGui>
#include <QVariant>
#include <limits>
////////////////////////////
// QgsAttributeTableModel //
////////////////////////////
QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayer *theLayer, QObject *parent )
: QAbstractTableModel( parent )
@ -38,67 +36,96 @@ QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayer *theLayer, QObjec
mLayer = theLayer;
loadAttributes();
connect( mLayer, SIGNAL( layerModified( bool ) ), this, SLOT( layerModified( bool ) ) );
//connect(mLayer, SIGNAL(attributeValueChanged(int, int, const QVariant&)), this, SLOT( attributeValueChanged(int, int, const QVariant&)));
//connect(mLayer, SIGNAL(featureDeleted(int)), this, SLOT( featureDeleted(int)));
//connect(mLayer, SIGNAL(featureAdded(int)), this, SLOT( featureAdded(int)));
connect( mLayer, SIGNAL( attributeValueChanged( int, int, const QVariant& ) ), this, SLOT( attributeValueChanged( int, int, const QVariant& ) ) );
connect( mLayer, SIGNAL( featureAdded( int ) ), this, SLOT( featureAdded( int ) ) );
connect( mLayer, SIGNAL( featureDeleted( int ) ), this, SLOT( featureDeleted( int ) ) );
loadLayer();
}
bool QgsAttributeTableModel::featureAtId( int fid ) const
{
return mLayer->featureAtId( fid, mFeat, false, true );
QgsDebugMsg( QString( "loading feature %1" ).arg( fid ) );
if ( fid == std::numeric_limits<int>::min() )
return false;
else
return mLayer->featureAtId( fid, mFeat, false, true );
}
#if 0
void QgsAttributeTableModel::featureDeleted( int fid )
{
QgsDebugMsg( "entered." );
QgsDebugMsg( QString( "deleted fid=%1 => row=%2" ).arg( fid ).arg( idToRow( fid ) ) );
int row = idToRow( fid );
beginRemoveRows( QModelIndex(), row, row );
removeRow( row );
endRemoveRows();
}
bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &parent )
{
QgsDebugMsg( QString( "remove %2 rows at %1" ).arg( row ).arg( count ) );
// clean old references
for ( int i = row; i < row + count; i++ )
{
mIdRowMap.remove( mRowIdMap[ row ] );
mRowIdMap.remove( row );
}
// update maps
int n = mRowIdMap.size() + count;
for ( int i = row + count; i < n; i++ )
{
int id = mRowIdMap[i];
mIdRowMap[ id ] -= count;
mRowIdMap[ i-count ] = id;
mRowIdMap.remove( i );
}
#ifdef QGISDEBUG
int idx = mIdRowMap[fid];
QgsDebugMsg( idx );
QgsDebugMsg( fid );
#endif
QgsDebugMsg( "id->row" );
QHash<int, int>::iterator it;
for ( it = mIdRowMap.begin(); it != mIdRowMap.end(); ++it )
QgsDebugMsg( QString( "%1->%2" ).arg( it.key() ).arg( *it ) );
QgsDebugMsg( "row->id" );
for ( it = mRowIdMap.begin(); it != mRowIdMap.end(); ++it )
QgsDebugMsg( QString( "%1->%2" ).arg( it.key() ).arg( *it ) );
}
void QgsAttributeTableModel::featureAdded( int fid )
{
QgsDebugMsg( "BM feature added" );
++mFeatureCount;
mIdRowMap.insert( fid, mFeatureCount - 1 );
mRowIdMap.insert( mFeatureCount - 1, fid );
QgsDebugMsg( QString( "map sizes:%1, %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ) );
reload( index( 0, 0 ), index( rowCount(), columnCount() ) );
}
#endif
return true;
}
void QgsAttributeTableModel::featureAdded( int fid, bool newOperation )
{
QgsDebugMsg( QString( "feature %1 added (%2, rows %3, ids %4)" ).arg( fid ).arg( newOperation ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ) );
int n = mRowIdMap.size();
if ( newOperation )
beginInsertRows( QModelIndex(), n, n );
mIdRowMap.insert( fid, n );
mRowIdMap.insert( n, fid );
if ( newOperation )
endInsertRows();
reload( index( rowCount() - 1, 0 ), index( rowCount() - 1, columnCount() ) );
}
void QgsAttributeTableModel::attributeAdded( int idx )
{
QgsDebugMsg( "BM attribute added" );
loadLayer();
QgsDebugMsg( QString( "map sizes:%1, %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ) );
QgsDebugMsg( "entered." );
reload( index( 0, 0 ), index( rowCount(), columnCount() ) );
emit modelChanged();
}
void QgsAttributeTableModel::attributeDeleted( int idx )
{
QgsDebugMsg( "BM attribute deleted" );
loadLayer();
QgsDebugMsg( QString( "map sizes:%1, %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ) );
QgsDebugMsg( "entered." );
reload( index( 0, 0 ), index( rowCount(), columnCount() ) );
emit modelChanged();
}
@ -106,28 +133,15 @@ void QgsAttributeTableModel::attributeDeleted( int idx )
void QgsAttributeTableModel::layerDeleted()
{
QgsDebugMsg( "entered." );
mIdRowMap.clear();
mRowIdMap.clear();
QgsDebugMsg( QString( "map sizes:%1, %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ) );
reload( index( 0, 0 ), index( rowCount(), columnCount() ) );
beginRemoveRows( QModelIndex(), 0, rowCount() - 1 );
removeRows( 0, rowCount() );
endRemoveRows();
}
//TODO: check whether caching in data()/setData() doesn't cache old value
void QgsAttributeTableModel::attributeValueChanged( int fid, int idx, const QVariant &value )
{
QgsDebugMsg( "entered." );
reload( index( 0, 0 ), index( rowCount(), columnCount() ) );
}
void QgsAttributeTableModel::layerModified( bool onlyGeometry )
{
if ( onlyGeometry )
return;
loadAttributes();
loadLayer();
emit modelChanged();
emit headerDataChanged( Qt::Horizontal, 0, columnCount() - 1 );
setData( index( idToRow( fid ), mAttributes.indexOf( idx ) ), value, Qt::EditRole );
}
void QgsAttributeTableModel::loadAttributes()
@ -187,26 +201,25 @@ void QgsAttributeTableModel::loadLayer()
{
QgsDebugMsg( "entered." );
QgsFeature f;
bool ins = false, rm = false;
Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
int previousSize = mRowIdMap.size();
beginRemoveRows( QModelIndex(), 0, rowCount() - 1 );
removeRows( 0, rowCount() );
endRemoveRows();
mRowIdMap.clear();
mIdRowMap.clear();
Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
QSettings settings;
int behaviour = settings.value( "/qgis/attributeTableBehaviour", 0 ).toInt();
if ( behaviour == 1 )
{
const QgsFeatureList &features = mLayer->selectedFeatures();
for ( int i = 0; i < features.size(); ++i )
beginInsertRows( QModelIndex(), 0, mLayer->selectedFeatureCount() );
foreach( int fid, mLayer->selectedFeaturesIds() )
{
mRowIdMap.insert( i, features[i].id() );
mIdRowMap.insert( features[i].id(), i );
featureAdded( fid, false );
}
endInsertRows();
}
else
{
@ -219,39 +232,16 @@ void QgsAttributeTableModel::loadLayer()
mLayer->select( mAttributes, rect, false );
QgsFeature f;
for ( int i = 0; mLayer->nextFeature( f ); ++i )
{
mRowIdMap.insert( i, f.id() );
mIdRowMap.insert( f.id(), i );
featureAdded( f.id() );
}
}
if ( previousSize < mRowIdMap.size() )
{
QgsDebugMsg( "ins" );
ins = true;
beginInsertRows( QModelIndex(), previousSize, mRowIdMap.size() - 1 );
}
else if ( previousSize > mRowIdMap.size() )
{
QgsDebugMsg( "rm" );
rm = true;
beginRemoveRows( QModelIndex(), mRowIdMap.size(), previousSize - 1 );
}
Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
// not needed when we have featureAdded signal
mFieldCount = mAttributes.size();
if ( ins )
{
endInsertRows();
QgsDebugMsg( "end ins" );
}
else if ( rm )
{
endRemoveRows();
QgsDebugMsg( "end rm" );
}
}
void QgsAttributeTableModel::swapRows( int a, int b )
@ -442,17 +432,7 @@ bool QgsAttributeTableModel::setData( const QModelIndex &index, const QVariant &
int rowId = rowToId( index.row() );
if ( mFeat.id() == rowId || featureAtId( rowId ) )
{
int fieldId = mAttributes[ index.column()];
disconnect( mLayer, SIGNAL( layerModified( bool ) ), this, SLOT( layerModified( bool ) ) );
mLayer->beginEditCommand( tr( "Attribute changed" ) );
mLayer->changeAttributeValue( rowId, fieldId, value, true );
mLayer->endEditCommand();
mFeat.changeAttribute( fieldId, value );
connect( mLayer, SIGNAL( layerModified( bool ) ), this, SLOT( layerModified( bool ) ) );
mFeat.changeAttribute( mAttributes[ index.column()], value );
}
if ( !mLayer->isModified() )
@ -509,3 +489,20 @@ void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx )
mLayer->actions()->doAction( action, attributes, fieldIdx( idx.column() ) );
}
void QgsAttributeTableModel::featureForm( QModelIndex &idx )
{
QgsFeature f;
QgsAttributeMap attributes;
for ( int i = 0; i < mAttributes.size(); i++ )
{
f.changeAttribute( i, data( index( idx.row(), i ), Qt::EditRole ) );
}
QgsFeatureAction action( tr( "Attributes changed" ), f, mLayer, -1, this );
if ( mLayer->isEditable() )
action.editFeature();
else
action.viewFeatureForm();
}

View File

@ -81,6 +81,10 @@ class QgsAttributeTableModel: public QAbstractTableModel
* @param index2 end index
*/
void reload( const QModelIndex &index1, const QModelIndex &index2 );
/**
* Remove rows
*/
bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() );
/**
* Resets the model
*/
@ -104,9 +108,9 @@ class QgsAttributeTableModel: public QAbstractTableModel
int fieldIdx( int col ) const;
/**
* Maps row to feature id
* @param id row id
* @param row row number
*/
int rowToId( const int id ) const;
int rowToId( const int row ) const;
/**
* Sorts the model
* @param column column to sort by
@ -128,6 +132,8 @@ class QgsAttributeTableModel: public QAbstractTableModel
/** Execute an action */
void executeAction( int action, const QModelIndex &idx ) const;
void featureForm( QModelIndex& );
signals:
/**
* Model has been changed
@ -151,6 +157,7 @@ class QgsAttributeTableModel: public QAbstractTableModel
* @param idx attribute index
*/
virtual void attributeDeleted( int idx );
protected slots:
/**
* Launched when attribute value has been changed
* @param fid feature id
@ -158,15 +165,6 @@ class QgsAttributeTableModel: public QAbstractTableModel
* @param value new value
*/
virtual void attributeValueChanged( int fid, int idx, const QVariant &value );
/**
* Launched when layer has been modified
* Rebuilds the model
* @param onlyGeometry true if only geometry has changed
*/
virtual void layerModified( bool onlyGeometry = false );
protected slots:
#if 0
/**
* Launched when a feature has been deleted
* @param fid feature id
@ -175,9 +173,9 @@ class QgsAttributeTableModel: public QAbstractTableModel
/**
* Launched when a feature has been added
* @param fid feature id
* @parem inOperation guard insertion with beginInsertRows() / endInsertRows()
*/
virtual void featureAdded( int fid );
#endif
virtual void featureAdded( int fid, bool inOperation = true );
/**
* Launched when layer has been deleted
*/

View File

@ -88,27 +88,32 @@ void QgsAttributeTableView::contextMenuEvent( QContextMenuEvent *event )
}
QgsVectorLayer *vlayer = mModel->layer();
if ( !vlayer || vlayer->actions()->size() == 0 )
{
if ( !vlayer )
return;
}
mActionPopup = new QMenu();
QAction *a = mActionPopup->addAction( tr( "Run action" ) );
a->setEnabled( false );
for ( int i = 0; i < vlayer->actions()->size(); i++ )
if ( vlayer->actions()->size() == 0 )
{
const QgsAction &action = vlayer->actions()->at( i );
if ( !action.runable() )
continue;
QAction *a = mActionPopup->addAction( tr( "Run action" ) );
a->setEnabled( false );
QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, mModel, i, idx );
mActionPopup->addAction( action.name(), a, SLOT( execute() ) );
for ( int i = 0; i < vlayer->actions()->size(); i++ )
{
const QgsAction &action = vlayer->actions()->at( i );
if ( !action.runable() )
continue;
QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), this, mModel, i, idx );
mActionPopup->addAction( action.name(), a, SLOT( execute() ) );
}
}
QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open form" ), this, mModel, -1, idx );
mActionPopup->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
mActionPopup->popup( event->globalPos() );
}
@ -116,3 +121,8 @@ void QgsAttributeTableAction::execute()
{
mModel->executeAction( mAction, mFieldIdx );
}
void QgsAttributeTableAction::featureForm()
{
mModel->featureForm( mFieldIdx );
}

View File

@ -26,7 +26,7 @@ class QgsVectorLayer;
class QMenu;
class QgsAttributeTableView: public QTableView
class QgsAttributeTableView : public QTableView
{
Q_OBJECT
@ -65,6 +65,7 @@ class QgsAttributeTableAction : public QAction
public slots:
void execute();
void featureForm();
private:
QgsAttributeTableModel *mModel;

View File

@ -29,7 +29,7 @@
#include "qgsproject.h"
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsattributedialog.h"
#include "qgsfeatureaction.h"
#include "qgsgeometry.h"
//for avoid intersections static method
@ -674,45 +674,13 @@ void QgsGPSInformationWidget::on_mBtnCloseFeature_clicked( )
memcpy( &wkb[5] + sizeof( double ), &y, sizeof( double ) );
f->setGeometryAndOwnership( &wkb[0], size );
// add the fields to the QgsFeature
const QgsFieldMap fields = vlayer->pendingFields();
for ( QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it )
{
f->addAttribute( it.key(), provider->defaultValue( it.key() ) );
}
vlayer->beginEditCommand( tr( "Feature added" ) );
QgsFeatureAction action( tr( "Feature added" ), *f, vlayer, -1, this );
if ( action.addFeature() )
mpCanvas->refresh();
// show the dialog to enter attribute values
QSettings settings;
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", false ).toBool();
if ( isDisabledAttributeValuesDlg )
{
QgsDebugMsg( "Adding feature to layer" );
vlayer->addFeature( *f );
vlayer->endEditCommand();
}
else
{
QgsAttributeDialog *mypDialog = new QgsAttributeDialog( vlayer, f );
if ( mypDialog->exec() )
{
QgsDebugMsg( "Adding feature to layer" );
vlayer->addFeature( *f );
vlayer->endEditCommand();
}
else
{
vlayer->destroyEditCommand();
QgsDebugMsg( "Adding feature to layer failed" );
delete f;
}
delete mypDialog;
}
mpCanvas->refresh();
delete f;
}
}
else // Line or poly
{
@ -819,48 +787,10 @@ void QgsGPSInformationWidget::on_mBtnCloseFeature_clicked( )
return; //unknown wkbtype
}
// add the fields to the QgsFeature
const QgsFieldMap fields = vlayer->pendingFields();
for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
{
f->addAttribute( it.key(), provider->defaultValue( it.key() ) );
}
QgsFeatureAction action( tr( "Feature added" ), *f, vlayer, -1, this );
if ( action.addFeature() )
mpCanvas->refresh();
QSettings settings;
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", false ).toBool();
if ( isDisabledAttributeValuesDlg )
{
vlayer->beginEditCommand( tr( "Feature added" ) );
if ( vlayer->addFeature( *f ) )
{
//add points to other features to keep topology up-to-date
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
if ( topologicalEditing )
{
vlayer->addTopologicalPoints( f->geometry() );
}
}
vlayer->endEditCommand();
}
else
{
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
if ( mypDialog->exec() )
{
vlayer->beginEditCommand( tr( "Feature added" ) );
if ( vlayer->addFeature( *f ) )
{
//add points to other features to keep topology up-to-date
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
if ( topologicalEditing )
{
vlayer->addTopologicalPoints( f->geometry() );
}
}
vlayer->endEditCommand();
}
mypDialog->deleteLater();
}
delete f;
delete mpRubberBand;

View File

@ -380,73 +380,6 @@ bool QgisAppInterface::openFeatureForm( QgsVectorLayer *vlayer, QgsFeature &f, b
if ( !vlayer )
return false;
QgsVectorDataProvider *dp = vlayer->dataProvider();
if ( dp )
{
// add the fields to the QgsFeature
const QgsFieldMap fields = vlayer->pendingFields();
for ( QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it )
{
if ( !f.attributeMap().contains( it.key() ) )
f.addAttribute( it.key(), dp->defaultValue( it.key() ) );
}
}
QgsAttributeMap src = f.attributeMap();
if ( !updateFeatureOnly && vlayer->isEditable() )
vlayer->beginEditCommand( tr( "Feature form edit" ) );
QgsAttributeDialog *ad = new QgsAttributeDialog( vlayer, &f );
if ( vlayer->actions()->size() > 0 )
{
ad->dialog()->setContextMenuPolicy( Qt::ActionsContextMenu );
QAction *a = new QAction( tr( "Run actions" ), ad->dialog() );
a->setEnabled( false );
ad->dialog()->addAction( a );
for ( int i = 0; i < vlayer->actions()->size(); i++ )
{
const QgsAction &action = vlayer->actions()->at( i );
if ( !action.runable() )
continue;
QgsFeatureAction *a = new QgsFeatureAction( action.name(), f, vlayer, i, ad->dialog() );
ad->dialog()->addAction( a );
connect( a, SIGNAL( triggered() ), a, SLOT( execute() ) );
QAbstractButton *pb = ad->dialog()->findChild<QAbstractButton *>( action.name() );
if ( pb )
connect( pb, SIGNAL( clicked() ), a, SLOT( execute() ) );
}
}
bool res = ad->exec();
if ( !updateFeatureOnly && vlayer->isEditable() )
{
if ( res )
{
const QgsAttributeMap &dst = f.attributeMap();
for ( QgsAttributeMap::const_iterator it = dst.begin(); it != dst.end(); it++ )
{
if ( !src.contains( it.key() ) || it.value() != src[it.key()] )
{
vlayer->changeAttributeValue( f.id(), it.key(), it.value() );
}
}
vlayer->endEditCommand();
}
else
{
vlayer->destroyEditCommand();
}
}
delete ad;
return res;
QgsFeatureAction action( tr( "Attributes changed" ), f, vlayer, -1, QgisApp::instance() );
return action.editFeature();
}

View File

@ -18,25 +18,189 @@
#include "qgsfeatureaction.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsidentifyresults.h"
#include "qgsattributedialog.h"
#include "qgslogger.h"
QgsFeatureAction::QgsFeatureAction( const QString &name, QgsIdentifyResults *results, QgsVectorLayer *vl, int action, QTreeWidgetItem *featItem )
: QAction( name, results )
, mLayer( vl )
, mAction( action )
{
results->retrieveAttributes( featItem, mAttributes, mIdx );
}
#include <QPushButton>
#include <QSettings>
QgsFeatureAction::QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *layer, int action, QObject *parent )
: QAction( name, parent )
, mLayer( layer )
, mFeature( f )
, mAction( action )
{
mAttributes = f.attributeMap();
}
void QgsFeatureAction::execute()
{
mLayer->actions()->doAction( mAction, mAttributes, mIdx );
mLayer->actions()->doAction( mAction, mFeature.attributeMap(), mIdx );
}
QgsAttributeDialog *QgsFeatureAction::newDialog()
{
QgsAttributeDialog *dialog = new QgsAttributeDialog( mLayer, &mFeature );
if ( mLayer->actions()->size() == 0 )
{
dialog->dialog()->setContextMenuPolicy( Qt::ActionsContextMenu );
QAction *a = new QAction( tr( "Run actions" ), dialog->dialog() );
a->setEnabled( false );
dialog->dialog()->addAction( a );
for ( int i = 0; i < mLayer->actions()->size(); i++ )
{
const QgsAction &action = mLayer->actions()->at( i );
if ( !action.runable() )
continue;
QgsFeatureAction *a = new QgsFeatureAction( action.name(), mFeature, mLayer, i, dialog->dialog() );
dialog->dialog()->addAction( a );
connect( a, SIGNAL( triggered() ), a, SLOT( execute() ) );
QAbstractButton *pb = dialog->dialog()->findChild<QAbstractButton *>( action.name() );
if ( pb )
connect( pb, SIGNAL( clicked() ), a, SLOT( execute() ) );
}
}
return dialog;
}
bool QgsFeatureAction::viewFeatureForm( QgsRubberBand *rb )
{
if ( !mLayer )
return false;
QgsAttributeDialog *dialog = newDialog();
dialog->setHighlight( rb );
dialog->show();
return true;
}
bool QgsFeatureAction::editFeature()
{
bool res = false;
if ( !mLayer )
return res;
QgsAttributeDialog *dialog = newDialog();
if ( !mLayer->isEditable() )
{
res = dialog->exec();
}
else
{
QgsAttributeMap src = mFeature.attributeMap();
if ( dialog->exec() )
{
mLayer->beginEditCommand( text() );
const QgsAttributeMap &dst = mFeature.attributeMap();
for ( QgsAttributeMap::const_iterator it = dst.begin(); it != dst.end(); it++ )
{
if ( !src.contains( it.key() ) || it.value() != src[it.key()] )
{
mLayer->changeAttributeValue( mFeature.id(), it.key(), it.value() );
}
}
mLayer->endEditCommand();
res = true;
}
else
{
res = false;
}
}
delete dialog;
return res;
}
bool QgsFeatureAction::addFeature()
{
if ( !mLayer || !mLayer->isEditable() )
return false;
QgsVectorDataProvider *provider = mLayer->dataProvider();
QSettings settings;
bool reuseLastValues = settings.value( "/qgis/digitizing/reuseLastValues", false ).toBool();
QgsDebugMsg( QString( "reuseLastValues: %1" ).arg( reuseLastValues ) );
// add the fields to the QgsFeature
const QgsFieldMap fields = mLayer->pendingFields();
for ( QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it )
{
if ( reuseLastValues && mLastUsedValues.contains( mLayer ) && mLastUsedValues[ mLayer ].contains( it.key() ) )
{
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( mLastUsedValues[ mLayer ][ it.key()].toString() ).arg( it.key() ) );
mFeature.addAttribute( it.key(), mLastUsedValues[ mLayer ][ it.key()] );
}
else
{
mFeature.addAttribute( it.key(), provider->defaultValue( it.key() ) );
}
}
bool res = false;
mLayer->beginEditCommand( text() );
// show the dialog to enter attribute values
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", true ).toBool();
if ( isDisabledAttributeValuesDlg )
{
res = mLayer->addFeature( mFeature );
}
else
{
QgsAttributeMap origValues;
if ( reuseLastValues )
origValues = mFeature.attributeMap();
QgsAttributeDialog *dialog = newDialog();
if ( dialog->exec() )
{
if ( reuseLastValues )
{
for ( QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it )
{
const QgsAttributeMap &newValues = mFeature.attributeMap();
if ( newValues.contains( it.key() )
&& origValues.contains( it.key() )
&& origValues[ it.key()] != newValues[ it.key()] )
{
QgsDebugMsg( QString( "saving %1 for %2" ).arg( mLastUsedValues[ mLayer ][ it.key()].toString() ).arg( it.key() ) );
mLastUsedValues[ mLayer ][ it.key()] = newValues[ it.key()];
}
}
}
res = mLayer->addFeature( mFeature );
}
else
{
QgsDebugMsg( "Adding feature to layer failed" );
res = false;
}
}
if ( res )
mLayer->endEditCommand();
else
mLayer->destroyEditCommand();
return res;
}
QMap<QgsVectorLayer *, QgsAttributeMap> QgsFeatureAction::mLastUsedValues;

View File

@ -26,7 +26,8 @@
class QgsIdentifyResults;
class QgsVectorLayer;
class QTreeWidgetItem;
class QgsRubberBand;
class QgsAttributeDialog;
class QgsFeatureAction : public QAction
{
@ -34,16 +35,22 @@ class QgsFeatureAction : public QAction
public:
QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *vl, int action, QObject *parent );
QgsFeatureAction( const QString &name, QgsIdentifyResults *results, QgsVectorLayer *vl, int action, QTreeWidgetItem *featItem );
public slots:
void execute();
bool viewFeatureForm( QgsRubberBand *rb = 0 );
bool editFeature();
bool addFeature();
private:
QgsAttributeDialog *newDialog();
QgsVectorLayer *mLayer;
QgsFeature &mFeature;
int mAction;
int mIdx;
QgsAttributeMap mAttributes;
static QMap<QgsVectorLayer *, QgsAttributeMap> mLastUsedValues;
};
#endif

View File

@ -63,7 +63,7 @@ class QgsIdentifyResultsDock : public QDockWidget
// Tree hierarchy
//
// layer [userrole: QgsMapLayer]
// feature: displayfield|displayvalue [userrole: fid]
// feature: displayfield|displayvalue [userrole: fid, index in feature list]
// derived attributes (if any) [userrole: "derived"]
// name value
// actions (if any) [userrole: "actions"]
@ -132,8 +132,8 @@ QTreeWidgetItem *QgsIdentifyResults::layerItem( QObject *layer )
return 0;
}
void QgsIdentifyResults::addFeature( QgsVectorLayer *vlayer, int fid,
const QgsAttributeMap &attributes,
void QgsIdentifyResults::addFeature( QgsVectorLayer *vlayer,
const QgsFeature &f,
const QMap<QString, QString> &derivedAttributes )
{
QTreeWidgetItem *layItem = layerItem( vlayer );
@ -153,10 +153,12 @@ void QgsIdentifyResults::addFeature( QgsVectorLayer *vlayer, int fid,
}
QTreeWidgetItem *featItem = new QTreeWidgetItem;
featItem->setData( 0, Qt::UserRole, fid );
featItem->setData( 0, Qt::UserRole, f.id() );
featItem->setData( 0, Qt::UserRole + 1, mFeatures.size() );
mFeatures << f;
layItem->addChild( featItem );
for ( QgsAttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++ )
for ( QgsAttributeMap::const_iterator it = f.attributeMap().begin(); it != f.attributeMap().end(); it++ )
{
QTreeWidgetItem *attrItem = new QTreeWidgetItem( QStringList() << QString::number( it.key() ) << it.value().toString() );
@ -461,7 +463,8 @@ void QgsIdentifyResults::contextMenuEvent( QContextMenuEvent* event )
if ( !action.runable() )
continue;
QgsFeatureAction *a = new QgsFeatureAction( action.name(), this, vlayer, i, featItem );
int idx = featItem->data( 0, Qt::UserRole + 1 ).toInt();
QgsFeatureAction *a = new QgsFeatureAction( action.name(), mFeatures[ idx ], vlayer, i, this );
mActionPopup->addAction( QgisApp::getThemeIcon( "/mAction.png" ), action.name(), a, SLOT( execute() ) );
}
}
@ -869,71 +872,23 @@ void QgsIdentifyResults::featureForm()
return;
int fid = featItem->data( 0, Qt::UserRole ).toInt();
int idx = featItem->data( 0, Qt::UserRole + 1 ).toInt();
QgsFeature f;
if ( !vlayer->featureAtId( fid, f ) )
return;
QgsAttributeMap src = f.attributeMap();
if ( vlayer->isEditable() )
vlayer->beginEditCommand( tr( "Attribute changed" ) );
QgsAttributeDialog *ad = new QgsAttributeDialog( vlayer, &f );
if ( vlayer->actions()->size() > 0 )
{
ad->dialog()->setContextMenuPolicy( Qt::ActionsContextMenu );
QAction *a = new QAction( tr( "Run actions" ), ad->dialog() );
a->setEnabled( false );
ad->dialog()->addAction( a );
for ( int i = 0; i < vlayer->actions()->size(); i++ )
{
const QgsAction &action = vlayer->actions()->at( i );
if ( !action.runable() )
continue;
QgsFeatureAction *a = new QgsFeatureAction( action.name(), this, vlayer, i, featItem );
ad->dialog()->addAction( a );
connect( a, SIGNAL( triggered() ), a, SLOT( execute() ) );
QAbstractButton *pb = ad->dialog()->findChild<QAbstractButton *>( action.name() );
if ( pb )
connect( pb, SIGNAL( clicked() ), a, SLOT( execute() ) );
}
}
QgsFeatureAction action( tr( "Attribute changes" ), f, vlayer, idx, this );
if ( vlayer->isEditable() )
{
if ( ad->exec() )
if ( action.editFeature() )
{
const QgsAttributeMap &dst = f.attributeMap();
for ( QgsAttributeMap::const_iterator it = dst.begin(); it != dst.end(); it++ )
{
if ( !src.contains( it.key() ) || it.value() != src[it.key()] )
{
vlayer->changeAttributeValue( f.id(), it.key(), it.value() );
}
}
vlayer->endEditCommand();
mCanvas->refresh();
}
else
{
vlayer->destroyEditCommand();
}
delete ad;
mCanvas->refresh();
}
else
{
QgsRubberBand *rb = mRubberBands.take( featItem );
ad->setHighlight( rb );
ad->show();
action.viewFeatureForm( mRubberBands.take( featItem ) );
}
}

View File

@ -55,8 +55,8 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
~QgsIdentifyResults();
/** Add add feature from vector layer */
void addFeature( QgsVectorLayer *layer, int fid,
const QgsAttributeMap &attributes,
void addFeature( QgsVectorLayer *layer,
const QgsFeature &f,
const QMap< QString, QString > &derivedAttributes );
/** Add add feature from other layer */
@ -117,6 +117,7 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
QMenu *mActionPopup;
QMap<QTreeWidgetItem *, QgsRubberBand * > mRubberBands;
QgsMapCanvas *mCanvas;
QList<QgsFeature> mFeatures;
QgsVectorLayer *vectorLayer( QTreeWidgetItem *item );
QTreeWidgetItem *featureItem( QTreeWidgetItem *item );

View File

@ -27,87 +27,24 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgslogger.h"
#include "qgsfeatureaction.h"
#include <QMessageBox>
#include <QMouseEvent>
#include <QSettings>
QgsMapToolAddFeature::QgsMapToolAddFeature( QgsMapCanvas* canvas, CaptureMode tool ): QgsMapToolCapture( canvas, tool )
{
}
QgsMapToolAddFeature::~QgsMapToolAddFeature()
{
}
bool QgsMapToolAddFeature::addFeature( QgsVectorLayer *vlayer, QgsFeature *f )
{
bool res = false;
QgsVectorDataProvider* provider = vlayer->dataProvider();
QSettings settings;
bool reuseLastValues = settings.value( "/qgis/digitizing/reuseLastValues", false ).toBool();
QgsDebugMsg( QString( "reuseLastValues: %1" ).arg( reuseLastValues ) );
// add the fields to the QgsFeature
const QgsFieldMap fields = vlayer->pendingFields();
for ( QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it )
{
if ( reuseLastValues && mLastUsedValues.contains( vlayer ) && mLastUsedValues[ vlayer ].contains( it.key() ) )
{
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( mLastUsedValues[ vlayer ][ it.key()].toString() ).arg( it.key() ) );
f->addAttribute( it.key(), mLastUsedValues[ vlayer ][ it.key()] );
}
else
{
f->addAttribute( it.key(), provider->defaultValue( it.key() ) );
}
}
// show the dialog to enter attribute values
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", true ).toBool();
if ( isDisabledAttributeValuesDlg )
{
res = vlayer->addFeature( *f );
}
else
{
QgsAttributeDialog *mypDialog = new QgsAttributeDialog( vlayer, f );
QgsAttributeMap origValues;
if ( reuseLastValues )
origValues = f->attributeMap();
if ( mypDialog->exec() )
{
if ( reuseLastValues )
{
for ( QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it )
{
const QgsAttributeMap &newValues = f->attributeMap();
if ( newValues.contains( it.key() )
&& origValues.contains( it.key() )
&& origValues[ it.key()] != newValues[ it.key()] )
{
QgsDebugMsg( QString( "saving %1 for %2" ).arg( mLastUsedValues[ vlayer ][ it.key()].toString() ).arg( it.key() ) );
mLastUsedValues[ vlayer ][ it.key()] = newValues[ it.key()];
}
}
}
res = vlayer->addFeature( *f );
}
else
{
QgsDebugMsg( "Adding feature to layer failed" );
res = false;
}
mypDialog->deleteLater();
}
return res;
QgsFeatureAction action( tr( "add feature" ), *f, vlayer, -1, this );
return action.addFeature();
}
void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e )

View File

@ -18,7 +18,7 @@
#include "qgsfeature.h"
/**This tool adds new point/line/polygon features to already existing vector layers*/
class QgsMapToolAddFeature: public QgsMapToolCapture
class QgsMapToolAddFeature : public QgsMapToolCapture
{
Q_OBJECT
public:
@ -26,7 +26,5 @@ class QgsMapToolAddFeature: public QgsMapToolCapture
virtual ~QgsMapToolAddFeature();
void canvasReleaseEvent( QMouseEvent * e );
private:
bool addFeature( QgsVectorLayer *vlayer, QgsFeature *f );
QMap<QgsVectorLayer *, QgsAttributeMap> mLastUsedValues;
};

View File

@ -300,7 +300,7 @@ bool QgsMapToolIdentify::identifyVectorLayer( QgsVectorLayer *layer, int x, int
derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : QString::number( fid ) );
results()->addFeature( layer, fid, f_it->attributeMap(), derivedAttributes );
results()->addFeature( layer, *f_it, derivedAttributes );
}
QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );

View File

@ -26,7 +26,12 @@
#include <limits>
#include <QComboBox>
QgsMergeAttributesDialog::QgsMergeAttributesDialog( const QgsFeatureList& features, QgsVectorLayer* vl, QgsMapCanvas* canvas, QWidget * parent, Qt::WindowFlags f ): QDialog( parent, f ), mFeatureList( features ), mVectorLayer( vl ), mMapCanvas( canvas ), mSelectionRubberBand( 0 )
QgsMergeAttributesDialog::QgsMergeAttributesDialog( const QgsFeatureList &features, QgsVectorLayer *vl, QgsMapCanvas *canvas, QWidget *parent, Qt::WindowFlags f )
: QDialog( parent, f )
, mFeatureList( features )
, mVectorLayer( vl )
, mMapCanvas( canvas )
, mSelectionRubberBand( 0 )
{
setupUi( this );
createTableWidgetContents();
@ -60,48 +65,50 @@ void QgsMergeAttributesDialog::createTableWidgetContents()
{
return;
}
const QgsFieldMap& fieldMap = mVectorLayer->pendingFields();
//combo box row, attributes titles, feature values and current merge results
mTableWidget->setRowCount( mFeatureList.size() + 2 );
mTableWidget->setColumnCount( fieldMap.size() );
//create combo boxes
for ( int i = 0; i < fieldMap.size(); ++i )
{
mTableWidget->setCellWidget( 0, i, createMergeComboBox( fieldMap[i].type() ) );
}
//create combo boxes and insert attribute names
const QgsFieldMap& fieldMap = mVectorLayer->pendingFields();
QgsFieldMap::const_iterator fieldIt = fieldMap.constBegin();
//insert attribute names
int col = 0;
for ( ; fieldIt != fieldMap.constEnd(); ++fieldIt )
for ( QgsFieldMap::const_iterator fieldIt = fieldMap.constBegin();
fieldIt != fieldMap.constEnd();
++fieldIt )
{
if ( mVectorLayer->editType( fieldIt.key() ) == QgsVectorLayer::Hidden ||
mVectorLayer->editType( fieldIt.key() ) == QgsVectorLayer::Immutable )
continue;
mTableWidget->setColumnCount( col + 1 );
mTableWidget->setCellWidget( 0, col, createMergeComboBox( fieldIt->type() ) );
QTableWidgetItem *item = new QTableWidgetItem( fieldIt.value().name() );
item->setData( Qt::UserRole, fieldIt.key() );
mTableWidget->setHorizontalHeaderItem( col++, item );
}
//insert the attribute values
int currentRow = 1;
QStringList verticalHeaderLabels; //the id column is in the
verticalHeaderLabels << tr( "Id" );
for ( int i = 0; i < mFeatureList.size(); ++i )
{
verticalHeaderLabels << QString::number( mFeatureList[i].id() );
QgsAttributeMap currentAttributeMap = mFeatureList[i].attributeMap();
QgsAttributeMap::const_iterator currentMapIt = currentAttributeMap.constBegin();
int col = 0;
for ( ; currentMapIt != currentAttributeMap.constEnd(); ++currentMapIt )
const QgsAttributeMap &attrs = mFeatureList[i].attributeMap();
for ( int j = 0; j < mTableWidget->columnCount(); j++ )
{
QTableWidgetItem* attributeValItem = new QTableWidgetItem( currentMapIt.value().toString() );
int idx = mTableWidget->horizontalHeaderItem( j )->data( Qt::UserRole ).toInt();
QTableWidgetItem* attributeValItem = new QTableWidgetItem( attrs[idx].toString() );
attributeValItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
mTableWidget->setItem( currentRow, col, attributeValItem );
mTableWidget->setCellWidget( currentRow, col++, QgsAttributeEditor::createAttributeEditor( mTableWidget, NULL, mVectorLayer, currentMapIt.key(), currentMapIt.value() ) );
mTableWidget->setItem( i + 1, j, attributeValItem );
mTableWidget->setCellWidget( i + 1, j, QgsAttributeEditor::createAttributeEditor( mTableWidget, NULL, mVectorLayer, idx, attrs[idx] ) );
}
++currentRow;
}
//merge
@ -109,7 +116,7 @@ void QgsMergeAttributesDialog::createTableWidgetContents()
mTableWidget->setVerticalHeaderLabels( verticalHeaderLabels );
//insert currently merged values
for ( int i = 0; i < fieldMap.size(); ++i )
for ( int i = 0; i < mTableWidget->columnCount(); ++i )
{
refreshMergedValue( i );
}
@ -180,7 +187,7 @@ void QgsMergeAttributesDialog::selectedRowChanged()
int row = selectionList[0]->row();
if ( !mTableWidget || !mMapCanvas || !mVectorLayer || row < 1 || row >= ( mTableWidget->rowCount() ) )
if ( !mTableWidget || !mMapCanvas || !mVectorLayer || row < 1 || row >= mTableWidget->rowCount() )
{
return;
}
@ -476,17 +483,18 @@ void QgsMergeAttributesDialog::on_mRemoveFeatureFromSelectionButton_clicked()
for ( int i = 0; i < mTableWidget->columnCount(); ++i )
{
QComboBox* currentComboBox = qobject_cast<QComboBox *>( mTableWidget->cellWidget( 0, i ) );
if ( currentComboBox )
{
currentComboBox->blockSignals( true );
currentComboBox->removeItem( currentComboBox->findText( tr( "feature %1" ).arg( featureId ) ) );
currentComboBox->blockSignals( false );
}
if ( !currentComboBox )
continue;
currentComboBox->blockSignals( true );
currentComboBox->removeItem( currentComboBox->findText( tr( "feature %1" ).arg( featureId ) ) );
currentComboBox->blockSignals( false );
}
//finally remove the feature from mFeatureList
QgsFeatureList::iterator f_it = mFeatureList.begin();
for ( ; f_it != mFeatureList.end(); ++f_it )
for ( QgsFeatureList::iterator f_it = mFeatureList.begin();
f_it != mFeatureList.end();
++f_it )
{
if ( f_it->id() == featureId )
{
@ -509,29 +517,22 @@ void QgsMergeAttributesDialog::createRubberBandForFeature( int featureId )
QgsAttributeMap QgsMergeAttributesDialog::mergedAttributesMap() const
{
QgsAttributeMap resultMap;
if ( mFeatureList.size() < 1 )
{
return resultMap; //return empty map
return QgsAttributeMap();
}
resultMap = mFeatureList[0].attributeMap();
int index = 0;
QgsAttributeMap::iterator it = resultMap.begin();
for ( ; it != resultMap.end(); ++it )
QgsAttributeMap resultMap;
for ( int i = 0; i < mTableWidget->columnCount(); i++ )
{
QTableWidgetItem* currentItem = mTableWidget->item( mFeatureList.size() + 1, index );
int idx = mTableWidget->horizontalHeaderItem( i )->data( Qt::UserRole ).toInt();
QTableWidgetItem* currentItem = mTableWidget->item( mFeatureList.size() + 1, i );
if ( !currentItem )
{
continue;
}
QString mergedString = currentItem->text();
QVariant newValue( mergedString );
resultMap.insert( it.key(), newValue );
++index;
resultMap.insert( idx, currentItem->text() );
}
return resultMap;
}

View File

@ -169,7 +169,7 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
QgsVectorLayer::~QgsVectorLayer()
{
QgsDebugMsg( "In QgsVectorLayer destructor" );
QgsDebugMsg( "entered." );
emit layerDeleted();
@ -1813,6 +1813,8 @@ bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent )
updateExtents();
}
emit featureAdded( f.id() );
return true;
}
@ -4509,6 +4511,7 @@ void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
for ( ; delIt != deletedFeatureIdChange.end(); ++delIt )
{
mDeletedFeatureIds.insert( *delIt );
emit featureDeleted( *delIt );
}
// added features
@ -4516,6 +4519,7 @@ void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
for ( ; addIt != addedFeatures.end(); ++addIt )
{
mAddedFeatures.append( *addIt );
emit featureAdded( addIt->id() );
}
// changed attributes
@ -4553,9 +4557,8 @@ void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
break;
}
}
}
emit attributeValueChanged( fid, attrChIt.key(), attrChIt.value().target );
}
}
@ -4566,6 +4569,7 @@ void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
int attrIndex = attrIt.key();
mAddedAttributeIds.insert( attrIndex );
mUpdatedFields.insert( attrIndex, attrIt.value() );
emit attributeAdded( attrIndex );
}
// deleted attributes
@ -4575,6 +4579,7 @@ void QgsVectorLayer::redoEditCommand( QgsUndoCommand* cmd )
int attrIndex = dAttrIt.key();
mDeletedAttributeIds.insert( attrIndex );
mUpdatedFields.remove( attrIndex );
emit attributeDeleted( attrIndex );
}
setModified( true );
@ -4598,6 +4603,7 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
int attrIndex = dAttrIt.key();
mDeletedAttributeIds.remove( attrIndex );
mUpdatedFields.insert( attrIndex, dAttrIt.value() );
emit attributeAdded( attrIndex );
}
// added attributes
@ -4607,6 +4613,7 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
int attrIndex = attrIt.key();
mAddedAttributeIds.remove( attrIndex );
mUpdatedFields.remove( attrIndex );
emit attributeDeleted( attrIndex );
}
// geometry changes
@ -4628,6 +4635,7 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
for ( ; delIt != deletedFeatureIdChange.end(); ++delIt )
{
mDeletedFeatureIds.remove( *delIt );
emit featureAdded( *delIt );
}
// added features
@ -4640,6 +4648,7 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
if ( addedIt->id() == addIt->id() )
{
mAddedFeatures.erase( addedIt );
emit featureDeleted( addIt->id() );
break; // feature was found so move to next one
}
}
@ -4675,9 +4684,15 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd )
break;
}
}
}
emit attributeValueChanged( fid, attrChIt.key(), attrChIt.value().original );
QVariant original = attrChIt.value().original;
if ( attrChIt.value().isFirstChange )
{
QgsFeature tmp;
mDataProvider->featureAtId( fid, tmp, false, QgsAttributeList() << attrChIt.key() );
original = tmp.attributeMap()[ attrChIt.key()];
}
emit attributeValueChanged( fid, attrChIt.key(), original );
}
}
setModified( true );

View File

@ -623,6 +623,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
void editingStopped();
void attributeAdded( int idx );
void attributeDeleted( int idx );
void featureAdded( int fid ); // added in 1.7
void featureDeleted( int fid );
void layerDeleted();

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>646</width>
<width>763</width>
<height>570</height>
</rect>
</property>
@ -312,6 +312,19 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mAddFeature">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Add feature</string>
</property>
<property name="text">
<string>+</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mOpenFieldCalculator">
<property name="toolTip">