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