QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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"
20 #include "qgslayoutitemregistry.h"
21 #include "qgslayouttablecolumn.h"
22 #include "qgsnumericformat.h"
23 #include "qgsxmlutils.h"
24 
25 //
26 // QgsLayoutItemManualTable
27 //
28 
30  : QgsLayoutTable( layout )
31 {
34 }
35 
37 {
38  qDeleteAll( mHeaders );
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 
67  for ( const QgsTableRow &row : qgis::as_const( mContents ) )
68  {
69  QgsLayoutTableRow currentRow;
70 
71  for ( int i = 0; i < mColumns.count(); ++i )
72  {
73  if ( i < row.count() )
74  {
75  if ( row.at( i ).numericFormat() )
76  currentRow << row.at( i ).numericFormat()->formatDouble( row.at( i ).content().toDouble(), numericContext );
77  else
78  currentRow << row.at( i ).content().toString();
79  }
80  else
81  {
82  currentRow << QString();
83  }
84  }
85  contents << currentRow;
86  }
87 
89  return true;
90 }
91 
93 {
94  if ( row < 0 || row >= mContents.size() )
95  return QgsConditionalStyle();
96 
97  const QgsTableRow &rowContents = mContents[ row ];
98  if ( column < 0 || column > rowContents.size() )
99  return QgsConditionalStyle();
100 
101  const QgsTableCell &c = rowContents[ column ];
103  if ( c.foregroundColor().isValid() )
104  res.setTextColor( c.foregroundColor() );
105  if ( c.backgroundColor().isValid() )
107 
108  return res;
109 }
110 
112 {
113  mContents = contents;
114 
115  refreshColumns();
117 }
118 
120 {
121  return mContents;
122 }
123 
124 void QgsLayoutItemManualTable::setRowHeights( const QList<double> &heights )
125 {
126  mRowHeights = heights;
127 
129 }
130 
131 void QgsLayoutItemManualTable::setColumnWidths( const QList<double> &widths )
132 {
133  mColumnWidths = widths;
134 
135  refreshColumns();
137 }
138 
140 {
141  return mIncludeHeader;
142 }
143 
145 {
146  mIncludeHeader = included;
147 
148  if ( !mIncludeHeader )
150  else
152  refreshColumns();
154 }
155 
157 {
158  return mHeaders;
159 }
160 
162 {
163  qDeleteAll( mHeaders );
164  mHeaders.clear();
165 
166  mHeaders.append( headers );
167  refreshColumns();
169 }
170 
171 bool QgsLayoutItemManualTable::writePropertiesToElement( QDomElement &tableElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
172 {
173  if ( !QgsLayoutTable::writePropertiesToElement( tableElem, doc, context ) )
174  return false;
175 
176  tableElem.setAttribute( QStringLiteral( "includeHeader" ), mIncludeHeader ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
177 
178  //headers
179  QDomElement headersElem = doc.createElement( QStringLiteral( "headers" ) );
180  for ( QgsLayoutTableColumn *header : mHeaders )
181  {
182  QDomElement headerElem = doc.createElement( QStringLiteral( "header" ) );
183  header->writeXml( headerElem, doc );
184  headersElem.appendChild( headerElem );
185  }
186  tableElem.appendChild( headersElem );
187 
188  QDomElement contentsElement = doc.createElement( QStringLiteral( "contents" ) );
189  for ( const QgsTableRow &row : mContents )
190  {
191  QDomElement rowElement = doc.createElement( QStringLiteral( "row" ) );
192  for ( int i = 0; i < mColumns.count(); ++i )
193  {
194  if ( i < row.count() )
195  {
196  rowElement.appendChild( QgsXmlUtils::writeVariant( row.at( i ).properties( context ), doc ) );
197  }
198  }
199  contentsElement.appendChild( rowElement );
200  }
201  tableElem.appendChild( contentsElement );
202 
203  QDomElement rowHeightsElement = doc.createElement( QStringLiteral( "rowHeights" ) );
204  for ( double height : mRowHeights )
205  {
206  QDomElement rowElement = doc.createElement( QStringLiteral( "row" ) );
207  rowElement.setAttribute( QStringLiteral( "height" ), height );
208  rowHeightsElement.appendChild( rowElement );
209  }
210  tableElem.appendChild( rowHeightsElement );
211 
212  QDomElement columnWidthsElement = doc.createElement( QStringLiteral( "columnWidths" ) );
213  for ( double width : mColumnWidths )
214  {
215  QDomElement columnElement = doc.createElement( QStringLiteral( "column" ) );
216  columnElement.setAttribute( QStringLiteral( "width" ), width );
217  columnWidthsElement.appendChild( columnElement );
218  }
219  tableElem.appendChild( columnWidthsElement );
220 
221  return true;
222 }
223 
224 bool QgsLayoutItemManualTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
225 {
226  if ( !QgsLayoutTable::readPropertiesFromElement( itemElem, doc, context ) )
227  return false;
228 
229  mIncludeHeader = itemElem.attribute( QStringLiteral( "includeHeader" ) ).toInt();
230  //restore header specifications
231  qDeleteAll( mHeaders );
232  mHeaders.clear();
233  QDomNodeList headersList = itemElem.elementsByTagName( QStringLiteral( "headers" ) );
234  if ( !headersList.isEmpty() )
235  {
236  QDomElement headersElem = headersList.at( 0 ).toElement();
237  QDomNodeList headerEntryList = headersElem.elementsByTagName( QStringLiteral( "header" ) );
238  for ( int i = 0; i < headerEntryList.size(); ++i )
239  {
240  QDomElement headerElem = headerEntryList.at( i ).toElement();
242  header->readXml( headerElem );
243  mHeaders.append( header );
244  }
245  }
246 
247  mRowHeights.clear();
248  const QDomNodeList rowHeightNodeList = itemElem.firstChildElement( QStringLiteral( "rowHeights" ) ).childNodes();
249  mRowHeights.reserve( rowHeightNodeList.size() );
250  for ( int r = 0; r < rowHeightNodeList.size(); ++r )
251  {
252  const QDomElement rowHeightElement = rowHeightNodeList.at( r ).toElement();
253  mRowHeights.append( rowHeightElement.attribute( QStringLiteral( "height" ) ).toDouble() );
254  }
255 
256  mColumnWidths.clear();
257  const QDomNodeList columnWidthNodeList = itemElem.firstChildElement( QStringLiteral( "columnWidths" ) ).childNodes();
258  mColumnWidths.reserve( columnWidthNodeList.size() );
259  for ( int r = 0; r < columnWidthNodeList.size(); ++r )
260  {
261  const QDomElement columnWidthElement = columnWidthNodeList.at( r ).toElement();
262  mColumnWidths.append( columnWidthElement.attribute( QStringLiteral( "width" ) ).toDouble() );
263  }
264 
265  QgsTableContents newContents;
266  const QDomElement contentsElement = itemElem.firstChildElement( QStringLiteral( "contents" ) );
267  const QDomNodeList rowNodeList = contentsElement.childNodes();
268  newContents.reserve( rowNodeList.size() );
269  for ( int r = 0; r < rowNodeList.size(); ++r )
270  {
271  QgsTableRow row;
272  const QDomElement rowElement = rowNodeList.at( r ).toElement();
273  const QDomNodeList cellNodeList = rowElement.childNodes();
274  row.reserve( cellNodeList.size() );
275  for ( int c = 0; c < cellNodeList.size(); ++c )
276  {
277  const QDomElement cellElement = cellNodeList.at( c ).toElement();
278  QgsTableCell newCell;
279  newCell.setProperties( QgsXmlUtils::readVariant( cellElement ).toMap(), context );
280  row << newCell;
281  }
282  newContents << row;
283  }
284  setTableContents( newContents );
285 
286  emit changed();
287  return true;
288 }
289 
291 {
293  return false;
294 
295  QMap<int, double> newHeights;
296  for ( auto it = mMaxRowHeightMap.constBegin(); it != mMaxRowHeightMap.constEnd(); ++it )
297  {
298  // first row in mMaxRowHeightMap corresponds to header, which we ignore here
299  const int row = it.key() - 1;
300  const double presetHeight = mRowHeights.value( row );
301  double thisRowHeight = it.value();
302  if ( presetHeight > 0 )
303  thisRowHeight = presetHeight;
304  newHeights.insert( row + 1, thisRowHeight );
305  }
306  mMaxRowHeightMap = newHeights;
307  return true;
308 }
309 
310 void QgsLayoutItemManualTable::refreshColumns()
311 {
312  // refresh columns
314  if ( !mContents.empty() )
315  {
316  int colIndex = 0;
317  const QgsTableRow &firstRow = mContents[ 0 ];
318  columns.reserve( firstRow.size() );
319  for ( const QgsTableCell &cell : firstRow )
320  {
321  ( void )cell;
322  std::unique_ptr< QgsLayoutTableColumn > newCol = qgis::make_unique< QgsLayoutTableColumn >( mHeaders.value( colIndex ) ? mHeaders.value( colIndex )->heading() : QString() );
323  newCol->setWidth( mColumnWidths.value( colIndex ) );
324  columns << newCol.release();
325  colIndex++;
326  }
327  }
328  setColumns( columns );
329 }
QgsLayoutItemManualTable(QgsLayout *layout)
Constructor for QgsLayoutItemManualTable, attached to the specified layout.
The class is used as a container of context for various read/write operations on other objects...
QMap< int, double > mMaxRowHeightMap
Map of maximum height for each row.
QColor backgroundColor() const
Returns the cell&#39;s background color, or an invalid color if a default color should be used for the ba...
Definition: qgstablecell.h:70
bool getTableContents(QgsLayoutTableContents &contents) override
Fetches the contents used for the cells in the table.
virtual bool calculateMaxRowHeights()
Calculates the maximum height of text shown in rows.
void setIncludeTableHeader(bool included)
Sets whether the table includes a header row.
QString displayName() const override
Returns the multiframe display name.
void setTableContents(const QgsTableContents &contents)
Sets the contents of the table.
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
A class to display a table in the print layout, and allow the table to span over multiple frames...
void setHeaders(const QgsLayoutTableColumns &headers)
Replaces the headers in the table with a specified list of QgsLayoutTableColumns. ...
Encapsulates the contents and formatting of a single table cell.
Definition: qgstablecell.h:34
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
QVector< QgsLayoutTableColumn *> QgsLayoutTableColumns
List of column definitions for a QgsLayoutTable.
bool readXml(const QDomElement &columnElem)
Reads the column&#39;s properties from xml.
virtual void refreshAttributes()
Refreshes the contents shown in the table by querying for new data.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void setProperties(const QVariantMap &properties, const QgsReadWriteContext &context)
Sets the properties for the cell.
Stores properties of a column for 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
No headers shown for table.
void setHeaderMode(HeaderMode mode)
Sets the display mode for headers in the table.
bool calculateMaxRowHeights() override
Calculates the maximum height of text shown in rows.
QgsTableContents tableContents() const
Returns the contents of the table.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
const QgsLayout * layout() const
Returns the layout the object is attached to.
Conditional styling for a rule.
void setRowHeights(const QList< double > &heights)
Sets the list of row heights (in millimeters) to use when rendering the table.
QgsLayoutTableColumns & headers()
Returns a reference to the list of headers shown in the table.
QgsConditionalStyle conditionalCellStyle(int row, int column) const override
Returns the conditional style to use for the cell at row, column.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
static QgsLayoutItemManualTable * create(QgsLayout *layout)
Returns a new QgsLayoutItemManualTable for the specified parent layout.
void setBackgroundColor(const QColor &value)
Set the background color for the style.
QIcon icon() const override
Returns the item&#39;s icon.
void setColumnWidths(const QList< double > &widths)
Sets the list of column widths (in millimeters) to use when rendering the table.
QVector< QgsTableRow > QgsTableContents
A set of table rows.
Definition: qgstablecell.h:158
QgsLayoutTableColumns mColumns
Columns to show in table.
QgsLayoutTableContents & contents()
Returns the current contents of the table.
Headers shown on all frames.
A context for numeric formats.
A layout table subclass that displays manually entered (and formatted) content.
QgsLayoutTableColumns & columns()
Returns a reference to the list of QgsLayoutTableColumns shown in the table.
bool includeTableHeader() const
Returns true if the table includes a header row.
void setColumns(const QgsLayoutTableColumns &columns)
Replaces the columns in the table with a specified list of QgsLayoutTableColumns. ...
void changed()
Emitted when the object&#39;s properties change.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
int type() const override
Returns unique multiframe type id.
QColor foregroundColor() const
Returns the cell&#39;s foreground color, or an invalid color if a default color should be used for the fo...
Definition: qgstablecell.h:86
QVector< QgsTableCell > QgsTableRow
A row of table cells.
Definition: qgstablecell.h:149
QVector< QgsLayoutTableRow > QgsLayoutTableContents
List of QgsLayoutTableRows, representing rows and column cell contents for a QgsLayoutTable.
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
QVector< QVariant > QgsLayoutTableRow
List of QVariants, representing a the contents of a single row in a QgsLayoutTable.
void recalculateTableSize()
Recalculates and updates the size of the table and all table frames.
void setTextColor(const QColor &value)
Set the text color for the style.