QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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
26
27QgsWeakRelation::QgsWeakRelation( const QString &relationId, const QString &relationName, const Qgis::RelationshipStrength strength,
28 const QString &referencingLayerId, const QString &referencingLayerName, const QString &referencingLayerSource, const QString &referencingLayerProviderKey,
29 const QString &referencedLayerId, const QString &referencedLayerName, const QString &referencedLayerSource, const QString &referencedLayerProviderKey )
30 : mReferencingLayer( referencingLayerId, referencingLayerName, referencingLayerSource, referencingLayerProviderKey )
31 , mReferencedLayer( referencedLayerId, referencedLayerName, referencedLayerSource, referencedLayerProviderKey )
32 , mRelationId( relationId )
33 , mRelationName( relationName )
34 , mStrength( strength )
35{
36}
37
38QList< QgsRelation > QgsWeakRelation::resolvedRelations( const QgsProject *project, QgsVectorLayerRef::MatchType matchType ) const
39{
40 QList< QgsRelation > res;
41
42 switch ( mCardinality )
43 {
47 {
48
49 QgsRelation relation;
50 relation.setId( mRelationId );
51 relation.setName( mRelationName );
52 relation.setStrength( mStrength );
53 QgsVectorLayerRef referencedLayerRef = mReferencedLayer;
54 QgsMapLayer *referencedLayer = referencedLayerRef.resolveWeakly( project, matchType );
55 if ( referencedLayer )
56 {
57 relation.setReferencedLayer( referencedLayer->id() );
58 }
59 QgsVectorLayerRef referencingLayerRef = mReferencingLayer;
60 QgsMapLayer *referencingLayer = referencingLayerRef.resolveWeakly( project, matchType );
61 if ( referencingLayer )
62 {
63 relation.setReferencingLayer( referencingLayer->id() );
64 }
65
66 for ( int i = 0 ; i < std::min( mReferencingLayerFields.size(), mReferencedLayerFields.size() ); ++i )
67 {
68 relation.addFieldPair( mReferencingLayerFields.at( i ), mReferencedLayerFields.at( i ) );
69 }
70
71 res.push_back( relation );
72 break;
73 }
74
76 {
77 // a many-to-many relationship is represented by two QgsRelations
78 QgsRelation relationLeft;
79 relationLeft.setId( mRelationId + QStringLiteral( "_forward" ) );
80 relationLeft.setName( mRelationName + QStringLiteral( "_forward" ) );
81 relationLeft.setStrength( mStrength );
82 QgsVectorLayerRef referencedLayerRef = mReferencedLayer;
83 QgsMapLayer *referencedLayer = referencedLayerRef.resolveWeakly( project, matchType );
84 if ( referencedLayer )
85 {
86 relationLeft.setReferencedLayer( referencedLayer->id() );
87 }
88
89 QgsVectorLayerRef mappingTableRef = mMappingTable;
90 QgsMapLayer *mappingLayer = mappingTableRef.resolveWeakly( project, matchType );
91 if ( mappingLayer )
92 {
93 relationLeft.setReferencingLayer( mappingLayer->id() );
94 }
95
96 for ( int i = 0 ; i < std::min( mMappingReferencedLayerFields.size(), mReferencedLayerFields.size() ); ++i )
97 {
98 relationLeft.addFieldPair( mMappingReferencedLayerFields.at( i ), mReferencedLayerFields.at( i ) );
99 }
100
101 res.push_back( relationLeft );
102
103 QgsRelation relationRight;
104 relationRight.setId( mRelationId + QStringLiteral( "_backward" ) );
105 relationRight.setName( mRelationName + QStringLiteral( "_backward" ) );
106 relationRight.setStrength( mStrength );
107
108 QgsVectorLayerRef referencingLayerRef = mReferencingLayer;
109 QgsMapLayer *referencingLayer = referencingLayerRef.resolveWeakly( project, matchType );
110 if ( referencingLayer )
111 {
112 relationRight.setReferencedLayer( referencingLayer->id() );
113 }
114 if ( mappingLayer )
115 {
116 relationRight.setReferencingLayer( mappingLayer->id() );
117 }
118
119 for ( int i = 0 ; i < std::min( mMappingReferencingLayerFields.size(), mReferencingLayerFields.size() ); ++i )
120 {
121 relationRight.addFieldPair( mMappingReferencingLayerFields.at( i ), mReferencingLayerFields.at( i ) );
122 }
123
124 res.push_back( relationRight );
125 break;
126 }
127 }
128
129 return res;
130}
131
133{
134 return mReferencingLayer;
135}
136
138{
139 return mReferencingLayer.source;
140}
141
143{
144 return mReferencingLayer.provider;
145}
146
147void QgsWeakRelation::setReferencingLayer( const QString &sourceUri, const QString &provider )
148{
149 mReferencingLayer.source = sourceUri;
150 mReferencingLayer.provider = provider;
151}
152
154{
155 if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( mReferencingLayer.provider ) )
156 {
157 return metadata->decodeUri( mReferencingLayer.source ).value( QStringLiteral( "layerName" ) ).toString();
158 }
159 return QString();
160}
161
163{
164 return mReferencedLayer;
165}
166
168{
169 return mReferencedLayer.source;
170}
171
173{
174 return mReferencedLayer.provider;
175}
176
178{
179 if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( mReferencedLayer.provider ) )
180 {
181 return metadata->decodeUri( mReferencedLayer.source ).value( QStringLiteral( "layerName" ) ).toString();
182 }
183 return QString();
184}
185
186void QgsWeakRelation::setReferencedLayer( const QString &sourceUri, const QString &provider )
187{
188 mReferencedLayer.source = sourceUri;
189 mReferencedLayer.provider = provider;
190}
191
193{
194 return mMappingTable;
195}
196
198{
199 mMappingTable = table;
200}
201
203{
204 return mMappingTable.source;
205}
206
208{
209 return mMappingTable.provider;
210}
211
213{
214 if ( QgsProviderMetadata *metadata = QgsProviderRegistry::instance()->providerMetadata( mMappingTable.provider ) )
215 {
216 return metadata->decodeUri( mMappingTable.source ).value( QStringLiteral( "layerName" ) ).toString();
217 }
218 return QString();
219}
220
221void QgsWeakRelation::setMappingTable( const QString &sourceUri, const QString &provider )
222{
223 mMappingTable.source = sourceUri;
224 mMappingTable.provider = provider;
225}
226
228{
229 return mStrength;
230}
231
232QgsWeakRelation QgsWeakRelation::readXml( const QgsVectorLayer *layer, WeakRelationType type, const QDomNode &node, const QgsPathResolver resolver )
233{
234 QDomElement relationElement = node.toElement();
235
236 if ( relationElement.tagName() != QLatin1String( "relation" ) )
237 {
238 QgsLogger::warning( QApplication::translate( "QgsRelation", "Cannot create relation. Unexpected tag '%1'" ).arg( relationElement.tagName() ) );
239 }
240
241 QStringList referencingFields;
242 QStringList referencedFields;
243 const QDomNodeList fieldPairNodes { relationElement.elementsByTagName( QStringLiteral( "fieldRef" ) ) };
244 for ( int j = 0; j < fieldPairNodes.length(); ++j )
245 {
246 const QDomElement fieldPairElement = fieldPairNodes.at( j ).toElement();
247 referencingFields.push_back( fieldPairElement.attribute( QStringLiteral( "referencingField" ) ) );
248 referencedFields.push_back( fieldPairElement.attribute( QStringLiteral( "referencedField" ) ) );
249 }
250
251 switch ( type )
252 {
253 case Referencing:
254 {
255 QgsWeakRelation rel{ relationElement.attribute( QStringLiteral( "id" ) ),
256 relationElement.attribute( QStringLiteral( "name" ) ),
257 static_cast<Qgis::RelationshipStrength>( relationElement.attribute( QStringLiteral( "strength" ) ).toInt() ),
258 // Referencing
259 layer->id(),
260 layer->name(),
261 resolver.writePath( layer->publicSource() ),
262 layer->providerType(),
263 // Referenced
264 relationElement.attribute( QStringLiteral( "layerId" ) ),
265 relationElement.attribute( QStringLiteral( "layerName" ) ),
266 relationElement.attribute( QStringLiteral( "dataSource" ) ),
267 relationElement.attribute( QStringLiteral( "providerKey" ) )
268 };
269 rel.setReferencedLayerFields( referencedFields );
270 rel.setReferencingLayerFields( referencingFields );
271 return rel;
272 }
273
274 case Referenced:
275 {
276 QgsWeakRelation rel{ relationElement.attribute( QStringLiteral( "id" ) ),
277 relationElement.attribute( QStringLiteral( "name" ) ),
278 static_cast<Qgis::RelationshipStrength>( relationElement.attribute( QStringLiteral( "strength" ) ).toInt() ),
279 // Referencing
280 relationElement.attribute( QStringLiteral( "layerId" ) ),
281 relationElement.attribute( QStringLiteral( "layerName" ) ),
282 relationElement.attribute( QStringLiteral( "dataSource" ) ),
283 relationElement.attribute( QStringLiteral( "providerKey" ) ),
284 // Referenced
285 layer->id(),
286 layer->name(),
287 resolver.writePath( layer->publicSource() ),
288 layer->providerType()
289 };
290 rel.setReferencedLayerFields( referencedFields );
291 rel.setReferencingLayerFields( referencingFields );
292 return rel;
293 }
294 }
295
296 // avoid build warnings
297 return QgsWeakRelation();
298}
299
300void QgsWeakRelation::writeXml( const QgsVectorLayer *layer, WeakRelationType type, const QgsRelation &relation, QDomNode &node, QDomDocument &doc )
301{
302 if ( !layer )
303 return;
304
305 if ( layer != relation.referencingLayer() && layer != relation.referencedLayer() )
306 return;
307
308 QgsPathResolver resolver;
309 if ( QgsProject *project = layer->project() )
310 resolver = project->pathResolver();
311
312 relation.writeXml( node, doc );
313 QDomNodeList relationsNodeList = node.toElement().elementsByTagName( QStringLiteral( "relation" ) );
314 QDomElement relationElement;
315
316 for ( int i = 0; i < relationsNodeList.size(); ++i )
317 {
318 relationElement = relationsNodeList.at( i ).toElement();
319 if ( relationElement.hasAttribute( QStringLiteral( "id" ) ) && relationElement.attribute( QStringLiteral( "id" ) ) == relation.id() )
320 {
321 switch ( type )
322 {
323 case Referencing:
324 // if the layer is the referencing one, we save the referenced layer info
325 relationElement.setAttribute( QStringLiteral( "layerId" ), relation.referencedLayer()->id() );
326 relationElement.setAttribute( QStringLiteral( "layerName" ), relation.referencedLayer()->name() );
327 relationElement.setAttribute( QStringLiteral( "dataSource" ), resolver.writePath( relation.referencedLayer()->publicSource() ) );
328 relationElement.setAttribute( QStringLiteral( "providerKey" ), relation.referencedLayer()->providerType() );
329 break;
330
331 case Referenced:
332 // if the layer is the referenced one, we save the referencing layer info
333 relationElement.setAttribute( QStringLiteral( "layerId" ), relation.referencingLayer()->id() );
334 relationElement.setAttribute( QStringLiteral( "layerName" ), relation.referencingLayer()->name() );
335 relationElement.setAttribute( QStringLiteral( "dataSource" ), resolver.writePath( relation.referencingLayer()->publicSource() ) );
336 relationElement.setAttribute( QStringLiteral( "providerKey" ), relation.referencingLayer()->providerType() );
337 break;
338 }
339 }
340 }
341}
RelationshipStrength
Relationship strength.
Definition qgis.h:4405
@ ManyToMany
Many to many relationship.
Definition qgis.h:4421
@ ManyToOne
Many to one relationship.
Definition qgis.h:4420
@ OneToOne
One to one relationship.
Definition qgis.h:4418
@ OneToMany
One to many relationship.
Definition qgis.h:4419
static void warning(const QString &msg)
Goes to qWarning.
Base class for all map layer types.
Definition qgsmaplayer.h:80
QString name
Definition qgsmaplayer.h:84
QString providerType() const
Returns the provider type (provider key) for this layer.
QString id
Definition qgsmaplayer.h:83
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:109
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.