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