Commit 73a0768d authored by Alexander Stippich's avatar Alexander Stippich
Browse files

export a list of options

parent 79609c4d
......@@ -11,6 +11,7 @@ set(ktwain_src
twainiface.cpp
ktwain_widget.cpp
../src/ksanewidget.h
../src/ksaneoption.h
)
add_library(KF5Sane ${ktwain_src})
......
......@@ -12,6 +12,7 @@
* ============================================================ */
#include "ksanewidget.h"
#include "ksaneoption.h"
// Qt includes
#include <QMap>
......@@ -188,5 +189,16 @@ void KSaneWidget::setSelection(QPointF lefttop, QPointF rightbottom)
void KSaneWidget::setOptionsCollapsed(bool) {}
void KSaneWidget::setScanButtonHidden(bool) {}
void KSaneWidget::initGetDeviceList() const {}
QList<KSaneOption *> KSaneWidget::getOptionsList()
{
return QList<KSaneOption *>();
}
KSaneOption *KSaneWidget::getOption(KSaneOptionName optionEnum)
{
return nullptr;
}
KSaneOption *KSaneWidget::getOption(QString optionName)
{
return nullptr;
}
} // NameSpace KSaneIface
......@@ -32,7 +32,9 @@ set(ksane_SRCS
ksanewidget_p.cpp
splittercollapser.cpp
ksaneauth.cpp
options/ksaneoption.cpp
ksaneoption.cpp
ksaneinternaloption.cpp
options/ksanebaseoption.cpp
options/ksaneactionoption.cpp
options/ksanebooloption.cpp
options/ksanestringoption.cpp
......@@ -78,6 +80,7 @@ set_target_properties(KF5Sane
ecm_generate_headers(KSane_HEADERS
HEADER_NAMES
KSaneWidget
KSaneOption
REQUIRED_HEADERS KSane_HEADERS
RELATIVE "../src/"
)
......
/* ============================================================
*
* SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
#include "ksaneinternaloption.h"
#include "ksaneoption_p.h"
#include "ksanebaseoption.h"
namespace KSaneIface
{
KSaneInternalOption::KSaneInternalOption(KSaneBaseOption *option, QObject *parent) : KSaneOption(parent)
{
d->option = option;
connect(d->option, &KSaneBaseOption::optionReloaded, this, &KSaneOption::optionReloaded);
connect(d->option, &KSaneBaseOption::valueChanged, this, &KSaneOption::valueChanged);
connect(d->option, &KSaneBaseOption::destroyed, [=]() { d->option = nullptr; } );
}
} // NameSpace KSaneIface
/* ============================================================
*
* SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
#ifndef KSANE_INTERNAL_OPTION_H
#define KSANE_INTERNAL_OPTION_H
#include "ksaneoption.h"
#include "ksanebaseoption.h"
namespace KSaneIface
{
class KSaneInternalOption : public KSaneOption
{
Q_OBJECT
public:
KSaneInternalOption(KSaneBaseOption *option, QObject *parent = nullptr);
};
} // NameSpace KSaneIface
#endif // KSANE_INTERNAL_OPTION_H
/* ============================================================
*
* SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
#include "ksaneoption.h"
#include "ksaneoption_p.h"
#include "ksanebaseoption.h"
#include <ksane_debug.h>
namespace KSaneIface
{
KSaneOption::KSaneOption(QObject *parent) : QObject(parent), d(std::unique_ptr<KSaneOptionPrivate>(new KSaneOptionPrivate()))
{
}
KSaneOption::~KSaneOption()
= default;
KSaneOption::KSaneOptionState KSaneOption::state() const
{
if (d->option != nullptr) {
return d->option->state();
} else {
return StateDisabled;
}
}
QString KSaneOption::name() const
{
if (d->option != nullptr) {
return d->option->name();
} else {
return QString();
}
}
QString KSaneOption::title() const
{
if (d->option != nullptr) {
return d->option->title();
} else {
return QString();
}
}
QString KSaneOption::description() const
{
if (d->option != nullptr) {
return d->option->description();
} else {
return QString();
}
}
KSaneOption::KSaneOptionType KSaneOption::type() const
{
if (d->option != nullptr) {
return d->option->type();
} else {
return TypeDetectFail;
}
}
QVariant KSaneOption::minimumValue() const
{
if (d->option != nullptr) {
return d->option->minimumValue();
} else {
return QVariant();
}
}
QVariant KSaneOption::maximumValue() const
{
if (d->option != nullptr) {
return d->option->maximumValue();
} else {
return QVariant();
}
}
QVariant KSaneOption::stepValue() const
{
if (d->option != nullptr) {
return d->option->stepValue();
} else {
return QVariant();
}
}
QVariantList KSaneOption::valueList() const
{
if (d->option != nullptr) {
return d->option->valueList();
} else {
return QVariantList();
}
}
QVariant KSaneOption::value() const
{
if (d->option != nullptr) {
return d->option->value();
} else {
return QVariant();
}
}
KSaneOption::KSaneOptionUnit KSaneOption::valueUnit() const
{
if (d->option != nullptr) {
return d->option->valueUnit();
} else {
return UnitNone;
}
}
int KSaneOption::valueSize() const
{
if (d->option != nullptr) {
return d->option->valueSize();
} else {
return 0;
}
}
bool KSaneOption::setValue(const QVariant &value)
{
if (d->option != nullptr) {
return d->option->setValue(value);
} else {
return false;
}
}
bool KSaneOption::storeCurrentData()
{
if (d->option != nullptr) {
return d->option->storeCurrentData();
} else {
return false;
}
}
bool KSaneOption::restoreSavedData()
{
if (d->option != nullptr) {
return d->option->restoreSavedData();
} else {
return false;
}
}
} // NameSpace KSaneIface
/* ============================================================
*
* SPDX-FileCopyrightText: 2009 Kare Sars <kare dot sars at iki dot fi>
* SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
* SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
......@@ -10,30 +9,25 @@
#ifndef KSANE_OPTION_H
#define KSANE_OPTION_H
// Qt includes
//KDE includes
#include <memory>
#include <klocalizedstring.h>
// Sane includes
extern "C"
{
#include <sane/sane.h>
#include <sane/saneopts.h>
}
// Qt includes
#define SANE_TRANSLATION_DOMAIN "sane-backends"
#include <QObject>
#include <QString>
#include <QVariant>
#include "ksane_export.h"
namespace KSaneIface
{
inline QString sane_i18n(const char *text) {
return i18nd(SANE_TRANSLATION_DOMAIN, text);
}
class KSaneOptionPrivate;
class KSaneOption : public QObject
/**
* A wrapper class providing access to the internal KSaneBaseOption
* to access all options provided by lib(k)sane
*/
class KSANE_EXPORT KSaneOption : public QObject
{
Q_OBJECT
......@@ -74,29 +68,24 @@ public:
StateDisabled,
StateActive
} KSaneOptionState;
KSaneOption();
KSaneOption(const SANE_Handle handle, const int index);
Q_ENUM(KSaneOptionState);
KSaneOption(QObject *parent = nullptr);
~KSaneOption();
static KSaneOptionType optionType(const SANE_Option_Descriptor *optDesc);
bool needsPolling() const;
virtual void readOption();
virtual void readValue();
virtual QString valueAsString() const;
/** This function returns the internal name of the option
* @return the internal name */
virtual QString name() const;
QString name() const;
/** This function returns the translated title of the option
* @return the title */
virtual QString title() const;
QString title() const;
/** This function returns a more verbose, translated description
* of the option.
* @return the description */
virtual QString description() const;
QString description() const;
/** This function the type of the option as determined by libksane.
* Each type provides a different implementation for different
......@@ -107,39 +96,39 @@ public:
/** This function returns the state of the option indicating
* if the function is disabled or should be hidden.
* @return the state of option the of value KSaneOptionState */
virtual KSaneOptionState state() const;
KSaneOptionState state() const;
/** This function returns the currently active value for the option.
* @return the current value */
virtual QVariant value() const;
QVariant value() const;
/** This function returns the minimum value for the option.
* Returns an empty QVariant if this value is not applicable
* for the option type.
* @return the minimum value */
virtual QVariant minimumValue() const;
QVariant minimumValue() const;
/** This function returns the maximum value for the option.
* Returns an empty QVariant if this value is not applicable
* for the option type.
* @return the maximum value */
virtual QVariant maximumValue() const;
QVariant maximumValue() const;
/** This function returns the step value for the option.
* Returns an empty QVariant if this value is not applicable
* for the option type.
* @return the step value */
virtual QVariant stepValue() const;
QVariant stepValue() const;
/** This function returns the list of possible values if the option
* is of type KSaneOptionType::values.
* @return a list with all possible values */
virtual QVariantList valueList() const;
QVariantList valueList() const;
/** This function returns an enum specifying whether the values
* of the option have a unit, e.g. mm, px, etc.
* @return unit of value KSaneOptionUnit */
virtual KSaneOptionUnit valueUnit() const;
KSaneOptionUnit valueUnit() const;
/** This function returns the size of the values of the option
* of type KSaneOptionType::TypeValueList.
......@@ -148,7 +137,7 @@ public:
* of elements. If the option is a KSaneOptionType::TypeString,
* the size represents the number of characters in the string.
* @return the number of elements */
virtual int valueSize() const;
int valueSize() const;
/** This function temporarily stores the current value
* in a member variable. */
......@@ -166,29 +155,19 @@ Q_SIGNALS:
/** This signal is emitted when the current value is updated,
* either when a user sets a new value or by a reload by the backend. */
void valueChanged(const QVariant &value);
void optionsNeedReload();
void valuesNeedReload();
public Q_SLOTS:
virtual bool setValue(const QVariant &val);
/** This slot allows to change the current value of the option.
* @param value the new value of option inside a QVariant.
* In case the variant cannot be cast to a value suitable for
* the specific option, the value is discarded. */
bool setValue(const QVariant &value);
protected:
static SANE_Word toSANE_Word(unsigned char *data);
static void fromSANE_Word(unsigned char *data, SANE_Word from);
bool writeData(void *data);
SANE_Handle m_handle = nullptr;
int m_index = -1;
const SANE_Option_Descriptor *m_optDesc = nullptr; ///< This pointer is provided by sane
unsigned char *m_data= nullptr;
KSaneOptionType m_optionType = TypeDetectFail;
std::unique_ptr<KSaneIface::KSaneOptionPrivate> d;
};
} // NameSpace KSaneIface
#endif // KSANE_OPTION_H
......
/* ============================================================
*
* SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
#ifndef KSANE_OPTION_P_H
#define KSANE_OPTION_P_H
#include "ksanebaseoption.h"
namespace KSaneIface
{
class KSaneOptionPrivate
{
public:
KSaneBaseOption *option;
};
} // NameSpace KSaneIface
#endif // KSANE_OPTION_P_H
......@@ -5,7 +5,8 @@
* SPDX-FileCopyrightText: 2009 Grzegorz Kurtyka <grzegorz dot kurtyka at gmail dot com>
* SPDX-FileCopyrightText: 2007-2008 Gilles Caulier <caulier dot gilles at gmail dot com>
* SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks
*
* SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net>
*
* SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*
* ============================================================ */
......@@ -24,6 +25,7 @@ extern "C"
#include <QApplication>
#include <QVarLengthArray>
#include <QList>
#include <QLabel>
#include <QSplitter>
#include <QMutex>
......@@ -36,7 +38,8 @@ extern "C"
#include <kwallet.h>
#endif
#include "ksaneoption.h"
#include "ksaneinternaloption.h"
#include "ksanebaseoption.h"
#include "ksaneactionoption.h"
#include "ksanebooloption.h"
#include "ksanelistoption.h"
......@@ -54,6 +57,33 @@ extern "C"
namespace KSaneIface
{
static int s_objectCount = 0;
static const QHash<QString, KSaneWidget::KSaneOptionName> stringEnumTranslation = {
{ QStringLiteral(SANE_NAME_SCAN_SOURCE), KSaneWidget::SourceOption },
{ QStringLiteral(SANE_NAME_SCAN_MODE), KSaneWidget::ScanModeOption },
{ QStringLiteral(SANE_NAME_BIT_DEPTH), KSaneWidget::BitDepthOption },
{ QStringLiteral(SANE_NAME_SCAN_RESOLUTION), KSaneWidget::ResolutionOption },
{ QStringLiteral(SANE_NAME_SCAN_TL_X), KSaneWidget::TopLeftXOption },
{ QStringLiteral(SANE_NAME_SCAN_TL_Y), KSaneWidget::TopLeftYOption },
{ QStringLiteral(SANE_NAME_SCAN_BR_X), KSaneWidget::BottomRightXOption },
{ QStringLiteral(SANE_NAME_SCAN_BR_Y), KSaneWidget::BottomRightYOption },
{ QStringLiteral("film-type"), KSaneWidget::FilmTypeOption },
{ QStringLiteral(SANE_NAME_NEGATIVE), KSaneWidget::NegativeOption },
{ InvertColorsOptionName, KSaneWidget::InvertColorOption },
{ PageSizeOptionName, KSaneWidget::PageSizeOption },
{ QStringLiteral(SANE_NAME_THRESHOLD), KSaneWidget::ThresholdOption },
{ QStringLiteral(SANE_NAME_SCAN_X_RESOLUTION), KSaneWidget::XResolutionOption },
{ QStringLiteral(SANE_NAME_SCAN_Y_RESOLUTION), KSaneWidget::YResolutionOption },
{ QStringLiteral(SANE_NAME_PREVIEW), KSaneWidget::PreviewOption },
{ QStringLiteral("wait-for-button"), KSaneWidget::WaitForButtonOption },
{ QStringLiteral(SANE_NAME_BRIGHTNESS), KSaneWidget::BrightnessOption },
{ QStringLiteral(SANE_NAME_CONTRAST), KSaneWidget::ContrastOption },
{ QStringLiteral(SANE_NAME_GAMMA_VECTOR_R), KSaneWidget::GammaRedOption },
{ QStringLiteral(SANE_NAME_GAMMA_VECTOR_G), KSaneWidget::GammaGreenOption },
{ QStringLiteral(SANE_NAME_GAMMA_VECTOR_B), KSaneWidget::GammaBlueOption },
{ QStringLiteral(SANE_NAME_BLACK_LEVEL), KSaneWidget::BlackLevelOption },
{ QStringLiteral(SANE_NAME_WHITE_LEVEL), KSaneWidget::WhiteLevelOption }, };
Q_GLOBAL_STATIC(QMutex, s_objectMutex)
KSaneWidget::KSaneWidget(QWidget *parent)
......@@ -436,16 +466,16 @@ bool KSaneWidget::openDevice(const QString &deviceName)
numSaneOptions = *reinterpret_cast<SANE_Word *>(data.data());
// read the rest of the options
KSaneOption *option;
KSaneOption *m_optionTopLeftX;
KSaneOption *m_optionTopLeftY;
KSaneOption *m_optionBottomRightX;
KSaneOption *m_optionBottomRightY;
KSaneOption *m_optionResolution;
KSaneBaseOption *option;
KSaneBaseOption *m_optionTopLeftX;
KSaneBaseOption *m_optionTopLeftY;
KSaneBaseOption *m_optionBottomRightX;
KSaneBaseOption *m_optionBottomRightY;
KSaneBaseOption *m_optionResolution;
for (i = 1; i < numSaneOptions; ++i) {
switch (KSaneOption::optionType(sane_get_option_descriptor(d->m_saneHandle, i))) {
switch (KSaneBaseOption::optionType(sane_get_option_descriptor(d->m_saneHandle, i))) {
case KSaneOption::TypeDetectFail:
option = new KSaneOption(d->m_saneHandle, i);
option = new KSaneBaseOption(d->m_saneHandle, i);
break;
case KSaneOption::TypeBool:
option = new KSaneBoolOption(d->m_saneHandle, i);
......@@ -470,8 +500,6 @@ bool KSaneWidget::openDevice(const QString &deviceName)
break;
}
d->m_optList.append(option);
if (option->name() == QStringLiteral(SANE_NAME_SCAN_TL_X)) {
m_optionTopLeftX = option;
}
......@@ -487,27 +515,39 @@ bool KSaneWidget::openDevice(const QString &deviceName)
if (option->name() == QStringLiteral(SANE_NAME_SCAN_RESOLUTION)) {
m_optionResolution = option;
}
connect(option, &KSaneOption::optionsNeedReload, d, &KSaneWidgetPrivate::reloadOptions);
connect(option, &KSaneOption::valuesNeedReload, d, &KSaneWidgetPrivate::scheduleValuesReload);
d->m_optionsList.append(option);
d->m_externalOptionsList.append(new KSaneInternalOption(option));
connect(option, &KSaneBaseOption::optionsNeedReload, d, &KSaneWidgetPrivate::reloadOptions);
connect(option, &KSaneBaseOption::valuesNeedReload, d, &KSaneWidgetPrivate::scheduleValuesReload);
if (option->needsPolling()) {
d->m_pollList.append(option);
d->m_optionsPollList.append(option);
if (option->type() == KSaneOption::TypeBool) {
connect( option, &KSaneOption::valueChanged,
connect( option, &KSaneBaseOption::valueChanged,
[=]( const QVariant &newValue ) { Q_EMIT buttonPressed(option->name(), option->title(), newValue.toBool()); } );
}
}
const auto it = stringEnumTranslation.find(option->name());
if (it != stringEnumTranslation.constEnd()) {
d->m_optionsLocation.insert(it.value(), i - 1);
}
}
// add extra option for inverting image colors
d->m_optList.append(new KSaneInvertOption());
option = new KSaneInvertOption();
d->m_optionsList.append(option);
d->m_externalOptionsList.append(new KSaneInternalOption(option));
d->m_optionsLocation.insert(InvertColorOption, d->m_optionsList.size() - 1);
// add extra option for selecting specific page sizes
d->m_optList.append(new KSanePageSizeOption(m_optionTopLeftX, m_optionTopLeftY,
m_optionBottomRightX, m_optionBottomRightY, m_optionResolution));
option = new KSanePageSizeOption(m_optionTopLeftX, m_optionTopLeftY,
m_optionBottomRightX, m_optionBottomRightY, m_optionResolution);
d->m_optionsList.append(option);
d->m_externalOptionsList.append(new KSaneInternalOption(option));
d->m_optionsLocation.insert(PageSizeOption, d->m_optionsList.size() - 1);
// start polling the poll options
if (d->m_pollList.size() > 0) {
if (d->m_optionsPollList.size() > 0) {
d->m_optionPollTmr.start();
}
......@@ -716,14 +756,38 @@ void KSaneWidget::setPreviewResolution(float dpi)
d->m_previewDPI = dpi;