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 }