Warning, file /utilities/skanpage/src/Skanpage.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /**
0002  * SPDX-FileCopyrightText: 2015 by Kåre Särs <kare.sars@iki .fi>
0003  * SPDX-FileCopyrightText: 2021 by Alexander Stippich <a.stippich@gmx.net>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006  */
0007 
0008 #include "Skanpage.h"
0009 
0010 #include <QThread>
0011 
0012 #include <KConfigGroup>
0013 #include <KSharedConfig>
0014 
0015 #include "DevicesModel.h"
0016 #include "DocumentModel.h"
0017 #include "OptionsModel.h"
0018 #include "FormatModel.h"
0019 #include "FilteredOptionsModel.h"
0020 #include "DocumentSaver.h"
0021 #include "DocumentPrinter.h"
0022 #include "OCREngine.h"
0023 #include "skanpage_debug.h"
0024 
0025 class SkanpagePrivate {
0026 public:
0027     KSaneCore::Interface m_ksaneInterface;
0028     DocumentModel m_documentHandler;
0029     DevicesModel m_availableDevices;
0030     OptionsModel m_optionsModel;
0031     FormatModel m_formatModel;
0032     FilteredOptionsModel m_filteredOptionsModel;
0033     DocumentSaver m_documentSaver;
0034     DocumentPrinter m_documentPrinter;
0035     OCREngine m_OCREngine;
0036     QThread m_fileIOThread;
0037     SkanpageConfiguration *m_configuration;
0038     SkanpageState *m_stateConfiguration;
0039 
0040     int m_progress = 100;
0041     int m_remainingSeconds = 0;
0042     int m_scannedImages = 0;
0043     Skanpage::ApplicationState m_state = Skanpage::SearchingForDevices;
0044     bool m_scanInProgress = false;
0045     QString m_deviceName;
0046     QString m_deviceVendor;
0047     QString m_deviceModel;
0048 };
0049 
0050 using namespace KSaneCore;
0051 
0052 Skanpage::Skanpage(const QString &deviceName, QObject *parent)
0053     : QObject(parent)
0054     , d(std::make_unique<SkanpagePrivate>())
0055 {
0056     d->m_stateConfiguration = SkanpageState::self();
0057     d->m_configuration = SkanpageConfiguration::self();
0058     if (d->m_configuration->defaultFolder().isEmpty()) {
0059         d->m_configuration->setDefaultFolder(QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)));
0060     }
0061 
0062     d->m_filteredOptionsModel.setSourceModel(&d->m_optionsModel);
0063 
0064     connect(&d->m_ksaneInterface, &Interface::scannedImageReady, this, &Skanpage::imageReady);
0065     connect(&d->m_ksaneInterface, &Interface::availableDevices, this, &Skanpage::availableDevices);
0066     connect(&d->m_ksaneInterface, &Interface::userMessage, this, &Skanpage::showKSaneMessage);
0067     connect(&d->m_ksaneInterface, &Interface::scanProgress, this, &Skanpage::progressUpdated);
0068     connect(&d->m_ksaneInterface, &Interface::scanFinished, this, &Skanpage::scanningFinished);
0069     connect(&d->m_ksaneInterface, &Interface::batchModeCountDown, this, &Skanpage::batchModeCountDown);
0070     connect(&d->m_documentHandler, &DocumentModel::newPageAdded, this, &Skanpage::imageTemporarilySaved);
0071     
0072     d->m_fileIOThread.start();
0073     d->m_documentSaver.moveToThread(&d->m_fileIOThread);
0074     d->m_OCREngine.moveToThread(&d->m_fileIOThread);
0075     d->m_documentSaver.setOCREngine(&d->m_OCREngine);
0076 
0077     connect(&d->m_documentHandler, &DocumentModel::saveDocument, &d->m_documentSaver, &DocumentSaver::saveDocument);
0078     connect(&d->m_documentHandler, &DocumentModel::saveNewPageTemporary, &d->m_documentSaver, &DocumentSaver::saveNewPageTemporary);
0079     connect(&d->m_documentSaver, &DocumentSaver::pageTemporarilySaved, &d->m_documentHandler, &DocumentModel::updatePageInModel);
0080     connect(&d->m_documentSaver, &DocumentSaver::showUserMessage, this, &Skanpage::showUserMessage);
0081     connect(&d->m_documentSaver, &DocumentSaver::fileSaved, &d->m_documentHandler, &DocumentModel::updateFileInformation);
0082     connect(&d->m_documentSaver, &DocumentSaver::sharingFileSaved, &d->m_documentHandler, &DocumentModel::updateSharingFileInformation);
0083     connect(&d->m_documentPrinter, &DocumentPrinter::showUserMessage, this, &Skanpage::showUserMessage);
0084 
0085     // try to open device from command line option first, then remembered device
0086     if (deviceName.isEmpty() || !openDevice(deviceName)) {
0087 
0088         KConfigGroup options(KSharedConfig::openStateConfig(), QStringLiteral("general"));
0089         const QString savedDeviceName = options.readEntry(QStringLiteral("deviceName"));
0090         const QString savedDeviceVendor = options.readEntry(QStringLiteral("deviceVendor"));
0091         const QString savedDeviceModel = options.readEntry(QStringLiteral("deviceModel"));
0092 
0093         if (!openDevice(savedDeviceName, savedDeviceVendor, savedDeviceModel)) {
0094             reloadDevicesList();
0095         }
0096     }
0097 }
0098 
0099 Skanpage::~Skanpage()
0100 {
0101     d->m_fileIOThread.quit();
0102     d->m_configuration->save();
0103     d->m_stateConfiguration->save();
0104     saveScannerOptions();
0105     d->m_fileIOThread.wait();
0106 }
0107 
0108 QString Skanpage::deviceVendor() const
0109 {
0110     return d->m_deviceVendor;
0111 }
0112 
0113 QString Skanpage::deviceModel() const
0114 {
0115     return d->m_deviceModel;
0116 }
0117 
0118 QString Skanpage::deviceName() const
0119 {
0120     return d->m_deviceName;
0121 }
0122 
0123 void Skanpage::startScan()
0124 {
0125     d->m_ksaneInterface.startScan();
0126     d->m_scanInProgress = true;
0127     d->m_state = ApplicationState::ScanInProgress;
0128     Q_EMIT applicationStateChanged(d->m_state);
0129 }
0130 
0131 Skanpage::ApplicationState Skanpage::applicationState() const
0132 {
0133     return d->m_state;
0134 }
0135 
0136 void Skanpage::imageReady(const QImage &image)
0137 {
0138     d->m_documentHandler.addImage(image);
0139     d->m_scannedImages++;
0140 }
0141 
0142 void Skanpage::saveScannerOptions()
0143 {
0144     KConfigGroup options(KSharedConfig::openStateConfig(), QString::fromLatin1("Options For %1").arg(d->m_ksaneInterface.deviceName()));
0145 
0146     QMap<QString, QString> optionMap = d->m_ksaneInterface.getOptionsMap();
0147 
0148     qCDebug(SKANPAGE_LOG) << QStringLiteral("Saving scanner options") << optionMap;
0149     QMap<QString, QString>::const_iterator it = optionMap.constBegin();
0150     while (it != optionMap.constEnd()) {
0151         options.writeEntry(it.key(), it.value());
0152         ++it;
0153     }
0154     options.sync();
0155 }
0156 
0157 void Skanpage::loadScannerOptions()
0158 {
0159     KConfigGroup scannerOptions(KSharedConfig::openStateConfig(), QString::fromLatin1("Options For %1").arg(d->m_ksaneInterface.deviceName()));
0160 
0161     qCDebug(SKANPAGE_LOG) << QStringLiteral("Loading scanner options") << scannerOptions.entryMap();
0162 
0163     d->m_ksaneInterface.setOptionsMap(scannerOptions.entryMap());
0164 }
0165 
0166 void Skanpage::availableDevices(const QList<DeviceInformation *> &deviceList)
0167 {
0168     if (d->m_state == SearchingForDevices) {
0169         d->m_availableDevices.updateDevicesList(deviceList);
0170 
0171         d->m_state = DeviceSelection;
0172         Q_EMIT applicationStateChanged(d->m_state);
0173 
0174         // if there is only one scanning device available, open it
0175         if (d->m_availableDevices.rowCount() == 1) {
0176             d->m_availableDevices.selectDevice(0);
0177             qCDebug(SKANPAGE_LOG) << QStringLiteral("Automatically selecting only available device: ") << d->m_availableDevices.getSelectedDeviceName();
0178             openDevice(d->m_availableDevices.getSelectedDeviceName());
0179         }
0180     }
0181 }
0182 
0183 bool Skanpage::openDevice(const QString &deviceName, const QString &deviceVendor, const QString &deviceModel)
0184 {
0185     Interface::OpenStatus status = Interface::OpeningFailed;
0186     if (!deviceName.isEmpty()) {
0187         qCDebug(SKANPAGE_LOG) << QStringLiteral("Trying to open device: %1").arg(deviceName);
0188         status = d->m_ksaneInterface.openDevice(deviceName);
0189         if (status == Interface::OpeningSucceeded) {
0190             if (!deviceVendor.isEmpty()) {
0191                 finishOpeningDevice(deviceName, deviceVendor, deviceModel);
0192             } else {
0193                 finishOpeningDevice(deviceName, d->m_ksaneInterface.deviceVendor(), d->m_ksaneInterface.deviceModel());
0194             }
0195         } else if (status == Interface::OpeningDenied) {
0196             showUserMessage(SkanpageUtils::ErrorMessage, QStringLiteral("Access to selected device has been denied"));
0197         } else {
0198             showUserMessage(SkanpageUtils::ErrorMessage, QStringLiteral("Failed to open selected device."));
0199         }
0200 
0201     }
0202     return status == Interface::OpeningSucceeded;
0203 }
0204 
0205 void Skanpage::finishOpeningDevice(const QString &deviceName, const QString &deviceVendor, const QString &deviceModel)
0206 {
0207     qCDebug(SKANPAGE_LOG()) << QStringLiteral("Finishing opening of device %1 and loading options").arg(deviceName);
0208 
0209     KConfigGroup options(KSharedConfig::openStateConfig(), QStringLiteral("general"));
0210     options.writeEntry(QStringLiteral("deviceName"), deviceName);
0211     options.writeEntry(QStringLiteral("deviceModel"), deviceVendor);
0212     options.writeEntry(QStringLiteral("deviceVendor"), deviceModel);
0213 
0214     d->m_deviceName = deviceName;
0215     d->m_deviceVendor = deviceVendor;
0216     d->m_deviceModel = deviceModel;
0217     Q_EMIT deviceInfoUpdated();
0218     
0219     d->m_optionsModel.setOptionsList(d->m_ksaneInterface.getOptionsList());
0220     Q_EMIT optionsChanged();
0221 
0222     // load saved options
0223     loadScannerOptions();
0224 
0225     d->m_state = ReadyForScan;
0226     Q_EMIT applicationStateChanged(d->m_state);
0227 }
0228 
0229 void Skanpage::reloadDevicesList()
0230 {
0231     qCDebug(SKANPAGE_LOG()) << QStringLiteral("(Re-)loading devices list");
0232 
0233     if (d->m_ksaneInterface.closeDevice()) {
0234         d->m_deviceName.clear();
0235         d->m_deviceVendor.clear();
0236         d->m_deviceModel.clear();
0237         Q_EMIT deviceInfoUpdated();
0238         d->m_optionsModel.clearOptions();
0239         Q_EMIT optionsChanged();
0240     }
0241     d->m_state = SearchingForDevices;
0242     Q_EMIT applicationStateChanged(d->m_state);
0243     d->m_ksaneInterface.reloadDevicesList(d->m_configuration->showAllDevices() ? Interface::DeviceType::AllDevices : Interface::DeviceType::NoCameraAndVirtualDevices);
0244 }
0245 
0246 void Skanpage::showKSaneMessage(Interface::ScanStatus status, const QString &strStatus)
0247 {
0248     switch (status) {
0249         case Interface::ErrorGeneral:
0250             showUserMessage(SkanpageUtils::ErrorMessage, strStatus);
0251             break;
0252         case Interface::Information:
0253             showUserMessage(SkanpageUtils::InformationMessage, strStatus);
0254             break;
0255         default:
0256             break;
0257     }
0258 }
0259 
0260 void Skanpage::showUserMessage(SkanpageUtils::MessageLevel level, const QString &text)
0261 {
0262     Q_EMIT newUserMessage(QVariant(level), QVariant(text));
0263 }
0264 
0265 void Skanpage::progressUpdated(int progress)
0266 {
0267     d->m_progress = progress;
0268     Q_EMIT progressChanged(d->m_progress);
0269 }
0270 
0271 void Skanpage::batchModeCountDown(int remainingSeconds)
0272 {
0273     d->m_remainingSeconds = remainingSeconds;
0274     Q_EMIT countDownChanged(d->m_remainingSeconds);
0275 }
0276 
0277 int Skanpage::progress() const
0278 {
0279     return d->m_progress;
0280 }
0281 
0282 int Skanpage::countDown() const
0283 {
0284     return d->m_remainingSeconds;
0285 }
0286 
0287 Interface *Skanpage::ksaneInterface() const
0288 {
0289     return &d->m_ksaneInterface;
0290 }
0291 
0292 DocumentModel *Skanpage::documentModel() const
0293 {
0294     return &d->m_documentHandler;
0295 }
0296 
0297 DevicesModel *Skanpage::devicesModel() const
0298 {
0299     return &d->m_availableDevices;
0300 }
0301 
0302 FormatModel *Skanpage::formatModel() const
0303 {
0304     return &d->m_formatModel;
0305 }
0306 
0307 FilteredOptionsModel *Skanpage::optionsModel() const
0308 {
0309     return &d->m_filteredOptionsModel;
0310 }
0311 
0312 OCRLanguageModel *Skanpage::languageModel() const
0313 {
0314     return d->m_OCREngine.languages();
0315 }
0316 
0317 SkanpageConfiguration *Skanpage::configuration() const
0318 {
0319     return d->m_configuration;
0320 }
0321 
0322 SkanpageState *Skanpage::stateConfiguration() const
0323 {
0324     return d->m_stateConfiguration;
0325 }
0326 
0327 bool Skanpage::OCRavailable() const
0328 {
0329     return d->m_OCREngine.available();
0330 }
0331 
0332 void Skanpage::cancelScan()
0333 {
0334     d->m_ksaneInterface.stopScan();
0335 }
0336 
0337 void Skanpage::imageTemporarilySaved()
0338 {
0339     d->m_scannedImages--;
0340     checkFinish();
0341 }
0342 
0343 void Skanpage::scanningFinished(Interface::ScanStatus status, const QString &strStatus)
0344 {
0345     //only print debug, errors are already reported by Interface::userMessage
0346     qCDebug(SKANPAGE_LOG) << QStringLiteral("Finished scanning! Status code:") << status << QStringLiteral("Status message:") << strStatus;
0347     
0348     d->m_scanInProgress = false;
0349     checkFinish();
0350 }
0351 void Skanpage::checkFinish()
0352 {
0353     if (d->m_scannedImages == 0 && !d->m_scanInProgress) {
0354         d->m_state = ApplicationState::ReadyForScan;
0355         Q_EMIT applicationStateChanged(d->m_state);
0356     }
0357 }