File indexing completed on 2024-12-08 07:19:39

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 "listoption.h"
0009 
0010 #include <QVarLengthArray>
0011 
0012 #include <ksanecore_debug.h>
0013 
0014 namespace KSaneCore
0015 {
0016 
0017 ListOption::ListOption(const SANE_Handle handle, const int index)
0018     : BaseOption(handle, index)
0019 {
0020     m_optionType = Option::TypeValueList;
0021 }
0022 
0023 void ListOption::readValue()
0024 {
0025     if (BaseOption::state() == Option::StateHidden) {
0026         return;
0027     }
0028 
0029     // read that current value
0030     QVarLengthArray<unsigned char> data(m_optDesc->size);
0031     SANE_Status status;
0032     SANE_Int res;
0033     status = sane_control_option(m_handle, m_index, SANE_ACTION_GET_VALUE, data.data(), &res);
0034     if (status != SANE_STATUS_GOOD) {
0035         return;
0036     }
0037 
0038     QVariant newValue;
0039     switch (m_optDesc->type) {
0040     case SANE_TYPE_INT:
0041         newValue = static_cast<int>(toSANE_Word(data.data()));
0042         break;
0043     case SANE_TYPE_FIXED:
0044         newValue = SANE_UNFIX(toSANE_Word(data.data()));
0045         break;
0046     case SANE_TYPE_STRING:
0047         newValue = sane_i18n(reinterpret_cast<char *>(data.data()));
0048         break;
0049     default:
0050         break;
0051     }
0052 
0053     if (newValue != m_currentValue) {
0054         m_currentValue = newValue;
0055         Q_EMIT valueChanged(m_currentValue);
0056     }
0057 }
0058 
0059 void ListOption::readOption()
0060 {
0061     beginOptionReload();
0062     countEntries();
0063     endOptionReload();
0064 }
0065 
0066 QVariantList ListOption::valueList() const
0067 {
0068     int i;
0069     QVariantList list;
0070     list.reserve(m_entriesCount);
0071 
0072     switch (m_optDesc->type) {
0073     case SANE_TYPE_INT:
0074         for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
0075             list << static_cast<int>(m_optDesc->constraint.word_list[i]);;
0076         }
0077         break;
0078     case SANE_TYPE_FIXED:
0079         for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
0080             list << SANE_UNFIX(m_optDesc->constraint.word_list[i]);
0081         }
0082         break;
0083     case SANE_TYPE_STRING:
0084         i = 0;
0085         while (m_optDesc->constraint.string_list[i] != nullptr) {
0086             list << sane_i18n(m_optDesc->constraint.string_list[i]);
0087             i++;
0088         }
0089         break;
0090     default :
0091         qCDebug(KSANECORE_LOG) << "can not handle type:" << m_optDesc->type;
0092         break;
0093     }
0094     return list;
0095 }
0096 
0097 QVariantList ListOption::internalValueList() const
0098 {
0099     int i;
0100     QVariantList list;
0101     list.reserve(m_entriesCount);
0102 
0103     switch (m_optDesc->type) {
0104     case SANE_TYPE_INT:
0105         for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
0106             list << static_cast<int>(m_optDesc->constraint.word_list[i]);;
0107         }
0108         break;
0109     case SANE_TYPE_FIXED:
0110         for (i = 1; i <= m_optDesc->constraint.word_list[0]; ++i) {
0111             list << SANE_UNFIX(m_optDesc->constraint.word_list[i]);
0112         }
0113         break;
0114     case SANE_TYPE_STRING:
0115         i = 0;
0116         while (m_optDesc->constraint.string_list[i] != nullptr) {
0117             list << QString::fromLatin1(m_optDesc->constraint.string_list[i]);
0118             i++;
0119         }
0120         break;
0121     default :
0122         qCDebug(KSANECORE_LOG) << "can not handle type:" << m_optDesc->type;
0123         break;
0124     }
0125     return list;
0126 }
0127 
0128 bool ListOption::setValue(const QVariant &value)
0129 {
0130     bool success = false;
0131 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0132     if (static_cast<QMetaType::Type>(value.type()) == QMetaType::QString) {
0133 #else
0134     if (value.userType() == QMetaType::QString) {
0135 #endif
0136         success = setValue(value.toString());
0137     } else {
0138         success = setValue(value.toDouble());
0139     }
0140 
0141     return success;
0142 }
0143 
0144 QVariant ListOption::minimumValue() const
0145 {
0146     QVariant value;
0147     if (BaseOption::state() == Option::StateHidden) {
0148         return value;
0149     }
0150     double dValueMin;
0151     int iValueMin;
0152     switch (m_optDesc->type) {
0153     case SANE_TYPE_INT:
0154         iValueMin = static_cast<int>(m_optDesc->constraint.word_list[1]);
0155         for (int i = 2; i <= m_optDesc->constraint.word_list[0]; i++) {
0156             iValueMin = qMin(static_cast<int>(m_optDesc->constraint.word_list[i]), iValueMin);
0157         }
0158         value = iValueMin;
0159         break;
0160     case SANE_TYPE_FIXED:
0161         dValueMin = SANE_UNFIX(m_optDesc->constraint.word_list[1]);
0162         for (int i = 2; i <= m_optDesc->constraint.word_list[0]; i++) {
0163             dValueMin = qMin(SANE_UNFIX(m_optDesc->constraint.word_list[i]), dValueMin);
0164         }
0165         value = dValueMin;
0166         break;
0167     default:
0168         qCDebug(KSANECORE_LOG) << "can not handle type:" << m_optDesc->type;
0169         return value;
0170     }
0171     return value;
0172 }
0173 
0174 QVariant ListOption::value() const
0175 {
0176     if (BaseOption::state() == Option::StateHidden) {
0177         return QVariant();
0178     }
0179     return m_currentValue;
0180 }
0181 
0182 bool ListOption::setValue(double value)
0183 {
0184     unsigned char data[4];
0185     double tmp;
0186     double minDiff;
0187     int i;
0188     int minIndex = 1;
0189 
0190     switch (m_optDesc->type) {
0191     case SANE_TYPE_INT:
0192         tmp = static_cast<double>(m_optDesc->constraint.word_list[minIndex]);
0193         minDiff = qAbs(value - tmp);
0194         for (i = 2; i <= m_optDesc->constraint.word_list[0]; ++i) {
0195             tmp = static_cast<double>(m_optDesc->constraint.word_list[i]);
0196             if (qAbs(value - tmp) < minDiff) {
0197                 minDiff = qAbs(value - tmp);
0198                 minIndex = i;
0199             }
0200         }
0201         fromSANE_Word(data, m_optDesc->constraint.word_list[minIndex]);
0202         writeData(data);
0203         readValue();
0204         return (minDiff < 1.0);
0205     case SANE_TYPE_FIXED:
0206         tmp = SANE_UNFIX(m_optDesc->constraint.word_list[minIndex]);
0207         minDiff = qAbs(value - tmp);
0208         for (i = 2; i <= m_optDesc->constraint.word_list[0]; ++i) {
0209             tmp = SANE_UNFIX(m_optDesc->constraint.word_list[i]);
0210             if (qAbs(value - tmp) < minDiff) {
0211                 minDiff = qAbs(value - tmp);
0212                 minIndex = i;
0213             }
0214         }
0215         fromSANE_Word(data, m_optDesc->constraint.word_list[minIndex]);
0216         writeData(data);
0217         readValue();
0218         return (minDiff < 1.0);
0219     default:
0220         qCDebug(KSANECORE_LOG) << "can not handle type:" << m_optDesc->type;
0221         break;
0222     }
0223     return false;
0224 }
0225 
0226 QString ListOption::valueAsString() const
0227 {
0228     if (BaseOption::state() == Option::StateHidden) {
0229         return QString();
0230     }
0231     return m_currentValue.toString();
0232 }
0233 
0234 bool ListOption::setValue(const QString &value)
0235 {
0236     if (BaseOption::state() == Option::StateHidden) {
0237         return false;
0238     }
0239 
0240     unsigned char data[4];
0241     void* data_ptr = nullptr;
0242     SANE_Word fixed;
0243     int i;
0244     double d;
0245     bool ok;
0246     QString tmp;
0247 
0248     switch (m_optDesc->type) {
0249     case SANE_TYPE_INT:
0250         i = value.toInt(&ok);
0251         if (ok) {
0252             fromSANE_Word(data, i);
0253             data_ptr = data;
0254         } else {
0255             return false;
0256         }
0257 
0258         break;
0259     case SANE_TYPE_FIXED:
0260         d = value.toDouble(&ok);
0261         if (ok) {
0262             fixed = SANE_FIX(d);
0263             fromSANE_Word(data, fixed);
0264             data_ptr = data;
0265         } else {
0266             return false;
0267         }
0268 
0269         break;
0270     case SANE_TYPE_STRING:
0271         i = 0;
0272         while (m_optDesc->constraint.string_list[i] != nullptr) {
0273             tmp = QString::fromLatin1(m_optDesc->constraint.string_list[i]);
0274             if (value != tmp) {
0275                 tmp = sane_i18n(m_optDesc->constraint.string_list[i]);
0276             }
0277             if (value == tmp) {
0278                 data_ptr = (void *)m_optDesc->constraint.string_list[i];
0279                 break;
0280             }
0281             i++;
0282         }
0283         if (m_optDesc->constraint.string_list[i] == nullptr) {
0284             return false;
0285         }
0286         break;
0287     default:
0288         qCDebug(KSANECORE_LOG) << "can only handle SANE_TYPE: INT, FIXED and STRING";
0289         return false;
0290     }
0291     writeData(data_ptr);
0292 
0293     readValue();
0294     return true;
0295 }
0296 
0297 void ListOption::countEntries()
0298 {
0299     m_entriesCount = 0;
0300 
0301     switch (m_optDesc->type) {
0302 
0303     case SANE_TYPE_INT:
0304     case SANE_TYPE_FIXED:
0305         m_entriesCount = m_optDesc->constraint.word_list[0];
0306         break;
0307 
0308     case SANE_TYPE_STRING:
0309         while (m_optDesc->constraint.string_list[m_entriesCount] != nullptr) {
0310             m_entriesCount++;
0311         }
0312         break;
0313 
0314     default :
0315         qCDebug(KSANECORE_LOG) << "can not handle type:" << m_optDesc->type;
0316         break;
0317     }
0318 }
0319 
0320 Option::OptionState ListOption::state() const
0321 {
0322     if (m_entriesCount <= 1) {
0323         return Option::StateHidden;
0324     } else {
0325         return BaseOption::state();
0326     }
0327 }
0328 
0329 } // namespace KSaneCore
0330 
0331 #include "moc_listoption.cpp"