QGIS API Documentation  2.99.0-Master (08c2e66)
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, SIGNAL( readProject( const QDomDocument& ) ), SLOT( readProject( const QDomDocument& ) ) );
29  connect( project, SIGNAL( writeProject( QDomDocument& ) ), SLOT( writeProject( QDomDocument& ) ) );
30  connect( project, SIGNAL( layersRemoved( QStringList ) ), this, SLOT( layersRemoved( QStringList ) ) );
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 }
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:386
QString name
Definition: qgsrelation.h:42
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QgsFields fields() const
Returns the list of fields of this layer.
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:40
QString id
Definition: qgsrelation.h:39
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
Get 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.
Definition: qgsrelation.cpp:93
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
Get access to the relations managed by this class.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:56
Q_INVOKABLE QgsRelation relation(const QString &id) const
Get access to a relation by its id.
QString referencingField() const
Get the name of the referencing (child) field.
Definition: qgsrelation.h:68
static QList< QgsRelation > discoverRelations(const QList< QgsRelation > &existingRelations, const QList< QgsVectorLayer * > &layers)
Discover all the relations available from the current layers.
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:74
static bool hasRelationWithEqualDefinition(const QList< QgsRelation > &existingRelations, const QgsRelation &relation)
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:41
int lookupField(const QString &fieldName) const
Look up field&#39;s index from the field name.
Definition: qgsfields.cpp:289
void relationsLoaded()
This signal is emitted when the relations were loaded after reading a project.
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.
bool isValid
Definition: qgsrelation.h:43
void changed()
Emitted when relations are added or removed to the manager.
QList< 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()
Returns the 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.