QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsvaluerelationsearchwidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvaluerelationsearchwidgetwrapper.cpp
3  --------------------------------------
4  Date : 5.1.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias at opengis dot ch
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 
18 #include "qgsfield.h"
19 #include "qgsmaplayerregistry.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsfilterlineedit.h"
23 
24 #include <QSettings>
25 #include <QStringListModel>
26 #include <QCompleter>
27 
29  : QgsSearchWidgetWrapper( vl, fieldIdx, parent )
30  , mComboBox( nullptr )
31  , mListWidget( nullptr )
32  , mLineEdit( nullptr )
33  , mLayer( nullptr )
34 {
35 }
36 
38 {
39  if ( mLineEdit )
40  {
41  return false;
42  }
43  return true;
44 }
45 
47 {
48  return mExpression;
49 }
50 
52 {
53  QVariant v;
54 
55  if ( mComboBox )
56  {
57  int cbxIdx = mComboBox->currentIndex();
58  if ( cbxIdx > -1 )
59  {
60  v = mComboBox->itemData( mComboBox->currentIndex() );
61  }
62  }
63 
64  if ( mListWidget )
65  {
66  QStringList selection;
67  for ( int i = 0; i < mListWidget->count(); ++i )
68  {
69  QListWidgetItem* item = mListWidget->item( i );
70  if ( item->checkState() == Qt::Checked )
71  selection << item->data( Qt::UserRole ).toString();
72  }
73 
74  v = selection.join( "," ).prepend( '{' ).append( '}' );
75  }
76 
77  if ( mLineEdit )
78  {
79  Q_FOREACH ( const ValueRelationItem& i , mCache )
80  {
81  if ( i.second == mLineEdit->text() )
82  {
83  v = i.first;
84  break;
85  }
86  }
87  }
88 
89  return v;
90 }
91 
92 QgsSearchWidgetWrapper::FilterFlags QgsValueRelationSearchWidgetWrapper::supportedFlags() const
93 {
94  return EqualTo | NotEqualTo | IsNull | IsNotNull;
95 }
96 
97 QgsSearchWidgetWrapper::FilterFlags QgsValueRelationSearchWidgetWrapper::defaultFlags() const
98 {
99  return EqualTo;
100 }
101 
102 QString QgsValueRelationSearchWidgetWrapper::createExpression( QgsSearchWidgetWrapper::FilterFlags flags ) const
103 {
104  QString fieldName = QgsExpression::quotedColumnRef( layer()->fields().at( mFieldIdx ).name() );
105 
106  //clear any unsupported flags
107  flags &= supportedFlags();
108  if ( flags & IsNull )
109  return fieldName + " IS NULL";
110  if ( flags & IsNotNull )
111  return fieldName + " IS NOT NULL";
112 
113  QVariant v = value();
114  if ( !v.isValid() )
115  return QString();
116 
117  switch ( v.type() )
118  {
119  case QVariant::Int:
120  case QVariant::UInt:
121  case QVariant::Double:
122  case QVariant::LongLong:
123  case QVariant::ULongLong:
124  {
125  if ( flags & EqualTo )
126  return fieldName + '=' + v.toString();
127  else if ( flags & NotEqualTo )
128  return fieldName + "<>" + v.toString();
129  break;
130  }
131 
132  default:
133  {
134  if ( flags & EqualTo )
135  return fieldName + "='" + v.toString() + '\'';
136  else if ( flags & NotEqualTo )
137  return fieldName + "<>'" + v.toString() + '\'';
138  break;
139  }
140  }
141 
142  return QString();
143 }
144 
146 {
147  if ( mComboBox )
148  {
149  mComboBox->setCurrentIndex( 0 );
150  }
151  if ( mListWidget )
152  {
153  mListWidget->clearSelection();
154  }
155  if ( mLineEdit )
156  {
157  mLineEdit->setText( QString() );
158  }
159 }
160 
162 {
163  if ( mComboBox )
164  {
165  mComboBox->setEnabled( enabled );
166  }
167  if ( mListWidget )
168  {
169  mListWidget->setEnabled( enabled );
170  }
171  if ( mLineEdit )
172  {
173  mLineEdit->setEnabled( enabled );
174  }
175 }
176 
178 {
179  return true;
180 }
181 
183 {
184  QVariant vl = value();
185  if ( !vl.isValid() )
186  {
187  clearExpression();
188  emit valueCleared();
189  }
190  else
191  {
192  QSettings settings;
193  setExpression( vl.isNull() ? settings.value( "qgis/nullValue", "NULL" ).toString() : vl.toString() );
194  emit valueChanged();
195  }
197 }
198 
200 {
201  QSettings settings;
202  QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
203  QString fieldName = layer()->fields().at( mFieldIdx ).name();
204 
205  QString str;
206  if ( exp == nullValue )
207  {
208  str = QString( "%1 IS NULL" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
209  }
210  else
211  {
212  str = QString( "%1 = '%3'" )
213  .arg( QgsExpression::quotedColumnRef( fieldName ),
214  exp.replace( '\'', "''" )
215  );
216  }
217  mExpression = str;
218 }
219 
221 {
222  if ( config( "AllowMulti" ).toBool() )
223  {
224  return new QgsFilterLineEdit( parent );
225  }
226  else if ( config( "UseCompleter" ).toBool() )
227  {
228  return new QgsFilterLineEdit( parent );
229  }
230  else
231  {
232  return new QComboBox( parent );
233  }
234 }
235 
237 {
239 
240  mComboBox = qobject_cast<QComboBox*>( editor );
241  mListWidget = qobject_cast<QListWidget*>( editor );
242  mLineEdit = qobject_cast<QLineEdit*>( editor );
243 
244  if ( mComboBox )
245  {
246  mComboBox->addItem( tr( "Please select" ), QVariant() ); // creates an invalid to allow selecting all features
247  if ( config( "AllowNull" ).toBool() )
248  {
249  mComboBox->addItem( tr( "(no selection)" ), QVariant( layer()->fields().at( mFieldIdx ).type() ) );
250  }
251 
252  Q_FOREACH ( const ValueRelationItem& element, mCache )
253  {
254  mComboBox->addItem( element.second, element.first );
255  }
256 
257  connect( mComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( onValueChanged() ) );
258  }
259  else if ( mListWidget )
260  {
261  Q_FOREACH ( const ValueRelationItem& element, mCache )
262  {
263  QListWidgetItem *item;
264  item = new QListWidgetItem( element.second );
265  item->setData( Qt::UserRole, element.first );
266 
267  mListWidget->addItem( item );
268  }
269  connect( mListWidget, SIGNAL( itemChanged( QListWidgetItem* ) ), this, SLOT( onValueChanged() ) );
270  }
271  else if ( mLineEdit )
272  {
273  QStringList values;
274  Q_FOREACH ( const ValueRelationItem& i, mCache )
275  {
276  values << i.second;
277  }
278 
279  QStringListModel* m = new QStringListModel( values, mLineEdit );
280  QCompleter* completer = new QCompleter( m, mLineEdit );
281  completer->setCaseSensitivity( Qt::CaseInsensitive );
282  mLineEdit->setCompleter( completer );
283  connect( mLineEdit, SIGNAL( textChanged( QString ) ), this, SLOT( onValueChanged() ) );
284  }
285 }
286 
287 
void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
QgsValueRelationSearchWidgetWrapper(QgsVectorLayer *vl, int fieldIdx, QWidget *parent=nullptr)
Manages an editor widget Widget and wrapper share the same parent.
QString & append(QChar ch)
Qt::CheckState checkState() const
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QString name
Definition: qgsfield.h:52
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
QString & prepend(QChar ch)
bool valid() const override
Return true if the widget has been properly initialized.
void clearExpression()
clears the expression to search for all features
QString join(const QString &separator) const
QString tr(const char *sourceText, const char *disambiguation, int n)
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:422
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
bool applyDirectly() override
If this is true, then this search widget should take effect directly when its expression changes...
QgsFields fields() const
Returns the list of fields of this layer.
void addItem(const QString &text, const QVariant &userData)
const char * name() const
void setEnabled(bool)
bool isNull() const
void valueChanged()
Emitted when a user changes the value of the search widget.
void onValueChanged()
Called when current value of search widget changes.
virtual QVariant data(int role) const
QString expression() override
Will be used to access the widget&#39;s value.
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
void expressionChanged(const QString &exp)
Emitted whenever the expression changes.
QListWidgetItem * item(int row) const
QVariant itemData(int index, int role) const
virtual void setData(int role, const QVariant &value)
static ValueRelationCache createCache(const QgsEditorWidgetConfig &config)
QString & replace(int position, int n, QChar after)
QVariant value(const QString &key, const QVariant &defaultValue) const
FilterFlags defaultFlags() const override
Returns the filter flags which should be set by default for the search widget.
void valueCleared()
Emitted when a user changes the value of the search widget back to an empty, default state...
bool isValid() const
QgsEditorWidgetConfig config() const
Returns the whole config.
virtual QString createExpression(FilterFlags flags) const override
Creates a filter expression based on the current state of the search widget and the specified filter ...
Type type() const
QgsVectorLayer * layer() const
Access the QgsVectorLayer, you are working on.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
Represents a vector layer which manages a vector based data sets.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
FilterFlags supportedFlags() const override
Returns filter flags supported by the search widget.