1 /************************************************************************
2  *									*
3  *  This file is part of Kooka, a scanning/OCR application using	*
4  *  Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>.	*
5  *									*
6  *  Copyright (C) 2000-2016 Klaas Freitag <freitag@suse.de>		*
7  *                          Jonathan Marten <jjm@keelhaul.me.uk>	*
8  *									*
9  *  Kooka is free software; you can redistribute it and/or modify it	*
10  *  under the terms of the GNU Library General Public License as	*
11  *  published by the Free Software Foundation and appearing in the	*
12  *  file COPYING included in the packaging of this file;  either	*
13  *  version 2 of the License, or (at your option) any later version.	*
14  *									*
15  *  As a special exception, permission is given to link this program	*
16  *  with any version of the KADMOS OCR/ICR engine (a product of		*
17  *  reRecognition GmbH, Kreuzlingen), and distribute the resulting	*
18  *  executable without including the source code for KADMOS in the	*
19  *  source distribution.						*
20  *									*
21  *  This program is distributed in the hope that it will be useful,	*
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of	*
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	*
24  *  GNU General Public License for more details.			*
25  *									*
26  *  You should have received a copy of the GNU General Public		*
27  *  License along with this program;  see the file COPYING.  If		*
28  *  not, see <http://www.gnu.org/licenses/>.				*
29  *									*
30  ************************************************************************/
31 
32 #include "prefspages.h"
33 
34 #include <qlayout.h>
35 #include <qcheckbox.h>
36 #include <qlabel.h>
37 #include <qradiobutton.h>
38 #include <qbuttongroup.h>
39 #include <qgroupbox.h>
40 #include <qcombobox.h>
41 #include <qdebug.h>
42 
43 #include <klocalizedstring.h>
44 #include <kmessagebox.h>
45 #include <kurlrequester.h>
46 #include <kseparator.h>
47 #include <kconfigskeleton.h>
48 
49 #include "scansettings.h"
50 #include "imagefilter.h"
51 
52 #include "kookapref.h"
53 #include "kookagallery.h"
54 #include "formatdialog.h"
55 #include "thumbview.h"
56 #include "pluginmanager.h"
57 #include "abstractocrengine.h"
58 #include "kookasettings.h"
59 
60 
61 //  Abstract base
62 
KookaPrefsPage(KPageDialog * parent)63 KookaPrefsPage::KookaPrefsPage(KPageDialog *parent)
64     : QWidget(parent)
65 {
66     mLayout = new QVBoxLayout(this);
67 }
68 
69 //  "General" page
70 
KookaGeneralPage(KPageDialog * parent)71 KookaGeneralPage::KookaGeneralPage(KPageDialog *parent)
72     : KookaPrefsPage(parent)
73 {
74     mLayout->addStretch(9);             // push down to bottom
75 
76     QGroupBox *gb = new QGroupBox(i18n("Hidden Messages"), this);
77     QGridLayout *gl = new QGridLayout(gb);
78 
79     /* Enable messages and questions */
80     QLabel *lab = new QLabel(i18n("Use this button to reenable all messages and questions which\nhave been hidden by using \"Don't ask me again\"."), gb);
81     gl->addWidget(lab, 0, 0);
82 
83     mEnableMessagesButton = new QPushButton(i18n("Enable Messages/Questions"), gb);
84     connect(mEnableMessagesButton, &QPushButton::clicked, this, &KookaGeneralPage::slotEnableWarnings);
85     gl->addWidget(mEnableMessagesButton, 1, 0, Qt::AlignRight);
86 
87     mLayout->addWidget(gb);
88 }
89 
saveSettings()90 void KookaGeneralPage::saveSettings()
91 {
92 }
93 
defaultSettings()94 void KookaGeneralPage::defaultSettings()
95 {
96 }
97 
slotEnableWarnings()98 void KookaGeneralPage::slotEnableWarnings()
99 {
100     //qDebug();
101 
102     KMessageBox::enableAllMessages();
103     FormatDialog::forgetRemembered();
104     KSharedConfig::openConfig()->reparseConfiguration();
105 
106     mEnableMessagesButton->setEnabled(false);           // show this has been done
107 }
108 
109 //  "Startup" page
110 
KookaStartupPage(KPageDialog * parent)111 KookaStartupPage::KookaStartupPage(KPageDialog *parent)
112     : KookaPrefsPage(parent)
113 {
114     /* Query for network scanner (Checkbox) */
115     const KConfigSkeletonItem *item = ScanSettings::self()->startupOnlyLocalItem();
116     Q_ASSERT(item!=nullptr);
117     mNetQueryCheck = new QCheckBox(item->label(), this);
118     mNetQueryCheck->setToolTip(item->toolTip());
119     mLayout->addWidget(mNetQueryCheck);
120 
121     /* Show scanner selection box on startup (Checkbox) */
122     item = ScanSettings::self()->startupSkipAskItem();
123     Q_ASSERT(item!=nullptr);
124     mSelectScannerCheck = new QCheckBox(item->label(), this);
125     mSelectScannerCheck->setToolTip(item->toolTip());
126     mLayout->addWidget(mSelectScannerCheck);
127 
128     /* Read startup image on startup (Checkbox) */
129     item = KookaSettings::self()->startupReadImageItem();
130     Q_ASSERT(item!=nullptr);
131     mRestoreImageCheck = new QCheckBox(item->label(), this);
132     mRestoreImageCheck->setToolTip(item->toolTip());
133     mLayout->addWidget(mRestoreImageCheck);
134 
135     applySettings();
136 }
137 
saveSettings()138 void KookaStartupPage::saveSettings()
139 {
140     ScanSettings::setStartupSkipAsk(!mSelectScannerCheck->isChecked());
141     ScanSettings::setStartupOnlyLocal(!mNetQueryCheck->isChecked());
142     ScanSettings::self()->save();
143 
144     KookaSettings::setStartupReadImage(mRestoreImageCheck->isChecked());
145     KookaSettings::self()->save();
146 }
147 
defaultSettings()148 void KookaStartupPage::defaultSettings()
149 {
150     ScanSettings::self()->startupSkipAskItem()->setDefault();
151     ScanSettings::self()->startupOnlyLocalItem()->setDefault();
152     KookaSettings::self()->startupReadImageItem()->setDefault();
153     applySettings();
154 }
155 
156 
applySettings()157 void KookaStartupPage::applySettings()
158 {
159     mSelectScannerCheck->setChecked(!ScanSettings::startupSkipAsk());
160     mNetQueryCheck->setChecked(!ScanSettings::startupOnlyLocal());
161     mRestoreImageCheck->setChecked(KookaSettings::startupReadImage());
162 }
163 
164 
165 //  "Saving" page
166 
KookaSavingPage(KPageDialog * parent)167 KookaSavingPage::KookaSavingPage(KPageDialog *parent)
168     : KookaPrefsPage(parent)
169 {
170     const KConfigSkeletonItem *item = KookaSettings::self()->saverAskForFormatItem();
171     Q_ASSERT(item!=nullptr);
172     mAskSaveFormat = new QCheckBox(item->label(), this);
173     mAskSaveFormat->setToolTip(item->toolTip());
174     mLayout->addWidget(mAskSaveFormat);
175 
176     mLayout->addSpacing(2 * DialogBase::verticalSpacing());
177 
178     item = KookaSettings::self()->saverAskForFilenameItem();
179     mAskFileName = new QCheckBox(item->label(), this);
180     mAskFileName->setToolTip(item->toolTip());
181     mLayout->addWidget(mAskFileName);
182 
183     QButtonGroup *bg = new QButtonGroup(this);
184     QGridLayout *gl = new QGridLayout;
185     gl->setVerticalSpacing(0);
186     gl->setColumnMinimumWidth(0, 3*DialogBase::verticalSpacing());
187 
188     item = KookaSettings::self()->saverAskBeforeScanItem();
189     Q_ASSERT(item!=nullptr);
190     mAskBeforeScan = new QRadioButton(item->label(), this);
191     mAskBeforeScan->setEnabled(mAskFileName->isChecked());
192     mAskBeforeScan->setToolTip(item->toolTip());
193     connect(mAskFileName, &QCheckBox::toggled, mAskBeforeScan, &QRadioButton::setEnabled);
194     bg->addButton(mAskBeforeScan);
195     gl->addWidget(mAskBeforeScan, 0, 1);
196 
197     item = KookaSettings::self()->saverAskAfterScanItem();
198     Q_ASSERT(item!=nullptr);
199     mAskAfterScan = new QRadioButton(item->label(), this);
200     mAskAfterScan->setEnabled(mAskFileName->isChecked());
201     mAskAfterScan->setToolTip(item->toolTip());
202     connect(mAskFileName, &QCheckBox::toggled, mAskAfterScan, &QRadioButton::setEnabled);
203     bg->addButton(mAskAfterScan);
204     gl->addWidget(mAskAfterScan, 1, 1);
205 
206     mLayout->addLayout(gl);
207 
208     applySettings();
209 }
210 
saveSettings()211 void KookaSavingPage::saveSettings()
212 {
213     KookaSettings::setSaverAskForFormat(mAskSaveFormat->isChecked());
214     KookaSettings::setSaverAskForFilename(mAskFileName->isChecked());
215     KookaSettings::setSaverAskBeforeScan(mAskBeforeScan->isChecked());
216     KookaSettings::self()->save();
217 }
218 
defaultSettings()219 void KookaSavingPage::defaultSettings()
220 {
221     KookaSettings::self()->saverAskForFormatItem()->setDefault();
222     KookaSettings::self()->saverAskForFilenameItem()->setDefault();
223     KookaSettings::self()->saverAskBeforeScanItem()->setDefault();
224     applySettings();
225 }
226 
227 
applySettings()228 void KookaSavingPage::applySettings()
229 {
230     mAskSaveFormat->setChecked(KookaSettings::saverAskForFormat());
231     mAskFileName->setChecked(KookaSettings::saverAskForFilename());
232     bool askBefore = KookaSettings::saverAskBeforeScan();
233     mAskBeforeScan->setChecked(askBefore);
234     mAskAfterScan->setChecked(!askBefore);
235 }
236 
237 //  "Gallery/Thumbnail" page
238 
KookaThumbnailPage(KPageDialog * parent)239 KookaThumbnailPage::KookaThumbnailPage(KPageDialog *parent)
240     : KookaPrefsPage(parent)
241 {
242     // Gallery options
243     QGroupBox *gb = new QGroupBox(i18n("Image Gallery"), this);
244     QGridLayout *gl = new QGridLayout(gb);
245     gl->setColumnStretch(1, 1);
246 
247     /* Layout */
248     const KConfigSkeletonItem *item = KookaSettings::self()->galleryLayoutItem();
249     Q_ASSERT(item!=nullptr);
250     QLabel *lab = new QLabel(item->label(), gb);
251     lab->setToolTip(item->toolTip());
252     gl->addWidget(lab, 0, 0, Qt::AlignRight);
253 
254     mGalleryLayoutCombo = new QComboBox(gb);
255     mGalleryLayoutCombo->setToolTip(item->toolTip());
256 // TODO: eliminate former enums
257     mGalleryLayoutCombo->addItem(i18n("Not shown"), KookaSettings::RecentNone);
258     mGalleryLayoutCombo->addItem(i18n("At top"), KookaSettings::RecentAtTop);
259     mGalleryLayoutCombo->addItem(i18n("At bottom"), KookaSettings::RecentAtBottom);
260 
261     lab->setBuddy(mGalleryLayoutCombo);
262     gl->addWidget(mGalleryLayoutCombo, 0, 1);
263 
264     /* Allow renaming */
265     item = KookaSettings::self()->galleryAllowRenameItem();
266     Q_ASSERT(item!=nullptr);
267     mAllowRenameCheck = new QCheckBox(item->label(), gb);
268     mAllowRenameCheck->setToolTip(item->toolTip());
269     gl->addWidget(mAllowRenameCheck, 1, 0, 1, 2);
270 
271     mLayout->addWidget(gb);
272 
273     // Thumbnail View options
274     gb = new QGroupBox(i18n("Thumbnail View"), this);
275     gl = new QGridLayout(gb);
276     gl->setColumnStretch(1, 1);
277 
278     // Do we want a background image?
279     item = KookaSettings::self()->thumbnailCustomBackgroundItem();
280     Q_ASSERT(item!=nullptr);
281     mCustomBackgroundCheck = new QCheckBox(item->label(), this);
282     mCustomBackgroundCheck->setToolTip(item->toolTip());
283     connect(mCustomBackgroundCheck, &QCheckBox::toggled, this, &KookaThumbnailPage::slotCustomThumbBgndToggled);
284     gl->addWidget(mCustomBackgroundCheck, 2, 0, 1, 2);
285 
286     /* Background image */
287     item = KookaSettings::self()->thumbnailBackgroundPathItem();
288     Q_ASSERT(item!=nullptr);
289     lab = new QLabel(item->label(), this);
290     lab->setToolTip(item->toolTip());
291     gl->addWidget(lab, 3, 0, Qt::AlignRight);
292 
293     /* Image file selector */
294     mTileSelector = new KUrlRequester(this);
295     mTileSelector->setToolTip(item->toolTip());
296     mTileSelector->setMode(KFile::File|KFile::ExistingOnly|KFile::LocalOnly);
297     mTileSelector->setFilter(ImageFilter::kdeFilter(ImageFilter::Reading));
298     gl->addWidget(mTileSelector, 3, 1);
299     lab->setBuddy(mTileSelector);
300 
301     gl->setRowMinimumHeight(4, 2*DialogBase::verticalSpacing());
302 
303     /* Preview size */
304     item = KookaSettings::self()->thumbnailPreviewSizeItem();
305     Q_ASSERT(item!=nullptr);
306     lab = new QLabel(item->label(), this);
307     lab->setToolTip(item->toolTip());
308     gl->addWidget(lab, 5, 0, Qt::AlignRight);
309 
310     mThumbSizeCombo = new QComboBox(this);
311     mThumbSizeCombo->setToolTip(item->toolTip());
312     mThumbSizeCombo->addItem(ThumbView::sizeName(KIconLoader::SizeEnormous), KIconLoader::SizeEnormous);
313     mThumbSizeCombo->addItem(ThumbView::sizeName(KIconLoader::SizeHuge), KIconLoader::SizeHuge);
314     mThumbSizeCombo->addItem(ThumbView::sizeName(KIconLoader::SizeLarge), KIconLoader::SizeLarge);
315     mThumbSizeCombo->addItem(ThumbView::sizeName(KIconLoader::SizeMedium), KIconLoader::SizeMedium);
316     mThumbSizeCombo->addItem(ThumbView::sizeName(KIconLoader::SizeSmallMedium), KIconLoader::SizeSmallMedium);
317     gl->addWidget(mThumbSizeCombo, 5, 1);
318     lab->setBuddy(mThumbSizeCombo);
319 
320     mLayout->addWidget(gb);
321 
322     applySettings();
323     slotCustomThumbBgndToggled(mCustomBackgroundCheck->isChecked());
324 }
325 
saveSettings()326 void KookaThumbnailPage::saveSettings()
327 {
328     KookaSettings::setGalleryAllowRename(mAllowRenameCheck->isChecked());
329     KookaSettings::setGalleryLayout(mGalleryLayoutCombo->itemData(mGalleryLayoutCombo->currentIndex()).toInt());
330 
331     KookaSettings::setThumbnailCustomBackground(mCustomBackgroundCheck->isChecked());
332     KookaSettings::setThumbnailBackgroundPath(mTileSelector->url().url(QUrl::PreferLocalFile));
333 
334     int size = mThumbSizeCombo->itemData(mThumbSizeCombo->currentIndex()).toInt();
335     if (size>0) KookaSettings::setThumbnailPreviewSize(size);
336 
337     KookaSettings::self()->save();
338 }
339 
defaultSettings()340 void KookaThumbnailPage::defaultSettings()
341 {
342     KookaSettings::self()->galleryLayoutItem()->setDefault();
343     KookaSettings::self()->galleryAllowRenameItem()->setDefault();
344     KookaSettings::self()->thumbnailCustomBackgroundItem()->setDefault();
345     KookaSettings::self()->thumbnailBackgroundPathItem()->setDefault();
346     KookaSettings::self()->thumbnailPreviewSizeItem()->setDefault();
347 
348     applySettings();
349     slotCustomThumbBgndToggled(false);
350 }
351 
352 
applySettings()353 void KookaThumbnailPage::applySettings()
354 {
355     mGalleryLayoutCombo->setCurrentIndex(KookaSettings::galleryLayout());
356     mAllowRenameCheck->setChecked(KookaSettings::galleryAllowRename());
357     mCustomBackgroundCheck->setChecked(KookaSettings::thumbnailCustomBackground());
358 
359     mTileSelector->setUrl(QUrl::fromLocalFile(KookaSettings::thumbnailBackgroundPath()));
360 
361     KIconLoader::StdSizes size = static_cast<KIconLoader::StdSizes>(KookaSettings::thumbnailPreviewSize());
362     int sel = mThumbSizeCombo->findData(size, Qt::UserRole, Qt::MatchExactly);
363     if (sel!=-1) mThumbSizeCombo->setCurrentIndex(sel);
364     //else kWarning() << "Cannot find combo index for size" << size;
365 }
366 
slotCustomThumbBgndToggled(bool state)367 void KookaThumbnailPage::slotCustomThumbBgndToggled(bool state)
368 {
369     mTileSelector->setEnabled(state);
370 }
371 
372 //  "OCR" page
373 
KookaOcrPage(KPageDialog * parent)374 KookaOcrPage::KookaOcrPage(KPageDialog *parent)
375     : KookaPrefsPage(parent)
376 {
377     QGridLayout *lay = new QGridLayout;
378     lay->setColumnStretch(1, 9);
379 
380     const QString configuredEngine = KookaSettings::ocrEngineName();
381     qDebug() << "configured engine" << configuredEngine;
382     int engineIndex = 0;
383 
384     mEngineCombo = new QComboBox(this);
385     mOcrPlugins = PluginManager::self()->allPlugins(PluginManager::OcrPlugin);
386     qDebug() << "have" << mOcrPlugins.count() << "OCR plugins";
387 
388     mEngineCombo->addItem(i18n("None"), QString());
389     for (QMap<QString,AbstractPluginInfo>::const_iterator it = mOcrPlugins.constBegin();
390          it!=mOcrPlugins.constEnd(); ++it)
391     {
392         const AbstractPluginInfo &info = it.value();
393         if (info.key==configuredEngine) engineIndex = mEngineCombo->count();
394         mEngineCombo->addItem(QIcon::fromTheme(info.icon), info.name, info.key);
395     }
396 
397     connect(mEngineCombo, QOverload<int>::of(&QComboBox::activated), this, &KookaOcrPage::slotEngineSelected);
398     lay->addWidget(mEngineCombo, 0, 1);
399 
400     QLabel *lab = new QLabel(i18n("OCR Engine:"), this);
401     lab->setBuddy(mEngineCombo);
402     lay->addWidget(lab, 0, 0, Qt::AlignRight);
403 
404     lay->setRowMinimumHeight(1, 2*DialogBase::verticalSpacing());
405 
406     mOcrAdvancedButton = new QPushButton(i18n("OCR Engine Settings..."), this);
407     connect(mOcrAdvancedButton, &QPushButton::clicked, this, &KookaOcrPage::slotOcrAdvanced);
408     lay->addWidget(mOcrAdvancedButton, 2, 1, Qt::AlignRight);
409 
410     lay->setRowMinimumHeight(3, 2*DialogBase::verticalSpacing());
411 
412     KSeparator *sep = new KSeparator(Qt::Horizontal, this);
413     lay->addWidget(sep, 4, 0, 1, 2);
414     lay->setRowMinimumHeight(5, 2*DialogBase::verticalSpacing());
415 
416     mDescLabel = new QLabel("?", this);
417     mDescLabel->setOpenExternalLinks(true);
418     mDescLabel->setWordWrap(true);
419     lay->addWidget(mDescLabel, 6, 0, 1, 2, Qt::AlignTop);
420     lay->setRowStretch(6, 1);
421 
422     mLayout->addLayout(lay);
423 
424     mEngineCombo->setCurrentIndex(engineIndex);
425     slotEngineSelected(mEngineCombo->currentIndex());
426 }
427 
428 
saveSettings()429 void KookaOcrPage::saveSettings()
430 {
431     KookaSettings::setOcrEngineName(mEngineCombo->currentData().toString());
432 }
433 
434 
defaultSettings()435 void KookaOcrPage::defaultSettings()
436 {
437     mEngineCombo->setCurrentIndex(0);
438     slotEngineSelected(mEngineCombo->currentIndex());
439 }
440 
441 
slotEngineSelected(int i)442 void KookaOcrPage::slotEngineSelected(int i)
443 {
444     const QString pluginKey = mEngineCombo->currentData().toString();
445     qDebug() << "selected" << pluginKey;
446 
447     QString msg;					// description message
448     bool enableAdvanced = false;			// for the moment, anyway
449 
450     if (pluginKey.isEmpty())				// no engine selected
451     {
452         msg = i18n("No OCR engine is selected. Select and configure one to be able to perform OCR.");
453     }
454     else						// an engine is selected,
455     {							// try to load its plugin
456         const AbstractPlugin *plugin = PluginManager::self()->loadPlugin(PluginManager::OcrPlugin, pluginKey);
457         const AbstractOcrEngine *engine = qobject_cast<const AbstractOcrEngine *>(plugin);
458         if (engine==nullptr)				// plugin not found
459         {
460             msg = i18n("Unknown engine '%1'.", pluginKey);
461         }
462         else
463         {
464             msg = engine->pluginInfo()->description;
465             enableAdvanced = engine->hasAdvancedSettings();
466         }
467     }
468 
469     mDescLabel->setText(msg);				// show description text
470     mOcrAdvancedButton->setEnabled(enableAdvanced);	// enable button if applicable
471 }
472 
473 
slotOcrAdvanced()474 void KookaOcrPage::slotOcrAdvanced()
475 {
476     AbstractPlugin *plugin = PluginManager::self()->currentPlugin(PluginManager::OcrPlugin);
477     AbstractOcrEngine *engine = qobject_cast<AbstractOcrEngine *>(plugin);
478     Q_ASSERT(engine!=nullptr);
479     Q_ASSERT(engine->hasAdvancedSettings());
480 
481     engine->openAdvancedSettings();
482 }
483