QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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"
22 #include "qgseditorwidgetconfig.h"
25 #include <QLayout>
26 #include <QLabel>
27 #include <QStackedWidget>
28 
30  QgsAttributeForm* form )
31  : QWidget( form )
32  , mWidget( editorWidget )
33  , mForm( form )
34  , mMode( DefaultMode )
35  , mMultiEditButton( new QgsMultiEditToolButton() )
36  , mBlockValueUpdate( false )
37  , mIsMixed( false )
38  , mIsChanged( false )
39 {
40  mEditPage = new QWidget();
41  QHBoxLayout* l = new QHBoxLayout();
42  l->setMargin( 0 );
43  l->setContentsMargins( 0, 0, 0, 0 );
44  mEditPage->setLayout( l );
45 
46  l = new QHBoxLayout();
47  l->setMargin( 0 );
48  l->setContentsMargins( 0, 0, 0, 0 );
49  mSearchFrame = new QWidget();
50  mSearchFrame->setLayout( l );
51 
52  mSearchPage = new QWidget();
53  l = new QHBoxLayout();
54  l->setMargin( 0 );
55  l->setContentsMargins( 0, 0, 0, 0 );
56  mSearchPage->setLayout( l );
57  l->addWidget( mSearchFrame, 1 );
58  mSearchWidgetToolButton = new QgsSearchWidgetToolButton();
59  connect( mSearchWidgetToolButton, SIGNAL( activeFlagsChanged( QgsSearchWidgetWrapper::FilterFlags ) ),
60  this, SLOT( searchWidgetFlagsChanged( QgsSearchWidgetWrapper::FilterFlags ) ) );
61  l->addWidget( mSearchWidgetToolButton, 0 );
62 
63 
64  mStack = new QStackedWidget;
65  mStack->addWidget( mEditPage );
66  mStack->addWidget( mSearchPage );
67 
68  l = new QHBoxLayout();
69  l->setMargin( 0 );
70  l->setContentsMargins( 0, 0, 0, 0 );
71  setLayout( l );
72  l->addWidget( mStack );
73 
74  if ( !mWidget || !mForm )
75  return;
76 
77  mEditPage->layout()->addWidget( mWidget->widget() );
78 
79  if ( mWidget->widget() )
80  {
81  mWidget->widget()->setObjectName( mWidget->field().name() );
82  }
83  connect( mWidget, SIGNAL( valueChanged( const QVariant& ) ), this, SLOT( editorWidgetChanged( const QVariant & ) ) );
84  connect( mMultiEditButton, SIGNAL( resetFieldValueTriggered() ), this, SLOT( resetValue() ) );
85  connect( mMultiEditButton, SIGNAL( setFieldValueTriggered() ), this, SLOT( setFieldTriggered() ) );
86 
87  mMultiEditButton->setField( mWidget->field() );
88 
89  updateWidgets();
90 }
91 
93 {
94  //there's a chance these widgets are not currently added to the layout, so have no parent set
95  delete mMultiEditButton;
96 }
97 
99 {
100  QgsSearchWidgetWrapper* sww = QgsEditorWidgetRegistry::instance()->createSearchWidget( widgetId, layer(), fieldIdx, config,
101  mSearchFrame, context );
102  setSearchWidgetWrapper( sww );
105  {
106  // create secondary widget for between type searches
107  QgsSearchWidgetWrapper* sww2 = QgsEditorWidgetRegistry::instance()->createSearchWidget( widgetId, layer(), fieldIdx, config,
108  mSearchFrame, context );
109  mSearchWidgets << sww2;
110  mSearchFrame->layout()->addWidget( sww2->widget() );
111  sww2->widget()->hide();
112  }
113 }
114 
116 {
117  mSearchWidgets.clear();
118  mSearchWidgets << wrapper;
119  mSearchFrame->layout()->addWidget( wrapper->widget() );
120  mSearchWidgetToolButton->setAvailableFlags( wrapper->supportedFlags() );
121  mSearchWidgetToolButton->setActiveFlags( QgsSearchWidgetWrapper::FilterFlags() );
122  mSearchWidgetToolButton->setDefaultFlags( wrapper->defaultFlags() );
123  connect( wrapper, SIGNAL( valueChanged() ), mSearchWidgetToolButton, SLOT( searchWidgetValueChanged() ) );
124  connect( wrapper, SIGNAL( valueCleared() ), mSearchWidgetToolButton, SLOT( setInactive() ) );
125 }
126 
128 {
129  return mSearchFrame;
130 }
131 
133 {
134  return mSearchWidgets;
135 }
136 
138 {
139  mMode = mode;
140  updateWidgets();
141 }
142 
144 {
145  if ( mWidget && mixed )
146  mWidget->showIndeterminateState( );
147  mMultiEditButton->setIsMixed( mixed );
148  mIsMixed = mixed;
149 }
150 
152 {
153  if ( mWidget )
154  mPreviousValue = mWidget->value();
155 
156  setIsMixed( false );
157  mMultiEditButton->changesCommitted();
158  mIsChanged = false;
159 }
160 
162 {
163  mSearchWidgetToolButton->setInactive();
164  Q_FOREACH ( QgsSearchWidgetWrapper* widget, mSearchWidgets )
165  {
166  widget->clearWidget();
167  }
168 }
169 
170 void QgsAttributeFormEditorWidget::initialize( const QVariant& initialValue, bool mixedValues )
171 {
172  if ( mWidget )
173  {
174  mBlockValueUpdate = true;
175  mWidget->setValue( initialValue );
176  mBlockValueUpdate = false;
177  }
178  mPreviousValue = initialValue;
179  setIsMixed( mixedValues );
180  mMultiEditButton->setIsChanged( false );
181  mIsChanged = false;
182 }
183 
185 {
186  return mWidget->value();
187 }
188 
190 {
191  if ( mSearchWidgets.isEmpty() )
192  return QString();
193 
194  if ( !mSearchWidgetToolButton->isActive() )
195  return QString();
196 
197  if ( mSearchWidgetToolButton->activeFlags() & QgsSearchWidgetWrapper::Between )
198  {
199  // special case: Between search
200  QString filter1 = mSearchWidgets.at( 0 )->createExpression( QgsSearchWidgetWrapper::GreaterThanOrEqualTo );
201  QString filter2 = mSearchWidgets.at( 1 )->createExpression( QgsSearchWidgetWrapper::LessThanOrEqualTo );
202  return QString( "%1 AND %2" ).arg( filter1, filter2 );
203  }
204  else if ( mSearchWidgetToolButton->activeFlags() & QgsSearchWidgetWrapper::IsNotBetween )
205  {
206  // special case: Is Not Between search
207  QString filter1 = mSearchWidgets.at( 0 )->createExpression( QgsSearchWidgetWrapper::LessThan );
208  QString filter2 = mSearchWidgets.at( 1 )->createExpression( QgsSearchWidgetWrapper::GreaterThan );
209  return QString( "%1 OR %2" ).arg( filter1, filter2 );
210  }
211 
212  return mSearchWidgets.at( 0 )->createExpression( mSearchWidgetToolButton->activeFlags() );
213 }
214 
215 void QgsAttributeFormEditorWidget::editorWidgetChanged( const QVariant& value )
216 {
217  if ( mBlockValueUpdate )
218  return;
219 
220  mIsChanged = true;
221 
222  switch ( mMode )
223  {
224  case DefaultMode:
225  case SearchMode:
226  break;
227  case MultiEditMode:
228  mMultiEditButton->setIsChanged( true );
229  }
230 
231  emit valueChanged( value );
232 }
233 
234 void QgsAttributeFormEditorWidget::resetValue()
235 {
236  mIsChanged = false;
237  mBlockValueUpdate = true;
238  if ( mWidget )
239  mWidget->setValue( mPreviousValue );
240  mBlockValueUpdate = false;
241 
242  switch ( mMode )
243  {
244  case DefaultMode:
245  case SearchMode:
246  break;
247  case MultiEditMode:
248  {
249  mMultiEditButton->setIsChanged( false );
250  if ( mWidget && mIsMixed )
251  mWidget->showIndeterminateState();
252  break;
253  }
254  }
255 }
256 
257 void QgsAttributeFormEditorWidget::setFieldTriggered()
258 {
259  mIsChanged = true;
260 }
261 
262 void QgsAttributeFormEditorWidget::searchWidgetFlagsChanged( QgsSearchWidgetWrapper::FilterFlags flags )
263 {
264  Q_FOREACH ( QgsSearchWidgetWrapper* widget, mSearchWidgets )
265  {
266  widget->setEnabled( !( flags & QgsSearchWidgetWrapper::IsNull )
267  && !( flags & QgsSearchWidgetWrapper::IsNotNull ) );
268  if ( !mSearchWidgetToolButton->isActive() )
269  {
270  widget->clearWidget();
271  }
272  }
273 
274  if ( mSearchWidgets.count() >= 2 )
275  {
276  mSearchWidgets.at( 1 )->widget()->setVisible( flags & QgsSearchWidgetWrapper::Between ||
278  }
279 }
280 
282 {
283  return mSearchWidgetToolButton;
284 }
285 
286 QgsVectorLayer* QgsAttributeFormEditorWidget::layer()
287 {
288  return mForm ? mForm->layer() : nullptr;
289 }
290 
291 void QgsAttributeFormEditorWidget::updateWidgets()
292 {
293  //first update the tool buttons
294  bool hasMultiEditButton = ( mEditPage->layout()->indexOf( mMultiEditButton ) >= 0 );
295  bool fieldReadOnly = layer()->editFormConfig()->readOnly( mWidget->fieldIdx() );
296 
297  if ( hasMultiEditButton )
298  {
299  if ( mMode != MultiEditMode || fieldReadOnly )
300  {
301  mEditPage->layout()->removeWidget( mMultiEditButton );
302  mMultiEditButton->setParent( nullptr );
303  }
304  }
305  else
306  {
307  if ( mMode == MultiEditMode && !fieldReadOnly )
308  {
309  mEditPage->layout()->addWidget( mMultiEditButton );
310  }
311  }
312 
313  switch ( mMode )
314  {
315  case DefaultMode:
316  case MultiEditMode:
317  {
318  mStack->setCurrentWidget( mEditPage );
319  break;
320  }
321 
322  case SearchMode:
323  {
324  mStack->setCurrentWidget( mSearchPage );
325  break;
326  }
327  }
328 }
QLayout * layout() const
void clear()
Manages an editor widget Widget and wrapper share the same parent.
void setContentsMargins(int left, int top, int right, int bottom)
virtual void setEnabled(bool enabled) override
Toggles whether the search widget is enabled or disabled.
QString name
Definition: qgsfield.h:52
void setDefaultFlags(QgsSearchWidgetWrapper::FilterFlags flags)
Sets the default filter flags to show in the widget.
QWidget * searchWidgetFrame()
Returns the widget which should be used as a parent during construction of the search widget wrapper...
QgsField field() const
Access the field.
This class contains context information for attribute editor widgets.
Manages an editor widget Widget and wrapper share the same parent.
void setActiveFlags(QgsSearchWidgetWrapper::FilterFlags flags)
Sets the current active filter flags for the widget.
const T & at(int i) const
A tool button widget which is displayed next to search widgets in forms, and allows for controlling h...
void initialize(const QVariant &initialValue, bool mixedValues=false)
Resets the widget to an initial value.
A tool button widget which is displayed next to editor widgets in attribute forms, and allows for controlling how the widget behaves and interacts with the form while in multi edit mode.
static QgsEditorWidgetRegistry * instance()
This class is a singleton and has therefore to be accessed with this method instead of a constructor...
void setParent(QWidget *parent)
QgsVectorLayer * layer()
Returns the layer for which this form is shown.
QgsEditFormConfig * editFormConfig() const
Get the configuration of the form used to represent this vector layer.
virtual int indexOf(QWidget *widget) const
void valueChanged(const QVariant &value)
Emitted when the widget&#39;s value changes.
virtual void clearWidget()
Clears the widget&#39;s current value and resets it back to the default state.
void removeWidget(QWidget *widget)
void setIsMixed(bool mixed)
Sets whether the widget should be displayed in a "mixed values" mode.
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
int count(const T &value) const
QVariantMap QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
void changesCommitted()
Called when field values have been changed and field now contains all the same values.
void setCurrentWidget(QWidget *widget)
void setLayout(QLayout *layout)
virtual void showIndeterminateState()
Sets the widget to display in an indeterminate "mixed value" state.
QString currentFilterExpression() const
Creates an expression matching the current search filter value and search properties represented in t...
bool isEmpty() const
void setObjectName(const QString &name)
QList< QgsSearchWidgetWrapper *> searchWidgetWrappers()
Returns the search widget wrapper used in this widget.
QgsSearchWidgetToolButton * searchWidgetToolButton()
Returns a pointer to the search widget tool button in the widget.
virtual void setValue(const QVariant &value)=0
Is called, when the value of the widget needs to be changed.
QgsAttributeFormEditorWidget(QgsEditorWidgetWrapper *editorWidget, QgsAttributeForm *form)
Constructor for QgsAttributeFormEditorWidget.
void setSearchWidgetWrapper(QgsSearchWidgetWrapper *wrapper)
Sets the search widget wrapper for the widget used when the form is in search mode.
void setIsChanged(bool changed)
Sets whether the associated field has changed.
void setMargin(int margin)
void addWidget(QWidget *w)
QVariant currentValue() const
Returns the current value of the attached editor widget.
void setInactive()
Sets the search widget as inactive, ie do not search the corresponding field.
void setMode(Mode mode)
Sets the current mode for the widget.
void setAvailableFlags(QgsSearchWidgetWrapper::FilterFlags flags)
Sets the available filter flags to show in the widget.
void setField(const QgsField &field)
Sets the field associated with this button.
QgsSearchWidgetWrapper * createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Mode mode() const
Returns the current mode for the widget.
bool isActive() const
Returns true if the widget is set to be included in the search.
void setIsMixed(bool mixed)
Sets whether the associated field contains mixed values.
QWidget(QWidget *parent, QFlags< Qt::WindowType > f)
virtual QVariant value() const =0
Will be used to access the widget&#39;s value.
void createSearchWidgetWrappers(const QString &widgetId, int fieldIdx, const QgsEditorWidgetConfig &config, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Creates the search widget wrappers for the widget used when the form is in search mode...
QgsSearchWidgetWrapper::FilterFlags activeFlags() const
Returns the active filter flags shown in the widget.
QWidget * widget()
Access the widget managed by this wrapper.
bool readOnly(int idx) const
This returns true if the field is manually set to read only or if the field does not support editing ...
void changesCommitted()
Called when field values have been committed;.
int fieldIdx() const
Access the field index.
int addWidget(QWidget *widget)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Represents a vector layer which manages a vector based data sets.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
virtual FilterFlags supportedFlags() const
Returns filter flags supported by the search widget.
void resetSearch()
Resets the search/filter value of the widget.