diff --git a/src/app/attributetable/qgsattributetabledelegate.cpp b/src/app/attributetable/qgsattributetabledelegate.cpp index fa133a45065..3708195df1d 100644 --- a/src/app/attributetable/qgsattributetabledelegate.cpp +++ b/src/app/attributetable/qgsattributetabledelegate.cpp @@ -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( index.model() ); + if ( tm ) + return tm->rowToId( index.row() ); + + const QgsAttributeTableFilterModel *fm = dynamic_cast( 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 diff --git a/src/app/attributetable/qgsattributetabledelegate.h b/src/app/attributetable/qgsattributetabledelegate.h index 0381e3f95d7..1666c43c11e 100644 --- a/src/app/attributetable/qgsattributetabledelegate.h +++ b/src/app/attributetable/qgsattributetabledelegate.h @@ -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 diff --git a/src/app/attributetable/qgsattributetabledialog.cpp b/src/app/attributetable/qgsattributetabledialog.cpp index e241f956a1d..9fc5ea1c588 100644 --- a/src/app/attributetable/qgsattributetabledialog.cpp +++ b/src/app/attributetable/qgsattributetabledialog.cpp @@ -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() ) ); } } diff --git a/src/app/attributetable/qgsattributetabledialog.h b/src/app/attributetable/qgsattributetabledialog.h index ddcf1bc0275..86a5a8f62dc 100644 --- a/src/app/attributetable/qgsattributetabledialog.h +++ b/src/app/attributetable/qgsattributetabledialog.h @@ -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: diff --git a/src/app/attributetable/qgsattributetablememorymodel.cpp b/src/app/attributetable/qgsattributetablememorymodel.cpp index c12e3872bd6..8ec61dbba22 100644 --- a/src/app/attributetable/qgsattributetablememorymodel.cpp +++ b/src/app/attributetable/qgsattributetablememorymodel.cpp @@ -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 ); } diff --git a/src/app/attributetable/qgsattributetablememorymodel.h b/src/app/attributetable/qgsattributetablememorymodel.h index 2ef9eebb668..7cc9e833f14 100644 --- a/src/app/attributetable/qgsattributetablememorymodel.h +++ b/src/app/attributetable/qgsattributetablememorymodel.h @@ -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 */ diff --git a/src/app/attributetable/qgsattributetablemodel.cpp b/src/app/attributetable/qgsattributetablemodel.cpp index 8bec009bfe9..76ac7bb7df1 100644 --- a/src/app/attributetable/qgsattributetablemodel.cpp +++ b/src/app/attributetable/qgsattributetablemodel.cpp @@ -22,14 +22,12 @@ #include "qgisapp.h" #include "qgsattributeaction.h" #include "qgsmapcanvas.h" +#include "qgsfeatureaction.h" #include #include #include -//////////////////////////// -// 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::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::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(); +} diff --git a/src/app/attributetable/qgsattributetablemodel.h b/src/app/attributetable/qgsattributetablemodel.h index f9c5e68465e..f388110ad6c 100644 --- a/src/app/attributetable/qgsattributetablemodel.h +++ b/src/app/attributetable/qgsattributetablemodel.h @@ -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 */ diff --git a/src/app/attributetable/qgsattributetableview.cpp b/src/app/attributetable/qgsattributetableview.cpp index 525f1d08621..3fefbff6263 100644 --- a/src/app/attributetable/qgsattributetableview.cpp +++ b/src/app/attributetable/qgsattributetableview.cpp @@ -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 ); +} diff --git a/src/app/attributetable/qgsattributetableview.h b/src/app/attributetable/qgsattributetableview.h index d64a2846e43..c72e8f1e456 100644 --- a/src/app/attributetable/qgsattributetableview.h +++ b/src/app/attributetable/qgsattributetableview.h @@ -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; diff --git a/src/app/gps/qgsgpsinformationwidget.cpp b/src/app/gps/qgsgpsinformationwidget.cpp index bd0a596b6c2..c3a52ccc17e 100644 --- a/src/app/gps/qgsgpsinformationwidget.cpp +++ b/src/app/gps/qgsgpsinformationwidget.cpp @@ -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; diff --git a/src/app/qgisappinterface.cpp b/src/app/qgisappinterface.cpp index 2a93bd7a9dd..e8569b3e00c 100644 --- a/src/app/qgisappinterface.cpp +++ b/src/app/qgisappinterface.cpp @@ -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( 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(); } diff --git a/src/app/qgsfeatureaction.cpp b/src/app/qgsfeatureaction.cpp index 09aa9a2751b..07807a6159d 100644 --- a/src/app/qgsfeatureaction.cpp +++ b/src/app/qgsfeatureaction.cpp @@ -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 +#include 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( 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 QgsFeatureAction::mLastUsedValues; diff --git a/src/app/qgsfeatureaction.h b/src/app/qgsfeatureaction.h index c57c11b3279..c3278ea00c4 100644 --- a/src/app/qgsfeatureaction.h +++ b/src/app/qgsfeatureaction.h @@ -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 mLastUsedValues; }; #endif diff --git a/src/app/qgsidentifyresults.cpp b/src/app/qgsidentifyresults.cpp index aaa5b47cfe3..b095d220cb7 100644 --- a/src/app/qgsidentifyresults.cpp +++ b/src/app/qgsidentifyresults.cpp @@ -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 &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( 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 ) ); } } diff --git a/src/app/qgsidentifyresults.h b/src/app/qgsidentifyresults.h index ea98ffe3859..c245559930f 100644 --- a/src/app/qgsidentifyresults.h +++ b/src/app/qgsidentifyresults.h @@ -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 mRubberBands; QgsMapCanvas *mCanvas; + QList mFeatures; QgsVectorLayer *vectorLayer( QTreeWidgetItem *item ); QTreeWidgetItem *featureItem( QTreeWidgetItem *item ); diff --git a/src/app/qgsmaptooladdfeature.cpp b/src/app/qgsmaptooladdfeature.cpp index 8dce4976d33..f8d4993e9c7 100644 --- a/src/app/qgsmaptooladdfeature.cpp +++ b/src/app/qgsmaptooladdfeature.cpp @@ -27,87 +27,24 @@ #include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" #include "qgslogger.h" +#include "qgsfeatureaction.h" + #include #include #include 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 ) diff --git a/src/app/qgsmaptooladdfeature.h b/src/app/qgsmaptooladdfeature.h index 5d6f9f8df4d..e6173b85e1f 100644 --- a/src/app/qgsmaptooladdfeature.h +++ b/src/app/qgsmaptooladdfeature.h @@ -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 mLastUsedValues; }; diff --git a/src/app/qgsmaptoolidentify.cpp b/src/app/qgsmaptoolidentify.cpp index 60d8bb7a04b..2547edebf82 100644 --- a/src/app/qgsmaptoolidentify.cpp +++ b/src/app/qgsmaptoolidentify.cpp @@ -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 ) ); diff --git a/src/app/qgsmergeattributesdialog.cpp b/src/app/qgsmergeattributesdialog.cpp index 62243770e88..8f22029c0ff 100644 --- a/src/app/qgsmergeattributesdialog.cpp +++ b/src/app/qgsmergeattributesdialog.cpp @@ -26,7 +26,12 @@ #include #include -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( 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; } - diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index e1e1f968954..7fd32a0e238 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -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 ); diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 0ff357314bc..b50c6457fc2 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -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(); diff --git a/src/ui/qgsattributetabledialog.ui b/src/ui/qgsattributetabledialog.ui index 83edb9245c9..f7932bb90ae 100644 --- a/src/ui/qgsattributetabledialog.ui +++ b/src/ui/qgsattributetabledialog.ui @@ -6,7 +6,7 @@ 0 0 - 646 + 763 570 @@ -312,6 +312,19 @@ + + + + false + + + Add feature + + + + + + +