/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2006-01-20 * Description : main image editor GUI implementation * * Copyright (C) 2006-2008 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ // C Ansi includes. extern "C" { #include #include } // C++ includes. #include // TQt includes. #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Local includes. #include "ddebug.h" #include "dpopupmenu.h" #include "canvas.h" #include "dimginterface.h" #include "imagedialog.h" #include "imageplugin.h" #include "imagepluginloader.h" #include "imageresize.h" #include "imageprint.h" #include "filesaveoptionsbox.h" #include "statusprogressbar.h" #include "iccsettingscontainer.h" #include "exposurecontainer.h" #include "iofilesettingscontainer.h" #include "savingcontextcontainer.h" #include "loadingcacheinterface.h" #include "slideshowsettings.h" #include "themeengine.h" #include "rawcameradlg.h" #include "editorstackview.h" #include "editortooliface.h" #include "editorwindowprivate.h" #include "editorwindow.h" #include "editorwindow.moc" void tqt_enter_modal( TQWidget *widget ); void tqt_leave_modal( TQWidget *widget ); namespace Digikam { EditorWindow::EditorWindow(const char *name) : TDEMainWindow(0, name, WType_TopLevel) { d = new EditorWindowPriv; m_themeMenuAction = 0; m_contextMenu = 0; m_canvas = 0; m_imagePluginLoader = 0; m_undoAction = 0; m_redoAction = 0; m_fullScreenAction = 0; m_saveAction = 0; m_saveAsAction = 0; m_revertAction = 0; m_fileDeleteAction = 0; m_forwardAction = 0; m_backwardAction = 0; m_firstAction = 0; m_lastAction = 0; m_undoAction = 0; m_redoAction = 0; m_stackView = 0; m_fullScreen = false; m_rotatedOrFlipped = false; m_setExifOrientationTag = true; m_cancelSlideShow = false; // Settings containers instance. d->ICCSettings = new ICCSettingsContainer(); d->exposureSettings = new ExposureSettingsContainer(); d->toolIface = new EditorToolIface(this); m_IOFileSettings = new IOFileSettingsContainer(); m_savingContext = new SavingContextContainer(); } EditorWindow::~EditorWindow() { delete m_canvas; delete m_IOFileSettings; delete m_savingContext; delete d->ICCSettings; delete d->exposureSettings; delete d; } EditorStackView* EditorWindow::editorStackView() const { return m_stackView; } void EditorWindow::setupContextMenu() { m_contextMenu = new DPopupMenu(this); TDEActionCollection *ac = actionCollection(); if( ac->action("editorwindow_backward") ) ac->action("editorwindow_backward")->plug(m_contextMenu); if( ac->action("editorwindow_forward") ) ac->action("editorwindow_forward")->plug(m_contextMenu); m_contextMenu->insertSeparator(); if( ac->action("editorwindow_slideshow") ) ac->action("editorwindow_slideshow")->plug(m_contextMenu); if( ac->action("editorwindow_rotate_left") ) ac->action("editorwindow_rotate_left")->plug(m_contextMenu); if( ac->action("editorwindow_rotate_right") ) ac->action("editorwindow_rotate_right")->plug(m_contextMenu); if( ac->action("editorwindow_crop") ) ac->action("editorwindow_crop")->plug(m_contextMenu); m_contextMenu->insertSeparator(); if( ac->action("editorwindow_delete") ) ac->action("editorwindow_delete")->plug(m_contextMenu); } void EditorWindow::setupStandardConnections() { // -- Canvas connections ------------------------------------------------ connect(m_canvas, TQ_SIGNAL(signalToggleOffFitToWindow()), this, TQ_SLOT(slotToggleOffFitToWindow())); connect(m_canvas, TQ_SIGNAL(signalShowNextImage()), this, TQ_SLOT(slotForward())); connect(m_canvas, TQ_SIGNAL(signalShowPrevImage()), this, TQ_SLOT(slotBackward())); connect(m_canvas, TQ_SIGNAL(signalRightButtonClicked()), this, TQ_SLOT(slotContextMenu())); connect(m_stackView, TQ_SIGNAL(signalZoomChanged(bool, bool, double)), this, TQ_SLOT(slotZoomChanged(bool, bool, double))); connect(m_canvas, TQ_SIGNAL(signalChanged()), this, TQ_SLOT(slotChanged())); connect(m_canvas, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)), this, TQ_SLOT(slotUndoStateChanged(bool, bool, bool))); connect(m_canvas, TQ_SIGNAL(signalSelected(bool)), this, TQ_SLOT(slotSelected(bool))); connect(m_canvas, TQ_SIGNAL(signalPrepareToLoad()), this, TQ_SLOT(slotPrepareToLoad())); connect(m_canvas, TQ_SIGNAL(signalLoadingStarted(const TQString &)), this, TQ_SLOT(slotLoadingStarted(const TQString &))); connect(m_canvas, TQ_SIGNAL(signalLoadingFinished(const TQString &, bool)), this, TQ_SLOT(slotLoadingFinished(const TQString &, bool))); connect(m_canvas, TQ_SIGNAL(signalLoadingProgress(const TQString &, float)), this, TQ_SLOT(slotLoadingProgress(const TQString &, float))); connect(m_canvas, TQ_SIGNAL(signalSavingStarted(const TQString&)), this, TQ_SLOT(slotSavingStarted(const TQString&))); connect(m_canvas, TQ_SIGNAL(signalSavingFinished(const TQString&, bool)), this, TQ_SLOT(slotSavingFinished(const TQString&, bool))); connect(m_canvas, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), this, TQ_SLOT(slotSavingProgress(const TQString&, float))); connect(m_canvas, TQ_SIGNAL(signalSelectionChanged(const TQRect&)), this, TQ_SLOT(slotSelectionChanged(const TQRect&))); // -- if rotating/flipping set the rotatedflipped flag to true ----------- connect(d->rotateLeftAction, TQ_SIGNAL(activated()), this, TQ_SLOT(slotRotatedOrFlipped())); connect(d->rotateRightAction, TQ_SIGNAL(activated()), this, TQ_SLOT(slotRotatedOrFlipped())); connect(d->flipHorizAction, TQ_SIGNAL(activated()), this, TQ_SLOT(slotRotatedOrFlipped())); connect(d->flipVertAction, TQ_SIGNAL(activated()), this, TQ_SLOT(slotRotatedOrFlipped())); // -- status bar connections -------------------------------------- connect(m_nameLabel, TQ_SIGNAL(signalCancelButtonPressed()), this, TQ_SLOT(slotNameLabelCancelButtonPressed())); connect(m_nameLabel, TQ_SIGNAL(signalCancelButtonPressed()), d->toolIface, TQ_SLOT(slotToolAborted())); } void EditorWindow::setupStandardActions() { // -- Standard 'File' menu actions --------------------------------------------- m_backwardAction = KStdAction::back(this, TQ_SLOT(slotBackward()), actionCollection(), "editorwindow_backward"); m_forwardAction = KStdAction::forward(this, TQ_SLOT(slotForward()), actionCollection(), "editorwindow_forward"); m_firstAction = new TDEAction(i18n("&First"), "go-first", TDEStdAccel::shortcut( TDEStdAccel::Home), this, TQ_SLOT(slotFirst()), actionCollection(), "editorwindow_first"); m_lastAction = new TDEAction(i18n("&Last"), "go-last", TDEStdAccel::shortcut( TDEStdAccel::End), this, TQ_SLOT(slotLast()), actionCollection(), "editorwindow_last"); m_saveAction = KStdAction::save(this, TQ_SLOT(slotSave()), actionCollection(), "editorwindow_save"); m_saveAsAction = KStdAction::saveAs(this, TQ_SLOT(slotSaveAs()), actionCollection(), "editorwindow_saveas"); m_revertAction = KStdAction::revert(this, TQ_SLOT(slotRevert()), actionCollection(), "editorwindow_revert"); m_saveAction->setEnabled(false); m_saveAsAction->setEnabled(false); m_revertAction->setEnabled(false); d->filePrintAction = new TDEAction(i18n("Print Image..."), "document-print", CTRL+Key_P, this, TQ_SLOT(slotFilePrint()), actionCollection(), "editorwindow_print"); m_fileDeleteAction = new TDEAction(i18n("Move to Trash"), "edittrash", Key_Delete, this, TQ_SLOT(slotDeleteCurrentItem()), actionCollection(), "editorwindow_delete"); KStdAction::close(this, TQ_SLOT(close()), actionCollection(), "editorwindow_close"); // -- Standard 'Edit' menu actions --------------------------------------------- d->copyAction = KStdAction::copy(m_canvas, TQ_SLOT(slotCopy()), actionCollection(), "editorwindow_copy"); d->copyAction->setEnabled(false); m_undoAction = new TDEToolBarPopupAction(i18n("Undo"), "edit-undo", TDEStdAccel::shortcut(TDEStdAccel::Undo), m_canvas, TQ_SLOT(slotUndo()), actionCollection(), "editorwindow_undo"); connect(m_undoAction->popupMenu(), TQ_SIGNAL(aboutToShow()), this, TQ_SLOT(slotAboutToShowUndoMenu())); connect(m_undoAction->popupMenu(), TQ_SIGNAL(activated(int)), m_canvas, TQ_SLOT(slotUndo(int))); m_undoAction->setEnabled(false); m_redoAction = new TDEToolBarPopupAction(i18n("Redo"), "edit-redo", TDEStdAccel::shortcut(TDEStdAccel::Redo), m_canvas, TQ_SLOT(slotRedo()), actionCollection(), "editorwindow_redo"); connect(m_redoAction->popupMenu(), TQ_SIGNAL(aboutToShow()), this, TQ_SLOT(slotAboutToShowRedoMenu())); connect(m_redoAction->popupMenu(), TQ_SIGNAL(activated(int)), m_canvas, TQ_SLOT(slotRedo(int))); m_redoAction->setEnabled(false); d->selectAllAction = new TDEAction(i18n("Select All"), 0, CTRL+Key_A, m_canvas, TQ_SLOT(slotSelectAll()), actionCollection(), "editorwindow_selectAll"); d->selectNoneAction = new TDEAction(i18n("Select None"), 0, CTRL+SHIFT+Key_A, m_canvas, TQ_SLOT(slotSelectNone()), actionCollection(), "editorwindow_selectNone"); // -- Standard 'View' menu actions --------------------------------------------- d->zoomPlusAction = KStdAction::zoomIn(this, TQ_SLOT(slotIncreaseZoom()), actionCollection(), "editorwindow_zoomplus"); d->zoomMinusAction = KStdAction::zoomOut(this, TQ_SLOT(slotDecreaseZoom()), actionCollection(), "editorwindow_zoomminus"); d->zoomTo100percents = new TDEAction(i18n("Zoom to 100%"), "zoom-original", ALT+CTRL+Key_0, // NOTE: Photoshop 7 use ALT+CTRL+0. this, TQ_SLOT(slotZoomTo100Percents()), actionCollection(), "editorwindow_zoomto100percents"); d->zoomFitToWindowAction = new TDEToggleAction(i18n("Fit to &Window"), "view_fit_window", CTRL+SHIFT+Key_E, // NOTE: Gimp 2 use CTRL+SHIFT+E. this, TQ_SLOT(slotToggleFitToWindow()), actionCollection(), "editorwindow_zoomfit2window"); d->zoomFitToSelectAction = new TDEAction(i18n("Fit to &Selection"), "zoom-fit-best", ALT+CTRL+Key_S, this, TQ_SLOT(slotFitToSelect()), actionCollection(), "editorwindow_zoomfit2select"); d->zoomFitToSelectAction->setEnabled(false); d->zoomFitToSelectAction->setWhatsThis(i18n("This option can be used to zoom the image to the " "current selection area.")); d->zoomCombo = new KComboBox(true); d->zoomCombo->setDuplicatesEnabled(false); d->zoomCombo->setFocusPolicy(TQWidget::ClickFocus); d->zoomCombo->setInsertionPolicy(TQComboBox::NoInsertion); d->zoomComboAction = new KWidgetAction(d->zoomCombo, i18n("Zoom"), 0, 0, 0, actionCollection(), "editorwindow_zoomto"); d->zoomCombo->insertItem(TQString("10%")); d->zoomCombo->insertItem(TQString("25%")); d->zoomCombo->insertItem(TQString("50%")); d->zoomCombo->insertItem(TQString("75%")); d->zoomCombo->insertItem(TQString("100%")); d->zoomCombo->insertItem(TQString("150%")); d->zoomCombo->insertItem(TQString("200%")); d->zoomCombo->insertItem(TQString("300%")); d->zoomCombo->insertItem(TQString("450%")); d->zoomCombo->insertItem(TQString("600%")); d->zoomCombo->insertItem(TQString("800%")); d->zoomCombo->insertItem(TQString("1200%")); connect(d->zoomCombo, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotZoomSelected()) ); connect(d->zoomCombo, TQ_SIGNAL(returnPressed(const TQString&)), this, TQ_SLOT(slotZoomTextChanged(const TQString &)) ); // Do not use std KDE action for full screen because action text is too large for app. toolbar. m_fullScreenAction = new TDEToggleAction(i18n("Full Screen"), "view-fullscreen", CTRL+SHIFT+Key_F, this, TQ_SLOT(slotToggleFullScreen()), actionCollection(), "editorwindow_fullscreen"); m_fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode")); d->slideShowAction = new TDEAction(i18n("Slideshow"), "slideshow", Key_F9, this, TQ_SLOT(slotToggleSlideShow()), actionCollection(),"editorwindow_slideshow"); d->viewUnderExpoAction = new TDEToggleAction(i18n("Under-Exposure Indicator"), "underexposure", Key_F10, this, TQ_SLOT(slotToggleUnderExposureIndicator()), actionCollection(),"editorwindow_underexposure"); d->viewOverExpoAction = new TDEToggleAction(i18n("Over-Exposure Indicator"), "overexposure", Key_F11, this, TQ_SLOT(slotToggleOverExposureIndicator()), actionCollection(),"editorwindow_overexposure"); d->viewCMViewAction = new TDEToggleAction(i18n("Color Managed View"), "tv", Key_F12, this, TQ_SLOT(slotToggleColorManagedView()), actionCollection(),"editorwindow_cmview"); // -- Standard 'Transform' menu actions --------------------------------------------- d->resizeAction = new TDEAction(i18n("&Resize..."), "resize_image", 0, this, TQ_SLOT(slotResize()), actionCollection(), "editorwindow_resize"); d->cropAction = new TDEAction(i18n("Crop"), "crop", CTRL+Key_X, m_canvas, TQ_SLOT(slotCrop()), actionCollection(), "editorwindow_crop"); d->cropAction->setEnabled(false); d->cropAction->setWhatsThis(i18n("This option can be used to crop the image. " "Select a region of the image to enable this action.")); // -- Standard 'Flip' menu actions --------------------------------------------- d->flipHorizAction = new TDEAction(i18n("Flip Horizontally"), "mirror", CTRL+Key_Asterisk, m_canvas, TQ_SLOT(slotFlipHoriz()), actionCollection(), "editorwindow_flip_horiz"); d->flipHorizAction->setEnabled(false); d->flipVertAction = new TDEAction(i18n("Flip Vertically"), "flip", CTRL+Key_Slash, m_canvas, TQ_SLOT(slotFlipVert()), actionCollection(), "editorwindow_flip_vert"); d->flipVertAction->setEnabled(false); // -- Standard 'Rotate' menu actions ---------------------------------------- d->rotateLeftAction = new TDEAction(i18n("Rotate Left"), "object-rotate-left", SHIFT+CTRL+Key_Left, m_canvas, TQ_SLOT(slotRotate270()), actionCollection(), "editorwindow_rotate_left"); d->rotateLeftAction->setEnabled(false); d->rotateRightAction = new TDEAction(i18n("Rotate Right"), "object-rotate-right", SHIFT+CTRL+Key_Right, m_canvas, TQ_SLOT(slotRotate90()), actionCollection(), "editorwindow_rotate_right"); d->rotateRightAction->setEnabled(false); // -- Standard 'Configure' menu actions ---------------------------------------- d->showMenuBarAction = KStdAction::showMenubar(this, TQ_SLOT(slotShowMenuBar()), actionCollection()); KStdAction::keyBindings(this, TQ_SLOT(slotEditKeys()), actionCollection()); KStdAction::configureToolbars(this, TQ_SLOT(slotConfToolbars()), actionCollection()); KStdAction::preferences(this, TQ_SLOT(slotSetup()), actionCollection()); // ----------------------------------------------------------------------------------------- m_themeMenuAction = new TDESelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu"); m_themeMenuAction->setItems(ThemeEngine::instance()->themeNames()); connect(m_themeMenuAction, TQ_SIGNAL(activated(const TQString&)), this, TQ_SLOT(slotChangeTheme(const TQString&))); connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), this, TQ_SLOT(slotThemeChanged())); // -- Standard 'Help' menu actions --------------------------------------------- d->donateMoneyAction = new TDEAction(i18n("Donate..."), 0, 0, this, TQ_SLOT(slotDonateMoney()), actionCollection(), "editorwindow_donatemoney"); d->contributeAction = new TDEAction(i18n("Contribute..."), 0, 0, this, TQ_SLOT(slotContribute()), actionCollection(), "editorwindow_contribute"); d->rawCameraListAction = new TDEAction(i18n("Supported RAW Cameras"), "kdcraw", 0, this, TQ_SLOT(slotRawCameraList()), actionCollection(), "editorwindow_rawcameralist"); } void EditorWindow::setupStandardAccelerators() { d->accelerators = new TDEAccel(this); d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"), i18n("Exit out of the fullscreen mode"), Key_Escape, this, TQ_SLOT(slotEscapePressed()), false, true); d->accelerators->insert("Next Image Key_Space", i18n("Next Image"), i18n("Load Next Image"), Key_Space, this, TQ_SLOT(slotForward()), false, true); d->accelerators->insert("Previous Image SHIFT+Key_Space", i18n("Previous Image"), i18n("Load Previous Image"), SHIFT+Key_Space, this, TQ_SLOT(slotBackward()), false, true); d->accelerators->insert("Previous Image Key_Backspace", i18n("Previous Image"), i18n("Load Previous Image"), Key_Backspace, this, TQ_SLOT(slotBackward()), false, true); d->accelerators->insert("Next Image Key_Next", i18n("Next Image"), i18n("Load Next Image"), Key_Next, this, TQ_SLOT(slotForward()), false, true); d->accelerators->insert("Previous Image Key_Prior", i18n("Previous Image"), i18n("Load Previous Image"), Key_Prior, this, TQ_SLOT(slotBackward()), false, true); d->accelerators->insert("Zoom Plus Key_Plus", i18n("Zoom In"), i18n("Zoom in on Image"), Key_Plus, this, TQ_SLOT(slotIncreaseZoom()), false, true); d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom Out"), i18n("Zoom out of Image"), Key_Minus, this, TQ_SLOT(slotDecreaseZoom()), false, true); d->accelerators->insert("Redo CTRL+Key_Y", i18n("Redo"), i18n("Redo Last action"), CTRL+Key_Y, m_canvas, TQ_SLOT(slotRedo()), false, true); } void EditorWindow::setupStatusBar() { m_nameLabel = new StatusProgressBar(statusBar()); m_nameLabel->setAlignment(TQt::AlignCenter); m_nameLabel->setMaximumHeight(fontMetrics().height()+2); statusBar()->addWidget(m_nameLabel, 100); d->selectLabel = new TQLabel(i18n("No selection"), statusBar()); d->selectLabel->setAlignment(TQt::AlignCenter); d->selectLabel->setMaximumHeight(fontMetrics().height()+2); statusBar()->addWidget(d->selectLabel, 100); TQToolTip::add(d->selectLabel, i18n("Information about current selection area")); m_resLabel = new TQLabel(statusBar()); m_resLabel->setAlignment(TQt::AlignCenter); m_resLabel->setMaximumHeight(fontMetrics().height()+2); statusBar()->addWidget(m_resLabel, 100); TQToolTip::add(m_resLabel, i18n("Information about image size")); d->underExposureIndicator = new TQToolButton(statusBar()); d->underExposureIndicator->setIconSet(SmallIcon("underexposure")); d->underExposureIndicator->setToggleButton(true); statusBar()->addWidget(d->underExposureIndicator, 1); d->overExposureIndicator = new TQToolButton(statusBar()); d->overExposureIndicator->setIconSet(SmallIcon("overexposure")); d->overExposureIndicator->setToggleButton(true); statusBar()->addWidget(d->overExposureIndicator, 1); d->cmViewIndicator = new TQToolButton(statusBar()); d->cmViewIndicator->setIconSet(SmallIcon("tv")); d->cmViewIndicator->setToggleButton(true); statusBar()->addWidget(d->cmViewIndicator, 1); connect(d->underExposureIndicator, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotToggleUnderExposureIndicator())); connect(d->overExposureIndicator, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotToggleOverExposureIndicator())); connect(d->cmViewIndicator, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotToggleColorManagedView())); } void EditorWindow::printImage(KURL url) { uchar* ptr = m_canvas->interface()->getImage(); int w = m_canvas->interface()->origWidth(); int h = m_canvas->interface()->origHeight(); bool hasAlpha = m_canvas->interface()->hasAlpha(); bool sixteenBit = m_canvas->interface()->sixteenBit(); if (!ptr || !w || !h) return; DImg image(w, h, sixteenBit, hasAlpha, ptr); KPrinter printer; TQString appName = TDEApplication::kApplication()->aboutData()->appName(); printer.setDocName( url.filename() ); printer.setCreator( appName ); #if KDE_IS_VERSION(3,2,0) printer.setUsePrinterResolution(true); #endif KPrinter::addDialogPage( new ImageEditorPrintDialogPage(image, this, TQString(appName.append(" page")).ascii() )); if ( printer.setup( this, i18n("Print %1").arg(printer.docName().section('/', -1)) ) ) { ImagePrint printOperations(image, printer, url.filename()); if (!printOperations.printImageWithTQt()) { KMessageBox::error(this, i18n("Failed to print file: '%1'") .arg(url.filename())); } } } void EditorWindow::slotEditKeys() { KKeyDialog dialog(true, this); dialog.insert( actionCollection(), i18n( "General" ) ); TQPtrList pluginList = ImagePluginLoader::instance()->pluginList(); for (ImagePlugin* plugin = pluginList.first(); plugin; plugin = pluginList.next()) { if (plugin) { dialog.insert( plugin->actionCollection(), plugin->name() ); } } dialog.configure(); } void EditorWindow::slotResize() { ImageResize dlg(this); dlg.exec(); } void EditorWindow::slotAboutToShowUndoMenu() { m_undoAction->popupMenu()->clear(); TQStringList titles; m_canvas->getUndoHistory(titles); if(!titles.isEmpty()) { int id = 1; TQStringList::Iterator iter = titles.begin(); for(; iter != titles.end(); ++iter,++id) { m_undoAction->popupMenu()->insertItem(*iter, id); } } } void EditorWindow::slotAboutToShowRedoMenu() { m_redoAction->popupMenu()->clear(); TQStringList titles; m_canvas->getRedoHistory(titles); if(!titles.isEmpty()) { int id = 1; TQStringList::Iterator iter = titles.begin(); for(; iter != titles.end(); ++iter,++id) { m_redoAction->popupMenu()->insertItem(*iter, id); } } } void EditorWindow::slotConfToolbars() { saveMainWindowSettings(TDEGlobal::config(), "ImageViewer Settings"); KEditToolbar dlg(factory(), this); connect(&dlg, TQ_SIGNAL(newToolbarConfig()), this, TQ_SLOT(slotNewToolbarConfig())); dlg.exec(); } void EditorWindow::slotNewToolbarConfig() { applyMainWindowSettings(TDEGlobal::config(), "ImageViewer Settings"); } void EditorWindow::slotIncreaseZoom() { m_stackView->increaseZoom(); } void EditorWindow::slotDecreaseZoom() { m_stackView->decreaseZoom(); } void EditorWindow::slotToggleFitToWindow() { d->zoomPlusAction->setEnabled(true); d->zoomComboAction->setEnabled(true); d->zoomMinusAction->setEnabled(true); m_stackView->toggleFitToWindow(); } void EditorWindow::slotFitToSelect() { d->zoomPlusAction->setEnabled(true); d->zoomComboAction->setEnabled(true); d->zoomMinusAction->setEnabled(true); m_stackView->fitToSelect(); } void EditorWindow::slotZoomTo100Percents() { d->zoomPlusAction->setEnabled(true); d->zoomComboAction->setEnabled(true); d->zoomMinusAction->setEnabled(true); m_stackView->zoomTo100Percents(); } void EditorWindow::slotZoomSelected() { TQString txt = d->zoomCombo->currentText(); txt = txt.left(txt.find('%')); slotZoomTextChanged(txt); } void EditorWindow::slotZoomTextChanged(const TQString &txt) { bool r = false; double zoom = TDEGlobal::locale()->readNumber(txt, &r) / 100.0; if (r && zoom > 0.0) m_stackView->setZoomFactor(zoom); } void EditorWindow::slotZoomChanged(bool isMax, bool isMin, double zoom) { d->zoomPlusAction->setEnabled(!isMax); d->zoomMinusAction->setEnabled(!isMin); d->zoomCombo->blockSignals(true); d->zoomCombo->setCurrentText(TQString::number(lround(zoom*100.0)) + TQString("%")); d->zoomCombo->blockSignals(false); } void EditorWindow::slotToggleOffFitToWindow() { d->zoomFitToWindowAction->blockSignals(true); d->zoomFitToWindowAction->setChecked(false); d->zoomFitToWindowAction->blockSignals(false); } void EditorWindow::slotEscapePressed() { if (m_fullScreen) m_fullScreenAction->activate(); } void EditorWindow::plugActionAccel(TDEAction* action) { if (!action) return; d->accelerators->insert(action->text(), action->text(), action->whatsThis(), action->shortcut(), action, TQ_SLOT(activate())); } void EditorWindow::unplugActionAccel(TDEAction* action) { d->accelerators->remove(action->text()); } void EditorWindow::loadImagePlugins() { TQPtrList pluginList = m_imagePluginLoader->pluginList(); for (ImagePlugin* plugin = pluginList.first(); plugin; plugin = pluginList.next()) { if (plugin) { guiFactory()->addClient(plugin); plugin->setEnabledSelectionActions(false); } else DDebug() << "Invalid plugin to add!" << endl; } } void EditorWindow::unLoadImagePlugins() { TQPtrList pluginList = m_imagePluginLoader->pluginList(); for (ImagePlugin* plugin = pluginList.first(); plugin; plugin = pluginList.next()) { if (plugin) { guiFactory()->removeClient(plugin); plugin->setEnabledSelectionActions(false); } } } void EditorWindow::readStandardSettings() { TDEConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); // Restore full screen Mode ? if (config->readBoolEntry("FullScreen", false)) { m_fullScreenAction->activate(); m_fullScreen = true; } // Restore Auto zoom action ? bool autoZoom = config->readBoolEntry("AutoZoom", true); if (autoZoom) d->zoomFitToWindowAction->activate(); } void EditorWindow::applyStandardSettings() { TDEConfig* config = kapp->config(); // -- Settings for Color Management stuff ---------------------------------------------- config->setGroup("Color Management"); d->ICCSettings->enableCMSetting = config->readBoolEntry("EnableCM", false); d->ICCSettings->askOrApplySetting = config->readBoolEntry("BehaviourICC", false); d->ICCSettings->BPCSetting = config->readBoolEntry("BPCAlgorithm",false); d->ICCSettings->managedViewSetting = config->readBoolEntry("ManagedView", false); d->ICCSettings->renderingSetting = config->readNumEntry("RenderingIntent"); d->ICCSettings->inputSetting = config->readPathEntry("InProfileFile", TQString()); d->ICCSettings->workspaceSetting = config->readPathEntry("WorkProfileFile", TQString()); d->ICCSettings->monitorSetting = config->readPathEntry("MonitorProfileFile", TQString()); d->ICCSettings->proofSetting = config->readPathEntry("ProofProfileFile", TQString()); d->viewCMViewAction->setEnabled(d->ICCSettings->enableCMSetting); d->viewCMViewAction->setChecked(d->ICCSettings->managedViewSetting); d->cmViewIndicator->setEnabled(d->ICCSettings->enableCMSetting); d->cmViewIndicator->setOn(d->ICCSettings->managedViewSetting); setColorManagedViewIndicatorToolTip(d->ICCSettings->enableCMSetting, d->ICCSettings->managedViewSetting); m_canvas->setICCSettings(d->ICCSettings); // -- JPEG, PNG, TIFF JPEG2000 files format settings -------------------------------------- config->setGroup("ImageViewer Settings"); // JPEG quality slider settings : 1 - 100 ==> libjpeg settings : 25 - 100. m_IOFileSettings->JPEGCompression = (int)((75.0/100.0)* (float)config->readNumEntry("JPEGCompression", 75) + 26.0 - (75.0/100.0)); m_IOFileSettings->JPEGSubSampling = config->readNumEntry("JPEGSubSampling", 1); // Medium subsampling // PNG compression slider settings : 1 - 9 ==> libpng settings : 100 - 1. m_IOFileSettings->PNGCompression = (int)(((1.0-100.0)/8.0)* (float)config->readNumEntry("PNGCompression", 1) + 100.0 - ((1.0-100.0)/8.0)); // TIFF compression setting. m_IOFileSettings->TIFFCompression = config->readBoolEntry("TIFFCompression", false); // JPEG2000 quality slider settings : 1 - 100 m_IOFileSettings->JPEG2000Compression = config->readNumEntry("JPEG2000Compression", 100); // JPEG2000 LossLess setting. m_IOFileSettings->JPEG2000LossLess = config->readBoolEntry("JPEG2000LossLess", true); // -- RAW images decoding settings ------------------------------------------------------ // If digiKam Color Management is enable, no need to correct color of decoded RAW image, // else, sRGB color workspace will be used. if (d->ICCSettings->enableCMSetting) m_IOFileSettings->rawDecodingSettings.outputColorSpace = DRawDecoding::RAWCOLOR; else m_IOFileSettings->rawDecodingSettings.outputColorSpace = DRawDecoding::SRGB; m_IOFileSettings->rawDecodingSettings.sixteenBitsImage = config->readBoolEntry("SixteenBitsImage", false); m_IOFileSettings->rawDecodingSettings.whiteBalance = (DRawDecoding::WhiteBalance)config->readNumEntry("WhiteBalance", DRawDecoding::CAMERA); m_IOFileSettings->rawDecodingSettings.customWhiteBalance = config->readNumEntry("CustomWhiteBalance", 6500); m_IOFileSettings->rawDecodingSettings.customWhiteBalanceGreen = config->readDoubleNumEntry("CustomWhiteBalanceGreen", 1.0); m_IOFileSettings->rawDecodingSettings.RGBInterpolate4Colors = config->readBoolEntry("RGBInterpolate4Colors", false); m_IOFileSettings->rawDecodingSettings.DontStretchPixels = config->readBoolEntry("DontStretchPixels", false); m_IOFileSettings->rawDecodingSettings.enableNoiseReduction = config->readBoolEntry("EnableNoiseReduction", false); m_IOFileSettings->rawDecodingSettings.unclipColors = config->readNumEntry("UnclipColors", 0); m_IOFileSettings->rawDecodingSettings.RAWQuality = (DRawDecoding::DecodingQuality)config->readNumEntry("RAWQuality", DRawDecoding::BILINEAR); m_IOFileSettings->rawDecodingSettings.NRThreshold = config->readNumEntry("NRThreshold", 100); m_IOFileSettings->rawDecodingSettings.enableCACorrection = config->readBoolEntry("EnableCACorrection", false); m_IOFileSettings->rawDecodingSettings.caMultiplier[0] = config->readDoubleNumEntry("caRedMultiplier", 1.0); m_IOFileSettings->rawDecodingSettings.caMultiplier[1] = config->readDoubleNumEntry("caBlueMultiplier", 1.0); m_IOFileSettings->rawDecodingSettings.brightness = config->readDoubleNumEntry("RAWBrightness", 1.0); m_IOFileSettings->rawDecodingSettings.medianFilterPasses = config->readNumEntry("MedianFilterPasses", 0); m_IOFileSettings->useRAWImport = config->readBoolEntry("UseRawImportTool", false); // -- GUI Settings ------------------------------------------------------- TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); if(config->hasKey("Splitter Sizes")) m_splitter->setSizes(config->readIntListEntry("Splitter Sizes")); else m_canvas->setSizePolicy(rightSzPolicy); d->fullScreenHideToolBar = config->readBoolEntry("FullScreen Hide ToolBar", false); slotThemeChanged(); // -- Exposure Indicators Settings --------------------------------------- TQColor black(TQt::black); TQColor white(TQt::white); d->exposureSettings->underExposureIndicator = config->readBoolEntry("UnderExposureIndicator", false); d->exposureSettings->overExposureIndicator = config->readBoolEntry("OverExposureIndicator", false); d->exposureSettings->underExposureColor = config->readColorEntry("UnderExposureColor", &white); d->exposureSettings->overExposureColor = config->readColorEntry("OverExposureColor", &black); d->viewUnderExpoAction->setChecked(d->exposureSettings->underExposureIndicator); d->viewOverExpoAction->setChecked(d->exposureSettings->overExposureIndicator); d->underExposureIndicator->setOn(d->exposureSettings->underExposureIndicator); d->overExposureIndicator->setOn(d->exposureSettings->overExposureIndicator); setUnderExposureToolTip(d->exposureSettings->underExposureIndicator); setOverExposureToolTip(d->exposureSettings->overExposureIndicator); m_canvas->setExposureSettings(d->exposureSettings); } void EditorWindow::saveStandardSettings() { TDEConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); config->writeEntry("AutoZoom", d->zoomFitToWindowAction->isChecked()); config->writeEntry("Splitter Sizes", m_splitter->sizes()); config->writeEntry("FullScreen", m_fullScreenAction->isChecked()); config->writeEntry("UnderExposureIndicator", d->exposureSettings->underExposureIndicator); config->writeEntry("OverExposureIndicator", d->exposureSettings->overExposureIndicator); config->sync(); } /** Method used by Editor Tools. Only Zoom+ and Zoom- are currently supported. TODO: Fix this behavour when editor tool preview widgets will be factored. */ void EditorWindow::toggleZoomActions(bool val) { d->zoomMinusAction->setEnabled(val); d->zoomPlusAction->setEnabled(val); } void EditorWindow::toggleStandardActions(bool val) { d->zoomComboAction->setEnabled(val); d->zoomTo100percents->setEnabled(val); d->zoomFitToWindowAction->setEnabled(val); d->zoomFitToSelectAction->setEnabled(val); toggleZoomActions(val); d->rotateLeftAction->setEnabled(val); d->rotateRightAction->setEnabled(val); d->flipHorizAction->setEnabled(val); d->flipVertAction->setEnabled(val); d->filePrintAction->setEnabled(val); d->resizeAction->setEnabled(val); m_fileDeleteAction->setEnabled(val); m_saveAsAction->setEnabled(val); d->selectAllAction->setEnabled(val); d->selectNoneAction->setEnabled(val); d->slideShowAction->setEnabled(val); // these actions are special: They are turned off if val is false, // but if val is true, they may be turned on or off. if (val) { // Trigger sending of signalUndoStateChanged // Note that for saving and loading, this is not necessary // because the signal will be sent later anyway. m_canvas->updateUndoState(); } else { m_saveAction->setEnabled(val); m_undoAction->setEnabled(val); m_redoAction->setEnabled(val); } TQPtrList pluginList = m_imagePluginLoader->pluginList(); for (ImagePlugin* plugin = pluginList.first(); plugin; plugin = pluginList.next()) { if (plugin) { plugin->setEnabledActions(val); } } } void EditorWindow::slotToggleFullScreen() { if (m_fullScreen) // out of fullscreen { m_canvas->setBackgroundColor(m_bgColor); setWindowState( windowState() & ~WindowFullScreen ); menuBar()->show(); statusBar()->show(); leftDock()->show(); rightDock()->show(); topDock()->show(); bottomDock()->show(); TQObject* obj = child("ToolBar","TDEToolBar"); if (obj) { TDEToolBar* toolBar = static_cast(obj); if (m_fullScreenAction->isPlugged(toolBar) && d->removeFullScreenButton) m_fullScreenAction->unplug(toolBar); if (toolBar->isHidden()) showToolBars(); } // -- remove the gui action accels ---- unplugActionAccel(m_forwardAction); unplugActionAccel(m_backwardAction); unplugActionAccel(m_firstAction); unplugActionAccel(m_lastAction); unplugActionAccel(m_saveAction); unplugActionAccel(m_saveAsAction); unplugActionAccel(d->zoomPlusAction); unplugActionAccel(d->zoomMinusAction); unplugActionAccel(d->zoomFitToWindowAction); unplugActionAccel(d->zoomFitToSelectAction); unplugActionAccel(d->cropAction); unplugActionAccel(d->filePrintAction); unplugActionAccel(m_fileDeleteAction); unplugActionAccel(d->selectAllAction); unplugActionAccel(d->selectNoneAction); toggleGUI2FullScreen(); m_fullScreen = false; } else // go to fullscreen { m_canvas->setBackgroundColor(TQColor(TQt::black)); // hide the menubar and the statusbar menuBar()->hide(); statusBar()->hide(); topDock()->hide(); leftDock()->hide(); rightDock()->hide(); bottomDock()->hide(); TQObject* obj = child("ToolBar","TDEToolBar"); if (obj) { TDEToolBar* toolBar = static_cast(obj); if (d->fullScreenHideToolBar) { hideToolBars(); } else { showToolBars(); if ( !m_fullScreenAction->isPlugged(toolBar) ) { m_fullScreenAction->plug(toolBar); d->removeFullScreenButton=true; } else { // If FullScreen button is enable in toolbar settings // We don't remove it when we out of fullscreen mode. d->removeFullScreenButton=false; } } } // -- Insert all the gui actions into the accel -- plugActionAccel(m_forwardAction); plugActionAccel(m_backwardAction); plugActionAccel(m_firstAction); plugActionAccel(m_lastAction); plugActionAccel(m_saveAction); plugActionAccel(m_saveAsAction); plugActionAccel(d->zoomPlusAction); plugActionAccel(d->zoomMinusAction); plugActionAccel(d->zoomFitToWindowAction); plugActionAccel(d->zoomFitToSelectAction); plugActionAccel(d->cropAction); plugActionAccel(d->filePrintAction); plugActionAccel(m_fileDeleteAction); plugActionAccel(d->selectAllAction); plugActionAccel(d->selectNoneAction); toggleGUI2FullScreen(); showFullScreen(); m_fullScreen = true; } } void EditorWindow::slotRotatedOrFlipped() { m_rotatedOrFlipped = true; } void EditorWindow::slotLoadingProgress(const TQString&, float progress) { m_nameLabel->setProgressValue((int)(progress*100.0)); } void EditorWindow::slotSavingProgress(const TQString&, float progress) { m_nameLabel->setProgressValue((int)(progress*100.0)); } bool EditorWindow::promptForOverWrite() { TQFileInfo fi(m_canvas->currentImageFilePath()); TQString warnMsg(i18n("About to overwrite file \"%1\"\nAre you sure?") .arg(fi.fileName())); return (KMessageBox::warningContinueCancel(this, warnMsg, i18n("Warning"), i18n("Overwrite"), "editorWindowSaveOverwrite") == KMessageBox::Continue); } bool EditorWindow::promptUserSave(const KURL& url) { if (m_saveAction->isEnabled()) { // if window is iconified, show it if (isMinimized()) { KWin::deIconifyWindow(winId()); } int result = KMessageBox::warningYesNoCancel(this, i18n("The image '%1' has been modified.\n" "Do you want to save it?") .arg(url.filename()), TQString(), KStdGuiItem::save(), KStdGuiItem::discard()); if (result == KMessageBox::Yes) { bool saving = false; if (m_canvas->isReadOnly()) saving = saveAs(); else if (promptForOverWrite()) saving = save(); // save and saveAs return false if they were cancelled and did not enter saving at all // In this case, do not call enter_loop because exit_loop will not be called. if (saving) { // Waiting for asynchronous image file saving operation runing in separate thread. m_savingContext->synchronizingState = SavingContextContainer::SynchronousSaving; enter_loop(); m_savingContext->synchronizingState = SavingContextContainer::NormalSaving; return m_savingContext->synchronousSavingResult; } else { return false; } } else if (result == KMessageBox::No) { m_saveAction->setEnabled(false); return true; } else { return false; } } return true; } bool EditorWindow::waitForSavingToComplete() { // avoid reentrancy - return false means we have reentered the loop already. if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving) return false; if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) { // Waiting for asynchronous image file saving operation runing in separate thread. m_savingContext->synchronizingState = SavingContextContainer::SynchronousSaving; KMessageBox::queuedMessageBox(this, KMessageBox::Information, i18n("Please wait while the image is being saved...")); enter_loop(); m_savingContext->synchronizingState = SavingContextContainer::NormalSaving; } return true; } void EditorWindow::enter_loop() { TQWidget dummy(0, 0, WType_Dialog | WShowModal); dummy.setFocusPolicy( TQWidget::NoFocus ); tqt_enter_modal(&dummy); tqApp->enter_loop(); tqt_leave_modal(&dummy); } void EditorWindow::slotSelected(bool val) { // Update menu actions. d->cropAction->setEnabled(val); d->zoomFitToSelectAction->setEnabled(val); d->copyAction->setEnabled(val); for (ImagePlugin* plugin = m_imagePluginLoader->pluginList().first(); plugin; plugin = m_imagePluginLoader->pluginList().next()) { if (plugin) { plugin->setEnabledSelectionActions(val); } } TQRect sel = m_canvas->getSelectedArea(); // Update histogram into sidebar. emit signalSelectionChanged(sel); // Update status bar if (val) d->selectLabel->setText(TQString("(%1, %2) (%3 x %4)").arg(sel.x()).arg(sel.y()) .arg(sel.width()).arg(sel.height())); else d->selectLabel->setText(i18n("No selection")); } void EditorWindow::hideToolBars() { TQPtrListIterator it = toolBarIterator(); TDEToolBar* bar; for(;it.current()!=0L; ++it) { bar = it.current(); if (bar->area()) bar->area()->hide(); else bar->hide(); } } void EditorWindow::showToolBars() { TQPtrListIterator it = toolBarIterator(); TDEToolBar* bar; for( ; it.current()!=0L ; ++it) { bar = it.current(); if (bar->area()) bar->area()->show(); else bar->show(); } } void EditorWindow::slotPrepareToLoad() { // Disable actions as appropriate during loading emit signalNoCurrentItem(); toggleActions(false); slotUpdateItemInfo(); } void EditorWindow::slotLoadingStarted(const TQString& /*filename*/) { setCursor( KCursor::waitCursor() ); m_nameLabel->progressBarMode(StatusProgressBar::ProgressBarMode, i18n("Loading: ")); } void EditorWindow::slotLoadingFinished(const TQString& filename, bool success) { m_nameLabel->progressBarMode(StatusProgressBar::TextMode); slotUpdateItemInfo(); // Enable actions as appropriate after loading // No need to re-enable image properties sidebar here, it's will be done // automatically by a signal from canvas toggleActions(success); unsetCursor(); // Note: in showfoto, we using a null filename to clear canvas. if (!success && filename != TQString()) { TQFileInfo fi(filename); TQString message = i18n("Failed to load image \"%1\"").arg(fi.fileName()); KMessageBox::error(this, message); DWarning() << "Failed to load image " << fi.fileName() << endl; } } void EditorWindow::slotNameLabelCancelButtonPressed() { // If we saving an image... if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) { m_savingContext->abortingSaving = true; m_canvas->abortSaving(); } // If we preparing SlideShow... m_cancelSlideShow = true; } void EditorWindow::slotSave() { if (m_canvas->isReadOnly()) saveAs(); else if (promptForOverWrite()) save(); } void EditorWindow::slotSavingStarted(const TQString& /*filename*/) { setCursor( KCursor::waitCursor() ); // Disable actions as appropriate during saving emit signalNoCurrentItem(); toggleActions(false); m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Saving: ")); } void EditorWindow::slotSavingFinished(const TQString& filename, bool success) { if (m_savingContext->savingState == SavingContextContainer::SavingStateSave) { // from save() m_savingContext->savingState = SavingContextContainer::SavingStateNone; if (!success) { if (!m_savingContext->abortingSaving) { KMessageBox::error(this, i18n("Failed to save file\n\"%1\"\nto\n\"%2\".") .arg(m_savingContext->destinationURL.filename()) .arg(m_savingContext->destinationURL.path())); } finishSaving(false); return; } DDebug() << "renaming to " << m_savingContext->destinationURL.path() << endl; if (!moveFile()) { finishSaving(false); return; } m_canvas->setUndoHistoryOrigin(); // remove image from cache since it has changed LoadingCacheInterface::cleanFromCache(m_savingContext->destinationURL.path()); // this won't be in the cache, but does not hurt to do it anyway LoadingCacheInterface::cleanFromCache(filename); // restore state of disabled actions. saveIsComplete can start any other task // (loading!) which might itself in turn change states finishSaving(true); saveIsComplete(); // Take all actions necessary to update information and re-enable sidebar slotChanged(); } else if (m_savingContext->savingState == SavingContextContainer::SavingStateSaveAs) { m_savingContext->savingState = SavingContextContainer::SavingStateNone; // from saveAs() if (!success) { if (!m_savingContext->abortingSaving) { KMessageBox::error(this, i18n("Failed to save file\n\"%1\"\nto\n\"%2\".") .arg(m_savingContext->destinationURL.filename()) .arg(m_savingContext->destinationURL.path())); } finishSaving(false); return; } // Only try to write exif if both src and destination are jpeg files DDebug() << "renaming to " << m_savingContext->destinationURL.path() << endl; if (!moveFile()) { finishSaving(false); return; } m_canvas->setUndoHistoryOrigin(); LoadingCacheInterface::cleanFromCache(m_savingContext->destinationURL.path()); LoadingCacheInterface::cleanFromCache(filename); finishSaving(true); saveAsIsComplete(); // Take all actions necessary to update information and re-enable sidebar slotChanged(); } } void EditorWindow::finishSaving(bool success) { m_savingContext->synchronousSavingResult = success; if (m_savingContext->saveTempFile) { delete m_savingContext->saveTempFile; m_savingContext->saveTempFile = 0; } // Exit of internal TQt event loop to unlock promptUserSave() method. if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving) tqApp->exit_loop(); // Enable actions as appropriate after saving toggleActions(true); unsetCursor(); m_nameLabel->progressBarMode(StatusProgressBar::TextMode); // On error, continue using current image if (!success) { m_canvas->switchToLastSaved(m_savingContext->srcURL.path()); } } void EditorWindow::startingSave(const KURL& url) { // avoid any reentrancy. Should be impossible anyway since actions will be disabled. if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) return; if (!checkPermissions(url)) return; m_savingContext->srcURL = url; m_savingContext->destinationURL = m_savingContext->srcURL; m_savingContext->destinationExisted = true; m_savingContext->originalFormat = m_canvas->currentImageFileFormat(); m_savingContext->format = m_savingContext->originalFormat; m_savingContext->abortingSaving = false; m_savingContext->savingState = SavingContextContainer::SavingStateSave; // use magic file extension which tells the digikamalbums ioslave to ignore the file m_savingContext->saveTempFile = new KTempFile(m_savingContext->srcURL.directory(false), ".digikamtempfile.tmp"); m_savingContext->saveTempFile->setAutoDelete(true); m_canvas->saveAs(m_savingContext->saveTempFile->name(), m_IOFileSettings, m_setExifOrientationTag && (m_rotatedOrFlipped || m_canvas->exifRotated())); } bool EditorWindow::startingSaveAs(const KURL& url) { if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) return false; TQString mimetypes = KImageIO::mimeTypes(KImageIO::Writing).join(" "); mimetypes.append(" image/tiff"); DDebug () << "mimetypes=" << mimetypes << endl; m_savingContext->srcURL = url; FileSaveOptionsBox *options = new FileSaveOptionsBox(); KFileDialog imageFileSaveDialog(m_savingContext->srcURL.isLocalFile() ? m_savingContext->srcURL.directory() : TQDir::homeDirPath(), TQString(), this, "imageFileSaveDialog", false, options); connect(&imageFileSaveDialog, TQ_SIGNAL(filterChanged(const TQString &)), options, TQ_SLOT(slotImageFileFormatChanged(const TQString &))); connect(&imageFileSaveDialog, TQ_SIGNAL(fileSelected(const TQString &)), options, TQ_SLOT(slotImageFileSelected(const TQString &))); ImageDialogPreview *preview = new ImageDialogPreview(&imageFileSaveDialog); imageFileSaveDialog.setPreviewWidget(preview); imageFileSaveDialog.setOperationMode(KFileDialog::Saving); imageFileSaveDialog.setMode(KFile::File); imageFileSaveDialog.setCaption(i18n("New Image File Name")); imageFileSaveDialog.setFilter(mimetypes); TQFileInfo info(m_savingContext->srcURL.fileName()); TDEConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); TQString ext = config->readEntry("LastSavedImageTypeMime", "png"); TQString fileName = info.baseName(false) + TQString(".") + ext; imageFileSaveDialog.setSelection(fileName); // Start dialog and check if canceled. if ( imageFileSaveDialog.exec() != KFileDialog::Accepted ) return false; // Update file save settings in editor instance. options->applySettings(); applyStandardSettings(); KURL newURL = imageFileSaveDialog.selectedURL(); // Check if target image format have been selected from Combo List of SaveAs dialog. m_savingContext->format = KImageIO::typeForMime(imageFileSaveDialog.currentMimeFilter()); if ( m_savingContext->format.isEmpty() ) { // Else, check if target image format have been add to target image file name using extension. TQFileInfo fi(newURL.path()); m_savingContext->format = fi.extension(false); if ( m_savingContext->format.isEmpty() ) { // If format is empty then file format is same as that of the original file. m_savingContext->format = TQImageIO::imageFormat(m_savingContext->srcURL.path()); } else { // Else, check if format from file name extension is include on file mime type list. TQString imgExtPattern; TQStringList imgExtList = TQStringList::split(" ", mimetypes); for (TQStringList::ConstIterator it = imgExtList.begin() ; it != imgExtList.end() ; ++it) { imgExtPattern.append (KImageIO::typeForMime(*it).upper()); imgExtPattern.append (" "); } imgExtPattern.append (" TIF TIFF"); if ( imgExtPattern.contains("JPEG") ) { imgExtPattern.append (" JPG"); imgExtPattern.append (" JPE"); } if ( !imgExtPattern.contains( m_savingContext->format.upper() ) ) { KMessageBox::error(this, i18n("Target image file format \"%1\" unsupported.") .arg(m_savingContext->format)); DWarning() << k_funcinfo << "target image file format " << m_savingContext->format << " unsupported!" << endl; return false; } } } if (!newURL.isValid()) { KMessageBox::error(this, i18n("Failed to save file\n\"%1\" to\n\"%2\".") .arg(newURL.filename()) .arg(newURL.path().section('/', -2, -2))); DWarning() << k_funcinfo << "target URL is not valid !" << endl; return false; } config->writeEntry("LastSavedImageTypeMime", m_savingContext->format); config->sync(); // if new and original url are equal use slotSave() ------------------------------ KURL currURL(m_savingContext->srcURL); currURL.cleanPath(); newURL.cleanPath(); if (currURL.equals(newURL)) { slotSave(); return false; } // Check for overwrite ---------------------------------------------------------- TQFileInfo fi(newURL.path()); m_savingContext->destinationExisted = fi.exists(); if ( m_savingContext->destinationExisted ) { int result = KMessageBox::warningYesNo( this, i18n("A file named \"%1\" already " "exists. Are you sure you want " "to overwrite it?") .arg(newURL.filename()), i18n("Overwrite File?"), i18n("Overwrite"), KStdGuiItem::cancel() ); if (result != KMessageBox::Yes) return false; // There will be two message boxes if the file is not writable. // This may be controversial, and it may be changed, but it was a deliberate decision. if (!checkPermissions(newURL)) return false; } // Now do the actual saving ----------------------------------------------------- // use magic file extension which tells the digikamalbums ioslave to ignore the file m_savingContext->saveTempFile = new KTempFile(newURL.directory(false), ".digikamtempfile.tmp"); m_savingContext->destinationURL = newURL; m_savingContext->originalFormat = m_canvas->currentImageFileFormat(); m_savingContext->savingState = SavingContextContainer::SavingStateSaveAs; m_savingContext->saveTempFile->setAutoDelete(true); m_savingContext->abortingSaving = false; m_canvas->saveAs(m_savingContext->saveTempFile->name(), m_IOFileSettings, m_setExifOrientationTag && (m_rotatedOrFlipped || m_canvas->exifRotated()), m_savingContext->format.lower()); return true; } bool EditorWindow::checkPermissions(const KURL& url) { //TODO: Check that the permissions can actually be changed // if write permissions are not available. TQFileInfo fi(url.path()); if (fi.exists() && !fi.isWritable()) { int result = KMessageBox::warningYesNo( this, i18n("You do not have write permissions " "for the file named \"%1\". " "Are you sure you want " "to overwrite it?") .arg(url.filename()), i18n("Overwrite File?"), i18n("Overwrite"), KStdGuiItem::cancel() ); if (result != KMessageBox::Yes) return false; } return true; } bool EditorWindow::moveFile() { TQCString dstFileName = TQFile::encodeName(m_savingContext->destinationURL.path()); // Store old permissions: // Just get the current umask. mode_t curr_umask = umask(S_IREAD | S_IWRITE); // Restore the umask. umask(curr_umask); // For new files respect the umask setting. mode_t filePermissions = (S_IREAD | S_IWRITE | S_IROTH | S_IWOTH | S_IRGRP | S_IWGRP) & ~curr_umask; // For existing files, use the mode of the original file. if (m_savingContext->destinationExisted) { struct stat stbuf; if (::stat(dstFileName, &stbuf) == 0) { filePermissions = stbuf.st_mode; } } // rename tmp file to dest if (::rename(TQFile::encodeName(m_savingContext->saveTempFile->name()), dstFileName) != 0) { KMessageBox::error(this, i18n("Failed to overwrite original file"), i18n("Error Saving File")); return false; } // restore permissions if (::chmod(dstFileName, filePermissions) != 0) { DWarning() << "Failed to restore file permissions for file " << dstFileName << endl; } return true; } void EditorWindow::slotToggleColorManagedView() { d->cmViewIndicator->blockSignals(true); d->viewCMViewAction->blockSignals(true); bool cmv = false; if (d->ICCSettings->enableCMSetting) { cmv = !d->ICCSettings->managedViewSetting; d->ICCSettings->managedViewSetting = cmv; m_canvas->setICCSettings(d->ICCSettings); // Save Color Managed View setting in config file. For performance // reason, no need to flush file, it cached in memory and will be flushed // to disk at end of session. TDEConfig* config = kapp->config(); config->setGroup("Color Management"); config->writeEntry("ManagedView", cmv); } d->cmViewIndicator->setOn(cmv); d->viewCMViewAction->setChecked(cmv); setColorManagedViewIndicatorToolTip(d->ICCSettings->enableCMSetting, cmv); d->cmViewIndicator->blockSignals(false); d->viewCMViewAction->blockSignals(false); } void EditorWindow::setColorManagedViewIndicatorToolTip(bool available, bool cmv) { TQToolTip::remove(d->cmViewIndicator); TQString tooltip; if (available) { if (cmv) tooltip = i18n("Color Managed View is enabled"); else tooltip = i18n("Color Managed View is disabled"); } else { tooltip = i18n("Color Management is not configured, so the Color Managed View is not available"); } TQToolTip::add(d->cmViewIndicator, tooltip); } void EditorWindow::slotToggleUnderExposureIndicator() { d->underExposureIndicator->blockSignals(true); d->viewUnderExpoAction->blockSignals(true); bool uei = !d->exposureSettings->underExposureIndicator; d->underExposureIndicator->setOn(uei); d->viewUnderExpoAction->setChecked(uei); d->exposureSettings->underExposureIndicator = uei; m_canvas->setExposureSettings(d->exposureSettings); setUnderExposureToolTip(uei); d->underExposureIndicator->blockSignals(false); d->viewUnderExpoAction->blockSignals(false); } void EditorWindow::setUnderExposureToolTip(bool uei) { TQToolTip::remove(d->underExposureIndicator); TQToolTip::add(d->underExposureIndicator, uei ? i18n("Under-Exposure indicator is enabled") : i18n("Under-Exposure indicator is disabled")); } void EditorWindow::slotToggleOverExposureIndicator() { d->overExposureIndicator->blockSignals(true); d->viewOverExpoAction->blockSignals(true); bool oei = !d->exposureSettings->overExposureIndicator; d->overExposureIndicator->setOn(oei); d->viewOverExpoAction->setChecked(oei); d->exposureSettings->overExposureIndicator = oei; m_canvas->setExposureSettings(d->exposureSettings); setOverExposureToolTip(oei); d->overExposureIndicator->blockSignals(false); d->viewOverExpoAction->blockSignals(false); } void EditorWindow::setOverExposureToolTip(bool oei) { TQToolTip::remove(d->overExposureIndicator); TQToolTip::add(d->overExposureIndicator, oei ? i18n("Over-Exposure indicator is enabled") : i18n("Over-Exposure indicator is disabled")); } void EditorWindow::slotDonateMoney() { TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation"); } void EditorWindow::slotContribute() { TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=contrib"); } void EditorWindow::slotToggleSlideShow() { TDEConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); bool startWithCurrent = config->readBoolEntry("SlideShowStartCurrent", false); SlideShowSettings settings; settings.delay = config->readNumEntry("SlideShowDelay", 5) * 1000; settings.printName = config->readBoolEntry("SlideShowPrintName", true); settings.printDate = config->readBoolEntry("SlideShowPrintDate", false); settings.printApertureFocal = config->readBoolEntry("SlideShowPrintApertureFocal", false); settings.printExpoSensitivity = config->readBoolEntry("SlideShowPrintExpoSensitivity", false); settings.printMakeModel = config->readBoolEntry("SlideShowPrintMakeModel", false); settings.printComment = config->readBoolEntry("SlideShowPrintComment", false); settings.loop = config->readBoolEntry("SlideShowLoop", false); slideShow(startWithCurrent, settings); } void EditorWindow::slotSelectionChanged(const TQRect& sel) { d->selectLabel->setText(TQString("(%1, %2) (%3 x %4)").arg(sel.x()).arg(sel.y()) .arg(sel.width()).arg(sel.height())); } void EditorWindow::slotRawCameraList() { RawCameraDlg dlg(this); dlg.exec(); } void EditorWindow::slotThemeChanged() { TQStringList themes(ThemeEngine::instance()->themeNames()); int index = themes.findIndex(ThemeEngine::instance()->getCurrentThemeName()); if (index == -1) index = themes.findIndex(i18n("Default")); m_themeMenuAction->setCurrentItem(index); TDEConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); if (!config->readBoolEntry("UseThemeBackgroundColor", true)) m_bgColor = config->readColorEntry("BackgroundColor", &TQt::black); else m_bgColor = ThemeEngine::instance()->baseColor(); m_canvas->setBackgroundColor(m_bgColor); } void EditorWindow::slotChangeTheme(const TQString& theme) { ThemeEngine::instance()->slotChangeTheme(theme); } void EditorWindow::setToolStartProgress(const TQString& toolName) { m_nameLabel->setProgressValue(0); m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, TQString("%1: ").arg(toolName)); } void EditorWindow::setToolProgress(int progress) { m_nameLabel->setProgressValue(progress); } void EditorWindow::setToolStopProgress() { m_nameLabel->setProgressValue(0); m_nameLabel->progressBarMode(StatusProgressBar::TextMode); slotUpdateItemInfo(); } void EditorWindow::slotShowMenuBar() { if (menuBar()->isVisible()) menuBar()->hide(); else menuBar()->show(); } } // namespace Digikam