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