QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsattributeformeditorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsattributeformeditorwidget.cpp
3  -------------------------------
4  Date : March 2016
5  Copyright : (C) 2016 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsattributeform.h"
18 #include "qgsmultiedittoolbutton.h"
20 #include "qgseditorwidgetwrapper.h"
21 #include "qgssearchwidgetwrapper.h"
24 #include "qgsaggregatetoolbutton.h"
25 #include "qgsgui.h"
27 #include "qgsvectorlayerutils.h"
28 
29 #include <QLayout>
30 #include <QLabel>
31 #include <QStackedWidget>
32 
34  : QgsAttributeFormWidget( editorWidget, form )
35  , mWidgetType( widgetType )
36  , mEditorWidget( editorWidget )
37  , mForm( form )
38  , mMultiEditButton( new QgsMultiEditToolButton() )
39  , mBlockValueUpdate( false )
40  , mIsMixed( false )
41  , mIsChanged( false )
42 {
43  mConstraintResultLabel = new QLabel( this );
44  mConstraintResultLabel->setObjectName( QStringLiteral( "ConstraintStatus" ) );
45  mConstraintResultLabel->setSizePolicy( QSizePolicy::Fixed, mConstraintResultLabel->sizePolicy().verticalPolicy() );
46 
47  mMultiEditButton->setField( mEditorWidget->field() );
48  mAggregateButton = new QgsAggregateToolButton();
49  mAggregateButton->setType( mEditorWidget->field().type() );
50  connect( mAggregateButton, &QgsAggregateToolButton::aggregateChanged, this, &QgsAttributeFormEditorWidget::onAggregateChanged );
51 
52  if ( mEditorWidget->widget() )
53  {
54  mEditorWidget->widget()->setObjectName( mEditorWidget->field().name() );
55  }
56 
57  connect( mEditorWidget, &QgsEditorWidgetWrapper::valuesChanged, this, &QgsAttributeFormEditorWidget::editorWidgetValuesChanged );
58 
59  connect( mMultiEditButton, &QgsMultiEditToolButton::resetFieldValueTriggered, this, &QgsAttributeFormEditorWidget::resetValue );
60  connect( mMultiEditButton, &QgsMultiEditToolButton::setFieldValueTriggered, this, &QgsAttributeFormEditorWidget::setFieldTriggered );
61 
62  mMultiEditButton->setField( mEditorWidget->field() );
63 
64  updateWidgets();
65 }
66 
68 {
69  //there's a chance these widgets are not currently added to the layout, so have no parent set
70  delete mMultiEditButton;
71 }
72 
74 {
75  Q_ASSERT( !mWidgetType.isEmpty() );
76  const QVariantMap config = mEditorWidget->config();
77  const int fieldIdx = mEditorWidget->fieldIdx();
78 
79  QgsSearchWidgetWrapper *sww = QgsGui::editorWidgetRegistry()->createSearchWidget( mWidgetType, layer(), fieldIdx, config,
80  searchWidgetFrame(), context );
82  searchWidgetFrame()->layout()->addWidget( mAggregateButton );
85  {
86  // create secondary widget for between type searches
87  QgsSearchWidgetWrapper *sww2 = QgsGui::editorWidgetRegistry()->createSearchWidget( mWidgetType, layer(), fieldIdx, config,
88  searchWidgetFrame(), context );
90  }
91 }
92 
93 void QgsAttributeFormEditorWidget::setConstraintStatus( const QString &constraint, const QString &description, const QString &err, QgsEditorWidgetWrapper::ConstraintResult result )
94 {
95  switch ( result )
96  {
98  mConstraintResultLabel->setText( QStringLiteral( "<font color=\"#FF9800\">%1</font>" ).arg( QChar( 0x2718 ) ) );
99  mConstraintResultLabel->setToolTip( description.isEmpty() ? QStringLiteral( "<b>%1</b>: %2" ).arg( constraint, err ) : description );
100  break;
101 
103  mConstraintResultLabel->setText( QStringLiteral( "<font color=\"#FFC107\">%1</font>" ).arg( QChar( 0x2718 ) ) );
104  mConstraintResultLabel->setToolTip( description.isEmpty() ? QStringLiteral( "<b>%1</b>: %2" ).arg( constraint, err ) : description );
105  break;
106 
108  mConstraintResultLabel->setText( QStringLiteral( "<font color=\"#259B24\">%1</font>" ).arg( QChar( 0x2714 ) ) );
109  mConstraintResultLabel->setToolTip( description );
110  break;
111  }
112 }
113 
115 {
116  mConstraintResultLabel->setHidden( !editable );
117 }
118 
120 {
121  return mEditorWidget;
122 }
123 
125 {
126  if ( mEditorWidget && mixed )
127  mEditorWidget->showIndeterminateState();
128  mMultiEditButton->setIsMixed( mixed );
129  mIsMixed = mixed;
130 }
131 
133 {
134  if ( mEditorWidget )
135  {
136  mPreviousValue = mEditorWidget->value();
137  mPreviousAdditionalValues = mEditorWidget->additionalFieldValues();
138  }
139 
140  setIsMixed( false );
141  mMultiEditButton->changesCommitted();
142  mIsChanged = false;
143 }
144 
145 
146 
147 void QgsAttributeFormEditorWidget::initialize( const QVariant &initialValue, bool mixedValues, const QVariantList &additionalFieldValues )
148 {
149  if ( mEditorWidget )
150  {
151  mBlockValueUpdate = true;
152  mEditorWidget->setValues( initialValue, additionalFieldValues );
153  mBlockValueUpdate = false;
154  }
155  mPreviousValue = initialValue;
156  mPreviousAdditionalValues = additionalFieldValues;
157  setIsMixed( mixedValues );
158  mMultiEditButton->setIsChanged( false );
159  mIsChanged = false;
160  updateWidgets();
161 }
162 
164 {
165  return mEditorWidget->value();
166 }
167 
168 
169 
170 void QgsAttributeFormEditorWidget::editorWidgetValuesChanged( const QVariant &value, const QVariantList &additionalFieldValues )
171 {
172  if ( mBlockValueUpdate )
173  return;
174 
175  mIsChanged = true;
176 
177  switch ( mode() )
178  {
179  case DefaultMode:
180  case SearchMode:
181  case AggregateSearchMode:
182  break;
183  case MultiEditMode:
184  mMultiEditButton->setIsChanged( true );
185  }
186 
188  emit valueChanged( value );
190  emit valuesChanged( value, additionalFieldValues );
191 }
192 
193 void QgsAttributeFormEditorWidget::resetValue()
194 {
195  mIsChanged = false;
196  mBlockValueUpdate = true;
197  if ( mEditorWidget )
198  mEditorWidget->setValues( mPreviousValue, mPreviousAdditionalValues );
199  mBlockValueUpdate = false;
200 
201  switch ( mode() )
202  {
203  case DefaultMode:
204  case SearchMode:
205  case AggregateSearchMode:
206  break;
207  case MultiEditMode:
208  {
209  mMultiEditButton->setIsChanged( false );
210  if ( mEditorWidget && mIsMixed )
211  mEditorWidget->showIndeterminateState();
212  break;
213  }
214  }
215 }
216 
217 void QgsAttributeFormEditorWidget::setFieldTriggered()
218 {
219  mIsChanged = true;
220 }
221 
222 void QgsAttributeFormEditorWidget::onAggregateChanged()
223 {
224  const auto constWigets( searchWidgetWrappers() );
225  for ( QgsSearchWidgetWrapper *searchWidget : constWigets )
226  searchWidget->setAggregate( mAggregateButton->aggregate() );
227 }
228 
229 void QgsAttributeFormEditorWidget::updateWidgets()
230 {
231  //first update the tool buttons
232  const bool hasMultiEditButton = ( editPage()->layout()->indexOf( mMultiEditButton ) >= 0 );
233 
234  bool shouldShowMultiEditButton = false;
235  switch ( mode() )
236  {
240  // in these modes we don't show the multi edit button
241  shouldShowMultiEditButton = false;
242  break;
243 
245  {
246  // in multi-edit mode we need to know upfront whether or not to allow add the multiedit buttons
247  // for this field.
248  // if the field is always read only regardless of the feature, no need to dig further. But otherwise
249  // we may need to test editability for the actual selected features...
250  const int fieldIndex = mEditorWidget->fieldIdx();
251  shouldShowMultiEditButton = !QgsVectorLayerUtils::fieldIsReadOnly( layer(), fieldIndex );
252  if ( shouldShowMultiEditButton )
253  {
254  // depending on the field type, the editability of the field may vary feature by feature (e.g. for joined
255  // fields coming from joins without the upsert on edit capabilities).
256  // But this feature-by-feature check is EXPENSIVE!!! (see https://github.com/qgis/QGIS/issues/41366), so
257  // avoid it whenever we can...
258  const bool fieldEditabilityDependsOnFeature = QgsVectorLayerUtils::fieldEditabilityDependsOnFeature( layer(), fieldIndex );
259  if ( fieldEditabilityDependsOnFeature )
260  {
261  QgsFeature feature;
263  while ( it.nextFeature( feature ) )
264  {
265  const bool isEditable = QgsVectorLayerUtils::fieldIsEditable( layer(), fieldIndex, feature );
266  if ( !isEditable )
267  {
268  // as soon as we find one read-only feature for the field, we can break early...
269  shouldShowMultiEditButton = false;
270  break;
271  }
272  }
273  }
274  }
275  }
276  break;
277  }
278 
279  if ( hasMultiEditButton && !shouldShowMultiEditButton )
280  {
281  editPage()->layout()->removeWidget( mMultiEditButton );
282  mMultiEditButton->setParent( nullptr );
283  }
284  else if ( !hasMultiEditButton && shouldShowMultiEditButton )
285  {
286  editPage()->layout()->addWidget( mMultiEditButton );
287  }
288 
289  switch ( mode() )
290  {
291  case DefaultMode:
292  case MultiEditMode:
293  {
294  stack()->setCurrentWidget( editPage() );
295  editPage()->layout()->addWidget( mConstraintResultLabel );
296  break;
297  }
298 
299  case AggregateSearchMode:
300  {
301  mAggregateButton->setVisible( true );
302  stack()->setCurrentWidget( searchPage() );
303  break;
304  }
305 
306  case SearchMode:
307  {
308  mAggregateButton->setVisible( false );
309  stack()->setCurrentWidget( searchPage() );
310  break;
311  }
312  }
313 }
QgsAttributeFormWidget::DefaultMode
@ DefaultMode
Default mode, only the editor widget is shown.
Definition: qgsattributeformwidget.h:47
QgsGui::editorWidgetRegistry
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition: qgsgui.cpp:85
qgssearchwidgettoolbutton.h
qgseditorwidgetwrapper.h
QgsAttributeFormEditorWidget::currentValue
QVariant currentValue() const
Returns the current value of the attached editor widget.
Definition: qgsattributeformeditorwidget.cpp:163
QgsEditorWidgetWrapper::setValues
void setValues(const QVariant &value, const QVariantList &additionalValues)
Is called when the value of the widget or additional field values needs to be changed.
Definition: qgseditorwidgetwrapper.cpp:86
qgsattributeform.h
QgsAttributeFormWidget::mode
Mode mode() const
Returns the current mode for the widget.
Definition: qgsattributeformwidget.h:86
QgsSearchWidgetWrapper::Between
@ Between
Supports searches between two values.
Definition: qgssearchwidgetwrapper.h:102
QgsMultiEditToolButton::setFieldValueTriggered
void setFieldValueTriggered()
Emitted when the "set field value for all features" option is selected.
QgsEditorWidgetWrapper::ConstraintResultFailHard
@ ConstraintResultFailHard
Widget failed at least one hard (enforced) constraint.
Definition: qgseditorwidgetwrapper.h:63
qgsaggregatetoolbutton.h
qgsgui.h
QgsEditorWidgetWrapper::additionalFieldValues
virtual QVariantList additionalFieldValues() const
Will be used to access the widget's values for potential additional fields handled by the widget.
Definition: qgseditorwidgetwrapper.h:100
QgsSearchWidgetWrapper
Shows a search widget on a filter form.
Definition: qgssearchwidgetwrapper.h:85
QgsAttributeFormWidget::layer
QgsVectorLayer * layer()
The layer for which this widget and its form is shown.
Definition: qgsattributeformwidget.cpp:146
QgsMultiEditToolButton::resetFieldValueTriggered
void resetFieldValueTriggered()
Emitted when the "reset to original values" option is selected.
QgsAttributeFormWidget::AggregateSearchMode
@ AggregateSearchMode
Embedded in a search form, show additional aggregate function toolbutton.
Definition: qgsattributeformwidget.h:50
QgsMultiEditToolButton::setIsChanged
void setIsChanged(bool changed)
Sets whether the associated field has changed.
Definition: qgsmultiedittoolbutton.h:80
QgsEditorWidgetWrapper::value
virtual QVariant value() const =0
Will be used to access the widget's value.
QgsAttributeFormEditorWidget::setConstraintStatus
void setConstraintStatus(const QString &constraint, const QString &description, const QString &err, QgsEditorWidgetWrapper::ConstraintResult result)
Set the constraint status for this widget.
Definition: qgsattributeformeditorwidget.cpp:93
QgsAttributeFormEditorWidget::editorWidget
QgsEditorWidgetWrapper * editorWidget() const
Returns the editor widget wrapper.
Definition: qgsattributeformeditorwidget.cpp:119
QgsAggregateToolButton::aggregateChanged
void aggregateChanged()
The function name of the selected aggregate has changed.
QgsEditorWidgetWrapper::ConstraintResult
ConstraintResult
Result of constraint checks.
Definition: qgseditorwidgetwrapper.h:60
QgsField::name
QString name
Definition: qgsfield.h:60
QgsAttributeFormWidget::addAdditionalSearchWidgetWrapper
void addAdditionalSearchWidgetWrapper(QgsSearchWidgetWrapper *wrapper)
Adds an additional search widget wrapper.
Definition: qgsattributeformwidget.cpp:97
QgsAttributeFormEditorWidget::valueChanged
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emitted when the widget's value changes.
QgsSearchWidgetWrapper::supportedFlags
virtual FilterFlags supportedFlags() const
Returns filter flags supported by the search widget.
Definition: qgssearchwidgetwrapper.cpp:94
QgsWidgetWrapper::widget
QWidget * widget()
Access the widget managed by this wrapper.
Definition: qgswidgetwrapper.cpp:47
QgsEditorWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgseditorwidgetwrapper.h:47
QgsMultiEditToolButton::setField
void setField(const QgsField &field)
Sets the field associated with this button.
Definition: qgsmultiedittoolbutton.h:62
QgsAggregateToolButton::aggregate
QString aggregate() const
The function name of the selected aggregate or a Null String if none is chosen.
Definition: qgsaggregatetoolbutton.cpp:89
QgsEditorWidgetWrapper::fieldIdx
int fieldIdx() const
Access the field index.
Definition: qgseditorwidgetwrapper.cpp:34
QgsAttributeFormEditorWidget::createSearchWidgetWrappers
void createSearchWidgetWrappers(const QgsAttributeEditorContext &context=QgsAttributeEditorContext()) override
Creates the search widget wrappers for the widget used when the form is in search mode.
Definition: qgsattributeformeditorwidget.cpp:73
QgsAttributeFormWidget::MultiEditMode
@ MultiEditMode
Multi edit mode, both the editor widget and a QgsMultiEditToolButton is shown.
Definition: qgsattributeformwidget.h:48
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsEditorWidgetWrapper::ConstraintResultPass
@ ConstraintResultPass
Widget passed constraints successfully.
Definition: qgseditorwidgetwrapper.h:62
QgsAttributeFormEditorWidget::~QgsAttributeFormEditorWidget
~QgsAttributeFormEditorWidget() override
Definition: qgsattributeformeditorwidget.cpp:67
QgsMultiEditToolButton::setIsMixed
void setIsMixed(bool mixed)
Sets whether the associated field contains mixed values.
Definition: qgsmultiedittoolbutton.h:72
QgsWidgetWrapper::config
QVariant config(const QString &key, const QVariant &defaultVal=QVariant()) const
Use this inside your overridden classes to access the configuration.
Definition: qgswidgetwrapper.cpp:73
QgsAttributeFormEditorWidget::changesCommitted
void changesCommitted()
Called when field values have been committed;.
Definition: qgsattributeformeditorwidget.cpp:132
qgsvectorlayerjoinbuffer.h
QgsEditorWidgetRegistry::createSearchWidget
QgsSearchWidgetWrapper * createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Definition: qgseditorwidgetregistry.cpp:130
QgsAttributeFormEditorWidget::valuesChanged
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues)
Emitted when the widget's value changes.
QgsAttributeFormEditorWidget::initialize
void initialize(const QVariant &initialValue, bool mixedValues=false, const QVariantList &additionalFieldValues=QVariantList())
Resets the widget to an initial value.
Definition: qgsattributeformeditorwidget.cpp:147
qgssearchwidgetwrapper.h
qgsattributeformeditorwidget.h
QgsAttributeFormWidget::searchWidgetFrame
QWidget * searchWidgetFrame()
Returns the widget which should be used as a parent during construction of the search widget wrapper.
Definition: qgsattributeformwidget.cpp:80
QgsSearchWidgetWrapper::IsNotBetween
@ IsNotBetween
Supports searching for values outside of a set range.
Definition: qgssearchwidgetwrapper.h:107
qgsvectorlayerutils.h
QgsAttributeFormEditorWidget::setConstraintResultVisible
void setConstraintResultVisible(bool editable)
Set the constraint result label visible or invisible according to the layer editable status.
Definition: qgsattributeformeditorwidget.cpp:114
QgsEditorWidgetWrapper::field
QgsField field() const
Access the field.
Definition: qgseditorwidgetwrapper.cpp:39
qgsattributeeditorcontext.h
qgsmultiedittoolbutton.h
QgsAttributeFormWidget::SearchMode
@ SearchMode
Layer search/filter mode.
Definition: qgsattributeformwidget.h:49
QgsMultiEditToolButton
A tool button widget which is displayed next to editor widgets in attribute forms,...
Definition: qgsmultiedittoolbutton.h:32
QgsMultiEditToolButton::changesCommitted
void changesCommitted()
Called when field values have been changed and field now contains all the same values.
Definition: qgsmultiedittoolbutton.h:94
QgsVectorLayer::getSelectedFeatures
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
Definition: qgsvectorlayer.cpp:3642
QgsEditorWidgetWrapper::valuesChanged
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
qgseditorwidgetregistry.h
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsEditorWidgetWrapper::ConstraintResultFailSoft
@ ConstraintResultFailSoft
Widget failed at least one soft (non-enforced) constraint.
Definition: qgseditorwidgetwrapper.h:64
QgsVectorLayerUtils::fieldIsEditable
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
Tests whether a field is editable for a particular feature.
Definition: qgsvectorlayerutils.cpp:919
QgsAttributeFormWidget::stack
QStackedWidget * stack() const
Returns a pointer to the stacked widget managing edit and search page.
Definition: qgsattributeformwidget.cpp:205
QgsAggregateToolButton
Offers a toolbutton to choose between different aggregate functions. Functions are filtered based on ...
Definition: qgsaggregatetoolbutton.h:33
QgsAttributeFormEditorWidget::setIsMixed
void setIsMixed(bool mixed)
Sets whether the widget should be displayed in a "mixed values" mode.
Definition: qgsattributeformeditorwidget.cpp:124
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsAttributeForm
Definition: qgsattributeform.h:44
QgsAttributeFormEditorWidget::QgsAttributeFormEditorWidget
QgsAttributeFormEditorWidget(QgsEditorWidgetWrapper *editorWidget, const QString &widgetType, QgsAttributeForm *form)
Constructor for QgsAttributeFormEditorWidget.
Definition: qgsattributeformeditorwidget.cpp:33
QgsVectorLayerUtils::fieldIsReadOnly
static bool fieldIsReadOnly(const QgsVectorLayer *layer, int fieldIndex)
Definition: qgsvectorlayerutils.cpp:871
QgsAttributeEditorContext
This class contains context information for attribute editor widgets. It will be passed to embedded w...
Definition: qgsattributeeditorcontext.h:40
QgsAggregateToolButton::setType
void setType(QVariant::Type type)
Based on the type of underlying data, some aggregates will be available or not.
Definition: qgsaggregatetoolbutton.cpp:34
QgsAttributeFormWidget::searchWidgetWrappers
QList< QgsSearchWidgetWrapper * > searchWidgetWrappers()
Returns the search widget wrapper used in this widget.
Definition: qgsattributeformwidget.cpp:105
QgsAttributeFormWidget::searchPage
QWidget * searchPage() const
Returns a pointer to the search page widget.
Definition: qgsattributeformwidget.cpp:200
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsAttributeFormWidget::setSearchWidgetWrapper
void setSearchWidgetWrapper(QgsSearchWidgetWrapper *wrapper)
Sets the search widget wrapper for the widget used when the form is in search mode.
Definition: qgsattributeformwidget.cpp:85
QgsAttributeFormWidget
Base class for all widgets shown on a QgsAttributeForm. Consists of the widget which is visible in ed...
Definition: qgsattributeformwidget.h:38
QgsField::type
QVariant::Type type
Definition: qgsfield.h:58
QgsVectorLayerUtils::fieldEditabilityDependsOnFeature
static bool fieldEditabilityDependsOnFeature(const QgsVectorLayer *layer, int fieldIndex)
Returns true if the editability of the field at index fieldIndex from layer may vary feature by featu...
Definition: qgsvectorlayerutils.cpp:898
QgsEditorWidgetWrapper::showIndeterminateState
virtual void showIndeterminateState()
Sets the widget to display in an indeterminate "mixed value" state.
Definition: qgseditorwidgetwrapper.h:155
QgsAttributeFormWidget::editPage
QWidget * editPage() const
Returns a pointer to the EDIT page widget.
Definition: qgsattributeformwidget.cpp:210