Skip to content

Commit 81293db

Browse files
committed
Fix add attribute dialog
Fix #10337
1 parent 3871ce7 commit 81293db

File tree

5 files changed

+127
-56
lines changed

5 files changed

+127
-56
lines changed

src/app/qgsfeatureaction.cpp

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
165165
QgsDebugMsg( QString( "Using specified default %1 for %2" ).arg( defaultAttributes.value( idx ).toString() ).arg( idx ) );
166166
mFeature.setAttribute( idx, defaultAttributes.value( idx ) );
167167
}
168-
else if ( reuseLastValues && mLastUsedValues.contains( mLayer ) && mLastUsedValues[ mLayer ].contains( idx ) )
168+
else if ( reuseLastValues && sLastUsedValues.contains( mLayer ) && sLastUsedValues[ mLayer ].contains( idx ) )
169169
{
170-
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( mLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
171-
mFeature.setAttribute( idx, mLastUsedValues[ mLayer ][idx] );
170+
QgsDebugMsg( QString( "reusing %1 for %2" ).arg( sLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
171+
mFeature.setAttribute( idx, sLastUsedValues[ mLayer ][idx] );
172172
}
173173
else
174174
{
@@ -178,7 +178,7 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
178178

179179
bool res = false;
180180

181-
mLayer->beginEditCommand( text() );
181+
182182

183183
// show the dialog to enter attribute values
184184
bool isDisabledAttributeValuesDlg = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", false ).toBool();
@@ -196,7 +196,13 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
196196
}
197197
if ( isDisabledAttributeValuesDlg )
198198
{
199+
mLayer->beginEditCommand( text() );
199200
res = mLayer->addFeature( mFeature );
201+
202+
if ( res )
203+
mLayer->endEditCommand();
204+
else
205+
mLayer->destroyEditCommand();
200206
}
201207
else
202208
{
@@ -205,36 +211,34 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap& defaultAttributes )
205211
origValues = mFeature.attributes();
206212

207213
QgsAttributeDialog *dialog = newDialog( false );
208-
if ( dialog->exec() )
209-
{
210-
if ( reuseLastValues )
211-
{
212-
for ( int idx = 0; idx < fields.count(); ++idx )
213-
{
214-
const QgsAttributes &newValues = mFeature.attributes();
215-
if ( origValues[idx] != newValues[idx] )
216-
{
217-
QgsDebugMsg( QString( "saving %1 for %2" ).arg( mLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
218-
mLastUsedValues[ mLayer ][idx] = newValues[idx];
219-
}
220-
}
221-
}
222-
223-
res = mLayer->addFeature( mFeature );
224-
}
225-
else
214+
dialog->setIsAddDialog( true );
215+
dialog->setEditCommandMessage( text() );
216+
dialog->exec();
217+
if ( reuseLastValues )
226218
{
227-
QgsDebugMsg( "Adding feature to layer failed" );
228-
res = false;
219+
connect( dialog->dialog(), SIGNAL( featureSaved( const QgsFeature& feature ) ), this, SLOT( updateLastUsedValues( const QgsFeature& feature ) ) );
229220
}
230221
}
231222

232-
if ( res )
233-
mLayer->endEditCommand();
234-
else
235-
mLayer->destroyEditCommand();
236-
237223
return res;
238224
}
239225

240-
QMap<QgsVectorLayer *, QgsAttributeMap> QgsFeatureAction::mLastUsedValues;
226+
void QgsFeatureAction::updateLastUsedValues( const QgsFeature& feature )
227+
{
228+
QgsAttributeForm* form = qobject_cast<QgsAttributeForm*>( sender() );
229+
Q_ASSERT( form );
230+
231+
QgsFields fields = mLayer->pendingFields();
232+
for ( int idx = 0; idx < fields.count(); ++idx )
233+
{
234+
const QgsAttributes &newValues = feature.attributes();
235+
QgsAttributeMap origValues = sLastUsedValues[ mLayer ];
236+
if ( origValues[idx] != newValues[idx] )
237+
{
238+
QgsDebugMsg( QString( "saving %1 for %2" ).arg( sLastUsedValues[ mLayer ][idx].toString() ).arg( idx ) );
239+
sLastUsedValues[ mLayer ][idx] = newValues[idx];
240+
}
241+
}
242+
}
243+
244+
QMap<QgsVectorLayer *, QgsAttributeMap> QgsFeatureAction::sLastUsedValues;

src/app/qgsfeatureaction.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
qgsfeatureaction.h - description
33
------------------
44
begin : 2010-09-20
5-
copyright : (C) 2010 by Jürgen E. Fischer
5+
copyright : (C) 2010 by Jürgen E. Fischer
66
email : jef at norbit dot de
77
***************************************************************************/
88

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

55+
private slots:
56+
void updateLastUsedValues( const QgsFeature& feature );
57+
5558
private:
5659
QgsAttributeDialog *newDialog( bool cloneFeature );
5760

@@ -60,7 +63,7 @@ class APP_EXPORT QgsFeatureAction : public QAction
6063
int mAction;
6164
int mIdx;
6265

63-
static QMap<QgsVectorLayer *, QgsAttributeMap> mLastUsedValues;
66+
static QMap<QgsVectorLayer *, QgsAttributeMap> sLastUsedValues;
6467
};
6568

6669
#endif

src/gui/qgsattributedialog.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,22 @@ class GUI_EXPORT QgsAttributeDialog : public QObject
9393
*/
9494
bool editable() { return mAttributeForm->editable(); }
9595

96+
/**
97+
* Toggles the form mode between edit feature and add feature.
98+
* If set to true, the dialog will be editable even with an invalid feature.
99+
* If set to true, the dialog will add a new feature when the form is accepted.
100+
*
101+
* @param isAddDialog If set to true, turn this dialog into an add feature dialog.
102+
*/
103+
void setIsAddDialog( bool isAddDialog ) { mAttributeForm->setIsAddDialog( isAddDialog ); }
104+
105+
/**
106+
* Sets the edit command message (Undo) that will be used when the dialog is accepted
107+
*
108+
* @param message The message
109+
*/
110+
void setEditCommandMessage( const QString& message ) { mAttributeForm->setEditCommandMessage( message ); }
111+
96112
public slots:
97113
void accept();
98114

src/gui/qgsattributeform.cpp

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ QgsAttributeForm::QgsAttributeForm( QgsVectorLayer* vl, const QgsFeature feature
4242
, mContext( context )
4343
, mFormNr( sFormCounter++ )
4444
, mIsSaving( false )
45+
, mIsAddDialog( false )
46+
, mEditCommandMessage( tr( "Attributes changed" ) )
4547
{
4648
init();
4749
initPython();
@@ -60,11 +62,16 @@ QgsAttributeForm::~QgsAttributeForm()
6062
void QgsAttributeForm::hideButtonBox()
6163
{
6264
mButtonBox->hide();
65+
66+
// Make sure that changes are taken into account if somebody tries to figure out if there have been some
67+
connect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
6368
}
6469

6570
void QgsAttributeForm::showButtonBox()
6671
{
6772
mButtonBox->show();
73+
74+
disconnect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
6875
}
6976

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

87+
void QgsAttributeForm::setIsAddDialog( bool isAddDialog )
88+
{
89+
mIsAddDialog = isAddDialog;
90+
91+
synchronizeEnabledState();
92+
}
93+
8094
void QgsAttributeForm::changeAttribute( const QString& field, const QVariant& value )
8195
{
8296
Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
@@ -118,7 +132,8 @@ bool QgsAttributeForm::save()
118132
if ( !success )
119133
return false;
120134

121-
if ( mFeature.isValid() )
135+
136+
if ( mFeature.isValid() || mIsAddDialog )
122137
{
123138
bool doUpdate = false;
124139

@@ -154,28 +169,43 @@ bool QgsAttributeForm::save()
154169

155170
if ( doUpdate )
156171
{
157-
mLayer->beginEditCommand( tr( "Attributes changed" ) );
158-
159-
for ( int i = 0; i < dst.count(); ++i )
160-
{
161-
if ( dst[i] == src[i] || !src[i].isValid() )
162-
continue;
172+
mLayer->beginEditCommand( mEditCommandMessage );
163173

164-
success &= mLayer->changeAttributeValue( mFeature.id(), i, dst[i], src[i] );
165-
}
166-
167-
if ( success )
174+
if ( mIsAddDialog )
168175
{
169-
mLayer->endEditCommand();
170-
mFeature.setAttributes( dst );
176+
mFeature.setValid( true );
177+
mLayer->beginEditCommand( mEditCommandMessage );
178+
bool res = mLayer->addFeature( updatedFeature );
179+
if ( res )
180+
mLayer->endEditCommand();
181+
else
182+
mLayer->destroyEditCommand();
171183
}
172184
else
173185
{
174-
mLayer->destroyEditCommand();
186+
for ( int i = 0; i < dst.count(); ++i )
187+
{
188+
if ( dst[i] == src[i] || !src[i].isValid() )
189+
continue;
190+
191+
success &= mLayer->changeAttributeValue( mFeature.id(), i, dst[i], src[i] );
192+
}
193+
194+
if ( success )
195+
{
196+
mLayer->endEditCommand();
197+
mFeature.setAttributes( dst );
198+
}
199+
else
200+
{
201+
mLayer->destroyEditCommand();
202+
}
175203
}
176204
}
177205
}
178206

207+
emit featureSaved( mFeature );
208+
179209
mIsSaving = false;
180210

181211
return success;
@@ -227,21 +257,16 @@ void QgsAttributeForm::onAttributeDeleted( int idx )
227257

228258
void QgsAttributeForm::synchronizeEnabledState()
229259
{
260+
bool isEditable = ( mFeature.isValid() || mIsAddDialog ) && mLayer->isEditable();
261+
230262
Q_FOREACH( QgsWidgetWrapper* ww, mWidgets )
231263
{
232-
if ( mFeature.isValid() && mLayer->isEditable() )
233-
{
234-
ww->setEnabled( true );
235-
}
236-
else
237-
{
238-
ww->setEnabled( false );
239-
}
264+
ww->setEnabled( isEditable );
240265
}
241266

242267
QPushButton* okButton = mButtonBox->button( QDialogButtonBox::Ok );
243268
if ( okButton )
244-
okButton->setEnabled( mFeature.isValid() && mLayer->isEditable() );
269+
okButton->setEnabled( isEditable );
245270
}
246271

247272
void QgsAttributeForm::init()
@@ -360,7 +385,6 @@ void QgsAttributeForm::init()
360385
connect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
361386
connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( resetValues() ) );
362387

363-
connect( mLayer, SIGNAL( beforeModifiedCheck() ), this, SLOT( save() ) );
364388
connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( synchronizeEnabledState() ) );
365389
connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( synchronizeEnabledState() ) );
366390

src/gui/qgsattributeform.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
5050

5151
bool editable();
5252

53+
/**
54+
* Toggles the form mode between edit feature and add feature.
55+
* If set to true, the dialog will be editable even with an invalid feature.
56+
* If set to true, the dialog will add a new feature when the form is accepted.
57+
*
58+
* @param isAddDialog If set to true, turn this dialog into an add feature dialog.
59+
*/
60+
void setIsAddDialog( bool isAddDialog );
61+
62+
/**
63+
* Sets the edit command message (Undo) that will be used when the dialog is accepted
64+
*
65+
* @param message The message
66+
*/
67+
void setEditCommandMessage( const QString& message ) { mEditCommandMessage = message; }
68+
5369
signals:
5470
/**
5571
* Notifies about changes of attributes
@@ -68,6 +84,11 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
6884
*/
6985
void beforeSave( bool& ok );
7086

87+
/**
88+
* Is emitted, when a feature is changed or added
89+
*/
90+
void featureSaved( const QgsFeature& feature );
91+
7192
public slots:
7293
void changeAttribute( const QString& field, const QVariant& value );
7394
void setFeature( const QgsFeature& feature );
@@ -125,6 +146,9 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
125146

126147
//! Set to true while saving to prevent recursive saves
127148
bool mIsSaving;
149+
bool mIsAddDialog;
150+
151+
QString mEditCommandMessage;
128152
};
129153

130154
#endif // QGSATTRIBUTEFORM_H

0 commit comments

Comments
 (0)