KD Reports API Documentation  2.0
KDReportsTableLayout.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-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDAB-KDReports OR LicenseRef-KDAB-KDReports-US
8 **
9 ** Licensees holding valid commercial KD Reports licenses may use this file in
10 ** accordance with the KD Reports Commercial License Agreement provided with
11 ** the Software.
12 **
13 ** Contact info@kdab.com if any conditions of this licensing are not clear to you.
14 **
15 ****************************************************************************/
16 
17 #include "KDReportsTableLayout_p.h"
18 #include "KDReportsLayoutHelper_p.h" // mmToPixels
19 #include <QAbstractItemModel>
20 
21 #include <QDebug>
22 #include <QFontMetrics>
23 
24 using namespace KDReports;
25 
27  : m_model(nullptr)
28  , m_cellFont()
29  , m_horizontalHeaderFont()
30  , m_verticalHeaderFont()
31  , m_horizontalHeaderVisible(true)
32  , m_verticalHeaderVisible(true)
33  , m_cellPadding(KDReports::mmToPixels(0.5))
34  , m_fixedRowHeight(0)
35  , m_iconSize(32, 32)
36  , m_rowHeight(0)
37  , m_vHeaderWidth(0)
38  , m_hHeaderHeight(0)
39  , m_cellFontScaler(m_cellFont)
40  , m_horizontalHeaderFontScaler(m_horizontalHeaderFont)
41  , m_verticalHeaderFontScaler(m_verticalHeaderFont)
42 {
43 }
44 
45 void TableLayout::setInitialFontScalingFactor(qreal fontScalingFactor)
46 {
47  m_cellFontScaler.setFontAndScalingFactor(m_cellFont, fontScalingFactor);
49  m_horizontalHeaderFontScaler.setFontAndScalingFactor(m_horizontalHeaderFont, fontScalingFactor);
50  }
52  m_verticalHeaderFontScaler.setFontAndScalingFactor(m_verticalHeaderFont, fontScalingFactor);
53  }
54  updateRowHeight();
55 #ifdef DEBUG_LAYOUT
56  qDebug() << "initial m_rowHeight=" << m_rowHeight;
57 #endif
58 }
59 
60 void TableLayout::updateRowHeight()
61 {
62  if (m_fixedRowHeight > 0) {
63  m_rowHeight = m_fixedRowHeight;
64  return;
65  }
66  m_rowHeight = m_cellFontScaler.fontMetrics().height() + 2.0 * scaledCellPadding();
68  m_hHeaderHeight = m_horizontalHeaderFontScaler.fontMetrics().height() + 2.0 * scaledCellPadding();
69  }
71  qreal vHeaderHeight = m_verticalHeaderFontScaler.fontMetrics().height() + 2.0 * scaledCellPadding();
72 #ifdef DEBUG_LAYOUT
73  qDebug() << "cells say rowHeight=" << m_rowHeight << "vHeader says height=" << vHeaderHeight;
74 #endif
75  m_rowHeight = qMax(m_rowHeight, vHeaderHeight);
76  }
77 }
78 
80 {
81  if (!m_model) {
82  return;
83  }
84 
85  const QFontMetricsF fm = m_cellFontScaler.fontMetrics();
86  m_hHeaderHeight = 0;
87  const int colCount = m_model->columnCount();
88  // qDebug() << "Starting layout of table" << colCount << "columns" << m_model->rowCount() << "rows";
89  m_columnWidths.resize(colCount);
90  m_widestTextPerColumn.resize(colCount);
91  const int rowCount = m_model->rowCount();
92  for (int col = 0; col < colCount; ++col) {
93  m_columnWidths[col] = 0;
95  const QString cellText = m_model->headerData(col, Qt::Horizontal).toString();
96  const qreal textWidth = m_horizontalHeaderFontScaler.textWidth(cellText);
97  const qreal width = addIconWidth(textWidth, m_model->headerData(col, Qt::Horizontal, Qt::DecorationRole));
98  m_columnWidths[col] = qMax(m_columnWidths[col], width);
99  m_widestTextPerColumn[col] = cellText;
100  m_hHeaderHeight = qMax(m_hHeaderHeight, m_horizontalHeaderFontScaler.fontMetrics().height());
101  }
102  for (int row = 0; row < rowCount; ++row) {
103  const QModelIndex index = m_model->index(row, col);
104  if (m_model->span(index).width() > 1) {
105  // Ignore spanned cells. Not ideal of course, but we'll have to assume
106  // the other cells determine width, and this one just has to fit in.
107  // I guess a two-pass algorithm is needed otherwise, checking every spanned cell
108  // after the initial column width distribution? Urgh.
109  continue;
110  }
111  qreal width;
112  const QString cellText = m_model->data(index, Qt::DisplayRole).toString();
113  const QSizeF cellSize = m_model->data(index, Qt::SizeHintRole).toSizeF();
114  if (cellSize.isValid()) {
115  width = mmToPixels(cellSize.width());
116  } else {
117  const qreal textWidth = fm.size(0 /*flags*/, cellText).width();
118  width = addIconWidth(textWidth, m_model->data(index, Qt::DecorationRole));
119  }
120  if (width > m_columnWidths[col]) {
121  m_columnWidths[col] = width;
122  m_widestTextPerColumn[col] = cellText;
123  }
124  }
125  // qDebug() << "Column" << col << "width" << m_columnWidths[col] << "+padding=" << m_columnWidths[col]+2*scaledCellPadding();
126  m_columnWidths[col] += 2 * scaledCellPadding();
127  }
128 
129  m_vHeaderWidth = 0;
131  for (int row = 0; row < rowCount; ++row) {
132  const QString cellText = m_model->headerData(row, Qt::Vertical).toString();
133  const qreal textWidth = m_verticalHeaderFontScaler.textWidth(cellText);
134  const qreal width = addIconWidth(textWidth, m_model->headerData(row, Qt::Vertical, Qt::DecorationRole));
135  m_vHeaderWidth = qMax(m_vHeaderWidth, width);
136  }
137  m_vHeaderWidth += 2 * scaledCellPadding();
138 #ifdef DEBUG_LAYOUT
139  // qDebug() << "m_vHeaderWidth=" << m_vHeaderWidth;
140 #endif
141  }
143  m_hHeaderHeight += 2 * scaledCellPadding();
144  }
145 }
146 
147 #if 0
148 void TableLayout::updateColumnWidthsByFactor( qreal factor )
149 {
150  const int colCount = m_model->columnCount();
151  for ( int col = 0; col < colCount; ++col )
152  {
153  m_columnWidths[col] *= factor;
154  }
155  m_vHeaderWidth *= factor;
156 #ifdef DEBUG_LAYOUT
157  qDebug() << "updateColumnWidthsByFactor: after factor" << factor << "m_vHeaderWidth=" << m_vHeaderWidth;
158 #endif
159 
160 #ifdef DEBUG_LAYOUT
161  qDebug() << "final scaling factors:" << m_cellFontScaler.scalingFactor()
162  << m_horizontalHeaderFontScaler.scalingFactor()
163  << m_verticalHeaderFontScaler.scalingFactor();
164 #endif
165 }
166 #endif
167 
169 {
170 #ifdef DEBUG_LAYOUT
171  qDebug() << "TableLayout::ensureScalingFactorForWidth" << factor;
172 #endif
173  // ## fonts are definitely not proportional. QFontMetricsF::width for "Hello world"
174  // jumps from 40 to 32 just by changing the font size from 6.6 to 6.3...
175  // So instead of saying "applying this scaling factor", we should iterate over all
176  // columns, and resize the font down until the column has the desired width, then choose
177  // the min font size over all columns? Well, this might add up rounding problems, but
178  // at least it will always fit...
179 
180  const int colCount = m_model->columnCount();
181  QString textForScaling;
182  for (int col = 0; col < colCount; ++col) {
183  // Which column should we use as 'reference' for the scaling calculation?
184  // The widest or the narrowest one? Chose narrowest, more rounding problems there.
185  if (col == 0 || m_widestTextPerColumn[col].length() < textForScaling.length())
186  textForScaling = m_widestTextPerColumn[col];
187  }
188 
189  m_cellFontScaler.setFactorForWidth(factor, textForScaling);
190  m_horizontalHeaderFontScaler.setFactorForWidth(factor, textForScaling);
191  m_verticalHeaderFontScaler.setFactorForWidth(factor, textForScaling);
192  updateRowHeight();
193 }
194 
196 {
197  const qreal wantedRowHeightFactor = maxRowHeight / m_rowHeight;
198  // Apply _final_ padding when determining the wanted text height, obviously.
199  // Testcase with numbers: initial: 6+2*2=10. Wanted row height 5, so wanted factor 0.5
200  // so wanted text height = 5 - 2*1 = 3.
201  const qreal wantedTextHeight = maxRowHeight - 2.0 * wantedRowHeightFactor * scaledCellPadding();
202 #ifdef DEBUG_LAYOUT
203  qDebug() << " ensureScalingFactorForHeight: wantedRowHeightFactor=" << wantedRowHeightFactor << "wantedTextHeight=" << wantedTextHeight << "after removing padding ( unscaled" << m_cellPadding
204  << "current scaling" << scaledCellPadding() << "wanted" << wantedRowHeightFactor << "*" << m_cellPadding << "*" << scalingFactor() << "=" << wantedRowHeightFactor * scaledCellPadding()
205  << ")";
206 #endif
207  qreal additionalFactor = 0;
208 
209  // Let's see if the height is constrained by the cell font or by the vHeader font,
210  // that's the one that has to determine the scaling factor
211  if (m_cellFontScaler.fontMetrics().height() >= m_verticalHeaderFontScaler.fontMetrics().height()) {
212 #ifdef DEBUG_LAYOUT
213  qDebug() << " Reducing the cell font to be wantedTextHeight=" << wantedTextHeight;
214 #endif
215  const qreal initialCellFactor = m_cellFontScaler.scalingFactor();
216  m_cellFontScaler.setFactorForHeight(wantedTextHeight);
217  additionalFactor = m_cellFontScaler.scalingFactor() / initialCellFactor;
218 #ifdef DEBUG_LAYOUT
219  // qDebug() << " applying factor to m_verticalHeaderFontScaler";
220 #endif
221  m_verticalHeaderFontScaler.applyAdditionalScalingFactor(additionalFactor);
222  } else {
223  // bigger font in the vertical header
224 #ifdef DEBUG_LAYOUT
225  qDebug() << "Reducing the vertical header font to be wantedTextHeight=" << wantedTextHeight;
226 #endif
227  const qreal initialVerticHeaderFactor = m_verticalHeaderFontScaler.scalingFactor();
228  m_verticalHeaderFontScaler.setFactorForHeight(wantedTextHeight);
229  additionalFactor = m_verticalHeaderFontScaler.scalingFactor() / initialVerticHeaderFactor;
230 #ifdef DEBUG_LAYOUT
231  // qDebug() << " applying factor to m_cellFontScaler";
232 #endif
233  m_cellFontScaler.applyAdditionalScalingFactor(additionalFactor);
234  }
235 
236 #ifdef DEBUG_LAYOUT
237  // qDebug() << " Now we have cellFontScaler:" << m_cellFontScaler.fontMetrics().height()
238  // << "verticalheaderfontscaler:" << m_verticalHeaderFontScaler.fontMetrics().height();
239 #endif
240 
241  m_horizontalHeaderFontScaler.applyAdditionalScalingFactor(additionalFactor);
242  updateRowHeight();
243  // With very small fonts, we can't get less than 3 pixels high for the text.
244  m_rowHeight = qMin(maxRowHeight, m_rowHeight);
245 
246 #ifdef DEBUG_LAYOUT
247  qDebug() << " ensureScalingFactorForHeight: applied additional factor" << additionalFactor << "row height is now" << m_rowHeight;
248 #endif
249 }
250 
251 QSize KDReports::TableLayout::decorationSize(const QVariant &cellDecoration) const
252 {
253  QImage img = qvariant_cast<QImage>(cellDecoration);
254  if (!img.isNull()) {
255  return img.size();
256  }
257  QPixmap pix = qvariant_cast<QPixmap>(cellDecoration);
258  if (!pix.isNull()) {
259  return pix.size();
260  }
261  return m_iconSize;
262 }
263 
264 qreal KDReports::TableLayout::addIconWidth(qreal textWidth, const QVariant &cellDecoration) const
265 {
266  qreal width = textWidth;
267  if (!cellDecoration.isNull())
268  width += decorationSize(cellDecoration).width() + 2 /*see textRect adjustments in SpreadsheetReportLayout::paintPageContent*/;
269  return width;
270 }
KDReports::TableLayout::m_horizontalHeaderVisible
bool m_horizontalHeaderVisible
Definition: KDReportsTableLayout_p.h:66
KDReports::TableLayout::m_verticalHeaderVisible
bool m_verticalHeaderVisible
Definition: KDReportsTableLayout_p.h:67
KDReports::TableLayout::ensureScalingFactorForWidth
void ensureScalingFactorForWidth(qreal scalingFactor)
Definition: KDReportsTableLayout.cpp:168
KDReports::TableLayout::m_verticalHeaderFont
QFont m_verticalHeaderFont
Definition: KDReportsTableLayout_p.h:64
KDReports::TableLayout::TableLayout
TableLayout()
Definition: KDReportsTableLayout.cpp:26
KDReports::TableLayout::m_fixedRowHeight
qreal m_fixedRowHeight
Definition: KDReportsTableLayout_p.h:72
KDReports::FontScaler::scalingFactor
qreal scalingFactor() const
Definition: KDReportsFontScaler_p.h:83
KDReports::FontScaler::setFactorForWidth
void setFactorForWidth(qreal wantedFactor, const QString &sampleText)
Definition: KDReportsFontScaler.cpp:111
KDReports::TableLayout::m_columnWidths
QVector< qreal > m_columnWidths
Definition: KDReportsTableLayout_p.h:71
KDReports::FontScaler::textWidth
qreal textWidth(const QString &text) const
Definition: KDReportsFontScaler.cpp:78
KDReports::FontScaler::setFactorForHeight
void setFactorForHeight(qreal wantedHeight)
Definition: KDReportsFontScaler.cpp:83
KDReports::TableLayout::updateColumnWidths
void updateColumnWidths()
Definition: KDReportsTableLayout.cpp:79
KDReportsTableLayout_p.h
KDReports::TableLayout::m_widestTextPerColumn
QVector< QString > m_widestTextPerColumn
Definition: KDReportsTableLayout_p.h:74
KDReports::FontScaler::setFontAndScalingFactor
void setFontAndScalingFactor(const QFont &font, qreal scalingFactor)
Definition: KDReportsFontScaler.cpp:32
KDReports::mmToPixels
KDREPORTS_EXPORT qreal mmToPixels(qreal mm)
Definition: KDReportsLayoutHelper.cpp:23
KDReportsLayoutHelper_p.h
KDReports::TableLayout::m_model
QAbstractItemModel * m_model
Definition: KDReportsTableLayout_p.h:60
KDReports::TableLayout::m_cellFont
QFont m_cellFont
Definition: KDReportsTableLayout_p.h:62
KDReports::FontScaler::fontMetrics
QFontMetricsF fontMetrics() const
Definition: KDReportsFontScaler_p.h:82
KDReports::TableLayout::ensureScalingFactorForHeight
void ensureScalingFactorForHeight(qreal maxRowHeight)
Definition: KDReportsTableLayout.cpp:195
KDReports::TableLayout::scaledCellPadding
qreal scaledCellPadding() const
Definition: KDReportsTableLayout_p.h:56
KDReports::FontScaler::applyAdditionalScalingFactor
void applyAdditionalScalingFactor(qreal factor)
Definition: KDReportsFontScaler.cpp:47
KDReports::TableLayout::m_horizontalHeaderFont
QFont m_horizontalHeaderFont
Definition: KDReportsTableLayout_p.h:63
KDReports::TableLayout::setInitialFontScalingFactor
void setInitialFontScalingFactor(qreal fontScalingFactor)
Definition: KDReportsTableLayout.cpp:45
KDReports::TableLayout::scalingFactor
qreal scalingFactor() const
Definition: KDReportsTableLayout_p.h:53
KDReports::TableLayout::decorationSize
QSize decorationSize(const QVariant &cellDecoration) const
Definition: KDReportsTableLayout.cpp:251
KDReports::TableLayout::m_cellPadding
qreal m_cellPadding
Definition: KDReportsTableLayout_p.h:70
KDReports
Definition: KDReportsAbstractReportLayout_p.h:30

© 2007-2021 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 Sat Jan 8 2022 02:38:32 for KD Reports API Documentation by doxygen 1.8.17