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