QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsvaluerelationwidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvaluerelationwidgetwrapper.cpp
3  --------------------------------------
4  Date : 5.1.2014
5  Copyright : (C) 2014 Matthias Kuhn
6  Email : matthias dot kuhn at gmx 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 
25 {
26  switch ( p1.first.type() )
27  {
28  case QVariant::String:
29  return p1.first.toString() < p2.first.toString();
30  break;
31 
32  case QVariant::Double:
33  return p1.first.toDouble() < p2.first.toDouble();
34  break;
35 
36  default:
37  return p1.first.toInt() < p2.first.toInt();
38  break;
39  }
40 }
41 
44 {
45  return p1.second < p2.second;
46 }
47 
48 QgsValueRelationWidgetWrapper::QgsValueRelationWidgetWrapper( QgsVectorLayer* vl, int fieldIdx, QWidget* editor, QWidget* parent )
49  : QgsEditorWidgetWrapper( vl, fieldIdx, editor, parent )
50  , mComboBox( NULL )
51  , mListWidget( NULL )
52  , mLayer( NULL )
53 {
54 }
55 
56 
58 {
59  QVariant v;
60 
61  if ( mComboBox )
62  {
63  int cbxIdx = mComboBox->currentIndex();
64  if ( cbxIdx > -1 )
65  {
66  v = mComboBox->itemData( mComboBox->currentIndex() );
67  }
68  }
69 
70  if ( mListWidget )
71  {
72  QStringList selection;
73  for ( int i = 0; i < mListWidget->count(); ++i )
74  {
75  QListWidgetItem* item = mListWidget->item( i );
76  if ( item->checkState() == Qt::Checked )
77  selection << item->data( Qt::UserRole ).toString();
78  }
79 
80  v = selection.join( "," ).prepend( "{" ).append( "}" );
81  }
82 
83  return v;
84 }
85 
87 {
88  if ( config( "AllowMulti" ).toBool() )
89  {
90  return new QListWidget( parent );
91  }
92  else
93  {
94  return new QComboBox( parent );
95  }
96 }
97 
99 {
100  mCache = createCache( config() );
101 
102  mComboBox = qobject_cast<QComboBox*>( editor );
103  mListWidget = qobject_cast<QListWidget*>( editor );
104 
105  if ( mComboBox )
106  {
107  if ( config( "AllowNull" ).toBool() )
108  {
109  mComboBox->addItem( tr( "(no selection)" ), QVariant( field().type() ) );
110  }
111 
112  Q_FOREACH ( const ValueRelationItem& element, mCache )
113  {
114  mComboBox->addItem( element.second, element.first );
115  }
116 
117  connect( mComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( valueChanged() ) );
118  }
119  else if ( mListWidget )
120  {
121  Q_FOREACH ( const ValueRelationItem& element, mCache )
122  {
123  QListWidgetItem *item;
124  item = new QListWidgetItem( element.second );
125  item->setData( Qt::UserRole, element.first );
126 
127  mListWidget->addItem( item );
128  }
129  connect( mListWidget, SIGNAL( itemChanged( QListWidgetItem* ) ), this, SLOT( valueChanged() ) );
130  }
131 }
132 
133 void QgsValueRelationWidgetWrapper::setValue( const QVariant& value )
134 {
135  if ( mListWidget )
136  {
137  QStringList checkList = value.toString().remove( QChar( '{' ) ).remove( QChar( '}' ) ).split( "," );
138 
139  for ( int i = 0; i < mListWidget->count(); ++i )
140  {
141  QListWidgetItem* item = mListWidget->item( i );
142  if ( config( "OrderByValue" ).toBool() )
143  {
144  item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
145  }
146  else
147  {
148  item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
149  }
150  }
151  }
152  else if ( mComboBox )
153  {
154  mComboBox->setCurrentIndex( mComboBox->findData( value ) );
155  }
156 }
157 
158 
160 {
161  ValueRelationCache cache;
162 
163  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( config.value( "Layer" ).toString() ) );
164 
165  if ( layer )
166  {
167  int ki = layer->fieldNameIndex( config.value( "Key" ).toString() );
168  int vi = layer->fieldNameIndex( config.value( "Value" ).toString() );
169 
170  QgsExpression *e = 0;
171  if ( !config.value( "FilterExpression" ).toString().isEmpty() )
172  {
173  e = new QgsExpression( config.value( "FilterExpression" ).toString() );
174  if ( e->hasParserError() || !e->prepare( layer->pendingFields() ) )
175  ki = -1;
176  }
177 
178  if ( ki >= 0 && vi >= 0 )
179  {
180  QSet<int> attributes;
181  attributes << ki << vi;
182 
183  QgsFeatureRequest::Flags flags = QgsFeatureRequest::NoGeometry;
184 
185  bool requiresAllAttributes = false;
186  if ( e )
187  {
188  if ( e->needsGeometry() )
190 
191  Q_FOREACH ( const QString& field, e->referencedColumns() )
192  {
193  if ( field == QgsFeatureRequest::AllAttributes )
194  {
195  requiresAllAttributes = true;
196  break;
197  }
198  int idx = layer->fieldNameIndex( field );
199  if ( idx < 0 )
200  continue;
201  attributes << idx;
202  }
203  }
204 
206  if ( !requiresAllAttributes )
207  {
208  fr.setSubsetOfAttributes( attributes.toList() );
209  }
210 
211  QgsFeatureIterator fit = layer->getFeatures( fr );
212 
213  QgsFeature f;
214  while ( fit.nextFeature( f ) )
215  {
216  if ( e && !e->evaluate( &f ).toBool() )
217  continue;
218 
219  cache.append( ValueRelationItem( f.attribute( ki ), f.attribute( vi ).toString() ) );
220  }
221  }
222  delete e;
223  }
224 
225  if ( config.value( "OrderByValue" ).toBool() )
226  {
227  qSort( cache.begin(), cache.end(), orderByValueLessThan );
228  }
229  else
230  {
231  qSort( cache.begin(), cache.end(), orderByKeyLessThan );
232  }
233 
234  return cache;
235 }
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
Wrapper for iterator of features from vector data provider or vector layer.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:94
QStringList referencedColumns() const
Get list of columns referenced by the expression.
void valueChanged()
Will call the value() method to determine the emitted value.
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
Manages an editor widget Widget and wrapper share the same parent.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
static QgsMapLayerRegistry * instance()
Definition: qgssingleton.h:23
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsVectorLayer * layer()
Access the QgsVectorLayer, you are working on.
void setValue(const QVariant &value) override
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
QgsValueRelationWidgetWrapper(QgsVectorLayer *vl, int fieldIdx, QWidget *editor=0, QWidget *parent=0)
QgsField field()
Access the field.
QVariant value() override
Will be used to access the widget's value.
bool orderByValueLessThan(const QgsValueRelationWidgetWrapper::ValueRelationItem &p1, const QgsValueRelationWidgetWrapper::ValueRelationItem &p2)
QPair< QVariant, QString > ValueRelationItem
const QgsEditorWidgetConfig config()
Returns the whole config.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool orderByKeyLessThan(const QgsValueRelationWidgetWrapper::ValueRelationItem &p1, const QgsValueRelationWidgetWrapper::ValueRelationItem &p2)
static const QString AllAttributes
static ValueRelationCache createCache(const QgsEditorWidgetConfig &config)
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
QMap< QString, QVariant > QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
QVector< ValueRelationItem > ValueRelationCache
#define tr(sourceText)