QGIS API Documentation  3.2.0-Bonn (bc43194)
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::readProject, 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  if ( !relation.isValid() )
54  return;
55 
56  mRelations.insert( relation.id(), relation );
57 
58  if ( mProject )
59  mProject->setDirty( true );
60  emit changed();
61 }
62 
63 void QgsRelationManager::removeRelation( const QString &id )
64 {
65  mRelations.remove( id );
66  emit changed();
67 }
68 
70 {
71  mRelations.remove( relation.id() );
72  emit changed();
73 }
74 
75 QgsRelation QgsRelationManager::relation( const QString &id ) const
76 {
77  return mRelations.value( id );
78 }
79 
80 QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const
81 {
82  QList<QgsRelation> relations;
83 
84  Q_FOREACH ( const QgsRelation &rel, mRelations )
85  {
86  if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 )
87  relations << rel;
88  }
89 
90  return relations;
91 }
92 
94 {
95  mRelations.clear();
96  emit changed();
97 }
98 
99 QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const
100 {
101  if ( !layer )
102  {
103  return mRelations.values();
104  }
105 
106  QList<QgsRelation> relations;
107 
108  Q_FOREACH ( const QgsRelation &rel, mRelations )
109  {
110  if ( rel.referencingLayer() == layer )
111  {
112  if ( fieldIdx != -2 )
113  {
114  bool containsField = false;
115  Q_FOREACH ( const QgsRelation::FieldPair &fp, rel.fieldPairs() )
116  {
117  if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) )
118  {
119  containsField = true;
120  break;
121  }
122  }
123 
124  if ( !containsField )
125  {
126  continue;
127  }
128  }
129  relations.append( rel );
130  }
131  }
132 
133  return relations;
134 }
135 
136 QList<QgsRelation> QgsRelationManager::referencedRelations( QgsVectorLayer *layer ) const
137 {
138  if ( !layer )
139  {
140  return mRelations.values();
141  }
142 
143  QList<QgsRelation> relations;
144 
145  Q_FOREACH ( const QgsRelation &rel, mRelations )
146  {
147  if ( rel.referencedLayer() == layer )
148  {
149  relations.append( rel );
150  }
151  }
152 
153  return relations;
154 }
155 
156 void QgsRelationManager::readProject( const QDomDocument &doc )
157 {
158  mRelations.clear();
159 
160  QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "relations" ) );
161  if ( nodes.count() )
162  {
163  QDomNode node = nodes.item( 0 );
164  QDomNodeList relationNodes = node.childNodes();
165  int relCount = relationNodes.count();
166  for ( int i = 0; i < relCount; ++i )
167  {
168  addRelation( QgsRelation::createFromXml( relationNodes.at( i ) ) );
169  }
170  }
171  else
172  {
173  QgsDebugMsg( "No relations data present in this document" );
174  }
175 
176  emit relationsLoaded();
177  emit changed();
178 }
179 
180 void QgsRelationManager::writeProject( QDomDocument &doc )
181 {
182  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
183  if ( !nl.count() )
184  {
185  QgsDebugMsg( "Unable to find qgis element in project file" );
186  return;
187  }
188  QDomNode qgisNode = nl.item( 0 ); // there should only be one
189 
190  QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) );
191  qgisNode.appendChild( relationsNode );
192 
193  Q_FOREACH ( const QgsRelation &relation, mRelations )
194  {
195  relation.writeXml( relationsNode, doc );
196  }
197 }
198 
199 void QgsRelationManager::layersRemoved( const QStringList &layers )
200 {
201  bool relationsChanged = false;
202  Q_FOREACH ( const QString &layer, layers )
203  {
204  QMapIterator<QString, QgsRelation> it( mRelations );
205 
206  while ( it.hasNext() )
207  {
208  it.next();
209 
210  if ( it.value().referencedLayerId() == layer
211  || it.value().referencingLayerId() == layer )
212  {
213  mRelations.remove( it.key() );
214  relationsChanged = true;
215  }
216  }
217  }
218  if ( relationsChanged )
219  {
220  emit changed();
221  }
222 }
223 
224 static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation )
225 {
226  Q_FOREACH ( const QgsRelation &cur, existingRelations )
227  {
228  if ( cur.hasEqualDefinition( relation ) ) return true;
229  }
230  return false;
231 }
232 
233 QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers )
234 {
235  QList<QgsRelation> result;
236  Q_FOREACH ( const QgsVectorLayer *layer, layers )
237  {
238  Q_FOREACH ( const QgsRelation &relation, layer->dataProvider()->discoverRelations( layer, layers ) )
239  {
240  if ( !hasRelationWithEqualDefinition( existingRelations, relation ) )
241  {
242  result.append( relation );
243  }
244  }
245  }
246  return result;
247 }
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:299
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:421
QString name
Definition: qgsrelation.h:45
#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:43
QString id
Definition: qgsrelation.h:42
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.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:72
QgsFields fields() const override
Returns the list of fields of this layer.
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.
void readProject(const QDomDocument &)
Emitted when a project is being read.
static QgsRelation createFromXml(const QDomNode &node)
Creates a relation from an XML structure.
Definition: qgsrelation.cpp:24
Reads and writes project states.
Definition: qgsproject.h:85
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:44
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.
bool isValid
Definition: qgsrelation.h:46
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.
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
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.
QString referencingField() const
Gets the name of the referencing (child) field.
Definition: qgsrelation.h:83
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
Definition: qgsrelation.cpp:95
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.