36 styleElem.setAttribute( QStringLiteral(
"enabled" ),
enabled );
43 enabled = ( styleElem.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" ) );
57 QString defaultFontString = settings.
value( QStringLiteral(
"LayoutDesigner/defaultFont" ), QVariant(),
QgsSettings::Gui ).toString();
58 if ( !defaultFontString.isEmpty() )
78 elem.setAttribute( QStringLiteral(
"cellMargin" ), QString::number(
mCellMargin ) );
79 elem.setAttribute( QStringLiteral(
"emptyTableMode" ), QString::number(
static_cast< int >(
mEmptyTableMode ) ) );
81 elem.setAttribute( QStringLiteral(
"showEmptyRows" ),
mShowEmptyRows );
84 elem.setAttribute( QStringLiteral(
"headerHAlignment" ), QString::number(
static_cast< int >(
mHeaderHAlignment ) ) );
85 elem.setAttribute( QStringLiteral(
"headerMode" ), QString::number(
static_cast< int >(
mHeaderMode ) ) );
88 elem.setAttribute( QStringLiteral(
"gridStrokeWidth" ), QString::number(
mGridStrokeWidth ) );
90 elem.setAttribute( QStringLiteral(
"horizontalGrid" ),
mHorizontalGrid );
91 elem.setAttribute( QStringLiteral(
"verticalGrid" ),
mVerticalGrid );
92 elem.setAttribute( QStringLiteral(
"showGrid" ),
mShowGrid );
94 elem.setAttribute( QStringLiteral(
"wrapBehavior" ), QString::number(
static_cast< int >(
mWrapBehavior ) ) );
97 QDomElement displayColumnsElem = doc.createElement( QStringLiteral(
"displayColumns" ) );
100 QDomElement columnElem = doc.createElement( QStringLiteral(
"column" ) );
101 column.writeXml( columnElem, doc );
102 displayColumnsElem.appendChild( columnElem );
104 elem.appendChild( displayColumnsElem );
106 QDomElement sortColumnsElem = doc.createElement( QStringLiteral(
"sortColumns" ) );
109 QDomElement columnElem = doc.createElement( QStringLiteral(
"column" ) );
110 column.writeXml( columnElem, doc );
111 sortColumnsElem.appendChild( columnElem );
113 elem.appendChild( sortColumnsElem );
117 QDomElement stylesElem = doc.createElement( QStringLiteral(
"cellStyles" ) );
118 QMap< CellStyleGroup, QString >::const_iterator it = mCellStyleNames.constBegin();
119 for ( ; it != mCellStyleNames.constEnd(); ++it )
121 QString styleName = it.value();
122 QDomElement styleElem = doc.createElement( styleName );
127 stylesElem.appendChild( styleElem );
130 elem.appendChild( stylesElem );
137 mEmptyTableMessage = itemElem.attribute( QStringLiteral(
"emptyTableMessage" ), tr(
"No matching records" ) );
138 mShowEmptyRows = itemElem.attribute( QStringLiteral(
"showEmptyRows" ), QStringLiteral(
"0" ) ).toInt();
141 mHeaderFont.fromString( itemElem.attribute( QStringLiteral(
"headerFont" ), QString() ) );
148 mContentFont.fromString( itemElem.attribute( QStringLiteral(
"contentFont" ), QString() ) );
151 mCellMargin = itemElem.attribute( QStringLiteral(
"cellMargin" ), QStringLiteral(
"1.0" ) ).toDouble();
152 mGridStrokeWidth = itemElem.attribute( QStringLiteral(
"gridStrokeWidth" ), QStringLiteral(
"0.5" ) ).toDouble();
153 mHorizontalGrid = itemElem.attribute( QStringLiteral(
"horizontalGrid" ), QStringLiteral(
"1" ) ).toInt();
154 mVerticalGrid = itemElem.attribute( QStringLiteral(
"verticalGrid" ), QStringLiteral(
"1" ) ).toInt();
155 mShowGrid = itemElem.attribute( QStringLiteral(
"showGrid" ), QStringLiteral(
"1" ) ).toInt();
162 QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral(
"displayColumns" ) );
163 if ( !columnsList.isEmpty() )
165 QDomElement columnsElem = columnsList.at( 0 ).toElement();
166 QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral(
"column" ) );
167 for (
int i = 0; i < columnEntryList.size(); ++i )
169 QDomElement columnElem = columnEntryList.at( i ).toElement();
177 QDomNodeList sortColumnsList = itemElem.elementsByTagName( QStringLiteral(
"sortColumns" ) );
178 if ( !sortColumnsList.isEmpty() )
180 QDomElement columnsElem = sortColumnsList.at( 0 ).toElement();
181 QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral(
"column" ) );
182 for (
int i = 0; i < columnEntryList.size(); ++i )
184 QDomElement columnElem = columnEntryList.at( i ).toElement();
201 QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral(
"cellStyles" ) );
202 if ( !stylesList.isEmpty() )
204 QDomElement stylesElem = stylesList.at( 0 ).toElement();
206 QMap< CellStyleGroup, QString >::const_iterator it = mCellStyleNames.constBegin();
207 for ( ; it != mCellStyleNames.constEnd(); ++it )
209 QString styleName = it.value();
210 QDomNodeList styleList = stylesElem.elementsByTagName( styleName );
211 if ( !styleList.isEmpty() )
213 QDomElement styleElem = styleList.at( 0 ).toElement();
239 double headerHeight = 0;
252 double contentHeight = frameHeight - headerHeight;
256 int currentRow = firstRow;
257 while ( contentHeight > 0 && currentRow <=
mTableContents.count() )
260 contentHeight -= currentRowHeight;
264 if ( includeEmptyRows && contentHeight > 0 )
267 currentRow += std::max( std::floor( contentHeight / rowHeight ), 0.0 );
270 return currentRow - firstRow - 1;
282 bool includeHeader =
false;
286 includeHeader =
true;
288 return rowsVisible( frameExtent.height(), firstRow, includeHeader, includeEmptyRows );
297 return qMakePair( 0, 0 );
302 int rowsAlreadyShown = 0;
305 rowsAlreadyShown +=
rowsVisible( idx, rowsAlreadyShown,
false );
309 int firstVisible = std::min( rowsAlreadyShown,
mTableContents.length() );
311 int lastVisible = std::min( firstVisible + possibleRowsVisible,
mTableContents.length() );
313 return qMakePair( firstVisible, lastVisible );
325 if ( !
mLayout->renderContext().isPreviewRender() )
347 int numberRowsToDraw = rowsToShow.second - rowsToShow.first;
348 int numberEmptyRows = 0;
352 numberEmptyRows = numberRowsToDraw - rowsToShow.second + rowsToShow.first;
354 bool mergeCells =
false;
369 p->setPen( Qt::SolidLine );
371 double currentX = gridSizeX;
372 double currentY = gridSizeY;
381 p->setPen( Qt::NoPen );
391 Qt::AlignmentFlag headerAlign = Qt::AlignLeft;
395 headerAlign = column.hAlignment();
398 headerAlign = Qt::AlignLeft;
401 headerAlign = Qt::AlignHCenter;
404 headerAlign = Qt::AlignRight;
410 QString str = column.heading();
411 Qt::TextFlag textFlag =
static_cast< Qt::TextFlag
>( Qt::TextDontClip );
414 str = wrappedText( str, column.width(),
mHeaderFont );
420 currentX += gridSizeX;
424 currentY += cellHeaderHeight;
425 currentY += gridSizeY;
433 for (
int row = rowsToShow.first; row < rowsToShow.second; ++row )
436 currentX = gridSizeX;
448 p->setPen( Qt::NoPen );
450 p->drawRect( fullCell );
457 QString str = cellContents.toString();
461 Qt::TextFlag textFlag =
static_cast< Qt::TextFlag
>( Qt::TextDontClip );
468 p->setClipRect( fullCell );
481 currentX += gridSizeX;
484 currentY += rowHeight;
485 currentY += gridSizeY;
489 if ( numberRowsToDraw > rowsDrawn )
492 p->setPen( Qt::NoPen );
495 for (
int row = rowsDrawn; row < numberRowsToDraw; ++row )
497 currentX = gridSizeX;
503 p->drawRect( QRectF( gridSizeX, currentY,
mTableSize.width() - 2 * gridSizeX, cellBodyHeight ) );
519 currentX += gridSizeX;
523 currentY += cellBodyHeight + gridSizeY;
534 gridPen.setJoinStyle( Qt::MiterJoin );
535 p->setPen( gridPen );
550 double messageY = gridSizeY + ( drawHeader ? cellHeaderHeight + gridSizeY : 0 );
551 cell = QRectF( messageX, messageY,
mTableSize.width() - messageX, cellBodyHeight );
801 if ( !newSortColumns.isEmpty() )
832 QMap<int, QString> headers;
837 headers.insert( i, col.heading() );
863 return QSizeF( 0, height );
885 void QgsLayoutTable::initStyles()
897 mCellStyleNames.insert(
OddColumns, QStringLiteral(
"oddColumns" ) );
898 mCellStyleNames.insert(
EvenColumns, QStringLiteral(
"evenColumns" ) );
899 mCellStyleNames.insert(
OddRows, QStringLiteral(
"oddRows" ) );
900 mCellStyleNames.insert(
EvenRows, QStringLiteral(
"evenRows" ) );
901 mCellStyleNames.insert(
FirstColumn, QStringLiteral(
"firstColumn" ) );
902 mCellStyleNames.insert(
LastColumn, QStringLiteral(
"lastColumn" ) );
903 mCellStyleNames.insert(
HeaderRow, QStringLiteral(
"headerRow" ) );
904 mCellStyleNames.insert(
FirstRow, QStringLiteral(
"firstRow" ) );
905 mCellStyleNames.insert(
LastRow, QStringLiteral(
"lastRow" ) );
915 QVector< double > widths( cells );
917 double currentCellTextWidth;
923 if ( col.width() > 0 )
926 widths[i] = col.width();
931 QStringList multiLineSplit = col.heading().split(
'\n' );
932 currentCellTextWidth = 0;
933 const auto constMultiLineSplit = multiLineSplit;
934 for (
const QString &line : constMultiLineSplit )
938 widths[i] = currentCellTextWidth;
948 QgsLayoutTableContents::const_iterator rowIt =
mTableContents.constBegin();
952 QgsLayoutTableRow::const_iterator colIt = rowIt->constBegin();
954 for ( ; colIt != rowIt->constEnd(); ++colIt )
956 if (
mColumns.at( col ).width() <= 0 )
959 QStringList multiLineSplit = ( *colIt ).toString().split(
'\n' );
960 currentCellTextWidth = 0;
961 const auto constMultiLineSplit = multiLineSplit;
962 for (
const QString &line : constMultiLineSplit )
966 widths[ row * cols + col ] = currentCellTextWidth;
970 widths[ row * cols + col ] = 0;
979 for (
int col = 0; col < cols; ++col )
981 double maxColWidth = 0;
984 maxColWidth = std::max( widths[ row * cols + col ], maxColWidth );
999 QVector< double > heights( cells );
1023 QgsLayoutTableContents::const_iterator rowIt =
mTableContents.constBegin();
1027 QgsLayoutTableRow::const_iterator colIt = rowIt->constBegin();
1029 for ( ; colIt != rowIt->constEnd(); ++colIt )
1049 double maxRowHeight = 0;
1050 for (
int col = 0; col < cols; ++col )
1052 maxRowHeight = std::max( heights[ row * cols + col ], maxRowHeight );
1093 int rowsAlreadyShown = 0;
1095 int rowsVisibleInLastFrame = 0;
1096 double heightOfLastFrame = 0;
1097 for (
int idx = 0; idx < numberExistingFrames; ++idx )
1101 heightOfLastFrame =
frame( idx )->rect().height();
1102 rowsVisibleInLastFrame =
rowsVisible( heightOfLastFrame, rowsAlreadyShown, hasHeader,
false );
1103 rowsAlreadyShown += rowsVisibleInLastFrame;
1104 height += heightOfLastFrame;
1115 if ( remainingRows <= 0 )
1131 int numberFramesMissing = 0;
1132 while ( remainingRows > 0 )
1134 numberFramesMissing++;
1136 rowsVisibleInLastFrame =
rowsVisible( heightOfLastFrame, rowsAlreadyShown, hasHeader,
false );
1137 if ( rowsVisibleInLastFrame < 1 )
1144 rowsAlreadyShown += rowsVisibleInLastFrame;
1150 height += heightOfLastFrame * numberFramesMissing;
1157 if ( lastRow - firstRow < 1 && !drawHeaderLines )
1164 double currentY = 0;
1165 currentY = halfGridStrokeWidth;
1166 if ( drawHeaderLines )
1168 painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF(
mTableSize.width() - halfGridStrokeWidth, currentY ) );
1172 for (
int row = firstRow; row < lastRow; ++row )
1174 painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF(
mTableSize.width() - halfGridStrokeWidth, currentY ) );
1179 painter->drawLine( QPointF( halfGridStrokeWidth, currentY ), QPointF(
mTableSize.width() - halfGridStrokeWidth, currentY ) );
1182 bool QgsLayoutTable::textRequiresWrapping(
const QString &text,
double columnWidth,
const QFont &font )
const
1187 QStringList multiLineSplit = text.split(
'\n' );
1188 double currentTextWidth = 0;
1189 const auto constMultiLineSplit = multiLineSplit;
1190 for (
const QString &line : constMultiLineSplit )
1195 return ( currentTextWidth > columnWidth );
1198 QString QgsLayoutTable::wrappedText(
const QString &value,
double columnWidth,
const QFont &font )
const
1200 QStringList lines = value.split(
'\n' );
1201 QStringList outLines;
1202 const auto constLines = lines;
1203 for (
const QString &line : constLines )
1205 if ( textRequiresWrapping( line, columnWidth, font ) )
1208 QStringList words = line.split(
' ' );
1209 QStringList linesToProcess;
1210 QString wordsInCurrentLine;
1211 const auto constWords = words;
1212 for (
const QString &word : constWords )
1214 if ( textRequiresWrapping( word, columnWidth, font ) )
1217 if ( !wordsInCurrentLine.isEmpty() )
1218 linesToProcess << wordsInCurrentLine;
1219 wordsInCurrentLine.clear();
1220 linesToProcess << word;
1224 if ( !wordsInCurrentLine.isEmpty() )
1225 wordsInCurrentLine.append(
' ' );
1226 wordsInCurrentLine.append( word );
1229 if ( !wordsInCurrentLine.isEmpty() )
1230 linesToProcess << wordsInCurrentLine;
1232 const auto constLinesToProcess = linesToProcess;
1233 for (
const QString &line : constLinesToProcess )
1235 QString remainingText = line;
1236 int lastPos = remainingText.lastIndexOf(
' ' );
1237 while ( lastPos > -1 )
1240 if ( !textRequiresWrapping( remainingText, columnWidth, font ) )
1245 if ( !textRequiresWrapping( remainingText.left( lastPos ), columnWidth, font ) )
1247 outLines << remainingText.left( lastPos );
1248 remainingText = remainingText.mid( lastPos + 1 );
1251 lastPos = remainingText.lastIndexOf(
' ', lastPos - 1 );
1253 outLines << remainingText;
1262 return outLines.join( QStringLiteral(
"\n" ) );
1269 if ( style->enabled && column % 2 == 0 )
1270 color = style->cellBackgroundColor;
1272 if ( style->enabled && column % 2 == 1 )
1273 color = style->cellBackgroundColor;
1275 if ( style->enabled && row % 2 == 0 )
1276 color = style->cellBackgroundColor;
1278 if ( style->enabled && row % 2 == 1 )
1279 color = style->cellBackgroundColor;
1281 if ( style->enabled && column == 0 )
1282 color = style->cellBackgroundColor;
1284 if ( style->enabled && column ==
mColumns.count() - 1 )
1285 color = style->cellBackgroundColor;
1287 if ( style->enabled && row == -1 )
1288 color = style->cellBackgroundColor;
1290 if ( style->enabled && row == 0 )
1291 color = style->cellBackgroundColor;
1294 color = style->cellBackgroundColor;
1309 if ( lastRow - firstRow < 1 && !hasHeader )
1315 double tableHeight = 0;
1321 double headerHeight = tableHeight;
1324 for (
int row = firstRow; row < lastRow; ++row )
1331 double currentX = halfGridStrokeWidth;
1332 painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
1334 QMap<int, double>::const_iterator maxColWidthIt = maxWidthMap.constBegin();
1336 for ( ; maxColWidthIt != maxWidthMap.constEnd(); ++maxColWidthIt )
1338 currentX += ( maxColWidthIt.value() + 2 *
mCellMargin );
1339 if ( col == maxWidthMap.size() || !mergeCells )
1341 painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, tableHeight - halfGridStrokeWidth ) );
1343 else if ( hasHeader )
1345 painter->drawLine( QPointF( currentX, halfGridStrokeWidth ), QPointF( currentX, headerHeight - halfGridStrokeWidth ) );
1364 return (
contents.indexOf( row ) >= 0 );