KD Reports API Documentation  2.1
KDReportsAutoTableElement.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Reports library.
4 **
5 ** SPDX-FileCopyrightText: 2007-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDAB-KDReports OR LicenseRef-KDAB-KDReports-US
8 **
9 ** Licensees holding valid commercial KD Reports licenses may use this file in
10 ** accordance with the KD Reports Commercial License Agreement provided with
11 ** the Software.
12 **
13 ** Contact info@kdab.com if any conditions of this licensing are not clear to you.
14 **
15 ****************************************************************************/
16 
20 #include "KDReportsReport_p.h" // modelForKey
21 #include <QAbstractItemModel>
22 #include <QBitArray>
23 #include <QDateTime>
24 #include <QDebug>
25 #include <QIcon>
26 #include <QTextCursor>
27 #include <QTextTableCell>
28 #include <QUrl>
29 #include <QVector>
30 
31 class KDReports::AutoTableElementPrivate
32 {
33 public:
34  void fillCellFromHeaderData(int section, Qt::Orientation orientation, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder) const;
35  QSize fillTableCell(int row, int column, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder) const;
36 
37  QAbstractItemModel *m_tableModel = nullptr;
38  QString m_modelKey;
39  bool m_verticalHeaderVisible = true;
40  bool m_horizontalHeaderVisible = true;
41  QBrush m_headerBackground = QColor(218, 218, 218);
42  QSize m_iconSize = QSize(32, 32);
43 };
44 
45 // Helper for fillCellFromHeaderData and fillTableCell
46 class FillCellHelper
47 {
48 public:
49  FillCellHelper(QAbstractItemModel *tableModel, int section, Qt::Orientation orientation, QSize iconSz)
50  : iconSize(iconSz)
51  , cellDecoration(tableModel->headerData(section, orientation, Qt::DecorationRole))
52  , cellFont(tableModel->headerData(section, orientation, Qt::FontRole))
53  , cellText(tableModel->headerData(section, orientation, Qt::DisplayRole).toString())
54  , foreground(tableModel->headerData(section, orientation, Qt::ForegroundRole))
55  , background(tableModel->headerData(section, orientation, Qt::BackgroundRole))
56  , alignment(Qt::Alignment(tableModel->headerData(section, orientation, Qt::TextAlignmentRole).toInt()))
57  , decorationAlignment(tableModel->headerData(section, orientation, KDReports::AutoTableElement::DecorationAlignmentRole))
58  , nonBreakableLines(tableModel->headerData(section, orientation, KDReports::AutoTableElement::NonBreakableLinesRole).toBool())
59  , span(1, 1)
60  {
61  }
62  FillCellHelper(QAbstractItemModel *tableModel, const QModelIndex &index, QSize _span, QSize iconSz)
63  : iconSize(iconSz)
64  , cellDecoration(tableModel->data(index, Qt::DecorationRole))
65  , cellFont(tableModel->data(index, Qt::FontRole))
66  , cellText(displayText(tableModel->data(index, Qt::DisplayRole)))
67  , foreground(tableModel->data(index, Qt::ForegroundRole))
68  , background(tableModel->data(index, Qt::BackgroundRole))
69  , alignment(Qt::Alignment(tableModel->data(index, Qt::TextAlignmentRole).toInt()))
70  , decorationAlignment(tableModel->data(index, KDReports::AutoTableElement::DecorationAlignmentRole))
71  , nonBreakableLines(tableModel->data(index, KDReports::AutoTableElement::NonBreakableLinesRole).toBool())
72  , span(_span)
73  {
74  }
75  void fill(QTextTable *textTable, KDReports::ReportBuilder &builder, QTextDocument &textDoc, QTextTableCell &cell);
76 
77 private:
78  void insertDecoration(KDReports::ReportBuilder &builder, QTextDocument &textDoc);
79  static QString displayText(const QVariant &value);
80 
81  QSize iconSize;
82  QVariant cellDecoration;
83  QVariant cellFont;
84  QString cellText;
85  QVariant foreground;
86  QVariant background;
87  Qt::Alignment alignment;
88  QVariant decorationAlignment;
89  bool nonBreakableLines;
90  QSize span;
91 
92  QTextCursor cellCursor;
93 };
94 
96 {
97  switch (alignment & Qt::AlignVertical_Mask) {
98  case Qt::AlignTop:
100  case Qt::AlignBottom:
102  case Qt::AlignVCenter:
104  case Qt::AlignBaseline:
106  }
108 }
109 
110 void FillCellHelper::fill(QTextTable *textTable, KDReports::ReportBuilder &builder, QTextDocument &textDoc, QTextTableCell &cell)
111 {
112  cellCursor = cell.firstCursorPosition();
113  QTextCharFormat cellFormat = cell.format();
114  if (background.canConvert<QBrush>()) {
115  cellFormat.setBackground(qvariant_cast<QBrush>(background));
116  }
117  cellFormat.setVerticalAlignment(toVerticalAlignment(alignment));
118  cell.setFormat(cellFormat);
119 
120  QTextBlockFormat blockFormat = cellCursor.blockFormat();
121  blockFormat.setAlignment(alignment);
122  blockFormat.setNonBreakableLines(nonBreakableLines);
123  builder.setupBlockFormat(blockFormat);
124 
125  cellCursor.setBlockFormat(blockFormat);
126 
127  const bool hasIcon = !cellDecoration.isNull();
128  const bool iconAfterText = decorationAlignment.isValid() && (decorationAlignment.toInt() & Qt::AlignRight);
129  if (hasIcon && !iconAfterText) {
130  insertDecoration(builder, textDoc);
131  }
132 
133  QTextCharFormat charFormat = cellCursor.charFormat();
134  if (cellFont.isValid()) {
135  QFont cellQFont = qvariant_cast<QFont>(cellFont);
136 #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
138 #else
139  charFormat.setFont(cellQFont);
140 #endif
141  } else {
142  charFormat.setFont(builder.defaultFont());
143  }
144  if (foreground.canConvert<QBrush>()) {
145  charFormat.setForeground(qvariant_cast<QBrush>(foreground));
146  }
147  cellCursor.setCharFormat(charFormat);
148 
149  if (hasIcon && !iconAfterText) {
150  cellCursor.insertText(QChar::fromLatin1(' ')); // spacing between icon and text
151  }
152 
153  // qDebug() << cellText;
154  if (cellText.startsWith(QLatin1String("<qt>")) || cellText.startsWith(QLatin1String("<html>")))
155  cellCursor.insertHtml(cellText);
156  else
157  cellCursor.insertText(cellText);
158 
159  if (hasIcon && iconAfterText) {
160  cellCursor.insertText(QChar::fromLatin1(' ')); // spacing between icon and text
161  insertDecoration(builder, textDoc);
162  }
163 
164  if (span.width() > 1 || span.height() > 1)
165  textTable->mergeCells(cell.row(), cell.column(), span.height(), span.width());
166 }
167 
168 void FillCellHelper::insertDecoration(KDReports::ReportBuilder &builder, QTextDocument &textDoc)
169 {
170  QImage img = qvariant_cast<QImage>(cellDecoration);
171  if (img.isNull()) {
172  img = qvariant_cast<QIcon>(cellDecoration).pixmap(iconSize).toImage();
173  }
174  if (!img.isNull()) {
175  static int imageNumber = 0;
176  const QString name = QStringLiteral("cell-image%1.png").arg(++imageNumber);
177  textDoc.addResource(QTextDocument::ImageResource, QUrl(name), img);
178  builder.currentDocumentData().addResourceName(name);
179  cellCursor.insertImage(name);
180  }
181 }
182 
183 QString FillCellHelper::displayText(const QVariant &value)
184 {
185  QLocale locale; // in QStyledItemDelegate this is configurable, it comes from QWidget::locale()...
186  QString text;
187  switch (value.userType()) {
188  case QMetaType::Float:
189  case QVariant::Double:
190  text = locale.toString(value.toReal());
191  break;
192  case QVariant::Int:
193  case QVariant::LongLong:
194  text = locale.toString(value.toLongLong());
195  break;
196  case QVariant::UInt:
197  case QVariant::ULongLong:
198  text = locale.toString(value.toULongLong());
199  break;
200  case QVariant::Date:
201  text = locale.toString(value.toDate(), QLocale::ShortFormat);
202  break;
203  case QVariant::Time:
204  text = locale.toString(value.toTime(), QLocale::ShortFormat);
205  break;
206  case QVariant::DateTime:
207  text = locale.toString(value.toDateTime().date(), QLocale::ShortFormat);
208  text += QLatin1Char(' ');
209  text += locale.toString(value.toDateTime().time(), QLocale::ShortFormat);
210  break;
211  default:
212  text = value.toString();
213  break;
214  }
215  return text;
216 }
217 
219 
221  : d(new AutoTableElementPrivate)
222 {
223  d->m_tableModel = tableModel;
224 }
225 
227  : d(new AutoTableElementPrivate)
228 {
229  d->m_tableModel = KDReports::modelForKey(modelKey);
230 }
231 
233  : AbstractTableElement(other)
234  , d(new AutoTableElementPrivate(*other.d))
235 {
236 }
237 
239 {
240  if (&other == this)
241  return *this;
243  *d = *other.d;
244  return *this;
245 }
246 
248 {
249 }
250 
251 void KDReports::AutoTableElementPrivate::fillCellFromHeaderData(int section, Qt::Orientation orientation, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable,
252  ReportBuilder &builder) const
253 {
254  FillCellHelper helper(m_tableModel, section, orientation, m_iconSize);
255  helper.fill(textTable, builder, textDoc, cell);
256 }
257 
258 QSize KDReports::AutoTableElementPrivate::fillTableCell(int row, int column, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder) const
259 {
260  const QModelIndex index = m_tableModel->index(row, column);
261  const QSize span = m_tableModel->span(index);
262  FillCellHelper helper(m_tableModel, index, span, m_iconSize);
263  helper.fill(textTable, builder, textDoc, cell);
264  return span;
265 }
266 
268 {
269  if (!d->m_tableModel) {
270  return;
271  }
272  QTextDocument &textDoc = builder.currentDocument();
273  QTextCursor &textDocCursor = builder.cursor();
274  textDocCursor.beginEditBlock();
275 
276  QTextTableFormat tableFormat;
277  const int headerRowCount = d->m_horizontalHeaderVisible ? 1 : 0;
278  const int headerColumnCount = d->m_verticalHeaderVisible ? 1 : 0;
279  tableFormat.setHeaderRowCount(headerRowCount);
280  tableFormat.setProperty(KDReports::HeaderColumnsProperty, headerColumnCount);
281 
282  tableFormat.setAlignment(textDocCursor.blockFormat().alignment());
283  fillTableFormat(tableFormat, textDocCursor);
284 
285  while (d->m_tableModel->canFetchMore(QModelIndex()))
286  d->m_tableModel->fetchMore(QModelIndex());
287 
288  const int rows = d->m_tableModel->rowCount();
289  const int columns = d->m_tableModel->columnCount();
290 
291  QTextTable *textTable = textDocCursor.insertTable(rows + headerRowCount, columns + headerColumnCount, tableFormat);
292 
293  QTextCharFormat tableHeaderFormat;
294  tableHeaderFormat.setBackground(d->m_headerBackground);
295  // qDebug( "rows = %d, columns = %d", textTable->rows(), textTable->columns() );
296 
297  if (d->m_horizontalHeaderVisible) {
298  for (int column = 0; column < columns; column++) {
299  QTextTableCell cell = textTable->cellAt(0, column + headerColumnCount);
300  Q_ASSERT(cell.isValid());
301  cell.setFormat(tableHeaderFormat);
302  d->fillCellFromHeaderData(column, Qt::Horizontal, cell, textDoc, textTable, builder);
303  }
304  }
305 
306  if (d->m_verticalHeaderVisible) {
307  for (int row = 0; row < rows; row++) {
308  QTextTableCell cell = textTable->cellAt(row + headerRowCount, 0);
309  Q_ASSERT(cell.isValid());
310  cell.setFormat(tableHeaderFormat);
311  d->fillCellFromHeaderData(row, Qt::Vertical, cell, textDoc, textTable, builder);
312  }
313  }
314 
315  QVector<QBitArray> coveredCells;
316  coveredCells.resize(rows);
317  for (int row = 0; row < rows; row++)
318  coveredCells[row].resize(columns);
319 
320  // The normal data
321  for (int row = 0; row < rows; row++) {
322  for (int column = 0; column < columns; column++) {
323  if (coveredCells[row].testBit(column))
324  continue;
325  QTextTableCell cell = textTable->cellAt(row + headerRowCount, column + headerColumnCount);
326  Q_ASSERT(cell.isValid());
327  const QSize span = d->fillTableCell(row, column, cell, textDoc, textTable, builder);
328  if (span.isValid()) {
329  for (int r = row; r < row + span.height() && r < rows; ++r) {
330  for (int c = column; c < column + span.width() && c < columns; ++c) {
331  coveredCells[r].setBit(c);
332  }
333  }
334  }
335  }
336  }
337 
338  textDocCursor.movePosition(QTextCursor::End);
339  textDocCursor.endEditBlock();
340 
341  builder.currentDocumentData().registerAutoTable(textTable, this);
342 }
343 
345 {
346  // never used at the moment
347  return new AutoTableElement(*this);
348 }
349 
351 {
352  d->m_verticalHeaderVisible = visible;
353 }
354 
356 {
357  d->m_horizontalHeaderVisible = visible;
358 }
359 
361 {
362  d->m_headerBackground = brush;
363 }
364 
366 {
367  return d->m_verticalHeaderVisible;
368 }
369 
371 {
372  return d->m_horizontalHeaderVisible;
373 }
374 
376 {
377  d->m_iconSize = iconSize;
378 }
379 
381 {
382  return d->m_iconSize;
383 }
384 
386 {
387  return d->m_tableModel;
388 }
389 
391 {
392  d->m_tableModel = tableModel;
393 }
394 
396 {
397  d->m_tableModel = KDReports::modelForKey(modelKey);
398 }
399 
401 {
402  return d->m_headerBackground;
403 }
KDReports::AutoTableElement::tableModel
QAbstractItemModel * tableModel() const
Definition: KDReportsAutoTableElement.cpp:385
QVariant::toReal
qreal toReal(bool *ok) const const
KDReports::TextDocumentData::registerAutoTable
void registerAutoTable(QTextTable *table, const KDReports::AutoTableElement *element)
Definition: KDReportsTextDocumentData.cpp:316
QTextTableCell::row
int row() const const
QTextDocument
QColor
KDReports::HeaderColumnsProperty
@ HeaderColumnsProperty
Definition: KDReportsTextDocument_p.h:48
Qt::Alignment
typedef Alignment
KDReports::ReportBuilder
Definition: KDReportsReportBuilder_p.h:42
KDReports::ReportBuilder::currentDocumentData
TextDocumentData & currentDocumentData()
Definition: KDReportsReportBuilder_p.h:69
KDReports::AutoTableElement::AutoTableElement
AutoTableElement(QAbstractItemModel *tableModel)
Definition: KDReportsAutoTableElement.cpp:220
Qt::DecorationRole
DecorationRole
KDReports::AutoTableElement::clone
Element * clone() const override
Definition: KDReportsAutoTableElement.cpp:344
QSize::isValid
bool isValid() const const
QTextCharFormat
QTextTableCell::firstCursorPosition
QTextCursor firstCursorPosition() const const
QTextTableFormat::setHeaderRowCount
void setHeaderRowCount(int count)
KDReports::AutoTableElement::setIconSize
void setIconSize(QSize iconSize)
Definition: KDReportsAutoTableElement.cpp:375
QUrl
KDReports::AutoTableElement::setModelKey
void setModelKey(const QString &modelKey)
Definition: KDReportsAutoTableElement.cpp:395
KDReports::modelForKey
QAbstractItemModel * modelForKey(const QString &key)
Definition: KDReportsReport.cpp:426
QDateTime::time
QTime time() const const
QTextTableCell::setFormat
void setFormat(const QTextCharFormat &format)
QTextCharFormat::setVerticalAlignment
void setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment)
QTextTableCell::format
QTextCharFormat format() const const
QTextDocument::ImageResource
ImageResource
QSize
KDReports::AutoTableElement::isHorizontalHeaderVisible
bool isHorizontalHeaderVisible() const
Definition: KDReportsAutoTableElement.cpp:370
KDReportsReport_p.h
QTextTable
QSize::width
int width() const const
QVariant::toLongLong
qlonglong toLongLong(bool *ok) const const
QTextBlockFormat::setAlignment
void setAlignment(Qt::Alignment alignment)
QVariant::toDate
QDate toDate() const const
KDReports::Element
Definition: KDReportsElement.h:41
QTextBlockFormat::alignment
Qt::Alignment alignment() const const
QLocale
QTextFormat::setBackground
void setBackground(const QBrush &brush)
QMetaType::Float
Float
KDReports::AutoTableElement::build
void build(ReportBuilder &) const override
Definition: KDReportsAutoTableElement.cpp:267
QTextTable::cellAt
QTextTableCell cellAt(int row, int column) const const
QVariant::userType
int userType() const const
KDReports::AutoTableElement
Definition: KDReportsAutoTableElement.h:41
QTextTableCell::isValid
bool isValid() const const
QVariant::toULongLong
qulonglong toULongLong(bool *ok) const const
KDReports::AutoTableElement::operator=
AutoTableElement & operator=(const AutoTableElement &other)
Definition: KDReportsAutoTableElement.cpp:238
QTextFormat::setForeground
void setForeground(const QBrush &brush)
QSize::height
int height() const const
QString
Qt
KDReports::ReportBuilder::setupBlockFormat
void setupBlockFormat(QTextBlockFormat &blockFormat) const
Definition: KDReportsReportBuilder.cpp:207
KDReports::AutoTableElement::setTableModel
void setTableModel(QAbstractItemModel *tableModel)
Definition: KDReportsAutoTableElement.cpp:390
Qt::Orientation
Orientation
KDReports::AutoTableElement::setVerticalHeaderVisible
void setVerticalHeaderVisible(bool visible)
Definition: KDReportsAutoTableElement.cpp:350
QImage::isNull
bool isNull() const const
QLocale::toString
QString toString(qlonglong i) const const
KDReportsReportBuilder_p.h
QTextCharFormat::setFont
void setFont(const QFont &font, QTextCharFormat::FontPropertiesInheritanceBehavior behavior)
QVector::resize
void resize(int size)
QTextFormat::setProperty
void setProperty(int propertyId, const QVariant &value)
QBrush
QLatin1String
QTextCursor::blockFormat
QTextBlockFormat blockFormat() const const
QTextCursor::insertTable
QTextTable * insertTable(int rows, int columns, const QTextTableFormat &format)
KDReports::AutoTableElement::~AutoTableElement
~AutoTableElement() override
Definition: KDReportsAutoTableElement.cpp:247
KDReports::ReportBuilder::defaultFont
QFont defaultFont() const
Definition: KDReportsReportBuilder_p.h:77
KDReports::AbstractTableElement::operator=
AbstractTableElement & operator=(const AbstractTableElement &other)
Definition: KDReportsAbstractTableElement.cpp:48
QVariant::toDateTime
QDateTime toDateTime() const const
QTextTableFormat
QTextBlockFormat::setNonBreakableLines
void setNonBreakableLines(bool b)
KDReportsAutoTableElement.h
QLocale::ShortFormat
ShortFormat
QTextCursor::beginEditBlock
void beginEditBlock()
QLatin1Char
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
KDReportsLayoutHelper_p.h
QVariant::toTime
QTime toTime() const const
QDateTime::date
QDate date() const const
QTextCharFormat::VerticalAlignment
VerticalAlignment
QTextCursor::End
End
KDReports::AutoTableElement::iconSize
QSize iconSize() const
Definition: KDReportsAutoTableElement.cpp:380
KDReports::ReportBuilder::cursor
QTextCursor & cursor()
Definition: KDReportsReportBuilder_p.h:48
QTextDocument::addResource
void addResource(int type, const QUrl &name, const QVariant &resource)
QTextTableCell::column
int column() const const
KDReports::TextDocumentData::addResourceName
void addResourceName(const QString &resourceName)
Definition: KDReportsTextDocumentData.cpp:405
QTextBlockFormat
QModelIndex
QVector
KDReports::AutoTableElement::headerBackground
QBrush headerBackground() const
Definition: KDReportsAutoTableElement.cpp:400
QVariant
QTextCharFormat::FontPropertiesSpecifiedOnly
FontPropertiesSpecifiedOnly
QTextTableFormat::setAlignment
void setAlignment(Qt::Alignment alignment)
QTextCursor::endEditBlock
void endEditBlock()
QTextCursor::movePosition
bool movePosition(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode, int n)
QVariant::Double
Double
KDReports::ReportBuilder::currentDocument
QTextDocument & currentDocument()
Definition: KDReportsReportBuilder_p.h:71
QFont
KDReports::AbstractTableElement
Definition: KDReportsAbstractTableElement.h:39
QImage
toVerticalAlignment
static QTextCharFormat::VerticalAlignment toVerticalAlignment(Qt::Alignment alignment)
Definition: KDReportsAutoTableElement.cpp:95
KDReports::AutoTableElement::setHeaderBackground
void setHeaderBackground(const QBrush &brush)
Definition: KDReportsAutoTableElement.cpp:360
QTextTable::mergeCells
void mergeCells(int row, int column, int numRows, int numCols)
QTextCursor
QAbstractItemModel
QTextTableCell
KDReports::AutoTableElement::setHorizontalHeaderVisible
void setHorizontalHeaderVisible(bool visible)
Definition: KDReportsAutoTableElement.cpp:355
KDReports::AutoTableElement::isVerticalHeaderVisible
bool isVerticalHeaderVisible() const
Definition: KDReportsAutoTableElement.cpp:365
QVariant::toString
QString toString() const const
KDReports
Definition: KDReportsAbstractReportLayout_p.h:30
QChar::fromLatin1
QChar fromLatin1(char c)

© 2007-2021 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-reports/
Generated on Fri Jul 15 2022 13:09:06 for KD Reports API Documentation by doxygen 1.8.20