Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
digikam/digikam/utilities/imageeditor/editor/editorwindow.cpp

1933 lignes
70 KiB

/* ============================================================
*
* 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