diff options
Diffstat (limited to 'src/utilities/imageeditor/editor/editorwindow.cpp')
-rw-r--r-- | src/utilities/imageeditor/editor/editorwindow.cpp | 1932 |
1 files changed, 1932 insertions, 0 deletions
diff --git a/src/utilities/imageeditor/editor/editorwindow.cpp b/src/utilities/imageeditor/editor/editorwindow.cpp new file mode 100644 index 00000000..eed7cfea --- /dev/null +++ b/src/utilities/imageeditor/editor/editorwindow.cpp @@ -0,0 +1,1932 @@ +/* ============================================================ + * + * 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 <caulier dot gilles at gmail dot com> + * + * 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 <sys/types.h> +#include <sys/stat.h> +} + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlabel.h> +#include <tqdockarea.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqtoolbutton.h> +#include <tqsplitter.h> +#include <tqdir.h> +#include <tqfileinfo.h> +#include <tqfile.h> +#include <tqcursor.h> +#include <tqtimer.h> +#include <tqfileinfo.h> + +// KDE includes. + +#include <kprinter.h> +#include <kkeydialog.h> +#include <tdeversion.h> +#include <tdeaction.h> +#include <kedittoolbar.h> +#include <tdeaboutdata.h> +#include <kcursor.h> +#include <kstdaction.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdefiledialog.h> +#include <tdemenubar.h> +#include <kimageio.h> +#include <tdeaccel.h> +#include <tdemessagebox.h> +#include <tdeglobal.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <tdeio/netaccess.h> +#include <tdeio/job.h> +#include <kprotocolinfo.h> +#include <tdeglobalsettings.h> +#include <tdetoolbar.h> +#include <kstatusbar.h> +#include <kprogress.h> +#include <twin.h> +#include <kcombobox.h> + +// 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<ImagePlugin> 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<ImagePlugin> 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<ImagePlugin> 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<ImagePlugin> 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<TDEToolBar*>(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<TDEToolBar*>(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<TDEToolBar> 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<TDEToolBar> 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 |