KSaneCore

pagesizeoption.cpp
1/*
2 * SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi>
3 * SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
4 * SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9#include "pagesizeoption.h"
10
11#include <QPageSize>
12#include <QSizeF>
13
14#include <ksanecore_debug.h>
15
16static constexpr int PageSizeWiggleRoom = 2; // in mm
17
18namespace KSaneCore
19{
20
21PageSizeOption::PageSizeOption(BaseOption *optionTopLeftX,
22 BaseOption *optionTopLeftY,
23 BaseOption *optionBottomRightX,
24 BaseOption *optionBottomRightY,
25 BaseOption *optionResolution,
26 BaseOption *optionPageWidth,
27 BaseOption *optionPageHeight)
28 : BaseOption()
29{
30 if (optionTopLeftX == nullptr || optionTopLeftY == nullptr || optionBottomRightX == nullptr || optionBottomRightY == nullptr) {
31 m_optionType = Option::TypeDetectFail;
32 return;
33 }
34
35 connect(optionTopLeftX, &BaseOption::valueChanged, this, &PageSizeOption::optionTopLeftXUpdated);
36 connect(optionTopLeftY, &BaseOption::valueChanged, this, &PageSizeOption::optionTopLeftYUpdated);
37 connect(optionBottomRightX, &BaseOption::valueChanged, this, &PageSizeOption::optionBottomRightXUpdated);
38 connect(optionBottomRightY, &BaseOption::valueChanged, this, &PageSizeOption::optionBottomRightYUpdated);
39
40 m_optionTopLeftX = optionTopLeftX;
41 m_optionTopLeftY = optionTopLeftY;
42 m_optionBottomRightX = optionBottomRightX;
43 m_optionBottomRightY = optionBottomRightY;
44 m_optionResolution = optionResolution;
45 m_optionPageWidth = optionPageWidth;
46 m_optionPageHeight = optionPageHeight;
47
48 m_optionType = Option::TypeValueList;
49
50 computePageSizes();
51}
52
53bool PageSizeOption::setValue(const QVariant &value)
54{
55 if (value.userType() == QMetaType::QString) {
56 QString newValue = value.toString();
57 if (newValue == m_availableSizesListNames.at(m_currentIndex)) {
58 return true;
59 }
60 for (int i = 0; i < m_availableSizesListNames.size(); i++) {
61 QString sizeEntry = m_availableSizesListNames.at(i).toString();
62 if (sizeEntry == newValue) {
63 m_currentIndex = i;
64
65 if (i != 0) {
66 const auto size = m_availableSizesList.at(i);
67 if (m_optionPageWidth != nullptr && m_optionPageHeight != nullptr) {
68 m_optionPageWidth->setValue(size.width());
69 m_optionPageHeight->setValue(size.height());
70 }
71 m_optionTopLeftX->setValue(0);
72 m_optionTopLeftY->setValue(0);
73 m_optionBottomRightX->setValue(size.width());
74 m_optionBottomRightY->setValue(size.height());
75 }
76 Q_EMIT valueChanged(sizeEntry);
77 return true;
78 }
79 }
80 }
81 return false;
82}
83
84QVariant PageSizeOption::value() const
85{
86 if (m_currentIndex >= 0 && m_currentIndex < m_availableSizesListNames.size()) {
87 return m_availableSizesListNames.at(m_currentIndex);
88 } else {
89 return QVariant();
90 }
91}
92
93QString PageSizeOption::valueAsString() const
94{
95 if (m_currentIndex >= 0 && m_currentIndex < m_availableSizesListNames.size()) {
96 return m_availableSizesListNames.at(m_currentIndex).toString();
97 } else {
98 return QString();
99 }
100}
101
102QVariantList PageSizeOption::valueList() const
103{
104 return m_availableSizesListNames;
105}
106
107QVariantList PageSizeOption::internalValueList() const
108{
109 return m_availableSizesListNames;
110}
111
112Option::OptionState PageSizeOption::state() const
113{
114 return m_state;
115}
116
117QString PageSizeOption::name() const
118{
119 return PageSizeOptionName;
120}
121
122QString PageSizeOption::title() const
123{
124 return i18n("Scan area size");
125}
126
127QString PageSizeOption::description() const
128{
129 return i18n("Select a predefined page size for the scanning area.");
130}
131
132void PageSizeOption::optionTopLeftXUpdated()
133{
134 if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size() && m_optionTopLeftY->value().toDouble() != 0) {
135 m_currentIndex = 0;
136 Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
137 }
138}
139
140void PageSizeOption::optionTopLeftYUpdated()
141{
142 if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size() && m_optionTopLeftY->value().toDouble() != 0) {
143 m_currentIndex = 0;
144 Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
145 }
146}
147
148void PageSizeOption::optionBottomRightXUpdated()
149{
150 if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size()
151 && ensureMilliMeter(m_optionBottomRightX, m_optionBottomRightX->value().toDouble()) != m_availableSizesList.at(m_currentIndex).width()) {
152 m_currentIndex = 0;
153 Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
154 }
155}
156
157void PageSizeOption::optionBottomRightYUpdated()
158{
159 if (m_currentIndex > 0 && m_currentIndex < m_availableSizesList.size()
160 && ensureMilliMeter(m_optionBottomRightY, m_optionBottomRightY->value().toDouble()) != m_availableSizesList.at(m_currentIndex).height()) {
161 m_currentIndex = 0;
162 Q_EMIT valueChanged(QPageSize::name(QPageSize::Custom));
163 }
164}
165
166double PageSizeOption::ensureMilliMeter(BaseOption *option, double value)
167{
168 // convert if necessary with current DPI if available
169 if (option->valueUnit() == Option::UnitPixel && m_optionResolution != nullptr) {
170 double dpi = m_optionResolution->value().toDouble();
171 if (dpi > 1) {
172 return value / (dpi / 25.4);
173 }
174 }
175 return value;
176}
177
178void PageSizeOption::storeOptions()
179{
180 m_previousCoordinates[0] = m_optionTopLeftX->value().toDouble();
181 m_previousCoordinates[1] = m_optionTopLeftY->value().toDouble();
182 m_previousCoordinates[2] = m_optionBottomRightX->value().toDouble();
183 m_previousCoordinates[3] = m_optionBottomRightY->value().toDouble();
184}
185
186void PageSizeOption::restoreOptions()
187{
188 computePageSizes();
189 Q_EMIT optionReloaded();
190
191 m_optionTopLeftX->setValue(m_previousCoordinates[0]);
192 m_optionTopLeftY->setValue(m_previousCoordinates[1]);
193 m_optionBottomRightX->setValue(m_previousCoordinates[2]);
194 m_optionBottomRightY->setValue(m_previousCoordinates[3]);
195
196 int newIndex = 0;
197 if (m_optionTopLeftX->value().toDouble() == 0 && m_optionTopLeftY->value().toDouble() == 0) {
198 QSizeF currentSize = QSizeF(ensureMilliMeter(m_optionBottomRightX, m_optionBottomRightX->value().toDouble()),
199 ensureMilliMeter(m_optionBottomRightY, m_optionBottomRightY->value().toDouble()));
200
201 for (int i = 0; i < m_availableSizesList.count(); i++) {
202 if (qFuzzyCompare(currentSize.height(), m_availableSizesList.at(i).height())
203 && qFuzzyCompare(currentSize.width(), m_availableSizesList.at(i).width())) {
204 newIndex = i;
205 }
206 }
207 }
208 if (newIndex != m_currentIndex) {
209 m_currentIndex = newIndex;
210 Q_EMIT valueChanged(m_availableSizesListNames.at(m_currentIndex));
211 }
212}
213
214void PageSizeOption::computePageSizes()
215{
216 /* some SANE backends set the maximum value of bottom right X and Y to the current page width and height values
217 * set current values of these option to maximum if available, such that we detect possible page sizes correctly
218 * see https://gitlab.com/sane-project/backends/-/issues/730 and https://bugs.kde.org/show_bug.cgi?id=476838 */
219 if (m_optionPageWidth != nullptr && m_optionPageHeight != nullptr) {
220 m_optionPageHeight->storeCurrentData();
221 m_optionPageWidth->storeCurrentData();
222 m_optionPageHeight->setValue(m_optionPageHeight->maximumValue());
223 m_optionPageWidth->setValue(m_optionPageWidth->maximumValue());
224 }
225
226 const QList<QPageSize::PageSizeId> possibleSizesList = {
230 };
231
232 m_availableSizesList.clear();
233 m_availableSizesListNames.clear();
234
236 m_availableSizesListNames << QPageSize::name(QPageSize::Custom);
237
238 double maxScannerWidth = ensureMilliMeter(m_optionBottomRightX, m_optionBottomRightX->maximumValue().toDouble());
239 double maxScannerHeight = ensureMilliMeter(m_optionBottomRightY, m_optionBottomRightY->maximumValue().toDouble());
240
241 // Add portrait page sizes
242 for (const auto sizeCode : possibleSizesList) {
244 if (size.width() - PageSizeWiggleRoom > maxScannerWidth) {
245 continue;
246 }
247 if (size.height() - PageSizeWiggleRoom > maxScannerHeight) {
248 continue;
249 }
250 m_availableSizesList << size;
251 m_availableSizesListNames << QPageSize::name(sizeCode);
252 }
253
254 // Add landscape page sizes
255 for (const auto sizeCode : possibleSizesList) {
257 size.transpose();
258 if (size.width() - PageSizeWiggleRoom > maxScannerWidth) {
259 continue;
260 }
261 if (size.height() - PageSizeWiggleRoom > maxScannerHeight) {
262 continue;
263 }
264 m_availableSizesList << size;
265 m_availableSizesListNames << i18nc("Page size landscape", "Landscape %1", QPageSize::name(sizeCode));
266 }
267
268 // Set custom as current
269 m_currentIndex = 0;
270 if (m_availableSizesList.count() > 1) {
271 m_state = Option::StateActive;
272 } else {
273 m_state = Option::StateHidden;
274 }
275
276 if (m_optionPageWidth != nullptr && m_optionPageHeight != nullptr) {
277 m_optionPageHeight->restoreSavedData();
278 m_optionPageWidth->restoreSavedData();
279 }
280}
281
282} // namespace KSaneCore
283
284#include "moc_pagesizeoption.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void clear()
QString name() const const
QString name(PageSizeId pageSizeId)
QSizeF size(PageSizeId pageSizeId, Unit units)
qreal height() const const
void transpose()
qreal width() const const
const QChar at(qsizetype position) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString() const const
int userType() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Mar 7 2025 11:50:57 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.