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