QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
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 "moc_qgslayoutitemmanualtable.cpp"
20#include "qgsconditionalstyle.h"
23#include "qgsnumericformat.h"
24#include "qgsxmlutils.h"
26
27//
28// QgsLayoutItemManualTable
29//
30
37
41
46
48{
49 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemTable.svg" ) );
50}
51
56
58{
59 return tr( "<Table frame>" );
60}
61
63{
64 contents.clear();
65
66 QgsNumericFormatContext numericContext;
67
69
70 int rowNumber = 0;
71 for ( const QgsTableRow &row : std::as_const( mContents ) )
72 {
73 QgsLayoutTableRow currentRow;
74
75 for ( int columnNumber = 0; columnNumber < mColumns.count(); ++columnNumber )
76 {
77 if ( columnNumber < row.count() )
78 {
79 QVariant cellContent = row.at( columnNumber ).content();
80
81 if ( cellContent.userType() == qMetaTypeId<QgsProperty>() )
82 {
83 // expression based cell content, evaluate now
84 QgsExpressionContextScopePopper popper( context, scopeForCell( rowNumber, columnNumber ) );
85 cellContent = cellContent.value< QgsProperty >().value( context );
86 }
87
88 if ( row.at( columnNumber ).numericFormat() )
89 currentRow << row.at( columnNumber ).numericFormat()->formatDouble( cellContent.toDouble(), numericContext );
90 else
91 currentRow << cellContent.toString();
92 }
93 else
94 {
95 currentRow << QString();
96 }
97 }
98 contents << currentRow;
99 rowNumber++;
100 }
101
103 return true;
104}
105
107{
108 if ( row < 0 || row >= mContents.size() )
109 return QgsConditionalStyle();
110
111 const QgsTableRow &rowContents = mContents[ row ];
112 if ( column < 0 || column > rowContents.size() )
113 return QgsConditionalStyle();
114
115 const QgsTableCell &c = rowContents[ column ];
117 if ( c.foregroundColor().isValid() )
118 res.setTextColor( c.foregroundColor() );
119 if ( c.backgroundColor().isValid() )
120 res.setBackgroundColor( c.backgroundColor() );
121
122 return res;
123}
124
126{
127 mContents = contents;
128
129 refreshColumns();
131}
132
134{
135 return mContents;
136}
137
138void QgsLayoutItemManualTable::setRowHeights( const QList<double> &heights )
139{
140 mRowHeights = heights;
141
143}
144
145void QgsLayoutItemManualTable::setColumnWidths( const QList<double> &widths )
146{
147 mColumnWidths = widths;
148
149 refreshColumns();
151}
152
154{
155 return mIncludeHeader;
156}
157
159{
160 mIncludeHeader = included;
161
162 if ( !mIncludeHeader )
164 else
166 refreshColumns();
168}
169
174
176{
177 mHeaders.clear();
178
179 mHeaders.append( headers );
180 refreshColumns();
182}
183
184bool QgsLayoutItemManualTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
185{
186 if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
187 return false;
188
189 tableElem.setAttribute( QStringLiteral( "includeHeader" ), mIncludeHeader ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
190
191 //headers
192 QDomElement headersElem = doc.createElement( QStringLiteral( "headers" ) );
193 for ( const QgsLayoutTableColumn &header : std::as_const( mHeaders ) )
194 {
195 QDomElement headerElem = doc.createElement( QStringLiteral( "header" ) );
196 header.writeXml( headerElem, doc );
197 headersElem.appendChild( headerElem );
198 }
199 tableElem.appendChild( headersElem );
200
201 QDomElement contentsElement = doc.createElement( QStringLiteral( "contents" ) );
202 for ( const QgsTableRow &row : mContents )
203 {
204 QDomElement rowElement = doc.createElement( QStringLiteral( "row" ) );
205 for ( int i = 0; i < mColumns.count(); ++i )
206 {
207 if ( i < row.count() )
208 {
209 rowElement.appendChild( QgsXmlUtils::writeVariant( row.at( i ).properties( context ), doc ) );
210 }
211 }
212 contentsElement.appendChild( rowElement );
213 }
214 tableElem.appendChild( contentsElement );
215
216 QDomElement rowHeightsElement = doc.createElement( QStringLiteral( "rowHeights" ) );
217 for ( double height : mRowHeights )
218 {
219 QDomElement rowElement = doc.createElement( QStringLiteral( "row" ) );
220 rowElement.setAttribute( QStringLiteral( "height" ), height );
221 rowHeightsElement.appendChild( rowElement );
222 }
223 tableElem.appendChild( rowHeightsElement );
224
225 QDomElement columnWidthsElement = doc.createElement( QStringLiteral( "columnWidths" ) );
226 for ( double width : mColumnWidths )
227 {
228 QDomElement columnElement = doc.createElement( QStringLiteral( "column" ) );
229 columnElement.setAttribute( QStringLiteral( "width" ), width );
230 columnWidthsElement.appendChild( columnElement );
231 }
232 tableElem.appendChild( columnWidthsElement );
233
234 return true;
235}
236
237bool QgsLayoutItemManualTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
238{
239 if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
240 return false;
241
242 mIncludeHeader = itemElem.attribute( QStringLiteral( "includeHeader" ) ).toInt();
243 //restore header specifications
244 mHeaders.clear();
245 QDomNodeList headersList = itemElem.elementsByTagName( QStringLiteral( "headers" ) );
246 if ( !headersList.isEmpty() )
247 {
248 QDomElement headersElem = headersList.at( 0 ).toElement();
249 QDomNodeList headerEntryList = headersElem.elementsByTagName( QStringLiteral( "header" ) );
250 for ( int i = 0; i < headerEntryList.size(); ++i )
251 {
252 QDomElement headerElem = headerEntryList.at( i ).toElement();
254 header.readXml( headerElem );
255 mHeaders.append( header );
256 }
257 }
258
259 mRowHeights.clear();
260 const QDomNodeList rowHeightNodeList = itemElem.firstChildElement( QStringLiteral( "rowHeights" ) ).childNodes();
261 mRowHeights.reserve( rowHeightNodeList.size() );
262 for ( int r = 0; r < rowHeightNodeList.size(); ++r )
263 {
264 const QDomElement rowHeightElement = rowHeightNodeList.at( r ).toElement();
265 mRowHeights.append( rowHeightElement.attribute( QStringLiteral( "height" ) ).toDouble() );
266 }
267
268 mColumnWidths.clear();
269 const QDomNodeList columnWidthNodeList = itemElem.firstChildElement( QStringLiteral( "columnWidths" ) ).childNodes();
270 mColumnWidths.reserve( columnWidthNodeList.size() );
271 for ( int r = 0; r < columnWidthNodeList.size(); ++r )
272 {
273 const QDomElement columnWidthElement = columnWidthNodeList.at( r ).toElement();
274 mColumnWidths.append( columnWidthElement.attribute( QStringLiteral( "width" ) ).toDouble() );
275 }
276
277 QgsTableContents newContents;
278 const QDomElement contentsElement = itemElem.firstChildElement( QStringLiteral( "contents" ) );
279 const QDomNodeList rowNodeList = contentsElement.childNodes();
280 newContents.reserve( rowNodeList.size() );
281 for ( int r = 0; r < rowNodeList.size(); ++r )
282 {
283 QgsTableRow row;
284 const QDomElement rowElement = rowNodeList.at( r ).toElement();
285 const QDomNodeList cellNodeList = rowElement.childNodes();
286 row.reserve( cellNodeList.size() );
287 for ( int c = 0; c < cellNodeList.size(); ++c )
288 {
289 const QDomElement cellElement = cellNodeList.at( c ).toElement();
290 QgsTableCell newCell;
291 newCell.setProperties( QgsXmlUtils::readVariant( cellElement ).toMap(), context );
292 row << newCell;
293 }
294 newContents << row;
295 }
296 setTableContents( newContents );
297
298 emit changed();
299 return true;
300}
301
303{
305 return false;
306
307 QMap<int, double> newHeights;
308 for ( auto it = mMaxRowHeightMap.constBegin(); it != mMaxRowHeightMap.constEnd(); ++it )
309 {
310 // first row in mMaxRowHeightMap corresponds to header, which we ignore here
311 const int row = it.key() - 1;
312 const double presetHeight = mRowHeights.value( row );
313 double thisRowHeight = it.value();
314 if ( presetHeight > 0 )
315 thisRowHeight = presetHeight;
316 newHeights.insert( row + 1, thisRowHeight );
317 }
318 mMaxRowHeightMap = newHeights;
319 return true;
320}
321
323{
324// if ( mHeaders.value( column ).)
326}
327
329{
330 if ( mContents.value( row ).value( column ).textFormat().isValid() )
331 return mContents.value( row ).value( column ).textFormat();
332
333 return QgsLayoutTable::textFormatForCell( row, column );
334}
335
336Qt::Alignment QgsLayoutItemManualTable::horizontalAlignmentForCell( int row, int column ) const
337{
338 if ( row < mContents.size() && column < mContents.at( row ).size() )
339 return mContents.value( row ).value( column ).horizontalAlignment();
340
341 return QgsLayoutTable::horizontalAlignmentForCell( row, column );
342}
343
344Qt::Alignment QgsLayoutItemManualTable::verticalAlignmentForCell( int row, int column ) const
345{
346 if ( row < mContents.size() && column < mContents.at( row ).size() )
347 return mContents.value( row ).value( column ).verticalAlignment();
348
349 return QgsLayoutTable::verticalAlignmentForCell( row, column );
350}
351
352int QgsLayoutItemManualTable::rowSpan( int row, int column ) const
353{
354 if ( row < mContents.size() && column < mContents.at( row ).size() )
355 return mContents.value( row ).value( column ).rowSpan();
356 return 1;
357}
358
359int QgsLayoutItemManualTable::columnSpan( int row, int column ) const
360{
361 if ( row < mContents.size() && column < mContents.at( row ).size() )
362 return mContents.value( row ).value( column ).columnSpan();
363 return 1;
364}
365
366void QgsLayoutItemManualTable::refreshColumns()
367{
368 // refresh columns
370 if ( !mContents.empty() )
371 {
372 int colIndex = 0;
373 const QgsTableRow &firstRow = mContents[ 0 ];
374 columns.reserve( firstRow.size() );
375 for ( const QgsTableCell &cell : firstRow )
376 {
377 ( void )cell;
378 QgsLayoutTableColumn newCol( mHeaders.value( colIndex ).heading() );
379 newCol.setWidth( mColumnWidths.value( colIndex ) );
380 columns << newCol;
381 colIndex++;
382 }
383 }
385}
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.
int rowSpan(int row, int column) const override
Returns the row span for the cell a row, column.
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.
int columnSpan(int row, int column) const override
Returns the column span for the cell a row, column.
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:49
A context for numeric formats.
A store for object properties.
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.
void setProperties(const QVariantMap &properties, const QgsReadWriteContext &context)
Sets the properties for the cell.
Container for all settings relating to text rendering.
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.
QVector< QgsTableCell > QgsTableRow
A row of table cells.