File indexing completed on 2024-12-08 07:19:38
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi> 0003 * SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks 0004 * 0005 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "baseoption.h" 0009 0010 #include <ksanecore_debug.h> 0011 0012 namespace KSaneCore 0013 { 0014 0015 BaseOption::BaseOption() : QObject() 0016 { 0017 } 0018 0019 BaseOption::BaseOption(const SANE_Handle handle, const int index) 0020 : QObject(), m_handle(handle), m_index(index) 0021 { 0022 } 0023 0024 BaseOption::~BaseOption() 0025 { 0026 if (m_data) { 0027 free(m_data); 0028 m_data = nullptr; 0029 } 0030 } 0031 0032 void BaseOption::readOption() 0033 { 0034 beginOptionReload(); 0035 endOptionReload(); 0036 } 0037 0038 void BaseOption::beginOptionReload() 0039 { 0040 if (m_handle != nullptr) { 0041 m_optDesc = sane_get_option_descriptor(m_handle, m_index); 0042 } 0043 } 0044 0045 void BaseOption::endOptionReload() 0046 { 0047 Q_EMIT optionReloaded(); 0048 } 0049 0050 Option::OptionState BaseOption::state() const 0051 { 0052 if (m_optDesc == nullptr) { 0053 return Option::StateHidden; 0054 } 0055 0056 if (((m_optDesc->cap & SANE_CAP_SOFT_DETECT) == 0) || (m_optDesc->cap & SANE_CAP_INACTIVE) || ((m_optDesc->size == 0) && (type() != Option::TypeAction))) { 0057 return Option::StateHidden; 0058 } else if ((m_optDesc->cap & SANE_CAP_SOFT_SELECT) == 0) { 0059 return Option::StateDisabled; 0060 } 0061 return Option::StateActive; 0062 } 0063 0064 bool BaseOption::needsPolling() const 0065 { 0066 if (!m_optDesc) { 0067 return false; 0068 } 0069 0070 if ((m_optDesc->cap & SANE_CAP_SOFT_DETECT) && !(m_optDesc->cap & SANE_CAP_SOFT_SELECT)) { 0071 qCDebug(KSANECORE_LOG) << name() << "optDesc->cap =" << m_optDesc->cap; 0072 return true; 0073 } 0074 0075 return false; 0076 } 0077 0078 QString BaseOption::name() const 0079 { 0080 if (m_optDesc == nullptr) { 0081 return QString(); 0082 } 0083 return QString::fromUtf8(m_optDesc->name); 0084 } 0085 0086 QString BaseOption::title() const 0087 { 0088 if (m_optDesc == nullptr) { 0089 return QString(); 0090 } 0091 return sane_i18n(m_optDesc->title); 0092 } 0093 0094 QString BaseOption::description() const 0095 { 0096 if (m_optDesc == nullptr) { 0097 return QString(); 0098 } 0099 return sane_i18n(m_optDesc->desc); 0100 } 0101 0102 Option::OptionType BaseOption::type() const 0103 { 0104 return m_optionType; 0105 } 0106 0107 bool BaseOption::writeData(void *data) 0108 { 0109 SANE_Status status; 0110 SANE_Int res; 0111 0112 if (state() == Option::StateDisabled) { 0113 return false; 0114 } 0115 0116 status = sane_control_option(m_handle, m_index, SANE_ACTION_SET_VALUE, data, &res); 0117 if (status != SANE_STATUS_GOOD) { 0118 qCDebug(KSANECORE_LOG) << m_optDesc->name << "sane_control_option returned:" << sane_strstatus(status); 0119 // write failed. re read the current setting 0120 readValue(); 0121 return false; 0122 } 0123 if (res & SANE_INFO_INEXACT) { 0124 //qCDebug(KSANECORE_LOG) << "write was inexact. Reload value just in case..."; 0125 readValue(); 0126 } 0127 0128 if (res & SANE_INFO_RELOAD_OPTIONS) { 0129 Q_EMIT optionsNeedReload(); 0130 // optReload reloads also the values 0131 } else if (res & SANE_INFO_RELOAD_PARAMS) { 0132 // 'else if' because with optReload we force also valReload :) 0133 Q_EMIT valuesNeedReload(); 0134 } 0135 0136 return true; 0137 } 0138 0139 void BaseOption::readValue() {} 0140 0141 SANE_Word BaseOption::toSANE_Word(unsigned char *data) 0142 { 0143 SANE_Word tmp; 0144 // if __BYTE_ORDER is not defined we get #if 0 == 0 0145 #if __BYTE_ORDER == __LITTLE_ENDIAN 0146 tmp = (data[0] & 0xff); 0147 tmp += ((SANE_Word)(data[1] & 0xff)) << 8; 0148 tmp += ((SANE_Word)(data[2] & 0xff)) << 16; 0149 tmp += ((SANE_Word)(data[3] & 0xff)) << 24; 0150 #else 0151 tmp = (data[3] & 0xff); 0152 tmp += ((SANE_Word)(data[2] & 0xff)) << 8; 0153 tmp += ((SANE_Word)(data[1] & 0xff)) << 16; 0154 tmp += ((SANE_Word)(data[0] & 0xff)) << 24; 0155 #endif 0156 return tmp; 0157 } 0158 0159 void BaseOption::fromSANE_Word(unsigned char *data, SANE_Word from) 0160 { 0161 // if __BYTE_ORDER is not defined we get #if 0 == 0 0162 #if __BYTE_ORDER == __LITTLE_ENDIAN 0163 data[0] = (from & 0x000000FF); 0164 data[1] = (from & 0x0000FF00) >> 8; 0165 data[2] = (from & 0x00FF0000) >> 16; 0166 data[3] = (from & 0xFF000000) >> 24; 0167 #else 0168 data[3] = (from & 0x000000FF); 0169 data[2] = (from & 0x0000FF00) >> 8; 0170 data[1] = (from & 0x00FF0000) >> 16; 0171 data[0] = (from & 0xFF000000) >> 24; 0172 #endif 0173 } 0174 0175 QVariant BaseOption::value() const 0176 { 0177 return QVariant(); 0178 } 0179 0180 QVariant BaseOption::minimumValue() const 0181 { 0182 return QVariant(); 0183 } 0184 0185 QVariant BaseOption::maximumValue() const 0186 { 0187 return QVariant(); 0188 } 0189 0190 QVariant BaseOption::stepValue() const 0191 { 0192 return QVariant(); 0193 } 0194 0195 QVariantList BaseOption::valueList() const 0196 { 0197 return QVariantList(); 0198 } 0199 0200 QVariantList BaseOption::internalValueList() const 0201 { 0202 return QVariantList(); 0203 } 0204 0205 Option::OptionUnit BaseOption::valueUnit() const 0206 { 0207 if (m_optDesc != nullptr) { 0208 switch (m_optDesc->unit) { 0209 case SANE_UNIT_PIXEL: 0210 return Option::UnitPixel; 0211 case SANE_UNIT_BIT: 0212 return Option::UnitBit; 0213 case SANE_UNIT_MM: 0214 return Option::UnitMilliMeter; 0215 case SANE_UNIT_DPI: 0216 return Option::UnitDPI; 0217 case SANE_UNIT_PERCENT: 0218 return Option::UnitPercent; 0219 case SANE_UNIT_MICROSECOND: 0220 return Option::UnitMicroSecond; 0221 default: 0222 return Option::UnitNone; 0223 } 0224 } else { 0225 return Option::UnitNone; 0226 } 0227 } 0228 0229 int BaseOption::valueSize() const 0230 { 0231 if (m_optDesc != nullptr) { 0232 return m_optDesc->size / sizeof(SANE_Word); 0233 } 0234 return 0; 0235 } 0236 0237 QString BaseOption::valueAsString() const 0238 { 0239 return QString(); 0240 } 0241 0242 bool BaseOption::setValue(const QVariant &) 0243 { 0244 return false; 0245 } 0246 0247 bool BaseOption::storeCurrentData() 0248 { 0249 SANE_Status status; 0250 SANE_Int res; 0251 0252 // check if we can read the value 0253 if (state() == Option::StateHidden) { 0254 return false; 0255 } 0256 0257 // read that current value 0258 if (m_data != nullptr) { 0259 free(m_data); 0260 } 0261 m_data = (unsigned char *)malloc(m_optDesc->size); 0262 status = sane_control_option(m_handle, m_index, SANE_ACTION_GET_VALUE, m_data, &res); 0263 if (status != SANE_STATUS_GOOD) { 0264 qCDebug(KSANECORE_LOG) << m_optDesc->name << "sane_control_option returned" << status; 0265 return false; 0266 } 0267 return true; 0268 } 0269 0270 bool BaseOption::restoreSavedData() 0271 { 0272 // check if we have saved any data 0273 if (m_data == nullptr) { 0274 return false; 0275 } 0276 0277 // check if we can write the value 0278 if (state() == Option::StateHidden) { 0279 return false; 0280 } 0281 if (state() == Option::StateDisabled) { 0282 return false; 0283 } 0284 0285 writeData(m_data); 0286 readValue(); 0287 return true; 0288 } 0289 0290 Option::OptionType BaseOption::optionType(const SANE_Option_Descriptor *optDesc) 0291 { 0292 if (!optDesc) { 0293 return Option::TypeDetectFail; 0294 } 0295 0296 switch (optDesc->constraint_type) { 0297 case SANE_CONSTRAINT_NONE: 0298 switch (optDesc->type) { 0299 case SANE_TYPE_BOOL: 0300 return Option::TypeBool; 0301 case SANE_TYPE_INT: 0302 if (optDesc->size == sizeof(SANE_Word)) { 0303 return Option::TypeInteger; 0304 } 0305 qCDebug(KSANECORE_LOG) << "Can not handle:" << optDesc->title; 0306 qCDebug(KSANECORE_LOG) << "SANE_CONSTRAINT_NONE && SANE_TYPE_INT"; 0307 qCDebug(KSANECORE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)"; 0308 break; 0309 case SANE_TYPE_FIXED: 0310 if (optDesc->size == sizeof(SANE_Word)) { 0311 return Option::TypeDouble; 0312 } 0313 qCDebug(KSANECORE_LOG) << "Can not handle:" << optDesc->title; 0314 qCDebug(KSANECORE_LOG) << "SANE_CONSTRAINT_NONE && SANE_TYPE_FIXED"; 0315 qCDebug(KSANECORE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)"; 0316 break; 0317 case SANE_TYPE_BUTTON: 0318 return Option::TypeAction; 0319 case SANE_TYPE_STRING: 0320 return Option::TypeString; 0321 case SANE_TYPE_GROUP: 0322 return Option::TypeDetectFail; 0323 } 0324 break; 0325 case SANE_CONSTRAINT_RANGE: 0326 switch (optDesc->type) { 0327 case SANE_TYPE_BOOL: 0328 return Option::TypeBool; 0329 case SANE_TYPE_INT: 0330 if (optDesc->size == sizeof(SANE_Word)) { 0331 return Option::TypeInteger; 0332 } 0333 0334 if ((strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR) == 0) || 0335 (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_R) == 0) || 0336 (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_G) == 0) || 0337 (strcmp(optDesc->name, SANE_NAME_GAMMA_VECTOR_B) == 0)) { 0338 return Option::TypeGamma; 0339 } 0340 qCDebug(KSANECORE_LOG) << "Can not handle:" << optDesc->title; 0341 qCDebug(KSANECORE_LOG) << "SANE_CONSTRAINT_RANGE && SANE_TYPE_INT && !SANE_NAME_GAMMA_VECTOR..."; 0342 qCDebug(KSANECORE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)"; 0343 break; 0344 case SANE_TYPE_FIXED: 0345 if (optDesc->size == sizeof(SANE_Word)) { 0346 return Option::TypeDouble; 0347 } 0348 qCDebug(KSANECORE_LOG) << "Can not handle:" << optDesc->title; 0349 qCDebug(KSANECORE_LOG) << "SANE_CONSTRAINT_RANGE && SANE_TYPE_FIXED"; 0350 qCDebug(KSANECORE_LOG) << "size" << optDesc->size << "!= sizeof(SANE_Word)"; 0351 qCDebug(KSANECORE_LOG) << "Analog Gamma vector?"; 0352 break; 0353 case SANE_TYPE_STRING: 0354 qCDebug(KSANECORE_LOG) << "Can not handle:" << optDesc->title; 0355 qCDebug(KSANECORE_LOG) << "SANE_CONSTRAINT_RANGE && SANE_TYPE_STRING"; 0356 return Option::TypeDetectFail; 0357 case SANE_TYPE_BUTTON: 0358 return Option::TypeAction; 0359 case SANE_TYPE_GROUP: 0360 return Option::TypeDetectFail; 0361 } 0362 break; 0363 case SANE_CONSTRAINT_WORD_LIST: 0364 case SANE_CONSTRAINT_STRING_LIST: 0365 return Option::TypeValueList; 0366 } 0367 return Option::TypeDetectFail; 0368 } 0369 0370 } // namespace KSaneCore 0371 0372 #include "moc_baseoption.cpp"