QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgsrelationreferencefactory.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelationreferencefactory.cpp
3  --------------------------------------
4  Date : 29.5.2013
5  Copyright : (C) 2013 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 
16 #include "qgsproject.h"
18 
22 
24  : QgsEditorWidgetFactory( name )
25  , mCanvas( canvas )
26  , mMessageBar( messageBar )
27 {
28 }
29 
31 {
32  return new QgsRelationReferenceWidgetWrapper( vl, fieldIdx, editor, mCanvas, mMessageBar, parent );
33 }
34 
36 {
37  return new QgsRelationReferenceSearchWidgetWrapper( vl, fieldIdx, mCanvas, parent );
38 }
39 
41 {
42  return new QgsRelationReferenceConfigDlg( vl, fieldIdx, parent );
43 }
44 
46 {
47  Q_UNUSED( layer );
48  Q_UNUSED( fieldIdx );
50 
51  cfg.insert( "AllowNULL", configElement.attribute( "AllowNULL" ) == "1" );
52  cfg.insert( "OrderByValue", configElement.attribute( "OrderByValue" ) == "1" );
53  cfg.insert( "ShowForm", configElement.attribute( "ShowForm" ) == "1" );
54  cfg.insert( "Relation", configElement.attribute( "Relation" ) );
55  cfg.insert( "MapIdentification", configElement.attribute( "MapIdentification" ) == "1" );
56  cfg.insert( "ReadOnly", configElement.attribute( "ReadOnly" ) == "1" );
57  cfg.insert( "AllowAddFeatures", configElement.attribute( "AllowAddFeatures" ) == "1" );
58 
59  QDomNode filterNode = configElement.elementsByTagName( "FilterFields" ).at( 0 );
60  if ( !filterNode.isNull() )
61  {
62  QStringList filterFields;
63  QDomNodeList fieldNodes = filterNode.toElement().elementsByTagName( "field" );
64  filterFields.reserve( fieldNodes.size() );
65  for ( int i = 0; i < fieldNodes.size(); i++ )
66  {
67  QDomElement fieldElement = fieldNodes.at( i ).toElement();
68  filterFields << fieldElement.attribute( "name" );
69  }
70  cfg.insert( "FilterFields", filterFields );
71 
72  cfg.insert( "ChainFilters", filterNode.toElement().attribute( "ChainFilters" ) == "1" );
73  }
74  return cfg;
75 }
76 
77 void QgsRelationReferenceFactory::writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx )
78 {
79  Q_UNUSED( doc );
80  Q_UNUSED( layer );
81  Q_UNUSED( fieldIdx );
82 
83  configElement.setAttribute( "AllowNULL", config["AllowNULL"].toBool() );
84  configElement.setAttribute( "OrderByValue", config["OrderByValue"].toBool() );
85  configElement.setAttribute( "ShowForm", config["ShowForm"].toBool() );
86  configElement.setAttribute( "Relation", config["Relation"].toString() );
87  configElement.setAttribute( "MapIdentification", config["MapIdentification"].toBool() );
88  configElement.setAttribute( "ReadOnly", config["ReadOnly"].toBool() );
89  configElement.setAttribute( "AllowAddFeatures", config["AllowAddFeatures"].toBool() );
90 
91  if ( config.contains( "FilterFields" ) )
92  {
93  QDomElement filterFields = doc.createElement( "FilterFields" );
94 
95  Q_FOREACH ( const QString& field, config["FilterFields"].toStringList() )
96  {
97  QDomElement fieldElem = doc.createElement( "field" );
98  fieldElem.setAttribute( "name", field );
99  filterFields.appendChild( fieldElem );
100  }
101  configElement.appendChild( filterFields );
102 
103  filterFields.setAttribute( "ChainFilters", config["ChainFilters"].toBool() );
104  }
105 }
106 
108 {
110  map.insert( QgsRelationReferenceWidget::staticMetaObject.className(), 10 );
111  return map;
112 }
113 
114 QString QgsRelationReferenceFactory::representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
115 {
116  Q_UNUSED( cache );
117 
118  // Some sanity checks
119  if ( !config.contains( "Relation" ) )
120  {
121  QgsDebugMsg( "Missing Relation in configuration" );
122  return value.toString();
123  }
124  QgsRelation relation = QgsProject::instance()->relationManager()->relation( config["Relation"].toString() );
125  if ( !relation.isValid() )
126  {
127  QgsDebugMsg( "Invalid relation" );
128  return value.toString();
129  }
130  QgsVectorLayer* referencingLayer = relation.referencingLayer();
131  if ( vl != referencingLayer )
132  {
133  QgsDebugMsg( "representValue() with inconsistent vl parameter w.r.t relation referencingLayer" );
134  return value.toString();
135  }
136  int referencingFieldIdx = referencingLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).first );
137  if ( referencingFieldIdx != fieldIdx )
138  {
139  QgsDebugMsg( "representValue() with inconsistent fieldIdx parameter w.r.t relation referencingFieldIdx" );
140  return value.toString();
141  }
142  QgsVectorLayer* referencedLayer = relation.referencedLayer();
143  if ( !referencedLayer )
144  {
145  QgsDebugMsg( "Cannot find referenced layer" );
146  return value.toString();
147  }
148 
149  // Attributes from the referencing layer
150  QgsAttributes attrs = QgsAttributes( vl->fields().count() );
151  // Set the value on the foreign key field of the referencing record
152  attrs[ referencingFieldIdx ] = value;
153 
154  QgsFeatureRequest request = relation.getReferencedFeatureRequest( attrs );
155  QgsFeature feature;
156  referencedLayer->getFeatures( request ).nextFeature( feature );
157  if ( !feature.isValid() )
158  return value.toString();
159 
160  QgsExpression expr( referencedLayer->displayExpression() );
161  QgsExpressionContext context;
164  << QgsExpressionContextUtils::layerScope( referencedLayer );
165  context.setFeature( feature );
166  QString title = expr.evaluate( &context ).toString();
167  if ( expr.hasEvalError() )
168  {
169  int referencedFieldIdx = referencedLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).second );
170  title = feature.attribute( referencedFieldIdx ).toString();
171  }
172  return title;
173 }
174 
175 QVariant QgsRelationReferenceFactory::sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
176 {
177  return representValue( vl, fieldIdx, config, cache, value );
178 }
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:199
Class for parsing and evaluation of expressions (formerly called "search strings").
virtual QgsEditorConfigWidget * configWidget(QgsVectorLayer *vl, int fieldIdx, QWidget *parent) const override
Override this in your implementation.
QDomNodeList elementsByTagName(const QString &tagname) const
bool isValid() const
Returns the validity of this relation.
Manages an editor widget Widget and wrapper share the same parent.
This class should be subclassed for every configurable editor widget type.
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
Manages an editor widget Widget and wrapper share the same parent.
void reserve(int alloc)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:42
QgsSearchWidgetWrapper * createSearchWidget(QgsVectorLayer *vl, int fieldIdx, QWidget *parent) const override
By default a simple QgsFilterLineEdit is returned as search widget.
virtual void writeConfig(const QgsEditorWidgetConfig &config, QDomElement &configElement, QDomDocument &doc, const QgsVectorLayer *layer, int fieldIdx) override
Serialize your configuration and save it in a xml doc.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QgsRelationManager * relationManager() const
int count() const
Return number of items.
Definition: qgsfield.cpp:402
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
QgsFields fields() const
Returns the list of fields of this layer.
QDomElement toElement() const
virtual QMap< const char *, int > supportedWidgetTypes() override
Returns a list of widget types which this editor widget supports.
QVariantMap QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsFeatureRequest getReferencedFeatureRequest(const QgsAttributes &attributes) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
QString & insert(int position, QChar ch)
virtual QString representValue(QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value) const override
Create a pretty String representation of the value.
void setAttribute(const QString &name, const QString &value)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Every attribute editor widget needs a factory, which inherits this class.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual QVariant sortValue(QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value) const override
If the default sort order should be overwritten for this widget, you can transform the value in here...
QList< FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
virtual QgsEditorWidgetConfig readConfig(const QDomElement &configElement, QgsVectorLayer *layer, int fieldIdx) override
Read the config from an XML file and map it to a proper QgsEditorWidgetConfig.
QgsVectorLayer * referencedLayer() const
Access the referenced (parent) layer.
QgsRelationReferenceFactory(const QString &name, QgsMapCanvas *canvas, QgsMessageBar *messageBar)
bool isNull() const
QgsVectorLayer * referencingLayer() const
Access the referencing (child) layer This is the layer which has the field(s) which point to another ...
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
iterator insert(const Key &key, const T &value)
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
int size() const
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
QDomElement createElement(const QString &tagName)
bool nextFeature(QgsFeature &f)
QgsRelation relation(const QString &id) const
Get access to a relation by its id.
A vector of attributes.
Definition: qgsfeature.h:115
QString displayExpression() const
Get the preview expression, used to create a human readable preview string.
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QString toString() const
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
virtual QgsEditorWidgetWrapper * create(QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QWidget *parent) const override
Override this in your implementation.
QDomNode at(int index) const