1 /* ============================================================
2 *
3 * SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi>
4 * SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
5 *
6 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 *
8 * ============================================================ */
9
10 #include "ksanelistoption.h"
11
12 #include <QVarLengthArray>
13
14 #include <ksane_debug.h>
15
16 namespace KSaneIface
17 {
18
KSaneListOption(const SANE_Handle handle,const int index)19 KSaneListOption::KSaneListOption(const SANE_Handle handle, const int index)
20 : KSaneBaseOption(handle, index)
21 {
22 m_optionType = KSaneOption::TypeValueList;
23 }
24
readValue()25 void KSaneListOption::readValue()
26 {
27 if (state() == KSaneOption::StateHidden) {
28 return;
29 }
30
31 // read that current value
32 QVarLengthArray<unsigned char> data(m_optDesc->size);
33 SANE_Status status;
34 SANE_Int res;
35 status = sane_control_option(m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res);
36 if (status != SANE_STATUS_GOOD) {
37 return;
38 }
39
40 QVariant newValue;
41 switch (m_optDesc->type) {
42 case SANE_TYPE_INT:
43 newValue = static_cast<int>(toSANE_Word(data.data()));
44 break;
45 case SANE_TYPE_FIXED:
46 newValue = SANE_UNFIX(toSANE_Word(data.data()));
47 break;
48 case SANE_TYPE_STRING:
49 newValue = sane_i18n(reinterpret_cast<char *>(data.data()));
50 break;
51 default:
52 break;
53 }
54
55 if (newValue != m_currentValue) {
56 m_currentValue = newValue;
57 Q_EMIT valueChanged(m_currentValue);
58 }
59 }
60
valueList() const61 QVariantList KSaneListOption::valueList() const
62 {
63 int i;
64 QVariantList list;
65
66 switch (m_optDesc->type) {
67 case SANE_TYPE_INT:
68 for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
69 list << static_cast<int>(m_optDesc->constraint.word_list[i]);;
70 }
71 break;
72 case SANE_TYPE_FIXED:
73 for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
74 list << SANE_UNFIX(m_optDesc->constraint.word_list[i]);
75 }
76 break;
77 case SANE_TYPE_STRING:
78 i = 0;
79 while (m_optDesc->constraint.string_list[i] != nullptr) {
80 list << sane_i18n(m_optDesc->constraint.string_list[i]);
81 i++;
82 }
83 break;
84 default :
85 qCDebug(KSANE_LOG) << "can not handle type:" << m_optDesc->type;
86 break;
87 }
88 return list;
89 }
90
internalValueList() const91 QVariantList KSaneListOption::internalValueList() const
92 {
93 int i;
94 QVariantList list;
95
96 switch (m_optDesc->type) {
97 case SANE_TYPE_INT:
98 for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
99 list << static_cast<int>(m_optDesc->constraint.word_list[i]);;
100 }
101 break;
102 case SANE_TYPE_FIXED:
103 for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
104 list << SANE_UNFIX(m_optDesc->constraint.word_list[i]);
105 }
106 break;
107 case SANE_TYPE_STRING:
108 i = 0;
109 while (m_optDesc->constraint.string_list[i] != nullptr) {
110 list << QString::fromLatin1(m_optDesc->constraint.string_list[i]);
111 i++;
112 }
113 break;
114 default :
115 qCDebug(KSANE_LOG) << "can not handle type:" << m_optDesc->type;
116 break;
117 }
118 return list;
119 }
120
setValue(const QVariant & value)121 bool KSaneListOption::setValue(const QVariant &value)
122 {
123 bool success = false;
124 if (static_cast<QMetaType::Type>(value.type()) == QMetaType::QString) {
125 success = setValue(value.toString());
126 } else {
127 success = setValue(value.toDouble());
128 }
129
130 return success;
131 }
132
minimumValue() const133 QVariant KSaneListOption::minimumValue() const
134 {
135 QVariant value;
136 if (state() == KSaneOption::StateHidden) {
137 return value;
138 }
139 double dValueMin;
140 int iValueMin;
141 switch (m_optDesc->type) {
142 case SANE_TYPE_INT:
143 iValueMin = static_cast<int>(m_optDesc->constraint.word_list[1]);
144 for (int i = 2; i <= m_optDesc->constraint.word_list[0]; i++) {
145 iValueMin = qMin(static_cast<int>(m_optDesc->constraint.word_list[i]), iValueMin);
146 }
147 value = iValueMin;
148 break;
149 case SANE_TYPE_FIXED:
150 dValueMin = SANE_UNFIX(m_optDesc->constraint.word_list[1]);
151 for (int i = 2; i <= m_optDesc->constraint.word_list[0]; i++) {
152 dValueMin = qMin(SANE_UNFIX(m_optDesc->constraint.word_list[i]), dValueMin);
153 }
154 value = dValueMin;
155 break;
156 default:
157 qCDebug(KSANE_LOG) << "can not handle type:" << m_optDesc->type;
158 return value;
159 }
160 return value;
161 }
162
value() const163 QVariant KSaneListOption::value() const
164 {
165 if (state() == KSaneOption::StateHidden) {
166 return QVariant();
167 }
168 return m_currentValue;
169 }
170
setValue(double value)171 bool KSaneListOption::setValue(double value)
172 {
173 unsigned char data[4];
174 double tmp;
175 double minDiff;
176 int i;
177 int minIndex = 1;
178
179 switch (m_optDesc->type) {
180 case SANE_TYPE_INT:
181 tmp = static_cast<double>(m_optDesc->constraint.word_list[minIndex]);
182 minDiff = qAbs(value - tmp);
183 for (i = 2; i <= m_optDesc->constraint.word_list[0]; ++i) {
184 tmp = static_cast<double>(m_optDesc->constraint.word_list[i]);
185 if (qAbs(value - tmp) < minDiff) {
186 minDiff = qAbs(value - tmp);
187 minIndex = i;
188 }
189 }
190 fromSANE_Word(data, m_optDesc->constraint.word_list[minIndex]);
191 writeData(data);
192 readValue();
193 return (minDiff < 1.0);
194 case SANE_TYPE_FIXED:
195 tmp = SANE_UNFIX(m_optDesc->constraint.word_list[minIndex]);
196 minDiff = qAbs(value - tmp);
197 for (i = 2; i <= m_optDesc->constraint.word_list[0]; ++i) {
198 tmp = SANE_UNFIX(m_optDesc->constraint.word_list[i]);
199 if (qAbs(value - tmp) < minDiff) {
200 minDiff = qAbs(value - tmp);
201 minIndex = i;
202 }
203 }
204 fromSANE_Word(data, m_optDesc->constraint.word_list[minIndex]);
205 writeData(data);
206 readValue();
207 return (minDiff < 1.0);
208 default:
209 qCDebug(KSANE_LOG) << "can not handle type:" << m_optDesc->type;
210 break;
211 }
212 return false;
213 }
214
valueAsString() const215 QString KSaneListOption::valueAsString() const
216 {
217 if (state() == KSaneOption::StateHidden) {
218 return QString();
219 }
220 return m_currentValue.toString();
221 }
222
setValue(const QString & value)223 bool KSaneListOption::setValue(const QString &value)
224 {
225 if (state() == KSaneOption::StateHidden) {
226 return false;
227 }
228
229 unsigned char data[4];
230 void* data_ptr = nullptr;
231 SANE_Word fixed;
232 int i;
233 double d;
234 bool ok;
235 QString tmp;
236
237 switch (m_optDesc->type) {
238 case SANE_TYPE_INT:
239 i = value.toInt(&ok);
240 if (ok) {
241 fromSANE_Word(data, i);
242 data_ptr = data;
243 } else {
244 return false;
245 }
246
247 break;
248 case SANE_TYPE_FIXED:
249 d = value.toDouble(&ok);
250 if (ok) {
251 fixed = SANE_FIX(d);
252 fromSANE_Word(data, fixed);
253 data_ptr = data;
254 } else {
255 return false;
256 }
257
258 break;
259 case SANE_TYPE_STRING:
260 i = 0;
261 while (m_optDesc->constraint.string_list[i] != nullptr) {
262 tmp = QString::fromLatin1(m_optDesc->constraint.string_list[i]);
263 if (value != tmp) {
264 tmp = sane_i18n(m_optDesc->constraint.string_list[i]);
265 }
266 if (value == tmp) {
267 data_ptr = (void *)m_optDesc->constraint.string_list[i];
268 break;
269 }
270 i++;
271 }
272 if (m_optDesc->constraint.string_list[i] == nullptr) {
273 return false;
274 }
275 break;
276 default:
277 qCDebug(KSANE_LOG) << "can only handle SANE_TYPE: INT, FIXED and STRING";
278 return false;
279 }
280 writeData(data_ptr);
281
282 readValue();
283 return true;
284 }
285
286 } // NameSpace KSaneIface
287