File indexing completed on 2024-04-28 04:32:23
0001 /* 0002 * SPDX-FileCopyrightText: 2007-2008 Kare Sars <kare dot sars at iki dot fi> 0003 * SPDX-FileCopyrightText: 2007-2008 Gilles Caulier <caulier dot gilles at gmail dot com> 0004 * SPDX-FileCopyrightText: 2014 Gregor Mitsch : port to KDE5 frameworks 0005 * SPDX-FileCopyrightText: 2021 Alexander Stippich <a.stippich@gmx.net> 0006 * 0007 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0008 */ 0009 0010 #include "ksanewidget_p.h" 0011 0012 #include <QImage> 0013 #include <QScrollArea> 0014 #include <QScrollBar> 0015 #include <QList> 0016 #include <QLabel> 0017 #include <QMessageBox> 0018 #include <QMetaMethod> 0019 #include <QPageSize> 0020 0021 #include <KLocalizedString> 0022 0023 #include <ksane_debug.h> 0024 0025 #define SCALED_PREVIEW_MAX_SIDE 400 0026 0027 static constexpr int ActiveSelection = 100000; 0028 static constexpr int PageSizeWiggleRoom = 2; // in mm 0029 0030 namespace KSaneIface 0031 { 0032 0033 KSaneWidgetPrivate::KSaneWidgetPrivate(KSaneWidget *parent): 0034 q(parent) 0035 { 0036 // Device independent UI variables 0037 m_optsTabWidget = nullptr; 0038 m_basicOptsTab = nullptr; 0039 m_otherOptsTab = nullptr; 0040 m_zInBtn = nullptr; 0041 m_zOutBtn = nullptr; 0042 m_zSelBtn = nullptr; 0043 m_zFitBtn = nullptr; 0044 m_clearSelBtn = nullptr; 0045 m_prevBtn = nullptr; 0046 m_scanBtn = nullptr; 0047 m_cancelBtn = nullptr; 0048 m_previewViewer = nullptr; 0049 m_autoSelect = true; 0050 m_selIndex = ActiveSelection; 0051 m_warmingUp = nullptr; 0052 m_progressBar = nullptr; 0053 0054 // scanning variables 0055 m_isPreview = false; 0056 0057 m_splitGamChB = nullptr; 0058 m_commonGamma = nullptr; 0059 m_previewDPI = 0; 0060 0061 m_previewWidth = 0; 0062 m_previewHeight = 0; 0063 0064 m_sizeCodes = { 0065 QPageSize::A4, 0066 QPageSize::A5, 0067 QPageSize::A6, 0068 QPageSize::Letter, 0069 QPageSize::Legal, 0070 QPageSize::Tabloid, 0071 QPageSize::A3, 0072 QPageSize::B3, 0073 QPageSize::B4, 0074 QPageSize::B5, 0075 QPageSize::B6, 0076 QPageSize::C5E, 0077 QPageSize::Comm10E, 0078 QPageSize::DLE, 0079 QPageSize::Executive, 0080 QPageSize::Folio, 0081 QPageSize::Ledger, 0082 QPageSize::JisB3, 0083 QPageSize::JisB4, 0084 QPageSize::JisB5, 0085 QPageSize::JisB6, 0086 }; 0087 0088 clearDeviceOptions(); 0089 } 0090 0091 void KSaneWidgetPrivate::clearDeviceOptions() 0092 { 0093 m_optSource = nullptr; 0094 m_colorOpts = nullptr; 0095 m_optNegative = nullptr; 0096 m_optFilmType = nullptr; 0097 m_optMode = nullptr; 0098 m_optDepth = nullptr; 0099 m_optRes = nullptr; 0100 m_optResX = nullptr; 0101 m_optResY = nullptr; 0102 m_optTlX = nullptr; 0103 m_optTlY = nullptr; 0104 m_optBrX = nullptr; 0105 m_optBrY = nullptr; 0106 m_optGamR = nullptr; 0107 m_optGamG = nullptr; 0108 m_optGamB = nullptr; 0109 m_optPreview = nullptr; 0110 m_optWaitForBtn = nullptr; 0111 m_scanOngoing = false; 0112 0113 m_handledOptions.clear(); 0114 0115 // remove the remaining layouts/widgets 0116 delete m_basicOptsTab; 0117 m_basicOptsTab = nullptr; 0118 0119 delete m_otherOptsTab; 0120 m_otherOptsTab = nullptr; 0121 } 0122 0123 void KSaneWidgetPrivate::signalDevListUpdate(const QList<KSaneCore::DeviceInformation*> &deviceList) 0124 { 0125 QList<KSaneWidget::DeviceInfo> list; 0126 list.reserve(deviceList.count()); 0127 for (const auto &device : deviceList) { 0128 KSaneWidget::DeviceInfo newDevice; 0129 newDevice.model = device->model(); 0130 newDevice.vendor = device->vendor(); 0131 newDevice.name = device->name(); 0132 newDevice.type = device->type(); 0133 list << newDevice; 0134 } 0135 Q_EMIT q->availableDevices(list); 0136 } 0137 0138 float KSaneWidgetPrivate::ratioToScanAreaX(float ratio) 0139 { 0140 if (!m_optBrX) { 0141 return 0.0; 0142 } 0143 float max = m_optBrX->maximumValue().toFloat(); 0144 0145 return max * ratio; 0146 } 0147 0148 float KSaneWidgetPrivate::ratioToScanAreaY(float ratio) 0149 { 0150 if (!m_optBrY) { 0151 return 0.0; 0152 } 0153 float max = m_optBrY->maximumValue().toFloat(); 0154 0155 return max * ratio; 0156 } 0157 0158 float KSaneWidgetPrivate::scanAreaToRatioX(float scanArea) 0159 { 0160 if (!m_optBrX) { 0161 return 0.0; 0162 } 0163 float max = m_optBrX->maximumValue().toFloat(); 0164 0165 if (scanArea > max) { 0166 return 1.0; 0167 } 0168 0169 if (max < 0.0001) { 0170 return 0.0; 0171 } 0172 0173 return scanArea / max; 0174 } 0175 0176 float KSaneWidgetPrivate::scanAreaToRatioY(float scanArea) 0177 { 0178 if (!m_optBrY) { 0179 return 0.0; 0180 } 0181 float max = m_optBrY->maximumValue().toFloat(); 0182 0183 if (scanArea > max) { 0184 return 1.0; 0185 } 0186 0187 if (max < 0.0001) { 0188 return 0.0; 0189 } 0190 0191 return scanArea / max; 0192 } 0193 0194 static float mmToDispUnit(float mm) { 0195 static QLocale locale; 0196 0197 if (locale.measurementSystem() == QLocale::MetricSystem) { 0198 return mm; 0199 } 0200 // else 0201 return mm / 25.4; 0202 } 0203 0204 float KSaneWidgetPrivate::ratioToDispUnitX(float ratio) 0205 { 0206 if (!m_optBrX) { 0207 return 0.0; 0208 } 0209 0210 float result = ratioToScanAreaX(ratio); 0211 0212 if (m_optBrX->valueUnit() == KSaneCore::Option::UnitMilliMeter) { 0213 return mmToDispUnit(result); 0214 } 0215 else if (m_optBrX->valueUnit() == KSaneCore::Option::UnitPixel && m_optRes) { 0216 // get current DPI 0217 float dpi = m_optRes->value().toFloat(); 0218 if (dpi > 1) { 0219 result = result / (dpi / 25.4); 0220 return mmToDispUnit(result); 0221 } 0222 } 0223 qCDebug(KSANE_LOG) << "Failed to convert scan area to mm"; 0224 return ratio; 0225 } 0226 0227 float KSaneWidgetPrivate::ratioToDispUnitY(float ratio) 0228 { 0229 if (!m_optBrY) { 0230 return 0.0; 0231 } 0232 0233 float result = ratioToScanAreaY(ratio); 0234 0235 if (m_optBrY->valueUnit() == KSaneCore::Option::UnitMilliMeter) { 0236 return mmToDispUnit(result); 0237 } 0238 else if (m_optBrY->valueUnit() == KSaneCore::Option::UnitPixel && m_optRes) { 0239 // get current DPI 0240 float dpi = m_optRes->value().toFloat(); 0241 if (dpi > 1) { 0242 result = result / (dpi / 25.4); 0243 return mmToDispUnit(result); 0244 } 0245 } 0246 qCDebug(KSANE_LOG) << "Failed to convert scan area to display unit"; 0247 return ratio; 0248 } 0249 0250 float KSaneWidgetPrivate::dispUnitToRatioX(float value) 0251 { 0252 float valueMax = ratioToDispUnitX(1); 0253 if (valueMax < 1) { 0254 return 0.0; 0255 } 0256 return value / valueMax; 0257 } 0258 0259 float KSaneWidgetPrivate::dispUnitToRatioY(float value) 0260 { 0261 float valueMax = ratioToDispUnitY(1); 0262 if (valueMax < 1) { 0263 return 0.0; 0264 } 0265 return value / valueMax; 0266 } 0267 0268 KSaneOptionWidget *KSaneWidgetPrivate::createOptionWidget(QWidget *parent, KSaneCore::Option *option) 0269 { 0270 KSaneOptionWidget *widget = nullptr; 0271 switch (option->type()) { 0272 case KSaneCore::Option::TypeBool: 0273 widget = new LabeledCheckbox(parent, option); 0274 break; 0275 case KSaneCore::Option::TypeInteger: 0276 widget = new LabeledSlider(parent, option); 0277 break; 0278 case KSaneCore::Option::TypeDouble: 0279 widget = new LabeledFSlider(parent, option); 0280 break; 0281 case KSaneCore::Option::TypeValueList: 0282 widget = new LabeledCombo(parent, option); 0283 break; 0284 case KSaneCore::Option::TypeString: 0285 widget = new LabeledEntry(parent, option); 0286 break; 0287 case KSaneCore::Option::TypeGamma: 0288 widget = new LabeledGamma(parent, option); 0289 break; 0290 case KSaneCore::Option::TypeAction: 0291 widget = new KSaneButton(parent, option); 0292 break; 0293 default: 0294 widget = new KSaneOptionWidget(parent, option); 0295 break; 0296 } 0297 m_handledOptions.insert(option->name()); 0298 return widget; 0299 } 0300 0301 void KSaneWidgetPrivate::createOptInterface() 0302 { 0303 m_basicOptsTab = new QWidget; 0304 m_basicScrollA->setWidget(m_basicOptsTab); 0305 0306 QVBoxLayout *basicLayout = new QVBoxLayout(m_basicOptsTab); 0307 KSaneCore::Option *option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::SourceOption); 0308 // Scan Source 0309 if (option != nullptr) { 0310 m_optSource = option; 0311 KSaneOptionWidget *source = createOptionWidget(m_basicOptsTab, option); 0312 basicLayout->addWidget(source); 0313 connect(m_optSource, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::checkInvert, Qt::QueuedConnection); 0314 connect(m_optSource, &KSaneCore::Option::valueChanged, this, [this]() { 0315 m_previewViewer->setMultiselectionEnabled(!scanSourceADF()); 0316 }); 0317 } 0318 0319 // film-type (note: No translation) 0320 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::FilmTypeOption)) != nullptr) { 0321 m_optFilmType = option; 0322 KSaneOptionWidget *film = createOptionWidget(m_basicOptsTab, option); 0323 basicLayout->addWidget(film); 0324 connect(m_optFilmType, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::checkInvert, Qt::QueuedConnection); 0325 } else if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::NegativeOption)) != nullptr) { 0326 m_optNegative = option; 0327 KSaneOptionWidget *negative = createOptionWidget(m_basicOptsTab, option); 0328 basicLayout->addWidget(negative); 0329 } 0330 // Scan mode 0331 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::ScanModeOption)) != nullptr) { 0332 m_optMode = option; 0333 KSaneOptionWidget *mode = createOptionWidget(m_basicOptsTab, option); 0334 basicLayout->addWidget(mode); 0335 } 0336 // Bitdepth 0337 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BitDepthOption)) != nullptr) { 0338 m_optDepth = option; 0339 KSaneOptionWidget *bitDepth = createOptionWidget(m_basicOptsTab, option); 0340 basicLayout->addWidget(bitDepth); 0341 } 0342 // Threshold 0343 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::ThresholdOption)) != nullptr) { 0344 KSaneOptionWidget *threshold = createOptionWidget(m_basicOptsTab, option); 0345 basicLayout->addWidget(threshold); 0346 } 0347 // Resolution 0348 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::ResolutionOption)) != nullptr) { 0349 m_optRes = option; 0350 KSaneOptionWidget *resolution = createOptionWidget(m_basicOptsTab, option); 0351 basicLayout->addWidget(resolution); 0352 } 0353 // These two next resolution options are a bit tricky. 0354 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::XResolutionOption)) != nullptr) { 0355 m_optResX = option; 0356 if (!m_optRes) { 0357 m_optRes = m_optResX; 0358 } 0359 KSaneOptionWidget *optResX = createOptionWidget(m_basicOptsTab, option); 0360 basicLayout->addWidget(optResX); 0361 } 0362 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::YResolutionOption)) != nullptr) { 0363 m_optResY = option; 0364 KSaneOptionWidget *optResY = createOptionWidget(m_basicOptsTab, option); 0365 basicLayout->addWidget(optResY); 0366 } 0367 0368 // save a pointer to the preview option if possible 0369 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::PreviewOption)) != nullptr) { 0370 m_optPreview = option; 0371 m_handledOptions.insert(option->name()); 0372 } 0373 0374 // save a pointer to the "wait-for-button" option if possible (Note: No translation) 0375 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::WaitForButtonOption)) != nullptr) { 0376 m_optWaitForBtn = option; 0377 m_handledOptions.insert(option->name()); 0378 } 0379 0380 // scan area (Do not add the widgets) 0381 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::TopLeftXOption)) != nullptr) { 0382 m_optTlX = option; 0383 connect(option, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::setTLX); 0384 m_handledOptions.insert(option->name()); 0385 connect(option, &KSaneCore::Option::optionReloaded, this, &KSaneWidgetPrivate::updatePreviewViewer); 0386 } 0387 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::TopLeftYOption)) != nullptr) { 0388 m_optTlY = option; 0389 connect(option, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::setTLY); 0390 m_handledOptions.insert(option->name()); 0391 connect(option, &KSaneCore::Option::optionReloaded, this, &KSaneWidgetPrivate::updatePreviewViewer); 0392 } 0393 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BottomRightXOption)) != nullptr) { 0394 m_optBrX = option; 0395 connect(option, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::setBRX); 0396 m_handledOptions.insert(option->name()); 0397 connect(option, &KSaneCore::Option::optionReloaded, this, &KSaneWidgetPrivate::updatePreviewViewer); 0398 } 0399 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BottomRightYOption)) != nullptr) { 0400 m_optBrY = option; 0401 connect(option, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::setBRY); 0402 m_handledOptions.insert(option->name()); 0403 connect(option, &KSaneCore::Option::optionReloaded, this, &KSaneWidgetPrivate::updatePreviewViewer); 0404 } 0405 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::PageSizeOption)) != nullptr) { 0406 m_handledOptions.insert(option->name()); 0407 } 0408 0409 // Add our own size options 0410 m_scanareaPapersize = new LabeledCombo(m_basicOptsTab, i18n("Scan Area Size")); 0411 connect(m_scanareaPapersize, &LabeledCombo::activated, this, &KSaneWidgetPrivate::setPageSize); 0412 basicLayout->addWidget(m_scanareaPapersize); 0413 0414 static QLocale locale; 0415 QString unitSuffix = locale.measurementSystem() == QLocale::MetricSystem ? i18n(" mm") : i18n(" inch"); 0416 0417 m_scanareaWidth = new LabeledFSlider(m_basicOptsTab, i18n("Width"), 0.0f, 500.0f, 0.1f); 0418 m_scanareaWidth->setSuffix(unitSuffix); 0419 connect(m_scanareaWidth, &LabeledFSlider::valueChanged, this, &KSaneWidgetPrivate::updateScanSelection); 0420 basicLayout->addWidget(m_scanareaWidth); 0421 0422 m_scanareaHeight = new LabeledFSlider(m_basicOptsTab, i18n("Height"), 0.0f, 500.0f, 0.1f); 0423 m_scanareaHeight->setSuffix(unitSuffix); 0424 connect(m_scanareaHeight, &LabeledFSlider::valueChanged, this, &KSaneWidgetPrivate::updateScanSelection); 0425 basicLayout->addWidget(m_scanareaHeight); 0426 0427 m_scanareaX = new LabeledFSlider(m_basicOptsTab, i18n("X Offset"), 0.0f, 500.0f, 0.1f); 0428 m_scanareaX->setSuffix(unitSuffix); 0429 connect(m_scanareaX, &LabeledFSlider::valueChanged, this, &KSaneWidgetPrivate::updateScanSelection); 0430 basicLayout->addWidget(m_scanareaX); 0431 0432 m_scanareaY = new LabeledFSlider(m_basicOptsTab, i18n("Y Offset"), 0.0f, 500.0f, 0.1f); 0433 m_scanareaY->setSuffix(unitSuffix); 0434 connect(m_scanareaY, &LabeledFSlider::valueChanged, this, &KSaneWidgetPrivate::updateScanSelection); 0435 basicLayout->addWidget(m_scanareaY); 0436 0437 // add a stretch to the end to keep the parameters at the top 0438 basicLayout->addStretch(); 0439 0440 // more advanced options 0441 m_advancedOptsTab = new QWidget; 0442 m_advancedScrollA->setWidget(m_advancedOptsTab); 0443 0444 QVBoxLayout *advancedLayout = new QVBoxLayout(m_advancedOptsTab); 0445 0446 // Color Options Frame 0447 m_colorOpts = new QWidget(m_advancedOptsTab); 0448 advancedLayout->addWidget(m_colorOpts); 0449 QVBoxLayout *colorLayout = new QVBoxLayout(m_colorOpts); 0450 colorLayout->setContentsMargins(0, 0, 0, 0); 0451 0452 // Add Color correction to the color "frame" 0453 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BrightnessOption)) != nullptr) { 0454 KSaneOptionWidget *brightness = createOptionWidget(m_advancedOptsTab, option); 0455 colorLayout->addWidget(brightness); 0456 } 0457 0458 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::ContrastOption)) != nullptr) { 0459 KSaneOptionWidget *contrast = createOptionWidget(m_advancedOptsTab, option); 0460 colorLayout->addWidget(contrast); 0461 } 0462 0463 // Add gamma tables to the color "frame" 0464 QWidget *gamma_frm = new QWidget(m_colorOpts); 0465 colorLayout->addWidget(gamma_frm); 0466 QVBoxLayout *gam_frm_l = new QVBoxLayout(gamma_frm); 0467 gam_frm_l->setContentsMargins(0, 0, 0, 0); 0468 LabeledGamma *gammaR = nullptr; 0469 LabeledGamma *gammaG = nullptr; 0470 LabeledGamma *gammaB = nullptr; 0471 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::GammaRedOption)) != nullptr) { 0472 m_optGamR = option; 0473 gammaR = new LabeledGamma(gamma_frm, option, Qt::red); 0474 gam_frm_l->addWidget(gammaR); 0475 m_handledOptions.insert(option->name()); 0476 } 0477 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::GammaGreenOption)) != nullptr) { 0478 m_optGamG = option; 0479 gammaG = new LabeledGamma(gamma_frm, option, Qt::green); 0480 gam_frm_l->addWidget(gammaG); 0481 m_handledOptions.insert(option->name()); 0482 } 0483 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::GammaBlueOption)) != nullptr) { 0484 m_optGamB = option; 0485 gammaB = new LabeledGamma(gamma_frm, option, Qt::blue); 0486 gam_frm_l->addWidget(gammaB); 0487 m_handledOptions.insert(option->name()); 0488 } 0489 0490 if ((m_optGamR != nullptr) && (m_optGamG != nullptr) && (m_optGamB != nullptr) 0491 && (gammaR != nullptr) && (gammaG != nullptr) && (gammaB != nullptr) ) { 0492 0493 m_commonGamma = new LabeledGamma(m_colorOpts, i18n("Image intensity"), gammaR->maxValue()); 0494 0495 colorLayout->addWidget(m_commonGamma); 0496 0497 m_commonGamma->setToolTip(i18n("Gamma-correction table. In color mode this option equally " \ 0498 "affects the red, green, and blue channels simultaneously (i.e., it is an " \ 0499 "intensity gamma table).")); 0500 0501 connect(m_commonGamma, &LabeledGamma::valuesChanged, gammaR, &LabeledGamma::setValues); 0502 connect(m_commonGamma, &LabeledGamma::valuesChanged, gammaG, &LabeledGamma::setValues); 0503 connect(m_commonGamma, &LabeledGamma::valuesChanged, gammaB, &LabeledGamma::setValues); 0504 0505 m_splitGamChB = new LabeledCheckbox(m_colorOpts, i18n("Separate color intensity tables")); 0506 colorLayout->addWidget(m_splitGamChB); 0507 0508 connect(m_splitGamChB, &LabeledCheckbox::toggled, gamma_frm, &QWidget::setVisible); 0509 connect(m_splitGamChB, &LabeledCheckbox::toggled, m_commonGamma, &LabeledGamma::setHidden); 0510 0511 gamma_frm->hide(); 0512 } 0513 0514 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BlackLevelOption)) != nullptr) { 0515 KSaneOptionWidget *blackLevel = createOptionWidget(m_colorOpts, option); 0516 colorLayout->addWidget(blackLevel); 0517 } 0518 0519 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::WhiteLevelOption)) != nullptr) { 0520 KSaneOptionWidget *blackLevel = createOptionWidget(m_colorOpts, option); 0521 colorLayout->addWidget(blackLevel); 0522 } 0523 0524 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::InvertColorOption)) != nullptr) { 0525 m_optInvert = option; 0526 KSaneOptionWidget *invertColor = createOptionWidget(m_colorOpts, option); 0527 colorLayout->addWidget(invertColor); 0528 connect(m_optInvert, &KSaneCore::Option::valueChanged, this, &KSaneWidgetPrivate::invertPreview); 0529 } 0530 0531 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BatchModeOption)) != nullptr) { 0532 KSaneOptionWidget *batchMode = createOptionWidget(m_advancedOptsTab, option); 0533 colorLayout->addWidget(batchMode); 0534 } 0535 0536 if ((option = m_ksaneCoreInterface->getOption(KSaneCore::Interface::BatchDelayOption)) != nullptr) { 0537 KSaneOptionWidget *batchDelay = createOptionWidget(m_advancedOptsTab, option); 0538 colorLayout->addWidget(batchDelay); 0539 } 0540 advancedLayout->addStretch(); 0541 0542 // Remaining (un known) options go to the "Other Options" 0543 m_otherOptsTab = new QWidget; 0544 m_otherScrollA->setWidget(m_otherOptsTab); 0545 0546 QVBoxLayout *otherLayout = new QVBoxLayout(m_otherOptsTab); 0547 0548 const auto optionsList = m_ksaneCoreInterface->getOptionsList(); 0549 // add the remaining parameters 0550 for (const auto option : optionsList) { 0551 if (m_handledOptions.find(option->name()) != m_handledOptions.end()) { 0552 continue; 0553 } 0554 if (option->type() != KSaneCore::Option::TypeDetectFail) { 0555 KSaneOptionWidget *widget = createOptionWidget(m_otherOptsTab, option); 0556 if (widget != nullptr) { 0557 otherLayout->addWidget(widget); 0558 } 0559 } 0560 } 0561 0562 // add a stretch to the end to keep the parameters at the top 0563 otherLayout->addStretch(); 0564 0565 // calculate label widths 0566 int labelWidth = 0; 0567 KSaneOptionWidget *tmpOption; 0568 // Basic Options 0569 for (int i = 0; i < basicLayout->count(); ++i) { 0570 if (basicLayout->itemAt(i) && basicLayout->itemAt(i)->widget()) { 0571 tmpOption = qobject_cast<KSaneOptionWidget *>(basicLayout->itemAt(i)->widget()); 0572 if (tmpOption) { 0573 labelWidth = qMax(labelWidth, tmpOption->labelWidthHint()); 0574 } 0575 } 0576 } 0577 // Color Options 0578 for (int i = 0; i < colorLayout->count(); ++i) { 0579 if (colorLayout->itemAt(i) && colorLayout->itemAt(i)->widget()) { 0580 tmpOption = qobject_cast<KSaneOptionWidget *>(colorLayout->itemAt(i)->widget()); 0581 if (tmpOption) { 0582 labelWidth = qMax(labelWidth, tmpOption->labelWidthHint()); 0583 } 0584 } 0585 } 0586 // Set label widths 0587 for (int i = 0; i < basicLayout->count(); ++i) { 0588 if (basicLayout->itemAt(i) && basicLayout->itemAt(i)->widget()) { 0589 tmpOption = qobject_cast<KSaneOptionWidget *>(basicLayout->itemAt(i)->widget()); 0590 if (tmpOption) { 0591 tmpOption->setLabelWidth(labelWidth); 0592 } 0593 } 0594 } 0595 for (int i = 0; i < colorLayout->count(); ++i) { 0596 if (colorLayout->itemAt(i) && colorLayout->itemAt(i)->widget()) { 0597 tmpOption = qobject_cast<KSaneOptionWidget *>(colorLayout->itemAt(i)->widget()); 0598 if (tmpOption) { 0599 tmpOption->setLabelWidth(labelWidth); 0600 } 0601 } 0602 } 0603 // Other Options 0604 labelWidth = 0; 0605 for (int i = 0; i < otherLayout->count(); ++i) { 0606 if (otherLayout->itemAt(i) && otherLayout->itemAt(i)->widget()) { 0607 tmpOption = qobject_cast<KSaneOptionWidget *>(otherLayout->itemAt(i)->widget()); 0608 if (tmpOption) { 0609 labelWidth = qMax(labelWidth, tmpOption->labelWidthHint()); 0610 } 0611 } 0612 } 0613 for (int i = 0; i < otherLayout->count(); ++i) { 0614 if (otherLayout->itemAt(i) && otherLayout->itemAt(i)->widget()) { 0615 tmpOption = qobject_cast<KSaneOptionWidget *>(otherLayout->itemAt(i)->widget()); 0616 if (tmpOption) { 0617 tmpOption->setLabelWidth(labelWidth); 0618 } 0619 } 0620 } 0621 0622 // ensure that we do not get a scrollbar at the bottom of the option of the options 0623 int min_width = m_basicOptsTab->sizeHint().width(); 0624 if (min_width < m_otherOptsTab->sizeHint().width()) { 0625 min_width = m_otherOptsTab->sizeHint().width(); 0626 } 0627 0628 m_optsTabWidget->setMinimumWidth(min_width + m_basicScrollA->verticalScrollBar()->sizeHint().width() + 5); 0629 } 0630 0631 void KSaneWidgetPrivate::updateCommonGamma() 0632 { 0633 // Gamma table special case 0634 if (m_optGamR && m_optGamG && m_optGamB) { 0635 m_commonGamma->setHidden(m_optGamR->state() == KSaneCore::Option::StateHidden); 0636 m_splitGamChB->setHidden(m_optGamR->state() == KSaneCore::Option::StateHidden); 0637 } 0638 } 0639 0640 void KSaneWidgetPrivate::updatePreviewViewer() 0641 { 0642 // estimate the preview size and create an empty image 0643 // this is done so that you can select scan area without 0644 // having to scan a preview. 0645 updatePreviewSize(); 0646 0647 // ensure that we do not get a scrollbar at the bottom of the option of the options 0648 int min_width = m_basicOptsTab->sizeHint().width(); 0649 if (min_width < m_otherOptsTab->sizeHint().width()) { 0650 min_width = m_otherOptsTab->sizeHint().width(); 0651 } 0652 0653 m_optsTabWidget->setMinimumWidth(min_width + m_basicScrollA->verticalScrollBar()->sizeHint().width() + 5); 0654 0655 m_previewViewer->zoom2Fit(); 0656 } 0657 0658 void KSaneWidgetPrivate::handleSelection(float tl_x, float tl_y, float br_x, float br_y) 0659 { 0660 if ((m_optTlX == nullptr) || (m_optTlY == nullptr) || (m_optBrX == nullptr) || (m_optBrY == nullptr)) { 0661 // clear the selection since we can not set one 0662 m_previewViewer->setTLX(0); 0663 m_previewViewer->setTLY(0); 0664 m_previewViewer->setBRX(0); 0665 m_previewViewer->setBRY(0); 0666 return; 0667 } 0668 0669 if ((m_previewImg.width() == 0) || (m_previewImg.height() == 0)) { 0670 m_scanareaX->setValue(0); 0671 m_scanareaY->setValue(0); 0672 0673 m_scanareaWidth->setValue(ratioToDispUnitX(1)); 0674 m_scanareaHeight->setValue(ratioToDispUnitY(1)); 0675 return; 0676 } 0677 0678 if (br_x < 0.0001) { 0679 m_scanareaWidth->setValue(ratioToDispUnitX(1)); 0680 m_scanareaHeight->setValue(ratioToDispUnitY(1)); 0681 } 0682 else { 0683 m_scanareaWidth->setValue(ratioToDispUnitX(br_x - tl_x)); 0684 m_scanareaHeight->setValue(ratioToDispUnitY(br_y - tl_y)); 0685 } 0686 m_scanareaX->setValue(ratioToDispUnitX(tl_x)); 0687 m_scanareaY->setValue(ratioToDispUnitY(tl_y)); 0688 0689 m_optTlX->setValue(ratioToScanAreaX(tl_x)); 0690 m_optTlY->setValue(ratioToScanAreaY(tl_y)); 0691 m_optBrX->setValue(ratioToScanAreaX(br_x)); 0692 m_optBrY->setValue(ratioToScanAreaY(br_y)); 0693 } 0694 0695 void KSaneWidgetPrivate::setTLX(const QVariant &x) 0696 { 0697 bool ok; 0698 float ftlx = x.toFloat(&ok); 0699 // ignore this when conversion not possible and during an active scan 0700 if (!ok || m_scanOngoing) { 0701 return; 0702 } 0703 0704 float ratio = scanAreaToRatioX(ftlx); 0705 m_previewViewer->setTLX(ratio); 0706 m_scanareaX->setValue(ratioToDispUnitX(ratio)); 0707 } 0708 0709 void KSaneWidgetPrivate::setTLY(const QVariant &y) 0710 { 0711 bool ok; 0712 float ftly = y.toFloat(&ok); 0713 // ignore this when conversion not possible and during an active scan 0714 if (!ok || m_scanOngoing) { 0715 return; 0716 } 0717 0718 float ratio = scanAreaToRatioY(ftly); 0719 m_previewViewer->setTLY(ratio); 0720 m_scanareaY->setValue(ratioToDispUnitY(ratio)); 0721 } 0722 0723 void KSaneWidgetPrivate::setBRX(const QVariant &x) 0724 { 0725 bool ok; 0726 float fbrx = x.toFloat(&ok); 0727 // ignore this when conversion not possible and during an active scan 0728 if (!ok || m_scanOngoing) { 0729 return; 0730 } 0731 0732 float ratio = scanAreaToRatioX(fbrx); 0733 m_previewViewer->setBRX(ratio); 0734 0735 if (!m_optTlX) { 0736 return; 0737 } 0738 0739 QVariant tlx = m_optTlX->value(); 0740 if (!tlx.isNull()) { 0741 float tlxRatio = scanAreaToRatioX(tlx.toFloat()); 0742 m_scanareaWidth->setValue(ratioToDispUnitX(ratio) - ratioToDispUnitX(tlxRatio)); 0743 } 0744 } 0745 0746 void KSaneWidgetPrivate::setBRY(const QVariant &y) 0747 { 0748 bool ok; 0749 float fbry = y.toFloat(&ok); 0750 // ignore this when conversion not possible and during an active scan 0751 if (!ok || m_scanOngoing) { 0752 return; 0753 } 0754 0755 float ratio = scanAreaToRatioY(fbry); 0756 m_previewViewer->setBRY(ratio); 0757 0758 if (!m_optTlY) { 0759 return; 0760 } 0761 QVariant tly = m_optTlY->value(); 0762 if (!tly.isNull()) { 0763 float tlyRatio = scanAreaToRatioY(tly.toFloat()); 0764 m_scanareaHeight->setValue(ratioToDispUnitY(ratio) - ratioToDispUnitY(tlyRatio)); 0765 } 0766 } 0767 0768 void KSaneWidgetPrivate::updatePreviewSize() 0769 { 0770 float max_x = 0; 0771 float max_y = 0; 0772 float ratio; 0773 int x, y; 0774 0775 // check if an update is necessary 0776 if (m_optBrX != nullptr) { 0777 max_x = m_optBrX->maximumValue().toFloat(); 0778 } 0779 if (m_optBrY != nullptr) { 0780 max_y = m_optBrY->maximumValue().toFloat(); 0781 } 0782 if ((max_x == m_previewWidth) && (max_y == m_previewHeight)) { 0783 //qCDebug(KSANE_LOG) << "no preview size change"; 0784 return; 0785 } 0786 0787 // The preview size has changed 0788 m_previewWidth = max_x; 0789 m_previewHeight = max_y; 0790 0791 // set the scan area to the whole area 0792 m_previewViewer->clearSelections(); 0793 if (m_optTlX != nullptr) { 0794 m_optTlX->setValue(0); 0795 } 0796 if (m_optTlY != nullptr) { 0797 m_optTlY->setValue(0); 0798 } 0799 0800 if (m_optBrX != nullptr) { 0801 m_optBrX->setValue(max_x); 0802 } 0803 if (m_optBrY != nullptr) { 0804 m_optBrY->setValue(max_y); 0805 } 0806 0807 // Avoid crash if max_y or max_x == 0 0808 if (max_x < 0.0001 || max_y < 0.0001) { 0809 qCWarning(KSANE_LOG) << "Risk for division by 0" << max_x << max_y; 0810 return; 0811 } 0812 0813 // create a "scaled" image of the preview 0814 ratio = max_x / max_y; 0815 if (ratio < 1) { 0816 x = SCALED_PREVIEW_MAX_SIDE; 0817 y = (int)(SCALED_PREVIEW_MAX_SIDE / ratio); 0818 } else { 0819 y = SCALED_PREVIEW_MAX_SIDE; 0820 x = (int)(SCALED_PREVIEW_MAX_SIDE / ratio); 0821 } 0822 0823 const qreal dpr = q->devicePixelRatioF(); 0824 m_previewImg = QImage(QSize(x, y) * dpr, QImage::Format_RGB32); 0825 m_previewImg.setDevicePixelRatio(dpr); 0826 m_previewImg.fill(0xFFFFFFFF); 0827 0828 // set the new image 0829 m_previewViewer->setQImage(&m_previewImg); 0830 0831 // update the scan-area-options 0832 m_scanareaWidth->setRange(0.1, ratioToDispUnitX(1)); 0833 m_scanareaWidth->setValue(ratioToDispUnitX(1)); 0834 0835 m_scanareaHeight->setRange(0.1, ratioToDispUnitY(1)); 0836 m_scanareaHeight->setValue(ratioToDispUnitY(1)); 0837 0838 m_scanareaX->setRange(0.0, ratioToDispUnitX(1)); 0839 m_scanareaY->setRange(0.0, ratioToDispUnitY(1)); 0840 0841 setPossibleScanSizes(); 0842 } 0843 0844 void KSaneWidgetPrivate::startPreviewScan() 0845 { 0846 if (m_scanOngoing) { 0847 return; 0848 } 0849 m_scanOngoing = true; 0850 0851 int targetPreviewDPI; 0852 float max_x, max_y; 0853 0854 // store the current settings of parameters to be changed 0855 if (m_optDepth != nullptr) { 0856 m_optDepth->storeCurrentData(); 0857 } 0858 if (m_optRes != nullptr) { 0859 m_optRes->storeCurrentData(); 0860 } 0861 if (m_optResX != nullptr) { 0862 m_optResX->storeCurrentData(); 0863 } 0864 if (m_optResY != nullptr) { 0865 m_optResY->storeCurrentData(); 0866 } 0867 if (m_optPreview != nullptr) { 0868 m_optPreview->storeCurrentData(); 0869 } 0870 0871 // check if we can modify the selection 0872 if ((m_optTlX != nullptr) && (m_optTlY != nullptr) && 0873 (m_optBrX != nullptr) && (m_optBrY != nullptr)) { 0874 // get maximums 0875 max_x = m_optBrX->maximumValue().toFloat(); 0876 max_y = m_optBrY->maximumValue().toFloat(); 0877 // select the whole area 0878 m_optTlX->setValue(0); 0879 m_optTlY->setValue(0); 0880 m_optBrX->setValue(max_x); 0881 m_optBrY->setValue(max_y); 0882 0883 } else { 0884 // no use to try auto selections if you can not use them 0885 m_autoSelect = false; 0886 } 0887 0888 if (m_optRes != nullptr) { 0889 if (m_previewDPI < m_optRes->minimumValue().toFloat()) { 0890 targetPreviewDPI = qMax(m_optRes->minimumValue().toFloat(), 25.0f); 0891 if ((m_optBrX != nullptr) && (m_optBrY != nullptr)) { 0892 if (m_optBrX->valueUnit() == KSaneCore::Option::UnitMilliMeter) { 0893 targetPreviewDPI = 300 * 25.4 / (m_optBrX->value().toFloat()); 0894 // always round to a multiple of 25 0895 int remainder = targetPreviewDPI % 25; 0896 targetPreviewDPI = targetPreviewDPI + 25 - remainder; 0897 } 0898 } 0899 } else { 0900 targetPreviewDPI = m_previewDPI; 0901 } 0902 if (m_optRes->type() == KSaneCore::Option::TypeValueList) { 0903 const auto &values = m_optRes->valueList(); 0904 if (values.count() <= 0) { 0905 qCWarning(KSANE_LOG) << "Resolution option is broken and has no entries"; 0906 return; 0907 } 0908 /* if there are discrete values, try to find the one which fits best. */ 0909 int minIndex = 0; 0910 int minDistance = abs(values.at(0).toInt() - m_previewDPI); 0911 for (int i = 1; i < values.count(); ++i) { 0912 int distance = abs(values.at(i).toInt() - m_previewDPI); 0913 if (distance < minDistance) { 0914 minIndex = i; 0915 minDistance = distance; 0916 } 0917 0918 } 0919 targetPreviewDPI = values.at(minIndex).toInt(); 0920 0921 } 0922 m_optRes->setValue(targetPreviewDPI); 0923 if ((m_optResY != nullptr) && (m_optRes == m_optResX)) { 0924 m_optResY->setValue(targetPreviewDPI); 0925 } 0926 } 0927 0928 // set preview option to true if possible 0929 if (m_optPreview != nullptr) { 0930 m_optPreview->setValue(true); 0931 } 0932 0933 // clear the preview 0934 m_previewViewer->clearHighlight(); 0935 m_previewViewer->clearSelections(); 0936 m_previewImg.fill(0xFFFFFFFF); 0937 updatePreviewSize(); 0938 0939 setBusy(true); 0940 0941 m_isPreview = true; 0942 m_cancelMultiScan = false; 0943 m_ksaneCoreInterface->startScan(); 0944 } 0945 0946 void KSaneWidgetPrivate::previewScanDone(KSaneCore::Interface::ScanStatus status, const QString &strStatus) 0947 { 0948 // restore the original settings of the changed parameters 0949 if (m_optDepth != nullptr) { 0950 m_optDepth->restoreSavedData(); 0951 } 0952 if (m_optRes != nullptr) { 0953 m_optRes->restoreSavedData(); 0954 } 0955 if (m_optResX != nullptr) { 0956 m_optResX->restoreSavedData(); 0957 } 0958 if (m_optResY != nullptr) { 0959 m_optResY->restoreSavedData(); 0960 } 0961 if (m_optPreview != nullptr) { 0962 m_optPreview->restoreSavedData(); 0963 } 0964 0965 m_previewImg = std::move(*m_ksaneCoreInterface->scanImage()); 0966 m_previewViewer->setQImage(&m_previewImg); 0967 m_previewViewer->zoom2Fit(); 0968 0969 if (status != KSaneCore::Interface::ErrorGeneral && m_autoSelect) { 0970 m_previewViewer->findSelections(); 0971 } 0972 0973 setBusy(false); 0974 m_scanOngoing = false; 0975 0976 Q_EMIT q->scanDone(KSaneWidget::NoError, QString()); 0977 0978 return; 0979 } 0980 0981 void KSaneWidgetPrivate::startFinalScan() 0982 { 0983 if (m_scanOngoing) { 0984 return; 0985 } 0986 m_scanOngoing = true; 0987 0988 m_isPreview = false; 0989 0990 float x1 = 0, y1 = 0, x2 = 0, y2 = 0; 0991 0992 m_selIndex = 0; 0993 0994 if ((m_optTlX != nullptr) && (m_optTlY != nullptr) && (m_optBrX != nullptr) && (m_optBrY != nullptr)) { 0995 // read the selection from the viewer 0996 m_previewViewer->selectionAt(m_selIndex, x1, y1, x2, y2); 0997 m_previewViewer->setHighlightArea(x1, y1, x2, y2); 0998 m_selIndex++; 0999 1000 // now set the selection 1001 m_optTlX->setValue(ratioToScanAreaX(x1)); 1002 m_optTlY->setValue(ratioToScanAreaY(y1)); 1003 m_optBrX->setValue(ratioToScanAreaX(x2)); 1004 m_optBrY->setValue(ratioToScanAreaY(y2)); 1005 } 1006 1007 setBusy(true); 1008 m_cancelMultiScan = false; 1009 m_ksaneCoreInterface->startScan(); 1010 } 1011 1012 void KSaneWidgetPrivate::imageReady(const QImage &image) 1013 { 1014 if (m_isPreview) { 1015 return; 1016 } 1017 Q_EMIT q->scannedImageReady(image); 1018 } 1019 1020 bool KSaneWidgetPrivate::scanSourceADF() 1021 { 1022 if (!m_optSource) { 1023 return false; 1024 } 1025 1026 QString source = m_optSource->value().toString(); 1027 1028 return source.contains(QStringLiteral("Automatic Document Feeder")) || 1029 source.contains(QStringLiteral("ADF")) || 1030 source.contains(QStringLiteral("Duplex")); 1031 } 1032 1033 void KSaneWidgetPrivate::scanDone(KSaneCore::Interface::ScanStatus status, const QString &strStatus) 1034 { 1035 if (m_isPreview) { 1036 previewScanDone(status, strStatus); 1037 } else { 1038 oneFinalScanDone(status, strStatus); 1039 } 1040 } 1041 1042 void KSaneWidgetPrivate::oneFinalScanDone(KSaneCore::Interface::ScanStatus status, const QString &strStatus) 1043 { 1044 // check if we have multiple selections. 1045 if (m_previewViewer->selListSize() > m_selIndex) { 1046 if ((m_optTlX != nullptr) && (m_optTlY != nullptr) && (m_optBrX != nullptr) && (m_optBrY != nullptr)) { 1047 float x1 = 0; 1048 float y1 = 0; 1049 float x2 = 0; 1050 float y2 = 0; 1051 1052 // read the selection from the viewer 1053 m_previewViewer->selectionAt(m_selIndex, x1, y1, x2, y2); 1054 1055 // set the highlight 1056 m_previewViewer->setHighlightArea(x1, y1, x2, y2); 1057 1058 // now set the selection 1059 m_optTlX->setValue(ratioToScanAreaX(x1)); 1060 m_optTlY->setValue(ratioToScanAreaY(y1)); 1061 m_optBrX->setValue(ratioToScanAreaX(x2)); 1062 m_optBrY->setValue(ratioToScanAreaY(y2)); 1063 m_selIndex++; 1064 1065 if (!m_cancelMultiScan) { 1066 m_ksaneCoreInterface->startScan(); 1067 return; 1068 } 1069 } 1070 } else { 1071 switch (status) { 1072 case KSaneCore::Interface::NoError: 1073 Q_EMIT q->scanDone(KSaneWidget::NoError, QString()); 1074 break; 1075 case KSaneCore::Interface::Information: 1076 Q_EMIT q->scanDone(KSaneWidget::Information, strStatus); 1077 break; 1078 case KSaneCore::Interface::ErrorGeneral: 1079 Q_EMIT q->scanDone(KSaneWidget::ErrorGeneral, strStatus); 1080 break; 1081 } 1082 } 1083 1084 // clear the highlight 1085 m_previewViewer->setHighlightArea(0, 0, 1, 1); 1086 setBusy(false); 1087 m_scanOngoing = false; 1088 } 1089 1090 void KSaneWidgetPrivate::setBusy(bool busy) 1091 { 1092 if (busy) { 1093 m_btnFrame->hide(); 1094 m_activityFrame->show(); 1095 } else { 1096 m_btnFrame->show(); 1097 m_activityFrame->hide(); 1098 } 1099 1100 m_optsTabWidget->setDisabled(busy); 1101 m_previewViewer->setDisabled(busy); 1102 1103 m_scanBtn->setFocus(Qt::OtherFocusReason); 1104 } 1105 1106 void KSaneWidgetPrivate::checkInvert() 1107 { 1108 if (!m_optSource) { 1109 return; 1110 } 1111 if (!m_optFilmType) { 1112 return; 1113 } 1114 if (m_scanOngoing) { 1115 return; 1116 } 1117 1118 QString source = m_optSource->value().toString(); 1119 QString filmtype = m_optFilmType->value().toString(); 1120 1121 if ((source.contains(i18nc("This is compared to the option string returned by sane", 1122 "Transparency"), Qt::CaseInsensitive)) && 1123 (filmtype.contains(i18nc("This is compared to the option string returned by sane", 1124 "Negative"), Qt::CaseInsensitive))) { 1125 m_optInvert->setValue(true); 1126 } else { 1127 m_optInvert->setValue(false); 1128 } 1129 } 1130 1131 void KSaneWidgetPrivate::invertPreview() 1132 { 1133 m_previewViewer->updateImage(); 1134 } 1135 1136 void KSaneWidgetPrivate::updateProgress(int progress) 1137 { 1138 if (progress < 0 && !m_warmingUp->isVisible()) { 1139 m_warmingUp->show(); 1140 m_progressBar->hide(); 1141 m_countDown->hide(); 1142 } else { 1143 m_warmingUp->hide(); 1144 m_progressBar->show(); 1145 m_countDown->hide(); 1146 } 1147 if (m_isPreview) { 1148 // the image size might have changed 1149 if (m_ksaneCoreInterface->scanImage()->height() != m_previewViewer->currentImageHeight() 1150 || m_ksaneCoreInterface->scanImage()->width() != m_previewViewer->currentImageWidth() ) { 1151 1152 m_ksaneCoreInterface->lockScanImage(); 1153 m_previewViewer->setQImage(m_ksaneCoreInterface->scanImage()); 1154 m_previewViewer->zoom2Fit(); 1155 m_ksaneCoreInterface->unlockScanImage(); 1156 } else { 1157 m_ksaneCoreInterface->lockScanImage(); 1158 m_previewViewer->updateImage(); 1159 m_ksaneCoreInterface->unlockScanImage(); 1160 } 1161 } else { 1162 m_previewViewer->setHighlightShown(progress); 1163 } 1164 1165 m_progressBar->setValue(progress); 1166 Q_EMIT q->scanProgress(progress); 1167 } 1168 1169 void KSaneWidgetPrivate::updateCountDown(int remainingSeconds) 1170 { 1171 m_countDown->setText(i18n("Next scan starts in %1 s.", remainingSeconds)); 1172 if (remainingSeconds > 0 && !m_countDown->isVisible()) { 1173 m_countDown->show(); 1174 m_warmingUp->hide(); 1175 m_progressBar->hide(); 1176 } 1177 } 1178 1179 void KSaneWidgetPrivate::alertUser(KSaneCore::Interface::ScanStatus status, const QString &strStatus) 1180 { 1181 if (!q->isSignalConnected(QMetaMethod::fromSignal(&KSaneWidget::userMessage))) { 1182 switch (status) { 1183 case KSaneCore::Interface::ErrorGeneral: 1184 QMessageBox::critical(nullptr, i18nc("@title:window", "General Error"), strStatus); 1185 break; 1186 default: 1187 QMessageBox::information(nullptr, i18nc("@title:window", "Information"), strStatus); 1188 break; 1189 } 1190 } else { 1191 switch (status) { 1192 case KSaneCore::Interface::NoError: 1193 Q_EMIT q->userMessage(KSaneWidget::NoError, QString()); 1194 break; 1195 case KSaneCore::Interface::Information: 1196 Q_EMIT q->userMessage(KSaneWidget::Information, strStatus); 1197 break; 1198 case KSaneCore::Interface::ErrorGeneral: 1199 Q_EMIT q->userMessage(KSaneWidget::ErrorGeneral, strStatus); 1200 break; 1201 } 1202 } 1203 } 1204 1205 void KSaneWidgetPrivate::updateScanSelection() 1206 { 1207 QVariant maxX; 1208 if (m_optBrX) { 1209 maxX = m_optBrX->maximumValue(); 1210 } 1211 1212 QVariant maxY; 1213 if (m_optBrY) { 1214 maxY = m_optBrY->maximumValue(); 1215 } 1216 1217 float x1 = m_scanareaX->value(); 1218 float y1 = m_scanareaY->value(); 1219 float w = m_scanareaWidth->value(); 1220 float h = m_scanareaHeight->value(); 1221 1222 float x1Max = maxX.toFloat() - w; 1223 m_scanareaX->setRange(0.0, x1Max); 1224 if (x1 > x1Max) { 1225 m_scanareaX->setValue(x1Max); 1226 } 1227 1228 float y1Max = maxY.toFloat() - h; 1229 m_scanareaY->setRange(0.0, y1Max); 1230 if (y1 > y1Max) { 1231 m_scanareaY->setValue(y1Max); 1232 } 1233 1234 float wR = dispUnitToRatioX(w); 1235 float hR = dispUnitToRatioY(h); 1236 1237 float x1R = dispUnitToRatioX(m_scanareaX->value()); 1238 float y1R = dispUnitToRatioY(m_scanareaY->value()); 1239 1240 m_previewViewer->setSelection(x1R, y1R, x1R+wR, y1R+hR); 1241 1242 // Update the page size combo, but not while updating or 1243 // if we already have custom page size. 1244 if (m_settingPageSize || 1245 m_scanareaPapersize->currentIndex() == m_scanareaPapersize->count() - 1) { 1246 return; 1247 } 1248 QSizeF size = m_scanareaPapersize->currentData().toSizeF(); 1249 float pageWidth = mmToDispUnit(size.width()); 1250 float pageHeight = mmToDispUnit(size.height()); 1251 if (qAbs(pageWidth - w) > (w * 0.001) || 1252 qAbs(pageHeight - h) > (h * 0.001)) 1253 { 1254 // The difference is bigger than 1% -> we have a custom size 1255 m_scanareaPapersize->blockSignals(true); 1256 m_scanareaPapersize->setCurrentIndex(0); // Custom is always first 1257 m_scanareaPapersize->blockSignals(false); 1258 } 1259 } 1260 1261 void KSaneWidgetPrivate::setPossibleScanSizes() 1262 { 1263 m_scanareaPapersize->clear(); 1264 float widthInDispUnit = ratioToDispUnitX(1); 1265 float heightInDispUnit = ratioToDispUnitY(1); 1266 1267 // Add the custom size first 1268 QSizeF customSize(widthInDispUnit, heightInDispUnit); 1269 m_scanareaPapersize->addItem(i18n("Custom"), customSize); 1270 1271 // Add portrait page sizes 1272 for (int sizeCode: qAsConst(m_sizeCodes)) { 1273 QSizeF size = QPageSize::size((QPageSize::PageSizeId)sizeCode, QPageSize::Millimeter); 1274 if (mmToDispUnit(size.width() - PageSizeWiggleRoom) > widthInDispUnit) { 1275 continue; 1276 } 1277 if (mmToDispUnit(size.height() - PageSizeWiggleRoom) > heightInDispUnit) { 1278 continue; 1279 } 1280 m_scanareaPapersize->addItem(QPageSize::name((QPageSize::PageSizeId)sizeCode), size); 1281 } 1282 1283 // Add landscape page sizes 1284 for (int sizeCode: qAsConst(m_sizeCodes)) { 1285 QSizeF size = QPageSize::size((QPageSize::PageSizeId)sizeCode, QPageSize::Millimeter); 1286 size.transpose(); 1287 if (mmToDispUnit(size.width() - PageSizeWiggleRoom) > widthInDispUnit) { 1288 continue; 1289 } 1290 if (mmToDispUnit(size.height() - PageSizeWiggleRoom) > heightInDispUnit) { 1291 continue; 1292 } 1293 QString name = QPageSize::name((QPageSize::PageSizeId)sizeCode) + 1294 i18nc("Page size landscape", " Landscape"); 1295 m_scanareaPapersize->addItem(name , size); 1296 } 1297 1298 // Set custom as current 1299 m_scanareaPapersize->blockSignals(true); 1300 m_scanareaPapersize->setCurrentIndex(0); 1301 m_scanareaPapersize->blockSignals(false); 1302 } 1303 1304 void KSaneWidgetPrivate::setPageSize(int) 1305 { 1306 QSizeF size = m_scanareaPapersize->currentData().toSizeF(); 1307 float pageWidth = mmToDispUnit(size.width()); 1308 float pageHeight = mmToDispUnit(size.height()); 1309 1310 m_settingPageSize = true; 1311 m_scanareaX->setValue(0); 1312 m_scanareaY->setValue(0); 1313 m_scanareaWidth->setValue(pageWidth); 1314 m_scanareaHeight->setValue(pageHeight); 1315 m_settingPageSize = false; 1316 } 1317 1318 1319 } // NameSpace KSaneIface 1320 1321 #include "moc_ksanewidget_p.cpp"