QGIS API Documentation  2.4.0-Chugiak
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 <QPainter>
21 #include <QSettings>
22 
23 
25  : QgsComposerItem( composition )
26  , mLineTextDistance( 1.0 )
27  , mHeaderHAlignment( FollowColumn )
28  , mShowGrid( true )
29  , mGridStrokeWidth( 0.5 )
30  , mGridColor( QColor( 0, 0, 0 ) )
31 {
32  //get default composer font from settings
33  QSettings settings;
34  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
35  if ( !defaultFontString.isEmpty() )
36  {
37  mHeaderFont.setFamily( defaultFontString );
38  mContentFont.setFamily( defaultFontString );
39  }
40 }
41 
43 {
44  qDeleteAll( mColumns );
45  mColumns.clear();
46 }
47 
49 {
50  mMaxColumnWidthMap.clear();
51  mAttributeMaps.clear();
52 
53  //getFeatureAttributes
55  {
56  return;
57  }
58 
59  //since attributes have changed, we also need to recalculate the column widths
60  //and size of table
62 }
63 
64 void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
65 {
66  Q_UNUSED( itemStyle );
67  Q_UNUSED( pWidget );
68  if ( !painter )
69  {
70  return;
71  }
72 
75  {
76  //exporting composition, so force an attribute refresh
77  //we do this in case vector layer has changed via an external source (eg, another database user)
79  }
80 
81  drawBackground( painter );
82  painter->setPen( Qt::SolidLine );
83 
84  //now draw the text
85  double currentX = mGridStrokeWidth;
86  double currentY;
87 
88  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
89 
90  int col = 0;
91  double cellHeaderHeight = fontAscentMillimeters( mHeaderFont ) + 2 * mLineTextDistance;
92  double cellBodyHeight = fontAscentMillimeters( mContentFont ) + 2 * mLineTextDistance;
93  QRectF cell;
94  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
95  {
96  currentY = mGridStrokeWidth;
97  currentX += mLineTextDistance;
98 
99  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );
100 
101  //calculate alignment of header
102  Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
103  switch ( mHeaderHAlignment )
104  {
105  case FollowColumn:
106  headerAlign = ( *columnIt )->hAlignment();
107  break;
108  case HeaderLeft:
109  headerAlign = Qt::AlignLeft;
110  break;
111  case HeaderCenter:
112  headerAlign = Qt::AlignHCenter;
113  break;
114  case HeaderRight:
115  headerAlign = Qt::AlignRight;
116  break;
117  }
118 
119  drawText( painter, cell, ( *columnIt )->heading(), mHeaderFont, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );
120 
121  currentY += cellHeaderHeight;
122  currentY += mGridStrokeWidth;
123 
124  //draw the attribute values
125  QList<QgsAttributeMap>::const_iterator attIt = mAttributeMaps.begin();
126  for ( ; attIt != mAttributeMaps.end(); ++attIt )
127  {
128  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight );
129 
130  const QgsAttributeMap &currentAttributeMap = *attIt;
131  QString str = currentAttributeMap[ col ].toString();
132  drawText( painter, cell, str, mContentFont, ( *columnIt )->hAlignment(), Qt::AlignVCenter, Qt::TextDontClip );
133 
134  currentY += cellBodyHeight;
135  currentY += mGridStrokeWidth;
136  }
137 
138  currentX += mMaxColumnWidthMap[ col ];
139  currentX += mLineTextDistance;
140  currentX += mGridStrokeWidth;
141  col++;
142  }
143 
144  //and the borders
145  if ( mShowGrid )
146  {
147  QPen gridPen;
148  gridPen.setWidthF( mGridStrokeWidth );
149  gridPen.setColor( mGridColor );
150  gridPen.setJoinStyle( Qt::MiterJoin );
151  painter->setPen( gridPen );
152  drawHorizontalGridLines( painter, mAttributeMaps.size() );
154  }
155 
156  //draw frame and selection boxes if necessary
157  drawFrame( painter );
158  if ( isSelected() )
159  {
160  drawSelectionBoxes( painter );
161  }
162 }
163 
165 {
166  mLineTextDistance = d;
167  //since spacing has changed, we need to recalculate the table size
169 }
170 
171 void QgsComposerTable::setHeaderFont( const QFont& f )
172 {
173  mHeaderFont = f;
174  //since font attributes have changed, we need to recalculate the table size
176 }
177 
179 {
180  mHeaderHAlignment = alignment;
181  repaint();
182 }
183 
184 void QgsComposerTable::setContentFont( const QFont& f )
185 {
186  mContentFont = f;
187  //since font attributes have changed, we need to recalculate the table size
189 }
190 
192 {
193  mShowGrid = show;
194  //since grid spacing has changed, we need to recalculate the table size
196 }
197 
199 {
200  mGridStrokeWidth = w;
201  //since grid spacing has changed, we need to recalculate the table size
203 }
204 
206 {
207  //check how much space each column needs
209  {
210  return;
211  }
212  //adapt item frame to max width / height
214 
215  repaint();
216 }
217 
218 QMap<int, QString> QgsComposerTable::headerLabels() const
219 {
220  QMap<int, QString> headers;
221 
222  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
223  int col = 0;
224  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
225  {
226  headers.insert( col, ( *columnIt )->heading() );
227  col++;
228  }
229  return headers;
230 }
231 
232 void QgsComposerTable::setColumns( QList<QgsComposerTableColumn*> columns )
233 {
234  //remove existing columns
235  qDeleteAll( mColumns );
236  mColumns.clear();
237 
238  mColumns.append( columns );
239 }
240 
241 bool QgsComposerTable::tableWriteXML( QDomElement& elem, QDomDocument & doc ) const
242 {
243  elem.setAttribute( "lineTextDist", QString::number( mLineTextDistance ) );
244  elem.setAttribute( "headerFont", mHeaderFont.toString() );
245  elem.setAttribute( "headerHAlignment", QString::number(( int )mHeaderHAlignment ) );
246  elem.setAttribute( "contentFont", mContentFont.toString() );
247  elem.setAttribute( "gridStrokeWidth", QString::number( mGridStrokeWidth ) );
248  elem.setAttribute( "gridColorRed", mGridColor.red() );
249  elem.setAttribute( "gridColorGreen", mGridColor.green() );
250  elem.setAttribute( "gridColorBlue", mGridColor.blue() );
251  elem.setAttribute( "gridColorAlpha", mGridColor.alpha() );
252  elem.setAttribute( "showGrid", mShowGrid );
253 
254  //columns
255  QDomElement displayColumnsElem = doc.createElement( "displayColumns" );
256  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
257  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
258  {
259  QDomElement columnElem = doc.createElement( "column" );
260  ( *columnIt )->writeXML( columnElem, doc );
261  displayColumnsElem.appendChild( columnElem );
262  }
263  elem.appendChild( displayColumnsElem );
264 
265  return _writeXML( elem, doc );
266 }
267 
268 bool QgsComposerTable::tableReadXML( const QDomElement& itemElem, const QDomDocument& doc )
269 {
270  if ( itemElem.isNull() )
271  {
272  return false;
273  }
274 
275  mHeaderFont.fromString( itemElem.attribute( "headerFont", "" ) );
276  mHeaderHAlignment = QgsComposerTable::HeaderHAlignment( itemElem.attribute( "headerHAlignment", "0" ).toInt() );
277  mContentFont.fromString( itemElem.attribute( "contentFont", "" ) );
278  mLineTextDistance = itemElem.attribute( "lineTextDist", "1.0" ).toDouble();
279  mGridStrokeWidth = itemElem.attribute( "gridStrokeWidth", "0.5" ).toDouble();
280  mShowGrid = itemElem.attribute( "showGrid", "1" ).toInt();
281 
282  //grid color
283  int gridRed = itemElem.attribute( "gridColorRed", "0" ).toInt();
284  int gridGreen = itemElem.attribute( "gridColorGreen", "0" ).toInt();
285  int gridBlue = itemElem.attribute( "gridColorBlue", "0" ).toInt();
286  int gridAlpha = itemElem.attribute( "gridColorAlpha", "255" ).toInt();
287  mGridColor = QColor( gridRed, gridGreen, gridBlue, gridAlpha );
288 
289  //restore column specifications
290  qDeleteAll( mColumns );
291  mColumns.clear();
292  QDomNodeList columnsList = itemElem.elementsByTagName( "displayColumns" );
293  if ( columnsList.size() > 0 )
294  {
295  QDomElement columnsElem = columnsList.at( 0 ).toElement();
296  QDomNodeList columnEntryList = columnsElem.elementsByTagName( "column" );
297  for ( int i = 0; i < columnEntryList.size(); ++i )
298  {
299  QDomElement columnElem = columnEntryList.at( i ).toElement();
301  column->readXML( columnElem );
302  mColumns.append( column );
303  }
304  }
305 
306  //restore general composer item properties
307  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
308  if ( composerItemList.size() > 0 )
309  {
310  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
311  _readXML( composerItemElem, doc );
312  }
313  return true;
314 }
315 
316 bool QgsComposerTable::calculateMaxColumnWidths( QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps ) const
317 {
318  maxWidthMap.clear();
319  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
320 
321  int col = 0;
322  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
323  {
324  maxWidthMap.insert( col, textWidthMillimeters( mHeaderFont, ( *columnIt )->heading() ) );
325  col++;
326  }
327 
328  //go through all the attributes and adapt the max width values
329  QList<QgsAttributeMap>::const_iterator attIt = attributeMaps.constBegin();
330 
331  double currentAttributeTextWidth;
332 
333  for ( ; attIt != attributeMaps.constEnd(); ++attIt )
334  {
335  QgsAttributeMap::const_iterator attIt2 = attIt->constBegin();
336  for ( ; attIt2 != attIt->constEnd(); ++attIt2 )
337  {
338  currentAttributeTextWidth = textWidthMillimeters( mContentFont, attIt2.value().toString() );
339  if ( currentAttributeTextWidth > maxWidthMap[ attIt2.key()] )
340  {
341  maxWidthMap[ attIt2.key()] = currentAttributeTextWidth;
342  }
343  }
344  }
345  return true;
346 }
347 
348 void QgsComposerTable::adaptItemFrame( const QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps )
349 {
350  //calculate height
351  int n = attributeMaps.size();
352  double totalHeight = fontAscentMillimeters( mHeaderFont )
354  + ( n + 1 ) * mLineTextDistance * 2
355  + ( n + 2 ) * mGridStrokeWidth;
356 
357  //adapt frame to total width
358  double totalWidth = 0;
359  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
360  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
361  {
362  totalWidth += maxColWidthIt.value();
363  }
364  totalWidth += ( 2 * maxWidthMap.size() * mLineTextDistance );
365  totalWidth += ( maxWidthMap.size() + 1 ) * mGridStrokeWidth;
366 
367  QgsComposerItem::setSceneRect( QRectF( pos().x(), pos().y(), totalWidth, totalHeight ) );
368 }
369 
370 void QgsComposerTable::drawHorizontalGridLines( QPainter* p, int nAttributes )
371 {
372  //horizontal lines
373  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
374  double currentY = halfGridStrokeWidth;
375  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
376  currentY += mGridStrokeWidth;
377  currentY += ( fontAscentMillimeters( mHeaderFont ) + 2 * mLineTextDistance );
378  for ( int i = 0; i < nAttributes; ++i )
379  {
380  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
381  currentY += mGridStrokeWidth;
382  currentY += ( fontAscentMillimeters( mContentFont ) + 2 * mLineTextDistance );
383  }
384  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
385 }
386 
387 void QgsComposerTable::drawVerticalGridLines( QPainter* p, const QMap<int, double>& maxWidthMap )
388 {
389  //vertical lines
390  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
391  double currentX = halfGridStrokeWidth;
392  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
393  currentX += mGridStrokeWidth;
394  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
395  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
396  {
397  currentX += ( maxColWidthIt.value() + 2 * mLineTextDistance );
398  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
399  currentX += mGridStrokeWidth;
400  }
401 }
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 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.
HeaderHAlignment mHeaderHAlignment
virtual void drawFrame(QPainter *p)
Draw black frame around item.
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.
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...
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.
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
Stores properties of a column in a QgsComposerTable.
virtual ~QgsComposerTable()
QgsComposition * mComposition
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
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.
double fontAscentMillimeters(const QFont &font) const
Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCAL...
void drawVerticalGridLines(QPainter *p, const QMap< int, double > &maxWidthMap)
Draws the vertical grid lines for the table.