QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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"
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 : std::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.userType() == QMetaType::type( "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
137void QgsLayoutItemManualTable::setRowHeights( const QList<double> &heights )
138{
139 mRowHeights = heights;
140
142}
143
144void 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
183bool 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 : std::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
236bool 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();
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 ).)
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
335Qt::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
343Qt::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
351void 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 }
370}
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Conditional styling for a rule.
void setTextColor(const QColor &value)
Set the text color for the style.
void setBackgroundColor(const QColor &value)
Set the background color for the style.
RAII class to pop scope from an expression context on destruction.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
A layout table subclass that displays manually entered (and formatted) content.
bool calculateMaxRowHeights() override
Calculates the maximum height of text shown in rows.
QIcon icon() const override
Returns the item's icon.
void setColumnWidths(const QList< double > &widths)
Sets the list of column widths (in millimeters) to use when rendering the table.
Qt::Alignment horizontalAlignmentForCell(int row, int column) const override
Returns the horizontal alignment to use for the cell at the specified row and column.
QString displayName() const override
Returns the multiframe display name.
QgsConditionalStyle conditionalCellStyle(int row, int column) const override
Returns the conditional style to use for the cell at row, column.
Qt::Alignment verticalAlignmentForCell(int row, int column) const override
Returns the vertical alignment to use for the cell at the specified row and column.
static QgsLayoutItemManualTable * create(QgsLayout *layout)
Returns a new QgsLayoutItemManualTable for the specified parent layout.
void setIncludeTableHeader(bool included)
Sets whether the table includes a header row.
void setHeaders(const QgsLayoutTableColumns &headers)
Replaces the headers in the table with a specified list of QgsLayoutTableColumns.
QgsTextFormat textFormatForCell(int row, int column) const override
Returns the text format to use for the cell at the specified row and column.
void setTableContents(const QgsTableContents &contents)
Sets the contents of the table.
QgsTextFormat textFormatForHeader(int column) const override
Returns the text format to use for the header cell at the specified column.
int type() const override
Returns unique multiframe type id.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
void setRowHeights(const QList< double > &heights)
Sets the list of row heights (in millimeters) to use when rendering the table.
bool includeTableHeader() const
Returns true if the table includes a header row.
QgsLayoutTableColumns & headers()
Returns a reference to the list of headers shown in the table.
QgsLayoutItemManualTable(QgsLayout *layout)
Constructor for QgsLayoutItemManualTable, attached to the specified layout.
QgsTableContents tableContents() const
Returns the contents of the table.
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
bool getTableContents(QgsLayoutTableContents &contents) override
Fetches the contents used for the cells in the table.
@ LayoutManualTable
Manual (fixed) table.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
Stores properties of a column for a QgsLayoutTable.
bool readXml(const QDomElement &columnElem)
Reads the column's properties from xml.
A class to display a table in the print layout, and allow the table to span over multiple frames.
QgsLayoutTableColumns & columns()
Returns a reference to the list of QgsLayoutTableColumns shown in the table.
void setColumns(const QgsLayoutTableColumns &columns)
Replaces the columns in the table with a specified list of QgsLayoutTableColumns.
virtual Qt::Alignment horizontalAlignmentForCell(int row, int column) const
Returns the horizontal alignment to use for the cell at the specified row and column.
virtual void refreshAttributes()
Refreshes the contents shown in the table by querying for new data.
virtual QgsTextFormat textFormatForHeader(int column) const
Returns the text format to use for the header cell at the specified column.
void setHeaderMode(HeaderMode mode)
Sets the display mode for headers in the table.
void recalculateTableSize()
Recalculates and updates the size of the table and all table frames.
virtual QgsExpressionContextScope * scopeForCell(int row, int column) const
Creates a new QgsExpressionContextScope for the cell at row, column.
@ AllFrames
Headers shown on all frames.
@ NoHeaders
No headers shown for table.
QgsLayoutTableColumns mColumns
Columns to show in table.
virtual Qt::Alignment verticalAlignmentForCell(int row, int column) const
Returns the vertical alignment to use for the cell at the specified row and column.
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
virtual QgsTextFormat textFormatForCell(int row, int column) const
Returns the text format to use for the cell at the specified row and column.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
QgsLayoutTableContents & contents()
Returns the current contents of the table.
virtual bool calculateMaxRowHeights()
Calculates the maximum height of text shown in rows.
QMap< int, double > mMaxRowHeightMap
Map of maximum height for each row.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:51
A context for numeric formats.
A store for object properties.
Definition: qgsproperty.h:230
The class is used as a container of context for various read/write operations on other objects.
Encapsulates the contents and formatting of a single table cell.
Definition: qgstablecell.h:36
void setProperties(const QVariantMap &properties, const QgsReadWriteContext &context)
Sets the properties for the cell.
Container for all settings relating to text rendering.
Definition: qgstextformat.h:41
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
QVector< QgsLayoutTableColumn > QgsLayoutTableColumns
List of column definitions for a QgsLayoutTable.
QVector< QgsLayoutTableRow > QgsLayoutTableContents
List of QgsLayoutTableRows, representing rows and column cell contents for a QgsLayoutTable.
QVector< QVariant > QgsLayoutTableRow
List of QVariants, representing a the contents of a single row in a QgsLayoutTable.
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
QVector< QgsTableRow > QgsTableContents
A set of table rows.
Definition: qgstablecell.h:220
QVector< QgsTableCell > QgsTableRow
A row of table cells.
Definition: qgstablecell.h:211