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

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) 2000-2016 Klaas Freitag <freitag@suse.de>     *
0007  *                          Jonathan Marten <jjm@keelhaul.me.uk>    *
0008  *                                  *
0009  *  Kooka is free software; you can redistribute it and/or modify it    *
0010  *  under the terms of the GNU Library General Public License as    *
0011  *  published by the Free Software Foundation and appearing in the  *
0012  *  file COPYING included in the packaging of this file;  either    *
0013  *  version 2 of the License, or (at your option) any later version.    *
0014  *                                  *
0015  *  As a special exception, permission is given to link this program    *
0016  *  with any version of the KADMOS OCR/ICR engine (a product of     *
0017  *  reRecognition GmbH, Kreuzlingen), and distribute the resulting  *
0018  *  executable without including the source code for KADMOS in the  *
0019  *  source distribution.                        *
0020  *                                  *
0021  *  This program is distributed in the hope that it will be useful, *
0022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  *
0023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
0024  *  GNU General Public License for more details.            *
0025  *                                  *
0026  *  You should have received a copy of the GNU General Public       *
0027  *  License along with this program;  see the file COPYING.  If     *
0028  *  not, see <http://www.gnu.org/licenses/>.                *
0029  *                                  *
0030  ************************************************************************/
0031 
0032 #include "kooka.h"
0033 
0034 #include <qevent.h>
0035 #include <qaction.h>
0036 #include <qicon.h>
0037 #include <qmenu.h>
0038 #include <qlabel.h>
0039 #include <qmimedata.h>
0040 
0041 #include <klocalizedstring.h>
0042 #include <ktoggleaction.h>
0043 #include <kactionmenu.h>
0044 #include <kiconloader.h>
0045 #include <kmessagebox.h>
0046 #include <kstandardaction.h>
0047 #include <kactioncollection.h>
0048 #include <kxmlguiwindow.h>
0049 
0050 #include "scanglobal.h"
0051 #include "imagecanvas.h"
0052 #include "previewer.h"
0053 
0054 #include "scangallery.h"
0055 #include "kookapref.h"
0056 #include "kookasettings.h"
0057 #include "kookaview.h"
0058 #include "imagetransform.h"
0059 #include "kooka_logging.h"
0060 
0061 
0062 Kooka::Kooka(const QByteArray &deviceToUse)
0063     : KXmlGuiWindow(nullptr),
0064       m_prefDialogIndex(0)
0065 {
0066     setObjectName("Kooka");
0067 
0068     // Set up the status bar
0069     StatusBarManager *sbm = new StatusBarManager(this);
0070 
0071     /* Start to create the main view framework */
0072     m_view = new KookaView(this, deviceToUse);
0073     setCentralWidget(m_view);
0074 
0075     setAcceptDrops(false); // Waba: Not (yet?) supported
0076 
0077     readProperties(KSharedConfig::openConfig()->group(autoSaveGroup()));
0078 
0079     // then, setup our actions
0080     setupActions();
0081 
0082     setupGUI(KXmlGuiWindow::Default, "kookaui.rc");
0083     setAutoSaveSettings();              // default group, do save
0084 
0085     // Allow the view to change the status bar and caption
0086     connect(m_view, &KookaView::changeStatus, sbm, &StatusBarManager::setStatus);
0087     connect(m_view, &KookaView::clearStatus, sbm, &StatusBarManager::clearStatus);
0088     connect(m_view, &KookaView::signalChangeCaption, this, QOverload<const QString &>::of(&KMainWindow::setCaption));
0089     connect(m_view, &KookaView::signalScannerChanged, this, &Kooka::slotUpdateScannerActions);
0090     connect(m_view, &KookaView::signalRectangleChanged, this, &Kooka::slotUpdateRectangleActions);
0091     connect(m_view, &KookaView::signalViewSelectionState, this, &Kooka::slotUpdateViewActions);
0092     connect(m_view, &KookaView::signalOcrResultAvailable, this, &Kooka::slotUpdateOcrResultActions);
0093     connect(m_view, &KookaView::signalOcrPrefs, this, &Kooka::optionsOcrPreferences);
0094 
0095     connect(m_view->imageViewer(), &ImageCanvas::imageReadOnly, this, &Kooka::slotUpdateReadOnlyActions);
0096 
0097     connect(m_view->previewer(), &Previewer::autoSelectStateChanged, this, &Kooka::slotUpdateAutoSelectActions);
0098     connect(m_view->previewer(), &Previewer::previewFileSizeChanged, sbm, &StatusBarManager::setFileSize);
0099 
0100     setCaption(i18n("KDE Scanning"));
0101 
0102     slotUpdateScannerActions(m_view->isScannerConnected());
0103     slotUpdateRectangleActions(false);
0104     slotUpdateViewActions(KookaView::GalleryShown | KookaView::IsDirectory | KookaView::RootSelected);
0105     slotUpdateOcrResultActions(false);
0106     slotUpdateReadOnlyActions(true);
0107 }
0108 
0109 Kooka::~Kooka()
0110 {
0111     m_view->closeScanDevice();
0112     delete m_view;                  // ensure its config saved
0113 }
0114 
0115 void Kooka::startup()
0116 {
0117     if (m_view == nullptr) return;
0118 
0119     qCDebug(KOOKA_LOG);
0120     m_view->gallery()->openRoots();
0121     m_view->loadStartupImage();
0122 }
0123 
0124 
0125 void Kooka::setupActions()
0126 {
0127     printImageAction = KStandardAction::print(this, &Kooka::filePrint, actionCollection());
0128 
0129     KStandardAction::quit(this, &QWidget::close, actionCollection());
0130     KStandardAction::preferences(this, &Kooka::optionsPreferences, actionCollection());
0131 
0132     // Image Viewer
0133 
0134     scaleToWidthAction = new QAction(QIcon::fromTheme("zoom-fit-width"), i18n("Scale to Width"), this);
0135     actionCollection()->addAction("scaleToWidth", scaleToWidthAction);
0136     // Use the traditional Kooka shortcut if no standard shortcut is
0137     // defined by KStandardShortcut.
0138     QList<QKeySequence> shortcuts = KStandardShortcut::shortcut(KStandardShortcut::FitToWidth);
0139     if (shortcuts.isEmpty()) shortcuts.append(Qt::CTRL + Qt::Key_I);
0140     actionCollection()->setDefaultShortcuts(scaleToWidthAction, shortcuts);
0141     connect(scaleToWidthAction, &QAction::triggered, this, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionFitWidth); });
0142     m_view->connectViewerAction(scaleToWidthAction);
0143     m_view->connectPreviewAction(scaleToWidthAction);
0144 
0145     scaleToHeightAction = new QAction(QIcon::fromTheme("zoom-fit-height"), i18n("Scale to Height"), this);
0146     actionCollection()->addAction("scaleToHeight", scaleToHeightAction);
0147     shortcuts = KStandardShortcut::shortcut(KStandardShortcut::FitToHeight);
0148     if (shortcuts.isEmpty()) shortcuts.append(Qt::CTRL + Qt::Key_H);
0149     actionCollection()->setDefaultShortcuts(scaleToHeightAction, shortcuts);
0150     connect(scaleToHeightAction, &QAction::triggered, this, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionFitHeight); });
0151     m_view->connectViewerAction(scaleToHeightAction);
0152     m_view->connectPreviewAction(scaleToHeightAction);
0153 
0154     scaleToOriginalAction = new QAction(QIcon::fromTheme("zoom-original"), i18n("Original Size"), this);
0155     actionCollection()->addAction("scaleOriginal", scaleToOriginalAction);
0156     actionCollection()->setDefaultShortcuts(scaleToOriginalAction, KStandardShortcut::shortcut(KStandardShortcut::ActualSize));
0157     connect(scaleToOriginalAction, &QAction::triggered, this, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionOrigSize); });
0158     m_view->connectViewerAction(scaleToOriginalAction);
0159 
0160     scaleToZoomAction = new QAction(QIcon::fromTheme("page-zoom"), i18n("Set Zoom..."), this);
0161     actionCollection()->addAction("showZoomDialog", scaleToZoomAction);
0162     actionCollection()->setDefaultShortcuts(scaleToZoomAction, KStandardShortcut::shortcut(KStandardShortcut::Zoom));
0163     connect(scaleToZoomAction, &QAction::triggered, this, [=]() { m_view->imageViewerAction(ImageCanvas::UserActionZoom); });
0164     m_view->connectViewerAction(scaleToZoomAction);
0165 
0166     keepZoomAction = new KToggleAction(QIcon::fromTheme("lockzoom"), i18n("Keep Zoom Setting"), this);
0167     actionCollection()->addAction("keepZoom", keepZoomAction);
0168     actionCollection()->setDefaultShortcut(keepZoomAction, Qt::CTRL + Qt::Key_Z);
0169     connect(keepZoomAction, &KToggleAction::toggled, m_view->imageViewer(), &ImageCanvas::setKeepZoom);
0170     m_view->connectViewerAction(keepZoomAction);
0171 
0172     // Thumb view and gallery actions
0173 
0174     newFromSelectionAction = new QAction(QIcon::fromTheme("transform-crop"), i18n("New Image From Selection"), this);
0175     actionCollection()->addAction("createFromSelection", newFromSelectionAction);
0176     actionCollection()->setDefaultShortcut(newFromSelectionAction, Qt::CTRL + Qt::Key_N);
0177     connect(newFromSelectionAction, &QAction::triggered, m_view, &KookaView::slotCreateNewImgFromSelection);
0178 
0179     mirrorVerticallyAction = new QAction(QIcon::fromTheme("object-flip-vertical"), i18n("Mirror Vertically"), this);
0180     mirrorVerticallyAction->setData(ImageTransform::MirrorVertical);
0181     actionCollection()->addAction("mirrorVertical", mirrorVerticallyAction);
0182     actionCollection()->setDefaultShortcut(mirrorVerticallyAction, Qt::CTRL + Qt::Key_V);
0183     connect(mirrorVerticallyAction, &QAction::triggered, m_view, &KookaView::slotTransformImage);
0184     m_view->connectViewerAction(mirrorVerticallyAction, true);
0185 
0186     mirrorHorizontallyAction = new QAction(QIcon::fromTheme("object-flip-horizontal"), i18n("Mirror Horizontally"), this);
0187     mirrorHorizontallyAction->setData(ImageTransform::MirrorHorizontal);
0188     actionCollection()->addAction("mirrorHorizontal", mirrorHorizontallyAction);
0189     actionCollection()->setDefaultShortcut(mirrorHorizontallyAction, Qt::CTRL + Qt::Key_M);
0190     connect(mirrorHorizontallyAction, &QAction::triggered, m_view, &KookaView::slotTransformImage);
0191     m_view->connectViewerAction(mirrorHorizontallyAction);
0192 
0193     // Standard KDE has icons for 'object-rotate-right' and 'object-rotate-left',
0194     // but not for rotate by 180 degrees.  The 3 used here are copies of the 22x22
0195     // icons from the old kdeclassic theme.
0196     rotateAcwAction = new QAction(QIcon::fromTheme("rotate-acw"), i18n("Rotate Counter-Clockwise"), this);
0197     rotateAcwAction->setData(ImageTransform::Rotate270);
0198     actionCollection()->addAction("rotateCounterClockwise", rotateAcwAction);
0199     actionCollection()->setDefaultShortcut(rotateAcwAction, Qt::CTRL + Qt::Key_7);
0200     connect(rotateAcwAction, &QAction::triggered, m_view, &KookaView::slotTransformImage);
0201     m_view->connectViewerAction(rotateAcwAction, true);
0202 
0203     rotateCwAction = new QAction(QIcon::fromTheme("rotate-cw"), i18n("Rotate Clockwise"), this);
0204     rotateCwAction->setData(ImageTransform::Rotate90);
0205     actionCollection()->addAction("rotateClockwise", rotateCwAction);
0206     actionCollection()->setDefaultShortcut(rotateCwAction, Qt::CTRL + Qt::Key_9);
0207     connect(rotateCwAction, &QAction::triggered, m_view, &KookaView::slotTransformImage);
0208     m_view->connectViewerAction(rotateCwAction);
0209 
0210     rotate180Action = new QAction(QIcon::fromTheme("rotate-180"), i18n("Rotate 180 Degrees"), this);
0211     rotate180Action->setData(ImageTransform::Rotate180);
0212     actionCollection()->addAction("upsitedown", rotate180Action);
0213     actionCollection()->setDefaultShortcut(rotate180Action, Qt::CTRL + Qt::Key_8);
0214     connect(rotate180Action, &QAction::triggered, m_view, &KookaView::slotTransformImage);
0215     m_view->connectViewerAction(rotate180Action);
0216 
0217     // Gallery actions
0218 
0219     createFolderAction = new QAction(QIcon::fromTheme("folder-new"), i18n("New Folder..."), this);
0220     actionCollection()->addAction("foldernew", createFolderAction);
0221     connect(createFolderAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotCreateFolder);
0222     m_view->connectGalleryAction(createFolderAction);
0223 
0224     openWithMenu = new KActionMenu(QIcon::fromTheme("document-open"), i18n("Open With"), this);
0225     actionCollection()->addAction("openWidth", openWithMenu);
0226     connect(openWithMenu->menu(), &QMenu::aboutToShow, this, &Kooka::slotOpenWithMenu);
0227     m_view->connectGalleryAction(openWithMenu, true);
0228     m_view->connectThumbnailAction(openWithMenu);
0229 
0230     saveImageAction = new QAction(QIcon::fromTheme("document-save"), i18n("Save Image..."), this);
0231     actionCollection()->addAction("saveImage", saveImageAction);
0232     actionCollection()->setDefaultShortcuts(saveImageAction, KStandardShortcut::save());
0233     connect(saveImageAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotExportFile);
0234     m_view->connectGalleryAction(saveImageAction);
0235     m_view->connectThumbnailAction(saveImageAction);
0236 
0237     importImageAction = new QAction(QIcon::fromTheme("document-import"), i18n("Import Image..."), this);
0238     actionCollection()->addAction("importImage", importImageAction);
0239     connect(importImageAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotImportFile);
0240     m_view->connectGalleryAction(importImageAction);
0241 
0242     deleteImageAction = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete Image"), this);
0243     actionCollection()->addAction("deleteImage", deleteImageAction);
0244     actionCollection()->setDefaultShortcuts(deleteImageAction, KStandardShortcut::deleteFile());
0245     connect(deleteImageAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotDeleteItems);
0246     m_view->connectGalleryAction(deleteImageAction);
0247     m_view->connectThumbnailAction(deleteImageAction);
0248 
0249     renameImageAction = new QAction(QIcon::fromTheme("edit-rename"), i18n("Rename Image"), this);
0250     actionCollection()->addAction("renameImage", renameImageAction);
0251     actionCollection()->setDefaultShortcuts(renameImageAction, KStandardShortcut::renameFile());
0252     connect(renameImageAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotRenameItems);
0253     m_view->connectGalleryAction(renameImageAction);
0254 
0255     unloadImageAction = new QAction(QIcon::fromTheme("document-close"), i18n("Unload Image"), this);
0256     actionCollection()->addAction("unloadImage", unloadImageAction);
0257     actionCollection()->setDefaultShortcut(unloadImageAction, Qt::CTRL + Qt::SHIFT + Qt::Key_U);
0258     connect(unloadImageAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotUnloadItems);
0259     m_view->connectGalleryAction(unloadImageAction);
0260     m_view->connectThumbnailAction(unloadImageAction);
0261 
0262     propsImageAction = new QAction(QIcon::fromTheme("document-properties"), i18n("Properties..."), this);
0263     actionCollection()->addAction("propsImage", propsImageAction);
0264     actionCollection()->setDefaultShortcut(propsImageAction, Qt::ALT + Qt::Key_Return);
0265     connect(propsImageAction, &QAction::triggered, m_view->gallery(), &ScanGallery::slotItemProperties);
0266     m_view->connectGalleryAction(propsImageAction, true);
0267     m_view->connectThumbnailAction(propsImageAction);
0268 
0269     // "Settings" menu
0270 
0271     selectDeviceAction = new QAction(QIcon::fromTheme("scanselect"), i18n("Select Scan Device..."), this);
0272     actionCollection()->addAction("selectsource", selectDeviceAction);
0273     connect(selectDeviceAction, &QAction::triggered, m_view, [this](){ m_view->slotSelectDevice(); });
0274 
0275     addDeviceAction = new QAction(QIcon::fromTheme("scanadd"), i18n("Add Scan Device..."), this);
0276     actionCollection()->addAction("addsource", addDeviceAction);
0277     connect(addDeviceAction, &QAction::triggered, m_view, &KookaView::slotAddDevice);
0278 
0279     // Scanning functions
0280 
0281     previewAction = new QAction(QIcon::fromTheme("preview"), i18n("Preview"), this);
0282     actionCollection()->addAction("startPreview", previewAction);
0283     actionCollection()->setDefaultShortcut(previewAction, Qt::Key_F3);
0284     connect(previewAction, &QAction::triggered, m_view, &KookaView::slotStartPreview);
0285 
0286     scanAction = new QAction(QIcon::fromTheme("scan"), i18n("Start Scan"), this);
0287     actionCollection()->addAction("startScan", scanAction);
0288     actionCollection()->setDefaultShortcut(scanAction, Qt::Key_F4);
0289     connect(scanAction, &QAction::triggered, m_view, &KookaView::slotStartFinalScan);
0290 
0291     paramsAction = new QAction(QIcon::fromTheme("bookmark-new"), i18n("Scan Presets..."), this);
0292     actionCollection()->addAction("scanparam", paramsAction);
0293     actionCollection()->setDefaultShortcut(paramsAction, Qt::CTRL + Qt::SHIFT + Qt::Key_S);
0294     connect(paramsAction, &QAction::triggered, m_view, &KookaView::slotScanParams);
0295 
0296     autoselAction = new KToggleAction(QIcon::fromTheme("autoselect"), i18n("Auto Select"), this);
0297     actionCollection()->addAction("autoselect", autoselAction);
0298     actionCollection()->setDefaultShortcut(autoselAction, Qt::CTRL + Qt::Key_A);
0299     connect(autoselAction, &QAction::toggled, m_view, &KookaView::slotAutoSelect);
0300     m_view->connectPreviewAction(autoselAction);
0301 
0302     // OCR functions
0303 
0304     ocrAction = new QAction(QIcon::fromTheme("ocr"), i18n("OCR Image..."), this);
0305     actionCollection()->addAction("ocrImage", ocrAction);
0306     connect(ocrAction, &QAction::triggered, m_view, &KookaView::slotStartOcr);
0307 
0308     ocrSelectAction = new QAction(QIcon::fromTheme("ocr-select"), i18n("OCR Selection..."), this);
0309     actionCollection()->addAction("ocrImageSelect", ocrSelectAction);
0310     connect(ocrSelectAction, &QAction::triggered, m_view, &KookaView::slotStartOcrSelection);
0311 
0312     QAction *ocrFileAction = new QAction(QIcon::fromTheme("ocr-file"), i18n("OCR File..."), this);
0313     actionCollection()->addAction("ocrFile", ocrFileAction);
0314     connect(ocrFileAction, &QAction::triggered, m_view, &KookaView::slotStartOcrFile);
0315 
0316     m_saveOCRTextAction = new QAction(QIcon::fromTheme("document-save-as"), i18n("Save OCR Result Text..."), this);
0317     actionCollection()->addAction("saveOCRResult", m_saveOCRTextAction);
0318     actionCollection()->setDefaultShortcut(m_saveOCRTextAction, Qt::CTRL + Qt::Key_U);
0319     connect(m_saveOCRTextAction, &QAction::triggered, m_view, &KookaView::slotSaveOcrResult);
0320 
0321     ocrSpellAction = new QAction(QIcon::fromTheme("tools-check-spelling"), i18n("Spell Check OCR Result..."), this);
0322     actionCollection()->addAction("ocrSpellCheck", ocrSpellAction);
0323     connect(ocrSpellAction, &QAction::triggered, m_view, [this](){ m_view->slotOcrSpellCheck(); });
0324 }
0325 
0326 void Kooka::closeEvent(QCloseEvent *ev)
0327 {
0328     KConfigGroup grp = KSharedConfig::openConfig()->group(autoSaveGroup());
0329     saveProperties(grp);
0330     if (autoSaveSettings())
0331     {
0332         saveAutoSaveSettings();
0333         m_view->saveWindowSettings(grp);
0334     }
0335 }
0336 
0337 void Kooka::saveProperties(KConfigGroup &grp)
0338 {
0339     qCDebug(KOOKA_LOG) << "to group" << grp.name();
0340 
0341     // The group object points to the session managed
0342     // config file.  Anything you write here will be available
0343     // later when this app is restored.
0344 
0345     KookaSettings::setPreferencesTab(m_prefDialogIndex);
0346     //FIXME crash KookaSettings::setStartupSelectedImage(m_view->gallery()->currentImageFileName());
0347     KookaSettings::self()->save();
0348 }
0349 
0350 void Kooka::applyMainWindowSettings(const KConfigGroup &grp)
0351 {
0352     qCDebug(KOOKA_LOG) << "from group" << grp.name();
0353     KXmlGuiWindow::applyMainWindowSettings(grp);
0354     m_view->applyWindowSettings(grp);
0355 }
0356 
0357 void Kooka::readProperties(const KConfigGroup &grp)
0358 {
0359     qCDebug(KOOKA_LOG) << "from group" << grp.name();
0360 
0361     // The group object points to the session managed
0362     // config file.  This function is automatically called whenever
0363     // the app is being restored.  Read in here whatever you wrote
0364     // in 'saveProperties'.
0365 
0366     m_prefDialogIndex = KookaSettings::preferencesTab();
0367 }
0368 
0369 void Kooka::dragEnterEvent(QDragEnterEvent *ev)
0370 {
0371     if (ev->mimeData()->hasUrls()) ev->accept();    // accept URI drops only
0372 }
0373 
0374 void Kooka::filePrint()
0375 {
0376     // this slot is called whenever the File->Print menu is selected,
0377     // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
0378     // button is clicked
0379     m_view->print();
0380 }
0381 
0382 
0383 void Kooka::optionsPreferences()
0384 {
0385     KookaPref dlg;
0386 
0387     dlg.showPageIndex(m_prefDialogIndex);
0388     connect(&dlg, &KookaPref::dataSaved, m_view, &KookaView::slotApplySettings);
0389     if (dlg.exec()) m_prefDialogIndex = dlg.currentPageIndex();
0390 }
0391 
0392 
0393 void Kooka::optionsOcrPreferences()
0394 {
0395     m_prefDialogIndex = 4;              // go to OCR page
0396     optionsPreferences();
0397 }
0398 
0399 void Kooka::slotUpdateScannerActions(bool haveConnection)
0400 {
0401     qCDebug(KOOKA_LOG) << "haveConnection" << haveConnection;
0402 
0403     scanAction->setEnabled(haveConnection);
0404     previewAction->setEnabled(haveConnection);
0405     paramsAction->setEnabled(haveConnection);
0406 
0407     if (!ScanGlobal::self()->available()) {
0408         selectDeviceAction->setEnabled(false);
0409         addDeviceAction->setEnabled(false);
0410     }
0411 
0412     setCaption(m_view->scannerName());
0413 }
0414 
0415 void Kooka::slotUpdateRectangleActions(bool haveSelection)
0416 {
0417     qCDebug(KOOKA_LOG) << "haveSelection" << haveSelection;
0418 
0419     ocrSelectAction->setEnabled(haveSelection);
0420     newFromSelectionAction->setEnabled(haveSelection);
0421 }
0422 
0423 //  This is the most complex action update, depending on the operation
0424 //  mode (i.e. the tab selected), the gallery selection, and whether the
0425 //  (two) image viewers have an image loaded.  The actions controlled
0426 //  here and the conditions for enabling them are:
0427 //
0428 //  +========================+==================+======================+
0429 //  | Action/Operation       | Scan mode        | Gallery/OCR mode     |
0430 //  +========================+==================+======================+
0431 //  | scale width/height     | preview valid    | image loaded         |
0432 //  +------------------------+------------------+----------------------+
0433 //  | (!GalleryShown && PreviewValid) || (GalleryShown && ImageValid)  |
0434 //  +========================+==================+======================+
0435 //  | scale original/zoom    | no               | image loaded         |
0436 //  +------------------------+------------------+----------------------+
0437 //  | GalleryShown && ImageValid                                       |
0438 //  +========================+==================+======================+
0439 //  | keep zoom              | no               | yes                  |
0440 //  +------------------------+------------------+----------------------+
0441 //  | GalleryShown                                                     |
0442 //  +========================+==================+======================+
0443 //  | mirror/rotate          | no               | 1 image              |
0444 //  +------------------------+------------------+----------------------+
0445 //  | GalleryShown && FileSelected && !IsSubImage && !HasSubImages     |
0446 //  +========================+==================+======================+
0447 //  | create folder          | directory        | directory            |
0448 //  +------------------------+------------------+----------------------+
0449 //  | IsDirectory                                                      |
0450 //  +========================+==================+======================+
0451 //  | import                 | no               | directory            |
0452 //  +------------------------+------------------+----------------------+
0453 //  | GalleryShown && IsDirectory                                      |
0454 //  +========================+==================+======================+
0455 //  | OCR/print              | 1                | 1                    |
0456 //  +------------------------+------------------+----------------------+
0457 //  | FileSelected && !HasSubImages                                    |
0458 //  +========================+==================+======================+
0459 //  | Save                   | 1                | 1                    |
0460 //  +------------------------+------------------+----------------------+
0461 //  | FileSelected && !IsSubImage                                      |
0462 //  +========================+==================+======================+
0463 //  | unload (dir)           | yes              | yes                  |
0464 //  | unload (not dir)       | image loaded     | image loaded         |
0465 //  +------------------------+------------------+----------------------+
0466 //  | IsDirectory | HasSubImages |                                     |
0467 //  |                    ((FileSelected | ManySelected) & ImageValid)  |
0468 //  +========================+==================+======================+
0469 //  | delete (dir)           | 1 not root       | 1 not root           |
0470 //  | delete (not dir)       | >1               | >1                   |
0471 //  +------------------------+------------------+----------------------+
0472 //  | (IsDirectory & !RootSelected) | ((FileSelected | ManySelected)   |
0473 //  |                                                   & !IsSubImage  |
0474 //  +========================+==================+======================+
0475 //  | rename (dir)           | not root         | not root             |
0476 //  | rename (not dir)       | 1 image          | 1 image              |
0477 //  +------------------------+------------------+----------------------+
0478 //  | (IsDirectory & !RootSelected) | (FileSelected & !IsSubImage)     |
0479 //  +========================+==================+======================+
0480 //  | props (dir)            | yes              | yes                  |
0481 //  | props (not dir)        | 1 image          | 1 image              |
0482 //  +------------------------+------------------+----------------------+
0483 //  | IsDirectory | FileSelected                                       |
0484 //  +========================+==================+======================+
0485 //  | Open with              | yes              | not subimage         |
0486 //  +------------------------+------------------+----------------------+
0487 //  | !IsSubImage                                                      |
0488 //  +==================================================================+
0489 //
0490 //  It is assumed that only one directory may be selected at a time in
0491 //  the gallery, but multiple files/images may be.  Currently, though,
0492 //  the Kooka gallery allows single selection only.
0493 //
0494 //  The source of the 'state' is KookaView::updateSelectionState().
0495 
0496 void Kooka::slotUpdateViewActions(KookaView::StateFlags state)
0497 {
0498     qCDebug(KOOKA_LOG) << "state" << Qt::hex << state;
0499 
0500     bool e;
0501 
0502     e = (!(state & KookaView::GalleryShown) && (state & KookaView::PreviewValid)) ||
0503         ((state & KookaView::GalleryShown) && (state & KookaView::ImageValid));
0504     scaleToWidthAction->setEnabled(e);
0505     scaleToHeightAction->setEnabled(e);
0506 
0507     e = (state & KookaView::GalleryShown) && (state & KookaView::ImageValid);
0508     scaleToOriginalAction->setEnabled(e);
0509     scaleToZoomAction->setEnabled(e);
0510 
0511     e = (state & KookaView::GalleryShown);
0512     keepZoomAction->setEnabled(e);
0513 
0514     e = (state & KookaView::GalleryShown) && (state & KookaView::FileSelected) && !(state & (KookaView::IsSubImage|KookaView::HasSubImages));
0515     m_imageChangeAllowed = e;
0516     mirrorVerticallyAction->setEnabled(e);
0517     mirrorHorizontallyAction->setEnabled(e);
0518     rotateCwAction->setEnabled(e);
0519     rotateAcwAction->setEnabled(e);
0520     rotate180Action->setEnabled(e);
0521 
0522     e = (state & KookaView::IsDirectory);
0523     createFolderAction->setEnabled(e);
0524 
0525     e = (state & KookaView::GalleryShown) && (state & KookaView::IsDirectory);
0526     importImageAction->setEnabled(e);
0527 
0528     e = (state & KookaView::FileSelected) && !(state & KookaView::HasSubImages);
0529     ocrAction->setEnabled(e);
0530     printImageAction->setEnabled(e);
0531 
0532     // TODO: allow this for sub-images (page extraction)
0533     e = (state & KookaView::FileSelected) && !(state & KookaView::IsSubImage);
0534     saveImageAction->setEnabled(e);
0535 
0536     if (state & KookaView::IsDirectory) {
0537         unloadImageAction->setText(i18n("Unload Folder"));
0538         deleteImageAction->setText(i18n("Delete Folder"));
0539         renameImageAction->setText(i18n("Rename Folder"));
0540 
0541         unloadImageAction->setEnabled(true);
0542 
0543         e = !(state & KookaView::RootSelected);
0544         deleteImageAction->setEnabled(e);
0545         renameImageAction->setEnabled(e);
0546 
0547         propsImageAction->setEnabled(true);
0548     } else {
0549         unloadImageAction->setText(i18n("Unload Image"));
0550         deleteImageAction->setText(i18n("Delete Image"));
0551         renameImageAction->setText(i18n("Rename Image"));
0552 
0553         e = ((state & (KookaView::FileSelected | KookaView::ManySelected)) &&
0554             (state & KookaView::ImageValid)) || (state & KookaView::HasSubImages);
0555         unloadImageAction->setEnabled(e);
0556 
0557         e = (state & (KookaView::FileSelected | KookaView::ManySelected)) && !(state & KookaView::IsSubImage);
0558         deleteImageAction->setEnabled(e);
0559 
0560         e = (state & KookaView::FileSelected) && !(state & KookaView::IsSubImage);
0561         renameImageAction->setEnabled(e);
0562         propsImageAction->setEnabled(e);
0563     }
0564 
0565     // TODO: allow this for sub-images
0566     openWithMenu->setEnabled(!(state & KookaView::IsSubImage));
0567 
0568     if (!(state & (KookaView::IsDirectory | KookaView::FileSelected | KookaView::ManySelected))) {
0569         slotUpdateRectangleActions(false);
0570     }
0571 }
0572 
0573 void Kooka::slotUpdateOcrResultActions(bool haveText)
0574 {
0575     qCDebug(KOOKA_LOG) << "haveText" << haveText;
0576     m_saveOCRTextAction->setEnabled(haveText);
0577     ocrSpellAction->setEnabled(haveText);
0578 }
0579 
0580 void Kooka::slotUpdateReadOnlyActions(bool ro)
0581 {
0582     bool enable = (m_imageChangeAllowed && !ro);    // also check gallery state
0583 
0584     mirrorVerticallyAction->setEnabled(enable);
0585     mirrorHorizontallyAction->setEnabled(enable);
0586     rotateCwAction->setEnabled(enable);
0587     rotateAcwAction->setEnabled(enable);
0588     rotate180Action->setEnabled(enable);
0589 }
0590 
0591 void Kooka::slotUpdateAutoSelectActions(bool isAvailable, bool isOn)
0592 {
0593     qCDebug(KOOKA_LOG) << "available" << isAvailable << "on" << isOn;
0594 
0595     autoselAction->setEnabled(isAvailable);
0596     autoselAction->setChecked(isOn);
0597 }
0598 
0599 void Kooka::slotOpenWithMenu()
0600 {
0601     m_view->showOpenWithMenu(openWithMenu);
0602 }