QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules 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 "qgsfontutils.h"
23 #include <QPainter>
24 #include <QSettings>
25 
26 
28  : QgsComposerItem( composition )
29  , mLineTextDistance( 1.0 )
30  , mHeaderFontColor( Qt::black )
31  , mContentFontColor( Qt::black )
32  , mHeaderHAlignment( FollowColumn )
33  , mShowGrid( true )
34  , mGridStrokeWidth( 0.5 )
35  , mGridColor( QColor( 0, 0, 0 ) )
36 {
37  //get default composer font from settings
38  QSettings settings;
39  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
40  if ( !defaultFontString.isEmpty() )
41  {
42  mHeaderFont.setFamily( defaultFontString );
43  mContentFont.setFamily( defaultFontString );
44  }
45 }
46 
48 {
49  qDeleteAll( mColumns );
50  mColumns.clear();
51 }
52 
54 {
56  mAttributeMaps.clear();
57 
58  //getFeatureAttributes
60  {
61  return;
62  }
63 
64  //since attributes have changed, we also need to recalculate the column widths
65  //and size of table
67 }
68 
69 void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
70 {
71  Q_UNUSED( itemStyle );
72  Q_UNUSED( pWidget );
73  if ( !painter )
74  {
75  return;
76  }
77  if ( !shouldDrawItem() )
78  {
79  return;
80  }
81 
84  {
85  //exporting composition, so force an attribute refresh
86  //we do this in case vector layer has changed via an external source (eg, another database user)
88  }
89 
90  drawBackground( painter );
91  painter->save();
92  //antialiasing on
93  painter->setRenderHint( QPainter::Antialiasing, true );
94 
95  painter->setPen( Qt::SolidLine );
96 
97  //now draw the text
98  double currentX = mGridStrokeWidth;
99  double currentY;
100 
102 
103  int col = 0;
104  double cellHeaderHeight = QgsComposerUtils::fontAscentMM( mHeaderFont ) + 2 * mLineTextDistance;
105  double cellBodyHeight = QgsComposerUtils::fontAscentMM( mContentFont ) + 2 * mLineTextDistance;
106  QRectF cell;
107  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
108  {
109  currentY = mGridStrokeWidth;
110  currentX += mLineTextDistance;
111 
112  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );
113 
114  //calculate alignment of header
115  Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
116  switch ( mHeaderHAlignment )
117  {
118  case FollowColumn:
119  headerAlign = ( *columnIt )->hAlignment();
120  break;
121  case HeaderLeft:
122  headerAlign = Qt::AlignLeft;
123  break;
124  case HeaderCenter:
125  headerAlign = Qt::AlignHCenter;
126  break;
127  case HeaderRight:
128  headerAlign = Qt::AlignRight;
129  break;
130  }
131 
132  QgsComposerUtils::drawText( painter, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );
133 
134  currentY += cellHeaderHeight;
135  currentY += mGridStrokeWidth;
136 
137  //draw the attribute values
139  for ( ; attIt != mAttributeMaps.end(); ++attIt )
140  {
141  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellBodyHeight );
142 
143  const QgsAttributeMap &currentAttributeMap = *attIt;
144  QString str = currentAttributeMap[ col ].toString();
145  QgsComposerUtils::drawText( painter, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), ( *columnIt )->vAlignment(), Qt::TextDontClip );
146 
147  currentY += cellBodyHeight;
148  currentY += mGridStrokeWidth;
149  }
150 
151  currentX += mMaxColumnWidthMap[ col ];
152  currentX += mLineTextDistance;
153  currentX += mGridStrokeWidth;
154  col++;
155  }
156 
157  //and the borders
158  if ( mShowGrid )
159  {
160  QPen gridPen;
161  gridPen.setWidthF( mGridStrokeWidth );
162  gridPen.setColor( mGridColor );
163  gridPen.setJoinStyle( Qt::MiterJoin );
164  painter->setPen( gridPen );
165  drawHorizontalGridLines( painter, mAttributeMaps.size() );
167  }
168 
169  painter->restore();
170 
171  //draw frame and selection boxes if necessary
172  drawFrame( painter );
173  if ( isSelected() )
174  {
175  drawSelectionBoxes( painter );
176  }
177 }
178 
180 {
181  mLineTextDistance = d;
182  //since spacing has changed, we need to recalculate the table size
184 }
185 
187 {
188  mHeaderFont = f;
189  //since font attributes have changed, we need to recalculate the table size
191 }
192 
194 {
195  mHeaderFontColor = color;
196  repaint();
197 }
198 
200 {
201  mHeaderHAlignment = alignment;
202  repaint();
203 }
204 
206 {
207  mContentFont = f;
208  //since font attributes have changed, we need to recalculate the table size
210 }
211 
213 {
214  mContentFontColor = color;
215  repaint();
216 }
217 
219 {
220  mShowGrid = show;
221  //since grid spacing has changed, we need to recalculate the table size
223 }
224 
226 {
227  mGridStrokeWidth = w;
228  //since grid spacing has changed, we need to recalculate the table size
230 }
231 
233 {
234  //check how much space each column needs
236  {
237  return;
238  }
239  //adapt item frame to max width / height
241 
242  repaint();
243 }
244 
246 {
247  QMap<int, QString> headers;
248 
250  int col = 0;
251  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
252  {
253  headers.insert( col, ( *columnIt )->heading() );
254  col++;
255  }
256  return headers;
257 }
258 
260 {
261  //remove existing columns
262  qDeleteAll( mColumns );
263  mColumns.clear();
264 
265  mColumns.append( columns );
266 }
267 
269 {
270  elem.setAttribute( "lineTextDist", QString::number( mLineTextDistance ) );
271  elem.appendChild( QgsFontUtils::toXmlElement( mHeaderFont, doc, "headerFontProperties" ) );
273  elem.setAttribute( "headerHAlignment", QString::number(( int )mHeaderHAlignment ) );
274  elem.appendChild( QgsFontUtils::toXmlElement( mContentFont, doc, "contentFontProperties" ) );
276  elem.setAttribute( "gridStrokeWidth", QString::number( mGridStrokeWidth ) );
278  elem.setAttribute( "showGrid", mShowGrid );
279 
280  //columns
281  QDomElement displayColumnsElem = doc.createElement( "displayColumns" );
283  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
284  {
285  QDomElement columnElem = doc.createElement( "column" );
286  ( *columnIt )->writeXML( columnElem, doc );
287  displayColumnsElem.appendChild( columnElem );
288  }
289  elem.appendChild( displayColumnsElem );
290 
291  return _writeXML( elem, doc );
292 }
293 
294 bool QgsComposerTable::tableReadXML( const QDomElement& itemElem, const QDomDocument& doc )
295 {
296  if ( itemElem.isNull() )
297  {
298  return false;
299  }
300 
301  if ( !QgsFontUtils::setFromXmlChildNode( mHeaderFont, itemElem, "headerFontProperties" ) )
302  {
303  mHeaderFont.fromString( itemElem.attribute( "headerFont", "" ) );
304  }
305  mHeaderFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "headerFontColor", "0,0,0,255" ) );
306  mHeaderHAlignment = QgsComposerTable::HeaderHAlignment( itemElem.attribute( "headerHAlignment", "0" ).toInt() );
307  if ( !QgsFontUtils::setFromXmlChildNode( mContentFont, itemElem, "contentFontProperties" ) )
308  {
309  mContentFont.fromString( itemElem.attribute( "contentFont", "" ) );
310  }
311  mContentFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "contentFontColor", "0,0,0,255" ) );
312  mLineTextDistance = itemElem.attribute( "lineTextDist", "1.0" ).toDouble();
313  mGridStrokeWidth = itemElem.attribute( "gridStrokeWidth", "0.5" ).toDouble();
314  mShowGrid = itemElem.attribute( "showGrid", "1" ).toInt();
315 
316  //grid color
317  if ( itemElem.hasAttribute( "gridColor" ) )
318  {
319  mGridColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "gridColor", "0,0,0,255" ) );
320  }
321  else
322  {
323  //old style grid color
324  int gridRed = itemElem.attribute( "gridColorRed", "0" ).toInt();
325  int gridGreen = itemElem.attribute( "gridColorGreen", "0" ).toInt();
326  int gridBlue = itemElem.attribute( "gridColorBlue", "0" ).toInt();
327  int gridAlpha = itemElem.attribute( "gridColorAlpha", "255" ).toInt();
328  mGridColor = QColor( gridRed, gridGreen, gridBlue, gridAlpha );
329  }
330 
331  //restore column specifications
332  qDeleteAll( mColumns );
333  mColumns.clear();
334  QDomNodeList columnsList = itemElem.elementsByTagName( "displayColumns" );
335  if ( columnsList.size() > 0 )
336  {
337  QDomElement columnsElem = columnsList.at( 0 ).toElement();
338  QDomNodeList columnEntryList = columnsElem.elementsByTagName( "column" );
339  for ( int i = 0; i < columnEntryList.size(); ++i )
340  {
341  QDomElement columnElem = columnEntryList.at( i ).toElement();
343  column->readXML( columnElem );
344  mColumns.append( column );
345  }
346  }
347 
348  //restore general composer item properties
349  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
350  if ( composerItemList.size() > 0 )
351  {
352  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
353  _readXML( composerItemElem, doc );
354  }
355  return true;
356 }
357 
359 {
360  maxWidthMap.clear();
362 
363  int col = 0;
364  for ( ; columnIt != mColumns.constEnd(); ++columnIt )
365  {
366  maxWidthMap.insert( col, QgsComposerUtils::textWidthMM( mHeaderFont, ( *columnIt )->heading() ) );
367  col++;
368  }
369 
370  //go through all the attributes and adapt the max width values
371  QList<QgsAttributeMap>::const_iterator attIt = attributeMaps.constBegin();
372 
373  double currentAttributeTextWidth;
374 
375  for ( ; attIt != attributeMaps.constEnd(); ++attIt )
376  {
377  QgsAttributeMap::const_iterator attIt2 = attIt->constBegin();
378  for ( ; attIt2 != attIt->constEnd(); ++attIt2 )
379  {
380  currentAttributeTextWidth = QgsComposerUtils::textWidthMM( mContentFont, attIt2.value().toString() );
381  if ( currentAttributeTextWidth > maxWidthMap[ attIt2.key()] )
382  {
383  maxWidthMap[ attIt2.key()] = currentAttributeTextWidth;
384  }
385  }
386  }
387  return true;
388 }
389 
390 void QgsComposerTable::adaptItemFrame( const QMap<int, double>& maxWidthMap, const QList<QgsAttributeMap>& attributeMaps )
391 {
392  //calculate height
393  int n = attributeMaps.size();
394  double totalHeight = QgsComposerUtils::fontAscentMM( mHeaderFont )
396  + ( n + 1 ) * mLineTextDistance * 2
397  + ( n + 2 ) * mGridStrokeWidth;
398 
399  //adapt frame to total width
400  double totalWidth = 0;
401  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
402  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
403  {
404  totalWidth += maxColWidthIt.value();
405  }
406  totalWidth += ( 2 * maxWidthMap.size() * mLineTextDistance );
407  totalWidth += ( maxWidthMap.size() + 1 ) * mGridStrokeWidth;
408 
409  QRectF evaluatedRect = evalItemRect( QRectF( pos().x(), pos().y(), totalWidth, totalHeight ) );
410 
411  //update rect for data defined size and position
412  QgsComposerItem::setSceneRect( evaluatedRect );
413 }
414 
416 {
417  //horizontal lines
418  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
419  double currentY = halfGridStrokeWidth;
420  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
421  currentY += mGridStrokeWidth;
423  for ( int i = 0; i < nAttributes; ++i )
424  {
425  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
426  currentY += mGridStrokeWidth;
428  }
429  p->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( rect().width() - halfGridStrokeWidth, currentY ) );
430 }
431 
433 {
434  //vertical lines
435  double halfGridStrokeWidth = mGridStrokeWidth / 2.0;
436  double currentX = halfGridStrokeWidth;
437  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
438  currentX += mGridStrokeWidth;
439  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
440  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
441  {
442  currentX += ( maxColWidthIt.value() + 2 * mLineTextDistance );
443  p->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, rect().height() - halfGridStrokeWidth ) );
444  currentX += mGridStrokeWidth;
445  }
446 }
void clear()
QDomNodeList elementsByTagName(const QString &tagname) const
qreal x() const
qreal y() const
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.
void setRenderHint(RenderHint hint, bool on)
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const
HeaderHAlignment
Controls how headers are horizontally aligned in a table.
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.
const_iterator constBegin() const
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.
void save()
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.
void setJoinStyle(Qt::PenJoinStyle style)
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.
void drawLine(const QLineF &line)
void clear()
double toDouble(bool *ok) const
int size() const
static QString encodeColor(QColor color)
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
QDomElement toElement() const
void drawHorizontalGridLines(QPainter *p, int nAttributes)
Draws the horizontal grid lines for the table.
QPointF pos() const
QString number(int n, int base)
void append(const T &value)
bool fromString(const QString &descrip)
bool hasAttribute(const QString &name) const
virtual void drawSelectionBoxes(QPainter *p)
Draws additional graphics on selected items.
void setPen(const QColor &color)
void setAttribute(const QString &name, const QString &value)
bool isSelected() const
int toInt(bool *ok, int base) const
bool isEmpty() const
QRectF evalItemRect(const QRectF &newRect, const bool resizeOnly=false, const QgsExpressionContext *context=0)
Evaluates an item's bounding rect to consider data defined position and size of item and reference po...
const_iterator constEnd() const
bool tableWriteXML(QDomElement &itemElem, QDomDocument &doc) const
Writes common table properties to xml for storage.
void setWidthF(qreal width)
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
void repaint() override
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
Stores properties of a column in a QgsComposerTable.
virtual ~QgsComposerTable()
void setColor(const QColor &color)
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
bool isNull() const
void restore()
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.
QVariant value(const QString &key, const QVariant &defaultValue) const
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
QList< QgsAttributeMap > mAttributeMaps
QString toString() const
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.
void setFamily(const QString &family)
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...
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
double mLineTextDistance
Distance between table lines and text.
iterator insert(const Key &key, const T &value)
virtual bool readXML(const QDomElement &columnElem)
Reads the column's properties from xml.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
int size() const
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.
const_iterator constEnd() const
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
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.
QString toString() const
int size() const
QDomNode at(int index) const
QRectF rect() const
const T value(const Key &key) const
void drawVerticalGridLines(QPainter *p, const QMap< int, double > &maxWidthMap)
Draws the vertical grid lines for the table.