21 #include <QAbstractItemModel>
26 #include <QTextCursor>
27 #include <QTextTableCell>
31 class KDReports::AutoTableElementPrivate
34 AutoTableElementPrivate()
35 : m_tableModel(nullptr)
36 , m_verticalHeaderVisible(true)
37 , m_horizontalHeaderVisible(true)
38 , m_headerBackground(QColor(218, 218, 218))
42 ~AutoTableElementPrivate() { }
44 void fillCellFromHeaderData(
int section, Qt::Orientation orientation, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder)
const;
45 QSize fillTableCell(
int row,
int column, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder)
const;
47 QAbstractItemModel *m_tableModel;
49 bool m_verticalHeaderVisible;
50 bool m_horizontalHeaderVisible;
51 QBrush m_headerBackground;
59 FillCellHelper(QAbstractItemModel *tableModel,
int section, Qt::Orientation orientation, QSize iconSz)
61 , cellDecoration(tableModel->headerData(section, orientation, Qt::DecorationRole))
62 , cellFont(tableModel->headerData(section, orientation, Qt::FontRole))
63 , cellText(tableModel->headerData(section, orientation, Qt::DisplayRole).toString())
64 , foreground(tableModel->headerData(section, orientation, Qt::ForegroundRole))
65 , background(tableModel->headerData(section, orientation, Qt::BackgroundRole))
66 , alignment(Qt::Alignment(tableModel->headerData(section, orientation, Qt::TextAlignmentRole).toInt()))
67 , decorationAlignment(tableModel->headerData(section, orientation,
KDReports::AutoTableElement::DecorationAlignmentRole))
68 , nonBreakableLines(tableModel->headerData(section, orientation,
KDReports::AutoTableElement::NonBreakableLinesRole).toBool())
72 FillCellHelper(QAbstractItemModel *tableModel,
const QModelIndex &index, QSize _span, QSize iconSz)
74 , cellDecoration(tableModel->data(index, Qt::DecorationRole))
75 , cellFont(tableModel->data(index, Qt::FontRole))
76 , cellText(displayText(tableModel->data(index, Qt::DisplayRole)))
77 , foreground(tableModel->data(index, Qt::ForegroundRole))
78 , background(tableModel->data(index, Qt::BackgroundRole))
79 , alignment(Qt::Alignment(tableModel->data(index, Qt::TextAlignmentRole).toInt()))
80 , decorationAlignment(tableModel->data(index,
KDReports::AutoTableElement::DecorationAlignmentRole))
81 , nonBreakableLines(tableModel->data(index,
KDReports::AutoTableElement::NonBreakableLinesRole).toBool())
89 static QString displayText(
const QVariant &value);
92 QVariant cellDecoration;
97 Qt::Alignment alignment;
98 QVariant decorationAlignment;
99 bool nonBreakableLines;
102 QTextCursor cellCursor;
107 switch (alignment & Qt::AlignVertical_Mask) {
109 return QTextCharFormat::AlignTop;
110 case Qt::AlignBottom:
111 return QTextCharFormat::AlignBottom;
112 case Qt::AlignVCenter:
113 return QTextCharFormat::AlignMiddle;
115 return QTextCharFormat::AlignNormal;
118 void FillCellHelper::fill(QTextTable *textTable,
KDReports::ReportBuilder &builder, QTextDocument &textDoc, QTextTableCell &cell)
120 cellCursor = cell.firstCursorPosition();
121 QTextCharFormat cellFormat = cell.format();
122 if (background.canConvert<QBrush>()) {
123 cellFormat.setBackground(qvariant_cast<QBrush>(background));
126 cell.setFormat(cellFormat);
128 QTextBlockFormat blockFormat = cellCursor.blockFormat();
129 blockFormat.setAlignment(alignment);
130 blockFormat.setNonBreakableLines(nonBreakableLines);
133 cellCursor.setBlockFormat(blockFormat);
135 const bool hasIcon = !cellDecoration.isNull();
136 const bool iconAfterText = decorationAlignment.isValid() && (decorationAlignment.toInt() & Qt::AlignRight);
137 if (hasIcon && !iconAfterText) {
138 insertDecoration(builder, textDoc);
141 QTextCharFormat charFormat = cellCursor.charFormat();
142 if (cellFont.isValid()) {
143 QFont cellQFont = qvariant_cast<QFont>(cellFont);
144 #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)
145 charFormat.setFont(cellQFont, QTextCharFormat::FontPropertiesSpecifiedOnly);
147 charFormat.setFont(cellQFont);
152 if (foreground.canConvert<QBrush>()) {
153 charFormat.setForeground(qvariant_cast<QBrush>(foreground));
155 cellCursor.setCharFormat(charFormat);
157 if (hasIcon && !iconAfterText) {
158 cellCursor.insertText(QChar::fromLatin1(
' '));
162 if (cellText.startsWith(QLatin1String(
"<qt>")) || cellText.startsWith(QLatin1String(
"<html>")))
163 cellCursor.insertHtml(cellText);
165 cellCursor.insertText(cellText);
167 if (hasIcon && iconAfterText) {
168 cellCursor.insertText(QChar::fromLatin1(
' '));
169 insertDecoration(builder, textDoc);
172 if (span.width() > 1 || span.height() > 1)
173 textTable->mergeCells(cell.row(), cell.column(), span.height(), span.width());
178 QImage img = qvariant_cast<QImage>(cellDecoration);
180 img = qvariant_cast<QIcon>(cellDecoration).pixmap(iconSize).toImage();
183 static int imageNumber = 0;
184 const QString name = QStringLiteral(
"cell-image%1.png").arg(++imageNumber);
185 textDoc.addResource(QTextDocument::ImageResource, QUrl(name), img);
187 cellCursor.insertImage(name);
191 QString FillCellHelper::displayText(
const QVariant &value)
195 switch (value.userType()) {
196 case QMetaType::Float:
197 case QVariant::Double:
198 text = locale.toString(value.toReal());
201 case QVariant::LongLong:
202 text = locale.toString(value.toLongLong());
205 case QVariant::ULongLong:
206 text = locale.toString(value.toULongLong());
209 text = locale.toString(value.toDate(), QLocale::ShortFormat);
212 text = locale.toString(value.toTime(), QLocale::ShortFormat);
214 case QVariant::DateTime:
215 text = locale.toString(value.toDateTime().date(), QLocale::ShortFormat);
216 text += QLatin1Char(
' ');
217 text += locale.toString(value.toDateTime().time(), QLocale::ShortFormat);
220 text = value.toString();
229 : d(new AutoTableElementPrivate)
235 : d(new AutoTableElementPrivate)
242 , d(new AutoTableElementPrivate(*other.d))
260 void KDReports::AutoTableElementPrivate::fillCellFromHeaderData(
int section, Qt::Orientation orientation, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable,
263 FillCellHelper helper(m_tableModel, section, orientation, m_iconSize);
264 helper.fill(textTable, builder, textDoc, cell);
267 QSize KDReports::AutoTableElementPrivate::fillTableCell(
int row,
int column, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder)
const
269 const QModelIndex index = m_tableModel->index(row, column);
270 const QSize span = m_tableModel->span(index);
271 FillCellHelper helper(m_tableModel, index, span, m_iconSize);
272 helper.fill(textTable, builder, textDoc, cell);
278 if (!d->m_tableModel) {
282 QTextCursor &textDocCursor = builder.
cursor();
283 textDocCursor.beginEditBlock();
285 QTextTableFormat tableFormat;
286 const int headerRowCount = d->m_horizontalHeaderVisible ? 1 : 0;
287 const int headerColumnCount = d->m_verticalHeaderVisible ? 1 : 0;
288 tableFormat.setHeaderRowCount(headerRowCount);
291 tableFormat.setAlignment(textDocCursor.blockFormat().alignment());
292 fillTableFormat(tableFormat, textDocCursor);
294 while (d->m_tableModel->canFetchMore(QModelIndex()))
295 d->m_tableModel->fetchMore(QModelIndex());
297 const int rows = d->m_tableModel->rowCount();
298 const int columns = d->m_tableModel->columnCount();
300 QTextTable *textTable = textDocCursor.insertTable(rows + headerRowCount, columns + headerColumnCount, tableFormat);
302 QTextCharFormat tableHeaderFormat;
303 tableHeaderFormat.setBackground(d->m_headerBackground);
306 if (d->m_horizontalHeaderVisible) {
307 for (
int column = 0; column < columns; column++) {
308 QTextTableCell cell = textTable->cellAt(0, column + headerColumnCount);
309 Q_ASSERT(cell.isValid());
310 cell.setFormat(tableHeaderFormat);
311 d->fillCellFromHeaderData(column, Qt::Horizontal, cell, textDoc, textTable, builder);
315 if (d->m_verticalHeaderVisible) {
316 for (
int row = 0; row < rows; row++) {
317 QTextTableCell cell = textTable->cellAt(row + headerRowCount, 0);
318 Q_ASSERT(cell.isValid());
319 cell.setFormat(tableHeaderFormat);
320 d->fillCellFromHeaderData(row, Qt::Vertical, cell, textDoc, textTable, builder);
324 QVector<QBitArray> coveredCells;
325 coveredCells.resize(rows);
326 for (
int row = 0; row < rows; row++)
327 coveredCells[row].resize(columns);
330 for (
int row = 0; row < rows; row++) {
331 for (
int column = 0; column < columns; column++) {
332 if (coveredCells[row].testBit(column))
334 QTextTableCell cell = textTable->cellAt(row + headerRowCount, column + headerColumnCount);
335 Q_ASSERT(cell.isValid());
336 const QSize span = d->fillTableCell(row, column, cell, textDoc, textTable, builder);
337 if (span.isValid()) {
338 for (
int r = row; r < row + span.height() && r < rows; ++r) {
339 for (
int c = column; c < column + span.width() && c < columns; ++c) {
340 coveredCells[r].setBit(c);
347 textDocCursor.movePosition(QTextCursor::End);
348 textDocCursor.endEditBlock();
361 d->m_verticalHeaderVisible = visible;
366 d->m_horizontalHeaderVisible = visible;
371 d->m_headerBackground = brush;
376 return d->m_verticalHeaderVisible;
381 return d->m_horizontalHeaderVisible;
386 d->m_iconSize = iconSize;
391 return d->m_iconSize;
396 return d->m_tableModel;
401 d->m_tableModel = tableModel;
411 return d->m_headerBackground;