QGIS API Documentation  2.17.0-Master (06698cd)
qgsrelation.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelation.cpp
3  --------------------------------------
4  Date : 29.4.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 "qgsrelation.h"
17 
18 #include "qgsapplication.h"
19 #include "qgslogger.h"
20 #include "qgsmaplayerregistry.h"
21 #include "qgsvectorlayer.h"
22 
24  : mReferencingLayer( nullptr )
25  , mReferencedLayer( nullptr )
26  , mValid( false )
27 {
28 }
29 
31 {
32  QDomElement elem = node.toElement();
33 
34  if ( elem.tagName() != "relation" )
35  {
36  QgsLogger::warning( QApplication::translate( "QgsRelation", "Cannot create relation. Unexpected tag '%1'" ).arg( elem.tagName() ) );
37  }
38 
39  QgsRelation relation;
40 
41  QString referencingLayerId = elem.attribute( "referencingLayer" );
42  QString referencedLayerId = elem.attribute( "referencedLayer" );
43  QString id = elem.attribute( "id" );
44  QString name = elem.attribute( "name" );
45 
47 
50 
51  if ( !referencingLayer )
52  {
53  QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which does not exist." ).arg( referencingLayerId ) );
54  }
55  else if ( QgsMapLayer::VectorLayer != referencingLayer->type() )
56  {
57  QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which is not of type VectorLayer." ).arg( referencingLayerId ) );
58  }
59 
60  if ( !referencedLayer )
61  {
62  QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which does not exist." ).arg( referencedLayerId ) );
63  }
64  else if ( QgsMapLayer::VectorLayer != referencedLayer->type() )
65  {
66  QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which is not of type VectorLayer." ).arg( referencedLayerId ) );
67  }
68 
69  relation.mReferencingLayerId = referencingLayerId;
70  relation.mReferencingLayer = qobject_cast<QgsVectorLayer*>( referencingLayer );
71  relation.mReferencedLayerId = referencedLayerId;
72  relation.mReferencedLayer = qobject_cast<QgsVectorLayer*>( referencedLayer );
73  relation.mRelationId = id;
74  relation.mRelationName = name;
75 
76  QDomNodeList references = elem.elementsByTagName( "fieldRef" );
77  for ( int i = 0; i < references.size(); ++i )
78  {
79  QDomElement refEl = references.at( i ).toElement();
80 
81  QString referencingField = refEl.attribute( "referencingField" );
82  QString referencedField = refEl.attribute( "referencedField" );
83 
84  relation.addFieldPair( referencingField, referencedField );
85  }
86 
87  relation.updateRelationStatus();
88 
89  return relation;
90 }
91 
92 void QgsRelation::writeXML( QDomNode &node, QDomDocument &doc ) const
93 {
94  QDomElement elem = doc.createElement( "relation" );
95  elem.setAttribute( "id", mRelationId );
96  elem.setAttribute( "name", mRelationName );
97  elem.setAttribute( "referencingLayer", mReferencingLayerId );
98  elem.setAttribute( "referencedLayer", mReferencedLayerId );
99 
100  Q_FOREACH ( const FieldPair& fields, mFieldPairs )
101  {
102  QDomElement referenceElem = doc.createElement( "fieldRef" );
103  referenceElem.setAttribute( "referencingField", fields.first );
104  referenceElem.setAttribute( "referencedField", fields.second );
105  elem.appendChild( referenceElem );
106  }
107 
108  node.appendChild( elem );
109 }
110 
112 {
113  mRelationId = id;
114 
116 }
117 
119 {
120  mRelationName = name;
121 }
122 
124 {
125  mReferencingLayerId = id;
126 
128 }
129 
131 {
132  mReferencedLayerId = id;
133 
135 }
136 
137 void QgsRelation::addFieldPair( const QString& referencingField, const QString& referencedField )
138 {
139  mFieldPairs << FieldPair( referencingField, referencedField );
141 }
142 
143 void QgsRelation::addFieldPair( const FieldPair& fieldPair )
144 {
145  mFieldPairs << fieldPair;
147 }
148 
150 {
152 }
153 
155 {
156  QString filter = getRelatedFeaturesFilter( feature );
157  QgsDebugMsg( QString( "Filter conditions: '%1'" ).arg( filter ) );
158 
159  QgsFeatureRequest myRequest;
160  myRequest.setFilterExpression( filter );
161  return myRequest;
162 }
163 
165 {
166  QStringList conditions;
167 
168  Q_FOREACH ( const QgsRelation::FieldPair& fieldPair, mFieldPairs )
169  {
170  int referencingIdx = referencingLayer()->fields().indexFromName( fieldPair.referencingField() );
171  QgsField referencingField = referencingLayer()->fields().at( referencingIdx );
172 
173  if ( referencingField.type() == QVariant::String )
174  {
175  // Use quotes
176  conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() );
177  }
178  else
179  {
180  // No quotes
181  conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencingField(), feature.attribute( fieldPair.referencedField() ).toString() );
182  }
183  }
184 
185  return conditions.join( " AND " );
186 }
187 
189 {
190  QStringList conditions;
191 
192  Q_FOREACH ( const QgsRelation::FieldPair& fieldPair, mFieldPairs )
193  {
194  int referencedIdx = referencedLayer()->fields().indexFromName( fieldPair.referencedField() );
195  int referencingIdx = referencingLayer()->fields().indexFromName( fieldPair.referencingField() );
196 
197  QgsField referencedField = referencedLayer()->fields().at( referencedIdx );
198 
199  if ( referencedField.type() == QVariant::String )
200  {
201  // Use quotes
202  conditions << QString( "\"%1\" = '%2'" ).arg( fieldPair.referencedField(), attributes.at( referencingIdx ).toString() );
203  }
204  else
205  {
206  // No quotes
207  conditions << QString( "\"%1\" = %2" ).arg( fieldPair.referencedField(), attributes.at( referencingIdx ).toString() );
208  }
209  }
210 
211  QgsFeatureRequest myRequest;
212 
213  QgsDebugMsg( QString( "Filter conditions: '%1'" ).arg( conditions.join( " AND " ) ) );
214 
215  myRequest.setFilterExpression( conditions.join( " AND " ) );
216 
217  return myRequest;
218 }
219 
221 {
222  return getReferencedFeatureRequest( feature.attributes() );
223 }
224 
226 {
227  QgsFeatureRequest request = getReferencedFeatureRequest( feature );
228 
229  QgsFeature f;
230  mReferencedLayer->getFeatures( request ).nextFeature( f );
231  return f;
232 }
233 
235 {
236  return mRelationName;
237 }
238 
240 {
241  return mRelationId;
242 }
243 
245 {
246  return mReferencingLayerId;
247 }
248 
250 {
251  return mReferencingLayer;
252 }
253 
255 {
256  return mReferencedLayerId;
257 }
258 
260 {
261  return mReferencedLayer;
262 }
263 
265 {
266  return mFieldPairs;
267 }
268 
270 {
271  QgsAttributeList attrs;
272 
273  Q_FOREACH ( const FieldPair& pair, mFieldPairs )
274  {
275  attrs << mReferencedLayer->fieldNameIndex( pair.second );
276  }
277  return attrs;
278 }
279 
281 {
282  QgsAttributeList attrs;
283 
284  Q_FOREACH ( const FieldPair& pair, mFieldPairs )
285  {
286  attrs << mReferencingLayer->fieldNameIndex( pair.first );
287  }
288  return attrs;
289 
290 }
291 
293 {
294  return mValid;
295 }
296 
298 {
300 
301  mReferencingLayer = qobject_cast<QgsVectorLayer*>( mapLayers[mReferencingLayerId] );
302  mReferencedLayer = qobject_cast<QgsVectorLayer*>( mapLayers[mReferencedLayerId] );
303 
304  mValid = true;
305 
306  if ( mRelationId.isEmpty() )
307  mValid = false;
308 
309  if ( !mReferencedLayer || !mReferencingLayer )
310  {
311  mValid = false;
312  }
313  else
314  {
315  if ( mFieldPairs.count() < 1 )
316  {
317  mValid = false;
318  }
319 
320  Q_FOREACH ( const FieldPair& fieldPair, mFieldPairs )
321  {
322  if ( -1 == mReferencingLayer->fieldNameIndex( fieldPair.first )
323  || -1 == mReferencedLayer->fieldNameIndex( fieldPair.second ) )
324  {
325  mValid = false;
326  }
327  }
328  }
329 }
Wrapper for iterator of features from vector data provider or vector layer.
bool isValid() const
Returns the validity of this relation.
QDomNodeList elementsByTagName(const QString &tagname) const
Base class for all map layer types.
Definition: qgsmaplayer.h:49
QString getRelatedFeaturesFilter(const QgsFeature &feature) const
Returns a filter expression which returns all the features on the referencing (child) layer which hav...
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:97
QString referencedField() const
Get the name of the referenced (parent) field.
Definition: qgsrelation.h:56
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:124
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
void setReferencingLayer(const QString &id)
Set the referencing (child) layer id.
QgsRelation()
Default constructor.
Definition: qgsrelation.cpp:23
void addFieldPair(const QString &referencingField, const QString &referencedField)
Add a field pairs which is part of this relation The first element of each pair are the field names o...
QgsVectorLayer * referencedLayer() const
Access the referenced (parent) layer.
static QgsRelation createFromXML(const QDomNode &node)
Creates a relation from an XML structure.
Definition: qgsrelation.cpp:30
QString join(const QString &separator) const
QString name() const
Returns a human readable name for this relation.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QString referencingLayerId() const
Access the referencing (child) layer&#39;s id This is the layer which has the field(s) which point to ano...
QgsAttributeList referencedFields() const
Returns a list of attributes used to form the referenced fields (most likely primary key) on the refe...
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 id() const
A (project-wide) unique id for this relation.
void writeXML(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
Definition: qgsrelation.cpp:92
QDomElement toElement() const
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:42
QgsFeature getReferencedFeature(const QgsFeature &feature) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
QString referencingField() const
Get the name of the referencing (child) field.
Definition: qgsrelation.h:54
QgsAttributes attributes() const
Returns the feature&#39;s attributes.
Definition: qgsfeature.cpp:110
void setAttribute(const QString &name, const QString &value)
void setRelationName(const QString &name)
Set a name for this relation.
QgsVectorLayer * referencingLayer() const
Access the referencing (child) layer This is the layer which has the field(s) which point to another ...
bool isEmpty() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:390
QMap< QString, QgsMapLayer * > mapLayers() const
Returns a map of all registered layers by layer ID.
QString referencedLayerId() const
Access the referenced (parent) layer&#39;s id.
int indexFromName(const QString &name) const
Look up field&#39;s index from name. Returns -1 on error.
Definition: qgsfield.cpp:429
void setReferencedLayer(const QString &id)
Set the referenced (parent) layer id.
QgsAttributeList referencingFields() const
Returns a list of attributes used to form the referencing fields (foreign key) on the referencing (ch...
const T & at(int i) const
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:271
void setRelationId(const QString &id)
Set a name for this relation.
QgsFeatureIterator getRelatedFeatures(const QgsFeature &feature) const
Creates an iterator which returns all the features on the referencing (child) layer which have a fore...
QString translate(const char *context, const char *sourceText, const char *disambiguation, Encoding encoding)
QList< FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
QString tagName() const
int size() const
QDomElement createElement(const QString &tagName)
bool nextFeature(QgsFeature &f)
A vector of attributes.
Definition: qgsfeature.h:115
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.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void updateRelationStatus()
Updates the validity status of this relation.
QDomNode at(int index) const
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:89