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 "kscancontrols.h"
33
34 #include <qgroupbox.h>
35 #include <qlayout.h>
36 #include <qtoolbutton.h>
37 #include <qspinbox.h>
38 #include <qcombobox.h>
39 #include <qcheckbox.h>
40 #include <qlabel.h>
41 #include <qslider.h>
42 #include <qlineedit.h>
43 #include <qdebug.h>
44 #include <qicon.h>
45 #include <qimagereader.h>
46 #include <qmimetype.h>
47 #include <qmimedatabase.h>
48
49 #include <klocalizedstring.h>
50 #include <kurlrequester.h>
51
52 #include "imagefilter.h"
53
54
55 // KScanControl - base class
56 // -------------------------
57
KScanControl(QWidget * parent,const QString & text)58 KScanControl::KScanControl(QWidget *parent, const QString &text)
59 : QWidget(parent)
60 {
61 mLayout = new QHBoxLayout(this);
62 mLayout->setMargin(0);
63
64 mText = text;
65 if (mText.isEmpty()) {
66 mText = i18n("(Unknown)");
67 }
68 }
69
~KScanControl()70 KScanControl::~KScanControl() {}
71
text() const72 QString KScanControl::text() const
73 {
74 return (QString());
75 }
setText(const QString & text)76 void KScanControl::setText(const QString &text) {}
77
value() const78 int KScanControl::value() const
79 {
80 return (0);
81 }
setValue(int val)82 void KScanControl::setValue(int val) {}
83
label() const84 QString KScanControl::label() const
85 {
86 return (mText + ":");
87 }
88
89 // KScanSlider - slider, spin box and optional reset button
90 // --------------------------------------------------------
91
KScanSlider(QWidget * parent,const QString & text,double min,double max,bool haveStdButt,int stdValue)92 KScanSlider::KScanSlider(QWidget *parent, const QString &text,
93 double min, double max,
94 bool haveStdButt, int stdValue)
95 : KScanControl(parent, text)
96 {
97 mValue = mStdValue = stdValue;
98 mStdButt = nullptr;
99
100 mSlider = new QSlider(Qt::Horizontal, this); // slider
101 mSlider->setRange(((int) min), ((int) max));
102 mSlider->setTickPosition(QSlider::TicksBelow);
103 mSlider->setTickInterval(qMax(((int)((max - min) / 10)), 1));
104 mSlider->setSingleStep(qMax(((int)((max - min) / 20)), 1));
105 mSlider->setPageStep(qMax(((int)((max - min) / 10)), 1));
106 mSlider->setMinimumWidth(140);
107 mSlider->setValue(mValue); // initial value
108 mLayout->addWidget(mSlider, 1);
109
110 mSpinbox = new QSpinBox(this); // spin box
111 mSpinbox->setRange((int) min, (int) max);
112 mSpinbox->setSingleStep(1);
113 mSpinbox->setValue(mValue); // initial value
114 mLayout->addWidget(mSpinbox);
115
116 if (haveStdButt) {
117 mStdButt = new QToolButton(this); // reset button
118 mStdButt->setIcon(QIcon::fromTheme("edit-undo"));
119 mStdButt->setToolTip(i18n("Reset this setting to its standard value, %1", stdValue));
120 mLayout->addWidget(mStdButt);
121 }
122
123 connect(mSlider, SIGNAL(valueChanged(int)), SLOT(slotSliderSpinboxChange(int)));
124 connect(mSpinbox, SIGNAL(valueChanged(int)), SLOT(slotSliderSpinboxChange(int)));
125 if (mStdButt != nullptr) {
126 connect(mStdButt, SIGNAL(clicked()), SLOT(slotRevertValue()));
127 }
128
129 setFocusProxy(mSlider);
130 setFocusPolicy(Qt::StrongFocus);
131 }
132
setValue(int val)133 void KScanSlider::setValue(int val)
134 {
135 if (val == mValue) {
136 return; // avoid recursive signals
137 }
138 mValue = val;
139
140 int spin = mSpinbox->value();
141 if (spin != val) {
142 mSpinbox->blockSignals(true);
143 mSpinbox->setValue(val); // track in spin box
144 mSpinbox->blockSignals(false);
145 }
146
147 int slid = mSlider->value();
148 if (slid != val) {
149 mSlider->blockSignals(true);
150 mSlider->setValue(val); // track in slider
151 mSlider->blockSignals(false);
152 }
153 }
154
value() const155 int KScanSlider::value() const
156 {
157 return (mValue);
158 }
159
slotSliderSpinboxChange(int val)160 void KScanSlider::slotSliderSpinboxChange(int val)
161 {
162 setValue(val);
163 emit settingChanged(val);
164 }
165
slotRevertValue()166 void KScanSlider::slotRevertValue()
167 {
168 // only connected if button exists
169 slotSliderSpinboxChange(mStdValue);
170 }
171
172 // KScanStringEntry - free text entry field
173 // ----------------------------------------
174
KScanStringEntry(QWidget * parent,const QString & text)175 KScanStringEntry::KScanStringEntry(QWidget *parent, const QString &text)
176 : KScanControl(parent, text)
177 {
178 mEntry = new QLineEdit(this);
179 mLayout->addWidget(mEntry);
180
181 connect(mEntry, SIGNAL(textChanged(QString)), SIGNAL(settingChanged(QString)));
182 connect(mEntry, SIGNAL(returnPressed()), SIGNAL(returnPressed()));
183
184 setFocusProxy(mEntry);
185 setFocusPolicy(Qt::StrongFocus);
186 }
187
text() const188 QString KScanStringEntry::text() const
189 {
190 return (mEntry->text());
191 }
192
setText(const QString & text)193 void KScanStringEntry::setText(const QString &text)
194 {
195 if (text == mEntry->text()) {
196 return; // avoid recursive signals
197 }
198 mEntry->setText(text);
199 }
200
201 // KScanNumberEntry - number entry field
202 // -------------------------------------
203
KScanNumberEntry(QWidget * parent,const QString & text)204 KScanNumberEntry::KScanNumberEntry(QWidget *parent, const QString &text)
205 : KScanControl(parent, text)
206 {
207 mEntry = new QLineEdit(this);
208 mEntry->setValidator(new QIntValidator);
209 mLayout->addWidget(mEntry);
210
211 connect(mEntry, SIGNAL(textChanged(QString)), SLOT(slotTextChanged(QString)));
212 connect(mEntry, SIGNAL(returnPressed()), SIGNAL(returnPressed()));
213
214 setFocusProxy(mEntry);
215 setFocusPolicy(Qt::StrongFocus);
216 }
217
value() const218 int KScanNumberEntry::value() const
219 {
220 return (mEntry->text().toInt());
221 }
222
setValue(int i)223 void KScanNumberEntry::setValue(int i)
224 {
225 mEntry->setText(QString::number(i));
226 }
227
slotTextChanged(const QString & s)228 void KScanNumberEntry::slotTextChanged(const QString &s)
229 {
230 emit settingChanged(s.toInt());
231 }
232
233 // KScanCheckbox - on/off option
234 // -----------------------------
235
KScanCheckbox(QWidget * parent,const QString & text)236 KScanCheckbox::KScanCheckbox(QWidget *parent, const QString &text)
237 : KScanControl(parent, text)
238 {
239 mCheckbox = new QCheckBox(text, this);
240 mLayout->addWidget(mCheckbox);
241
242 connect(mCheckbox, SIGNAL(stateChanged(int)), SIGNAL(settingChanged(int)));
243
244 setFocusProxy(mCheckbox);
245 setFocusPolicy(Qt::StrongFocus);
246 }
247
value() const248 int KScanCheckbox::value() const
249 {
250 return ((int) mCheckbox->isChecked());
251 }
252
setValue(int i)253 void KScanCheckbox::setValue(int i)
254 {
255 mCheckbox->setChecked((bool) i);
256 }
257
label() const258 QString KScanCheckbox::label() const
259 {
260 return (QString());
261 }
262
263 // KScanCombo - combo box with list of options
264 // -------------------------------------------
265 //
266 // This control (and currently only this control) is special, because the
267 // item text is set to the translated value of the option values. But these
268 // values need to reported back unchanged, so the untranslated form is stored
269 // in the itemData and the translated form is seen by the user as itemText.
270 // Any access needs to only set or report the itemData, never the itemText,
271 // which is why the activated(QString) signal cannot be used directly.
272
KScanCombo(QWidget * parent,const QString & text)273 KScanCombo::KScanCombo(QWidget *parent, const QString &text)
274 : KScanControl(parent, text)
275 {
276 mCombo = new QComboBox(this);
277 mLayout->addWidget(mCombo);
278
279 connect(mCombo, SIGNAL(activated(int)), SLOT(slotActivated(int)));
280
281 setFocusProxy(mCombo);
282 setFocusPolicy(Qt::StrongFocus);
283 }
284
285
setList(const QList<QByteArray> & list)286 void KScanCombo::setList(const QList<QByteArray> &list)
287 {
288 // An optimisation, which may turn out to be not a valid one:
289 // only update the combo box if the number of items has changed.
290 if (list.count()==mCombo->count()) return;
291 //qDebug() << "count" << mCombo->count() << "->" << list.count() << "=" << list;
292
293 const QString cur = text(); // get current setting
294
295 const bool bs = mCombo->blockSignals(true);
296 mCombo->clear();
297
298 foreach (const QByteArray &item, list)
299 {
300 // See the KI18N Programmer's Guide, "Connecting to Catalogs in Library Code"
301 mCombo->addItem(ki18n(item.constData()).toString("sane-backends"), item);
302 }
303
304 mCombo->blockSignals(bs);
305 if (!cur.isEmpty()) setText(cur); // try to restore old setting
306 }
307
setText(const QString & text)308 void KScanCombo::setText(const QString &text)
309 {
310 int i = mCombo->findData(text); // find item with that text
311 if (i == -1) return; // ignore if not present
312
313 if (i == mCombo->currentIndex()) return; // avoid recursive signals
314 mCombo->setCurrentIndex(i);
315 }
316
setIcon(const QIcon & icon,const char * ent)317 void KScanCombo::setIcon(const QIcon &icon, const char *ent)
318 {
319 int i = mCombo->findData(ent); // find item with that text
320 if (i != -1) mCombo->setItemIcon(i, icon);
321 }
322
text() const323 QString KScanCombo::text() const
324 {
325 return (textAt(mCombo->currentIndex()));
326 }
327
setValue(int i)328 void KScanCombo::setValue(int i)
329 {
330 mCombo->setCurrentIndex(i);
331 }
332
textAt(int i) const333 QString KScanCombo::textAt(int i) const
334 {
335 return (i == -1 ? QString() : mCombo->itemData(i).toString());
336 }
337
count() const338 int KScanCombo::count() const
339 {
340 return (mCombo->count());
341 }
342
slotActivated(int i)343 void KScanCombo::slotActivated(int i)
344 {
345 emit settingChanged(i);
346 emit settingChanged(textAt(i));
347 }
348
349 // KScanFileRequester - standard URL requester
350 // -------------------------------------------
351
KScanFileRequester(QWidget * parent,const QString & text)352 KScanFileRequester::KScanFileRequester(QWidget *parent, const QString &text)
353 : KScanControl(parent, text)
354 {
355 mEntry = new KUrlRequester(this);
356 mLayout->addWidget(mEntry);
357
358 QString filter = i18n("*.pnm *.pbm *.pgm *.ppm|PNM Image Files");
359 filter += '\n'+ImageFilter::kdeFilter(ImageFilter::Reading);
360 mEntry->setFilter(filter);
361
362 connect(mEntry, SIGNAL(textChanged(QString)), SIGNAL(settingChanged(QString)));
363 connect(mEntry, SIGNAL(returnPressed()), SIGNAL(returnPressed()));
364
365 setFocusProxy(mEntry);
366 setFocusPolicy(Qt::StrongFocus);
367 }
368
text() const369 QString KScanFileRequester::text() const
370 {
371 return (mEntry->url().url());
372 }
373
setText(const QString & text)374 void KScanFileRequester::setText(const QString &text)
375 {
376 if (text == mEntry->url().url()) {
377 return; // avoid recursive signals
378 }
379 mEntry->setUrl(QUrl::fromLocalFile(text));
380 }
381
382 // KScanGroup - group separator
383 // ----------------------------
384
KScanGroup(QWidget * parent,const QString & text)385 KScanGroup::KScanGroup(QWidget *parent, const QString &text)
386 : KScanControl(parent, text)
387 {
388 mGroup = new QGroupBox(text, this);
389 mGroup->setFlat(true);
390 mLayout->addWidget(mGroup);
391 }
392
label() const393 QString KScanGroup::label() const
394 {
395 return (QString());
396 }
397
398 // KScanPushButton - action button
399 // -------------------------------
400
KScanPushButton(QWidget * parent,const QString & text)401 KScanPushButton::KScanPushButton(QWidget *parent, const QString &text)
402 : KScanControl(parent, text)
403 {
404 mButton = new QPushButton(text, this);
405 mLayout->addWidget(mButton);
406
407 connect(mButton, SIGNAL(clicked()), SIGNAL(returnPressed()));
408 }
409
label() const410 QString KScanPushButton::label() const
411 {
412 return (QString());
413 }
414