21 #include <QAbstractItemModel>
30 : m_tableBreakingPageOrder(
Report::DownThenRight)
31 , m_numHorizontalPages(1)
32 , m_numVerticalPages(0)
34 , m_userRequestedFontScalingFactor(1.0)
48 m_tableLayout.m_cellFont = font;
49 m_tableLayout.m_horizontalHeaderFont = font;
50 m_tableLayout.m_verticalHeaderFont = font;
56 return m_tableLayout.m_cellFont;
59 qreal KDReports::SpreadsheetReportLayout::paintTableVerticalHeader(qreal x, qreal y, QPainter &painter,
int row)
61 QAbstractItemModel *model = m_tableLayout.m_model;
63 const QRectF cellRect(x, y, m_tableLayout.vHeaderWidth(), m_tableLayout.rowHeight());
65 painter.setFont(m_tableLayout.verticalHeaderScaledFont());
66 painter.fillRect(cellRect, m_tableSettings.m_headerBackground);
67 drawBorder(cellRect, painter);
69 const QColor foreground = qvariant_cast<QColor>(model->headerData(row, Qt::Vertical, Qt::ForegroundRole));
70 if (foreground.isValid())
71 painter.setPen(foreground);
73 const QString cellText = model->headerData(row, Qt::Vertical).toString();
74 const qreal padding = m_tableLayout.scaledCellPadding();
75 const Qt::Alignment alignment(model->headerData(row, Qt::Vertical, Qt::TextAlignmentRole).toInt());
76 const QVariant cellDecoration = model->headerData(row, Qt::Vertical, Qt::DecorationRole);
79 const QRectF cellContentsRect = cellRect.adjusted(padding, padding, -padding, -padding);
81 paintTextAndIcon(painter, cellContentsRect, cellText, cellDecoration, decorationAlignment, alignment);
83 if (foreground.isValid())
84 painter.setPen(Qt::black);
86 x += cellRect.width();
90 void KDReports::SpreadsheetReportLayout::paintTableHorizontalHeader(
const QRectF &cellRect, QPainter &painter,
int col)
92 QAbstractItemModel *model = m_tableLayout.m_model;
94 painter.setFont(m_tableLayout.horizontalHeaderScaledFont());
96 painter.fillRect(cellRect.adjusted(-0.5, -0.5, -0.5, -0.5), m_tableSettings.m_headerBackground);
97 drawBorder(cellRect, painter);
99 const QColor foreground = qvariant_cast<QColor>(model->headerData(col, Qt::Horizontal, Qt::ForegroundRole));
100 if (foreground.isValid())
101 painter.setPen(foreground);
103 const QString cellText = model->headerData(col, Qt::Horizontal).toString();
104 const qreal padding = m_tableLayout.scaledCellPadding();
105 const Qt::Alignment alignment(model->headerData(col, Qt::Horizontal, Qt::TextAlignmentRole).toInt());
106 const QVariant cellDecoration = model->headerData(col, Qt::Horizontal, Qt::DecorationRole);
109 const QRectF cellContentsRect = cellRect.adjusted(padding, padding, -padding, -padding);
111 paintTextAndIcon(painter, cellContentsRect, cellText, cellDecoration, decorationAlignment, alignment);
113 if (foreground.isValid())
114 painter.setPen(Qt::black);
117 void KDReports::SpreadsheetReportLayout::paintIcon(QPainter &painter,
const QRectF &cellContentsRect,
const QVariant &cellDecoration)
const
119 QPixmap pix = qvariant_cast<QPixmap>(cellDecoration);
121 pix = qvariant_cast<QIcon>(cellDecoration).pixmap(m_tableLayout.m_iconSize);
123 qreal height = pix.height();
126 img = qvariant_cast<QImage>(cellDecoration);
129 height = img.height();
135 if (m_tableLayout.scalingFactor() != 1.) {
137 pix = pix.scaledToWidth(qRound(pix.width() * m_tableLayout.scalingFactor()));
138 height = pix.height();
140 img = img.scaledToWidth(qRound(img.width() * m_tableLayout.scalingFactor()));
141 height = img.height();
146 const int y = qMax(0,
int((cellContentsRect.height() - height) / 2.0));
147 const QPoint topLeft = cellContentsRect.topLeft().toPoint() + QPoint(0, y);
150 painter.drawImage(topLeft, img);
153 painter.drawPixmap(topLeft, pix);
158 void KDReports::SpreadsheetReportLayout::paintTextAndIcon(QPainter &painter,
const QRectF &cellContentsRect,
const QString &cellText,
const QVariant &cellDecoration,
159 const QVariant &decorationAlignment, Qt::Alignment alignment)
161 QRectF textRect = cellContentsRect;
163 const bool hasIcon = !cellDecoration.isNull();
165 const bool iconAfterText = decorationAlignment.isValid() && (decorationAlignment.toInt() & Qt::AlignRight);
167 iconWidth = m_tableLayout.decorationSize(cellDecoration).width() * m_tableLayout.scalingFactor();
169 if (!iconAfterText) {
170 paintIcon(painter, cellContentsRect, cellDecoration);
171 textRect.setLeft(textRect.left() + iconWidth + 2);
173 textRect.setWidth(textRect.width() - iconWidth - 2);
178 painter.drawText(textRect, alignment, cellText);
180 if (hasIcon && iconAfterText) {
181 QRectF iconRect = cellContentsRect;
182 iconRect.setLeft(iconRect.right() - iconWidth);
184 paintIcon(painter, iconRect, cellDecoration);
188 void KDReports::SpreadsheetReportLayout::drawBorder(
const QRectF &cellRect, QPainter &painter)
const
190 if (m_tableSettings.m_border > 0) {
191 const QPen oldPen = painter.pen();
195 painter.setPen(QPen(m_tableSettings.m_borderBrush.color(), m_tableSettings.m_border));
196 painter.drawRect(cellRect);
197 painter.setPen(oldPen);
204 QAbstractItemModel *model = m_tableLayout.m_model;
205 const qreal padding = m_tableLayout.scaledCellPadding();
206 const QRect cellCoords = m_pageRects[pageNumber];
209 const qreal rowHeight = m_tableLayout.rowHeight();
211 if (m_tableLayout.m_horizontalHeaderVisible) {
213 if (m_tableLayout.m_verticalHeaderVisible) {
214 x += m_tableLayout.vHeaderWidth();
216 for (
int col = cellCoords.left(); col <= cellCoords.right(); ++col) {
217 const QRectF cellRect(x, y, m_tableLayout.m_columnWidths[col], m_tableLayout.hHeaderHeight());
218 paintTableHorizontalHeader(cellRect, painter, col);
219 x += cellRect.width();
221 y += m_tableLayout.hHeaderHeight();
224 const int firstRow = cellCoords.top();
225 const int firstColumn = cellCoords.left();
226 const int numRows = cellCoords.height();
227 const int numColumns = cellCoords.width();
230 QVector<QBitArray> coveredCells;
231 coveredCells.resize(numRows);
232 for (
int row = firstRow; row <= cellCoords.bottom(); ++row)
233 coveredCells[row - firstRow].resize(numColumns);
235 for (
int row = firstRow; row <= cellCoords.bottom(); ++row) {
237 if (m_tableLayout.m_verticalHeaderVisible) {
238 x = paintTableVerticalHeader(x, y, painter, row);
240 painter.setFont(m_tableLayout.scaledFont());
241 for (
int col = cellCoords.left(); col <= cellCoords.right(); ++col) {
242 if (coveredCells[row - firstRow].testBit(col - firstColumn)) {
243 x += m_tableLayout.m_columnWidths[col];
247 const QModelIndex index = model->index(row, col);
249 const QSize span = model->span(index);
250 if (span.isValid()) {
251 for (
int r = row; r < row + span.height() && r < numRows; ++r) {
252 for (
int c = col; c < col + span.width() && c < numColumns; ++c) {
253 coveredCells[r - firstRow].setBit(c - firstColumn);
258 const QRectF cellRect(x, y, cellWidth(col, span.width()), qMax(1, span.height()) * rowHeight);
259 const QRectF cellContentsRect = cellRect.adjusted(padding, padding, -padding, -padding);
262 const QString cellText = model->data(index, Qt::DisplayRole).toString();
263 const QColor foreground = qvariant_cast<QColor>(model->data(index, Qt::ForegroundRole));
264 const QVariant background = model->data(index, Qt::BackgroundRole);
265 const Qt::Alignment alignment(model->data(index, Qt::TextAlignmentRole).toInt());
267 const QVariant cellDecoration(model->data(index, Qt::DecorationRole));
269 if (background.canConvert<QBrush>()) {
270 painter.fillRect(cellRect, background.value<QBrush>());
271 }
else if (span.isValid()) {
272 painter.fillRect(cellRect, Qt::white);
274 drawBorder(cellRect, painter);
285 if (foreground.isValid())
286 painter.setPen(foreground);
288 paintTextAndIcon(painter, cellContentsRect, cellText, cellDecoration, decorationAlignment, alignment);
290 if (foreground.isValid())
291 painter.setPen(Qt::black);
293 x += m_tableLayout.m_columnWidths[col];
303 return m_pageRects.count();
308 m_tableLayout.setInitialFontScalingFactor(m_userRequestedFontScalingFactor);
309 QAbstractItemModel *model = m_tableLayout.m_model;
312 m_tableLayout.updateColumnWidths();
313 const qreal total = totalWidth();
315 qDebug() <<
"idealWidth:" << total <<
"pixels";
321 qreal KDReports::SpreadsheetReportLayout::totalWidth()
const
323 qreal totalWidth = 0;
324 for (
int col = 0; col < m_tableLayout.m_columnWidths.size(); ++col) {
325 totalWidth += m_tableLayout.m_columnWidths[col];
327 if (m_tableLayout.m_verticalHeaderVisible)
328 totalWidth += m_tableLayout.vHeaderWidth();
332 qreal KDReports::SpreadsheetReportLayout::cellWidth(
int col,
int horizSpan)
const
334 qreal cellWidth = m_tableLayout.m_columnWidths[col];
335 for (
int extraCol = 1; extraCol < horizSpan; ++extraCol) {
336 cellWidth += m_tableLayout.m_columnWidths[col + extraCol];
343 m_pageContentSize = size;
345 qDebug() <<
"page content size" << m_pageContentSize;
354 if (m_pageContentSize.isEmpty()) {
355 qWarning(
"No paper size specified!");
359 m_tableLayout.setInitialFontScalingFactor(m_userRequestedFontScalingFactor);
362 QAbstractItemModel *model = m_tableLayout.m_model;
370 m_tableLayout.updateColumnWidths();
379 QVector<qreal> widthPerPage = optimizer.
widthPerPage(columnsPerPage);
380 const int horizPages = columnsPerPage.count();
385 const qreal horizMargins = 0 + 0 ;
386 const qreal verticalMargins = 0 + 0 ;
387 const qreal usablePageWidth = m_pageContentSize.width() - horizMargins;
388 const qreal usablePageHeight = m_pageContentSize.height() - verticalMargins - m_tableLayout.hHeaderHeight();
391 qDebug() <<
"usablePageHeight=" << m_pageContentSize.height() <<
"minus hHeaderHeight" << m_tableLayout.hHeaderHeight();
397 qreal bestScalingFactor = 1000000;
398 for (
int page = 0; page < horizPages; ++page) {
399 const qreal width = widthPerPage[page] + m_tableLayout.vHeaderWidth();
400 if (width > usablePageWidth) {
401 const qreal scalingFactor = usablePageWidth / width;
403 qDebug() <<
"page" << page <<
"sum of column widths:" << width <<
"usablePageWidth=" << usablePageWidth;
404 qDebug() <<
"scaling factor so that it fits horizontally:" << scalingFactor;
406 bestScalingFactor = qMin(bestScalingFactor, scalingFactor);
412 m_tableLayout.ensureScalingFactorForWidth(bestScalingFactor);
417 const int rowCount = m_tableLayout.m_model->rowCount();
418 if (m_numVerticalPages > 0) {
419 const qreal rowHeight = m_tableLayout.rowHeight();
429 const int maxRowsPerPage = qCeil(
static_cast<qreal
>(rowCount) / m_numVerticalPages);
430 const qreal maxRowHeight = usablePageHeight / maxRowsPerPage;
432 qDebug() <<
"usablePageHeight=" << usablePageHeight <<
"rowHeight=" << rowHeight <<
"maxRowsPerPage=" << maxRowsPerPage <<
"maxRowHeight=" << usablePageHeight <<
"/" << maxRowsPerPage <<
"="
435 if (rowHeight > maxRowHeight) {
436 m_tableLayout.ensureScalingFactorForHeight(maxRowHeight);
444 qDebug() <<
"final scaling factor" << m_tableLayout.scalingFactor();
445 qDebug() <<
"final fonts: cells:" << m_tableLayout.scaledFont().pointSizeF() <<
"hHeader:" << m_tableLayout.horizontalHeaderScaledFont().pointSizeF()
446 <<
"vHeader:" << m_tableLayout.verticalHeaderScaledFont().pointSizeF();
453 m_tableLayout.updateColumnWidths();
456 qDebug() <<
"New total width:" << totalWidth();
459 #if 0 // not used right now, but could be useful, especially if we want to goto step 3 again, to resize down
462 for (
int page = 0; page < horizPages; ++page ) {
463 const int numColumnsInPage = columnsPerPage[page];
464 widthPerPage[page] = 0;
465 for (
int col = column; col < column + numColumnsInPage; ++col) {
466 widthPerPage[page] += m_tableLayout.m_columnWidths[col];
469 const qreal width = widthPerPage[page] + m_tableLayout.vHeaderWidth();
470 if ( width > usablePageWidth ) {
471 qWarning() <<
"Too much width on page" << page;
474 column += numColumnsInPage;
476 qDebug() <<
"widthPerPage:" << widthPerPage;
480 const qreal rowHeight = m_tableLayout.rowHeight();
484 const int maxRowsPerPage = qFloor(usablePageHeight / rowHeight);
485 int verticPages = qCeil(qreal(rowCount) / qreal(maxRowsPerPage));
488 qDebug() <<
"maxRowsPerPage=" << usablePageHeight <<
"/" << rowHeight <<
"=" << maxRowsPerPage;
489 qDebug() <<
"pages:" << horizPages <<
"x" << verticPages;
490 qDebug() <<
"verticPages = qCeil(" << rowCount <<
"/" << maxRowsPerPage <<
") =" << verticPages;
495 if (m_numVerticalPages > 0) {
496 Q_ASSERT(verticPages <= m_numVerticalPages);
505 for (
int y = 0; y < verticPages; ++y) {
507 const int numRowsInPage = qMin(maxRowsPerPage, rowCount - row);
508 for (
int x = 0; x < horizPages; ++x) {
509 const int numColumnsInPage = columnsPerPage[x];
510 m_pageRects.append(QRect(column, row, numColumnsInPage, numRowsInPage));
511 column += numColumnsInPage;
513 row += maxRowsPerPage;
518 for (
int x = 0; x < horizPages; ++x) {
520 const int numColumnsInPage = columnsPerPage[x];
521 for (
int y = 0; y < verticPages; ++y) {
522 const int numRowsInPage = qMin(maxRowsPerPage, rowCount - row);
523 m_pageRects.append(QRect(column, row, numColumnsInPage, numRowsInPage));
524 row += maxRowsPerPage;
526 column += numColumnsInPage;
530 m_layoutDirty =
false;
542 m_tableLayout.setInitialFontScalingFactor(m_userRequestedFontScalingFactor);
543 const int rowCount = m_tableLayout.m_model->rowCount();
544 const qreal usableTotalHeight = m_tableLayout.rowHeight() * rowCount;
545 const qreal pageContentHeight = usableTotalHeight + 0 + m_tableLayout.hHeaderHeight();
547 m_pageContentSize = QSizeF(width, pageContentHeight);
549 qDebug() <<
"layoutAsOnePage: page content size" << m_pageContentSize << rowCount <<
"*" << m_tableLayout.rowHeight() <<
"+" << m_tableLayout.hHeaderHeight();
552 return pageContentHeight;
557 return QStringLiteral(
"Not implemented");
565 m_numHorizontalPages = numPagesHorizontally;
566 m_numVerticalPages = numPagesVertically;
573 m_tableLayout.m_fixedRowHeight = height;
578 return m_numHorizontalPages;
583 return m_numVerticalPages;
589 m_userRequestedFontScalingFactor = factor;
590 m_numHorizontalPages = 1;
591 m_numVerticalPages = 0;
597 return m_userRequestedFontScalingFactor;
610 m_tableBreakingPageOrder = order;
617 m_tableLayout.m_horizontalHeaderFont = font;
623 m_tableLayout.m_verticalHeaderFont = font;
630 m_tableLayout.m_model = model;
636 m_tableLayout.m_verticalHeaderVisible = visible;
642 m_tableLayout.m_horizontalHeaderVisible = visible;
656 m_tableLayout.m_iconSize = iconSize;
661 m_tableSettings.m_border = border;
662 m_tableSettings.m_borderBrush = borderBrush;
668 m_tableSettings.m_headerBackground = headerBackground;