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