File indexing completed on 2024-04-28 12:07:03
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 }