QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgsrelationmanager.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrelationmanager.cpp
3 --------------------------------------
4 Date : 1.3.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 "qgsrelationmanager.h"
17
18#include "qgslogger.h"
19#include "qgsproject.h"
21#include "qgsvectorlayer.h"
22
23#include "moc_qgsrelationmanager.cpp"
24
26 : QObject( project )
27 , mProject( project )
28{
29 if ( project )
30 {
31 // TODO: QGIS 4 remove: relations are now stored with the layer style
32 connect( project, &QgsProject::readProjectWithContext, this, &QgsRelationManager::readProject );
33 // TODO: QGIS 4 remove: relations are now stored with the layer style
34 connect( project, &QgsProject::writeProject, this, &QgsRelationManager::writeProject );
35
36 connect( project, &QgsProject::layersRemoved, this, &QgsRelationManager::layersRemoved );
37 }
38}
39
44
45void QgsRelationManager::setRelations( const QList<QgsRelation> &relations )
46{
47 mRelations.clear();
48 for ( const QgsRelation &rel : std::as_const( relations ) )
49 {
50 addRelation( rel );
51 }
52 emit changed();
53}
54
55QMap<QString, QgsRelation> QgsRelationManager::relations() const
56{
57 return mRelations;
58}
59
61{
62 // Do not add relations to layers that do not exist
63 if ( !( relation.referencingLayer() && relation.referencedLayer() ) )
64 return;
65
66 mRelations.insert( relation.id(), relation );
67 if ( mProject )
68 {
69 mProject->setDirty( true );
70 }
71 emit changed();
72}
73
74
76{
77 for ( auto relationIt = mRelations.begin(); relationIt != mRelations.end(); ++relationIt )
78 {
79 relationIt->updateRelationStatus();
80 }
81}
82
83
84void QgsRelationManager::removeRelation( const QString &id )
85{
86 mRelations.remove( id );
87 emit changed();
88}
89
91{
92 mRelations.remove( relation.id() );
93 emit changed();
94}
95
96QgsRelation QgsRelationManager::relation( const QString &id ) const
97{
98 if ( !mRelations.contains( id ) )
99 {
100 // Check whether the provided ID refers to a polymorphic relation's generated ID
101 // from older versions of QGIS that used layer names instead of stable layer IDs.
102 const QList<QString> keys = mPolymorphicRelations.keys();
103 for ( const QString &key : keys )
104 {
105 if ( id.startsWith( key ) )
106 {
107 return mRelations.value( mPolymorphicRelations[key].upgradeGeneratedRelationId( id ) );
108 }
109 }
110 }
111
112 return mRelations.value( id );
113}
114
115QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
116{
117 QList<QgsRelation> relations;
118
119 for ( const QgsRelation &rel : std::as_const( mRelations ) )
120 {
121 if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
122 relations << rel;
123 }
124
125 return relations;
126}
127
129{
130 mRelations.clear();
131 emit changed();
132}
133
134QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
135{
136 if ( !layer )
137 {
138 return mRelations.values();
139 }
140
141 QList<QgsRelation> relations;
142
143 for ( const QgsRelation &rel : std::as_const( mRelations ) )
144 {
145 if ( rel.referencingLayer() == layer )
146 {
147 if ( fieldIdx != -2 )
148 {
149 bool containsField = false;
150 const auto constFieldPairs = rel.fieldPairs();
151 for ( const QgsRelation::FieldPair &fp : constFieldPairs )
152 {
153 if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
154 {
155 containsField = true;
156 break;
157 }
158 }
159
160 if ( !containsField )
161 {
162 continue;
163 }
164 }
165 relations.append( rel );
166 }
167 }
168
169 return relations;
170}
171
172QList<QgsRelation> QgsRelationManager::referencedRelations( const QgsVectorLayer *layer ) const
173{
174 if ( !layer )
175 {
176 return mRelations.values();
177 }
178
179 QList<QgsRelation> relations;
180
181 for ( const QgsRelation &rel : std::as_const( mRelations ) )
182 {
183 if ( rel.referencedLayer() == layer )
184 {
185 relations.append( rel );
186 }
187 }
188
189 return relations;
190}
191
192void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context )
193{
194 mRelations.clear();
195 mPolymorphicRelations.clear();
196
197 QDomNodeList relationNodes = doc.elementsByTagName( QStringLiteral( "relations" ) );
198 if ( relationNodes.count() )
199 {
200 QgsRelationContext relcontext( mProject );
201
202 QDomNode node = relationNodes.item( 0 );
203 QDomNodeList relationNodes = node.childNodes();
204 int relCount = relationNodes.count();
205 for ( int i = 0; i < relCount; ++i )
206 {
207 addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
208 }
209 }
210 else
211 {
212 QgsDebugMsgLevel( QStringLiteral( "No relations data present in this document" ), 2 );
213 }
214
215 QDomNodeList polymorphicRelationNodes = doc.elementsByTagName( QStringLiteral( "polymorphicRelations" ) );
216 if ( polymorphicRelationNodes.count() )
217 {
218 QgsRelationContext relcontext( mProject );
219
220 QDomNode node = polymorphicRelationNodes.item( 0 );
221 QDomNodeList relationNodes = node.childNodes();
222 int relCount = relationNodes.count();
223 for ( int i = 0; i < relCount; ++i )
224 {
225 addPolymorphicRelation( QgsPolymorphicRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
226 }
227 }
228 else
229 {
230 QgsDebugMsgLevel( QStringLiteral( "No polymorphic relations data present in this document" ), 3 );
231 }
232
233 emit relationsLoaded();
234 emit changed();
235}
236
237void QgsRelationManager::writeProject( QDomDocument &doc )
238{
239 QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
240 if ( !nl.count() )
241 {
242 QgsDebugError( QStringLiteral( "Unable to find qgis element in project file" ) );
243 return;
244 }
245 QDomNode qgisNode = nl.item( 0 ); // there should only be one
246
247 QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) );
248 qgisNode.appendChild( relationsNode );
249
250 for ( const QgsRelation &relation : std::as_const( mRelations ) )
251 {
252 // the generated relations for polymorphic relations should be ignored,
253 // they are generated every time when a polymorphic relation is added
254 switch ( relation.type() )
255 {
257 continue;
259 break;
260 }
261
262 relation.writeXml( relationsNode, doc );
263 }
264
265 QDomElement polymorphicRelationsNode = doc.createElement( QStringLiteral( "polymorphicRelations" ) );
266 qgisNode.appendChild( polymorphicRelationsNode );
267
268 for ( const QgsPolymorphicRelation &relation : std::as_const( mPolymorphicRelations ) )
269 {
270 relation.writeXml( polymorphicRelationsNode, doc );
271 }
272}
273
274void QgsRelationManager::layersRemoved( const QStringList &layers )
275{
276 bool relationsChanged = false;
277 for ( const QString &layer : std::as_const( layers ) )
278 {
279 QMapIterator<QString, QgsRelation> it( mRelations );
280
281 while ( it.hasNext() )
282 {
283 it.next();
284
285 if ( it.value().referencedLayerId() == layer
286 || it.value().referencingLayerId() == layer )
287 {
288 mRelations.remove( it.key() );
289 relationsChanged = true;
290 }
291 }
292 }
293 if ( relationsChanged )
294 {
295 emit changed();
296 }
297}
298
299static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
300{
301 for ( const QgsRelation &cur : std::as_const( existingRelations ) )
302 {
303 if ( cur.hasEqualDefinition( relation ) ) return true;
304 }
305 return false;
306}
307
308QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
309{
310 QList<QgsRelation> result;
311 for ( const QgsVectorLayer *layer : std::as_const( layers ) )
312 {
313 if ( const QgsVectorDataProvider *provider = layer->dataProvider() )
314 {
315 const auto constDiscoverRelations = provider->discoverRelations( layer, layers );
316 for ( const QgsRelation &relation : constDiscoverRelations )
317 {
318 if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
319 {
320 result.append( relation );
321 }
322 }
323 }
324 }
325 return result;
326}
327
328QMap<QString, QgsPolymorphicRelation> QgsRelationManager::polymorphicRelations() const
329{
330 return mPolymorphicRelations;
331}
332
333QgsPolymorphicRelation QgsRelationManager::polymorphicRelation( const QString &polymorphicRelationId ) const
334{
335 return mPolymorphicRelations.value( polymorphicRelationId );
336}
337
339{
340 if ( !polymorphicRelation.referencingLayer() || polymorphicRelation.id().isNull() )
341 return;
342
343 mPolymorphicRelations.insert( polymorphicRelation.id(), polymorphicRelation );
344
345 const QList<QgsRelation> generatedRelations = polymorphicRelation.generateRelations();
346 for ( const QgsRelation &generatedRelation : generatedRelations )
347 addRelation( generatedRelation );
348}
349
350void QgsRelationManager::removePolymorphicRelation( const QString &polymorphicRelationId )
351{
352 QgsPolymorphicRelation relation = mPolymorphicRelations.take( polymorphicRelationId );
353
354 const QList<QgsRelation> generatedRelations = relation.generateRelations();
355 for ( const QgsRelation &generatedRelation : generatedRelations )
356 removeRelation( generatedRelation.id() );
357}
358
359void QgsRelationManager::setPolymorphicRelations( const QList<QgsPolymorphicRelation> &relations )
360{
361 const QList<QgsPolymorphicRelation> oldRelations = polymorphicRelations().values();
362 for ( const QgsPolymorphicRelation &oldRelation : oldRelations )
363 removePolymorphicRelation( oldRelation.id() );
364
365 for ( const QgsPolymorphicRelation &newRelation : relations )
366 addPolymorphicRelation( newRelation );
367}
@ Generated
A generated relation is a child of a polymorphic relation.
Definition qgis.h:4393
@ Normal
A normal relation.
Definition qgis.h:4392
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A relation where the referenced (parent) layer is calculated based on fields from the referencing (ch...
static QgsPolymorphicRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:109
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the registry.
void readProjectWithContext(const QDomDocument &document, QgsReadWriteContext &context)
Emitted when a project is being read.
void writeProject(QDomDocument &document)
Emitted when the project is being written.
A container for the context for various read/write operations on objects.
Context for relations.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
static QList< QgsRelation > discoverRelations(const QList< QgsRelation > &existingRelations, const QList< QgsVectorLayer * > &layers)
Discover all the relations available from the current layers.
QList< QgsRelation > relationsByName(const QString &name) const
Returns a list of relations with matching names.
void addPolymorphicRelation(const QgsPolymorphicRelation &polymorphicRelation)
Adds a new polymorphic relation.
QgsPolymorphicRelation polymorphicRelation(const QString &polymorphicRelationId) const
Returns the list of relations associated with a polymorphic relation.
void setPolymorphicRelations(const QList< QgsPolymorphicRelation > &relations)
Sets the specified polymorphic relations and removes any polymorphic relations currently set.
QMap< QString, QgsPolymorphicRelation > polymorphicRelations() const
Returns all the polymorphic relations.
QgsRelationManager(QgsProject *project=nullptr)
Constructor for QgsRelationManager.
QList< QgsRelation > referencingRelations(const QgsVectorLayer *layer=nullptr, int fieldIdx=-2) const
Gets all relations where the specified layer (and field) is the referencing part (i....
void clear()
Remove any relation managed by this class.
void changed()
Emitted when relations are added or removed to the manager.
QgsRelationContext context() const
Gets the relation context.
void updateRelationsStatus()
Updates relations status.
Q_INVOKABLE void removeRelation(const QString &id)
Remove a relation.
void setRelations(const QList< QgsRelation > &relations)
Will set the specified relations and remove any relation currently set.
void removePolymorphicRelation(const QString &polymorphicRelationId)
Removes an existing polymorphic relation and it's generated relations.
Q_INVOKABLE void addRelation(const QgsRelation &relation)
Add a relation.
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Defines a relation between matching fields of the two involved tables of a relation.
Definition qgsrelation.h:72
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
static QgsRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
Base class for vector data providers.
Represents a vector layer which manages a vector based dataset.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
#define QgsDebugError(str)
Definition qgslogger.h:57