QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 ( mProject )
29  {
30  connect( project, &QgsProject::readProjectWithContext, this, &QgsRelationManager::readProject );
31  connect( project, &QgsProject::writeProject, this, &QgsRelationManager::writeProject );
32  connect( project, &QgsProject::layersRemoved, this, &QgsRelationManager::layersRemoved );
33  }
34 }
35 
36 void QgsRelationManager::setRelations( const QList<QgsRelation> &relations )
37 {
38  mRelations.clear();
39  const auto constRelations = relations;
40  for ( const QgsRelation &rel : constRelations )
41  {
42  addRelation( rel );
43  }
44  emit changed();
45 }
46 
47 QMap<QString, QgsRelation> QgsRelationManager::relations() const
48 {
49  return mRelations;
50 }
51 
53 {
54  // Do not add relations to layers that do not exist
55  if ( !( relation.referencingLayer() && relation.referencedLayer() ) )
56  return;
57 
58  mRelations.insert( relation.id(), relation );
59 
60  if ( mProject )
61  mProject->setDirty( true );
62  emit changed();
63 }
64 
65 
67 {
68  for ( auto relation : mRelations )
69  {
71  }
72 }
73 
74 
75 void QgsRelationManager::removeRelation( const QString &id )
76 {
77  mRelations.remove( id );
78  emit changed();
79 }
80 
82 {
83  mRelations.remove( relation.id() );
84  emit changed();
85 }
86 
87 QgsRelation QgsRelationManager::relation( const QString &id ) const
88 {
89  return mRelations.value( id );
90 }
91 
92 QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
93 {
94  QList<QgsRelation> relations;
95 
96  const auto constMRelations = mRelations;
97  for ( const QgsRelation &rel : constMRelations )
98  {
99  if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
100  relations << rel;
101  }
102 
103  return relations;
104 }
105 
107 {
108  mRelations.clear();
109  emit changed();
110 }
111 
112 QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
113 {
114  if ( !layer )
115  {
116  return mRelations.values();
117  }
118 
119  QList<QgsRelation> relations;
120 
121  const auto constMRelations = mRelations;
122  for ( const QgsRelation &rel : constMRelations )
123  {
124  if ( rel.referencingLayer() == layer )
125  {
126  if ( fieldIdx != -2 )
127  {
128  bool containsField = false;
129  const auto constFieldPairs = rel.fieldPairs();
130  for ( const QgsRelation::FieldPair &fp : constFieldPairs )
131  {
132  if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
133  {
134  containsField = true;
135  break;
136  }
137  }
138 
139  if ( !containsField )
140  {
141  continue;
142  }
143  }
144  relations.append( rel );
145  }
146  }
147 
148  return relations;
149 }
150 
151 QList<QgsRelation> QgsRelationManager::referencedRelations( QgsVectorLayer *layer ) const
152 {
153  if ( !layer )
154  {
155  return mRelations.values();
156  }
157 
158  QList<QgsRelation> relations;
159 
160  const auto constMRelations = mRelations;
161  for ( const QgsRelation &rel : constMRelations )
162  {
163  if ( rel.referencedLayer() == layer )
164  {
165  relations.append( rel );
166  }
167  }
168 
169  return relations;
170 }
171 
172 void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context )
173 {
174  mRelations.clear();
175 
176  QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "relations" ) );
177  if ( nodes.count() )
178  {
179  QDomNode node = nodes.item( 0 );
180  QDomNodeList relationNodes = node.childNodes();
181  int relCount = relationNodes.count();
182  for ( int i = 0; i < relCount; ++i )
183  {
184  addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context ) );
185  }
186  }
187  else
188  {
189  QgsDebugMsg( QStringLiteral( "No relations data present in this document" ) );
190  }
191 
192  emit relationsLoaded();
193  emit changed();
194 }
195 
196 void QgsRelationManager::writeProject( QDomDocument &doc )
197 {
198  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
199  if ( !nl.count() )
200  {
201  QgsDebugMsg( QStringLiteral( "Unable to find qgis element in project file" ) );
202  return;
203  }
204  QDomNode qgisNode = nl.item( 0 ); // there should only be one
205 
206  QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) );
207  qgisNode.appendChild( relationsNode );
208 
209  const auto constMRelations = mRelations;
210  for ( const QgsRelation &relation : constMRelations )
211  {
212  relation.writeXml( relationsNode, doc );
213  }
214 }
215 
216 void QgsRelationManager::layersRemoved( const QStringList &layers )
217 {
218  bool relationsChanged = false;
219  const auto constLayers = layers;
220  for ( const QString &layer : constLayers )
221  {
222  QMapIterator<QString, QgsRelation> it( mRelations );
223 
224  while ( it.hasNext() )
225  {
226  it.next();
227 
228  if ( it.value().referencedLayerId() == layer
229  || it.value().referencingLayerId() == layer )
230  {
231  mRelations.remove( it.key() );
232  relationsChanged = true;
233  }
234  }
235  }
236  if ( relationsChanged )
237  {
238  emit changed();
239  }
240 }
241 
242 static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
243 {
244  const auto constExistingRelations = existingRelations;
245  for ( const QgsRelation &cur : constExistingRelations )
246  {
247  if ( cur.hasEqualDefinition( relation ) ) return true;
248  }
249  return false;
250 }
251 
252 QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
253 {
254  QList<QgsRelation> result;
255  const auto constLayers = layers;
256  for ( const QgsVectorLayer *layer : constLayers )
257  {
258  const auto constDiscoverRelations = layer->dataProvider()->discoverRelations( layer, layers );
259  for ( const QgsRelation &relation : constDiscoverRelations )
260  {
261  if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
262  {
263  result.append( relation );
264  }
265  }
266  }
267  return result;
268 }
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:468
The class is used as a container of context for various read/write operations on other objects...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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.e.
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the registry.
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
static QgsRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context)
Creates a relation from an XML structure.
Definition: qgsrelation.cpp:43
QString id
Definition: qgsrelation.h:45
void updateRelationsStatus()
Updates relations status.
void clear()
Remove any relation managed by this class.
void setRelations(const QList< QgsRelation > &relations)
Will set the specified relations and remove any relation currently set.
void readProjectWithContext(const QDomDocument &, QgsReadWriteContext &context)
Emitted when a project is being read.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:74
QList< QgsRelation > relationsByName(const QString &name) const
Returns a list of relations with matching names.
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
Reads and writes project states.
Definition: qgsproject.h:89
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:47
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
void relationsLoaded()
Emitted when the relations were loaded after reading a project.
void writeProject(QDomDocument &)
Emitted when the project is being written.
void changed()
Emitted when relations are added or removed to the manager.
static QList< QgsRelation > discoverRelations(const QList< QgsRelation > &existingRelations, const QList< QgsVectorLayer *> &layers)
Discover all the relations available from the current layers.
void removeRelation(const QString &id)
Remove a relation.
QgsRelationManager(QgsProject *project=nullptr)
Constructor for QgsRelationManager.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Represents a vector layer which manages a vector based data sets.
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
void updateRelationStatus()
Updates the validity status of this relation.
void addRelation(const QgsRelation &relation)
Add a relation.