QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsvectorlayerjoinbuffer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerjoinbuffer.cpp
3  ----------------------------
4  begin : Feb 09, 2011
5  copyright : (C) 2011 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 
20 #include "qgsmaplayerregistry.h"
21 #include "qgsvectordataprovider.h"
22 
23 #include <QDomElement>
24 
26 {
27 }
28 
30 {
31 }
32 
34 {
35  mVectorJoins.push_back( joinInfo );
36 
37  //cache joined layer to virtual memory if specified by user
38  if ( joinInfo.memoryCache )
39  {
40  cacheJoinLayer( mVectorJoins.last() );
41  }
42 }
43 
44 void QgsVectorLayerJoinBuffer::removeJoin( const QString& joinLayerId )
45 {
46  for ( int i = 0; i < mVectorJoins.size(); ++i )
47  {
48  if ( mVectorJoins.at( i ).joinLayerId == joinLayerId )
49  {
50  mVectorJoins.removeAt( i );
51  }
52  }
53 }
54 
56 {
57  //memory cache not required or already done
58  if ( !joinInfo.memoryCache || joinInfo.cachedAttributes.size() > 0 )
59  {
60  return;
61  }
62 
63  QgsVectorLayer* cacheLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) );
64  if ( cacheLayer )
65  {
66  int joinFieldIndex;
67  if ( joinInfo.joinFieldName.isEmpty() )
68  joinFieldIndex = joinInfo.joinFieldIndex; //for compatibility with 1.x
69  else
70  joinFieldIndex = cacheLayer->pendingFields().indexFromName( joinInfo.joinFieldName );
71 
72  if ( joinFieldIndex < 0 || joinFieldIndex >= cacheLayer->pendingFields().count() )
73  return;
74 
75  joinInfo.cachedAttributes.clear();
76 
78  QgsFeature f;
79  while ( fit.nextFeature( f ) )
80  {
81  const QgsAttributes& attrs = f.attributes();
82  joinInfo.cachedAttributes.insert( attrs[joinFieldIndex].toString(), attrs );
83  }
84  }
85 }
86 
88 {
89  QList< QgsVectorJoinInfo>::const_iterator joinIt = mVectorJoins.constBegin();
90  for ( int joinIdx = 0 ; joinIt != mVectorJoins.constEnd(); ++joinIt, ++joinIdx )
91  {
92  QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinIt->joinLayerId ) );
93  if ( !joinLayer )
94  {
95  continue;
96  }
97 
98  const QgsFields& joinFields = joinLayer->pendingFields();
99  QString joinFieldName;
100  if ( joinIt->joinFieldName.isEmpty() && joinIt->joinFieldIndex >= 0 && joinIt->joinFieldIndex < joinFields.count() )
101  joinFieldName = joinFields.field( joinIt->joinFieldIndex ).name(); //for compatibility with 1.x
102  else
103  joinFieldName = joinIt->joinFieldName;
104 
105  for ( int idx = 0; idx < joinFields.count(); ++idx )
106  {
107  //skip the join field to avoid double field names (fields often have the same name)
108  if ( joinFields[idx].name() != joinFieldName )
109  {
110  QgsField f = joinFields[idx];
111  f.setName( joinLayer->name() + "_" + f.name() );
112  fields.append( f, QgsFields::OriginJoin, idx + ( joinIdx*1000 ) );
113  }
114  }
115  }
116 }
117 
119 {
120  QList< QgsVectorJoinInfo >::iterator joinIt = mVectorJoins.begin();
121  for ( ; joinIt != mVectorJoins.end(); ++joinIt )
122  {
123  cacheJoinLayer( *joinIt );
124  }
125 }
126 
127 
128 void QgsVectorLayerJoinBuffer::writeXml( QDomNode& layer_node, QDomDocument& document ) const
129 {
130  QDomElement vectorJoinsElem = document.createElement( "vectorjoins" );
131  layer_node.appendChild( vectorJoinsElem );
132  QList< QgsVectorJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
133  for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
134  {
135  QDomElement joinElem = document.createElement( "join" );
136 
137  if ( joinIt->targetFieldName.isEmpty() )
138  joinElem.setAttribute( "targetField", joinIt->targetFieldIndex ); //for compatibility with 1.x
139  else
140  joinElem.setAttribute( "targetFieldName", joinIt->targetFieldName );
141 
142  joinElem.setAttribute( "joinLayerId", joinIt->joinLayerId );
143  if ( joinIt->joinFieldName.isEmpty() )
144  joinElem.setAttribute( "joinField", joinIt->joinFieldIndex ); //for compatibility with 1.x
145  else
146  joinElem.setAttribute( "joinFieldName", joinIt->joinFieldName );
147 
148  joinElem.setAttribute( "memoryCache", !joinIt->cachedAttributes.isEmpty() );
149  vectorJoinsElem.appendChild( joinElem );
150  }
151 }
152 
153 void QgsVectorLayerJoinBuffer::readXml( const QDomNode& layer_node )
154 {
155  mVectorJoins.clear();
156  QDomElement vectorJoinsElem = layer_node.firstChildElement( "vectorjoins" );
157  if ( !vectorJoinsElem.isNull() )
158  {
159  QDomNodeList joinList = vectorJoinsElem.elementsByTagName( "join" );
160  for ( int i = 0; i < joinList.size(); ++i )
161  {
162  QDomElement infoElem = joinList.at( i ).toElement();
163  QgsVectorJoinInfo info;
164  info.joinFieldName = infoElem.attribute( "joinFieldName" );
165  info.joinLayerId = infoElem.attribute( "joinLayerId" );
166  info.targetFieldName = infoElem.attribute( "targetFieldName" );
167  info.memoryCache = infoElem.attribute( "memoryCache" ).toInt();
168 
169  info.joinFieldIndex = infoElem.attribute( "joinField" ).toInt(); //for compatibility with 1.x
170  info.targetFieldIndex = infoElem.attribute( "targetField" ).toInt(); //for compatibility with 1.x
171 
172  addJoin( info );
173  }
174  }
175 }
176 
177 const QgsVectorJoinInfo* QgsVectorLayerJoinBuffer::joinForFieldIndex( int index, const QgsFields& fields, int& sourceFieldIndex ) const
178 {
179  if ( fields.fieldOrigin( index ) != QgsFields::OriginJoin )
180  return 0;
181 
182  int originIndex = fields.fieldOriginIndex( index );
183  int sourceJoinIndex = originIndex / 1000;
184  sourceFieldIndex = originIndex % 1000;
185 
186  if ( sourceJoinIndex < 0 || sourceJoinIndex >= mVectorJoins.count() )
187  return 0;
188 
189  return &( mVectorJoins[sourceJoinIndex] );
190 }
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:58
Wrapper for iterator of features from vector data provider or vector layer.
static unsigned index
QString joinFieldName
Join field in the source layer.
QString targetFieldName
Join field in the target layer.
void createJoinCaches()
Calls cacheJoinLayer() for all vector joins.
const QgsField & field(int fieldIdx) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.h:215
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
int joinFieldIndex
Join field index in the source layer.
void readXml(const QDomNode &layer_node)
Reads joins from project file.
Container of fields for a vector layer.
Definition: qgsfield.h:163
bool memoryCache
True if the join is cached in virtual memory.
int targetFieldIndex
Join field index in the target layer.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
const QgsVectorJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
const QString & name() const
Get the display name of the layer.
int fieldOriginIndex(int fieldIdx) const
Get field's origin index (its meaning is specific to each type of origin)
Definition: qgsfield.h:222
This class wraps a request for features to a vector layer (or directly its vector data provider)...
const QgsAttributes & attributes() const
Definition: qgsfeature.h:142
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfield.cpp:140
int count() const
Return number of items.
Definition: qgsfield.h:200
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:33
void removeJoin(const QString &joinLayerId)
Removes a vector layer join.
int indexFromName(const QString &name) const
Look up field's index from name. Returns -1 on error.
Definition: qgsfield.h:227
void setName(const QString &nam)
Set the field name.
Definition: qgsfield.cpp:88
QList< QgsVectorJoinInfo > mVectorJoins
Joined vector layers.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QHash< QString, QgsAttributes > cachedAttributes
Cache for joined attributes to provide fast lookup (size is 0 if no memory caching) ...
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:100
void writeXml(QDomNode &layer_node, QDomDocument &document) const
Saves mVectorJoins to xml under the layer node.
FieldOrigin fieldOrigin(int fieldIdx) const
Get field's origin (value from an enumeration)
Definition: qgsfield.h:220
void cacheJoinLayer(QgsVectorJoinInfo &joinInfo)
Caches attributes of join layer in memory if QgsVectorJoinInfo.memoryCache is true (and the cache is ...
void updateFields(QgsFields &fields)
Updates field map with joined attributes.
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfield.h:171
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
QString joinLayerId
Source layer.
void addJoin(const QgsVectorJoinInfo &joinInfo)
Joins another vector layer to this layer.