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