Skip to content

Commit

Permalink
Fix add attribute dialog
Browse files Browse the repository at this point in the history
Fix #10337
  • Loading branch information
m-kuhn committed May 25, 2014
1 parent 3871ce7 commit 81293db
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 56 deletions.
64 changes: 34 additions & 30 deletions src/app/qgsfeatureaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
QgsDebugMsg( QString( "Using specified default %1 for %2" ).arg( defaultAttributes.value( idx ).toString() ).arg( idx ) );
mFeature.setAttribute( idx, defaultAttributes.value( idx ) );
}
else if ( reuseLastValues && mLastUsedValues.contains( mLayer ) && mLastUsedValues[ mLayer ].contains( idx ) )
else if ( reuseLastValues && sLastUsedValues.contains( mLayer ) && sLastUsedValues[ mLayer ].contains( idx ) )
{
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( mLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
mFeature.setAttribute( idx, mLastUsedValues[ mLayer ][idx] );
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( sLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
mFeature.setAttribute( idx, sLastUsedValues[ mLayer ][idx] );
}
else
{
Expand All @@ -178,7 +178,7 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )

bool res = false;

mLayer->beginEditCommand( text() );


// show the dialog to enter attribute values
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", false ).toBool();
Expand All @@ -196,7 +196,13 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
}
if ( isDisabledAttributeValuesDlg )
{
mLayer->beginEditCommand( text() );
res = mLayer->addFeature( mFeature );

if ( res )
mLayer->endEditCommand();
else
mLayer->destroyEditCommand();
}
else
{
Expand All @@ -205,36 +211,34 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
origValues = mFeature.attributes();

QgsAttributeDialog *dialog = newDialog( false );
if ( dialog->exec() )
{
if ( reuseLastValues )
{
for ( int idx = 0; idx < fields.count(); ++idx )
{
const QgsAttributes &newValues = mFeature.attributes();
if ( origValues[idx] != newValues[idx] )
{
QgsDebugMsg( QString( "saving %1 for %2" ).arg( mLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
mLastUsedValues[ mLayer ][idx] = newValues[idx];
}
}
}

res = mLayer->addFeature( mFeature );
}
else
dialog->setIsAddDialog( true );
dialog->setEditCommandMessage( text() );
dialog->exec();
if ( reuseLastValues )
{
QgsDebugMsg( "Adding feature to layer failed" );
res = false;
connect( dialog->dialog(), SIGNAL( featureSaved( const QgsFeature& feature ) ), this, SLOT( updateLastUsedValues( const QgsFeature& feature ) ) );
}
}

if ( res )
mLayer->endEditCommand();
else
mLayer->destroyEditCommand();

return res;
}

QMap<QgsVectorLayer *, QgsAttributeMap> QgsFeatureAction::mLastUsedValues;
void QgsFeatureAction::updateLastUsedValues( const QgsFeature& feature )
{
QgsAttributeForm* form = qobject_cast<QgsAttributeForm*>( sender() );
Q_ASSERT( form );

QgsFields fields = mLayer->pendingFields();
for ( int idx = 0; idx < fields.count(); ++idx )
{
const QgsAttributes &newValues = feature.attributes();
QgsAttributeMap origValues = sLastUsedValues[ mLayer ];
if ( origValues[idx] != newValues[idx] )
{
QgsDebugMsg( QString( "saving %1 for %2" ).arg( sLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
sLastUsedValues[ mLayer ][idx] = newValues[idx];
}
}
}

QMap<QgsVectorLayer *, QgsAttributeMap> QgsFeatureAction::sLastUsedValues;
7 changes: 5 additions & 2 deletions src/app/qgsfeatureaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
qgsfeatureaction.h - description
------------------
begin : 2010-09-20
copyright : (C) 2010 by Jürgen E. Fischer
copyright : (C) 2010 by Jürgen E. Fischer
email : jef at norbit dot de
***************************************************************************/

Expand Down Expand Up @@ -52,6 +52,9 @@ class APP_EXPORT QgsFeatureAction : public QAction
*/
bool addFeature( const QgsAttributeMap& defaultAttributes = QgsAttributeMap() );

private slots:
void updateLastUsedValues( const QgsFeature& feature );

private:
QgsAttributeDialog *newDialog( bool cloneFeature );

Expand All @@ -60,7 +63,7 @@ class APP_EXPORT QgsFeatureAction : public QAction
int mAction;
int mIdx;

static QMap<QgsVectorLayer *, QgsAttributeMap> mLastUsedValues;
static QMap<QgsVectorLayer *, QgsAttributeMap> sLastUsedValues;
};

#endif
16 changes: 16 additions & 0 deletions src/gui/qgsattributedialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ class GUI_EXPORT QgsAttributeDialog : public QObject
*/
bool editable() { return mAttributeForm->editable(); }

/**
* Toggles the form mode between edit feature and add feature.
* If set to true, the dialog will be editable even with an invalid feature.
* If set to true, the dialog will add a new feature when the form is accepted.
*
* @param isAddDialog If set to true, turn this dialog into an add feature dialog.
*/
void setIsAddDialog( bool isAddDialog ) { mAttributeForm->setIsAddDialog( isAddDialog ); }

/**
* Sets the edit command message (Undo) that will be used when the dialog is accepted
*
* @param message The message
*/
void setEditCommandMessage( const QString& message ) { mAttributeForm->setEditCommandMessage( message ); }

public slots:
void accept();

Expand Down
72 changes: 48 additions & 24 deletions src/gui/qgsattributeform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ QgsAttributeForm::QgsAttributeForm( QgsVectorLayer* vl, const QgsFeature feature
, mContext( context )
, mFormNr( sFormCounter++ )
, mIsSaving( false )
, mIsAddDialog( false )
, mEditCommandMessage( tr( "Attributes changed" ) )
{
init();
initPython();
Expand All @@ -60,11 +62,16 @@ QgsAttributeForm::~QgsAttributeForm()
void QgsAttributeForm::hideButtonBox()
{
mButtonBox->hide();

// Make sure that changes are taken into account if somebody tries to figure out if there have been some
connect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
}

void QgsAttributeForm::showButtonBox()
{
mButtonBox->show();

disconnect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
}

void QgsAttributeForm::addInterface( QgsAttributeFormInterface* iface )
Expand All @@ -77,6 +84,13 @@ bool QgsAttributeForm::editable()
return mFeature.isValid() && mLayer->isEditable() ;
}

void QgsAttributeForm::setIsAddDialog( bool isAddDialog )
{
mIsAddDialog = isAddDialog;

synchronizeEnabledState();
}

void QgsAttributeForm::changeAttribute( const QString& field, const QVariant& value )
{
Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
Expand Down Expand Up @@ -118,7 +132,8 @@ bool QgsAttributeForm::save()
if ( !success )
return false;

if ( mFeature.isValid() )

if ( mFeature.isValid() || mIsAddDialog )
{
bool doUpdate = false;

Expand Down Expand Up @@ -154,28 +169,43 @@ bool QgsAttributeForm::save()

if ( doUpdate )
{
mLayer->beginEditCommand( tr( "Attributes changed" ) );

for ( int i = 0; i < dst.count(); ++i )
{
if ( dst[i] == src[i] || !src[i].isValid() )
continue;
mLayer->beginEditCommand( mEditCommandMessage );

success &= mLayer->changeAttributeValue( mFeature.id(), i, dst[i], src[i] );
}

if ( success )
if ( mIsAddDialog )
{
mLayer->endEditCommand();
mFeature.setAttributes( dst );
mFeature.setValid( true );
mLayer->beginEditCommand( mEditCommandMessage );
bool res = mLayer->addFeature( updatedFeature );
if ( res )
mLayer->endEditCommand();
else
mLayer->destroyEditCommand();
}
else
{
mLayer->destroyEditCommand();
for ( int i = 0; i < dst.count(); ++i )
{
if ( dst[i] == src[i] || !src[i].isValid() )
continue;

success &= mLayer->changeAttributeValue( mFeature.id(), i, dst[i], src[i] );
}

if ( success )
{
mLayer->endEditCommand();
mFeature.setAttributes( dst );
}
else
{
mLayer->destroyEditCommand();
}
}
}
}

emit featureSaved( mFeature );

mIsSaving = false;

return success;
Expand Down Expand Up @@ -227,21 +257,16 @@ void QgsAttributeForm::onAttributeDeleted( int idx )

void QgsAttributeForm::synchronizeEnabledState()
{
bool isEditable = ( mFeature.isValid() || mIsAddDialog ) && mLayer->isEditable();

Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
{
if ( mFeature.isValid() && mLayer->isEditable() )
{
ww->setEnabled( true );
}
else
{
ww->setEnabled( false );
}
ww->setEnabled( isEditable );
}

QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
if ( okButton )
okButton->setEnabled( mFeature.isValid() && mLayer->isEditable() );
okButton->setEnabled( isEditable );
}

void QgsAttributeForm::init()
Expand Down Expand Up @@ -360,7 +385,6 @@ void QgsAttributeForm::init()
connect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( resetValues() ) );

connect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( synchronizeEnabledState() ) );
connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( synchronizeEnabledState() ) );

Expand Down
24 changes: 24 additions & 0 deletions src/gui/qgsattributeform.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ class GUI_EXPORT QgsAttributeForm : public QWidget

bool editable();

/**
* Toggles the form mode between edit feature and add feature.
* If set to true, the dialog will be editable even with an invalid feature.
* If set to true, the dialog will add a new feature when the form is accepted.
*
* @param isAddDialog If set to true, turn this dialog into an add feature dialog.
*/
void setIsAddDialog( bool isAddDialog );

/**
* Sets the edit command message (Undo) that will be used when the dialog is accepted
*
* @param message The message
*/
void setEditCommandMessage( const QString& message ) { mEditCommandMessage = message; }

signals:
/**
* Notifies about changes of attributes
Expand All @@ -68,6 +84,11 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
*/
void beforeSave( bool& ok );

/**
* Is emitted, when a feature is changed or added
*/
void featureSaved( const QgsFeature& feature );

public slots:
void changeAttribute( const QString& field, const QVariant& value );
void setFeature( const QgsFeature& feature );
Expand Down Expand Up @@ -125,6 +146,9 @@ class GUI_EXPORT QgsAttributeForm : public QWidget

//! Set to true while saving to prevent recursive saves
bool mIsSaving;
bool mIsAddDialog;

QString mEditCommandMessage;
};

#endif // QGSATTRIBUTEFORM_H

4 comments on commit 81293db

@blazek
Copy link
Member

@blazek blazek commented on 81293db Dec 9, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without calling setIsAddDialog( True ) on a dialog acquired in python via iface.getFeatureForm(), the dialog is disabled for new features. But as this method is new in 2.4, I have to fiddle with QGis.QGIS_VERSION_INT.

Does not this commit breaks plugins using attribute dialog for new features?

@m-kuhn
Copy link
Member Author

@m-kuhn m-kuhn commented on 81293db Dec 9, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was actually broken before when the attribute form was changed such that an invalid feature will be used to disable the dialog whereas before an invalid feature was used to denote a new feature.
This commit made it possible to override this behavior.

I think we could call setIsAddDialog( True ) in iface.getFeatureForm for invalid features automatically to be compatible again as of 2.8.

@blazek
Copy link
Member

@blazek blazek commented on 81293db Dec 9, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could call setIsAddDialog( True ) in iface.getFeatureForm for invalid features automatically to be compatible again as of 2.8.

That should work.

@m-kuhn
Copy link
Member Author

@m-kuhn m-kuhn commented on 81293db Dec 10, 2014 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.