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

© 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 Wed Apr 24 2024 04:08:14 for KD Reports API Documentation by doxygen 1.9.8