QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::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 : qgis::as_const( layers ) )
292  {
293  const auto constDiscoverRelations = layer->dataProvider()->discoverRelations( layer, layers );
294  for ( const QgsRelation &relation : constDiscoverRelations )
295  {
296  if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
297  {
298  result.append( relation );
299  }
300  }
301  }
302  return result;
303 }
304 
305 QMap<QString, QgsPolymorphicRelation> QgsRelationManager::polymorphicRelations() const
306 {
307  return mPolymorphicRelations;
308 }
309 
310 QgsPolymorphicRelation QgsRelationManager::polymorphicRelation( const QString &polymorphicRelationId ) const
311 {
312  return mPolymorphicRelations.value( polymorphicRelationId );
313 }
314 
316 {
318  return;
319 
320  mPolymorphicRelations.insert( polymorphicRelation.id(), polymorphicRelation );
321 
322  const QList<QgsRelation> generatedRelations = polymorphicRelation.generateRelations();
323  for ( const QgsRelation &generatedRelation : generatedRelations )
324  addRelation( generatedRelation );
325 }
326 
327 void QgsRelationManager::removePolymorphicRelation( const QString &polymorphicRelationId )
328 {
329  QgsPolymorphicRelation relation = mPolymorphicRelations.take( polymorphicRelationId );
330 
331  const QList<QgsRelation> generatedRelations = relation.generateRelations();
332  for ( const QgsRelation &generatedRelation : generatedRelations )
333  removeRelation( generatedRelation.id() );
334 }
335 
336 void QgsRelationManager::setPolymorphicRelations( const QList<QgsPolymorphicRelation> &relations )
337 {
338  const QList<QgsPolymorphicRelation> oldRelations = polymorphicRelations().values();
339  for ( const QgsPolymorphicRelation &oldRelation : oldRelations )
340  removePolymorphicRelation( oldRelation.id() );
341 
342  for ( const QgsPolymorphicRelation &newRelation : relations )
343  addPolymorphicRelation( newRelation );
344 }
345 
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
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:99
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:552
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:89
static QgsRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
Definition: qgsrelation.cpp:53
QgsVectorLayer * referencedLayer
Definition: qgsrelation.h:48
@ Generated
A generated relation is a child of a polymorphic relation.
Definition: qgsrelation.h:62
Q_GADGET QString id
Definition: qgsrelation.h:46
RelationType type() const
Returns the type of the relation.
QgsVectorLayer * referencingLayer
Definition: qgsrelation.h:47
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
void updateRelationStatus()
Updates the validity status of this relation.
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 QgsDebugMsg(str)
Definition: qgslogger.h:38