QGIS API Documentation  2.7.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 {
51 }
52 
53 
55 {
56  QVariant v;
57 
58  if ( mComboBox )
59  {
60  int cbxIdx = mComboBox->currentIndex();
61  if ( cbxIdx > -1 )
62  {
63  v = mComboBox->itemData( mComboBox->currentIndex() );
64  }
65  }
66 
67  if ( mListWidget )
68  {
69  QStringList selection;
70  for ( int i = 0; i < mListWidget->count(); ++i )
71  {
72  QListWidgetItem* item = mListWidget->item( i );
73  if ( item->checkState() == Qt::Checked )
74  selection << item->data( Qt::UserRole ).toString();
75  }
76 
77  v = selection.join( "," ).prepend( "{" ).append( "}" );
78  }
79 
80  return v;
81 }
82 
84 {
85  if ( config( "AllowMulti" ).toBool() )
86  {
87  return new QListWidget( parent );
88  }
89  else
90  {
91  return new QComboBox( parent );
92  }
93 }
94 
96 {
97  mCache = createCache( config() );
98 
99  mComboBox = qobject_cast<QComboBox*>( editor );
100  mListWidget = qobject_cast<QListWidget*>( editor );
101 
102  if ( mComboBox )
103  {
104  if ( config( "AllowNull" ).toBool() )
105  {
106  mComboBox->addItem( tr( "(no selection)" ), QVariant( field().type() ) );
107  }
108 
109  Q_FOREACH ( const ValueRelationItem& element, mCache )
110  {
111  mComboBox->addItem( element.second, element.first );
112  }
113 
114  connect( mComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( valueChanged() ) );
115  }
116  else if ( mListWidget )
117  {
118  Q_FOREACH ( const ValueRelationItem& element, mCache )
119  {
120  QListWidgetItem *item;
121  item = new QListWidgetItem( element.second );
122  item->setData( Qt::UserRole, element.first );
123 
124  mListWidget->addItem( item );
125  }
126  connect( mListWidget, SIGNAL( itemChanged( QListWidgetItem* ) ), this, SLOT( valueChanged() ) );
127  }
128 }
129 
130 void QgsValueRelationWidgetWrapper::setValue( const QVariant& value )
131 {
132  if ( mListWidget )
133  {
134  QStringList checkList = value.toString().remove( QChar( '{' ) ).remove( QChar( '}' ) ).split( "," );
135 
136  for ( int i = 0; i < mListWidget->count(); ++i )
137  {
138  QListWidgetItem* item = mListWidget->item( i );
139  if ( config( "OrderByValue" ).toBool() )
140  {
141  item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
142  }
143  else
144  {
145  item->setCheckState( checkList.contains( item->data( Qt::UserRole ).toString() ) ? Qt::Checked : Qt::Unchecked );
146  }
147  }
148  }
149  else if ( mComboBox )
150  {
151  mComboBox->setCurrentIndex( mComboBox->findData( value ) );
152  }
153 }
154 
155 
157 {
158  ValueRelationCache cache;
159 
160  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( config.value( "Layer" ).toString() ) );
161 
162  if ( layer )
163  {
164  int ki = layer->fieldNameIndex( config.value( "Key" ).toString() );
165  int vi = layer->fieldNameIndex( config.value( "Value" ).toString() );
166 
167  QgsExpression *e = 0;
168  if ( !config.value( "FilterExpression" ).toString().isEmpty() )
169  {
170  e = new QgsExpression( config.value( "FilterExpression" ).toString() );
171  if ( e->hasParserError() || !e->prepare( layer->pendingFields() ) )
172  ki = -1;
173  }
174 
175  if ( ki >= 0 && vi >= 0 )
176  {
177  QSet<int> attributes;
178  attributes << ki << vi;
179 
180  QgsFeatureRequest::Flags flags = QgsFeatureRequest::NoGeometry;
181 
182  bool requiresAllAttributes = false;
183  if ( e )
184  {
185  if ( e->needsGeometry() )
187 
188  Q_FOREACH ( const QString& field, e->referencedColumns() )
189  {
190  if ( field == QgsFeatureRequest::AllAttributes )
191  {
192  requiresAllAttributes = true;
193  break;
194  }
195  int idx = layer->fieldNameIndex( field );
196  if ( idx < 0 )
197  continue;
198  attributes << idx;
199  }
200  }
201 
203  if ( !requiresAllAttributes )
204  {
205  fr.setSubsetOfAttributes( attributes.toList() );
206  }
207 
208  QgsFeatureIterator fit = layer->getFeatures( fr );
209 
210  QgsFeature f;
211  while ( fit.nextFeature( f ) )
212  {
213  if ( e && !e->evaluate( &f ).toBool() )
214  continue;
215 
216  cache.append( ValueRelationItem( f.attribute( ki ), f.attribute( vi ).toString() ) );
217  }
218  }
219  }
220 
221  if ( config.value( "OrderByValue" ).toBool() )
222  {
223  qSort( cache.begin(), cache.end(), orderByValueLessThan );
224  }
225  else
226  {
227  qSort( cache.begin(), cache.end(), orderByKeyLessThan );
228  }
229 
230  return cache;
231 }
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
QVariant value()
Will be used to access the widget's value.
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.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsVectorLayer * layer()
Access the QgsVectorLayer, you are working on.
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.
bool orderByValueLessThan(const QgsValueRelationWidgetWrapper::ValueRelationItem &p1, const QgsValueRelationWidgetWrapper::ValueRelationItem &p2)
QWidget * createWidget(QWidget *parent)
This method should create a new widget with the provided parent.
QPair< QVariant, QString > ValueRelationItem
const QgsEditorWidgetConfig config()
Returns the whole config.
QStringList referencedColumns()
Get list of columns referenced by the expression.
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
bool needsGeometry()
Returns true if the expression uses feature geometry for some computation.
static ValueRelationCache createCache(const QgsEditorWidgetConfig &config)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
void initWidget(QWidget *editor)
This method should initialize the editor widget with runtime data.
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)