QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 "qgsapplication.h"
19 #include "qgslogger.h"
20 #include "qgsproject.h"
21 #include "qgsvectordataprovider.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 
40 {
41  return QgsRelationContext( mProject );
42 }
43 
44 void 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 
54 QMap<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 relation : mRelations )
77  {
79  }
80 }
81 
82 
83 void 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 
95 QgsRelation QgsRelationManager::relation( const QString &id ) const
96 {
97  return mRelations.value( id );
98 }
99 
100 QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
101 {
102  QList<QgsRelation> relations;
103 
104  for ( const QgsRelation &rel : std::as_const( mRelations ) )
105  {
106  if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
107  relations << rel;
108  }
109 
110  return relations;
111 }
112 
114 {
115  mRelations.clear();
116  emit changed();
117 }
118 
119 QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
120 {
121  if ( !layer )
122  {
123  return mRelations.values();
124  }
125 
126  QList<QgsRelation> relations;
127 
128  for ( const QgsRelation &rel : std::as_const( mRelations ) )
129  {
130  if ( rel.referencingLayer() == layer )
131  {
132  if ( fieldIdx != -2 )
133  {
134  bool containsField = false;
135  const auto constFieldPairs = rel.fieldPairs();
136  for ( const QgsRelation::FieldPair &fp : constFieldPairs )
137  {
138  if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
139  {
140  containsField = true;
141  break;
142  }
143  }
144 
145  if ( !containsField )
146  {
147  continue;
148  }
149  }
150  relations.append( rel );
151  }
152  }
153 
154  return relations;
155 }
156 
157 QList<QgsRelation> QgsRelationManager::referencedRelations( const QgsVectorLayer *layer ) const
158 {
159  if ( !layer )
160  {
161  return mRelations.values();
162  }
163 
164  QList<QgsRelation> relations;
165 
166  for ( const QgsRelation &rel : std::as_const( mRelations ) )
167  {
168  if ( rel.referencedLayer() == layer )
169  {
170  relations.append( rel );
171  }
172  }
173 
174  return relations;
175 }
176 
177 void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context )
178 {
179  mRelations.clear();
180  mPolymorphicRelations.clear();
181 
182  QDomNodeList relationNodes = doc.elementsByTagName( QStringLiteral( "relations" ) );
183  if ( relationNodes.count() )
184  {
185  QgsRelationContext relcontext( mProject );
186 
187  QDomNode node = relationNodes.item( 0 );
188  QDomNodeList relationNodes = node.childNodes();
189  int relCount = relationNodes.count();
190  for ( int i = 0; i < relCount; ++i )
191  {
192  addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
193  }
194  }
195  else
196  {
197  QgsDebugMsg( QStringLiteral( "No relations data present in this document" ) );
198  }
199 
200  QDomNodeList polymorphicRelationNodes = doc.elementsByTagName( QStringLiteral( "polymorphicRelations" ) );
201  if ( polymorphicRelationNodes.count() )
202  {
203  QgsRelationContext relcontext( mProject );
204 
205  QDomNode node = polymorphicRelationNodes.item( 0 );
206  QDomNodeList relationNodes = node.childNodes();
207  int relCount = relationNodes.count();
208  for ( int i = 0; i < relCount; ++i )
209  {
210  addPolymorphicRelation( QgsPolymorphicRelation::createFromXml( relationNodes.at( i ), context, relcontext ) );
211  }
212  }
213  else
214  {
215  QgsDebugMsgLevel( QStringLiteral( "No polymorphic relations data present in this document" ), 3 );
216  }
217 
218  emit relationsLoaded();
219  emit changed();
220 }
221 
222 void QgsRelationManager::writeProject( QDomDocument &doc )
223 {
224  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
225  if ( !nl.count() )
226  {
227  QgsDebugMsg( QStringLiteral( "Unable to find qgis element in project file" ) );
228  return;
229  }
230  QDomNode qgisNode = nl.item( 0 ); // there should only be one
231 
232  QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) );
233  qgisNode.appendChild( relationsNode );
234 
235  for ( const QgsRelation &relation : std::as_const( mRelations ) )
236  {
237  // the generated relations for polymorphic relations should be ignored,
238  // they are generated every time when a polymorphic relation is added
240  continue;
241 
242  relation.writeXml( relationsNode, doc );
243  }
244 
245  QDomElement polymorphicRelationsNode = doc.createElement( QStringLiteral( "polymorphicRelations" ) );
246  qgisNode.appendChild( polymorphicRelationsNode );
247 
248  for ( const QgsPolymorphicRelation &relation : std::as_const( mPolymorphicRelations ) )
249  {
250  relation.writeXml( polymorphicRelationsNode, doc );
251  }
252 }
253 
254 void QgsRelationManager::layersRemoved( const QStringList &layers )
255 {
256  bool relationsChanged = false;
257  for ( const QString &layer : std::as_const( layers ) )
258  {
259  QMapIterator<QString, QgsRelation> it( mRelations );
260 
261  while ( it.hasNext() )
262  {
263  it.next();
264 
265  if ( it.value().referencedLayerId() == layer
266  || it.value().referencingLayerId() == layer )
267  {
268  mRelations.remove( it.key() );
269  relationsChanged = true;
270  }
271  }
272  }
273  if ( relationsChanged )
274  {
275  emit changed();
276  }
277 }
278 
279 static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
280 {
281  for ( const QgsRelation &cur : std::as_const( existingRelations ) )
282  {
283  if ( cur.hasEqualDefinition( relation ) ) return true;
284  }
285  return false;
286 }
287 
288 QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
289 {
290  QList<QgsRelation> result;
291  for ( const QgsVectorLayer *layer : std::as_const( layers ) )
292  {
293  if ( const QgsVectorDataProvider *provider = layer->dataProvider() )
294  {
295  const auto constDiscoverRelations = provider->discoverRelations( layer, layers );
296  for ( const QgsRelation &relation : constDiscoverRelations )
297  {
298  if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
299  {
300  result.append( relation );
301  }
302  }
303  }
304  }
305  return result;
306 }
307 
308 QMap<QString, QgsPolymorphicRelation> QgsRelationManager::polymorphicRelations() const
309 {
310  return mPolymorphicRelations;
311 }
312 
313 QgsPolymorphicRelation QgsRelationManager::polymorphicRelation( const QString &polymorphicRelationId ) const
314 {
315  return mPolymorphicRelations.value( polymorphicRelationId );
316 }
317 
319 {
321  return;
322 
323  mPolymorphicRelations.insert( polymorphicRelation.id(), polymorphicRelation );
324 
325  const QList<QgsRelation> generatedRelations = polymorphicRelation.generateRelations();
326  for ( const QgsRelation &generatedRelation : generatedRelations )
327  addRelation( generatedRelation );
328 }
329 
330 void QgsRelationManager::removePolymorphicRelation( const QString &polymorphicRelationId )
331 {
332  QgsPolymorphicRelation relation = mPolymorphicRelations.take( polymorphicRelationId );
333 
334  const QList<QgsRelation> generatedRelations = relation.generateRelations();
335  for ( const QgsRelation &generatedRelation : generatedRelations )
336  removeRelation( generatedRelation.id() );
337 }
338 
339 void QgsRelationManager::setPolymorphicRelations( const QList<QgsPolymorphicRelation> &relations )
340 {
341  const QList<QgsPolymorphicRelation> oldRelations = polymorphicRelations().values();
342  for ( const QgsPolymorphicRelation &oldRelation : oldRelations )
343  removePolymorphicRelation( oldRelation.id() );
344 
345  for ( const QgsPolymorphicRelation &newRelation : relations )
346  addPolymorphicRelation( newRelation );
347 }
QgsProject::layersRemoved
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the registry.
QgsPolymorphicRelation
A polymorphic relation consists of the same properties like a normal relation except for the referenc...
Definition: qgspolymorphicrelation.h:49
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsRelation::updateRelationStatus
void updateRelationStatus()
Updates the validity status of this relation.
Definition: qgsrelation.cpp:388
QgsRelationManager::clear
void clear()
Remove any relation managed by this class.
Definition: qgsrelationmanager.cpp:113
QgsRelationManager::relation
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Definition: qgsrelationmanager.cpp:95
QgsPolymorphicRelation::createFromXml
static QgsPolymorphicRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
Definition: qgspolymorphicrelation.cpp:52
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRelation::type
RelationType type() const
Returns the type of the relation.
Definition: qgsrelation.cpp:461
QgsRelationManager::removeRelation
void removeRelation(const QString &id)
Remove a relation.
Definition: qgsrelationmanager.cpp:83
QgsRelationManager::changed
void changed()
Emitted when relations are added or removed to the manager.
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:103
QgsRelation::referencingLayer
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:47
QgsProject::writeProject
void writeProject(QDomDocument &)
Emitted when the project is being written.
QgsRelation::id
QString id
Definition: qgsrelation.h:46
QgsRelationManager::relationsByName
QList< QgsRelation > relationsByName(const QString &name) const
Returns a list of relations with matching names.
Definition: qgsrelationmanager.cpp:100
qgsapplication.h
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsRelationManager::setPolymorphicRelations
void setPolymorphicRelations(const QList< QgsPolymorphicRelation > &relations)
Sets the specified polymorphic relations and removes any polymorphic relations currently set.
Definition: qgsrelationmanager.cpp:339
QgsRelationManager::referencedRelations
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Definition: qgsrelationmanager.cpp:157
QgsRelationManager::relations
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
Definition: qgsrelationmanager.cpp:54
QgsRelationManager::setRelations
void setRelations(const QList< QgsRelation > &relations)
Will set the specified relations and remove any relation currently set.
Definition: qgsrelationmanager.cpp:44
QgsRelationManager::relationsLoaded
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
QgsRelation::referencedLayer
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:48
QgsRelationManager::polymorphicRelations
QMap< QString, QgsPolymorphicRelation > polymorphicRelations() const
Returns all the polymorphic relations.
Definition: qgsrelationmanager.cpp:308
QgsRelationManager::QgsRelationManager
QgsRelationManager(QgsProject *project=nullptr)
Constructor for QgsRelationManager.
Definition: qgsrelationmanager.cpp:24
qgsvectordataprovider.h
QgsRelationManager::addPolymorphicRelation
void addPolymorphicRelation(const QgsPolymorphicRelation &polymorphicRelation)
Adds a new polymorphic relation.
Definition: qgsrelationmanager.cpp:318
QgsProject::setDirty
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:576
QgsRelationManager::removePolymorphicRelation
void removePolymorphicRelation(const QString &polymorphicRelationId)
Removes an existing polymorphic relation and it's generated relations.
Definition: qgsrelationmanager.cpp:330
QgsRelationManager::addRelation
void addRelation(const QgsRelation &relation)
Add a relation.
Definition: qgsrelationmanager.cpp:59
qgsrelationmanager.h
QgsRelation::FieldPair
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:88
qgsvectorlayer.h
QgsPolymorphicRelation::id
QString id
Definition: qgspolymorphicrelation.h:53
QgsPolymorphicRelation::referencingLayer
QgsVectorLayer referencingLayer
Definition: qgspolymorphicrelation.h:54
QgsRelationManager::polymorphicRelation
QgsPolymorphicRelation polymorphicRelation(const QString &polymorphicRelationId) const
Returns the list of relations associated with a polymorphic relation.
Definition: qgsrelationmanager.cpp:313
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsRelationManager::discoverRelations
static QList< QgsRelation > discoverRelations(const QList< QgsRelation > &existingRelations, const QList< QgsVectorLayer * > &layers)
Discover all the relations available from the current layers.
Definition: qgsrelationmanager.cpp:288
QgsRelationManager::referencingRelations
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....
Definition: qgsrelationmanager.cpp:119
QgsRelation::createFromXml
static QgsRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
Definition: qgsrelation.cpp:53
QgsRelationManager::updateRelationsStatus
void updateRelationsStatus()
Updates relations status.
Definition: qgsrelationmanager.cpp:74
QgsPolymorphicRelation::generateRelations
QList< QgsRelation > generateRelations() const
Returns a list of generated relations, based on the currently set referencedLayerIds()
Definition: qgspolymorphicrelation.cpp:378
QgsRelation
Definition: qgsrelation.h:42
QgsVectorDataProvider
This is the base class for vector data providers.
Definition: qgsvectordataprovider.h:58
QgsProject::readProjectWithContext
void readProjectWithContext(const QDomDocument &, QgsReadWriteContext &context)
Emitted when a project is being read.
QgsRelationContext
Context for relations. Used to resolve layers from projects.
Definition: qgsrelationcontext.h:31
qgslogger.h
QgsRelation::writeXml
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
Definition: qgsrelation.cpp:117
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QgsRelationManager::context
QgsRelationContext context() const
Gets the relation context.
Definition: qgsrelationmanager.cpp:39
qgsproject.h
QgsRelation::Generated
@ Generated
A generated relation is a child of a polymorphic relation.
Definition: qgsrelation.h:62