QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgslayoutitemmanualtable.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemmanualtable.cpp
3  ---------------------------
4  begin : January 2020
5  copyright : (C) 2020 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
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 "qgsconditionalstyle.h"
20 #include "qgslayoutitemregistry.h"
21 #include "qgslayouttablecolumn.h"
22 #include "qgsnumericformat.h"
23 #include "qgsxmlutils.h"
25 
26 //
27 // QgsLayoutItemManualTable
28 //
29 
31  : QgsLayoutTable( layout )
32 {
35 }
36 
38 {
39 }
40 
42 {
44 }
45 
47 {
48  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
49 }
50 
52 {
53  return new QgsLayoutItemManualTable( layout );
54 }
55 
57 {
58  return tr( "<Table frame>" );
59 }
60 
62 {
63  contents.clear();
64 
65  QgsNumericFormatContext numericContext;
66 
68 
69  int rowNumber = 0;
70  for ( const QgsTableRow &row : qgis::as_const( mContents ) )
71  {
72  QgsLayoutTableRow currentRow;
73 
74  for ( int columnNumber = 0; columnNumber < mColumns.count(); ++columnNumber )
75  {
76  if ( columnNumber < row.count() )
77  {
78  QVariant cellContent = row.at( columnNumber ).content();
79 
80  if ( cellContent.canConvert< QgsProperty >() )
81  {
82  // expression based cell content, evaluate now
83  QgsExpressionContextScopePopper popper( context, scopeForCell( rowNumber, columnNumber ) );
84  cellContent = cellContent.value< QgsProperty >().value( context );
85  }
86 
87  if ( row.at( columnNumber ).numericFormat() )
88  currentRow << row.at( columnNumber ).numericFormat()->formatDouble( cellContent.toDouble(), numericContext );
89  else
90  currentRow << cellContent.toString();
91  }
92  else
93  {
94  currentRow << QString();
95  }
96  }
97  contents << currentRow;
98  rowNumber++;
99  }
100 
102  return true;
103 }
104 
106 {
107  if ( row < 0 || row >= mContents.size() )
108  return QgsConditionalStyle();
109 
110  const QgsTableRow &rowContents = mContents[ row ];
111  if ( column < 0 || column > rowContents.size() )
112  return QgsConditionalStyle();
113 
114  const QgsTableCell &c = rowContents[ column ];
116  if ( c.foregroundColor().isValid() )
117  res.setTextColor( c.foregroundColor() );
118  if ( c.backgroundColor().isValid() )
119  res.setBackgroundColor( c.backgroundColor() );
120 
121  return res;
122 }
123 
125 {
126  mContents = contents;
127 
128  refreshColumns();
130 }
131 
133 {
134  return mContents;
135 }
136 
137 void QgsLayoutItemManualTable::setRowHeights( const QList<double> &heights )
138 {
139  mRowHeights = heights;
140 
142 }
143 
144 void QgsLayoutItemManualTable::setColumnWidths( const QList<double> &widths )
145 {
146  mColumnWidths = widths;
147 
148  refreshColumns();
150 }
151 
153 {
154  return mIncludeHeader;
155 }
156 
158 {
159  mIncludeHeader = included;
160 
161  if ( !mIncludeHeader )
163  else
165  refreshColumns();
167 }
168 
170 {
171  return mHeaders;
172 }
173 
175 {
176  mHeaders.clear();
177 
178  mHeaders.append( headers );
179  refreshColumns();
181 }
182 
183 bool QgsLayoutItemManualTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
184 {
185  if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
186  return false;
187 
188  tableElem.setAttribute( QStringLiteral( "includeHeader" ), mIncludeHeader ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
189 
190  //headers
191  QDomElement headersElem = doc.createElement( QStringLiteral( "headers" ) );
192  for ( const QgsLayoutTableColumn &header : qgis::as_const( mHeaders ) )
193  {
194  QDomElement headerElem = doc.createElement( QStringLiteral( "header" ) );
195  header.writeXml( headerElem, doc );
196  headersElem.appendChild( headerElem );
197  }
198  tableElem.appendChild( headersElem );
199 
200  QDomElement contentsElement = doc.createElement( QStringLiteral( "contents" ) );
201  for ( const QgsTableRow &row : mContents )
202  {
203  QDomElement rowElement = doc.createElement( QStringLiteral( "row" ) );
204  for ( int i = 0; i < mColumns.count(); ++i )
205  {
206  if ( i < row.count() )
207  {
208  rowElement.appendChild( QgsXmlUtils::writeVariant( row.at( i ).properties( context ), doc ) );
209  }
210  }
211  contentsElement.appendChild( rowElement );
212  }
213  tableElem.appendChild( contentsElement );
214 
215  QDomElement rowHeightsElement = doc.createElement( QStringLiteral( "rowHeights" ) );
216  for ( double height : mRowHeights )
217  {
218  QDomElement rowElement = doc.createElement( QStringLiteral( "row" ) );
219  rowElement.setAttribute( QStringLiteral( "height" ), height );
220  rowHeightsElement.appendChild( rowElement );
221  }
222  tableElem.appendChild( rowHeightsElement );
223 
224  QDomElement columnWidthsElement = doc.createElement( QStringLiteral( "columnWidths" ) );
225  for ( double width : mColumnWidths )
226  {
227  QDomElement columnElement = doc.createElement( QStringLiteral( "column" ) );
228  columnElement.setAttribute( QStringLiteral( "width" ), width );
229  columnWidthsElement.appendChild( columnElement );
230  }
231  tableElem.appendChild( columnWidthsElement );
232 
233  return true;
234 }
235 
236 bool QgsLayoutItemManualTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
237 {
238  if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
239  return false;
240 
241  mIncludeHeader = itemElem.attribute( QStringLiteral( "includeHeader" ) ).toInt();
242  //restore header specifications
243  mHeaders.clear();
244  QDomNodeList headersList = itemElem.elementsByTagName( QStringLiteral( "headers" ) );
245  if ( !headersList.isEmpty() )
246  {
247  QDomElement headersElem = headersList.at( 0 ).toElement();
248  QDomNodeList headerEntryList = headersElem.elementsByTagName( QStringLiteral( "header" ) );
249  for ( int i = 0; i < headerEntryList.size(); ++i )
250  {
251  QDomElement headerElem = headerEntryList.at( i ).toElement();
252  QgsLayoutTableColumn header;
253  header.readXml( headerElem );
254  mHeaders.append( header );
255  }
256  }
257 
258  mRowHeights.clear();
259  const QDomNodeList rowHeightNodeList = itemElem.firstChildElement( QStringLiteral( "rowHeights" ) ).childNodes();
260  mRowHeights.reserve( rowHeightNodeList.size() );
261  for ( int r = 0; r < rowHeightNodeList.size(); ++r )
262  {
263  const QDomElement rowHeightElement = rowHeightNodeList.at( r ).toElement();
264  mRowHeights.append( rowHeightElement.attribute( QStringLiteral( "height" ) ).toDouble() );
265  }
266 
267  mColumnWidths.clear();
268  const QDomNodeList columnWidthNodeList = itemElem.firstChildElement( QStringLiteral( "columnWidths" ) ).childNodes();
269  mColumnWidths.reserve( columnWidthNodeList.size() );
270  for ( int r = 0; r < columnWidthNodeList.size(); ++r )
271  {
272  const QDomElement columnWidthElement = columnWidthNodeList.at( r ).toElement();
273  mColumnWidths.append( columnWidthElement.attribute( QStringLiteral( "width" ) ).toDouble() );
274  }
275 
276  QgsTableContents newContents;
277  const QDomElement contentsElement = itemElem.firstChildElement( QStringLiteral( "contents" ) );
278  const QDomNodeList rowNodeList = contentsElement.childNodes();
279  newContents.reserve( rowNodeList.size() );
280  for ( int r = 0; r < rowNodeList.size(); ++r )
281  {
282  QgsTableRow row;
283  const QDomElement rowElement = rowNodeList.at( r ).toElement();
284  const QDomNodeList cellNodeList = rowElement.childNodes();
285  row.reserve( cellNodeList.size() );
286  for ( int c = 0; c < cellNodeList.size(); ++c )
287  {
288  const QDomElement cellElement = cellNodeList.at( c ).toElement();
289  QgsTableCell newCell;
290  newCell.setProperties( QgsXmlUtils::readVariant( cellElement ).toMap(), context );
291  row << newCell;
292  }
293  newContents << row;
294  }
295  setTableContents( newContents );
296 
297  emit changed();
298  return true;
299 }
300 
302 {
304  return false;
305 
306  QMap<int, double> newHeights;
307  for ( auto it = mMaxRowHeightMap.constBegin(); it != mMaxRowHeightMap.constEnd(); ++it )
308  {
309  // first row in mMaxRowHeightMap corresponds to header, which we ignore here
310  const int row = it.key() - 1;
311  const double presetHeight = mRowHeights.value( row );
312  double thisRowHeight = it.value();
313  if ( presetHeight > 0 )
314  thisRowHeight = presetHeight;
315  newHeights.insert( row + 1, thisRowHeight );
316  }
317  mMaxRowHeightMap = newHeights;
318  return true;
319 }
320 
322 {
323 // if ( mHeaders.value( column ).)
324  return QgsLayoutTable::textFormatForHeader( column );
325 }
326 
328 {
329  if ( mContents.value( row ).value( column ).textFormat().isValid() )
330  return mContents.value( row ).value( column ).textFormat();
331 
332  return QgsLayoutTable::textFormatForCell( row, column );
333 }
334 
335 Qt::Alignment QgsLayoutItemManualTable::horizontalAlignmentForCell( int row, int column ) const
336 {
337  if ( row < mContents.size() && column < mContents.at( row ).size() )
338  return mContents.value( row ).value( column ).horizontalAlignment();
339 
340  return QgsLayoutTable::horizontalAlignmentForCell( row, column );
341 }
342 
343 Qt::Alignment QgsLayoutItemManualTable::verticalAlignmentForCell( int row, int column ) const
344 {
345  if ( row < mContents.size() && column < mContents.at( row ).size() )
346  return mContents.value( row ).value( column ).verticalAlignment();
347 
348  return QgsLayoutTable::verticalAlignmentForCell( row, column );
349 }
350 
351 void QgsLayoutItemManualTable::refreshColumns()
352 {
353  // refresh columns
355  if ( !mContents.empty() )
356  {
357  int colIndex = 0;
358  const QgsTableRow &firstRow = mContents[ 0 ];
359  columns.reserve( firstRow.size() );
360  for ( const QgsTableCell &cell : firstRow )
361  {
362  ( void )cell;
363  QgsLayoutTableColumn newCol( mHeaders.value( colIndex ).heading() );
364  newCol.setWidth( mColumnWidths.value( colIndex ) );
365  columns << newCol;
366  colIndex++;
367  }
368  }
369  setColumns( columns );
370 }
QgsLayoutItemManualTable::headers
QgsLayoutTableColumns & headers()
Returns a reference to the list of headers shown in the table.
Definition: qgslayoutitemmanualtable.cpp:169
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:370
QgsLayoutTable::setHeaderMode
void setHeaderMode(HeaderMode mode)
Sets the display mode for headers in the table.
Definition: qgslayouttable.cpp:776
QgsLayoutObject::layout
const QgsLayout * layout() const
Returns the layout the object is attached to.
Definition: qgslayoutobject.cpp:126
qgsexpressioncontextutils.h
qgsconditionalstyle.h
QgsLayoutMultiFrame::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgslayoutmultiframe.cpp:283
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:355
QgsLayoutTableColumns
QVector< QgsLayoutTableColumn > QgsLayoutTableColumns
List of column definitions for a QgsLayoutTable.
Definition: qgslayouttable.h:58
QgsProperty
A store for object properties.
Definition: qgsproperty.h:232
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:626
QgsLayoutItemManualTable::tableContents
QgsTableContents tableContents() const
Returns the contents of the table.
Definition: qgslayoutitemmanualtable.cpp:132
QgsLayoutTableContents
QVector< QgsLayoutTableRow > QgsLayoutTableContents
List of QgsLayoutTableRows, representing rows and column cell contents for a QgsLayoutTable.
Definition: qgslayouttable.h:47
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
QgsConditionalStyle::setBackgroundColor
void setBackgroundColor(const QColor &value)
Set the background color for the style.
Definition: qgsconditionalstyle.h:155
QgsConditionalStyle::setTextColor
void setTextColor(const QColor &value)
Set the text color for the style.
Definition: qgsconditionalstyle.h:161
QgsLayoutItemManualTable::setRowHeights
void setRowHeights(const QList< double > &heights)
Sets the list of row heights (in millimeters) to use when rendering the table.
Definition: qgslayoutitemmanualtable.cpp:137
QgsLayoutTable::columns
QgsLayoutTableColumns & columns()
Returns a reference to the list of QgsLayoutTableColumns shown in the table.
Definition: qgslayouttable.h:482
QgsLayoutItemManualTable::QgsLayoutItemManualTable
QgsLayoutItemManualTable(QgsLayout *layout)
Constructor for QgsLayoutItemManualTable, attached to the specified layout.
Definition: qgslayoutitemmanualtable.cpp:30
QgsLayoutItemManualTable::conditionalCellStyle
QgsConditionalStyle conditionalCellStyle(int row, int column) const override
Returns the conditional style to use for the cell at row, column.
Definition: qgslayoutitemmanualtable.cpp:105
QgsLayoutItemManualTable::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
Definition: qgslayoutitemmanualtable.cpp:236
QgsLayoutTable::writePropertiesToElement
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
Definition: qgslayouttable.cpp:69
QgsLayoutObject::changed
void changed()
Emitted when the object's properties change.
QgsLayoutItemManualTable::setTableContents
void setTableContents(const QgsTableContents &contents)
Sets the contents of the table.
Definition: qgslayoutitemmanualtable.cpp:124
QgsConditionalStyle
Conditional styling for a rule.
Definition: qgsconditionalstyle.h:113
QgsLayoutTableColumn::readXml
bool readXml(const QDomElement &columnElem)
Reads the column's properties from xml.
Definition: qgslayouttablecolumn.cpp:50
QgsLayoutTable::textFormatForCell
virtual QgsTextFormat textFormatForCell(int row, int column) const
Returns the text format to use for the cell at the specified row and column.
Definition: qgslayouttable.cpp:1544
QgsTableContents
QVector< QgsTableRow > QgsTableContents
A set of table rows.
Definition: qgstablecell.h:220
QgsLayoutTable::verticalAlignmentForCell
virtual Qt::Alignment verticalAlignmentForCell(int row, int column) const
Returns the vertical alignment to use for the cell at the specified row and column.
Definition: qgslayouttable.cpp:1559
QgsLayoutTable::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
Definition: qgslayouttable.cpp:133
QgsTextFormat
Container for all settings relating to text rendering.
Definition: qgstextformat.h:40
QgsLayoutItemManualTable::textFormatForHeader
QgsTextFormat textFormatForHeader(int column) const override
Returns the text format to use for the header cell at the specified column.
Definition: qgslayoutitemmanualtable.cpp:321
QgsTableCell
Encapsulates the contents and formatting of a single table cell.
Definition: qgstablecell.h:36
QgsLayoutTable::contents
QgsLayoutTableContents & contents()
Returns the current contents of the table.
Definition: qgslayouttable.h:550
QgsLayoutItemManualTable::horizontalAlignmentForCell
Qt::Alignment horizontalAlignmentForCell(int row, int column) const override
Returns the horizontal alignment to use for the cell at the specified row and column.
Definition: qgslayoutitemmanualtable.cpp:335
QgsLayoutTable::scopeForCell
virtual QgsExpressionContextScope * scopeForCell(int row, int column) const
Creates a new QgsExpressionContextScope for the cell at row, column.
Definition: qgslayouttable.cpp:994
QgsXmlUtils::readVariant
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
Definition: qgsxmlutils.cpp:251
QgsLayoutItemManualTable::getTableContents
bool getTableContents(QgsLayoutTableContents &contents) override
Fetches the contents used for the cells in the table.
Definition: qgslayoutitemmanualtable.cpp:61
QgsLayoutItemManualTable::verticalAlignmentForCell
Qt::Alignment verticalAlignmentForCell(int row, int column) const override
Returns the vertical alignment to use for the cell at the specified row and column.
Definition: qgslayoutitemmanualtable.cpp:343
QgsLayoutItemManualTable::displayName
QString displayName() const override
Returns the multiframe display name.
Definition: qgslayoutitemmanualtable.cpp:56
QgsLayoutTable::NoHeaders
@ NoHeaders
No headers shown for table.
Definition: qgslayouttable.h:136
QgsLayoutItemManualTable::includeTableHeader
bool includeTableHeader() const
Returns true if the table includes a header row.
Definition: qgslayoutitemmanualtable.cpp:152
QgsLayoutItemManualTable::setHeaders
void setHeaders(const QgsLayoutTableColumns &headers)
Replaces the headers in the table with a specified list of QgsLayoutTableColumns.
Definition: qgslayoutitemmanualtable.cpp:174
QgsLayoutItemManualTable::setIncludeTableHeader
void setIncludeTableHeader(bool included)
Sets whether the table includes a header row.
Definition: qgslayoutitemmanualtable.cpp:157
QgsLayoutTable::textFormatForHeader
virtual QgsTextFormat textFormatForHeader(int column) const
Returns the text format to use for the header cell at the specified column.
Definition: qgslayouttable.cpp:1549
QgsLayoutItemManualTable::writePropertiesToElement
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
Definition: qgslayoutitemmanualtable.cpp:183
QgsLayoutItemManualTable::icon
QIcon icon() const override
Returns the item's icon.
Definition: qgslayoutitemmanualtable.cpp:46
QgsLayoutTable
A class to display a table in the print layout, and allow the table to span over multiple frames.
Definition: qgslayouttable.h:113
QgsLayoutTable::refreshAttributes
virtual void refreshAttributes()
Refreshes the contents shown in the table by querying for new data.
Definition: qgslayouttable.cpp:1031
qgsxmlutils.h
QgsLayoutTable::recalculateTableSize
void recalculateTableSize()
Recalculates and updates the size of the table and all table frames.
Definition: qgslayouttable.cpp:1530
qgsnumericformat.h
qgslayoutitemmanualtable.h
QgsLayoutTable::calculateMaxRowHeights
virtual bool calculateMaxRowHeights()
Calculates the maximum height of text shown in rows.
Definition: qgslayouttable.cpp:1155
QgsTableCell::setProperties
void setProperties(const QVariantMap &properties, const QgsReadWriteContext &context)
Sets the properties for the cell.
Definition: qgstablecell.cpp:86
QgsLayoutItemManualTable::type
int type() const override
Returns unique multiframe type id.
Definition: qgslayoutitemmanualtable.cpp:41
QgsLayoutTable::setColumns
void setColumns(const QgsLayoutTableColumns &columns)
Replaces the columns in the table with a specified list of QgsLayoutTableColumns.
Definition: qgslayouttable.cpp:942
QgsTableRow
QVector< QgsTableCell > QgsTableRow
A row of table cells.
Definition: qgstablecell.h:211
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
qgslayouttablecolumn.h
QgsLayoutTable::mMaxRowHeightMap
QMap< int, double > mMaxRowHeightMap
Map of maximum height for each row.
Definition: qgslayouttable.h:627
QgsLayoutTableRow
QVector< QVariant > QgsLayoutTableRow
List of QVariants, representing a the contents of a single row in a QgsLayoutTable.
Definition: qgslayouttable.h:30
QgsLayoutItemManualTable::~QgsLayoutItemManualTable
~QgsLayoutItemManualTable() override
Definition: qgslayoutitemmanualtable.cpp:37
QgsLayoutTable::mColumns
QgsLayoutTableColumns mColumns
Columns to show in table.
Definition: qgslayouttable.h:615
QgsLayoutTableColumn
Stores properties of a column for a QgsLayoutTable.
Definition: qgslayouttablecolumn.h:37
QgsLayoutTable::horizontalAlignmentForCell
virtual Qt::Alignment horizontalAlignmentForCell(int row, int column) const
Returns the horizontal alignment to use for the cell at the specified row and column.
Definition: qgslayouttable.cpp:1554
QgsLayoutItemManualTable::textFormatForCell
QgsTextFormat textFormatForCell(int row, int column) const override
Returns the text format to use for the cell at the specified row and column.
Definition: qgslayoutitemmanualtable.cpp:327
QgsLayoutItemManualTable::setColumnWidths
void setColumnWidths(const QList< double > &widths)
Sets the list of column widths (in millimeters) to use when rendering the table.
Definition: qgslayoutitemmanualtable.cpp:144
QgsLayoutItemManualTable::create
static QgsLayoutItemManualTable * create(QgsLayout *layout)
Returns a new QgsLayoutItemManualTable for the specified parent layout.
Definition: qgslayoutitemmanualtable.cpp:51
QgsXmlUtils::writeVariant
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
Definition: qgsxmlutils.cpp:106
qgslayoutitemregistry.h
QgsLayoutItemRegistry::LayoutManualTable
@ LayoutManualTable
Manual (fixed) table.
Definition: qgslayoutitemregistry.h:338
QgsLayoutTable::AllFrames
@ AllFrames
Headers shown on all frames.
Definition: qgslayouttable.h:135
QgsLayoutItemManualTable
A layout table subclass that displays manually entered (and formatted) content.
Definition: qgslayoutitemmanualtable.h:32
QgsLayoutItemManualTable::calculateMaxRowHeights
bool calculateMaxRowHeights() override
Calculates the maximum height of text shown in rows.
Definition: qgslayoutitemmanualtable.cpp:301
QgsNumericFormatContext
A context for numeric formats.
Definition: qgsnumericformat.h:35