15 #include <QAbstractItemModel>
20 #include <QTextCursor>
21 #include <QTextTableCell>
25 class KDReports::AutoTableElementPrivate
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;
33 QAbstractItemModel *m_tableModel =
nullptr;
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);
47 FillCellHelper(QAbstractItemModel *tableModel,
int section, Qt::Orientation orientation, QSize 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())
60 FillCellHelper(QAbstractItemModel *tableModel,
const QModelIndex &index, QSize _span, QSize 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())
77 static QString displayText(
const QVariant &value);
80 QVariant cellDecoration;
85 Qt::Alignment alignment;
86 QVariant decorationAlignment;
87 bool nonBreakableLines;
90 QTextCursor cellCursor;
93 void FillCellHelper::fill(QTextTable *textTable,
KDReports::ReportBuilder &builder, QTextDocument &textDoc, QTextTableCell &cell)
95 cellCursor = cell.firstCursorPosition();
96 QTextCharFormat cellFormat = cell.format();
97 if (background.canConvert<QBrush>()) {
98 cellFormat.setBackground(qvariant_cast<QBrush>(background));
101 cell.setFormat(cellFormat);
103 QTextBlockFormat blockFormat = cellCursor.blockFormat();
104 blockFormat.setAlignment(alignment);
105 blockFormat.setNonBreakableLines(nonBreakableLines);
108 cellCursor.setBlockFormat(blockFormat);
110 const bool hasIcon = !cellDecoration.isNull();
111 const bool iconAfterText = decorationAlignment.isValid() && (decorationAlignment.toInt() & Qt::AlignRight);
112 if (hasIcon && !iconAfterText) {
113 insertDecoration(builder, textDoc);
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)
120 charFormat.setFont(cellQFont, QTextCharFormat::FontPropertiesSpecifiedOnly);
122 charFormat.setFont(cellQFont);
127 if (foreground.canConvert<QBrush>()) {
128 charFormat.setForeground(qvariant_cast<QBrush>(foreground));
130 cellCursor.setCharFormat(charFormat);
132 if (hasIcon && !iconAfterText) {
133 cellCursor.insertText(QChar::fromLatin1(
' '));
137 if (cellText.startsWith(QLatin1String(
"<qt>")) || cellText.startsWith(QLatin1String(
"<html>")))
138 cellCursor.insertHtml(cellText);
140 cellCursor.insertText(cellText);
142 if (hasIcon && iconAfterText) {
143 cellCursor.insertText(QChar::fromLatin1(
' '));
144 insertDecoration(builder, textDoc);
147 if (span.width() > 1 || span.height() > 1)
148 textTable->mergeCells(cell.row(), cell.column(), span.height(), span.width());
153 QImage img = qvariant_cast<QImage>(cellDecoration);
155 img = qvariant_cast<QIcon>(cellDecoration).pixmap(iconSize).toImage();
158 static int imageNumber = 0;
159 const QString name = QStringLiteral(
"cell-image%1.png").arg(++imageNumber);
160 textDoc.addResource(QTextDocument::ImageResource, QUrl(name), img);
162 cellCursor.insertImage(name);
166 QString FillCellHelper::displayText(
const QVariant &value)
170 switch (value.userType()) {
171 case QMetaType::Float:
172 case QVariant::Double:
173 text = locale.toString(value.toReal());
176 case QVariant::LongLong:
177 text = locale.toString(value.toLongLong());
180 case QVariant::ULongLong:
181 text = locale.toString(value.toULongLong());
184 text = locale.toString(value.toDate(), QLocale::ShortFormat);
187 text = locale.toString(value.toTime(), QLocale::ShortFormat);
189 case QVariant::DateTime:
190 text = locale.toString(value.toDateTime().date(), QLocale::ShortFormat);
191 text += QLatin1Char(
' ');
192 text += locale.toString(value.toDateTime().time(), QLocale::ShortFormat);
195 text = value.toString();
204 : d(new AutoTableElementPrivate)
210 : d(new AutoTableElementPrivate)
217 , d(new AutoTableElementPrivate(*other.d))
234 void KDReports::AutoTableElementPrivate::fillCellFromHeaderData(
int section, Qt::Orientation orientation, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable,
237 FillCellHelper helper(m_tableModel, section, orientation, m_iconSize);
238 helper.fill(textTable, builder, textDoc, cell);
241 QSize KDReports::AutoTableElementPrivate::fillTableCell(
int row,
int column, QTextTableCell &cell, QTextDocument &textDoc, QTextTable *textTable, ReportBuilder &builder)
const
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);
250 void KDReports::AutoTableElementPrivate::createHorizontalHeader(ReportBuilder &builder, QTextDocument &textDoc, QTextTable *textTable,
int columns,
int headerColumnCount)
const
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);
266 void KDReports::AutoTableElementPrivate::createVerticalHeader(ReportBuilder &builder, QTextDocument &textDoc, QTextTable *textTable,
int rows,
int headerRowCount)
const
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);
284 if (!d->m_tableModel) {
288 QTextCursor &textDocCursor = builder.
cursor();
289 textDocCursor.beginEditBlock();
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);
297 tableFormat.setAlignment(textDocCursor.blockFormat().alignment());
298 fillTableFormat(tableFormat, textDocCursor);
300 while (d->m_tableModel->canFetchMore(QModelIndex()))
301 d->m_tableModel->fetchMore(QModelIndex());
303 const int rows = d->m_tableModel->rowCount();
304 const int columns = d->m_tableModel->columnCount();
306 QTextTable *textTable = textDocCursor.insertTable(rows + headerRowCount, columns + headerColumnCount, tableFormat);
310 d->createHorizontalHeader(builder, textDoc, textTable, columns, headerColumnCount);
311 d->createVerticalHeader(builder, textDoc, textTable, rows, headerRowCount);
313 QVector<QBitArray> coveredCells;
314 coveredCells.resize(rows);
315 for (
int row = 0; row < rows; row++)
316 coveredCells[row].resize(columns);
319 for (
int row = 0; row < rows; row++) {
320 for (
int column = 0; column < columns; column++) {
321 if (coveredCells[row].testBit(column))
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);
336 textDocCursor.movePosition(QTextCursor::End);
337 textDocCursor.endEditBlock();
350 d->m_verticalHeaderVisible = visible;
355 d->m_horizontalHeaderVisible = visible;
360 d->m_headerBackground = brush;
365 return d->m_verticalHeaderVisible;
370 return d->m_horizontalHeaderVisible;
375 d->m_iconSize = iconSize;
380 return d->m_iconSize;
385 return d->m_tableModel;
390 d->m_tableModel = tableModel;
400 return d->m_headerBackground;
405 d->m_horizontalHeaderFormatFunc = func;
410 d->m_verticalHeaderFormatFunc = func;
AbstractTableElement & operator=(const AbstractTableElement &other)
~AutoTableElement() override
QAbstractItemModel * tableModel() const
AutoTableElement(QAbstractItemModel *tableModel)
AutoTableElement & operator=(const AutoTableElement &other)
void setHorizontalHeaderVisible(bool visible)
QBrush headerBackground() const
void setModelKey(const QString &modelKey)
bool isHorizontalHeaderVisible() const
bool isVerticalHeaderVisible() const
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 setVerticalHeaderVisible(bool visible)
void setHorizontalHeaderFormatFunction(const CellFormatFunc &func)
Sets the function to call in order to customize the format of the cells created for the horizontal he...
void setIconSize(QSize iconSize)
std::function< void(int, QTextTableCellFormat &)> CellFormatFunc
void build(ReportBuilder &) const override
void setHeaderBackground(const QBrush &brush)
Element * clone() const override
TextDocumentData & currentDocumentData()
QTextDocument & currentDocument()
static QTextCharFormat::VerticalAlignment toVerticalAlignment(Qt::Alignment alignment)
void setupBlockFormat(QTextBlockFormat &blockFormat) const
QFont defaultFont() const
void addResourceName(const QString &resourceName)
void registerAutoTable(QTextTable *table, const KDReports::AutoTableElement *element)
QAbstractItemModel * modelForKey(const QString &key)