QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslayouttable.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayouttable.cpp
3  ------------------
4  begin : November 2017
5  copyright : (C) 2017 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 "qgsexpressionutils.h"
20 #include "qgslayouttable.h"
21 #include "qgslayout.h"
22 #include "qgslayoututils.h"
23 #include "qgslayouttablecolumn.h"
24 #include "qgssymbollayerutils.h"
25 #include "qgslayoutframe.h"
26 #include "qgsfontutils.h"
27 #include "qgssettings.h"
29 #include "qgstextrenderer.h"
30 
31 //
32 // QgsLayoutTableStyle
33 //
34 
35 bool QgsLayoutTableStyle::writeXml( QDomElement &styleElem, QDomDocument &doc ) const
36 {
37  Q_UNUSED( doc )
38  styleElem.setAttribute( QStringLiteral( "cellBackgroundColor" ), QgsSymbolLayerUtils::encodeColor( cellBackgroundColor ) );
39  styleElem.setAttribute( QStringLiteral( "enabled" ), enabled );
40  return true;
41 }
42 
43 bool QgsLayoutTableStyle::readXml( const QDomElement &styleElem )
44 {
45  cellBackgroundColor = QgsSymbolLayerUtils::decodeColor( styleElem.attribute( QStringLiteral( "cellBackgroundColor" ), QStringLiteral( "255,255,255,255" ) ) );
46  enabled = ( styleElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
47  return true;
48 }
49 
50 
51 //
52 // QgsLayoutTable
53 //
54 
56  : QgsLayoutMultiFrame( layout )
57 {
58  initStyles();
59 }
60 
62 {
63  mColumns.clear();
64  mSortColumns.clear();
65 
66  qDeleteAll( mCellStyles );
67  mCellStyles.clear();
68 }
69 
70 bool QgsLayoutTable::writePropertiesToElement( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const
71 {
72  elem.setAttribute( QStringLiteral( "cellMargin" ), QString::number( mCellMargin ) );
73  elem.setAttribute( QStringLiteral( "emptyTableMode" ), QString::number( static_cast< int >( mEmptyTableMode ) ) );
74  elem.setAttribute( QStringLiteral( "emptyTableMessage" ), mEmptyTableMessage );
75  elem.setAttribute( QStringLiteral( "showEmptyRows" ), mShowEmptyRows );
76 
77  QDomElement headerElem = doc.createElement( QStringLiteral( "headerTextFormat" ) );
78  const QDomElement headerTextElem = mHeaderTextFormat.writeXml( doc, context );
79  headerElem.appendChild( headerTextElem );
80  elem.appendChild( headerElem );
81  elem.setAttribute( QStringLiteral( "headerHAlignment" ), QString::number( static_cast< int >( mHeaderHAlignment ) ) );
82  elem.setAttribute( QStringLiteral( "headerMode" ), QString::number( static_cast< int >( mHeaderMode ) ) );
83 
84  QDomElement contentElem = doc.createElement( QStringLiteral( "contentTextFormat" ) );
85  const QDomElement contentTextElem = mContentTextFormat.writeXml( doc, context );
86  contentElem.appendChild( contentTextElem );
87  elem.appendChild( contentElem );
88  elem.setAttribute( QStringLiteral( "gridStrokeWidth" ), QString::number( mGridStrokeWidth ) );
89  elem.setAttribute( QStringLiteral( "gridColor" ), QgsSymbolLayerUtils::encodeColor( mGridColor ) );
90  elem.setAttribute( QStringLiteral( "horizontalGrid" ), mHorizontalGrid );
91  elem.setAttribute( QStringLiteral( "verticalGrid" ), mVerticalGrid );
92  elem.setAttribute( QStringLiteral( "showGrid" ), mShowGrid );
93  elem.setAttribute( QStringLiteral( "backgroundColor" ), QgsSymbolLayerUtils::encodeColor( mBackgroundColor ) );
94  elem.setAttribute( QStringLiteral( "wrapBehavior" ), QString::number( static_cast< int >( mWrapBehavior ) ) );
95 
96  // display columns
97  QDomElement displayColumnsElem = doc.createElement( QStringLiteral( "displayColumns" ) );
98  for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
99  {
100  QDomElement columnElem = doc.createElement( QStringLiteral( "column" ) );
101  column.writeXml( columnElem, doc );
102  displayColumnsElem.appendChild( columnElem );
103  }
104  elem.appendChild( displayColumnsElem );
105  // sort columns
106  QDomElement sortColumnsElem = doc.createElement( QStringLiteral( "sortColumns" ) );
107  for ( const QgsLayoutTableColumn &column : std::as_const( mSortColumns ) )
108  {
109  QDomElement columnElem = doc.createElement( QStringLiteral( "column" ) );
110  column.writeXml( columnElem, doc );
111  sortColumnsElem.appendChild( columnElem );
112  }
113  elem.appendChild( sortColumnsElem );
114 
115 
116  //cell styles
117  QDomElement stylesElem = doc.createElement( QStringLiteral( "cellStyles" ) );
118  QMap< CellStyleGroup, QString >::const_iterator it = mCellStyleNames.constBegin();
119  for ( ; it != mCellStyleNames.constEnd(); ++it )
120  {
121  QString styleName = it.value();
122  QDomElement styleElem = doc.createElement( styleName );
123  QgsLayoutTableStyle *style = mCellStyles.value( it.key() );
124  if ( style )
125  {
126  style->writeXml( styleElem, doc );
127  stylesElem.appendChild( styleElem );
128  }
129  }
130  elem.appendChild( stylesElem );
131  return true;
132 }
133 
134 bool QgsLayoutTable::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
135 {
136  mEmptyTableMode = QgsLayoutTable::EmptyTableMode( itemElem.attribute( QStringLiteral( "emptyTableMode" ), QStringLiteral( "0" ) ).toInt() );
137  mEmptyTableMessage = itemElem.attribute( QStringLiteral( "emptyTableMessage" ), tr( "No matching records" ) );
138  mShowEmptyRows = itemElem.attribute( QStringLiteral( "showEmptyRows" ), QStringLiteral( "0" ) ).toInt();
139 
140  const QDomElement headerTextFormat = itemElem.firstChildElement( QStringLiteral( "headerTextFormat" ) );
141  if ( !headerTextFormat.isNull() )
142  {
143  QDomNodeList textFormatNodeList = headerTextFormat.elementsByTagName( QStringLiteral( "text-style" ) );
144  QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
145  mHeaderTextFormat.readXml( textFormatElem, context );
146  }
147  else
148  {
149  QFont headerFont;
150  if ( !QgsFontUtils::setFromXmlChildNode( headerFont, itemElem, QStringLiteral( "headerFontProperties" ) ) )
151  {
152  headerFont.fromString( itemElem.attribute( QStringLiteral( "headerFont" ), QString() ) );
153  }
154  QColor headerFontColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "headerFontColor" ), QStringLiteral( "0,0,0,255" ) ) );
156  if ( headerFont.pointSizeF() > 0 )
157  {
158  mHeaderTextFormat.setSize( headerFont.pointSizeF() );
160  }
161  else if ( headerFont.pixelSize() > 0 )
162  {
163  mHeaderTextFormat.setSize( headerFont.pixelSize() );
165  }
167  }
168 
169  mHeaderHAlignment = QgsLayoutTable::HeaderHAlignment( itemElem.attribute( QStringLiteral( "headerHAlignment" ), QStringLiteral( "0" ) ).toInt() );
170  mHeaderMode = QgsLayoutTable::HeaderMode( itemElem.attribute( QStringLiteral( "headerMode" ), QStringLiteral( "0" ) ).toInt() );
171 
172  const QDomElement contentTextFormat = itemElem.firstChildElement( QStringLiteral( "contentTextFormat" ) );
173  if ( !contentTextFormat.isNull() )
174  {
175  QDomNodeList textFormatNodeList = contentTextFormat.elementsByTagName( QStringLiteral( "text-style" ) );
176  QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
177  mContentTextFormat.readXml( textFormatElem, context );
178  }
179  else
180  {
181  QFont contentFont;
182  if ( !QgsFontUtils::setFromXmlChildNode( contentFont, itemElem, QStringLiteral( "contentFontProperties" ) ) )
183  {
184  contentFont.fromString( itemElem.attribute( QStringLiteral( "contentFont" ), QString() ) );
185  }
186  QColor contentFontColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "contentFontColor" ), QStringLiteral( "0,0,0,255" ) ) );
188  if ( contentFont.pointSizeF() > 0 )
189  {
190  mContentTextFormat.setSize( contentFont.pointSizeF() );
192  }
193  else if ( contentFont.pixelSize() > 0 )
194  {
195  mContentTextFormat.setSize( contentFont.pixelSize() );
197  }
199  }
200 
201  mCellMargin = itemElem.attribute( QStringLiteral( "cellMargin" ), QStringLiteral( "1.0" ) ).toDouble();
202  mGridStrokeWidth = itemElem.attribute( QStringLiteral( "gridStrokeWidth" ), QStringLiteral( "0.5" ) ).toDouble();
203  mHorizontalGrid = itemElem.attribute( QStringLiteral( "horizontalGrid" ), QStringLiteral( "1" ) ).toInt();
204  mVerticalGrid = itemElem.attribute( QStringLiteral( "verticalGrid" ), QStringLiteral( "1" ) ).toInt();
205  mShowGrid = itemElem.attribute( QStringLiteral( "showGrid" ), QStringLiteral( "1" ) ).toInt();
206  mGridColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridColor" ), QStringLiteral( "0,0,0,255" ) ) );
207  mBackgroundColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "backgroundColor" ), QStringLiteral( "255,255,255,0" ) ) );
208  mWrapBehavior = QgsLayoutTable::WrapBehavior( itemElem.attribute( QStringLiteral( "wrapBehavior" ), QStringLiteral( "0" ) ).toInt() );
209 
210  //restore display column specifications
211  mColumns.clear();
212  QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
213  if ( !columnsList.isEmpty() )
214  {
215  QDomElement columnsElem = columnsList.at( 0 ).toElement();
216  QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
217  for ( int i = 0; i < columnEntryList.size(); ++i )
218  {
219  QDomElement columnElem = columnEntryList.at( i ).toElement();
220  QgsLayoutTableColumn column;
221  column.readXml( columnElem );
222  mColumns.append( column );
223  }
224  }
225  // sort columns
226  mSortColumns.clear();
227  QDomNodeList sortColumnsList = itemElem.elementsByTagName( QStringLiteral( "sortColumns" ) );
228  if ( !sortColumnsList.isEmpty() )
229  {
230  QDomElement columnsElem = sortColumnsList.at( 0 ).toElement();
231  QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
232  for ( int i = 0; i < columnEntryList.size(); ++i )
233  {
234  QDomElement columnElem = columnEntryList.at( i ).toElement();
235  QgsLayoutTableColumn column;
236  column.readXml( columnElem );
237  mSortColumns.append( column );
238  }
239  }
240  else
241  {
242  // backward compatibility for QGIS < 3.14
243  // copy the display columns if sortByRank > 0 and then, sort them by rank
245  std::copy_if( mColumns.begin(), mColumns.end(), std::back_inserter( mSortColumns ), []( const QgsLayoutTableColumn & col ) {return col.sortByRank() > 0;} );
246  std::sort( mSortColumns.begin(), mSortColumns.end(), []( const QgsLayoutTableColumn & a, const QgsLayoutTableColumn & b ) {return a.sortByRank() < b.sortByRank();} );
248  }
249 
250  //restore cell styles
251  QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral( "cellStyles" ) );
252  if ( !stylesList.isEmpty() )
253  {
254  QDomElement stylesElem = stylesList.at( 0 ).toElement();
255 
256  QMap< CellStyleGroup, QString >::const_iterator it = mCellStyleNames.constBegin();
257  for ( ; it != mCellStyleNames.constEnd(); ++it )
258  {
259  QString styleName = it.value();
260  QDomNodeList styleList = stylesElem.elementsByTagName( styleName );
261  if ( !styleList.isEmpty() )
262  {
263  QDomElement styleElem = styleList.at( 0 ).toElement();
264  QgsLayoutTableStyle *style = mCellStyles.value( it.key() );
265  if ( style )
266  style->readXml( styleElem );
267  }
268  }
269  }
270 
271  emit changed();
272  return true;
273 }
274 
276 {
277  return mTableSize;
278 }
279 
281 {
284 }
285 
286 int QgsLayoutTable::rowsVisible( QgsRenderContext &context, double frameHeight, int firstRow, bool includeHeader, bool includeEmptyRows ) const
287 {
288  //calculate header height
289  double headerHeight = 0;
290  if ( includeHeader )
291  {
292  headerHeight = mMaxRowHeightMap.value( 0 ) + 2 * ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 ) + 2 * mCellMargin;
293  }
294  else
295  {
296  //frame has no header text, just the stroke
297  headerHeight = ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 );
298  }
299 
300  //remaining height available for content rows
301  double contentHeight = frameHeight - headerHeight;
302 
303  double gridHeight = ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 );
304 
305  int currentRow = firstRow;
306  while ( contentHeight > 0 && currentRow <= mTableContents.count() )
307  {
308  double currentRowHeight = mMaxRowHeightMap.value( currentRow + 1 ) + gridHeight + 2 * mCellMargin;
309  contentHeight -= currentRowHeight;
310  currentRow++;
311  }
312 
313  if ( includeEmptyRows && contentHeight > 0 )
314  {
315  const QFontMetricsF emptyRowContentFontMetrics = QgsTextRenderer::fontMetrics( context, mContentTextFormat, QgsTextRenderer::FONT_WORKAROUND_SCALE );
316  double rowHeight = ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 ) + 2 * mCellMargin + emptyRowContentFontMetrics.ascent() / context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters ) / QgsTextRenderer::FONT_WORKAROUND_SCALE;
317  currentRow += std::max( std::floor( contentHeight / rowHeight ), 0.0 );
318  }
319 
320  return currentRow - firstRow - 1;
321 }
322 
323 int QgsLayoutTable::rowsVisible( QgsRenderContext &context, int frameIndex, int firstRow, bool includeEmptyRows ) const
324 {
325  //get frame extent
326  if ( frameIndex >= frameCount() )
327  {
328  return 0;
329  }
330  QRectF frameExtent = frame( frameIndex )->extent();
331 
332  bool includeHeader = false;
335  {
336  includeHeader = true;
337  }
338  return rowsVisible( context, frameExtent.height(), firstRow, includeHeader, includeEmptyRows );
339 }
340 
341 QPair<int, int> QgsLayoutTable::rowRange( QgsRenderContext &context, const int frameIndex ) const
342 {
343  //calculate row height
344  if ( frameIndex >= frameCount() )
345  {
346  //bad frame index
347  return qMakePair( 0, 0 );
348  }
349 
350  //loop through all previous frames to calculate how many rows are visible in each
351  //as the entire height of a frame may not be utilized for content rows
352  int rowsAlreadyShown = 0;
353  for ( int idx = 0; idx < frameIndex; ++idx )
354  {
355  rowsAlreadyShown += rowsVisible( context, idx, rowsAlreadyShown, false );
356  }
357 
358  //using zero based indexes
359  int firstVisible = std::min( rowsAlreadyShown, static_cast<int>( mTableContents.length() ) );
360  int possibleRowsVisible = rowsVisible( context, frameIndex, rowsAlreadyShown, false );
361  int lastVisible = std::min( firstVisible + possibleRowsVisible, static_cast<int>( mTableContents.length() ) );
362 
363  return qMakePair( firstVisible, lastVisible );
364 }
365 
366 void QgsLayoutTable::render( QgsLayoutItemRenderContext &context, const QRectF &, const int frameIndex )
367 {
368  bool emptyTable = mTableContents.length() == 0;
369  if ( emptyTable && mEmptyTableMode == QgsLayoutTable::HideTable )
370  {
371  //empty table set to hide table mode, so don't draw anything
372  return;
373  }
374 
375  if ( !mLayout->renderContext().isPreviewRender() )
376  {
377  //exporting composition, so force an attribute refresh
378  //we do this in case vector layer has changed via an external source (e.g., another database user)
380  }
381 
382  const bool prevTextFormatScaleFlag = context.renderContext().testFlag( Qgis::RenderContextFlag::ApplyScalingWorkaroundForTextRendering );
384 
385  //calculate which rows to show in this frame
386  QPair< int, int > rowsToShow = rowRange( context.renderContext(), frameIndex );
387 
388  double gridSizeX = mShowGrid && mVerticalGrid ? mGridStrokeWidth : 0;
389  double gridSizeY = mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0;
390  double cellHeaderHeight = mMaxRowHeightMap[0] + 2 * mCellMargin;
392  QRectF cell;
393 
394  //calculate whether a header is required
395  bool drawHeader = ( ( mHeaderMode == QgsLayoutTable::FirstFrame && frameIndex < 1 )
397  //calculate whether drawing table contents is required
398  bool drawContents = !( emptyTable && mEmptyTableMode == QgsLayoutTable::ShowMessage );
399 
400  int numberRowsToDraw = rowsToShow.second - rowsToShow.first;
401  int numberEmptyRows = 0;
402  if ( drawContents && mShowEmptyRows )
403  {
404  numberRowsToDraw = rowsVisible( context.renderContext(), frameIndex, rowsToShow.first, true );
405  numberEmptyRows = numberRowsToDraw - rowsToShow.second + rowsToShow.first;
406  }
407  bool mergeCells = false;
408  if ( emptyTable && mEmptyTableMode == QgsLayoutTable::ShowMessage )
409  {
410  //draw a merged row for the empty table message
411  numberRowsToDraw++;
412  rowsToShow.second++;
413  mergeCells = true;
414  }
415 
416  QPainter *p = context.renderContext().painter();
417  QgsScopedQPainterState painterState( p );
418  // painter is scaled to dots, so scale back to layout units
419  p->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() );
420 
421  //draw the text
422  p->setPen( Qt::SolidLine );
423 
424  double currentX = gridSizeX;
425  double currentY = gridSizeY;
426  if ( drawHeader )
427  {
428  //draw the headers
429  int col = 0;
430  for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
431  {
432  std::unique_ptr< QgsExpressionContextScope > headerCellScope = std::make_unique< QgsExpressionContextScope >();
433  headerCellScope->setVariable( QStringLiteral( "column_number" ), col + 1, true );
434  QgsExpressionContextScopePopper popper( context.renderContext().expressionContext(), headerCellScope.release() );
435 
436  const QgsTextFormat headerFormat = textFormatForHeader( col );
437  //draw background
438  p->save();
439  p->setPen( Qt::NoPen );
440  p->setBrush( backgroundColor( -1, col ) );
441  p->drawRect( QRectF( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, cellHeaderHeight ) );
442  p->restore();
443 
444  currentX += mCellMargin;
445 
446  cell = QRectF( currentX, currentY, mMaxColumnWidthMap[col], cellHeaderHeight );
447 
448  //calculate alignment of header
450  switch ( mHeaderHAlignment )
451  {
452  case FollowColumn:
453  headerAlign = QgsTextRenderer::convertQtHAlignment( column.hAlignment() );
454  break;
455  case HeaderLeft:
456  headerAlign = QgsTextRenderer::AlignLeft;
457  break;
458  case HeaderCenter:
459  headerAlign = QgsTextRenderer::AlignCenter;
460  break;
461  case HeaderRight:
462  headerAlign = QgsTextRenderer::AlignRight;
463  break;
464  }
465 
466  const QRectF textCell = QRectF( currentX, currentY + mCellMargin, mMaxColumnWidthMap[col], cellHeaderHeight - 2 * mCellMargin );
467 
468  const QStringList str = column.heading().split( '\n' );
469 
470  // scale to dots
471  {
473  QgsTextRenderer::drawText( QRectF( textCell.left() * context.renderContext().scaleFactor(),
474  textCell.top() * context.renderContext().scaleFactor(),
475  textCell.width() * context.renderContext().scaleFactor(),
476  textCell.height() * context.renderContext().scaleFactor() ), 0,
477  headerAlign, str, context.renderContext(), headerFormat, true, QgsTextRenderer::AlignVCenter,
478  mWrapBehavior == WrapText ? Qgis::TextRendererFlag::WrapLines : Qgis::TextRendererFlags()
479  );
480  }
481 
482  currentX += mMaxColumnWidthMap[ col ];
483  currentX += mCellMargin;
484  currentX += gridSizeX;
485  col++;
486  }
487 
488  currentY += cellHeaderHeight;
489  currentY += gridSizeY;
490  }
491 
492  //now draw the body cells
493  int rowsDrawn = 0;
494  if ( drawContents )
495  {
496  //draw the attribute values
497  for ( int row = rowsToShow.first; row < rowsToShow.second; ++row )
498  {
499  rowsDrawn++;
500  currentX = gridSizeX;
501  int col = 0;
502 
503  //calculate row height
504  double rowHeight = mMaxRowHeightMap[row + 1] + 2 * mCellMargin;
505 
506  for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
507  {
508  ( void )column;
509  const QRectF fullCell( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, rowHeight );
510  //draw background
511  p->save();
512  p->setPen( Qt::NoPen );
513  p->setBrush( backgroundColor( row, col ) );
514  p->drawRect( fullCell );
515  p->restore();
516 
517  // currentY = gridSize;
518  currentX += mCellMargin;
519 
520  QVariant cellContents = mTableContents.at( row ).at( col );
521  const QString localizedString { QgsExpressionUtils::toLocalizedString( cellContents ) };
522  const QStringList str = localizedString.split( '\n' );
523 
524  QgsTextFormat cellFormat = textFormatForCell( row, col );
526  cellFormat.updateDataDefinedProperties( context.renderContext() );
527 
528  p->save();
529  p->setClipRect( fullCell );
530  const QRectF textCell = QRectF( currentX, currentY + mCellMargin, mMaxColumnWidthMap[col], rowHeight - 2 * mCellMargin );
531 
532  const QgsConditionalStyle style = conditionalCellStyle( row, col );
533  QColor foreColor = cellFormat.color();
534  if ( style.textColor().isValid() )
535  foreColor = style.textColor();
536 
537  cellFormat.setColor( foreColor );
538 
539  // scale to dots
540  {
542  QgsTextRenderer::drawText( QRectF( textCell.left() * context.renderContext().scaleFactor(),
543  textCell.top() * context.renderContext().scaleFactor(),
544  textCell.width() * context.renderContext().scaleFactor(),
545  textCell.height() * context.renderContext().scaleFactor() ), 0,
546  QgsTextRenderer::convertQtHAlignment( horizontalAlignmentForCell( row, col ) ), str, context.renderContext(), cellFormat, true,
548  mWrapBehavior == WrapText ? Qgis::TextRendererFlag::WrapLines : Qgis::TextRendererFlags() );
549  }
550  p->restore();
551 
552  currentX += mMaxColumnWidthMap[ col ];
553  currentX += mCellMargin;
554  currentX += gridSizeX;
555  col++;
556  }
557  currentY += rowHeight;
558  currentY += gridSizeY;
559  }
560  }
561 
562  if ( numberRowsToDraw > rowsDrawn )
563  {
564  p->save();
565  p->setPen( Qt::NoPen );
566 
567  //draw background of empty rows
568  for ( int row = rowsDrawn; row < numberRowsToDraw; ++row )
569  {
570  currentX = gridSizeX;
571  int col = 0;
572 
573  if ( mergeCells )
574  {
575  p->setBrush( backgroundColor( row + 10000, 0 ) );
576  p->drawRect( QRectF( gridSizeX, currentY, mTableSize.width() - 2 * gridSizeX, cellBodyHeightForEmptyRows ) );
577  }
578  else
579  {
580  for ( const QgsLayoutTableColumn &column : std::as_const( mColumns ) )
581  {
582  Q_UNUSED( column )
583 
584  //draw background
585 
586  //we use a bit of a hack here - since we don't want these extra blank rows to match the firstrow/lastrow rule, add 10000 to row number
587  p->setBrush( backgroundColor( row + 10000, col ) );
588  p->drawRect( QRectF( currentX, currentY, mMaxColumnWidthMap[col] + 2 * mCellMargin, cellBodyHeightForEmptyRows ) );
589 
590  // currentY = gridSize;
591  currentX += mMaxColumnWidthMap[ col ] + 2 * mCellMargin;
592  currentX += gridSizeX;
593  col++;
594  }
595  }
596  currentY += cellBodyHeightForEmptyRows + gridSizeY;
597  }
598  p->restore();
599  }
600 
601  //and the borders
602  if ( mShowGrid )
603  {
604  QPen gridPen;
605  gridPen.setWidthF( mGridStrokeWidth );
606  gridPen.setColor( mGridColor );
607  gridPen.setJoinStyle( Qt::MiterJoin );
608  p->setPen( gridPen );
609  if ( mHorizontalGrid )
610  {
611  drawHorizontalGridLines( context, rowsToShow.first, rowsToShow.second + numberEmptyRows, drawHeader );
612  }
613  if ( mVerticalGrid )
614  {
615  drawVerticalGridLines( context, mMaxColumnWidthMap, rowsToShow.first, rowsToShow.second + numberEmptyRows, drawHeader, mergeCells );
616  }
617  }
618 
619  //special case - no records and table is set to ShowMessage mode
620  if ( emptyTable && mEmptyTableMode == QgsLayoutTable::ShowMessage )
621  {
622  double messageX = gridSizeX + mCellMargin;
623  double messageY = gridSizeY + ( drawHeader ? cellHeaderHeight + gridSizeY : 0 );
624  cell = QRectF( messageX, messageY, mTableSize.width() - messageX, cellBodyHeightForEmptyRows );
625 
626  // scale to dots
627  {
629  QgsTextRenderer::drawText( QRectF( cell.left() * context.renderContext().scaleFactor(),
630  cell.top() * context.renderContext().scaleFactor(),
631  cell.width() * context.renderContext().scaleFactor(),
632  cell.height() * context.renderContext().scaleFactor() ), 0,
634  }
635  }
636 
638 }
639 
640 void QgsLayoutTable::setCellMargin( const double margin )
641 {
642  if ( qgsDoubleNear( margin, mCellMargin ) )
643  {
644  return;
645  }
646 
647  mCellMargin = margin;
648 
649  //since spacing has changed, we need to recalculate the table size
651 
652  emit changed();
653 }
654 
656 {
657  if ( mode == mEmptyTableMode )
658  {
659  return;
660  }
661 
662  mEmptyTableMode = mode;
663 
664  //since appearance has changed, we need to recalculate the table size
666 
667  emit changed();
668 }
669 
670 void QgsLayoutTable::setEmptyTableMessage( const QString &message )
671 {
672  if ( message == mEmptyTableMessage )
673  {
674  return;
675  }
676 
677  mEmptyTableMessage = message;
678 
679  //since message has changed, we need to recalculate the table size
681 
682  emit changed();
683 }
684 
685 void QgsLayoutTable::setShowEmptyRows( const bool showEmpty )
686 {
687  if ( showEmpty == mShowEmptyRows )
688  {
689  return;
690  }
691 
692  mShowEmptyRows = showEmpty;
693  update();
694  emit changed();
695 }
696 
697 void QgsLayoutTable::setHeaderFont( const QFont &font )
698 {
699  mHeaderTextFormat.setFont( font );
700  if ( font.pointSizeF() > 0 )
701  {
702  mHeaderTextFormat.setSize( font.pointSizeF() );
704  }
705  else if ( font.pixelSize() > 0 )
706  {
707  mHeaderTextFormat.setSize( font.pixelSize() );
709  }
710 
711  //since font attributes have changed, we need to recalculate the table size
713 
714  emit changed();
715 }
716 
718 {
719  return mHeaderTextFormat.toQFont();
720 }
721 
722 void QgsLayoutTable::setHeaderFontColor( const QColor &color )
723 {
724  if ( color == mHeaderTextFormat.color() )
725  {
726  return;
727  }
728 
729  mHeaderTextFormat.setColor( color );
730  update();
731 
732  emit changed();
733 }
734 
736 {
737  return mHeaderTextFormat.color();
738 }
739 
741 {
742  mHeaderTextFormat = format;
743 
744  //since font attributes have changed, we need to recalculate the table size
746 
747  emit changed();
748 }
749 
751 {
752  return mHeaderTextFormat;
753 }
754 
756 {
757  if ( alignment == mHeaderHAlignment )
758  {
759  return;
760  }
761 
762  mHeaderHAlignment = alignment;
763  update();
764 
765  emit changed();
766 }
767 
769 {
770  if ( mode == mHeaderMode )
771  {
772  return;
773  }
774 
775  mHeaderMode = mode;
777 
778  emit changed();
779 }
780 
781 void QgsLayoutTable::setContentFont( const QFont &font )
782 {
783  mContentTextFormat.setFont( font );
784  if ( font.pointSizeF() > 0 )
785  {
786  mContentTextFormat.setSize( font.pointSizeF() );
788  }
789  else if ( font.pixelSize() > 0 )
790  {
791  mContentTextFormat.setSize( font.pixelSize() );
793  }
794 
795  //since font attributes have changed, we need to recalculate the table size
797 
798  emit changed();
799 }
800 
802 {
803  return mContentTextFormat.toQFont();
804 }
805 
806 void QgsLayoutTable::setContentFontColor( const QColor &color )
807 {
808  if ( color == mContentTextFormat.color() )
809  {
810  return;
811  }
812 
813  mContentTextFormat.setColor( color );
814  update();
815 
816  emit changed();
817 }
818 
820 {
821  return mContentTextFormat.color();
822 }
823 
825 {
826  mContentTextFormat = format;
827 
828  //since spacing has changed, we need to recalculate the table size
830 
831  emit changed();
832 }
833 
835 {
836  return mContentTextFormat;
837 }
838 
839 void QgsLayoutTable::setShowGrid( const bool showGrid )
840 {
841  if ( showGrid == mShowGrid )
842  {
843  return;
844  }
845 
847  //since grid spacing has changed, we need to recalculate the table size
849 
850  emit changed();
851 }
852 
853 void QgsLayoutTable::setGridStrokeWidth( const double width )
854 {
855  if ( qgsDoubleNear( width, mGridStrokeWidth ) )
856  {
857  return;
858  }
859 
860  mGridStrokeWidth = width;
861  //since grid spacing has changed, we need to recalculate the table size
863 
864  emit changed();
865 }
866 
867 void QgsLayoutTable::setGridColor( const QColor &color )
868 {
869  if ( color == mGridColor )
870  {
871  return;
872  }
873 
874  mGridColor = color;
875  update();
876 
877  emit changed();
878 }
879 
880 void QgsLayoutTable::setHorizontalGrid( const bool horizontalGrid )
881 {
883  {
884  return;
885  }
886 
888  //since grid spacing has changed, we need to recalculate the table size
890 
891  emit changed();
892 }
893 
894 void QgsLayoutTable::setVerticalGrid( const bool verticalGrid )
895 {
896  if ( verticalGrid == mVerticalGrid )
897  {
898  return;
899  }
900 
902  //since grid spacing has changed, we need to recalculate the table size
904 
905  emit changed();
906 }
907 
908 void QgsLayoutTable::setBackgroundColor( const QColor &color )
909 {
910  if ( color == mBackgroundColor )
911  {
912  return;
913  }
914 
915  mBackgroundColor = color;
916  update();
917 
918  emit changed();
919 }
920 
922 {
923  if ( behavior == mWrapBehavior )
924  {
925  return;
926  }
927 
928  mWrapBehavior = behavior;
930 
931  emit changed();
932 }
933 
935 {
936  //remove existing columns
937  mColumns = columns;
938 
939  // backward compatibility
940  // test if sorting is provided with the columns and call setSortColumns in such case
941  QgsLayoutTableSortColumns newSortColumns;
943  std::copy_if( mColumns.begin(), mColumns.end(), std::back_inserter( newSortColumns ), []( const QgsLayoutTableColumn & col ) {return col.sortByRank() > 0;} );
944  if ( !newSortColumns.isEmpty() )
945  {
946  std::sort( newSortColumns.begin(), newSortColumns.end(), []( const QgsLayoutTableColumn & a, const QgsLayoutTableColumn & b ) {return a.sortByRank() < b.sortByRank();} );
947  setSortColumns( newSortColumns );
948  }
950 }
951 
953 {
955 }
956 
958 {
959  if ( mCellStyles.contains( group ) )
960  delete mCellStyles.take( group );
961 
962  mCellStyles.insert( group, new QgsLayoutTableStyle( style ) );
963 }
964 
966 {
967  if ( !mCellStyles.contains( group ) )
968  return nullptr;
969 
970  return mCellStyles.value( group );
971 }
972 
973 QMap<int, QString> QgsLayoutTable::headerLabels() const
974 {
975  QMap<int, QString> headers;
976 
977  int i = 0;
978  for ( const QgsLayoutTableColumn &col : std::as_const( mColumns ) )
979  {
980  headers.insert( i, col.heading() );
981  i++;
982  }
983  return headers;
984 }
985 
987 {
988  std::unique_ptr< QgsExpressionContextScope > cellScope = std::make_unique< QgsExpressionContextScope >();
989  cellScope->setVariable( QStringLiteral( "row_number" ), row + 1, true );
990  cellScope->setVariable( QStringLiteral( "column_number" ), column + 1, true );
991  return cellScope.release();
992 }
993 
995 {
996  return QgsConditionalStyle();
997 }
998 
999 QSizeF QgsLayoutTable::fixedFrameSize( const int frameIndex ) const
1000 {
1001  Q_UNUSED( frameIndex )
1002  return QSizeF( mTableSize.width(), 0 );
1003 }
1004 
1005 QSizeF QgsLayoutTable::minFrameSize( const int frameIndex ) const
1006 {
1009 
1010  double height = 0;
1013  {
1014  //header required, force frame to be high enough for header
1015  for ( int col = 0; col < mColumns.size(); ++ col )
1016  {
1018  }
1019  }
1020  return QSizeF( 0, height );
1021 }
1022 
1024 {
1025  mMaxColumnWidthMap.clear();
1026  mMaxRowHeightMap.clear();
1027  mTableContents.clear();
1028 
1029  //get new contents
1030  if ( !getTableContents( mTableContents ) )
1031  {
1032  return;
1033  }
1034 }
1035 
1037 {
1038  mTableSize = QSizeF( totalWidth(), totalHeight() );
1040 }
1041 
1042 void QgsLayoutTable::initStyles()
1043 {
1044  mCellStyles.insert( OddColumns, new QgsLayoutTableStyle() );
1045  mCellStyles.insert( EvenColumns, new QgsLayoutTableStyle() );
1046  mCellStyles.insert( OddRows, new QgsLayoutTableStyle() );
1047  mCellStyles.insert( EvenRows, new QgsLayoutTableStyle() );
1048  mCellStyles.insert( FirstColumn, new QgsLayoutTableStyle() );
1049  mCellStyles.insert( LastColumn, new QgsLayoutTableStyle() );
1050  mCellStyles.insert( HeaderRow, new QgsLayoutTableStyle() );
1051  mCellStyles.insert( FirstRow, new QgsLayoutTableStyle() );
1052  mCellStyles.insert( LastRow, new QgsLayoutTableStyle() );
1053 
1054  mCellStyleNames.insert( OddColumns, QStringLiteral( "oddColumns" ) );
1055  mCellStyleNames.insert( EvenColumns, QStringLiteral( "evenColumns" ) );
1056  mCellStyleNames.insert( OddRows, QStringLiteral( "oddRows" ) );
1057  mCellStyleNames.insert( EvenRows, QStringLiteral( "evenRows" ) );
1058  mCellStyleNames.insert( FirstColumn, QStringLiteral( "firstColumn" ) );
1059  mCellStyleNames.insert( LastColumn, QStringLiteral( "lastColumn" ) );
1060  mCellStyleNames.insert( HeaderRow, QStringLiteral( "headerRow" ) );
1061  mCellStyleNames.insert( FirstRow, QStringLiteral( "firstRow" ) );
1062  mCellStyleNames.insert( LastRow, QStringLiteral( "lastRow" ) );
1063 }
1064 
1066 {
1067  mMaxColumnWidthMap.clear();
1068 
1069  //total number of cells (rows + 1 for header)
1070  int cols = mColumns.count();
1071  int cells = cols * ( mTableContents.count() + 1 );
1072  QVector< double > widths( cells );
1073 
1074  double currentCellTextWidth;
1075 
1078 
1079  //first, go through all the column headers and calculate the sizes
1080  int i = 0;
1081  for ( const QgsLayoutTableColumn &col : std::as_const( mColumns ) )
1082  {
1083  if ( col.width() > 0 )
1084  {
1085  //column has manually specified width
1086  widths[i] = col.width();
1087  }
1088  else if ( mHeaderMode != QgsLayoutTable::NoHeaders )
1089  {
1090  std::unique_ptr< QgsExpressionContextScope > headerCellScope = std::make_unique< QgsExpressionContextScope >();
1091  headerCellScope->setVariable( QStringLiteral( "column_number" ), i + 1, true );
1092  QgsExpressionContextScopePopper popper( context.expressionContext(), headerCellScope.release() );
1093 
1094  //column width set to automatic, so check content size
1095  const QStringList multiLineSplit = col.heading().split( '\n' );
1096  currentCellTextWidth = QgsTextRenderer::textWidth( context, textFormatForHeader( i ), multiLineSplit ) / context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
1097  widths[i] = currentCellTextWidth;
1098  }
1099  else
1100  {
1101  widths[i] = 0.0;
1102  }
1103  i++;
1104  }
1105 
1106  //next, go through all the table contents and calculate the sizes
1107  QgsLayoutTableContents::const_iterator rowIt = mTableContents.constBegin();
1108  int row = 1;
1109  for ( ; rowIt != mTableContents.constEnd(); ++rowIt )
1110  {
1111  QgsLayoutTableRow::const_iterator colIt = rowIt->constBegin();
1112  int col = 0;
1113  for ( ; colIt != rowIt->constEnd(); ++colIt )
1114  {
1115  if ( mColumns.at( col ).width() <= 0 )
1116  {
1117  //column width set to automatic, so check content size
1118  const QStringList multiLineSplit = QgsExpressionUtils::toLocalizedString( *colIt ).split( '\n' );
1119 
1120  QgsTextFormat cellFormat = textFormatForCell( row - 1, col );
1121  QgsExpressionContextScopePopper popper( context.expressionContext(), scopeForCell( row - 1, col ) );
1122  cellFormat.updateDataDefinedProperties( context );
1123 
1124  currentCellTextWidth = QgsTextRenderer::textWidth( context, cellFormat, multiLineSplit ) / context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
1125  widths[ row * cols + col ] = currentCellTextWidth;
1126  }
1127  else
1128  {
1129  widths[ row * cols + col ] = 0;
1130  }
1131 
1132  col++;
1133  }
1134  row++;
1135  }
1136 
1137  //calculate maximum
1138  for ( int col = 0; col < cols; ++col )
1139  {
1140  double maxColWidth = 0;
1141  for ( int row = 0; row < mTableContents.count() + 1; ++row )
1142  {
1143  maxColWidth = std::max( widths[ row * cols + col ], maxColWidth );
1144  }
1145  mMaxColumnWidthMap.insert( col, maxColWidth );
1146  }
1147 
1148  return true;
1149 }
1150 
1152 {
1153  mMaxRowHeightMap.clear();
1154 
1155  //total number of cells (rows + 1 for header)
1156  int cols = mColumns.count();
1157  int cells = cols * ( mTableContents.count() + 1 );
1158  QVector< double > heights( cells );
1159 
1162 
1163  //first, go through all the column headers and calculate the sizes
1164  int i = 0;
1165  for ( const QgsLayoutTableColumn &col : std::as_const( mColumns ) )
1166  {
1167  std::unique_ptr< QgsExpressionContextScope > headerCellScope = std::make_unique< QgsExpressionContextScope >();
1168  headerCellScope->setVariable( QStringLiteral( "column_number" ), i + 1, true );
1169  QgsExpressionContextScopePopper popper( context.expressionContext(), headerCellScope.release() );
1170 
1171  const QgsTextFormat cellFormat = textFormatForHeader( i );
1173  //height
1175  {
1176  heights[i] = 0;
1177  }
1178  else
1179  {
1180  heights[i] = QgsTextRenderer::textHeight( context,
1181  cellFormat,
1182  QStringList() << col.heading(), QgsTextRenderer::Rect,
1183  nullptr,
1184  mWrapBehavior == WrapText ? Qgis::TextRendererFlag::WrapLines : Qgis::TextRendererFlags(),
1186  )
1188  - headerDescentMm;
1189  }
1190  i++;
1191  }
1192 
1193  //next, go through all the table contents and calculate the sizes
1194  QgsLayoutTableContents::const_iterator rowIt = mTableContents.constBegin();
1195  int row = 1;
1196  for ( ; rowIt != mTableContents.constEnd(); ++rowIt )
1197  {
1198  QgsLayoutTableRow::const_iterator colIt = rowIt->constBegin();
1199  int i = 0;
1200  for ( ; colIt != rowIt->constEnd(); ++colIt )
1201  {
1202  QgsTextFormat cellFormat = textFormatForCell( row - 1, i );
1203  QgsExpressionContextScopePopper popper( context.expressionContext(), scopeForCell( row - 1, i ) );
1204  cellFormat.updateDataDefinedProperties( context );
1206  const QString localizedString { QgsExpressionUtils::toLocalizedString( *colIt ) };
1207 
1208  heights[ row * cols + i ] = QgsTextRenderer::textHeight( context,
1209  cellFormat,
1210  QStringList() << localizedString.split( '\n' ),
1212  nullptr,
1213  mWrapBehavior == WrapText ? Qgis::TextRendererFlag::WrapLines : Qgis::TextRendererFlags(),
1215  ) / context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters ) - contentDescentMm;
1216 
1217  i++;
1218  }
1219  row++;
1220  }
1221 
1222  //calculate maximum
1223  for ( int row = 0; row < mTableContents.count() + 1; ++row )
1224  {
1225  double maxRowHeight = 0;
1226  for ( int col = 0; col < cols; ++col )
1227  {
1228  maxRowHeight = std::max( heights[ row * cols + col ], maxRowHeight );
1229  }
1230  mMaxRowHeightMap.insert( row, maxRowHeight );
1231  }
1232 
1233  return true;
1234 }
1235 
1237 {
1238  //check how much space each column needs
1239  if ( !calculateMaxColumnWidths() )
1240  {
1241  return 0;
1242  }
1243 
1244  //adapt frame to total width
1245  double totalWidth = 0;
1246  QMap<int, double>::const_iterator maxColWidthIt = mMaxColumnWidthMap.constBegin();
1247  for ( ; maxColWidthIt != mMaxColumnWidthMap.constEnd(); ++maxColWidthIt )
1248  {
1249  totalWidth += maxColWidthIt.value();
1250  }
1251  totalWidth += ( 2 * mMaxColumnWidthMap.size() * mCellMargin );
1252  totalWidth += ( mMaxColumnWidthMap.size() + 1 ) * ( mShowGrid && mVerticalGrid ? mGridStrokeWidth : 0 );
1253 
1254  return totalWidth;
1255 }
1256 
1258 {
1259  //check how much space each row needs
1260  if ( !calculateMaxRowHeights() )
1261  {
1262  return 0;
1263  }
1264 
1265  double height = 0;
1266 
1269 
1270  //loop through all existing frames to calculate how many rows are visible in each
1271  //as the entire height of a frame may not be utilized for content rows
1272  int rowsAlreadyShown = 0;
1273  int numberExistingFrames = frameCount();
1274  int rowsVisibleInLastFrame = 0;
1275  double heightOfLastFrame = 0;
1276  for ( int idx = 0; idx < numberExistingFrames; ++idx )
1277  {
1278  bool hasHeader = ( ( mHeaderMode == QgsLayoutTable::FirstFrame && idx == 0 )
1280  heightOfLastFrame = frame( idx )->rect().height();
1281  rowsVisibleInLastFrame = rowsVisible( context, heightOfLastFrame, rowsAlreadyShown, hasHeader, false );
1282  rowsAlreadyShown += rowsVisibleInLastFrame;
1283  height += heightOfLastFrame;
1284  if ( rowsAlreadyShown >= mTableContents.length() )
1285  {
1286  //shown entire contents of table, nothing remaining
1287  return height;
1288  }
1289  }
1290 
1291  //calculate how many rows left to show
1292  int remainingRows = mTableContents.length() - rowsAlreadyShown;
1293 
1294  if ( remainingRows <= 0 )
1295  {
1296  //no remaining rows
1297  return height;
1298  }
1299 
1301  {
1302  QgsLayoutItemPage *page = mLayout->pageCollection()->page( mLayout->pageCollection()->pageCount() - 1 );
1303  if ( page )
1304  heightOfLastFrame = page->sizeWithUnits().height();
1305  }
1306 
1307  bool hasHeader = ( ( mHeaderMode == QgsLayoutTable::FirstFrame && numberExistingFrames < 1 )
1309 
1310  int numberFramesMissing = 0;
1311  while ( remainingRows > 0 )
1312  {
1313  numberFramesMissing++;
1314 
1315  rowsVisibleInLastFrame = rowsVisible( context, heightOfLastFrame, rowsAlreadyShown, hasHeader, false );
1316  if ( rowsVisibleInLastFrame < 1 )
1317  {
1318  //if no rows are visible in the last frame, calculation of missing frames
1319  //is impossible. So just return total height of existing frames
1320  return height;
1321  }
1322 
1323  rowsAlreadyShown += rowsVisibleInLastFrame;
1324  remainingRows = mTableContents.length() - rowsAlreadyShown;
1325  }
1326 
1327  //rows remain unshown -- how many extra frames would we need to complete the table?
1328  //assume all added frames are same size as final frame
1329  height += heightOfLastFrame * numberFramesMissing;
1330  return height;
1331 }
1332 
1333 void QgsLayoutTable::drawHorizontalGridLines( QgsLayoutItemRenderContext &context, int firstRow, int lastRow, bool drawHeaderLines ) const
1334 {
1335  //horizontal lines
1336  if ( lastRow - firstRow < 1 && !drawHeaderLines )
1337  {
1338  return;
1339  }
1340 
1341  QPainter *painter = context.renderContext().painter();
1342 
1344  double halfGridStrokeWidth = ( mShowGrid ? mGridStrokeWidth : 0 ) / 2.0;
1345  double currentY = 0;
1346  currentY = halfGridStrokeWidth;
1347  if ( drawHeaderLines )
1348  {
1349  painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) );
1350  currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
1351  currentY += mMaxRowHeightMap[0] + 2 * mCellMargin;
1352  }
1353  for ( int row = firstRow; row < lastRow; ++row )
1354  {
1355  painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) );
1356  currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
1357  double rowHeight = row < mTableContents.count() ? mMaxRowHeightMap[row + 1] : cellBodyHeightForEmptyRows;
1358  currentY += ( rowHeight + 2 * mCellMargin );
1359  }
1360  painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF( mTableSize.width() - halfGridStrokeWidth, currentY ) );
1361 }
1362 
1363 QColor QgsLayoutTable::backgroundColor( int row, int column ) const
1364 {
1365  QColor color = mBackgroundColor;
1366  if ( QgsLayoutTableStyle *style = mCellStyles.value( OddColumns ) )
1367  if ( style->enabled && column % 2 == 0 )
1368  color = style->cellBackgroundColor;
1369  if ( QgsLayoutTableStyle *style = mCellStyles.value( EvenColumns ) )
1370  if ( style->enabled && column % 2 == 1 )
1371  color = style->cellBackgroundColor;
1372  if ( QgsLayoutTableStyle *style = mCellStyles.value( OddRows ) )
1373  if ( style->enabled && row % 2 == 0 )
1374  color = style->cellBackgroundColor;
1375  if ( QgsLayoutTableStyle *style = mCellStyles.value( EvenRows ) )
1376  if ( style->enabled && row % 2 == 1 )
1377  color = style->cellBackgroundColor;
1378  if ( QgsLayoutTableStyle *style = mCellStyles.value( FirstColumn ) )
1379  if ( style->enabled && column == 0 )
1380  color = style->cellBackgroundColor;
1381  if ( QgsLayoutTableStyle *style = mCellStyles.value( LastColumn ) )
1382  if ( style->enabled && column == mColumns.count() - 1 )
1383  color = style->cellBackgroundColor;
1384  if ( QgsLayoutTableStyle *style = mCellStyles.value( HeaderRow ) )
1385  if ( style->enabled && row == -1 )
1386  color = style->cellBackgroundColor;
1387  if ( QgsLayoutTableStyle *style = mCellStyles.value( FirstRow ) )
1388  if ( style->enabled && row == 0 )
1389  color = style->cellBackgroundColor;
1390  if ( QgsLayoutTableStyle *style = mCellStyles.value( LastRow ) )
1391  if ( style->enabled && row == mTableContents.count() - 1 )
1392  color = style->cellBackgroundColor;
1393 
1394  if ( row >= 0 )
1395  {
1396  QgsConditionalStyle conditionalStyle = conditionalCellStyle( row, column );
1397  if ( conditionalStyle.backgroundColor().isValid() )
1398  color = conditionalStyle.backgroundColor();
1399  }
1400 
1401  return color;
1402 }
1403 
1404 void QgsLayoutTable::drawVerticalGridLines( QgsLayoutItemRenderContext &context, const QMap<int, double> &maxWidthMap, int firstRow, int lastRow, bool hasHeader, bool mergeCells ) const
1405 {
1406  //vertical lines
1407  if ( lastRow - firstRow < 1 && !hasHeader )
1408  {
1409  return;
1410  }
1411 
1412  QPainter *painter = context.renderContext().painter();
1413 
1414  //calculate height of table within frame
1415  double tableHeight = 0;
1416  if ( hasHeader )
1417  {
1418  tableHeight += ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 ) + mCellMargin * 2 + mMaxRowHeightMap[0];
1419  }
1420  tableHeight += ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 );
1421  double headerHeight = tableHeight;
1422 
1424  for ( int row = firstRow; row < lastRow; ++row )
1425  {
1426  double rowHeight = row < mTableContents.count() ? mMaxRowHeightMap[row + 1] : cellBodyHeightForEmptyRows;
1427  tableHeight += rowHeight + ( mShowGrid && mHorizontalGrid ? mGridStrokeWidth : 0 ) + mCellMargin * 2;
1428  }
1429 
1430  double halfGridStrokeWidth = ( mShowGrid && mVerticalGrid ? mGridStrokeWidth : 0 ) / 2.0;
1431  double currentX = halfGridStrokeWidth;
1432  painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
1433  currentX += ( mShowGrid && mVerticalGrid ? mGridStrokeWidth : 0 );
1434  QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
1435  int col = 1;
1436  for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
1437  {
1438  currentX += ( maxColWidthIt.value() + 2 * mCellMargin );
1439  if ( col == maxWidthMap.size() || !mergeCells )
1440  {
1441  painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
1442  }
1443  else if ( hasHeader )
1444  {
1445  painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, headerHeight - halfGridStrokeWidth ) );
1446  }
1447 
1448  currentX += ( mShowGrid && mVerticalGrid ? mGridStrokeWidth : 0 );
1449  col++;
1450  }
1451 }
1452 
1454 {
1456 
1457  //force recalculation of frame rects, so that they are set to the correct
1458  //fixed and minimum frame sizes
1460 }
1461 
1463 {
1464  return ( contents.indexOf( row ) >= 0 );
1465 }
1466 
1468 {
1469  return mContentTextFormat;
1470 }
1471 
1473 {
1474  return mHeaderTextFormat;
1475 }
1476 
1477 Qt::Alignment QgsLayoutTable::horizontalAlignmentForCell( int, int column ) const
1478 {
1479  return mColumns.value( column ).hAlignment();
1480 }
1481 
1482 Qt::Alignment QgsLayoutTable::verticalAlignmentForCell( int, int column ) const
1483 {
1484  return mColumns.value( column ).vAlignment();
1485 }
1486 
QgsLayoutMultiFrame::frame
QgsLayoutFrame * frame(int index) const
Returns the child frame at a specified index from the multiframe.
Definition: qgslayoutmultiframe.cpp:475
QgsLayoutTable::mWrapBehavior
WrapBehavior mWrapBehavior
Definition: qgslayouttable.h:640
QgsLayoutTable::setHeaderMode
void setHeaderMode(HeaderMode mode)
Sets the display mode for headers in the table.
Definition: qgslayouttable.cpp:768
qgsexpressioncontextutils.h
QgsLayoutTableStyle::cellBackgroundColor
QColor cellBackgroundColor
Cell background color.
Definition: qgslayouttable.h:87
QgsLayoutTable::showGrid
bool showGrid() const
Returns whether grid lines are drawn in the table.
Definition: qgslayouttable.h:378
QgsExpressionContextScopePopper
RAII class to pop scope from an expression context on destruction.
Definition: qgsexpressioncontextutils.h:361
QgsLayoutTable::backgroundColor
QColor backgroundColor() const
Returns the color used for the background of the table.
Definition: qgslayouttable.h:462
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:64
QgsLayoutTable::render
void render(QgsLayoutItemRenderContext &context, const QRectF &renderExtent, int frameIndex) override
Renders a portion of the multiframe's content into a render context.
Definition: qgslayouttable.cpp:366
QgsLayoutTableColumns
QVector< QgsLayoutTableColumn > QgsLayoutTableColumns
List of column definitions for a QgsLayoutTable.
Definition: qgslayouttable.h:58
QgsLayoutTable::setHeaderHAlignment
void setHeaderHAlignment(HeaderHAlignment alignment)
Sets the horizontal alignment for table headers.
Definition: qgslayouttable.cpp:755
QgsLayoutTable::headerFontColor
Q_DECL_DEPRECATED QColor headerFontColor() const
Returns the color used to draw header text in the table.
Definition: qgslayouttable.cpp:735
QgsLayoutTable::HeaderHAlignment
HeaderHAlignment
Controls how headers are horizontally aligned in a table.
Definition: qgslayouttable.h:121
QgsTextFormat::setFont
void setFont(const QFont &font)
Sets the font used for rendering text.
Definition: qgstextformat.cpp:207
QgsLayoutItemPage
Item representing the paper in a layout.
Definition: qgslayoutitempage.h:58
QgsLayoutTable::setContentTextFormat
void setContentTextFormat(const QgsTextFormat &format)
Sets the format used to draw content text in the table.
Definition: qgslayouttable.cpp:824
QgsLayoutTable::mTableContents
QgsLayoutTableContents mTableContents
Contents to show in table.
Definition: qgslayouttable.h:630
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsLayoutTable::mHeaderTextFormat
QgsTextFormat mHeaderTextFormat
Definition: qgslayouttable.h:602
QgsLayoutTableContents
QVector< QgsLayoutTableRow > QgsLayoutTableContents
List of QgsLayoutTableRows, representing rows and column cell contents for a QgsLayoutTable.
Definition: qgslayouttable.h:47
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsTextRenderer::convertQtVAlignment
static VAlignment convertQtVAlignment(Qt::Alignment alignment)
Converts a Qt vertical alignment flag to a QgsTextRenderer::VAlignment value.
Definition: qgstextrenderer.cpp:61
QgsLayoutTable::mMaxColumnWidthMap
QMap< int, double > mMaxColumnWidthMap
Map of maximum width for each column.
Definition: qgslayouttable.h:633
qgstextrenderer.h
QgsLayoutTable::rowsVisible
int rowsVisible(QgsRenderContext &context, double frameHeight, int firstRow, bool includeHeader, bool includeEmptyRows) const
Calculates how many content rows would be visible within a frame of the specified height.
Definition: qgslayouttable.cpp:286
QgsLayoutTable::mVerticalGrid
bool mVerticalGrid
True if grid should be shown.
Definition: qgslayouttable.h:618
QgsLayoutTable::CellStyleGroup
CellStyleGroup
Row or column groups for cell styling.
Definition: qgslayouttable.h:161
QgsTextRenderer::AlignCenter
@ AlignCenter
Center align.
Definition: qgstextrenderer.h:61
QgsLayoutTable::~QgsLayoutTable
~QgsLayoutTable() override
Definition: qgslayouttable.cpp:61
QgsLayoutTable::cellStyle
const QgsLayoutTableStyle * cellStyle(CellStyleGroup group) const
Returns the cell style for a cell group.
Definition: qgslayouttable.cpp:965
QgsTextRenderer::AlignRight
@ AlignRight
Right align.
Definition: qgstextrenderer.h:62
QgsLayoutTable::sortColumns
QgsLayoutTableSortColumns & sortColumns()
Returns a reference to the list of QgsLayoutTableSortColumns shown in the table.
Definition: qgslayouttable.h:501
QgsLayoutTableStyle::writeXml
bool writeXml(QDomElement &styleElem, QDomDocument &doc) const
Writes the style's properties to XML for storage.
Definition: qgslayouttable.cpp:35
QgsUnitTypes::RenderPoints
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
qgssymbollayerutils.h
QgsLayoutTable::drawVerticalGridLines
void drawVerticalGridLines(QgsLayoutItemRenderContext &context, const QMap< int, double > &maxWidthMap, int firstRow, int lastRow, bool hasHeader, bool mergeCells=false) const
Draws the vertical grid lines for the table.
Definition: qgslayouttable.cpp:1404
QgsLayoutTable::columns
QgsLayoutTableColumns & columns()
Returns a reference to the list of QgsLayoutTableColumns shown in the table.
Definition: qgslayouttable.h:482
QgsLayoutItemRenderContext
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
QgsTextRenderer::fontMetrics
static QFontMetricsF fontMetrics(QgsRenderContext &context, const QgsTextFormat &format, double scaleFactor=1.0)
Returns the font metrics for the given text format, when rendered in the specified render context.
Definition: qgstextrenderer.cpp:280
QgsRenderContext::testFlag
bool testFlag(Qgis::RenderContextFlag flag) const
Check whether a particular flag is enabled.
Definition: qgsrendercontext.cpp:229
QgsLayoutTable::mEmptyTableMode
EmptyTableMode mEmptyTableMode
Behavior for empty tables.
Definition: qgslayouttable.h:587
QgsLayoutTable::setGridColor
void setGridColor(const QColor &color)
Sets the color used for grid lines in the table.
Definition: qgslayouttable.cpp:867
QgsLayoutTable::mHeaderHAlignment
HeaderHAlignment mHeaderHAlignment
Alignment for table headers.
Definition: qgslayouttable.h:597
QgsLayoutTable::mEmptyTableMessage
QString mEmptyTableMessage
String to show in empty tables.
Definition: qgslayouttable.h:590
QgsLayoutTable::setBackgroundColor
void setBackgroundColor(const QColor &color)
Sets the color used for background of table.
Definition: qgslayouttable.cpp:908
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
QgsLayoutTable::OddColumns
@ OddColumns
Style odd numbered columns.
Definition: qgslayouttable.h:163
QgsLayoutTable::setGridStrokeWidth
void setGridStrokeWidth(double width)
Sets the width in mm for grid lines in the table.
Definition: qgslayouttable.cpp:853
QgsLayoutTable::HideTable
@ HideTable
Hides entire table if empty.
Definition: qgslayouttable.h:145
QgsLayoutTable::FirstRow
@ FirstRow
Style first row only.
Definition: qgslayouttable.h:170
QgsLayoutTable::FirstColumn
@ FirstColumn
Style first column only.
Definition: qgslayouttable.h:167
QgsLayoutTable::writePropertiesToElement
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
Definition: qgslayouttable.cpp:70
QgsLayoutMultiFrame
Abstract base class for layout items with the ability to distribute the content to several frames (Qg...
Definition: qgslayoutmultiframe.h:48
qgsfontutils.h
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:266
QgsLayoutTable::setEmptyTableBehavior
void setEmptyTableBehavior(EmptyTableMode mode)
Sets the behavior mode for empty tables with no content rows.
Definition: qgslayouttable.cpp:655
QgsLayoutObject::changed
void changed()
Emitted when the object's properties change.
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
QgsLayoutTable::setShowGrid
void setShowGrid(bool showGrid)
Sets whether grid lines should be drawn in the table.
Definition: qgslayouttable.cpp:839
QgsConditionalStyle
Conditional styling for a rule.
Definition: qgsconditionalstyle.h:120
QgsLayoutItem::sizeWithUnits
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
Definition: qgslayoutitem.h:673
QgsLayoutTable::calculateMaxColumnWidths
virtual bool calculateMaxColumnWidths()
Calculates the maximum width of text shown in columns.
Definition: qgslayouttable.cpp:1065
QgsLayoutTable::mShowGrid
bool mShowGrid
True if grid should be shown.
Definition: qgslayouttable.h:606
QgsLayoutTableColumn::readXml
bool readXml(const QDomElement &columnElem)
Reads the column's properties from xml.
Definition: qgslayouttablecolumn.cpp:50
QgsLayoutTable::textFormatForCell
virtual QgsTextFormat textFormatForCell(int row, int column) const
Returns the text format to use for the cell at the specified row and column.
Definition: qgslayouttable.cpp:1467
QgsLayoutTableSortColumns
QVector< QgsLayoutTableColumn > QgsLayoutTableSortColumns
List of column definitions for sorting a QgsLayoutTable.
Definition: qgslayouttable.h:65
QgsTextRenderer::textHeight
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
Definition: qgstextrenderer.cpp:620
QgsLayoutMultiFrame::ExtendToNextPage
@ ExtendToNextPage
Creates new full page frames on the following page(s) until the entire multiframe content is visible.
Definition: qgslayoutmultiframe.h:104
QgsTextFormat::color
QColor color() const
Returns the color that text will be rendered in.
Definition: qgstextformat.cpp:297
QgsLayoutTable::mCellMargin
double mCellMargin
Margin between cell borders and cell text.
Definition: qgslayouttable.h:584
QgsLayoutTable::contentFontColor
Q_DECL_DEPRECATED QColor contentFontColor() const
Returns the color used to draw text in table body cells.
Definition: qgslayouttable.cpp:819
QgsTextRenderer::Rect
@ Rect
Text within rectangle draw mode.
Definition: qgstextrenderer.h:43
QgsTextRenderer::textWidth
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
Definition: qgstextrenderer.cpp:545
qgslayoutframe.h
QgsLayoutTable::setHeaderFont
Q_DECL_DEPRECATED void setHeaderFont(const QFont &font)
Sets the font used to draw header text in the table.
Definition: qgslayouttable.cpp:697
qgslayoututils.h
QgsLayoutTable::verticalAlignmentForCell
virtual Qt::Alignment verticalAlignmentForCell(int row, int column) const
Returns the vertical alignment to use for the cell at the specified row and column.
Definition: qgslayouttable.cpp:1482
QgsLayoutTable::mSortColumns
QgsLayoutTableSortColumns mSortColumns
Columns to sort the table.
Definition: qgslayouttable.h:627
QgsLayoutUtils::createRenderContextForLayout
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Definition: qgslayoututils.cpp:141
QgsLayoutTable::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
Definition: qgslayouttable.cpp:134
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsTextFormat
Container for all settings relating to text rendering.
Definition: qgstextformat.h:40
QgsTextFormat::setColor
void setColor(const QColor &color)
Sets the color that text will be rendered in.
Definition: qgstextformat.cpp:302
QgsLayoutTable::fixedFrameSize
QSizeF fixedFrameSize(int frameIndex=-1) const override
Returns the fixed size for a frame, if desired.
Definition: qgslayouttable.cpp:999
QgsLayoutTable::HeaderRow
@ HeaderRow
Style header row.
Definition: qgslayouttable.h:169
QgsLayoutTable::FirstFrame
@ FirstFrame
Header shown on first frame only.
Definition: qgslayouttable.h:134
QgsLayoutTable::QgsLayoutTable
QgsLayoutTable(QgsLayout *layout)
Constructor for QgsLayoutTable, belonging to the specified layout.
Definition: qgslayouttable.cpp:55
QgsLayoutMultiFrame::update
void update()
Forces a redraw of all child frames.
Definition: qgslayoutmultiframe.cpp:451
QgsLayoutTable::mGridColor
QColor mGridColor
Color for grid lines.
Definition: qgslayouttable.h:612
QgsLayoutTable::ShowMessage
@ ShowMessage
Shows preset message instead of table contents.
Definition: qgslayouttable.h:146
qgslayouttable.h
QgsLayoutTable::minFrameSize
QSizeF minFrameSize(int frameIndex=-1) const override
Returns the minimum size for a frames, if desired.
Definition: qgslayouttable.cpp:1005
QgsLayoutTable::contents
QgsLayoutTableContents & contents()
Returns the current contents of the table.
Definition: qgslayouttable.h:559
QgsTextFormat::updateDataDefinedProperties
void updateDataDefinedProperties(QgsRenderContext &context)
Updates the format by evaluating current values of data defined properties.
Definition: qgstextformat.cpp:861
QgsLayoutTable::WrapText
@ WrapText
Text which doesn't fit inside the cell is wrapped. Note that this only applies to text in columns wit...
Definition: qgslayouttable.h:155
QgsLayoutTable::verticalGrid
bool verticalGrid() const
Returns whether the grid's vertical lines are drawn in the table.
Definition: qgslayouttable.h:448
QgsLayoutTable::setVerticalGrid
void setVerticalGrid(bool verticalGrid)
Sets whether the grid's vertical lines should be drawn in the table.
Definition: qgslayouttable.cpp:894
QgsLayoutTable::scopeForCell
virtual QgsExpressionContextScope * scopeForCell(int row, int column) const
Creates a new QgsExpressionContextScope for the cell at row, column.
Definition: qgslayouttable.cpp:986
QgsLayoutTable::totalHeight
double totalHeight()
Returns total height of table contents.
Definition: qgslayouttable.cpp:1257
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsLayoutTable::setCellMargin
void setCellMargin(double margin)
Sets the margin distance in mm between cell borders and their contents.
Definition: qgslayouttable.cpp:640
QgsRenderContext::setFlag
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:216
QgsConditionalStyle::backgroundColor
QColor backgroundColor() const
The background color for style.
Definition: qgsconditionalstyle.h:225
Qgis::RenderContextFlag::ApplyScalingWorkaroundForTextRendering
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
QgsLayoutTable::OddRows
@ OddRows
Style odd numbered rows.
Definition: qgslayouttable.h:165
QgsLayoutTable::setHorizontalGrid
void setHorizontalGrid(bool horizontalGrid)
Sets whether the grid's horizontal lines should be drawn in the table.
Definition: qgslayouttable.cpp:880
QgsLayoutFrame::extent
QRectF extent() const
Returns the visible portion of the multi frame's content which is shown in this frame,...
Definition: qgslayoutframe.h:76
QgsLayoutTable::totalSize
QSizeF totalSize() const override
Returns the total size of the multiframe's content, in layout units.
Definition: qgslayouttable.cpp:275
QgsLayoutTable::LastRow
@ LastRow
Style last row only.
Definition: qgslayouttable.h:171
qgsexpressionutils.h
QgsLayoutTable::mGridStrokeWidth
double mGridStrokeWidth
Width of grid lines.
Definition: qgslayouttable.h:609
QgsLayoutTable::NoHeaders
@ NoHeaders
No headers shown for table.
Definition: qgslayouttable.h:136
QgsLayoutTable::getTableContents
virtual bool getTableContents(QgsLayoutTableContents &contents)=0
Fetches the contents used for the cells in the table.
QgsTextRenderer::drawText
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws text within a rectangle using the specified settings.
Definition: qgstextrenderer.cpp:81
QgsLayoutTable::mTableSize
QSizeF mTableSize
Definition: qgslayouttable.h:638
QgsTextRenderer::AlignLeft
@ AlignLeft
Left align.
Definition: qgstextrenderer.h:60
QgsLayoutTable::textFormatForHeader
virtual QgsTextFormat textFormatForHeader(int column) const
Returns the text format to use for the header cell at the specified column.
Definition: qgslayouttable.cpp:1472
QgsLayoutMultiFrame::mResizeMode
ResizeMode mResizeMode
Definition: qgslayoutmultiframe.h:410
QgsLayoutTable::contentTextFormat
QgsTextFormat contentTextFormat() const
Returns the format used to draw content text in the table.
Definition: qgslayouttable.cpp:834
QgsLayoutTable::HeaderRight
@ HeaderRight
Align headers right.
Definition: qgslayouttable.h:126
QgsLayoutTable::HeaderMode
HeaderMode
Controls where headers are shown in the table.
Definition: qgslayouttable.h:132
QgsTextFormat::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgstextformat.cpp:488
QgsTextFormat::toQFont
QFont toQFont() const
Returns a QFont matching the relevant settings from this text format.
Definition: qgstextformat.cpp:758
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1336
QgsLayoutTable::WrapBehavior
WrapBehavior
Controls how long strings in the table are handled.
Definition: qgslayouttable.h:152
QgsLayoutTable::refreshAttributes
virtual void refreshAttributes()
Refreshes the contents shown in the table by querying for new data.
Definition: qgslayouttable.cpp:1023
QgsLayoutTable::recalculateFrameSizes
void recalculateFrameSizes() override
Definition: qgslayouttable.cpp:1036
qgslayout.h
QgsLayoutTable::EvenRows
@ EvenRows
Style even numbered rows.
Definition: qgslayouttable.h:166
QgsLayoutTable::EmptyTableMode
EmptyTableMode
Controls how empty tables are displayed.
Definition: qgslayouttable.h:142
QgsLayoutMultiFrame::recalculateFrameRects
void recalculateFrameRects()
Forces a recalculation of all the associated frame's scene rectangles.
Definition: qgslayoutmultiframe.cpp:227
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsUnitTypes::RenderPixels
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:171
QgsLayoutTable::recalculateTableSize
void recalculateTableSize()
Recalculates and updates the size of the table and all table frames.
Definition: qgslayouttable.cpp:1453
QgsLayoutTable::HeaderCenter
@ HeaderCenter
Align headers to center.
Definition: qgslayouttable.h:125
QgsLayoutMultiFrame::refresh
void refresh() override
Refreshes the multiframe, causing a recalculation of any property overrides.
Definition: qgslayoutmultiframe.cpp:338
QgsLayoutSize::height
double height() const
Returns the height of the size.
Definition: qgslayoutsize.h:90
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:367
QgsLayoutTable::calculateMaxRowHeights
virtual bool calculateMaxRowHeights()
Calculates the maximum height of text shown in rows.
Definition: qgslayouttable.cpp:1151
QgsLayoutTable::setSortColumns
void setSortColumns(const QgsLayoutTableSortColumns &sortColumns)
Replaces the sorting columns in the table with a specified list of QgsLayoutTableSortColumns.
Definition: qgslayouttable.cpp:952
QgsLayoutTable::setShowEmptyRows
void setShowEmptyRows(bool showEmpty)
Sets whether empty rows should be drawn.
Definition: qgslayouttable.cpp:685
QgsLayoutTable::setHeaderFontColor
Q_DECL_DEPRECATED void setHeaderFontColor(const QColor &color)
Sets the color used to draw header text in the table.
Definition: qgslayouttable.cpp:722
QgsLayoutTable::headerLabels
virtual QMap< int, QString > headerLabels() const
Returns the text used in the column headers for the table.
Definition: qgslayouttable.cpp:973
QgsFontUtils::setFromXmlChildNode
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
Definition: qgsfontutils.cpp:400
QgsLayoutItemRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
QgsLayoutTableStyle::enabled
bool enabled
Whether the styling option is enabled.
Definition: qgslayouttable.h:84
QgsLayoutTable::rowRange
QPair< int, int > rowRange(QgsRenderContext &context, int frameIndex) const
Calculates a range of rows which should be visible in a given frame.
Definition: qgslayouttable.cpp:341
QgsLayoutTableStyle
Styling option for a layout table cell.
Definition: qgslayouttable.h:76
QgsLayoutTable::setColumns
void setColumns(const QgsLayoutTableColumns &columns)
Replaces the columns in the table with a specified list of QgsLayoutTableColumns.
Definition: qgslayouttable.cpp:934
QgsLayoutTable::LastColumn
@ LastColumn
Style last column only.
Definition: qgslayouttable.h:168
QgsLayoutTable::mCellStyles
QMap< CellStyleGroup, QgsLayoutTableStyle * > mCellStyles
Definition: qgslayouttable.h:642
QgsLayoutObject::mLayout
QPointer< QgsLayout > mLayout
Definition: qgslayoutobject.h:363
QgsLayoutTable::horizontalGrid
bool horizontalGrid() const
Returns whether the grid's horizontal lines are drawn in the table.
Definition: qgslayouttable.h:429
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
QgsConditionalStyle::textColor
QColor textColor() const
The text color set for style.
Definition: qgsconditionalstyle.h:212
str
#define str(x)
Definition: qgis.cpp:37
QgsLayoutTable::setWrapBehavior
void setWrapBehavior(WrapBehavior behavior)
Sets the wrap behavior for the table, which controls how text within cells is automatically wrapped.
Definition: qgslayouttable.cpp:921
QgsLayoutTable::setCellStyle
void setCellStyle(CellStyleGroup group, const QgsLayoutTableStyle &style)
Sets the cell style for a cell group.
Definition: qgslayouttable.cpp:957
qgslayouttablecolumn.h
QgsLayoutTable::setContentFont
Q_DECL_DEPRECATED void setContentFont(const QFont &font)
Sets the font used to draw text in table body cells.
Definition: qgslayouttable.cpp:781
qgssettings.h
QgsLayoutTable::setHeaderTextFormat
void setHeaderTextFormat(const QgsTextFormat &format)
Sets the format used to draw header text in the table.
Definition: qgslayouttable.cpp:740
QgsLayoutTable::contentsContainsRow
bool contentsContainsRow(const QgsLayoutTableContents &contents, const QgsLayoutTableRow &row) const
Checks whether a table contents contains a given row.
Definition: qgslayouttable.cpp:1462
QgsLayoutTable::headerTextFormat
QgsTextFormat headerTextFormat() const
Returns the format used to draw header text in the table.
Definition: qgslayouttable.cpp:750
qgslayoutpagecollection.h
QgsTextFormat::setSizeUnit
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
Definition: qgstextformat.cpp:269
QgsTextRenderer::AlignVCenter
@ AlignVCenter
Center align.
Definition: qgstextrenderer.h:81
QgsLayoutTable::mMaxRowHeightMap
QMap< int, double > mMaxRowHeightMap
Map of maximum height for each row.
Definition: qgslayouttable.h:636
QgsLayoutMultiFrame::recalculateFrameSizes
virtual void recalculateFrameSizes()
Recalculates the portion of the multiframe item which is shown in each of its component frames.
Definition: qgslayoutmultiframe.cpp:96
QgsLayoutTableStyle::readXml
bool readXml(const QDomElement &styleElem)
Reads the style's properties from XML.
Definition: qgslayouttable.cpp:43
QgsLayoutTableRow
QVector< QVariant > QgsLayoutTableRow
List of QVariants, representing a the contents of a single row in a QgsLayoutTable.
Definition: qgslayouttable.h:30
QgsLayoutTable::conditionalCellStyle
virtual QgsConditionalStyle conditionalCellStyle(int row, int column) const
Returns the conditional style to use for the cell at row, column.
Definition: qgslayouttable.cpp:994
QgsLayoutTable::mColumns
QgsLayoutTableColumns mColumns
Columns to show in table.
Definition: qgslayouttable.h:624
QgsLayoutTableColumn
Stores properties of a column for a QgsLayoutTable.
Definition: qgslayouttablecolumn.h:37
QgsLayoutTable::horizontalAlignmentForCell
virtual Qt::Alignment horizontalAlignmentForCell(int row, int column) const
Returns the horizontal alignment to use for the cell at the specified row and column.
Definition: qgslayouttable.cpp:1477
QgsScopedRenderContextScaleToPixels
Scoped object for temporary scaling of a QgsRenderContext for pixel based rendering.
Definition: qgsrendercontext.h:1292
QgsLayoutTable::FollowColumn
@ FollowColumn
Header uses the same alignment as the column.
Definition: qgslayouttable.h:123
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsTextFormat::setSize
void setSize(double size)
Sets the size for rendered text.
Definition: qgstextformat.cpp:291
QgsLayoutTable::mBackgroundColor
QColor mBackgroundColor
Color for table background.
Definition: qgslayouttable.h:621
QgsLayoutTable::setContentFontColor
Q_DECL_DEPRECATED void setContentFontColor(const QColor &color)
Sets the color used to draw text in table body cells.
Definition: qgslayouttable.cpp:806
QgsLayoutTable::mHeaderMode
HeaderMode mHeaderMode
Header display mode.
Definition: qgslayouttable.h:600
QgsLayoutMultiFrame::frameIndex
int frameIndex(QgsLayoutFrame *frame) const
Returns the index of a frame within the multiframe.
Definition: qgslayoutmultiframe.cpp:484
QgsTextRenderer::convertQtHAlignment
static HAlignment convertQtHAlignment(Qt::Alignment alignment)
Converts a Qt horizontal alignment flag to a QgsTextRenderer::HAlignment value.
Definition: qgstextrenderer.cpp:46
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsLayoutTable::HeaderLeft
@ HeaderLeft
Align headers left.
Definition: qgslayouttable.h:124
QgsLayoutTable::setEmptyTableMessage
void setEmptyTableMessage(const QString &message)
Sets the message for empty tables with no content rows.
Definition: qgslayouttable.cpp:670
QgsLayoutTable::mContentTextFormat
QgsTextFormat mContentTextFormat
Definition: qgslayouttable.h:603
QgsLayoutTable::totalWidth
double totalWidth()
Returns total width of table contents.
Definition: qgslayouttable.cpp:1236
QgsLayoutTable::AllFrames
@ AllFrames
Headers shown on all frames.
Definition: qgslayouttable.h:135
QgsLayoutTable::contentFont
Q_DECL_DEPRECATED QFont contentFont() const
Returns the font used to draw text in table body cells.
Definition: qgslayouttable.cpp:801
QgsTextFormat::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgstextformat.cpp:671
QgsLayoutTable::drawHorizontalGridLines
void drawHorizontalGridLines(QgsLayoutItemRenderContext &context, int firstRow, int lastRow, bool drawHeaderLines) const
Draws the horizontal grid lines for the table.
Definition: qgslayouttable.cpp:1333
QgsLayoutTable::mHorizontalGrid
bool mHorizontalGrid
True if grid should be shown.
Definition: qgslayouttable.h:615
QgsLayoutTable::refresh
void refresh() override
Definition: qgslayouttable.cpp:280
QgsTextRenderer::FONT_WORKAROUND_SCALE
static constexpr double FONT_WORKAROUND_SCALE
Scale factor for upscaling font sizes and downscaling destination painter devices.
Definition: qgstextrenderer.h:260
Qgis::TextRendererFlag::WrapLines
@ WrapLines
Automatically wrap long lines of text.
QgsLayoutMultiFrame::frameCount
int frameCount() const
Returns the number of frames associated with this multiframe.
Definition: qgslayoutmultiframe.h:265
QgsTextRenderer::HAlignment
HAlignment
Horizontal alignment.
Definition: qgstextrenderer.h:58
QgsLayoutTable::EvenColumns
@ EvenColumns
Style even numbered columns.
Definition: qgslayouttable.h:164
QgsLayoutTable::mShowEmptyRows
bool mShowEmptyRows
True if empty rows should be shown in the table.
Definition: qgslayouttable.h:593
QgsLayoutTable::headerFont
Q_DECL_DEPRECATED QFont headerFont() const
Returns the font used to draw header text in the table.
Definition: qgslayouttable.cpp:717