/* ============================================================
 *
 * 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 <tdestandarddirs.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 = tdeApp->aboutData()->appName();
    printer.setDocName( url.filename() );
    printer.setCreator( appName );
    printer.setUsePrinterResolution(true);

    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 = tdeApp->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 = tdeApp->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 = tdeApp->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 = tdeApp->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 = tdeApp->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()
{
    tdeApp->invokeBrowser("http://www.digikam.org/?q=donation");
}

void EditorWindow::slotContribute()
{
    tdeApp->invokeBrowser("http://www.digikam.org/?q=contrib");
}

void EditorWindow::slotToggleSlideShow()
{
    TDEConfig* config = tdeApp->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 = tdeApp->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
