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