15 #include <QAbstractItemModel>
24 : m_tableBreakingPageOrder(
Report::DownThenRight)
25 , m_numHorizontalPages(1)
26 , m_numVerticalPages(0)
28 , m_userRequestedFontScalingFactor(1.0)
42 m_tableLayout.m_cellFont = font;
43 m_tableLayout.m_horizontalHeaderFont = font;
44 m_tableLayout.m_verticalHeaderFont = font;
50 return m_tableLayout.m_cellFont;
53 qreal KDReports::SpreadsheetReportLayout::paintTableVerticalHeader(qreal x, qreal y, QPainter &painter,
int row)
55 QAbstractItemModel *model = m_tableLayout.m_model;
57 const QRectF cellRect(x, y, m_tableLayout.vHeaderWidth(), m_tableLayout.rowHeight());
59 painter.setFont(m_tableLayout.verticalHeaderScaledFont());
60 painter.fillRect(cellRect, m_tableSettings.m_headerBackground);
61 drawBorder(cellRect, painter);
63 const QColor foreground = qvariant_cast<QColor>(model->headerData(row, Qt::Vertical, Qt::ForegroundRole));
64 if (foreground.isValid())
65 painter.setPen(foreground);
67 const QString cellText = model->headerData(row, Qt::Vertical).toString();
68 const qreal padding = m_tableLayout.scaledCellPadding();
69 const Qt::Alignment alignment(model->headerData(row, Qt::Vertical, Qt::TextAlignmentRole).toInt());
70 const QVariant cellDecoration = model->headerData(row, Qt::Vertical, Qt::DecorationRole);
73 const QRectF cellContentsRect = cellRect.adjusted(padding, padding, -padding, -padding);
75 paintTextAndIcon(painter, cellContentsRect, cellText, cellDecoration, decorationAlignment, alignment);
77 if (foreground.isValid())
78 painter.setPen(Qt::black);
80 x += cellRect.width();
84 void KDReports::SpreadsheetReportLayout::paintTableHorizontalHeader(
const QRectF &cellRect, QPainter &painter,
int col)
86 QAbstractItemModel *model = m_tableLayout.m_model;
88 painter.setFont(m_tableLayout.horizontalHeaderScaledFont());
90 painter.fillRect(cellRect.adjusted(-0.5, -0.5, -0.5, -0.5), m_tableSettings.m_headerBackground);
91 drawBorder(cellRect, painter);
93 const QColor foreground = qvariant_cast<QColor>(model->headerData(col, Qt::Horizontal, Qt::ForegroundRole));
94 if (foreground.isValid())
95 painter.setPen(foreground);
97 const QString cellText = model->headerData(col, Qt::Horizontal).toString();
98 const qreal padding = m_tableLayout.scaledCellPadding();
99 const Qt::Alignment alignment(model->headerData(col, Qt::Horizontal, Qt::TextAlignmentRole).toInt());
100 const QVariant cellDecoration = model->headerData(col, Qt::Horizontal, Qt::DecorationRole);
103 const QRectF cellContentsRect = cellRect.adjusted(padding, padding, -padding, -padding);
105 paintTextAndIcon(painter, cellContentsRect, cellText, cellDecoration, decorationAlignment, alignment);
107 if (foreground.isValid())
108 painter.setPen(Qt::black);
111 void KDReports::SpreadsheetReportLayout::paintIcon(QPainter &painter,
const QRectF &cellContentsRect,
const QVariant &cellDecoration)
const
113 QPixmap pix = qvariant_cast<QPixmap>(cellDecoration);
115 pix = qvariant_cast<QIcon>(cellDecoration).pixmap(m_tableLayout.m_iconSize);
117 qreal height = pix.height();
120 img = qvariant_cast<QImage>(cellDecoration);
123 height = img.height();
129 if (m_tableLayout.scalingFactor() != 1.) {
131 pix = pix.scaledToWidth(qRound(pix.width() * m_tableLayout.scalingFactor()));
132 height = pix.height();
134 img = img.scaledToWidth(qRound(img.width() * m_tableLayout.scalingFactor()));
135 height = img.height();
140 const int y = qMax(0,
int((cellContentsRect.height() - height) / 2.0));
141 const QPoint topLeft = cellContentsRect.topLeft().toPoint() + QPoint(0, y);
144 painter.drawImage(topLeft, img);
147 painter.drawPixmap(topLeft, pix);
152 void KDReports::SpreadsheetReportLayout::paintTextAndIcon(QPainter &painter,
const QRectF &cellContentsRect,
const QString &cellText,
const QVariant &cellDecoration,
153 const QVariant &decorationAlignment, Qt::Alignment alignment)
155 QRectF textRect = cellContentsRect;
157 const bool hasIcon = !cellDecoration.isNull();
159 const bool iconAfterText = decorationAlignment.isValid() && (decorationAlignment.toInt() & Qt::AlignRight);
161 iconWidth = m_tableLayout.decorationSize(cellDecoration).width() * m_tableLayout.scalingFactor();
163 if (!iconAfterText) {
164 paintIcon(painter, cellContentsRect, cellDecoration);
165 textRect.setLeft(textRect.left() + iconWidth + 2);
167 textRect.setWidth(textRect.width() - iconWidth - 2);
172 painter.drawText(textRect, alignment, cellText);
174 if (hasIcon && iconAfterText) {
175 QRectF iconRect = cellContentsRect;
176 iconRect.setLeft(iconRect.right() - iconWidth);
178 paintIcon(painter, iconRect, cellDecoration);
182 void KDReports::SpreadsheetReportLayout::drawBorder(
const QRectF &cellRect, QPainter &painter)
const
184 if (m_tableSettings.m_border > 0) {
185 const QPen oldPen = painter.pen();
189 painter.setPen(QPen(m_tableSettings.m_borderBrush.color(), m_tableSettings.m_border));
190 painter.drawRect(cellRect);
191 painter.setPen(oldPen);
198 QAbstractItemModel *model = m_tableLayout.m_model;
199 const qreal padding = m_tableLayout.scaledCellPadding();
200 const QRect cellCoords = m_pageRects[pageNumber];
203 const qreal rowHeight = m_tableLayout.rowHeight();
205 if (m_tableLayout.m_horizontalHeaderVisible) {
207 if (m_tableLayout.m_verticalHeaderVisible) {
208 x += m_tableLayout.vHeaderWidth();
210 for (
int col = cellCoords.left(); col <= cellCoords.right(); ++col) {
211 const QRectF cellRect(x, y, m_tableLayout.m_columnWidths[col], m_tableLayout.hHeaderHeight());
212 paintTableHorizontalHeader(cellRect, painter, col);
213 x += cellRect.width();
215 y += m_tableLayout.hHeaderHeight();
218 const int firstRow = cellCoords.top();
219 const int firstColumn = cellCoords.left();
220 const int numRows = cellCoords.height();
221 const int numColumns = cellCoords.width();
224 QVector<QBitArray> coveredCells;
225 coveredCells.resize(numRows);
226 for (
int row = firstRow; row <= cellCoords.bottom(); ++row)
227 coveredCells[row - firstRow].resize(numColumns);
229 for (
int row = firstRow; row <= cellCoords.bottom(); ++row) {
231 if (m_tableLayout.m_verticalHeaderVisible) {
232 x = paintTableVerticalHeader(x, y, painter, row);
234 painter.setFont(m_tableLayout.scaledFont());
235 for (
int col = cellCoords.left(); col <= cellCoords.right(); ++col) {
236 if (coveredCells[row - firstRow].testBit(col - firstColumn)) {
237 x += m_tableLayout.m_columnWidths[col];
241 const QModelIndex index = model->index(row, col);
243 const QSize span = model->span(index);
244 if (span.isValid()) {
245 for (
int r = row; r < row + span.height() && r < numRows; ++r) {
246 for (
int c = col; c < col + span.width() && c < numColumns; ++c) {
247 coveredCells[r - firstRow].setBit(c - firstColumn);
252 const QRectF cellRect(x, y, cellWidth(col, span.width()), qMax(1, span.height()) * rowHeight);
253 const QRectF cellContentsRect = cellRect.adjusted(padding, padding, -padding, -padding);
256 const QString cellText = model->data(index, Qt::DisplayRole).toString();
257 const QColor foreground = qvariant_cast<QColor>(model->data(index, Qt::ForegroundRole));
258 const QVariant background = model->data(index, Qt::BackgroundRole);
259 const Qt::Alignment alignment(model->data(index, Qt::TextAlignmentRole).toInt());
261 const QVariant cellDecoration(model->data(index, Qt::DecorationRole));
263 if (background.canConvert<QBrush>()) {
264 painter.fillRect(cellRect, background.value<QBrush>());
265 }
else if (span.isValid()) {
266 painter.fillRect(cellRect, Qt::white);
268 drawBorder(cellRect, painter);
279 if (foreground.isValid())
280 painter.setPen(foreground);
282 paintTextAndIcon(painter, cellContentsRect, cellText, cellDecoration, decorationAlignment, alignment);
284 if (foreground.isValid())
285 painter.setPen(Qt::black);
287 x += m_tableLayout.m_columnWidths[col];
297 return m_pageRects.count();
302 m_tableLayout.setInitialFontScalingFactor(m_userRequestedFontScalingFactor);
303 QAbstractItemModel *model = m_tableLayout.m_model;
306 m_tableLayout.updateColumnWidths();
307 const qreal total = totalWidth();
309 qDebug() <<
"idealWidth:" << total <<
"pixels";
315 qreal KDReports::SpreadsheetReportLayout::totalWidth()
const
317 qreal totalWidth = 0;
318 for (
int col = 0; col < m_tableLayout.m_columnWidths.size(); ++col) {
319 totalWidth += m_tableLayout.m_columnWidths[col];
321 if (m_tableLayout.m_verticalHeaderVisible)
322 totalWidth += m_tableLayout.vHeaderWidth();
326 qreal KDReports::SpreadsheetReportLayout::cellWidth(
int col,
int horizSpan)
const
328 qreal cellWidth = m_tableLayout.m_columnWidths[col];
329 for (
int extraCol = 1; extraCol < horizSpan; ++extraCol) {
330 cellWidth += m_tableLayout.m_columnWidths[col + extraCol];
337 m_pageContentSize = size;
339 qDebug() <<
"page content size" << m_pageContentSize;
348 if (m_pageContentSize.isEmpty()) {
349 qWarning(
"No paper size specified!");
353 m_tableLayout.setInitialFontScalingFactor(m_userRequestedFontScalingFactor);
356 QAbstractItemModel *model = m_tableLayout.m_model;
364 m_tableLayout.updateColumnWidths();
373 QVector<qreal> widthPerPage = optimizer.
widthPerPage(columnsPerPage);
374 const int horizPages = columnsPerPage.count();
379 const qreal horizMargins = 0 + 0 ;
380 const qreal verticalMargins = 0 + 0 ;
381 const qreal usablePageWidth = m_pageContentSize.width() - horizMargins;
382 const qreal usablePageHeight = m_pageContentSize.height() - verticalMargins - m_tableLayout.hHeaderHeight();
385 qDebug() <<
"usablePageHeight=" << m_pageContentSize.height() <<
"minus hHeaderHeight" << m_tableLayout.hHeaderHeight();
391 qreal bestScalingFactor = 1000000;
392 for (
int page = 0; page < horizPages; ++page) {
393 const qreal width = widthPerPage[page] + m_tableLayout.vHeaderWidth();
394 if (width > usablePageWidth) {
395 const qreal scalingFactor = usablePageWidth / width;
397 qDebug() <<
"page" << page <<
"sum of column widths:" << width <<
"usablePageWidth=" << usablePageWidth;
398 qDebug() <<
"scaling factor so that it fits horizontally:" << scalingFactor;
400 bestScalingFactor = qMin(bestScalingFactor, scalingFactor);
406 m_tableLayout.ensureScalingFactorForWidth(bestScalingFactor);
411 const int rowCount = m_tableLayout.m_model->rowCount();
412 if (m_numVerticalPages > 0) {
413 const qreal rowHeight = m_tableLayout.rowHeight();
423 const int maxRowsPerPage = qCeil(
static_cast<qreal
>(rowCount) / m_numVerticalPages);
424 const qreal maxRowHeight = usablePageHeight / maxRowsPerPage;
426 qDebug() <<
"usablePageHeight=" << usablePageHeight <<
"rowHeight=" << rowHeight <<
"maxRowsPerPage=" << maxRowsPerPage <<
"maxRowHeight=" << usablePageHeight <<
"/" << maxRowsPerPage <<
"="
429 if (rowHeight > maxRowHeight) {
430 m_tableLayout.ensureScalingFactorForHeight(maxRowHeight);
438 qDebug() <<
"final scaling factor" << m_tableLayout.scalingFactor();
439 qDebug() <<
"final fonts: cells:" << m_tableLayout.scaledFont().pointSizeF() <<
"hHeader:" << m_tableLayout.horizontalHeaderScaledFont().pointSizeF()
440 <<
"vHeader:" << m_tableLayout.verticalHeaderScaledFont().pointSizeF();
447 m_tableLayout.updateColumnWidths();
450 qDebug() <<
"New total width:" << totalWidth();
456 for (
int page = 0; page < horizPages; ++page ) {
457 const int numColumnsInPage = columnsPerPage[page];
458 widthPerPage[page] = 0;
459 for (
int col = column; col < column + numColumnsInPage; ++col) {
460 widthPerPage[page] += m_tableLayout.m_columnWidths[col];
463 const qreal width = widthPerPage[page] + m_tableLayout.vHeaderWidth();
464 if ( width > usablePageWidth ) {
465 qWarning() <<
"Too much width on page" << page;
468 column += numColumnsInPage;
470 qDebug() <<
"widthPerPage:" << widthPerPage;
474 const qreal rowHeight = m_tableLayout.rowHeight();
478 const int maxRowsPerPage = qFloor(usablePageHeight / rowHeight);
479 int verticPages = qCeil(qreal(rowCount) / qreal(maxRowsPerPage));
482 qDebug() <<
"maxRowsPerPage=" << usablePageHeight <<
"/" << rowHeight <<
"=" << maxRowsPerPage;
483 qDebug() <<
"pages:" << horizPages <<
"x" << verticPages;
484 qDebug() <<
"verticPages = qCeil(" << rowCount <<
"/" << maxRowsPerPage <<
") =" << verticPages;
489 if (m_numVerticalPages > 0) {
490 Q_ASSERT(verticPages <= m_numVerticalPages);
499 for (
int y = 0; y < verticPages; ++y) {
501 const int numRowsInPage = qMin(maxRowsPerPage, rowCount - row);
502 for (
int x = 0; x < horizPages; ++x) {
503 const int numColumnsInPage = columnsPerPage[x];
504 m_pageRects.append(QRect(column, row, numColumnsInPage, numRowsInPage));
505 column += numColumnsInPage;
507 row += maxRowsPerPage;
512 for (
int x = 0; x < horizPages; ++x) {
514 const int numColumnsInPage = columnsPerPage[x];
515 for (
int y = 0; y < verticPages; ++y) {
516 const int numRowsInPage = qMin(maxRowsPerPage, rowCount - row);
517 m_pageRects.append(QRect(column, row, numColumnsInPage, numRowsInPage));
518 row += maxRowsPerPage;
520 column += numColumnsInPage;
524 m_layoutDirty =
false;
536 m_tableLayout.setInitialFontScalingFactor(m_userRequestedFontScalingFactor);
537 const int rowCount = m_tableLayout.m_model->rowCount();
538 const qreal usableTotalHeight = m_tableLayout.rowHeight() * rowCount;
539 const qreal pageContentHeight = usableTotalHeight + 0 + m_tableLayout.hHeaderHeight();
541 m_pageContentSize = QSizeF(width, pageContentHeight);
543 qDebug() <<
"layoutAsOnePage: page content size" << m_pageContentSize << rowCount <<
"*" << m_tableLayout.rowHeight() <<
"+" << m_tableLayout.hHeaderHeight();
546 return pageContentHeight;
551 return QStringLiteral(
"Not implemented");
561 m_numHorizontalPages = numPagesHorizontally;
562 m_numVerticalPages = numPagesVertically;
569 m_tableLayout.m_fixedRowHeight = height;
574 return m_numHorizontalPages;
579 return m_numVerticalPages;
585 m_userRequestedFontScalingFactor = factor;
586 m_numHorizontalPages = 1;
587 m_numVerticalPages = 0;
593 return m_userRequestedFontScalingFactor;
606 m_tableBreakingPageOrder = order;
613 m_tableLayout.m_horizontalHeaderFont = font;
619 m_tableLayout.m_verticalHeaderFont = font;
626 m_tableLayout.m_model = model;
632 m_tableLayout.m_verticalHeaderVisible = visible;
638 m_tableLayout.m_horizontalHeaderVisible = visible;
652 m_tableLayout.m_iconSize = iconSize;
657 m_tableSettings.m_border = border;
658 m_tableSettings.m_borderBrush = borderBrush;
664 m_tableSettings.m_headerBackground = headerBackground;
@ DecorationAlignmentRole
This model role allows to specify whether the icon should go before the text (Qt::AlignLeft) or after...
int maximumNumberOfPagesForVerticalScaling() const override
Reimplemented for internal purposes. .
void setTableBreakingPageOrder(KDReports::Report::TableBreakingPageOrder order)
int maximumNumberOfPagesForHorizontalScaling() const override
Reimplemented for internal purposes. .
QString toHtml() const override
Reimplemented for internal purposes. .
SpreadsheetReportLayout(KDReports::Report *report)
int numberOfPages() override
Reimplemented for internal purposes. .
void setVerticalHeaderVisible(bool visible)
void setIconSize(QSize iconSize)
void setCellBorder(qreal border, const QBrush &borderBrush)
void setUserRequestedFontScalingFactor(qreal factor) override
Reimplemented for internal purposes. .
void ensureLayouted() override
Reimplemented for internal purposes. .
bool scaleTo(int numPagesHorizontally, int numPagesVertically) override
Reimplemented for internal purposes. .
void setPageContentSize(QSizeF size) override
Reimplemented for internal purposes. .
void updateTextValue(const QString &id, const QString &newValue) override
Reimplemented for internal purposes. .
void setHorizontalHeaderFont(const QFont &font)
QFont defaultFont() const override
Reimplemented for internal purposes. .
void setHeaderBackground(const QBrush &headerBackground)
qreal idealWidth() override
Reimplemented for internal purposes. .
void paintPageContent(int pageNumber, QPainter &painter) override
Reimplemented for internal purposes. .
QString anchorAt(int pageNumber, QPoint pos) override
Reimplemented for internal purposes. .
void setCellPadding(qreal padding)
void finishHtmlExport() override
Reimplemented for internal purposes. .
void setDefaultFont(const QFont &font) override
Reimplemented for internal purposes. .
qreal userRequestedFontScalingFactor() const override
Reimplemented for internal purposes. .
qreal layoutAsOnePage(qreal width) override
Reimplemented for internal purposes. .
void setVerticalHeaderFont(const QFont &font)
void setFixedRowHeight(qreal height) override
Reimplemented for internal purposes. .
void setHorizontalHeaderVisible(bool visible)
void setModel(QAbstractItemModel *model)
void setLayoutDirty() override
Reimplemented for internal purposes. .
QVector< int > columnsPerPage() const
void setColumnWidths(const WidthVector &widths)
WidthVector widthPerPage(const QVector< int > &colPerPage) const
void setPageCount(int pages)
KDREPORTS_EXPORT qreal mmToPixels(qreal mm)