QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposerattributetable.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerattributetable.cpp
3  -----------------------------
4  begin : April 2010
5  copyright : (C) 2010 by Marco Hugentobler
6  email : marco at hugis dot net
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 #include "qgscomposermap.h"
20 #include "qgsmaplayerregistry.h"
21 #include "qgsvectorlayer.h"
22 
24  : mCurrentSortColumn( 0 ), mAscending( true )
25 {
26 }
27 
28 
30 {
31  QVariant v1 = m1[mCurrentSortColumn];
32  QVariant v2 = m2[mCurrentSortColumn];
33 
34  bool less = false;
35  if ( v1.type() == QVariant::String && v2.type() == QVariant::String )
36  {
37  less = v1.toString() < v2.toString();
38  }
39  else
40  {
41  less = v1.toDouble() < v2.toDouble();
42  }
43  return ( mAscending ? less : !less );
44 }
45 
46 
48  : QgsComposerTable( composition )
49  , mVectorLayer( 0 )
50  , mComposerMap( 0 )
51  , mMaximumNumberOfFeatures( 5 )
52  , mShowOnlyVisibleFeatures( true )
53  , mFilterFeatures( false )
54  , mFeatureFilter( "" )
55 {
56  //set first vector layer from layer registry as default one
57  QMap<QString, QgsMapLayer*> layerMap = QgsMapLayerRegistry::instance()->mapLayers();
58  QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();
59  for ( ; mapIt != layerMap.constEnd(); ++mapIt )
60  {
61  QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( mapIt.value() );
62  if ( vl )
63  {
64  mVectorLayer = vl;
65  break;
66  }
67  }
68  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
69 }
70 
72 {
73 }
74 
75 void QgsComposerAttributeTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
76 {
78  {
79  return;
80  }
81  QgsComposerTable::paint( painter, itemStyle, pWidget );
82 }
83 
85 {
86  mFieldAliasMap.clear();
87  if ( mVectorLayer )
88  {
89  const QgsFields& fields = mVectorLayer->pendingFields();
90  for ( int idx = 0; idx < fields.count(); ++idx )
91  {
92  QString currentAlias = mVectorLayer->attributeAlias( idx );
93  if ( !currentAlias.isEmpty() )
94  {
95  mFieldAliasMap.insert( idx, currentAlias );
96  }
97  }
98  }
99 }
100 
102 {
103  if ( vl != mVectorLayer )
104  {
105  mDisplayAttributes.clear();
106  mVectorLayer = vl;
108  }
109 }
110 
112 {
113  if ( mComposerMap )
114  {
115  QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
116  }
117  mComposerMap = map;
118  if ( mComposerMap )
119  {
120  QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
121  }
122 }
123 
124 bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &attributeMaps )
125 {
126  if ( !mVectorLayer )
127  {
128  return false;
129  }
130 
131  attributeMaps.clear();
132 
133  //prepare filter expression
134  std::auto_ptr<QgsExpression> filterExpression;
135  bool activeFilter = false;
136  if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
137  {
138  filterExpression = std::auto_ptr<QgsExpression>( new QgsExpression( mFeatureFilter ) );
139  if ( !filterExpression->hasParserError() )
140  {
141  activeFilter = true;
142  }
143  }
144 
145  QgsRectangle selectionRect;
147  {
148  selectionRect = *mComposerMap->currentMapExtent();
150  {
151  //transform back to layer CRS
153  try
154  {
155  selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
156  }
157  catch ( QgsCsException &cse )
158  {
159  Q_UNUSED( cse );
160  return false;
161  }
162  }
163  }
164 
165  QgsFeatureRequest req;
166  if ( !selectionRect.isEmpty() )
167  req.setFilterRect( selectionRect );
168 
170 
171  if ( !mDisplayAttributes.isEmpty() )
173 
174  QgsFeature f;
175  int counter = 0;
177 
178  while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
179  {
180  //check feature against filter
181  if ( activeFilter )
182  {
183  QVariant result = filterExpression->evaluate( &f, mVectorLayer->pendingFields() );
184  // skip this feature if the filter evaluation if false
185  if ( !result.toBool() )
186  {
187  continue;
188  }
189  }
190 
191  attributeMaps.push_back( QgsAttributeMap() );
192 
193  for ( int i = 0; i < f.attributes().size(); i++ )
194  {
195  if ( !mDisplayAttributes.isEmpty() && !mDisplayAttributes.contains( i ) )
196  continue;
197 
198  attributeMaps.last().insert( i, f.attributes()[i] );
199  }
200 
201  ++counter;
202  }
203 
204  //sort the list, starting with the last attribute
206  for ( int i = mSortInformation.size() - 1; i >= 0; --i )
207  {
208  c.setSortColumn( mSortInformation.at( i ).first );
209  c.setAscending( mSortInformation.at( i ).second );
210  qStableSort( attributeMaps.begin(), attributeMaps.end(), c );
211  }
212  return true;
213 }
214 
216 {
217  QMap<int, QString> header;
218  if ( mVectorLayer )
219  {
220  const QgsFields& vectorFields = mVectorLayer->pendingFields();
221  for ( int idx = 0; idx < vectorFields.count(); ++idx )
222  {
223  if ( mDisplayAttributes.size() > 0 && !mDisplayAttributes.contains( idx ) )
224  {
225  continue;
226  }
227  header.insert( idx, attributeDisplayName( idx, vectorFields[idx].name() ) );
228  }
229  }
230  return header;
231 }
232 
233 QString QgsComposerAttributeTable::attributeDisplayName( int attributeIndex, const QString& name ) const
234 {
235  return mFieldAliasMap.value( attributeIndex, name );
236 }
237 
239 {
240  if ( mVectorLayer )
241  {
242  if ( layerId == mVectorLayer->id() )
243  {
244  mVectorLayer = 0;
245  }
246  }
247 }
248 
249 void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
250 {
251  double titleHeight = 2 * mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mHeaderFont );
252  double attributeHeight = mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mContentFont );
253  if (( rectangle.height() - titleHeight ) > 0 )
254  {
255  mMaximumNumberOfFeatures = ( rectangle.height() - titleHeight ) / attributeHeight;
256  }
257  else
258  {
260  }
261  QgsComposerItem::setSceneRect( rectangle );
263 }
264 
265 bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc ) const
266 {
267  QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
268  composerTableElem.setAttribute( "showOnlyVisibleFeatures", mShowOnlyVisibleFeatures );
269  composerTableElem.setAttribute( "maxFeatures", mMaximumNumberOfFeatures );
270  composerTableElem.setAttribute( "filterFeatures", mFilterFeatures ? "true" : "false" );
271  composerTableElem.setAttribute( "featureFilter", mFeatureFilter );
272 
273  if ( mComposerMap )
274  {
275  composerTableElem.setAttribute( "composerMap", mComposerMap->id() );
276  }
277  else
278  {
279  composerTableElem.setAttribute( "composerMap", -1 );
280  }
281  if ( mVectorLayer )
282  {
283  composerTableElem.setAttribute( "vectorLayer", mVectorLayer->id() );
284  }
285 
286  //display attributes
287  QDomElement displayAttributesElem = doc.createElement( "displayAttributes" );
288  QSet<int>::const_iterator attIt = mDisplayAttributes.constBegin();
289  for ( ; attIt != mDisplayAttributes.constEnd(); ++attIt )
290  {
291  QDomElement attributeIndexElem = doc.createElement( "attributeEntry" );
292  attributeIndexElem.setAttribute( "index", *attIt );
293  displayAttributesElem.appendChild( attributeIndexElem );
294  }
295  composerTableElem.appendChild( displayAttributesElem );
296 
297  //alias map
298  QDomElement aliasMapElem = doc.createElement( "attributeAliasMap" );
299  QMap<int, QString>::const_iterator aliasIt = mFieldAliasMap.constBegin();
300  for ( ; aliasIt != mFieldAliasMap.constEnd(); ++aliasIt )
301  {
302  QDomElement mapEntryElem = doc.createElement( "aliasEntry" );
303  mapEntryElem.setAttribute( "key", aliasIt.key() );
304  mapEntryElem.setAttribute( "value", aliasIt.value() );
305  aliasMapElem.appendChild( mapEntryElem );
306  }
307  composerTableElem.appendChild( aliasMapElem );
308 
309  //sort info
310  QDomElement sortColumnsElem = doc.createElement( "sortColumns" );
311  QList< QPair<int, bool> >::const_iterator sortIt = mSortInformation.constBegin();
312  for ( ; sortIt != mSortInformation.constEnd(); ++sortIt )
313  {
314  QDomElement columnElem = doc.createElement( "column" );
315  columnElem.setAttribute( "index", QString::number( sortIt->first ) );
316  columnElem.setAttribute( "ascending", sortIt->second == true ? "true" : "false" );
317  sortColumnsElem.appendChild( columnElem );
318  }
319  composerTableElem.appendChild( sortColumnsElem );
320  elem.appendChild( composerTableElem );
321  bool ok = tableWriteXML( composerTableElem, doc );
322  return ok;
323 }
324 
325 bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDomDocument& doc )
326 {
327  if ( itemElem.isNull() )
328  {
329  return false;
330  }
331 
332  mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
333  mFilterFeatures = itemElem.attribute( "filterFeatures", "false" ) == "true" ? true : false;
334  mFeatureFilter = itemElem.attribute( "featureFilter", "" );
335 
336  //composer map
337  int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
338  if ( composerMapId == -1 )
339  {
340  mComposerMap = 0;
341  }
342 
343  if ( composition() )
344  {
345  mComposerMap = composition()->getComposerMapById( composerMapId );
346  }
347  else
348  {
349  mComposerMap = 0;
350  }
351 
352  //vector layer
353  QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
354  if ( layerId == "not_existing" )
355  {
356  mVectorLayer = 0;
357  }
358  else
359  {
361  if ( ml )
362  {
363  mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
364  }
365  }
366 
367  //restore display attribute map
368  mDisplayAttributes.clear();
369  QDomNodeList displayAttributeList = itemElem.elementsByTagName( "displayAttributes" );
370  if ( displayAttributeList.size() > 0 )
371  {
372  QDomElement displayAttributesElem = displayAttributeList.at( 0 ).toElement();
373  QDomNodeList attributeEntryList = displayAttributesElem.elementsByTagName( "attributeEntry" );
374  for ( int i = 0; i < attributeEntryList.size(); ++i )
375  {
376  QDomElement attributeEntryElem = attributeEntryList.at( i ).toElement();
377  int index = attributeEntryElem.attribute( "index", "-1" ).toInt();
378  if ( index != -1 )
379  {
380  mDisplayAttributes.insert( index );
381  }
382  }
383  }
384 
385  //restore alias map
386  mFieldAliasMap.clear();
387  QDomNodeList aliasMapNodeList = itemElem.elementsByTagName( "attributeAliasMap" );
388  if ( aliasMapNodeList.size() > 0 )
389  {
390  QDomElement attributeAliasMapElem = aliasMapNodeList.at( 0 ).toElement();
391  QDomNodeList aliasMepEntryList = attributeAliasMapElem.elementsByTagName( "aliasEntry" );
392  for ( int i = 0; i < aliasMepEntryList.size(); ++i )
393  {
394  QDomElement aliasEntryElem = aliasMepEntryList.at( i ).toElement();
395  int key = aliasEntryElem.attribute( "key", "-1" ).toInt();
396  QString value = aliasEntryElem.attribute( "value", "" );
397  mFieldAliasMap.insert( key, value );
398  }
399  }
400 
401  //restore sort columns
402  mSortInformation.clear();
403  QDomElement sortColumnsElem = itemElem.firstChildElement( "sortColumns" );
404  if ( !sortColumnsElem.isNull() )
405  {
406  QDomNodeList columns = sortColumnsElem.elementsByTagName( "column" );
407  for ( int i = 0; i < columns.size(); ++i )
408  {
409  QDomElement columnElem = columns.at( i ).toElement();
410  int attribute = columnElem.attribute( "index" ).toInt();
411  bool ascending = columnElem.attribute( "ascending" ) == "true" ? true : false;
412  mSortInformation.push_back( qMakePair( attribute, ascending ) );
413  }
414  }
415  bool success = tableReadXML( itemElem, doc );
416 
417  //must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
418  mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();
419 
420  emit itemChanged();
421  return success;
422 }
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
Wrapper for iterator of features from vector data provider or vector layer.
void setVectorLayer(QgsVectorLayer *vl)
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:46
QMap< int, QString > mFieldAliasMap
Map of attribute name aliases.
bool isEmpty() const
test if rectangle is empty
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:98
Use exact geometry intersection (slower) instead of bounding boxes.
bool getFeatureAttributes(QList< QgsAttributeMap > &attributeMaps)
Retrieves feature attributes.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
void setComposerMap(const QgsComposerMap *map)
void maximumNumberOfFeaturesChanged(int n)
This signal is emitted if the maximum number of feature changes (interactively)
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom element
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
Container of fields for a vector layer.
Definition: qgsfield.h:164
void initializeAliasMap()
Inserts aliases from vector layer as starting configuration to the alias map.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:114
bool operator()(const QgsAttributeMap &m1, const QgsAttributeMap &m2)
QSet< int > mDisplayAttributes
List of attribute indices to display (or all attributes if list is empty)
const QgsComposerMap * mComposerMap
Associated composer map (used to display the visible features)
A class to display feature attributes in the print composer.
QMap< int, QString > getHeaderLabels() const
bool isDrawing() const
True if a draw is already in progress.
void itemChanged()
Used e.g.
QgsVectorLayer * mVectorLayer
Associated vector layer.
QList< QPair< int, bool > > mSortInformation
Contains information about sort attribute index / ascending (true/false).
void setSceneRect(const QRectF &rectangle)
Adapts mMaximumNumberOfFeatures depending on the rectangle height.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
bool tableWriteXML(QDomElement &itemElem, QDomDocument &doc) const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
const QgsAttributes & attributes() const
Definition: qgsfeature.h:143
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:92
int count() const
Return number of items.
Definition: qgsfield.h:198
QgsComposerAttributeTable(QgsComposition *composition)
QString attributeAlias(int attributeIndex) const
Returns the alias of an attribute name or an empty string if there is no alias.
QgsComposition * mComposition
Graphics scene for map printing.
Object representing map window.
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
int id() const
Get identification number.
void removeLayer(QString layerId)
Checks if this vector layer will be removed (and sets mVectorLayer to 0 if yes)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
int mMaximumNumberOfFeatures
Maximum number of features that is displayed.
bool tableReadXML(const QDomElement &itemElem, const QDomDocument &doc)
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
const QgsComposition * composition() const
const QMap< QString, QgsMapLayer * > & mapLayers()
Retrieve the mapLayers collection (mainly intended for use by projection)
Class for doing transforms between two map coordinate systems.
double mLineTextDistance
Distance between table lines and text.
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
Custom exception class for Coordinate Reference System related exceptions.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
bool nextFeature(QgsFeature &f)
bool mShowOnlyVisibleFeatures
Shows only the features that are visible in the associated composer map (true by default) ...
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QString attributeDisplayName(int attributeIndex, const QString &name) const
Returns the attribute name to display in the item (attribute name or an alias if present) ...
Represents a vector layer which manages a vector based data sets.
const QgsComposerMap * getComposerMapById(int id) const
Returns the composer map with specified id.
QgsFeatureRequest & setFlags(Flags flags)
Set flags that affect how features will be fetched.
Helper class for sorting, takes into account sorting column and ascending / descending.
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
double fontAscentMillimeters(const QFont &font) const
Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCAL...