QGIS API Documentation  2.2.0-Valmiera
 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 {
54  //set first vector layer from layer registry as default one
55  QMap<QString, QgsMapLayer*> layerMap = QgsMapLayerRegistry::instance()->mapLayers();
56  QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();
57  for ( ; mapIt != layerMap.constEnd(); ++mapIt )
58  {
59  QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( mapIt.value() );
60  if ( vl )
61  {
62  mVectorLayer = vl;
63  break;
64  }
65  }
66  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
67 }
68 
70 {
71 }
72 
73 void QgsComposerAttributeTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
74 {
76  {
77  return;
78  }
79  QgsComposerTable::paint( painter, itemStyle, pWidget );
80 }
81 
83 {
84  mFieldAliasMap.clear();
85  if ( mVectorLayer )
86  {
87  const QgsFields& fields = mVectorLayer->pendingFields();
88  for ( int idx = 0; idx < fields.count(); ++idx )
89  {
90  QString currentAlias = mVectorLayer->attributeAlias( idx );
91  if ( !currentAlias.isEmpty() )
92  {
93  mFieldAliasMap.insert( idx, currentAlias );
94  }
95  }
96  }
97 }
98 
100 {
101  if ( vl != mVectorLayer )
102  {
103  mDisplayAttributes.clear();
104  mVectorLayer = vl;
106  }
107 }
108 
110 {
111  if ( mComposerMap )
112  {
113  QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
114  }
115  mComposerMap = map;
116  if ( mComposerMap )
117  {
118  QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
119  }
120 }
121 
122 bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &attributeMaps )
123 {
124  if ( !mVectorLayer )
125  {
126  return false;
127  }
128 
129  attributeMaps.clear();
130 
131  QgsRectangle selectionRect;
133  {
134  selectionRect = *mComposerMap->currentMapExtent();
137  {
138  //transform back to layer CRS
140  try
141  {
142  selectionRect = coordTransform.transformBoundingBox( selectionRect, QgsCoordinateTransform::ReverseTransform );
143  }
144  catch ( QgsCsException &cse )
145  {
146  Q_UNUSED( cse );
147  return false;
148  }
149  }
150  }
151 
152  QgsFeatureRequest req;
153  if ( !selectionRect.isEmpty() )
154  req.setFilterRect( selectionRect );
155 
157 
158  if ( !mDisplayAttributes.isEmpty() )
160 
161  QgsFeature f;
162  int counter = 0;
164 
165  while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
166  {
167  attributeMaps.push_back( QgsAttributeMap() );
168 
169  for ( int i = 0; i < f.attributes().size(); i++ )
170  {
171  if ( !mDisplayAttributes.isEmpty() && !mDisplayAttributes.contains( i ) )
172  continue;
173 
174  attributeMaps.last().insert( i, f.attributes()[i] );
175  }
176 
177  ++counter;
178  }
179 
180  //sort the list, starting with the last attribute
182  for ( int i = mSortInformation.size() - 1; i >= 0; --i )
183  {
184  c.setSortColumn( mSortInformation.at( i ).first );
185  c.setAscending( mSortInformation.at( i ).second );
186  qStableSort( attributeMaps.begin(), attributeMaps.end(), c );
187  }
188  return true;
189 }
190 
192 {
193  QMap<int, QString> header;
194  if ( mVectorLayer )
195  {
196  const QgsFields& vectorFields = mVectorLayer->pendingFields();
197  for ( int idx = 0; idx < vectorFields.count(); ++idx )
198  {
199  if ( mDisplayAttributes.size() > 0 && !mDisplayAttributes.contains( idx ) )
200  {
201  continue;
202  }
203  header.insert( idx, attributeDisplayName( idx, vectorFields[idx].name() ) );
204  }
205  }
206  return header;
207 }
208 
209 QString QgsComposerAttributeTable::attributeDisplayName( int attributeIndex, const QString& name ) const
210 {
211  return mFieldAliasMap.value( attributeIndex, name );
212 }
213 
215 {
216  if ( mVectorLayer )
217  {
218  if ( layerId == mVectorLayer->id() )
219  {
220  mVectorLayer = 0;
221  }
222  }
223 }
224 
225 void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
226 {
227  double titleHeight = 2 * mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mHeaderFont );
228  double attributeHeight = mGridStrokeWidth + 2 * mLineTextDistance + fontAscentMillimeters( mContentFont );
229  if (( rectangle.height() - titleHeight ) > 0 )
230  {
231  mMaximumNumberOfFeatures = ( rectangle.height() - titleHeight ) / attributeHeight;
232  }
233  else
234  {
236  }
237  QgsComposerItem::setSceneRect( rectangle );
239 }
240 
241 bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc ) const
242 {
243  QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
244  composerTableElem.setAttribute( "showOnlyVisibleFeatures", mShowOnlyVisibleFeatures );
245  composerTableElem.setAttribute( "maxFeatures", mMaximumNumberOfFeatures );
246 
247  if ( mComposerMap )
248  {
249  composerTableElem.setAttribute( "composerMap", mComposerMap->id() );
250  }
251  else
252  {
253  composerTableElem.setAttribute( "composerMap", -1 );
254  }
255  if ( mVectorLayer )
256  {
257  composerTableElem.setAttribute( "vectorLayer", mVectorLayer->id() );
258  }
259 
260  //display attributes
261  QDomElement displayAttributesElem = doc.createElement( "displayAttributes" );
262  QSet<int>::const_iterator attIt = mDisplayAttributes.constBegin();
263  for ( ; attIt != mDisplayAttributes.constEnd(); ++attIt )
264  {
265  QDomElement attributeIndexElem = doc.createElement( "attributeEntry" );
266  attributeIndexElem.setAttribute( "index", *attIt );
267  displayAttributesElem.appendChild( attributeIndexElem );
268  }
269  composerTableElem.appendChild( displayAttributesElem );
270 
271  //alias map
272  QDomElement aliasMapElem = doc.createElement( "attributeAliasMap" );
273  QMap<int, QString>::const_iterator aliasIt = mFieldAliasMap.constBegin();
274  for ( ; aliasIt != mFieldAliasMap.constEnd(); ++aliasIt )
275  {
276  QDomElement mapEntryElem = doc.createElement( "aliasEntry" );
277  mapEntryElem.setAttribute( "key", aliasIt.key() );
278  mapEntryElem.setAttribute( "value", aliasIt.value() );
279  aliasMapElem.appendChild( mapEntryElem );
280  }
281  composerTableElem.appendChild( aliasMapElem );
282 
283  //sort info
284  QDomElement sortColumnsElem = doc.createElement( "sortColumns" );
285  QList< QPair<int, bool> >::const_iterator sortIt = mSortInformation.constBegin();
286  for ( ; sortIt != mSortInformation.constEnd(); ++sortIt )
287  {
288  QDomElement columnElem = doc.createElement( "column" );
289  columnElem.setAttribute( "index", QString::number( sortIt->first ) );
290  columnElem.setAttribute( "ascending", sortIt->second == true ? "true" : "false" );
291  sortColumnsElem.appendChild( columnElem );
292  }
293  composerTableElem.appendChild( sortColumnsElem );
294  elem.appendChild( composerTableElem );
295  bool ok = tableWriteXML( composerTableElem, doc );
296  return ok;
297 }
298 
299 bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDomDocument& doc )
300 {
301  if ( itemElem.isNull() )
302  {
303  return false;
304  }
305 
306  mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
307 
308  //composer map
309  int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
310  if ( composerMapId == -1 )
311  {
312  mComposerMap = 0;
313  }
314 
315  if ( composition() )
316  {
317  mComposerMap = composition()->getComposerMapById( composerMapId );
318  }
319  else
320  {
321  mComposerMap = 0;
322  }
323 
324  //vector layer
325  QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
326  if ( layerId == "not_existing" )
327  {
328  mVectorLayer = 0;
329  }
330  else
331  {
333  if ( ml )
334  {
335  mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
336  }
337  }
338 
339  //restore display attribute map
340  mDisplayAttributes.clear();
341  QDomNodeList displayAttributeList = itemElem.elementsByTagName( "displayAttributes" );
342  if ( displayAttributeList.size() > 0 )
343  {
344  QDomElement displayAttributesElem = displayAttributeList.at( 0 ).toElement();
345  QDomNodeList attributeEntryList = displayAttributesElem.elementsByTagName( "attributeEntry" );
346  for ( int i = 0; i < attributeEntryList.size(); ++i )
347  {
348  QDomElement attributeEntryElem = attributeEntryList.at( i ).toElement();
349  int index = attributeEntryElem.attribute( "index", "-1" ).toInt();
350  if ( index != -1 )
351  {
352  mDisplayAttributes.insert( index );
353  }
354  }
355  }
356 
357  //restore alias map
358  mFieldAliasMap.clear();
359  QDomNodeList aliasMapNodeList = itemElem.elementsByTagName( "attributeAliasMap" );
360  if ( aliasMapNodeList.size() > 0 )
361  {
362  QDomElement attributeAliasMapElem = aliasMapNodeList.at( 0 ).toElement();
363  QDomNodeList aliasMepEntryList = attributeAliasMapElem.elementsByTagName( "aliasEntry" );
364  for ( int i = 0; i < aliasMepEntryList.size(); ++i )
365  {
366  QDomElement aliasEntryElem = aliasMepEntryList.at( i ).toElement();
367  int key = aliasEntryElem.attribute( "key", "-1" ).toInt();
368  QString value = aliasEntryElem.attribute( "value", "" );
369  mFieldAliasMap.insert( key, value );
370  }
371  }
372 
373  //restore sort columns
374  mSortInformation.clear();
375  QDomElement sortColumnsElem = itemElem.firstChildElement( "sortColumns" );
376  if ( !sortColumnsElem.isNull() )
377  {
378  QDomNodeList columns = sortColumnsElem.elementsByTagName( "column" );
379  for ( int i = 0; i < columns.size(); ++i )
380  {
381  QDomElement columnElem = columns.at( i ).toElement();
382  int attribute = columnElem.attribute( "index" ).toInt();
383  bool ascending = columnElem.attribute( "ascending" ) == "true" ? true : false;
384  mSortInformation.push_back( qMakePair( attribute, ascending ) );
385  }
386  }
387  bool success = tableReadXML( itemElem, doc );
388 
389  //must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
390  mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();
391 
392  emit itemChanged();
393  return success;
394 }
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:45
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.
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.
Container of fields for a vector layer.
Definition: qgsfield.h:162
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.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
const QgsMapRenderer * mapRenderer() const
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:94
int count() const
Return number of items.
Definition: qgsfield.h:196
QgsComposerAttributeTable(QgsComposition *composition)
QString attributeAlias(int attributeIndex) const
Returns the alias of an attribute name or an empty string if there is no alias.
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...