QGIS API Documentation  3.6.0-Noosa (5873452)
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  Q_FOREACH ( const QgsRelation &rel, relations )
40  {
41  addRelation( rel );
42  }
43  emit changed();
44 }
45 
46 QMap<QString, QgsRelation> QgsRelationManager::relations() const
47 {
48  return mRelations;
49 }
50 
52 {
53  // Do not add relations to layers that do not exist
54  if ( !( relation.referencingLayer() && relation.referencedLayer() ) )
55  return;
56 
57  mRelations.insert( relation.id(), relation );
58 
59  if ( mProject )
60  mProject->setDirty( true );
61  emit changed();
62 }
63 
64 
66 {
67  for ( auto relation : mRelations )
68  {
70  }
71 }
72 
73 
74 void QgsRelationManager::removeRelation( const QString &id )
75 {
76  mRelations.remove( id );
77  emit changed();
78 }
79 
81 {
82  mRelations.remove( relation.id() );
83  emit changed();
84 }
85 
86 QgsRelation QgsRelationManager::relation( const QString &id ) const
87 {
88  return mRelations.value( id );
89 }
90 
91 QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
92 {
93  QList<QgsRelation> relations;
94 
95  Q_FOREACH ( const QgsRelation &rel, mRelations )
96  {
97  if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
98  relations << rel;
99  }
100 
101  return relations;
102 }
103 
105 {
106  mRelations.clear();
107  emit changed();
108 }
109 
110 QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
111 {
112  if ( !layer )
113  {
114  return mRelations.values();
115  }
116 
117  QList<QgsRelation> relations;
118 
119  Q_FOREACH ( const QgsRelation &rel, mRelations )
120  {
121  if ( rel.referencingLayer() == layer )
122  {
123  if ( fieldIdx != -2 )
124  {
125  bool containsField = false;
126  Q_FOREACH ( const QgsRelation::FieldPair &fp, rel.fieldPairs() )
127  {
128  if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
129  {
130  containsField = true;
131  break;
132  }
133  }
134 
135  if ( !containsField )
136  {
137  continue;
138  }
139  }
140  relations.append( rel );
141  }
142  }
143 
144  return relations;
145 }
146 
147 QList<QgsRelation> QgsRelationManager::referencedRelations( QgsVectorLayer *layer ) const
148 {
149  if ( !layer )
150  {
151  return mRelations.values();
152  }
153 
154  QList<QgsRelation> relations;
155 
156  Q_FOREACH ( const QgsRelation &rel, mRelations )
157  {
158  if ( rel.referencedLayer() == layer )
159  {
160  relations.append( rel );
161  }
162  }
163 
164  return relations;
165 }
166 
167 void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context )
168 {
169  mRelations.clear();
170 
171  QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "relations" ) );
172  if ( nodes.count() )
173  {
174  QDomNode node = nodes.item( 0 );
175  QDomNodeList relationNodes = node.childNodes();
176  int relCount = relationNodes.count();
177  for ( int i = 0; i < relCount; ++i )
178  {
179  addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context ) );
180  }
181  }
182  else
183  {
184  QgsDebugMsg( QStringLiteral( "No relations data present in this document" ) );
185  }
186 
187  emit relationsLoaded();
188  emit changed();
189 }
190 
191 void QgsRelationManager::writeProject( QDomDocument &doc )
192 {
193  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
194  if ( !nl.count() )
195  {
196  QgsDebugMsg( QStringLiteral( "Unable to find qgis element in project file" ) );
197  return;
198  }
199  QDomNode qgisNode = nl.item( 0 ); // there should only be one
200 
201  QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) );
202  qgisNode.appendChild( relationsNode );
203 
204  Q_FOREACH ( const QgsRelation &relation, mRelations )
205  {
206  relation.writeXml( relationsNode, doc );
207  }
208 }
209 
210 void QgsRelationManager::layersRemoved( const QStringList &layers )
211 {
212  bool relationsChanged = false;
213  Q_FOREACH ( const QString &layer, layers )
214  {
215  QMapIterator<QString, QgsRelation> it( mRelations );
216 
217  while ( it.hasNext() )
218  {
219  it.next();
220 
221  if ( it.value().referencedLayerId() == layer
222  || it.value().referencingLayerId() == layer )
223  {
224  mRelations.remove( it.key() );
225  relationsChanged = true;
226  }
227  }
228  }
229  if ( relationsChanged )
230  {
231  emit changed();
232  }
233 }
234 
235 static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
236 {
237  Q_FOREACH ( const QgsRelation &cur, existingRelations )
238  {
239  if ( cur.hasEqualDefinition( relation ) ) return true;
240  }
241  return false;
242 }
243 
244 QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
245 {
246  QList<QgsRelation> result;
247  Q_FOREACH ( const QgsVectorLayer *layer, layers )
248  {
249  Q_FOREACH ( const QgsRelation &relation, layer->dataProvider()->discoverRelations( layer, layers ) )
250  {
251  if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
252  {
253  result.append( relation );
254  }
255  }
256  }
257  return result;
258 }
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:460
QString name
Definition: qgsrelation.h:48
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.
bool hasEqualDefinition(const QgsRelation &other) const
Compares the two QgsRelation, ignoring the name and the ID.
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
void relationsLoaded()
This signal is 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.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be null.
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.
QString referencingField() const
Gets the name of the referencing (child) field.
Definition: qgsrelation.h:85
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.
virtual QList< QgsRelation > discoverRelations(const QgsVectorLayer *self, const QList< QgsVectorLayer *> &layers) const
Discover the available relations with the given layers.