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 "kooka.h"
33
34 #include <qevent.h>
35 #include <qaction.h>
36 #include <qicon.h>
37 #include <qmenu.h>
38 #include <qdebug.h>
39 #include <qlabel.h>
40 #include <qmimedata.h>
41
42 #include <klocalizedstring.h>
43 #include <ktoggleaction.h>
44 #include <kactionmenu.h>
45 #include <kiconloader.h>
46 #include <kmessagebox.h>
47 #include <kstandardaction.h>
48 #include <kactioncollection.h>
49 #include <kxmlguiwindow.h>
50 #ifndef KDE4
51 #include <kprinter.h>
52 #endif
53
54 #include "scanglobal.h"
55 #include "imagecanvas.h"
56 #include "previewer.h"
57
58 #include "scangallery.h"
59 #include "kookapref.h"
60 #include "kookasettings.h"
61 #include "kookaview.h"
62 #include "imagetransform.h"
63
64
Kooka(const QByteArray & deviceToUse)65 Kooka::Kooka(const QByteArray &deviceToUse)
66 : KXmlGuiWindow(nullptr),
67 #ifndef KDE4
68 m_printer(0),
69 #endif
70 m_prefDialogIndex(0)
71 {
72 setObjectName("Kooka");
73
74 // Set up the status bar
75 StatusBarManager *sbm = new StatusBarManager(this);
76
77 /* Start to create the main view framework */
78 m_view = new KookaView(this, deviceToUse);
79 setCentralWidget(m_view);
80
81 setAcceptDrops(false); // Waba: Not (yet?) supported
82
83 readProperties(KSharedConfig::openConfig()->group(autoSaveGroup()));
84
85 // then, setup our actions
86 setupActions();
87
88 setupGUI(KXmlGuiWindow::Default, "kookaui.rc");
89 setAutoSaveSettings(); // default group, do save
90
91 // Allow the view to change the status bar and caption
92 connect(m_view, SIGNAL(changeStatus(QString,StatusBarManager::Item)),
93 sbm, SLOT(setStatus(QString,StatusBarManager::Item)));
94 connect(m_view, SIGNAL(clearStatus(StatusBarManager::Item)),
95 sbm, SLOT(clearStatus(StatusBarManager::Item)));
96 connect(m_view, SIGNAL(signalChangeCaption(QString)),
97 SLOT(setCaption(QString)));
98 connect(m_view, SIGNAL(signalScannerChanged(bool)),
99 SLOT(slotUpdateScannerActions(bool)));
100 connect(m_view, SIGNAL(signalRectangleChanged(bool)),
101 SLOT(slotUpdateRectangleActions(bool)));
102 connect(m_view, SIGNAL(signalViewSelectionState(KookaView::StateFlags)),
103 SLOT(slotUpdateViewActions(KookaView::StateFlags)));
104 connect(m_view, SIGNAL(signalOcrResultAvailable(bool)),
105 SLOT(slotUpdateOcrResultActions(bool)));
106 connect(m_view, SIGNAL(signalOcrPrefs()),
107 SLOT(optionsOcrPreferences()));
108
109 connect(m_view->imageViewer(), SIGNAL(imageReadOnly(bool)),
110 SLOT(slotUpdateReadOnlyActions(bool)));
111
112 connect(m_view->previewer(), SIGNAL(autoSelectStateChanged(bool,bool)),
113 SLOT(slotUpdateAutoSelectActions(bool,bool)));
114 connect(m_view->previewer(), SIGNAL(previewFileSizeChanged(long)),
115 sbm, SLOT(setFileSize(long)));
116
117 setCaption(i18n("KDE Scanning"));
118
119 slotUpdateScannerActions(m_view->isScannerConnected());
120 slotUpdateRectangleActions(false);
121 slotUpdateViewActions(KookaView::GalleryShown | KookaView::IsDirectory | KookaView::RootSelected);
122 slotUpdateOcrResultActions(false);
123 slotUpdateReadOnlyActions(true);
124 }
125
~Kooka()126 Kooka::~Kooka()
127 {
128 m_view->closeScanDevice();
129 delete m_view; // ensure its config saved
130 #ifndef KDE4
131 delete m_printer;
132 #endif
133 }
134
startup()135 void Kooka::startup()
136 {
137 if (m_view == nullptr) {
138 return;
139 }
140
141 //qDebug();
142 m_view->gallery()->openRoots();
143 m_view->loadStartupImage();
144 }
145
146 // TODO: use KStandardShortcut wherever available
setupActions()147 void Kooka::setupActions()
148 {
149 printImageAction = KStandardAction::print(this, SLOT(filePrint()), actionCollection());
150
151 KStandardAction::quit(this, SLOT(close()), actionCollection());
152 KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
153
154 // Image Viewer
155
156 scaleToWidthAction = new QAction(QIcon::fromTheme("zoom-fit-width"), i18n("Scale to Width"), this);
157 actionCollection()->addAction("scaleToWidth", scaleToWidthAction);
158 actionCollection()->setDefaultShortcut(scaleToWidthAction, Qt::CTRL + Qt::Key_I);
159 connect(scaleToWidthAction, &QAction::triggered, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionFitWidth); });
160 m_view->connectViewerAction(scaleToWidthAction);
161 m_view->connectPreviewAction(scaleToWidthAction);
162
163 scaleToHeightAction = new QAction(QIcon::fromTheme("zoom-fit-height"), i18n("Scale to Height"), this);
164 actionCollection()->addAction("scaleToHeight", scaleToHeightAction);
165 actionCollection()->setDefaultShortcut(scaleToHeightAction, Qt::CTRL + Qt::Key_H);
166 connect(scaleToHeightAction, &QAction::triggered, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionFitHeight); });
167 m_view->connectViewerAction(scaleToHeightAction);
168 m_view->connectPreviewAction(scaleToHeightAction);
169
170 scaleToOriginalAction = new QAction(QIcon::fromTheme("zoom-original"), i18n("Original Size"), this);
171 actionCollection()->addAction("scaleOriginal", scaleToOriginalAction);
172 actionCollection()->setDefaultShortcut(scaleToOriginalAction, Qt::CTRL + Qt::Key_1);
173 connect(scaleToOriginalAction, &QAction::triggered, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionOrigSize); });
174 m_view->connectViewerAction(scaleToOriginalAction);
175
176 scaleToZoomAction = new QAction(QIcon::fromTheme("page-zoom"), i18n("Set Zoom..."), this);
177 actionCollection()->addAction("showZoomDialog", scaleToZoomAction);
178 // No shortcut. There wasn't a standard shortcut for "Zoom" in KDE4,
179 // and there is no KStandardShortcut::Zoom in KF5.
180 connect(scaleToZoomAction, &QAction::triggered, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionZoom); });
181 m_view->connectViewerAction(scaleToZoomAction);
182
183 keepZoomAction = new KToggleAction(QIcon::fromTheme("lockzoom"), i18n("Keep Zoom Setting"), this);
184 actionCollection()->addAction("keepZoom", keepZoomAction);
185 actionCollection()->setDefaultShortcut(keepZoomAction, Qt::CTRL + Qt::Key_Z);
186 connect(keepZoomAction, &KToggleAction::toggled, m_view->imageViewer(), &ImageCanvas::setKeepZoom);
187 m_view->connectViewerAction(keepZoomAction);
188
189 // Thumb view and gallery actions
190
191 newFromSelectionAction = new QAction(QIcon::fromTheme("transform-crop"), i18n("New Image From Selection"), this);
192 actionCollection()->addAction("createFromSelection", newFromSelectionAction);
193 actionCollection()->setDefaultShortcut(newFromSelectionAction, Qt::CTRL + Qt::Key_N);
194 connect(newFromSelectionAction, SIGNAL(triggered()), m_view, SLOT(slotCreateNewImgFromSelection()));
195
196 mirrorVerticallyAction = new QAction(QIcon::fromTheme("object-flip-vertical"), i18n("Mirror Vertically"), this);
197 mirrorVerticallyAction->setData(ImageTransform::MirrorVertical);
198 actionCollection()->addAction("mirrorVertical", mirrorVerticallyAction);
199 actionCollection()->setDefaultShortcut(mirrorVerticallyAction, Qt::CTRL + Qt::Key_V);
200 connect(mirrorVerticallyAction, SIGNAL(triggered()), m_view, SLOT(slotTransformImage()));
201 m_view->connectViewerAction(mirrorVerticallyAction, true);
202
203 mirrorHorizontallyAction = new QAction(QIcon::fromTheme("object-flip-horizontal"), i18n("Mirror Horizontally"), this);
204 mirrorHorizontallyAction->setData(ImageTransform::MirrorHorizontal);
205 actionCollection()->addAction("mirrorHorizontal", mirrorHorizontallyAction);
206 actionCollection()->setDefaultShortcut(mirrorHorizontallyAction, Qt::CTRL + Qt::Key_M);
207 connect(mirrorHorizontallyAction, SIGNAL(triggered()), m_view, SLOT(slotTransformImage()));
208 m_view->connectViewerAction(mirrorHorizontallyAction);
209
210 // Standard KDE has icons for 'object-rotate-right' and 'object-rotate-left',
211 // but not for rotate by 180 degrees. The 3 used here are copies of the 22x22
212 // icons from the old kdeclassic theme.
213 rotateAcwAction = new QAction(QIcon::fromTheme("rotate-acw"), i18n("Rotate Counter-Clockwise"), this);
214 rotateAcwAction->setData(ImageTransform::Rotate270);
215 actionCollection()->addAction("rotateCounterClockwise", rotateAcwAction);
216 actionCollection()->setDefaultShortcut(rotateAcwAction, Qt::CTRL + Qt::Key_7);
217 connect(rotateAcwAction, SIGNAL(triggered()), m_view, SLOT(slotTransformImage()));
218 m_view->connectViewerAction(rotateAcwAction, true);
219
220 rotateCwAction = new QAction(QIcon::fromTheme("rotate-cw"), i18n("Rotate Clockwise"), this);
221 rotateCwAction->setData(ImageTransform::Rotate90);
222 actionCollection()->addAction("rotateClockwise", rotateCwAction);
223 actionCollection()->setDefaultShortcut(rotateCwAction, Qt::CTRL + Qt::Key_9);
224 connect(rotateCwAction, SIGNAL(triggered()), m_view, SLOT(slotTransformImage()));
225 m_view->connectViewerAction(rotateCwAction);
226
227 rotate180Action = new QAction(QIcon::fromTheme("rotate-180"), i18n("Rotate 180 Degrees"), this);
228 rotate180Action->setData(ImageTransform::Rotate180);
229 actionCollection()->addAction("upsitedown", rotate180Action);
230 actionCollection()->setDefaultShortcut(rotate180Action, Qt::CTRL + Qt::Key_8);
231 connect(rotate180Action, SIGNAL(triggered()), m_view, SLOT(slotTransformImage()));
232 m_view->connectViewerAction(rotate180Action);
233
234 // Gallery actions
235
236 createFolderAction = new QAction(QIcon::fromTheme("folder-new"), i18n("New Folder..."), this);
237 actionCollection()->addAction("foldernew", createFolderAction);
238 connect(createFolderAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotCreateFolder()));
239 m_view->connectGalleryAction(createFolderAction);
240
241 openWithMenu = new KActionMenu(QIcon::fromTheme("document-open"), i18n("Open With"), this);
242 actionCollection()->addAction("openWidth", openWithMenu);
243 connect(openWithMenu->menu(), SIGNAL(aboutToShow()), SLOT(slotOpenWithMenu()));
244 m_view->connectGalleryAction(openWithMenu, true);
245 m_view->connectThumbnailAction(openWithMenu);
246
247 saveImageAction = new QAction(QIcon::fromTheme("document-save"), i18n("Save Image..."), this);
248 actionCollection()->addAction("saveImage", saveImageAction);
249 actionCollection()->setDefaultShortcuts(saveImageAction, KStandardShortcut::save());
250 connect(saveImageAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotExportFile()));
251 m_view->connectGalleryAction(saveImageAction);
252 m_view->connectThumbnailAction(saveImageAction);
253
254 importImageAction = new QAction(QIcon::fromTheme("document-import"), i18n("Import Image..."), this);
255 actionCollection()->addAction("importImage", importImageAction);
256 connect(importImageAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotImportFile()));
257 m_view->connectGalleryAction(importImageAction);
258
259 deleteImageAction = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete Image"), this);
260 actionCollection()->addAction("deleteImage", deleteImageAction);
261 actionCollection()->setDefaultShortcut(deleteImageAction, Qt::SHIFT + Qt::Key_Delete);
262 connect(deleteImageAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotDeleteItems()));
263 m_view->connectGalleryAction(deleteImageAction);
264 m_view->connectThumbnailAction(deleteImageAction);
265
266 renameImageAction = new QAction(QIcon::fromTheme("edit-rename"), i18n("Rename Image"), this);
267 actionCollection()->addAction("renameImage", renameImageAction);
268 actionCollection()->setDefaultShortcut(renameImageAction, Qt::Key_F2);
269 connect(renameImageAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotRenameItems()));
270 m_view->connectGalleryAction(renameImageAction);
271
272 unloadImageAction = new QAction(QIcon::fromTheme("document-close"), i18n("Unload Image"), this);
273 actionCollection()->addAction("unloadImage", unloadImageAction);
274 actionCollection()->setDefaultShortcut(unloadImageAction, Qt::CTRL + Qt::SHIFT + Qt::Key_U);
275 connect(unloadImageAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotUnloadItems()));
276 m_view->connectGalleryAction(unloadImageAction);
277 m_view->connectThumbnailAction(unloadImageAction);
278
279 propsImageAction = new QAction(QIcon::fromTheme("document-properties"), i18n("Properties..."), this);
280 actionCollection()->addAction("propsImage", propsImageAction);
281 actionCollection()->setDefaultShortcut(propsImageAction, Qt::ALT + Qt::Key_Return);
282 connect(propsImageAction, SIGNAL(triggered()), m_view->gallery(), SLOT(slotItemProperties()));
283 m_view->connectGalleryAction(propsImageAction, true);
284 m_view->connectThumbnailAction(propsImageAction);
285
286 // "Settings" menu
287
288 selectDeviceAction = new QAction(QIcon::fromTheme("scanselect"), i18n("Select Scan Device..."), this);
289 actionCollection()->addAction("selectsource", selectDeviceAction);
290 connect(selectDeviceAction, SIGNAL(triggered()), m_view, SLOT(slotSelectDevice()));
291
292 addDeviceAction = new QAction(QIcon::fromTheme("scanadd"), i18n("Add Scan Device..."), this);
293 actionCollection()->addAction("addsource", addDeviceAction);
294 connect(addDeviceAction, SIGNAL(triggered()), m_view, SLOT(slotAddDevice()));
295
296 // Scanning functions
297
298 previewAction = new QAction(QIcon::fromTheme("preview"), i18n("Preview"), this);
299 actionCollection()->addAction("startPreview", previewAction);
300 actionCollection()->setDefaultShortcut(previewAction, Qt::Key_F3);
301 connect(previewAction, SIGNAL(triggered()), m_view, SLOT(slotStartPreview()));
302
303 scanAction = new QAction(QIcon::fromTheme("scan"), i18n("Start Scan"), this);
304 actionCollection()->addAction("startScan", scanAction);
305 actionCollection()->setDefaultShortcut(scanAction, Qt::Key_F4);
306 connect(scanAction, SIGNAL(triggered()), m_view, SLOT(slotStartFinalScan()));
307
308 photocopyAction = new QAction(QIcon::fromTheme("photocopy"), i18n("Photocopy..."), this);
309 actionCollection()->addAction("startPhotoCopy", photocopyAction);
310 actionCollection()->setDefaultShortcut(photocopyAction, Qt::CTRL + Qt::Key_F);
311 connect(photocopyAction, SIGNAL(triggered()), m_view, SLOT(slotStartPhotoCopy()));
312
313 paramsAction = new QAction(QIcon::fromTheme("bookmark-new"), i18n("Scan Parameters..."), this);
314 actionCollection()->addAction("scanparam", paramsAction);
315 actionCollection()->setDefaultShortcut(paramsAction, Qt::CTRL + Qt::SHIFT + Qt::Key_S);
316 connect(paramsAction, SIGNAL(triggered()), m_view, SLOT(slotScanParams()));
317
318 autoselAction = new KToggleAction(QIcon::fromTheme("autoselect"), i18n("Auto Select"), this);
319 actionCollection()->addAction("autoselect", autoselAction);
320 actionCollection()->setDefaultShortcut(autoselAction, Qt::CTRL + Qt::Key_A);
321 connect(autoselAction, SIGNAL(toggled(bool)), m_view, SLOT(slotAutoSelect(bool)));
322 m_view->connectPreviewAction(autoselAction);
323
324 // OCR functions
325
326 ocrAction = new QAction(QIcon::fromTheme("ocr"), i18n("OCR Image..."), this);
327 actionCollection()->addAction("ocrImage", ocrAction);
328 connect(ocrAction, SIGNAL(triggered()), m_view, SLOT(slotStartOcr()));
329
330 ocrSelectAction = new QAction(QIcon::fromTheme("ocr-select"), i18n("OCR Selection..."), this);
331 actionCollection()->addAction("ocrImageSelect", ocrSelectAction);
332 connect(ocrSelectAction, SIGNAL(triggered()), m_view, SLOT(slotStartOcrSelection()));
333
334 m_saveOCRTextAction = new QAction(QIcon::fromTheme("document-save-as"), i18n("Save OCR Result Text..."), this);
335 actionCollection()->addAction("saveOCRResult", m_saveOCRTextAction);
336 actionCollection()->setDefaultShortcut(m_saveOCRTextAction, Qt::CTRL + Qt::Key_U);
337 connect(m_saveOCRTextAction, SIGNAL(triggered()), m_view, SLOT(slotSaveOcrResult()));
338
339 ocrSpellAction = new QAction(QIcon::fromTheme("tools-check-spelling"), i18n("Spell Check OCR Result..."), this);
340 actionCollection()->addAction("ocrSpellCheck", ocrSpellAction);
341 connect(ocrSpellAction, SIGNAL(triggered()), m_view, SLOT(slotOcrSpellCheck()));
342 }
343
closeEvent(QCloseEvent * ev)344 void Kooka::closeEvent(QCloseEvent *ev)
345 {
346 KConfigGroup grp = KSharedConfig::openConfig()->group(autoSaveGroup());
347 saveProperties(grp);
348 if (autoSaveSettings())
349 {
350 saveAutoSaveSettings();
351 m_view->saveWindowSettings(grp);
352 }
353 }
354
saveProperties(KConfigGroup & grp)355 void Kooka::saveProperties(KConfigGroup &grp)
356 {
357 //qDebug() << "to group" << grp.name();
358
359 // The group object points to the session managed
360 // config file. Anything you write here will be available
361 // later when this app is restored.
362
363 KookaSettings::setPreferencesTab(m_prefDialogIndex);
364 //FIXME crash KookaSettings::setStartupSelectedImage(m_view->gallery()->currentImageFileName());
365 KookaSettings::self()->save();
366 }
367
applyMainWindowSettings(const KConfigGroup & grp)368 void Kooka::applyMainWindowSettings(const KConfigGroup &grp)
369 {
370 //qDebug() << "from group" << grp.name();
371 KXmlGuiWindow::applyMainWindowSettings(grp);
372 m_view->applyWindowSettings(grp);
373 }
374
readProperties(const KConfigGroup & grp)375 void Kooka::readProperties(const KConfigGroup &grp)
376 {
377 //qDebug() << "from group" << grp.name();
378
379 // The group object points to the session managed
380 // config file. This function is automatically called whenever
381 // the app is being restored. Read in here whatever you wrote
382 // in 'saveProperties'.
383
384 m_prefDialogIndex = KookaSettings::preferencesTab();
385 }
386
dragEnterEvent(QDragEnterEvent * ev)387 void Kooka::dragEnterEvent(QDragEnterEvent *ev)
388 {
389 if (ev->mimeData()->hasUrls()) ev->accept(); // accept URI drops only
390 }
391
filePrint()392 void Kooka::filePrint()
393 {
394 // this slot is called whenever the File->Print menu is selected,
395 // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
396 // button is clicked
397 m_view->print();
398 }
399
optionsPreferences()400 void Kooka::optionsPreferences()
401 {
402 KookaPref dlg;
403
404 dlg.showPageIndex(m_prefDialogIndex);
405 connect(&dlg, SIGNAL(dataSaved()), m_view, SLOT(slotApplySettings()));
406 if (dlg.exec()) {
407 m_prefDialogIndex = dlg.currentPageIndex();
408 }
409 }
410
optionsOcrPreferences()411 void Kooka::optionsOcrPreferences()
412 {
413 m_prefDialogIndex = 4; // go to OCR page
414 optionsPreferences();
415 }
416
slotUpdateScannerActions(bool haveConnection)417 void Kooka::slotUpdateScannerActions(bool haveConnection)
418 {
419 //qDebug() << "haveConnection" << haveConnection;
420
421 scanAction->setEnabled(haveConnection);
422 previewAction->setEnabled(haveConnection);
423 photocopyAction->setEnabled(haveConnection);
424 paramsAction->setEnabled(haveConnection);
425
426 if (!ScanGlobal::self()->available()) {
427 selectDeviceAction->setEnabled(false);
428 addDeviceAction->setEnabled(false);
429 }
430
431 setCaption(m_view->scannerName());
432 }
433
slotUpdateRectangleActions(bool haveSelection)434 void Kooka::slotUpdateRectangleActions(bool haveSelection)
435 {
436 //qDebug() << "haveSelection" << haveSelection;
437
438 ocrSelectAction->setEnabled(haveSelection);
439 newFromSelectionAction->setEnabled(haveSelection);
440 }
441
442 // This is the most complex action update, depending on the operation
443 // mode (i.e. the tab selected), the gallery selection, and whether the
444 // (two) image viewers have an image loaded. The actions controlled
445 // here and the conditions for enabling them are:
446 //
447 // +========================+==================+======================+
448 // | Action/Operation | Scan mode | Gallery/OCR mode |
449 // +========================+==================+======================+
450 // | scale width/height | preview valid | image loaded |
451 // +------------------------+------------------+----------------------+
452 // | (!GalleryShown && PreviewValid) || (GalleryShown && ImageValid) |
453 // +========================+==================+======================+
454 // | scale original/zoom | no | image loaded |
455 // +------------------------+------------------+----------------------+
456 // | GalleryShown && ImageValid |
457 // +========================+==================+======================+
458 // | keep zoom | no | yes |
459 // +------------------------+------------------+----------------------+
460 // | GalleryShown |
461 // +========================+==================+======================+
462 // | mirror/rotate | no | 1 image |
463 // +------------------------+------------------+----------------------+
464 // | GalleryShown && FileSelected && !IsSubImage && !HasSubImages |
465 // +========================+==================+======================+
466 // | create folder | directory | directory |
467 // +------------------------+------------------+----------------------+
468 // | IsDirectory |
469 // +========================+==================+======================+
470 // | import | no | directory |
471 // +------------------------+------------------+----------------------+
472 // | GalleryShown && IsDirectory |
473 // +========================+==================+======================+
474 // | OCR/print | 1 | 1 |
475 // +------------------------+------------------+----------------------+
476 // | FileSelected && !HasSubImages |
477 // +========================+==================+======================+
478 // | Save | 1 | 1 |
479 // +------------------------+------------------+----------------------+
480 // | FileSelected && !IsSubImage |
481 // +========================+==================+======================+
482 // | unload (dir) | yes | yes |
483 // | unload (not dir) | image loaded | image loaded |
484 // +------------------------+------------------+----------------------+
485 // | IsDirectory | HasSubImages | |
486 // | ((FileSelected | ManySelected) & ImageValid) |
487 // +========================+==================+======================+
488 // | delete (dir) | 1 not root | 1 not root |
489 // | delete (not dir) | >1 | >1 |
490 // +------------------------+------------------+----------------------+
491 // | (IsDirectory & !RootSelected) | ((FileSelected | ManySelected) |
492 // | & !IsSubImage |
493 // +========================+==================+======================+
494 // | rename (dir) | not root | not root |
495 // | rename (not dir) | 1 image | 1 image |
496 // +------------------------+------------------+----------------------+
497 // | (IsDirectory & !RootSelected) | (FileSelected & !IsSubImage) |
498 // +========================+==================+======================+
499 // | props (dir) | yes | yes |
500 // | props (not dir) | 1 image | 1 image |
501 // +------------------------+------------------+----------------------+
502 // | IsDirectory | FileSelected |
503 // +========================+==================+======================+
504 // | Open with | yes | not subimage |
505 // +------------------------+------------------+----------------------+
506 // | !IsSubImage |
507 // +==================================================================+
508 //
509 // It is assumed that only one directory may be selected at a time in
510 // the gallery, but multiple files/images may be. Currently, though,
511 // the Kooka gallery allows single selection only.
512 //
513 // The source of the 'state' is KookaView::updateSelectionState().
514
slotUpdateViewActions(KookaView::StateFlags state)515 void Kooka::slotUpdateViewActions(KookaView::StateFlags state)
516 {
517 //qDebug() << "state" << hex << state;
518
519 bool e;
520
521 e = (!(state & KookaView::GalleryShown) && (state & KookaView::PreviewValid)) ||
522 ((state & KookaView::GalleryShown) && (state & KookaView::ImageValid));
523 scaleToWidthAction->setEnabled(e);
524 scaleToHeightAction->setEnabled(e);
525
526 e = (state & KookaView::GalleryShown) && (state & KookaView::ImageValid);
527 scaleToOriginalAction->setEnabled(e);
528 scaleToZoomAction->setEnabled(e);
529
530 e = (state & KookaView::GalleryShown);
531 keepZoomAction->setEnabled(e);
532
533 e = (state & KookaView::GalleryShown) && (state & KookaView::FileSelected) && !(state & (KookaView::IsSubImage|KookaView::HasSubImages));
534 m_imageChangeAllowed = e;
535 mirrorVerticallyAction->setEnabled(e);
536 mirrorHorizontallyAction->setEnabled(e);
537 rotateCwAction->setEnabled(e);
538 rotateAcwAction->setEnabled(e);
539 rotate180Action->setEnabled(e);
540
541 e = (state & KookaView::IsDirectory);
542 createFolderAction->setEnabled(e);
543
544 e = (state & KookaView::GalleryShown) && (state & KookaView::IsDirectory);
545 importImageAction->setEnabled(e);
546
547 e = (state & KookaView::FileSelected) && !(state & KookaView::HasSubImages);
548 ocrAction->setEnabled(e);
549 printImageAction->setEnabled(e);
550
551 // TODO: allow this for sub-images (page extraction)
552 e = (state & KookaView::FileSelected) && !(state & KookaView::IsSubImage);
553 saveImageAction->setEnabled(e);
554
555 if (state & KookaView::IsDirectory) {
556 unloadImageAction->setText(i18n("Unload Folder"));
557 deleteImageAction->setText(i18n("Delete Folder"));
558 renameImageAction->setText(i18n("Rename Folder"));
559
560 unloadImageAction->setEnabled(true);
561
562 e = !(state & KookaView::RootSelected);
563 deleteImageAction->setEnabled(e);
564 renameImageAction->setEnabled(e);
565
566 propsImageAction->setEnabled(true);
567 } else {
568 unloadImageAction->setText(i18n("Unload Image"));
569 deleteImageAction->setText(i18n("Delete Image"));
570 renameImageAction->setText(i18n("Rename Image"));
571
572 e = ((state & (KookaView::FileSelected | KookaView::ManySelected)) &&
573 (state & KookaView::ImageValid)) || (state & KookaView::HasSubImages);
574 unloadImageAction->setEnabled(e);
575
576 e = (state & (KookaView::FileSelected | KookaView::ManySelected)) && !(state & KookaView::IsSubImage);
577 deleteImageAction->setEnabled(e);
578
579 e = (state & KookaView::FileSelected) && !(state & KookaView::IsSubImage);
580 renameImageAction->setEnabled(e);
581 propsImageAction->setEnabled(e);
582 }
583
584 // TODO: allow this for sub-images
585 openWithMenu->setEnabled(!(state & KookaView::IsSubImage));
586
587 if (!(state & (KookaView::IsDirectory | KookaView::FileSelected | KookaView::ManySelected))) {
588 slotUpdateRectangleActions(false);
589 }
590 }
591
slotUpdateOcrResultActions(bool haveText)592 void Kooka::slotUpdateOcrResultActions(bool haveText)
593 {
594 //qDebug() << "haveText" << haveText;
595 m_saveOCRTextAction->setEnabled(haveText);
596 ocrSpellAction->setEnabled(haveText);
597 }
598
slotUpdateReadOnlyActions(bool ro)599 void Kooka::slotUpdateReadOnlyActions(bool ro)
600 {
601 bool enable = (m_imageChangeAllowed && !ro); // also check gallery state
602
603 mirrorVerticallyAction->setEnabled(enable);
604 mirrorHorizontallyAction->setEnabled(enable);
605 rotateCwAction->setEnabled(enable);
606 rotateAcwAction->setEnabled(enable);
607 rotate180Action->setEnabled(enable);
608 }
609
slotUpdateAutoSelectActions(bool isAvailable,bool isOn)610 void Kooka::slotUpdateAutoSelectActions(bool isAvailable, bool isOn)
611 {
612 //qDebug() << "available" << isAvailable << "on" << isOn;
613
614 autoselAction->setEnabled(isAvailable);
615 autoselAction->setChecked(isOn);
616 }
617
slotOpenWithMenu()618 void Kooka::slotOpenWithMenu()
619 {
620 m_view->showOpenWithMenu(openWithMenu);
621 }
622