File indexing completed on 2024-04-21 15:12:07

0001 /************************************************************************
0002  *                                  *
0003  *  This file is part of Kooka, a scanning/OCR application using    *
0004  *  Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>.  *
0005  *                                  *
0006  *  Copyright (C) 2008-2016 Jonathan Marten <jjm@keelhaul.me.uk>    *
0007  *                                  *
0008  *  Kooka is free software; you can redistribute it and/or modify it    *
0009  *  under the terms of the GNU Library General Public License as    *
0010  *  published by the Free Software Foundation and appearing in the  *
0011  *  file COPYING included in the packaging of this file;  either    *
0012  *  version 2 of the License, or (at your option) any later version.    *
0013  *                                  *
0014  *  As a special exception, permission is given to link this program    *
0015  *  with any version of the KADMOS OCR/ICR engine (a product of     *
0016  *  reRecognition GmbH, Kreuzlingen), and distribute the resulting  *
0017  *  executable without including the source code for KADMOS in the  *
0018  *  source distribution.                        *
0019  *                                  *
0020  *  This program is distributed in the hope that it will be useful, *
0021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  *
0022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
0023  *  GNU General Public License for more details.            *
0024  *                                  *
0025  *  You should have received a copy of the GNU General Public       *
0026  *  License along with this program;  see the file COPYING.  If     *
0027  *  not, see <http://www.gnu.org/licenses/>.                *
0028  *                                  *
0029  ************************************************************************/
0030 
0031 #include "scanpresetsdialog.h"
0032 
0033 #include <qlabel.h>
0034 #include <qlayout.h>
0035 #include <qpushbutton.h>
0036 #include <qlistwidget.h>
0037 
0038 #include <klocalizedstring.h>
0039 #include <kmessagebox.h>
0040 #include <kstandardguiitem.h>
0041 
0042 extern "C" {
0043 #include <sane/saneopts.h>
0044 }
0045 
0046 #include "kscandevice.h"
0047 #include "kscanoption.h"
0048 #include "kscanoptset.h"
0049 #include "kscancontrols.h"
0050 #include "scanicons.h"
0051 #include "newscanpresetdialog.h"
0052 #include "kooka_logging.h"
0053 
0054 
0055 // TODO: also associate an icon, default the "color"/"grey" etc
0056 
0057 ScanPresetsDialog::ScanPresetsDialog(KScanDevice *scandev, QWidget *pnt)
0058     : DialogBase(pnt)
0059 {
0060     setObjectName("ScanPresetsDialog");
0061 
0062     setButtons(QDialogButtonBox::Close);
0063     setWindowTitle(i18n("Scan Presets"));
0064 
0065     QWidget *w = new QWidget(this);
0066     QGridLayout *gl = new QGridLayout(w);
0067 
0068     mParamsList = new QListWidget(w);
0069     mParamsList->setSelectionMode(QAbstractItemView::SingleSelection);
0070     mParamsList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
0071     mParamsList->setMinimumWidth(200);
0072     connect(mParamsList, &QListWidget::itemSelectionChanged, this, &ScanPresetsDialog::slotSelectionChanged);
0073     connect(mParamsList, &QListWidget::itemDoubleClicked, this, &ScanPresetsDialog::slotLoadAndClose);
0074     gl->addWidget(mParamsList, 1, 0, 5, 1);
0075 
0076     QLabel *l = new QLabel(i18n("Saved scan preset sets:"), w);
0077     gl->addWidget(l, 0, 0, Qt::AlignLeft);
0078     l->setBuddy(mParamsList);
0079 
0080     mLoadButton = new QPushButton(i18n("Select"), w);
0081     mLoadButton->setIcon(QIcon::fromTheme("dialog-ok-apply"));
0082     mLoadButton->setToolTip(i18n("Load the selected scan preset set to use as scanner settings"));
0083     connect(mLoadButton, &QPushButton::clicked, this, &ScanPresetsDialog::slotLoad);
0084     gl->addWidget(mLoadButton, 1, 2);
0085 
0086     mSaveButton = new QPushButton(i18n("Save..."), w);
0087     mSaveButton->setIcon(QIcon::fromTheme("bookmark-new"));
0088     mSaveButton->setToolTip(i18n("Save the current scanner settings as a new scan preset set"));
0089     connect(mSaveButton, &QPushButton::clicked, this, &ScanPresetsDialog::slotSave);
0090     gl->addWidget(mSaveButton, 2, 2);
0091 
0092     mDeleteButton = new QPushButton(w);
0093     KGuiItem::assign(mDeleteButton, KStandardGuiItem::del());
0094     mDeleteButton->setToolTip(i18n("Delete the selected scan preset set"));
0095     connect(mDeleteButton, &QPushButton::clicked, this, &ScanPresetsDialog::slotDelete);
0096     gl->addWidget(mDeleteButton, 3, 2);
0097 
0098     mEditButton = new QPushButton(i18n("Edit..."), w);
0099     mEditButton->setIcon(QIcon::fromTheme("document-edit"));
0100     mEditButton->setToolTip(i18n("Change the name or description of the selected scan preset set"));
0101     connect(mEditButton, &QPushButton::clicked, this, &ScanPresetsDialog::slotEdit);
0102     gl->addWidget(mEditButton, 4, 2);
0103 
0104     gl->setRowStretch(5, 9);
0105     gl->setRowMinimumHeight(6, 2*DialogBase::verticalSpacing());
0106 
0107     gl->setColumnStretch(0, 9);
0108     gl->setColumnMinimumWidth(1, 2*DialogBase::horizontalSpacing());
0109 
0110     mDescLabel = new QLabel(w);
0111     gl->addWidget(mDescLabel, 7, 0, 1, 3);
0112 
0113     mScanDevice = scandev;
0114 
0115     setMainWidget(w);
0116     populateList();
0117     slotSelectionChanged();
0118 }
0119 
0120 
0121 void ScanPresetsDialog::populateList()
0122 {
0123     mParamsList->clear();
0124     mSets = KScanOptSet::readList();
0125 
0126     for (KScanOptSet::StringMap::const_iterator it = mSets.constBegin(); it != mSets.constEnd(); ++it)
0127     {
0128         const QString &setName = it.key();
0129         qCDebug(KOOKA_LOG) << "saveset" << setName;
0130 
0131         KScanOptSet optSet(setName);
0132         optSet.loadConfig();
0133         const QByteArray scanMode = optSet.value(SANE_NAME_SCAN_MODE);
0134 
0135         mParamsList->addItem(new QListWidgetItem(ScanIcons::self()->icon(scanMode), setName));
0136     }
0137 }
0138 
0139 
0140 void ScanPresetsDialog::slotSelectionChanged()
0141 {
0142     QString desc;
0143     bool enable = false;
0144 
0145     QListWidgetItem *item = mParamsList->currentItem();
0146     if (item == nullptr) desc = i18n("No preset set selected.");
0147     else                        // something getting selected
0148     {
0149         desc = mSets[item->text()];
0150         enable = true;
0151     }
0152 
0153     mDescLabel->setText(desc);
0154     mLoadButton->setEnabled(enable);
0155     mDeleteButton->setEnabled(enable);
0156     mEditButton->setEnabled(enable);
0157 
0158     mLoadButton->setDefault(enable);
0159     buttonBox()->button(QDialogButtonBox::Close)->setDefault(!enable);
0160 }
0161 
0162 
0163 void ScanPresetsDialog::slotLoad()
0164 {
0165     QListWidgetItem *item = mParamsList->currentItem();
0166     if (item == nullptr) return;
0167 
0168     QString name = item->text();
0169     qCDebug(KOOKA_LOG) << "set" << name;
0170 
0171     KScanOptSet optSet(name);
0172     if (!optSet.loadConfig())
0173     {
0174         qCWarning(KOOKA_LOG) << "Failed to load set" << name;
0175         return;
0176     }
0177 
0178     mScanDevice->loadOptionSet(&optSet);
0179     mScanDevice->reloadAllOptions();
0180 }
0181 
0182 
0183 void ScanPresetsDialog::slotLoadAndClose(QListWidgetItem *item)
0184 {
0185     if (item == nullptr) return;
0186 
0187     qCDebug(KOOKA_LOG) << "set" << item->text();
0188     mParamsList->setCurrentItem(item);
0189     slotLoad();
0190     accept();
0191 }
0192 
0193 
0194 void ScanPresetsDialog::slotSave()
0195 {
0196     QString name;
0197     QListWidgetItem *item = mParamsList->currentItem();
0198     if (item != nullptr) name = item->text();
0199     qCDebug(KOOKA_LOG) << "selected set" << name;
0200 
0201     QString newdesc;
0202     if (mSets.contains(name)) newdesc = mSets[name];
0203     else
0204     {
0205         const KScanOption *sm = mScanDevice->getExistingGuiElement(SANE_NAME_SCAN_MODE);
0206         const KScanOption *sr = mScanDevice->getExistingGuiElement(SANE_NAME_SCAN_RESOLUTION);
0207         if (sm != nullptr && sr != nullptr)
0208         {
0209             // See KScanCombo for explanation of how the translation works.
0210             QString scanMode = ki18n(sm->widget()->text().toLocal8Bit().constData()).toString("sane-backends");
0211             if (scanMode.isEmpty()) scanMode = sm->get();
0212             newdesc = i18nc("New set name, %1=scan mode, %2=resolution", "%1, %2 dpi",
0213                             scanMode, sr->get().constData());
0214         }
0215     }
0216 
0217     NewScanPresetDialog d(name, newdesc, false, this);
0218     if (!d.exec()) return;
0219 
0220     const QString newName = d.getName();
0221     const QString newDesc = d.getDescription();
0222     qCDebug(KOOKA_LOG) << "name" << newName << "desc" << newDesc;
0223 
0224     KScanOptSet optSet(newName);
0225     mScanDevice->getCurrentOptions(&optSet);
0226 
0227     optSet.saveConfig(mScanDevice->scannerBackendName(), newDesc);
0228     mSets[newName] = newDesc;
0229 
0230     // TODO: why?
0231     mParamsList->setCurrentItem(nullptr);
0232     QList<QListWidgetItem *> found = mParamsList->findItems(newName, Qt::MatchFixedString | Qt::MatchCaseSensitive);
0233     if (found.isEmpty())
0234     {
0235         const QByteArray scanMode = optSet.value(SANE_NAME_SCAN_MODE);
0236         mParamsList->addItem(new QListWidgetItem(ScanIcons::self()->icon(scanMode), newName));
0237         item = mParamsList->item(mParamsList->count() - 1);
0238     }
0239     else item = found.first();
0240 
0241     mParamsList->setCurrentItem(item);
0242     slotSelectionChanged();
0243 }
0244 
0245 
0246 void ScanPresetsDialog::slotEdit()
0247 {
0248     QListWidgetItem *item = mParamsList->currentItem();
0249     if (item == nullptr) {
0250         return;
0251     }
0252     QString oldName = item->text();
0253     qCDebug(KOOKA_LOG) << "selected set" << oldName;
0254 
0255     NewScanPresetDialog d(oldName, mSets[oldName], true, this);
0256     if (!d.exec()) return;
0257 
0258     const QString newName = d.getName();
0259     const QString newDesc = d.getDescription();
0260     if (newName==oldName && newDesc==mSets[oldName]) return;
0261     qCDebug(KOOKA_LOG) << "new name" << newName << "desc" << newDesc;
0262 
0263     KScanOptSet optSet(oldName.toLocal8Bit());
0264     if (!optSet.loadConfig()) {
0265         qCWarning(KOOKA_LOG) << "Failed to load set" << oldName;
0266         return;
0267     }
0268 
0269     KScanOptSet::deleteSet(oldName);            // do first, in case name not changed
0270     optSet.setSetName(newName);
0271     optSet.saveConfig(mScanDevice->scannerBackendName(), newDesc);
0272 
0273     mSets.remove(oldName);              // do first, ditto
0274     mSets[newName] = newDesc;
0275 
0276     item->setText(newName);
0277     slotSelectionChanged();             // recalculate 'item', it may change
0278 }
0279 
0280 
0281 void ScanPresetsDialog::slotDelete()
0282 {
0283     QListWidgetItem *item = mParamsList->currentItem();
0284     if (item == nullptr) return;
0285 
0286     QString name = item->text();
0287     qCDebug(KOOKA_LOG) << "set" << name;
0288     if (KMessageBox::warningContinueCancel(this,
0289                                            xi18nc("@info", "Do you really want to delete the set <resource>%1</resource>?", name),
0290                                            i18n("Delete Scan Preset Set"),
0291                                            KStandardGuiItem::del(),
0292                                            KStandardGuiItem::cancel(),
0293                                            "deleteSaveSet") != KMessageBox::Continue) return;
0294 
0295     KScanOptSet::deleteSet(name);
0296     delete mParamsList->takeItem(mParamsList->row(item));
0297     mParamsList->setCurrentItem(nullptr);       // clear selection
0298 }