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