QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposertable.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposertable.cpp
3  --------------------
4  begin : January 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 
18 #include "qgscomposertable.h"
19 #include "qgscomposertablecolumn.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgscomposerutils.h"
22 #include <QPainter>
23 #include <QSettings>
24 
25 
27  : QgsComposerItem( composition )
28  , mLineTextDistance( 1.0 )
29  , mHeaderFontColor( Qt::black )
30  , mContentFontColor( Qt::black )
31  , mHeaderHAlignment( FollowColumn )
32  , mShowGrid( true )
33  , mGridStrokeWidth( 0.5 )
34  , mGridColor( QColor( 0, 0, 0 ) )
35 {
36  //get default composer font from settings
37  QSettings settings;
38  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
39  if ( !defaultFontString.isEmpty() )
40  {
41  mHeaderFont.setFamily( defaultFontString );
42  mContentFont.setFamily( defaultFontString );
43  }
44 }
45 
47 {
48  qDeleteAll( mColumns );
49  mColumns.clear();
50 }
51 
53 {
54  mMaxColumnWidthMap.clear();
55  mAttributeMaps.clear();
56 
57  //getFeatureAttributes
59  {
60  return;
61  }
62 
63  //since attributes have changed, we also need to recalculate the column widths
64  //and size of table
66 }
67 
68 void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
69 {
70  Q_UNUSED( itemStyle );
71  Q_UNUSED( pWidget );
72  if ( !painter )
73  {
74  return;
75  }
76 
79  {
80  //exporting composition, so force an attribute refresh
81  //we do this in case vector layer has changed via an external source (eg, another database user)
83  }
84 
85  drawBackground( painter );
86  painter->save();
87  //antialiasing on
88  painter->setRenderHint( QPainter::Antialiasing, true );
89 
90  painter->setPen( Qt::SolidLine );
91 
92  //now draw the text
93  double currentX = mGridStrokeWidth;
94  double currentY;
95 
96  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
97 
98  int col = 0;
99  double cellHeaderHeight = QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mLineTextDistance;
100  double cellBodyHeight = QgsComposerUtils::fontAscentMM( mContentFont ) + 2 * mLineTextDistance;
101  QRectF cell;
102  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
103  {
104  currentY = mGridStrokeWidth;
105  currentX += mLineTextDistance;
106 
107  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );
108 
109  //calculate alignment of header
110  Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
111  switch ( mHeaderHAlignment )
112  {
113  case FollowColumn:
114  headerAlign = ( *columnIt )->hAlignment();
115  break;
116  case HeaderLeft:
117  headerAlign = Qt::AlignLeft;
118  break;
119  case HeaderCenter:
120  headerAlign = Qt::AlignHCenter;
121  break;
122  case HeaderRight:
123  headerAlign = Qt::AlignRight;
124  break;
125  }
126 
127  QgsComposerUtils::drawText( painter, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );
128 
129  currentY += cellHeaderHeight;
130  currentY += mGridStrokeWidth;
131 
132  //draw the attribute values
133  QList<QgsAttributeMap>::const_iterator attIt = mAttributeMaps.begin();
134  for ( ; attIt != mAttributeMaps.end(); ++attIt )
135  {
136  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight );
137 
138  const QgsAttributeMap &currentAttributeMap = *attIt;
139  QString str = currentAttributeMap[ col ].toString();
140  QgsComposerUtils::drawText( painter, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), Qt::AlignVCenter, Qt::TextDontClip );
141 
142  currentY += cellBodyHeight;
143  currentY += mGridStrokeWidth;
144  }
145 
146  currentX += mMaxColumnWidthMap[ col ];
147  currentX += mLineTextDistance;
148  currentX += mGridStrokeWidth;
149  col++;
150  }
151 
152  //and the borders
153  if ( mShowGrid )
154  {
155  QPen gridPen;
156  gridPen.setWidthF( mGridStrokeWidth );
157  gridPen.setColor( mGridColor );
158  gridPen.setJoinStyle( Qt::MiterJoin );
159  painter->setPen( gridPen );
160  drawHorizontalGridLines( painter, mAttributeMaps.size() );
162  }
163 
164  painter->restore();
165 
166  //draw frame and selection boxes if necessary
167  drawFrame( painter );
168  if ( isSelected() )
169  {
170  drawSelectionBoxes( painter );
171  }
172 }
173 
175 {
176  mLineTextDistance = d;
177  //since spacing has changed, we need to recalculate the table size
179 }
180 
181 void QgsComposerTable::setHeaderFont( const QFont& f )
182 {
183  mHeaderFont = f;
184  //since font attributes have changed, we need to recalculate the table size
186 }
187 
188 void QgsComposerTable::setHeaderFontColor( const QColor &color )
189 {
190  mHeaderFontColor = color;
191  repaint();
192 }
193 
195 {
196  mHeaderHAlignment = alignment;
197  repaint();
198 }
199 
200 void QgsComposerTable::setContentFont( const QFont& f )
201 {
202  mContentFont = f;
203  //since font attributes have changed, we need to recalculate the table size
205 }
206 
207 void QgsComposerTable::setContentFontColor( const QColor &color )
208 {
209  mContentFontColor = color;
210  repaint();
211 }
212 
214 {
215  mShowGrid = show;
216  //since grid spacing has changed, we need to recalculate the table size
218 }
219 
221 {
222  mGridStrokeWidth = w;
223  //since grid spacing has changed, we need to recalculate the table size
225 }
226 
228 {
229  //check how much space each column needs
231  {
232  return;
233  }
234  //adapt item frame to max width / height
236 
237  repaint();
238 }
239 
240 QMap<int, QString> QgsComposerTable::headerLabels() const
241 {
242  QMap<int, QString> headers;
243 
244  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
245  int col = 0;
246  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
247  {
248  headers.insert( col, ( *columnIt )->heading() );
249  col++;
250  }
251  return headers;
252 }
253 
254 void QgsComposerTable::setColumns( QList<QgsComposerTableColumn*> columns )
255 {
256  //remove existing columns
257  qDeleteAll( mColumns );
258  mColumns.clear();
259 
260  mColumns.append( columns );
261 }
262 
263 bool QgsComposerTable::tableWriteXML( QDomElement& elem, QDomDocument & doc ) const
264 {
265  elem.setAttribute( "lineTextDist", QString::number( mLineTextDistance ) );
266  elem.setAttribute( "headerFont", mHeaderFont.toString() );
267  elem.setAttribute( "headerFontColor", QgsSymbolLayerV2Utils::encodeColor( mHeaderFontColor ) );
268  elem.setAttribute( "headerHAlignment", QString::number(( int )mHeaderHAlignment ) );
269  elem.setAttribute( "contentFont", mContentFont.toString() );
270  elem.setAttribute( "contentFontColor", QgsSymbolLayerV2Utils::encodeColor( mContentFontColor ) );
271  elem.setAttribute( "gridStrokeWidth", QString::number( mGridStrokeWidth ) );
272  elem.setAttribute( "gridColor", QgsSymbolLayerV2Utils::encodeColor( mGridColor ) );
273  elem.setAttribute( "showGrid", mShowGrid );
274 
275  //columns
276  QDomElement displayColumnsElem = doc.createElement( "displayColumns" );
277  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
278  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
279  {
280  QDomElement columnElem = doc.createElement( "column" );
281  ( *columnIt )->writeXML( columnElem, doc );
282  displayColumnsElem.appendChild( columnElem );
283  }
284  elem.appendChild( displayColumnsElem );
285 
286  return _writeXML( elem, doc );
287 }
288 
289 bool QgsComposerTable::tableReadXML( const QDomElement& itemElem, const QDomDocument& doc )
290 {
291  if ( itemElem.isNull() )
292  {
293  return false;
294  }
295 
296  mHeaderFont.fromString( itemElem.attribute( "headerFont", "" ) );
297  mHeaderFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "headerFontColor", "0,0,0,255" ) );
298  mHeaderHAlignment = QgsComposerTable::HeaderHAlignment( itemElem.attribute( "headerHAlignment", "0" ).toInt() );
299  mContentFont.fromString( itemElem.attribute( "contentFont", "" ) );
300  mContentFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "contentFontColor", "0,0,0,255" ) );
301  mLineTextDistance = itemElem.attribute( "lineTextDist", "1.0" ).toDouble();
302  mGridStrokeWidth = itemElem.attribute( "gridStrokeWidth", "0.5" ).toDouble();
303  mShowGrid = itemElem.attribute( "showGrid", "1" ).toInt();
304 
305  //grid color
306  if ( itemElem.hasAttribute( "gridColor" ) )
307  {
308  mGridColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "gridColor", "0,0,0,255" ) );
309  }
310  else
311  {
312  //old style grid color
313  int gridRed = itemElem.attribute( "gridColorRed", "0" ).toInt();
314  int gridGreen = itemElem.attribute( "gridColorGreen", "0" ).toInt();
315  int gridBlue = itemElem.attribute( "gridColorBlue", "0" ).toInt();
316  int gridAlpha = itemElem.attribute( "gridColorAlpha", "255" ).toInt();
317  mGridColor = QColor( gridRed, gridGreen, gridBlue, gridAlpha );
318  }
319 
320  //restore column specifications
321  qDeleteAll( mColumns );
322  mColumns.clear();
323  QDomNodeList columnsList = itemElem.elementsByTagName( "displayColumns" );
324  if ( columnsList.size() > 0 )
325  {
326  QDomElement columnsElem = columnsList.at( 0 ).toElement();
327  QDomNodeList columnEntryList = columnsElem.elementsByTagName( "column" );
328  for ( int i = 0; i < columnEntryList.size(); ++i )
329  {
330  QDomElement columnElem = columnEntryList.at( i ).toElement();
332  column->readXML( columnElem );
333  mColumns.append( column );
334  }
335  }
336 
337  //restore general composer item properties
338  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
339  if ( composerItemList.size() > 0 )
340  {
341  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
342  _readXML( composerItemElem, doc );
343  }
344  return true;
345 }
346 
347 bool QgsComposerTable::calculateMaxColumnWidths( QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps ) const
348 {
349  maxWidthMap.clear();
350  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
351 
352  int col = 0;
353  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
354  {
355  maxWidthMap.insert( col, QgsComposerUtils::textWidthMM( mHeaderFont, ( *columnIt )->heading() ) );
356  col++;
357  }
358 
359  //go through all the attributes and adapt the max width values
360  QList<QgsAttributeMap>::const_iterator attIt = attributeMaps.constBegin();
361 
362  double currentAttributeTextWidth;
363 
364  for ( ; attIt != attributeMaps.constEnd(); ++attIt )
365  {
366  QgsAttributeMap::const_iterator attIt2 = attIt->constBegin();
367  for ( ; attIt2 != attIt->constEnd(); ++attIt2 )
368  {
369  currentAttributeTextWidth = QgsComposerUtils::textWidthMM( mContentFont, attIt2.value().toString() );
370  if ( currentAttributeTextWidth > maxWidthMap[ attIt2.key()] )
371  {
372  maxWidthMap[ attIt2.key()] = currentAttributeTextWidth;
373  }
374  }
375  }
376  return true;
377 }
378 
379 void QgsComposerTable::adaptItemFrame( const QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps )
380 {
381  //calculate height
382  int n = attributeMaps.size();
383  double totalHeight = QgsComposerUtils::fontAscentMM( mHeaderFont )
385  + ( n + 1 ) * mLineTextDistance * 2
386  + ( n + 2 ) * mGridStrokeWidth;
387 
388  //adapt frame to total width
389  double totalWidth = 0;
390  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
391  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
392  {
393  totalWidth += maxColWidthIt.value();
394  }
395  totalWidth += ( 2 * maxWidthMap.size() * mLineTextDistance );
396  totalWidth += ( maxWidthMap.size() + 1 ) * mGridStrokeWidth;
397 
398  QRectF evaluatedRect = evalItemRect( QRectF( pos().x(), pos().y(), totalWidth, totalHeight ) );
399 
400  //update rect for data defined size and position
401  QgsComposerItem::setSceneRect( evaluatedRect );
402 }
403 
404 void QgsComposerTable::drawHorizontalGridLines( QPainter* p, int nAttributes )
405 {
406  //horizontal lines
407  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
408  double currentY = halfGridStrokeWidth;
409  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
410  currentY += mGridStrokeWidth;
412  for ( int i = 0; i < nAttributes; ++i )
413  {
414  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
415  currentY += mGridStrokeWidth;
417  }
418  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
419 }
420 
421 void QgsComposerTable::drawVerticalGridLines( QPainter* p, const QMap<int, double>& maxWidthMap )
422 {
423  //vertical lines
424  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
425  double currentX = halfGridStrokeWidth;
426  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
427  currentX += mGridStrokeWidth;
428  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
429  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
430  {
431  currentX += ( maxColWidthIt.value() + 2 * mLineTextDistance );
432  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
433  currentX += mGridStrokeWidth;
434  }
435 }
void setLineTextDistance(double d)
Sets the margin distance between cell borders and their contents.
void setContentFont(const QFont &f)
Sets the font used to draw text in table body cells.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsfeature.h:98
void setGridStrokeWidth(double w)
Sets the width for grid lines in the table.
virtual QMap< int, QString > headerLabels() const
Returns the text used in the column headers for the table.
A item that forms part of a map composition.
void setHeaderFontColor(const QColor &color)
Sets the color used to draw header text in the table.
void setColumns(QList< QgsComposerTableColumn * > columns)
Replaces the columns in the table with a specified list of QgsComposerTableColumns.
void setShowGrid(bool show)
Sets whether grid lines should be drawn in the table.
static void drawText(QPainter *painter, const QPointF &pos, const QString &text, const QFont &font, const QColor &color=QColor())
Draws text on a painter at a specific position, taking care of composer specific issues (calculation ...
void setContentFontColor(const QColor &color)
Sets the color used to draw text in table body cells.
static QColor decodeColor(QString str)
HeaderHAlignment mHeaderHAlignment
static double fontAscentMM(const QFont &font)
Calculate font ascent in millimeters, including workarounds for QT font rendering issues...
virtual void drawFrame(QPainter *p)
Draw black frame around item.
static QString encodeColor(QColor color)
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
void drawHorizontalGridLines(QPainter *p, int nAttributes)
Draws the horizontal grid lines for the table.
virtual void drawSelectionBoxes(QPainter *p)
Draw selection boxes around item.
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
bool tableWriteXML(QDomElement &itemElem, QDomDocument &doc) const
Writes common table properties to xml for storage.
Stores properties of a column in a QgsComposerTable.
virtual ~QgsComposerTable()
QRectF evalItemRect(const QRectF &newRect)
Update an item rect to consider data defined position and size of item.
Graphics scene for map printing.
virtual bool getFeatureAttributes(QList< QgsAttributeMap > &attributeMaps)
Fetches the text used for the rows of the table.
void setHeaderHAlignment(const HeaderHAlignment alignment)
Sets the horizontal alignment for table headers.
QList< QgsComposerTableColumn * > mColumns
static double textWidthMM(const QFont &font, const QString &text)
Calculate font width in millimeters for a string, including workarounds for QT font rendering issues...
QgsComposition * mComposition
virtual void refreshAttributes()
Refreshes the attributes shown in the table by querying the vector layer for new data.
QgsComposerTable(QgsComposition *composition)
void setHeaderFont(const QFont &f)
Sets the font used to draw header text in the table.
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
QList< QgsAttributeMap > mAttributeMaps
bool tableReadXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads the table's common properties from xml.
virtual void adjustFrameToSize()
Adapts the size of the frame to match the content.
virtual void drawBackground(QPainter *p)
Draw background.
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...
double mLineTextDistance
Distance between table lines and text.
virtual bool readXML(const QDomElement &columnElem)
Reads the column's properties from xml.
QMap< int, double > mMaxColumnWidthMap
void adaptItemFrame(const QMap< int, double > &maxWidthMap, const QList< QgsAttributeMap > &attributeMaps)
Adapts the size of the item frame to match the table's content.
QgsComposition::PlotStyle plotStyle() const
virtual bool calculateMaxColumnWidths(QMap< int, double > &maxWidthMap, const QList< QgsAttributeMap > &attributeMaps) const
Calculates the maximum width of text shown in columns.
void drawVerticalGridLines(QPainter *p, const QMap< int, double > &maxWidthMap)
Draws the vertical grid lines for the table.