QGIS API Documentation  2.4.0-Chugiak
 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 <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( "showGrid", mShowGrid );
252 
253  //columns
254  QDomElement displayColumnsElem = doc.createElement( "displayColumns" );
255  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
256  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
257  {
258  QDomElement columnElem = doc.createElement( "column" );
259  ( *columnIt )->writeXML( columnElem, doc );
260  displayColumnsElem.appendChild( columnElem );
261  }
262  elem.appendChild( displayColumnsElem );
263 
264  return _writeXML( elem, doc );
265 }
266 
267 bool QgsComposerTable::tableReadXML( const QDomElement& itemElem, const QDomDocument& doc )
268 {
269  if ( itemElem.isNull() )
270  {
271  return false;
272  }
273 
274  mHeaderFont.fromString( itemElem.attribute( "headerFont", "" ) );
275  mHeaderHAlignment = QgsComposerTable::HeaderHAlignment( itemElem.attribute( "headerHAlignment", "0" ).toInt() );
276  mContentFont.fromString( itemElem.attribute( "contentFont", "" ) );
277  mLineTextDistance = itemElem.attribute( "lineTextDist", "1.0" ).toDouble();
278  mGridStrokeWidth = itemElem.attribute( "gridStrokeWidth", "0.5" ).toDouble();
279  mShowGrid = itemElem.attribute( "showGrid", "1" ).toInt();
280 
281  //grid color
282  int gridRed = itemElem.attribute( "gridColorRed", "0" ).toInt();
283  int gridGreen = itemElem.attribute( "gridColorGreen", "0" ).toInt();
284  int gridBlue = itemElem.attribute( "gridColorBlue", "0" ).toInt();
285  mGridColor = QColor( gridRed, gridGreen, gridBlue );
286 
287  //restore column specifications
288  qDeleteAll( mColumns );
289  mColumns.clear();
290  QDomNodeList columnsList = itemElem.elementsByTagName( "displayColumns" );
291  if ( columnsList.size() > 0 )
292  {
293  QDomElement columnsElem = columnsList.at( 0 ).toElement();
294  QDomNodeList columnEntryList = columnsElem.elementsByTagName( "column" );
295  for ( int i = 0; i < columnEntryList.size(); ++i )
296  {
297  QDomElement columnElem = columnEntryList.at( i ).toElement();
299  column->readXML( columnElem );
300  mColumns.append( column );
301  }
302  }
303 
304  //restore general composer item properties
305  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
306  if ( composerItemList.size() > 0 )
307  {
308  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
309  _readXML( composerItemElem, doc );
310  }
311  return true;
312 }
313 
314 bool QgsComposerTable::calculateMaxColumnWidths( QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps ) const
315 {
316  maxWidthMap.clear();
317  QList<QgsComposerTableColumn*>::const_iterator columnIt = mColumns.constBegin();
318 
319  int col = 0;
320  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
321  {
322  maxWidthMap.insert( col, textWidthMillimeters( mHeaderFont, ( *columnIt )->heading() ) );
323  col++;
324  }
325 
326  //go through all the attributes and adapt the max width values
327  QList<QgsAttributeMap>::const_iterator attIt = attributeMaps.constBegin();
328 
329  double currentAttributeTextWidth;
330 
331  for ( ; attIt != attributeMaps.constEnd(); ++attIt )
332  {
333  QgsAttributeMap::const_iterator attIt2 = attIt->constBegin();
334  for ( ; attIt2 != attIt->constEnd(); ++attIt2 )
335  {
336  currentAttributeTextWidth = textWidthMillimeters( mContentFont, attIt2.value().toString() );
337  if ( currentAttributeTextWidth > maxWidthMap[ attIt2.key()] )
338  {
339  maxWidthMap[ attIt2.key()] = currentAttributeTextWidth;
340  }
341  }
342  }
343  return true;
344 }
345 
346 void QgsComposerTable::adaptItemFrame( const QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps )
347 {
348  //calculate height
349  int n = attributeMaps.size();
350  double totalHeight = fontAscentMillimeters( mHeaderFont )
352  + ( n + 1 ) * mLineTextDistance * 2
353  + ( n + 2 ) * mGridStrokeWidth;
354 
355  //adapt frame to total width
356  double totalWidth = 0;
357  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
358  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
359  {
360  totalWidth += maxColWidthIt.value();
361  }
362  totalWidth += ( 2 * maxWidthMap.size() * mLineTextDistance );
363  totalWidth += ( maxWidthMap.size() + 1 ) * mGridStrokeWidth;
364 
365  QgsComposerItem::setSceneRect( QRectF( pos().x(), pos().y(), totalWidth, totalHeight ) );
366 }
367 
368 void QgsComposerTable::drawHorizontalGridLines( QPainter* p, int nAttributes )
369 {
370  //horizontal lines
371  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
372  double currentY = halfGridStrokeWidth;
373  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
374  currentY += mGridStrokeWidth;
375  currentY += ( fontAscentMillimeters( mHeaderFont ) + 2 * mLineTextDistance );
376  for ( int i = 0; i < nAttributes; ++i )
377  {
378  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
379  currentY += mGridStrokeWidth;
380  currentY += ( fontAscentMillimeters( mContentFont ) + 2 * mLineTextDistance );
381  }
382  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
383 }
384 
385 void QgsComposerTable::drawVerticalGridLines( QPainter* p, const QMap<int, double>& maxWidthMap )
386 {
387  //vertical lines
388  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
389  double currentX = halfGridStrokeWidth;
390  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
391  currentX += mGridStrokeWidth;
392  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
393  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
394  {
395  currentX += ( maxColWidthIt.value() + 2 * mLineTextDistance );
396  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
397  currentX += mGridStrokeWidth;
398  }
399 }
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.