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 "ksanebaseoption.h"
11
12 #include <ksane_debug.h>
13
14 namespace KSaneIface
15 {
16
KSaneBaseOption()17 KSaneBaseOption::KSaneBaseOption() : QObject()
18 {
19 }
20
KSaneBaseOption(const SANE_Handle handle,const int index)21 KSaneBaseOption::KSaneBaseOption(const SANE_Handle handle, const int index)
22 : QObject(), m_handle(handle), m_index(index)
23 {
24 }
25
~KSaneBaseOption()26 KSaneBaseOption::~KSaneBaseOption()
27 {
28 if (m_data) {
29 free(m_data);
30 m_data = nullptr;
31 }
32 }
33
readOption()34 void KSaneBaseOption::readOption()
35 {
36 if (m_handle != nullptr) {
37 m_optDesc = sane_get_option_descriptor(m_handle, m_index);
38 Q_EMIT optionReloaded();
39 }
40 }
41
state() const42 KSaneOption::KSaneOptionState KSaneBaseOption::state() const
43 {
44 if (m_optDesc == nullptr) {
45 return KSaneOption::StateHidden;
46 }
47
48 if (((m_optDesc->cap & SANE_CAP_SOFT_DETECT) == 0) ||
49 (m_optDesc->cap & SANE_CAP_INACTIVE) ||
50 ((m_optDesc->size == 0) && (type() != KSaneOption::TypeAction))) {
51 return KSaneOption::StateHidden;
52 } else if ((m_optDesc->cap & SANE_CAP_SOFT_SELECT) == 0) {
53 return KSaneOption::StateDisabled;
54 }
55 return KSaneOption::StateActive;
56 }
57
needsPolling() const58 bool KSaneBaseOption::needsPolling() const
59 {
60 if (!m_optDesc) {
61 return false;
62 }
63
64 if ((m_optDesc->cap & SANE_CAP_SOFT_DETECT) && !(m_optDesc->cap & SANE_CAP_SOFT_SELECT)) {
65 qCDebug(KSANE_LOG) << name() << "optDesc->cap =" << m_optDesc->cap;
66 return true;
67 }
68
69 return false;
70 }
71
name() const72 QString KSaneBaseOption::name() const
73 {
74 if (m_optDesc == nullptr) {
75 return QString();
76 }
77 return QString::fromUtf8(m_optDesc->name);
78 }
79
title() const80 QString KSaneBaseOption::title() const
81 {
82 if (m_optDesc == nullptr) {
83 return QString();
84 }
85 return sane_i18n(m_optDesc->title);
86 }
87
description() const88 QString KSaneBaseOption::description() const
89 {
90 if (m_optDesc == nullptr) {
91 return QString();
92 }
93 return sane_i18n(m_optDesc->desc);
94 }
95
type() const96 KSaneOption::KSaneOptionType KSaneBaseOption::type() const
97 {
98 return m_optionType;
99 }
100
writeData(void * data)101 bool KSaneBaseOption::writeData(void *data)
102 {
103 SANE_Status status;
104 SANE_Int res;
105
106 if (state() == KSaneOption::StateDisabled) {
107 return false;
108 }
109
110 status = sane_control_option(m_handle, m_index, SANE_ACTION_SET_VALUE, data, &res);
111 if (status != SANE_STATUS_GOOD) {
112 qCDebug(KSANE_LOG) << m_optDesc->name << "sane_control_option returned:" << sane_strstatus(status);
113 // write failed. re read the current setting
114 readValue();
115 return false;
116 }
117 if (res & SANE_INFO_INEXACT) {
118 //qCDebug(KSANE_LOG) << "write was inexact. Reload value just in case...";
119 readValue();
120 }
121
122 if (res & SANE_INFO_RELOAD_OPTIONS) {
123 Q_EMIT optionsNeedReload();
124 // optReload reloads also the values
125 } else if (res & SANE_INFO_RELOAD_PARAMS) {
126 // 'else if' because with optReload we force also valReload :)
127 Q_EMIT valuesNeedReload();
128 }
129
130 return true;
131 }
132
readValue()133 void KSaneBaseOption::readValue() {}
134
toSANE_Word(unsigned char * data)135 SANE_Word KSaneBaseOption::toSANE_Word(unsigned char *data)
136 {
137 SANE_Word tmp;
138 // if __BYTE_ORDER is not defined we get #if 0 == 0
139 #if __BYTE_ORDER == __LITTLE_ENDIAN
140 tmp = (data[0] & 0xff);
141 tmp += ((SANE_Word)(data[1] & 0xff)) << 8;
142 tmp += ((SANE_Word)(data[2] & 0xff)) << 16;
143 tmp += ((SANE_Word)(data[3] & 0xff)) << 24;
144 #else
145 tmp = (data[3] & 0xff);
146 tmp += ((SANE_Word)(data[2] & 0xff)) << 8;
147 tmp += ((SANE_Word)(data[1] & 0xff)) << 16;
148 tmp += ((SANE_Word)(data[0] & 0xff)) << 24;
149 #endif
150 return tmp;
151 }
152
fromSANE_Word(unsigned char * data,SANE_Word from)153 void KSaneBaseOption::fromSANE_Word(unsigned char *data, SANE_Word from)
154 {
155 // if __BYTE_ORDER is not defined we get #if 0 == 0
156 #if __BYTE_ORDER == __LITTLE_ENDIAN
157 data[0] = (from & 0x000000FF);
158 data[1] = (from & 0x0000FF00) >> 8;
159 data[2] = (from & 0x00FF0000) >> 16;
160 data[3] = (from & 0xFF000000) >> 24;
161 #else
162 data[3] = (from & 0x000000FF);
163 data[2] = (from & 0x0000FF00) >> 8;
164 data[1] = (from & 0x00FF0000) >> 16;
165 data[0] = (from & 0xFF000000) >> 24;
166 #endif
167 }
168
value() const169 QVariant KSaneBaseOption::value() const
170 {
171 return QVariant();
172 }
173
minimumValue() const174 QVariant KSaneBaseOption::minimumValue() const
175 {
176 return QVariant();
177 }
178
maximumValue() const179 QVariant KSaneBaseOption::maximumValue() const
180 {
181 return QVariant();
182 }
183
stepValue() const184 QVariant KSaneBaseOption::stepValue() const
185 {
186 return QVariant();
187 }
188
valueList() const189 QVariantList KSaneBaseOption::valueList() const
190 {
191 return QVariantList();
192 }
193
internalValueList() const194 QVariantList KSaneBaseOption::internalValueList() const
195 {
196 return QVariantList();
197 }
198
valueUnit() const199 KSaneOption::KSaneOptionUnit KSaneBaseOption::valueUnit() const
200 {
201 if (m_optDesc != nullptr) {
202 switch (m_optDesc->unit) {
203 case SANE_UNIT_PIXEL: return KSaneOption::UnitPixel;
204 case SANE_UNIT_BIT: return KSaneOption::UnitBit;
205 case SANE_UNIT_MM: return KSaneOption::UnitMilliMeter;
206 case SANE_UNIT_DPI: return KSaneOption::UnitDPI;
207 case SANE_UNIT_PERCENT: return KSaneOption::UnitPercent;
208 case SANE_UNIT_MICROSECOND: return KSaneOption::UnitMicroSecond;
209 default: return KSaneOption::UnitNone;
210 }
211 } else {
212 return KSaneOption::UnitNone;
213 }
214 }
215
valueSize() const216 int KSaneBaseOption::valueSize() const
217 {
218 if (m_optDesc != nullptr) {
219 return m_optDesc->size / sizeof(SANE_Word);
220 }
221 return 0;
222 }
223
valueAsString() const224 QString KSaneBaseOption::valueAsString() const
225 {
226 return QString();
227 }
228
setValue(const QVariant &)229 bool KSaneBaseOption::setValue(const QVariant &)
230 {
231 return false;
232 }
233
storeCurrentData()234 bool KSaneBaseOption::storeCurrentData()
235 {
236 SANE_Status status;
237 SANE_Int res;
238
239 // check if we can read the value
240 if (state() == KSaneOption::StateHidden) {
241 return false;
242 }
243
244 // read that current value
245 if (m_data != nullptr) {
246 free(m_data);
247 }
248 m_data = (unsigned char *)malloc(m_optDesc->size);
249 status = sane_control_option(m_handle, m_index, SANE_ACTION_GET_VALUE, m_data, &res);
250 if (status != SANE_STATUS_GOOD) {
251 qCDebug(KSANE_LOG) << m_optDesc->name << "sane_control_option returned" << status;
252 return false;
253 }
254 return true;
255 }
256
restoreSavedData()257 bool KSaneBaseOption::restoreSavedData()
258 {
259 // check if we have saved any data
260 if (m_data == nullptr) {
261 return false;
262 }
263
264 // check if we can write the value
265 if (state() == KSaneOption::StateHidden) {
266 return false;
267 }
268 if (state() == KSaneOption::StateDisabled) {
269 return false;
270 }
271
272 writeData(m_data);
273 readValue();
274 return true;
275 }
276
optionType(const SANE_Option_Descriptor * optDesc)277 KSaneOption::KSaneOptionType KSaneBaseOption::optionType(const SANE_Option_Descriptor *optDesc)
278 {
279 if (!optDesc) {
280 return KSaneOption::TypeDetectFail;
281 }
282
283 switch (optDesc->constraint_type) {
284 case SANE_CONSTRAINT_NONE:
285 switch (optDesc->type) {
286 case SANE_TYPE_BOOL:
287 return KSaneOption::TypeBool;
288 case SANE_TYPE_INT:
289 if (optDesc->size == sizeof(SANE_Word)) {
290 return KSaneOption::TypeInteger;
291 }
292 qCDebug(KSANE_LOG) << "Can not handle:" << optDesc->title;
293 qCDebug(KSANE_LOG) << "SANE_CONSTRAINT_NONE && SANE_TYPE_INT";
294 qCDebug(KSANE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)";
295 break;
296 case SANE_TYPE_FIXED:
297 if (optDesc->size == sizeof(SANE_Word)) {
298 return KSaneOption::TypeDouble;
299 }
300 qCDebug(KSANE_LOG) << "Can not handle:" << optDesc->title;
301 qCDebug(KSANE_LOG) << "SANE_CONSTRAINT_NONE && SANE_TYPE_FIXED";
302 qCDebug(KSANE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)";
303 break;
304 case SANE_TYPE_BUTTON:
305 return KSaneOption::TypeAction;
306 case SANE_TYPE_STRING:
307 return KSaneOption::TypeString;
308 case SANE_TYPE_GROUP:
309 return KSaneOption::TypeDetectFail;
310 }
311 break;
312 case SANE_CONSTRAINT_RANGE:
313 switch (optDesc->type) {
314 case SANE_TYPE_BOOL:
315 return KSaneOption::TypeBool;
316 case SANE_TYPE_INT:
317 if (optDesc->size == sizeof(SANE_Word)) {
318 return KSaneOption::TypeInteger;
319 }
320
321 if ((strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR) == 0) ||
322 (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_R) == 0) ||
323 (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_G) == 0) ||
324 (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_B) == 0)) {
325 return KSaneOption::TypeGamma;
326 }
327 qCDebug(KSANE_LOG) << "Can not handle:" << optDesc->title;
328 qCDebug(KSANE_LOG) << "SANE_CONSTRAINT_RANGE && SANE_TYPE_INT && !SANE_NAME_GAMMA_VECTOR...";
329 qCDebug(KSANE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)";
330 break;
331 case SANE_TYPE_FIXED:
332 if (optDesc->size == sizeof(SANE_Word)) {
333 return KSaneOption::TypeDouble;
334 }
335 qCDebug(KSANE_LOG) << "Can not handle:" << optDesc->title;
336 qCDebug(KSANE_LOG) << "SANE_CONSTRAINT_RANGE && SANE_TYPE_FIXED";
337 qCDebug(KSANE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)";
338 qCDebug(KSANE_LOG) << "Analog Gamma vector?";
339 break;
340 case SANE_TYPE_STRING:
341 qCDebug(KSANE_LOG) << "Can not handle:" << optDesc->title;
342 qCDebug(KSANE_LOG) << "SANE_CONSTRAINT_RANGE && SANE_TYPE_STRING";
343 return KSaneOption::TypeDetectFail;
344 case SANE_TYPE_BUTTON:
345 return KSaneOption::TypeAction;
346 case SANE_TYPE_GROUP:
347 return KSaneOption::TypeDetectFail;
348 }
349 break;
350 case SANE_CONSTRAINT_WORD_LIST:
351 case SANE_CONSTRAINT_STRING_LIST:
352 return KSaneOption::TypeValueList;
353 }
354 return KSaneOption::TypeDetectFail;
355 }
356
357 } // NameSpace KSaneIface
358