QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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.
field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfield.h:169
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:210
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:161
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:217
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:195
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:31
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:220
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:215
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
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.