QGIS API Documentation 3.99.0-Master (8e76e220402)
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 <QString>
24
25#include "moc_qgsrelationmanager.cpp"
26
27using namespace Qt::StringLiterals;
28
30 : QObject( project )
31 , mProject( project )
32{
33 if ( project )
34 {
35 // TODO: QGIS 5 remove: relations are now stored with the layer style
36 connect( project, &QgsProject::readProjectWithContext, this, &QgsRelationManager::readProject );
37 // TODO: QGIS 5 remove: relations are now stored with the layer style
38 connect( project, &QgsProject::writeProject, this, &QgsRelationManager::writeProject );
39
40 connect( project, &QgsProject::layersRemoved, this, &QgsRelationManager::layersRemoved );
41 }
42}
43
48
49void QgsRelationManager::setRelations( const QList<QgsRelation> &relations )
50{
51 mRelations.clear();
52 for ( const QgsRelation &rel : std::as_const( relations ) )
53 {
54 addRelation( rel );
55 }
56 emit changed();
57}
58
59QMap<QString, QgsRelation> QgsRelationManager::relations() const
60{
61 return mRelations;
62}
63
65{
66 // Do not add relations to layers that do not exist
67 if ( !( relation.referencingLayer() && relation.referencedLayer() ) )
68 return;
69
70 mRelations.insert( relation.id(), relation );
71 if ( mProject )
72 {
73 mProject->setDirty( true );
74 }
75 emit changed();
76}
77
78
80{
81 for ( auto relationIt = mRelations.begin(); relationIt != mRelations.end(); ++relationIt )
82 {
83 relationIt->updateRelationStatus();
84 }
85}
86
87
88void QgsRelationManager::removeRelation( const QString &id )
89{
90 mRelations.remove( id );
91 emit changed();
92}
93
95{
96 mRelations.remove( relation.id() );
97 emit changed();
98}
99
101{
102 if ( !mRelations.contains( id ) )
103 {
104 // Check whether the provided ID refers to a polymorphic relation's generated ID
105 // from older versions of QGIS that used layer names instead of stable layer IDs.
106 const QList<QString> keys = mPolymorphicRelations.keys();
107 for ( const QString &key : keys )
108 {
109 if ( id.startsWith( key ) )
110 {
111 return mRelations.value( mPolymorphicRelations[key].upgradeGeneratedRelationId( id ) );
112 }
113 }
114 }
115
116 return mRelations.value( id );
117}
118
119QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
120{
121 QList<QgsRelation> relations;
122
123 for ( const QgsRelation &rel : std::as_const( mRelations ) )
124 {
125 if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
126 relations << rel;
127 }
128
129 return relations;
130}
131
133{
134 mRelations.clear();
135 emit changed();
136}
137
138QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
139{
140 if ( !layer )
141 {
142 return mRelations.values();
143 }
144
145 QList<QgsRelation> relations;
146
147 for ( const QgsRelation &rel : std::as_const( mRelations ) )
148 {
149 if ( rel.referencingLayer() == layer )
150 {
151 if ( fieldIdx != -2 )
152 {
153 bool containsField = false;
154 const auto constFieldPairs = rel.fieldPairs();
155 for ( const QgsRelation::FieldPair &fp : constFieldPairs )
156 {
157 if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
158 {
159 containsField = true;
160 break;
161 }
162 }
163
164 if ( !containsField )
165 {
166 continue;
167 }
168 }
169 relations.append( rel );
170 }
171 }
172
173 return relations;
174}
175
176QList<QgsRelation> QgsRelationManager::referencedRelations( const QgsVectorLayer *layer ) const
177{
178 if ( !layer )
179 {
180 return mRelations.values();
181 }
182
183 QList<QgsRelation> relations;
184
185 for ( const QgsRelation &rel : std::as_const( mRelations ) )
186 {
187 if ( rel.referencedLayer() == layer )
188 {
189 relations.append( rel );
190 }
191 }
192
193 return relations;
194}
195
196void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context )
197{
198 mRelations.clear();
199 mPolymorphicRelations.clear();
200
201 QDomNodeList relationNodes = doc.elementsByTagName( u"relations"_s );
202 if ( relationNodes.count() )
203 {
204 QgsRelationContext relcontext( mProject );
205
206 QDomNode node = relationNodes.item( 0 );
207 QDomNodeList relationNodes = node.childNodes();
208 int relCount = relationNodes.count();
209 for ( int i = 0; i < relCount; ++i )
210 {
211 addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
212 }
213 }
214 else
215 {
216 QgsDebugMsgLevel( u"No relations data present in this document"_s, 2 );
217 }
218
219 QDomNodeList polymorphicRelationNodes = doc.elementsByTagName( u"polymorphicRelations"_s );
220 if ( polymorphicRelationNodes.count() )
221 {
222 QgsRelationContext relcontext( mProject );
223
224 QDomNode node = polymorphicRelationNodes.item( 0 );
225 QDomNodeList relationNodes = node.childNodes();
226 int relCount = relationNodes.count();
227 for ( int i = 0; i < relCount; ++i )
228 {
229 addPolymorphicRelation( QgsPolymorphicRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
230 }
231 }
232 else
233 {
234 QgsDebugMsgLevel( u"No polymorphic relations data present in this document"_s, 3 );
235 }
236
237 emit relationsLoaded();
238 emit changed();
239}
240
241void QgsRelationManager::writeProject( QDomDocument &doc )
242{
243 QDomNodeList nl = doc.elementsByTagName( u"qgis"_s );
244 if ( !nl.count() )
245 {
246 QgsDebugError( u"Unable to find qgis element in project file"_s );
247 return;
248 }
249 QDomNode qgisNode = nl.item( 0 ); // there should only be one
250
251 QDomElement relationsNode = doc.createElement( u"relations"_s );
252 qgisNode.appendChild( relationsNode );
253
254 for ( const QgsRelation &relation : std::as_const( mRelations ) )
255 {
256 // the generated relations for polymorphic relations should be ignored,
257 // they are generated every time when a polymorphic relation is added
258 switch ( relation.type() )
259 {
261 continue;
263 break;
264 }
265
266 relation.writeXml( relationsNode, doc );
267 }
268
269 QDomElement polymorphicRelationsNode = doc.createElement( u"polymorphicRelations"_s );
270 qgisNode.appendChild( polymorphicRelationsNode );
271
272 for ( const QgsPolymorphicRelation &relation : std::as_const( mPolymorphicRelations ) )
273 {
274 relation.writeXml( polymorphicRelationsNode, doc );
275 }
276}
277
278void QgsRelationManager::layersRemoved( const QStringList &layers )
279{
280 bool relationsChanged = false;
281 for ( const QString &layer : std::as_const( layers ) )
282 {
283 QMapIterator<QString, QgsRelation> it( mRelations );
284
285 while ( it.hasNext() )
286 {
287 it.next();
288
289 if ( it.value().referencedLayerId() == layer
290 || it.value().referencingLayerId() == layer )
291 {
292 mRelations.remove( it.key() );
293 relationsChanged = true;
294 }
295 }
296 }
297 if ( relationsChanged )
298 {
299 emit changed();
300 }
301}
302
303static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
304{
305 for ( const QgsRelation &cur : std::as_const( existingRelations ) )
306 {
307 if ( cur.hasEqualDefinition( relation ) ) return true;
308 }
309 return false;
310}
311
312QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
313{
314 QList<QgsRelation> result;
315 for ( const QgsVectorLayer *layer : std::as_const( layers ) )
316 {
317 if ( const QgsVectorDataProvider *provider = layer->dataProvider() )
318 {
319 const auto constDiscoverRelations = provider->discoverRelations( layer, layers );
320 for ( const QgsRelation &relation : constDiscoverRelations )
321 {
322 if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
323 {
324 result.append( relation );
325 }
326 }
327 }
328 }
329 return result;
330}
331
332QMap<QString, QgsPolymorphicRelation> QgsRelationManager::polymorphicRelations() const
333{
334 return mPolymorphicRelations;
335}
336
337QgsPolymorphicRelation QgsRelationManager::polymorphicRelation( const QString &polymorphicRelationId ) const
338{
339 return mPolymorphicRelations.value( polymorphicRelationId );
340}
341
343{
344 if ( !polymorphicRelation.referencingLayer() || polymorphicRelation.id().isNull() )
345 return;
346
347 mPolymorphicRelations.insert( polymorphicRelation.id(), polymorphicRelation );
348
349 const QList<QgsRelation> generatedRelations = polymorphicRelation.generateRelations();
350 for ( const QgsRelation &generatedRelation : generatedRelations )
351 addRelation( generatedRelation );
352}
353
354void QgsRelationManager::removePolymorphicRelation( const QString &polymorphicRelationId )
355{
356 QgsPolymorphicRelation relation = mPolymorphicRelations.take( polymorphicRelationId );
357
358 const QList<QgsRelation> generatedRelations = relation.generateRelations();
359 for ( const QgsRelation &generatedRelation : generatedRelations )
360 removeRelation( generatedRelation.id() );
361}
362
363void QgsRelationManager::setPolymorphicRelations( const QList<QgsPolymorphicRelation> &relations )
364{
365 const QList<QgsPolymorphicRelation> oldRelations = polymorphicRelations().values();
366 for ( const QgsPolymorphicRelation &oldRelation : oldRelations )
367 removePolymorphicRelation( oldRelation.id() );
368
369 for ( const QgsPolymorphicRelation &newRelation : relations )
370 addPolymorphicRelation( newRelation );
371}
@ Generated
A generated relation is a child of a polymorphic relation.
Definition qgis.h:4487
@ Normal
A normal relation.
Definition qgis.h:4486
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:113
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:63
#define QgsDebugError(str)
Definition qgslogger.h:59