QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
39{
40 return QgsRelationContext( mProject );
41}
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 return mRelations.value( id );
97}
98
99QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
100{
101 QList<QgsRelation> relations;
102
103 for ( const QgsRelation &rel : std::as_const( mRelations ) )
104 {
105 if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
106 relations << rel;
107 }
108
109 return relations;
110}
111
113{
114 mRelations.clear();
115 emit changed();
116}
117
118QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
119{
120 if ( !layer )
121 {
122 return mRelations.values();
123 }
124
125 QList<QgsRelation> relations;
126
127 for ( const QgsRelation &rel : std::as_const( mRelations ) )
128 {
129 if ( rel.referencingLayer() == layer )
130 {
131 if ( fieldIdx != -2 )
132 {
133 bool containsField = false;
134 const auto constFieldPairs = rel.fieldPairs();
135 for ( const QgsRelation::FieldPair &fp : constFieldPairs )
136 {
137 if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
138 {
139 containsField = true;
140 break;
141 }
142 }
143
144 if ( !containsField )
145 {
146 continue;
147 }
148 }
149 relations.append( rel );
150 }
151 }
152
153 return relations;
154}
155
156QList<QgsRelation> QgsRelationManager::referencedRelations( const QgsVectorLayer *layer ) const
157{
158 if ( !layer )
159 {
160 return mRelations.values();
161 }
162
163 QList<QgsRelation> relations;
164
165 for ( const QgsRelation &rel : std::as_const( mRelations ) )
166 {
167 if ( rel.referencedLayer() == layer )
168 {
169 relations.append( rel );
170 }
171 }
172
173 return relations;
174}
175
176void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context )
177{
178 mRelations.clear();
179 mPolymorphicRelations.clear();
180
181 QDomNodeList relationNodes = doc.elementsByTagName( QStringLiteral( "relations" ) );
182 if ( relationNodes.count() )
183 {
184 QgsRelationContext relcontext( mProject );
185
186 QDomNode node = relationNodes.item( 0 );
187 QDomNodeList relationNodes = node.childNodes();
188 int relCount = relationNodes.count();
189 for ( int i = 0; i < relCount; ++i )
190 {
191 addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
192 }
193 }
194 else
195 {
196 QgsDebugMsgLevel( QStringLiteral( "No relations data present in this document" ), 2 );
197 }
198
199 QDomNodeList polymorphicRelationNodes = doc.elementsByTagName( QStringLiteral( "polymorphicRelations" ) );
200 if ( polymorphicRelationNodes.count() )
201 {
202 QgsRelationContext relcontext( mProject );
203
204 QDomNode node = polymorphicRelationNodes.item( 0 );
205 QDomNodeList relationNodes = node.childNodes();
206 int relCount = relationNodes.count();
207 for ( int i = 0; i < relCount; ++i )
208 {
209 addPolymorphicRelation( QgsPolymorphicRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
210 }
211 }
212 else
213 {
214 QgsDebugMsgLevel( QStringLiteral( "No polymorphic relations data present in this document" ), 3 );
215 }
216
217 emit relationsLoaded();
218 emit changed();
219}
220
221void QgsRelationManager::writeProject( QDomDocument &doc )
222{
223 QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
224 if ( !nl.count() )
225 {
226 QgsDebugError( QStringLiteral( "Unable to find qgis element in project file" ) );
227 return;
228 }
229 QDomNode qgisNode = nl.item( 0 ); // there should only be one
230
231 QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) );
232 qgisNode.appendChild( relationsNode );
233
234 for ( const QgsRelation &relation : std::as_const( mRelations ) )
235 {
236 // the generated relations for polymorphic relations should be ignored,
237 // they are generated every time when a polymorphic relation is added
238 switch ( relation.type() )
239 {
241 continue;
243 break;
244 }
245
246 relation.writeXml( relationsNode, doc );
247 }
248
249 QDomElement polymorphicRelationsNode = doc.createElement( QStringLiteral( "polymorphicRelations" ) );
250 qgisNode.appendChild( polymorphicRelationsNode );
251
252 for ( const QgsPolymorphicRelation &relation : std::as_const( mPolymorphicRelations ) )
253 {
254 relation.writeXml( polymorphicRelationsNode, doc );
255 }
256}
257
258void QgsRelationManager::layersRemoved( const QStringList &layers )
259{
260 bool relationsChanged = false;
261 for ( const QString &layer : std::as_const( layers ) )
262 {
263 QMapIterator<QString, QgsRelation> it( mRelations );
264
265 while ( it.hasNext() )
266 {
267 it.next();
268
269 if ( it.value().referencedLayerId() == layer
270 || it.value().referencingLayerId() == layer )
271 {
272 mRelations.remove( it.key() );
273 relationsChanged = true;
274 }
275 }
276 }
277 if ( relationsChanged )
278 {
279 emit changed();
280 }
281}
282
283static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
284{
285 for ( const QgsRelation &cur : std::as_const( existingRelations ) )
286 {
287 if ( cur.hasEqualDefinition( relation ) ) return true;
288 }
289 return false;
290}
291
292QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
293{
294 QList<QgsRelation> result;
295 for ( const QgsVectorLayer *layer : std::as_const( layers ) )
296 {
297 if ( const QgsVectorDataProvider *provider = layer->dataProvider() )
298 {
299 const auto constDiscoverRelations = provider->discoverRelations( layer, layers );
300 for ( const QgsRelation &relation : constDiscoverRelations )
301 {
302 if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
303 {
304 result.append( relation );
305 }
306 }
307 }
308 }
309 return result;
310}
311
312QMap<QString, QgsPolymorphicRelation> QgsRelationManager::polymorphicRelations() const
313{
314 return mPolymorphicRelations;
315}
316
317QgsPolymorphicRelation QgsRelationManager::polymorphicRelation( const QString &polymorphicRelationId ) const
318{
319 return mPolymorphicRelations.value( polymorphicRelationId );
320}
321
323{
325 return;
326
327 mPolymorphicRelations.insert( polymorphicRelation.id(), polymorphicRelation );
328
329 const QList<QgsRelation> generatedRelations = polymorphicRelation.generateRelations();
330 for ( const QgsRelation &generatedRelation : generatedRelations )
331 addRelation( generatedRelation );
332}
333
334void QgsRelationManager::removePolymorphicRelation( const QString &polymorphicRelationId )
335{
336 QgsPolymorphicRelation relation = mPolymorphicRelations.take( polymorphicRelationId );
337
338 const QList<QgsRelation> generatedRelations = relation.generateRelations();
339 for ( const QgsRelation &generatedRelation : generatedRelations )
340 removeRelation( generatedRelation.id() );
341}
342
343void QgsRelationManager::setPolymorphicRelations( const QList<QgsPolymorphicRelation> &relations )
344{
345 const QList<QgsPolymorphicRelation> oldRelations = polymorphicRelations().values();
346 for ( const QgsPolymorphicRelation &oldRelation : oldRelations )
347 removePolymorphicRelation( oldRelation.id() );
348
349 for ( const QgsPolymorphicRelation &newRelation : relations )
350 addPolymorphicRelation( newRelation );
351}
@ Generated
A generated relation is a child of a polymorphic relation.
@ Normal
A normal relation.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
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.
QgsVectorLayer * referencingLayer
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 &, QgsReadWriteContext &context)
Emitted when a project is being read.
void writeProject(QDomDocument &)
Emitted when the project is being written.
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:599
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:67
static QgsRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
Definition: qgsrelation.cpp:54
QgsVectorLayer * referencedLayer
Definition: qgsrelation.h:47
Qgis::RelationshipType type() const
Returns the type of the relation.
Q_GADGET QString id
Definition: qgsrelation.h:45
QgsVectorLayer * referencingLayer
Definition: qgsrelation.h:46
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38