QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  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, QgsReadWriteContext &context )
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 ), context ) );
169  }
170  }
171  else
172  {
173  QgsDebugMsg( QStringLiteral( "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( QStringLiteral( "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 }
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:441
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
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the registry.
virtual QList< QgsRelation > discoverRelations(const QgsVectorLayer *self, const QList< QgsVectorLayer * > &layers) const
Discover the available relations with the given layers.
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
QList< QgsRelation > relationsByName(const QString &name) const
Returns a list of relations with matching names.
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 writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
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.
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
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
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
QString referencingField() const
Gets the name of the referencing (child) field.
Definition: qgsrelation.h:85
static QList< QgsRelation > discoverRelations(const QList< QgsRelation > &existingRelations, const QList< QgsVectorLayer * > &layers)
Discover all the relations available from the current layers.
Reads and writes project states.
Definition: qgsproject.h:89
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:47
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:320
void relationsLoaded()
This signal is emitted when the relations were loaded after reading a project.
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.
void writeProject(QDomDocument &)
Emitted when the project is being written.
bool isValid
Definition: qgsrelation.h:49
void changed()
Emitted when relations are added or removed to the manager.
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 removeRelation(const QString &id)
Remove a relation.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider.
QgsRelationManager(QgsProject *project=nullptr)
Constructor for QgsRelationManager.
Represents a vector layer which manages a vector based data sets.
void addRelation(const QgsRelation &relation)
Add a relation.