QGIS API Documentation 4.1.0-Master (60fea48833c)
Loading...
Searching...
No Matches
qgsweakrelation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsweakrelation.cpp - QgsWeakRelation
3
4 ---------------------
5 begin : 5.12.2019
6 copyright : (C) 2019 by Alessandro Pasotti
7 email : elpaso at itopen dot it
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#include "qgsweakrelation.h"
18
19#include "qgslogger.h"
20#include "qgsprovidermetadata.h"
21#include "qgsproviderregistry.h"
22
23#include <QApplication>
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
29
31 const QString &relationId,
32 const QString &relationName,
34 const QString &referencingLayerId,
35 const QString &referencingLayerName,
36 const QString &referencingLayerSource,
37 const QString &referencingLayerProviderKey,
38 const QString &referencedLayerId,
39 const QString &referencedLayerName,
40 const QString &referencedLayerSource,
41 const QString &referencedLayerProviderKey
42)
43 : mReferencingLayer( referencingLayerId, referencingLayerName, referencingLayerSource, referencingLayerProviderKey )
44 , mReferencedLayer( referencedLayerId, referencedLayerName, referencedLayerSource, referencedLayerProviderKey )
45 , mRelationId( relationId )
46 , mRelationName( relationName )
47 , mStrength( strength )
48{}
49
50QList< QgsRelation > QgsWeakRelation::resolvedRelations( const QgsProject *project, QgsVectorLayerRef::MatchType matchType ) const
51{
52 QList< QgsRelation > res;
53
54 switch ( mCardinality )
55 {
59 {
60 QgsRelation relation;
61 relation.setId( mRelationId );
62 relation.setName( mRelationName );
63 relation.setStrength( mStrength );
64 QgsVectorLayerRef referencedLayerRef = mReferencedLayer;
65 QgsMapLayer *referencedLayer = referencedLayerRef.resolveWeakly( project, matchType );
66 if ( referencedLayer )
67 {
68 relation.setReferencedLayer( referencedLayer->id() );
69 }
70 QgsVectorLayerRef referencingLayerRef = mReferencingLayer;
71 QgsMapLayer *referencingLayer = referencingLayerRef.resolveWeakly( project, matchType );
72 if ( referencingLayer )
73 {
74 relation.setReferencingLayer( referencingLayer->id() );
75 }
76
77 for ( int i = 0; i < std::min( mReferencingLayerFields.size(), mReferencedLayerFields.size() ); ++i )
78 {
79 relation.addFieldPair( mReferencingLayerFields.at( i ), mReferencedLayerFields.at( i ) );
80 }
81
82 res.push_back( relation );
83 break;
84 }
85
87 {
88 // a many-to-many relationship is represented by two QgsRelations
89 QgsRelation relationLeft;
90 relationLeft.setId( mRelationId + u"_forward"_s );
91 relationLeft.setName( mRelationName + u"_forward"_s );
92 relationLeft.setStrength( mStrength );
93 QgsVectorLayerRef referencedLayerRef = mReferencedLayer;
94 QgsMapLayer *referencedLayer = referencedLayerRef.resolveWeakly( project, matchType );
95 if ( referencedLayer )
96 {
97 relationLeft.setReferencedLayer( referencedLayer->id() );
98 }
99
100 QgsVectorLayerRef mappingTableRef = mMappingTable;
101 QgsMapLayer *mappingLayer = mappingTableRef.resolveWeakly( project, matchType );
102 if ( mappingLayer )
103 {
104 relationLeft.setReferencingLayer( mappingLayer->id() );
105 }
106
107 for ( int i = 0; i < std::min( mMappingReferencedLayerFields.size(), mReferencedLayerFields.size() ); ++i )
108 {
109 relationLeft.addFieldPair( mMappingReferencedLayerFields.at( i ), mReferencedLayerFields.at( i ) );
110 }
111
112 res.push_back( relationLeft );
113
114 QgsRelation relationRight;
115 relationRight.setId( mRelationId + u"_backward"_s );
116 relationRight.setName( mRelationName + u"_backward"_s );
117 relationRight.setStrength( mStrength );
118
119 QgsVectorLayerRef referencingLayerRef = mReferencingLayer;
120 QgsMapLayer *referencingLayer = referencingLayerRef.resolveWeakly( project, matchType );
121 if ( referencingLayer )
122 {
123 relationRight.setReferencedLayer( referencingLayer->id() );
124 }
125 if ( mappingLayer )
126 {
127 relationRight.setReferencingLayer( mappingLayer->id() );
128 }
129
130 for ( int i = 0; i < std::min( mMappingReferencingLayerFields.size(), mReferencingLayerFields.size() ); ++i )
131 {
132 relationRight.addFieldPair( mMappingReferencingLayerFields.at( i ), mReferencingLayerFields.at( i ) );
133 }
134
135 res.push_back( relationRight );
136 break;
137 }
138 }
139
140 return res;
141}
142
144{
145 return mReferencingLayer;
146}
147
149{
150 return mReferencingLayer.source;
151}
152
154{
155 return mReferencingLayer.provider;
156}
157
158void QgsWeakRelation::setReferencingLayer( const QString &sourceUri, const QString &provider )
159{
160 mReferencingLayer.source = sourceUri;
161 mReferencingLayer.provider = provider;
162}
163
165{
166 if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( mReferencingLayer.provider ) )
167 {
168 return metadata->decodeUri( mReferencingLayer.source ).value( u"layerName"_s ).toString();
169 }
170 return QString();
171}
172
174{
175 return mReferencedLayer;
176}
177
179{
180 return mReferencedLayer.source;
181}
182
184{
185 return mReferencedLayer.provider;
186}
187
189{
190 if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( mReferencedLayer.provider ) )
191 {
192 return metadata->decodeUri( mReferencedLayer.source ).value( u"layerName"_s ).toString();
193 }
194 return QString();
195}
196
197void QgsWeakRelation::setReferencedLayer( const QString &sourceUri, const QString &provider )
198{
199 mReferencedLayer.source = sourceUri;
200 mReferencedLayer.provider = provider;
201}
202
204{
205 return mMappingTable;
206}
207
209{
210 mMappingTable = table;
211}
212
214{
215 return mMappingTable.source;
216}
217
219{
220 return mMappingTable.provider;
221}
222
224{
225 if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( mMappingTable.provider ) )
226 {
227 return metadata->decodeUri( mMappingTable.source ).value( u"layerName"_s ).toString();
228 }
229 return QString();
230}
231
232void QgsWeakRelation::setMappingTable( const QString &sourceUri, const QString &provider )
233{
234 mMappingTable.source = sourceUri;
235 mMappingTable.provider = provider;
236}
237
239{
240 return mStrength;
241}
242
243QgsWeakRelation QgsWeakRelation::readXml( const QgsVectorLayer *layer, WeakRelationType type, const QDomNode &node, const QgsPathResolver resolver )
244{
245 QDomElement relationElement = node.toElement();
246
247 if ( relationElement.tagName() != "relation"_L1 )
248 {
249 QgsLogger::warning( QApplication::translate( "QgsRelation", "Cannot create relation. Unexpected tag '%1'" ).arg( relationElement.tagName() ) );
250 }
251
252 QStringList referencingFields;
253 QStringList referencedFields;
254 const QDomNodeList fieldPairNodes { relationElement.elementsByTagName( u"fieldRef"_s ) };
255 for ( int j = 0; j < fieldPairNodes.length(); ++j )
256 {
257 const QDomElement fieldPairElement = fieldPairNodes.at( j ).toElement();
258 referencingFields.push_back( fieldPairElement.attribute( u"referencingField"_s ) );
259 referencedFields.push_back( fieldPairElement.attribute( u"referencedField"_s ) );
260 }
261
262 switch ( type )
263 {
264 case Referencing:
265 {
266 QgsWeakRelation rel {
267 relationElement.attribute( u"id"_s ),
268 relationElement.attribute( u"name"_s ),
269 static_cast<Qgis::RelationshipStrength>( relationElement.attribute( u"strength"_s ).toInt() ),
270 // Referencing
271 layer->id(),
272 layer->name(),
273 resolver.writePath( layer->publicSource() ),
274 layer->providerType(),
275 // Referenced
276 relationElement.attribute( u"layerId"_s ),
277 relationElement.attribute( u"layerName"_s ),
278 relationElement.attribute( u"dataSource"_s ),
279 relationElement.attribute( u"providerKey"_s )
280 };
281 rel.setReferencedLayerFields( referencedFields );
282 rel.setReferencingLayerFields( referencingFields );
283 return rel;
284 }
285
286 case Referenced:
287 {
288 QgsWeakRelation rel {
289 relationElement.attribute( u"id"_s ),
290 relationElement.attribute( u"name"_s ),
291 static_cast<Qgis::RelationshipStrength>( relationElement.attribute( u"strength"_s ).toInt() ),
292 // Referencing
293 relationElement.attribute( u"layerId"_s ),
294 relationElement.attribute( u"layerName"_s ),
295 relationElement.attribute( u"dataSource"_s ),
296 relationElement.attribute( u"providerKey"_s ),
297 // Referenced
298 layer->id(),
299 layer->name(),
300 resolver.writePath( layer->publicSource() ),
301 layer->providerType()
302 };
303 rel.setReferencedLayerFields( referencedFields );
304 rel.setReferencingLayerFields( referencingFields );
305 return rel;
306 }
307 }
308
309 // avoid build warnings
310 return QgsWeakRelation();
311}
312
313void QgsWeakRelation::writeXml( const QgsVectorLayer *layer, WeakRelationType type, const QgsRelation &relation, QDomNode &node, QDomDocument &doc )
314{
315 if ( !layer )
316 return;
317
318 if ( layer != relation.referencingLayer() && layer != relation.referencedLayer() )
319 return;
320
321 QgsPathResolver resolver;
322 if ( QgsProject *project = layer->project() )
323 resolver = project->pathResolver();
324
325 relation.writeXml( node, doc );
326 QDomNodeList relationsNodeList = node.toElement().elementsByTagName( u"relation"_s );
327 QDomElement relationElement;
328
329 for ( int i = 0; i < relationsNodeList.size(); ++i )
330 {
331 relationElement = relationsNodeList.at( i ).toElement();
332 if ( relationElement.hasAttribute( u"id"_s ) && relationElement.attribute( u"id"_s ) == relation.id() )
333 {
334 switch ( type )
335 {
336 case Referencing:
337 // if the layer is the referencing one, we save the referenced layer info
338 relationElement.setAttribute( u"layerId"_s, relation.referencedLayer()->id() );
339 relationElement.setAttribute( u"layerName"_s, relation.referencedLayer()->name() );
340 relationElement.setAttribute( u"dataSource"_s, resolver.writePath( relation.referencedLayer()->publicSource() ) );
341 relationElement.setAttribute( u"providerKey"_s, relation.referencedLayer()->providerType() );
342 break;
343
344 case Referenced:
345 // if the layer is the referenced one, we save the referencing layer info
346 relationElement.setAttribute( u"layerId"_s, relation.referencingLayer()->id() );
347 relationElement.setAttribute( u"layerName"_s, relation.referencingLayer()->name() );
348 relationElement.setAttribute( u"dataSource"_s, resolver.writePath( relation.referencingLayer()->publicSource() ) );
349 relationElement.setAttribute( u"providerKey"_s, relation.referencingLayer()->providerType() );
350 break;
351 }
352 }
353 }
354}
RelationshipStrength
Relationship strength.
Definition qgis.h:4549
@ ManyToMany
Many to many relationship.
Definition qgis.h:4565
@ ManyToOne
Many to one relationship.
Definition qgis.h:4564
@ OneToOne
One to one relationship.
Definition qgis.h:4562
@ OneToMany
One to many relationship.
Definition qgis.h:4563
static void warning(const QString &msg)
Goes to qWarning.
Base class for all map layer types.
Definition qgsmaplayer.h:83
QString name
Definition qgsmaplayer.h:87
QString providerType() const
Returns the provider type (provider key) for this layer.
QString id
Definition qgsmaplayer.h:86
QString publicSource(bool hidePassword=false) const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QgsProject * project() const
Returns the parent project if this map layer is added to a project.
Resolves relative paths into absolute paths and vice versa.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:113
Holds data provider key, description, and associated shared library file or function pointer informat...
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
void setId(const QString &id)
Set an id for this relation.
void setReferencedLayer(const QString &id)
Set the referenced (parent) layer id.
QgsVectorLayer * referencedLayer
Definition qgsrelation.h:50
void setStrength(Qgis::RelationshipStrength strength)
Set a strength for this relation.
QString id
Definition qgsrelation.h:45
Q_INVOKABLE void addFieldPair(const QString &referencingField, const QString &referencedField)
Add a field pair which is part of this relation The first element of each pair are the field names of...
void setReferencingLayer(const QString &id)
Set the referencing (child) layer id.
QgsVectorLayer * referencingLayer
Definition qgsrelation.h:47
void setName(const QString &name)
Set a name for this relation.
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
Represents a vector layer which manages a vector based dataset.
void setReferencedLayer(const QString &sourceUri, const QString &provider)
Sets the source for the referenced (or "parent" / "left") layer, by sourceUri and provider ID.
QgsVectorLayerRef referencedLayer() const
Returns a weak reference to the referenced (or "parent" / "left") layer.
QList< QgsRelation > resolvedRelations(const QgsProject *project, QgsVectorLayerRef::MatchType matchType=QgsVectorLayerRef::MatchType::All) const
Resolves a weak relation in the given project returning a list of possibly invalid QgsRelations and w...
void setMappingTable(const QgsVectorLayerRef &table)
Sets a weak reference to the mapping table, which forms the middle table in many-to-many relationship...
WeakRelationType
Enum to distinguish if the layer is referenced or referencing.
@ Referencing
The layer is referencing (or the "child" / "right" layer in the relationship).
@ Referenced
The layer is referenced (or the "parent" / "left" left in the relationship).
QString referencedLayerProvider() const
Returns the provider ID for the referenced (or "parent" / "left") layer.
QgsWeakRelation()
Default constructor for an invalid relation.
QString mappingTableProvider() const
Returns the provider ID for the mapping table, which forms the middle table in many-to-many relations...
QString mappingTableName() const
Returns the layer name of the mapping table, which forms the middle table in many-to-many relationshi...
QString mappingTableSource() const
Returns the source URI for the mapping table, which forms the middle table in many-to-many relationsh...
QString referencingLayerProvider() const
Returns the provider ID for the referencing (or "child" / "right") layer.
QgsVectorLayerRef referencingLayer() const
Returns a weak reference to the referencing (or "child" / "right") layer.
QString referencedLayerName() const
Returns the layer name of the referenced (or "parent" / "left") layer.
void setReferencingLayerFields(const QStringList &fields)
Sets the list of fields from the referencingLayer() involved in the relationship.
static void writeXml(const QgsVectorLayer *layer, WeakRelationType type, const QgsRelation &relation, QDomNode &node, QDomDocument &doc)
Writes a weak relation infoto an XML structure.
static QgsWeakRelation readXml(const QgsVectorLayer *layer, WeakRelationType type, const QDomNode &node, const QgsPathResolver resolver)
Returns a weak relation for the given layer.
void setReferencingLayer(const QString &sourceUri, const QString &provider)
Sets the source for the referencing (or "child" / "right") layer, by sourceUri and provider ID.
QString referencedLayerSource() const
Returns the source URI for the referenced (or "parent" / "left") layer.
QString referencingLayerSource() const
Returns the source URI for the referencing (or "child" / "right") layer.
QgsVectorLayerRef mappingTable() const
Returns a weak reference to the mapping table, which forms the middle table in many-to-many relations...
QString referencingLayerName() const
Returns the layer name of the referencing (or "child" / "right") layer.
void setReferencedLayerFields(const QStringList &fields)
Sets the list of fields from the referencedLayer() involved in the relationship.
Qgis::RelationshipStrength strength() const
Returns the strength of the relation.
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
QString source
Weak reference to layer public source.