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

© 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 Wed Apr 24 2024 04:08:15 for KD Reports API Documentation by doxygen 1.9.8