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"