From 5bed6e4a4c916a97f8fe4d1b07f7eecf4d733b90 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Fri, 22 Nov 2024 18:41:30 +0900 Subject: Rename 'digikam' folder to 'src' Signed-off-by: Michele Calgaro (cherry picked from commit ee0d99607c14cb63d3ebdb3a970b508949fa8219) --- src/utilities/imageeditor/editor/Makefile.am | 51 + .../imageeditor/editor/digikamimageplugin.desktop | 39 + .../imageeditor/editor/digikamimagewindowui.rc | 125 ++ .../imageeditor/editor/editorstackview.cpp | 233 +++ src/utilities/imageeditor/editor/editorstackview.h | 97 + src/utilities/imageeditor/editor/editortool.cpp | 436 +++++ src/utilities/imageeditor/editor/editortool.h | 164 ++ .../imageeditor/editor/editortooliface.cpp | 147 ++ src/utilities/imageeditor/editor/editortooliface.h | 76 + .../imageeditor/editor/editortoolsettings.cpp | 331 ++++ .../imageeditor/editor/editortoolsettings.h | 110 ++ src/utilities/imageeditor/editor/editorwindow.cpp | 1932 ++++++++++++++++++++ src/utilities/imageeditor/editor/editorwindow.h | 263 +++ .../imageeditor/editor/editorwindowprivate.h | 143 ++ src/utilities/imageeditor/editor/imageiface.cpp | 444 +++++ src/utilities/imageeditor/editor/imageiface.h | 198 ++ src/utilities/imageeditor/editor/imagewindow.cpp | 1263 +++++++++++++ src/utilities/imageeditor/editor/imagewindow.h | 155 ++ .../imageeditor/editor/savingcontextcontainer.h | 89 + 19 files changed, 6296 insertions(+) create mode 100644 src/utilities/imageeditor/editor/Makefile.am create mode 100644 src/utilities/imageeditor/editor/digikamimageplugin.desktop create mode 100644 src/utilities/imageeditor/editor/digikamimagewindowui.rc create mode 100644 src/utilities/imageeditor/editor/editorstackview.cpp create mode 100644 src/utilities/imageeditor/editor/editorstackview.h create mode 100644 src/utilities/imageeditor/editor/editortool.cpp create mode 100644 src/utilities/imageeditor/editor/editortool.h create mode 100644 src/utilities/imageeditor/editor/editortooliface.cpp create mode 100644 src/utilities/imageeditor/editor/editortooliface.h create mode 100644 src/utilities/imageeditor/editor/editortoolsettings.cpp create mode 100644 src/utilities/imageeditor/editor/editortoolsettings.h create mode 100644 src/utilities/imageeditor/editor/editorwindow.cpp create mode 100644 src/utilities/imageeditor/editor/editorwindow.h create mode 100644 src/utilities/imageeditor/editor/editorwindowprivate.h create mode 100644 src/utilities/imageeditor/editor/imageiface.cpp create mode 100644 src/utilities/imageeditor/editor/imageiface.h create mode 100644 src/utilities/imageeditor/editor/imagewindow.cpp create mode 100644 src/utilities/imageeditor/editor/imagewindow.h create mode 100644 src/utilities/imageeditor/editor/savingcontextcontainer.h (limited to 'src/utilities/imageeditor/editor') diff --git a/src/utilities/imageeditor/editor/Makefile.am b/src/utilities/imageeditor/editor/Makefile.am new file mode 100644 index 00000000..71031991 --- /dev/null +++ b/src/utilities/imageeditor/editor/Makefile.am @@ -0,0 +1,51 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdimgeditor.la libshowfoto.la + +libdimgeditor_la_SOURCES = editorwindow.cpp imageiface.cpp imagewindow.cpp editorstackview.cpp \ + editortooliface.cpp editortool.cpp editortoolsettings.cpp + +libdimgeditor_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TDEPRINT) + +libdimgeditor_la_LIBADD = $(top_builddir)/src/utilities/imageeditor/tools/libdimgeditortools.la \ + $(top_builddir)/src/utilities/imageeditor/rawimport/librawimport.la + +libshowfoto_la_SOURCES = editorwindow.cpp imageiface.cpp editorstackview.cpp \ + editortooliface.cpp editortool.cpp editortoolsettings.cpp + +libshowfoto_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TDEPRINT) + +libshowfoto_la_LIBADD = $(top_builddir)/src/libs/dimg/libdimg.la \ + $(top_builddir)/src/libs/dialogs/libdialogshowfoto.la \ + $(top_builddir)/src/libs/widgets/libwidgets.la \ + $(top_builddir)/src/libs/greycstoration/libgreycstoration.la \ + $(top_builddir)/src/utilities/imageeditor/canvas/libdimgcanvas.la \ + $(top_builddir)/src/utilities/imageeditor/tools/libdimgeditortools.la \ + $(top_builddir)/src/utilities/imageeditor/rawimport/librawimport.la + +INCLUDES = -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/themeengine \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/libs/imageproperties \ + -I$(top_srcdir)/src/libs/threadimageio \ + -I$(top_srcdir)/src/utilities/setup \ + -I$(top_srcdir)/src/utilities/slideshow \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/utilities/imageeditor/tools \ + -I$(top_builddir)/src/libs/dialogs \ + $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes) + +digikaminclude_HEADERS = imageiface.h + +digikamincludedir = $(includedir)/digikam + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimagewindowui.rc + +kde_servicetypes_DATA = digikamimageplugin.desktop + diff --git a/src/utilities/imageeditor/editor/digikamimageplugin.desktop b/src/utilities/imageeditor/editor/digikamimageplugin.desktop new file mode 100644 index 00000000..31bef621 --- /dev/null +++ b/src/utilities/imageeditor/editor/digikamimageplugin.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=ServiceType +X-TDE-ServiceType=Digikam/ImagePlugin +X-TDE-DerivedName=Digikam ImagePlugin +Comment=A digiKam Image Plugin +Comment[bg]=Приставка за снимки в digiKam +Comment[br]=Ul lugent skeudenn digiKam +Comment[ca]=Un connector d'imatges del digiKam +Comment[cs]=Modul pro digiKam +Comment[da]=Et Digikam billed-plugin +Comment[de]=Ein Bild-Modul von digiKam +Comment[el]=Ένα πρόσθετο εικόνας digiKam +Comment[es]=Plugin de digiKam para imágenes +Comment[et]=DigiKami pildiplugin +Comment[fa]=یک وصلۀ تصویر digiKam +Comment[fi]=digiKam-liitännäinen +Comment[fr]=Un module externe pour digiKam +Comment[gl]=Un plugin de Imaxe de digiKam +Comment[hr]=digiKam dodatak za slike +Comment[is]=digiKam ljósmynda-íforrit +Comment[it]=Un plugin per le immagini di digiKam +Comment[ja]=digiKam 画像プラグイン +Comment[ms]=Plugin Imej digiKam +Comment[nds]=En digiKam-Bildmoduul +Comment[nl]=Een plugin voor Digikam +Comment[pa]=ਇੱਕ ਡਿਜ਼ੀਕੈਮ ਚਿੱਤਰ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka obrazu digiKama +Comment[pt]=Um 'Plugin' de Imagem do digiKam +Comment[pt_BR]=Plugin de imagem digiKam +Comment[ru]=Модуль изображений digiKam +Comment[sk]=DigiKam obrázkový plugin +Comment[sr]=digiKam-ов сликовни прикључак +Comment[sr@Latn]=digiKam-ov slikovni priključak +Comment[sv]=Ett bildinsticksprogram för Digikam +Comment[tr]=Bir digiKam Resim Eklentisi +Comment[uk]=Втулок зображень digiKam +Comment[vi]=Một phần bổ sung ảnh digiKam +Comment[xx]=xxA digiKam Image Pluginxx diff --git a/src/utilities/imageeditor/editor/digikamimagewindowui.rc b/src/utilities/imageeditor/editor/digikamimagewindowui.rc new file mode 100644 index 00000000..2c0314ad --- /dev/null +++ b/src/utilities/imageeditor/editor/digikamimagewindowui.rc @@ -0,0 +1,125 @@ + + + + + + &File + + + + + + + + + + + + + + + + + + &Edit + + + + + + + + + + &View + + + + + + + + + + + + + + + &Color + + + Enh&ance + + + Tra&nsform + + + + + + + + + + + &Decorate + + + F&ilters + + + &Help + + + + + + + + &Settings + + + + + + + + + + + + + +Main Toolbar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/utilities/imageeditor/editor/editorstackview.cpp b/src/utilities/imageeditor/editor/editorstackview.cpp new file mode 100644 index 00000000..61550300 --- /dev/null +++ b/src/utilities/imageeditor/editor/editorstackview.cpp @@ -0,0 +1,233 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : A widget stack to embed editor view. + * + * Copyright (C) 2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// Local includes. + +#include "previewwidget.h" +#include "imageregionwidget.h" +#include "imagepanelwidget.h" +#include "canvas.h" +#include "editorstackview.h" +#include "editorstackview.moc" + +namespace Digikam +{ + +class EditorStackViewPriv +{ + +public: + + EditorStackViewPriv() + { + canvas = 0; + toolView = 0; + } + + TQWidget *toolView; + Canvas *canvas; +}; + +EditorStackView::EditorStackView(TQWidget *parent) + : TQWidgetStack(parent, 0, TQt::WDestructiveClose) +{ + d = new EditorStackViewPriv; +} + +EditorStackView::~EditorStackView() +{ + delete d; +} + +void EditorStackView::setCanvas(Canvas* canvas) +{ + if (d->canvas) return; + + d->canvas = canvas; + addWidget(d->canvas, CanvasMode); + + connect(d->canvas, TQ_SIGNAL(signalZoomChanged(double)), + this, TQ_SLOT(slotZoomChanged(double))); +} + +Canvas* EditorStackView::canvas() const +{ + return d->canvas; +} + +void EditorStackView::setToolView(TQWidget* view) +{ + if (d->toolView) + removeWidget(d->toolView); + + d->toolView = view; + + if (d->toolView) + addWidget(d->toolView, ToolViewMode); + + PreviewWidget *preview = previewWidget(); + if (preview) + { + connect(preview, TQ_SIGNAL(signalZoomFactorChanged(double)), + this, TQ_SLOT(slotZoomChanged(double))); + } +} + +TQWidget* EditorStackView::toolView() const +{ + return d->toolView; +} + +int EditorStackView::viewMode() +{ + return id(visibleWidget()); +} + +void EditorStackView::setViewMode(int mode) +{ + if (mode != CanvasMode && mode != ToolViewMode) + return; + + raiseWidget(mode); +} + +void EditorStackView::increaseZoom() +{ + if (viewMode() == CanvasMode) + { + d->canvas->slotIncreaseZoom(); + } + else + { + PreviewWidget *preview = previewWidget(); + if (preview) + preview->slotIncreaseZoom(); + } +} + +void EditorStackView::decreaseZoom() +{ + if (viewMode() == CanvasMode) + { + d->canvas->slotDecreaseZoom(); + } + else + { + PreviewWidget *preview = previewWidget(); + if (preview) + preview->slotDecreaseZoom(); + } +} + +void EditorStackView::toggleFitToWindow() +{ + if (viewMode() == CanvasMode) + { + d->canvas->toggleFitToWindow(); + } + else + { + PreviewWidget *preview = previewWidget(); + if (preview) + preview->toggleFitToWindow(); + } +} + +void EditorStackView::fitToSelect() +{ + if (viewMode() == CanvasMode) + { + d->canvas->fitToSelect(); + } +} + +void EditorStackView::zoomTo100Percents() +{ + if (viewMode() == CanvasMode) + { + if (d->canvas->zoomFactor() == 1.0) + d->canvas->toggleFitToWindow(); + else + d->canvas->setZoomFactor(1.0); + } + else + { + PreviewWidget *preview = previewWidget(); + if (preview) + { + if (preview->zoomFactor() == 1.0) + preview->toggleFitToWindow(); + else + preview->setZoomFactor(1.0); + } + } +} + +void EditorStackView::setZoomFactor(double zoom) +{ + if (viewMode() == CanvasMode) + { + d->canvas->setZoomFactor(zoom); + } + else + { + PreviewWidget *preview = previewWidget(); + if (preview) + preview->setZoomFactor(zoom); + } +} + +void EditorStackView::slotZoomChanged(double zoom) +{ + bool max, min; + + if (viewMode() == CanvasMode) + { + max = d->canvas->maxZoom(); + min = d->canvas->minZoom(); + emit signalZoomChanged(max, min, zoom); + } + else + { + PreviewWidget *preview = previewWidget(); + if (preview) + { + max = preview->maxZoom(); + min = preview->minZoom(); + emit signalZoomChanged(max, min, zoom); + } + } +} + +PreviewWidget* EditorStackView::previewWidget() const +{ + PreviewWidget *preview = dynamic_cast(d->toolView); + if (preview) return preview; + + ImagePanelWidget *panel = dynamic_cast(d->toolView); + if (panel) return (dynamic_cast(panel->previewWidget())); + + return 0; +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/editor/editorstackview.h b/src/utilities/imageeditor/editor/editorstackview.h new file mode 100644 index 00000000..e428fcd7 --- /dev/null +++ b/src/utilities/imageeditor/editor/editorstackview.h @@ -0,0 +1,97 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : A widget stack to embed editor view. + * + * Copyright (C) 2008-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORSTACKVIEW_H +#define EDITORSTACKVIEW_H + +// KDE includes. + +#include + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class PreviewWidget; +class Canvas; +class EditorStackViewPriv; + +class DIGIKAM_EXPORT EditorStackView : public TQWidgetStack +{ +TQ_OBJECT + + +public: + + enum StackViewMode + { + CanvasMode=0, + ToolViewMode + }; + +public: + + EditorStackView(TQWidget *parent=0); + ~EditorStackView(); + + void setCanvas(Canvas* canvas); + Canvas *canvas() const; + + void setToolView(TQWidget* view); + TQWidget *toolView() const; + + int viewMode(); + void setViewMode(int mode); + + void increaseZoom(); + void decreaseZoom(); + void toggleFitToWindow(); + void fitToSelect(); + void zoomTo100Percents(); + void setZoomFactor(double zoom); + + /** Two widgets are embedded in Editor Tool to perform preview with panning and zooming: + a PreviewWidget derivated class or ImagePanelWidget. + This method try to find the right PreviewWidget instance accordingly else return 0. + */ + PreviewWidget* previewWidget() const; + +signals: + + void signalZoomChanged(bool isMax, bool isMin, double zoom); + +private slots: + + void slotZoomChanged(double); + +private: + + EditorStackViewPriv* d; +}; + +} // namespace Digikam + +#endif /* EDITORSTACKVIEW_H */ diff --git a/src/utilities/imageeditor/editor/editortool.cpp b/src/utilities/imageeditor/editor/editortool.cpp new file mode 100644 index 00000000..b840e673 --- /dev/null +++ b/src/utilities/imageeditor/editor/editortool.cpp @@ -0,0 +1,436 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : editor tool template class. + * + * Copyright (C) 2008-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include +#include + +// KDE includes. + +#include + +// Local includes. + +#include "ddebug.h" +#include "imagewidget.h" +#include "imageguidewidget.h" +#include "imagepanelwidget.h" +#include "dimgthreadedfilter.h" +#include "editortoolsettings.h" +#include "editortooliface.h" +#include "editortool.h" +#include "editortool.moc" + +namespace Digikam +{ + +class EditorToolPriv +{ + +public: + + EditorToolPriv() + { + timer = 0; + view = 0; + settings = 0; + } + + TQString helpAnchor; + TQString name; + + TQWidget *view; + + TQPixmap icon; + + TQTimer *timer; + + EditorToolSettings *settings; +}; + +EditorTool::EditorTool(TQObject *parent) + : TQObject(parent) +{ + d = new EditorToolPriv; + d->timer = new TQTimer(this); + + connect(d->timer, TQ_SIGNAL(timeout()), + this, TQ_SLOT(slotEffect())); +} + +EditorTool::~EditorTool() +{ + delete d; +} + +void EditorTool::init() +{ + TQTimer::singleShot(0, this, TQ_SLOT(slotInit())); +} + +TQPixmap EditorTool::toolIcon() const +{ + return d->icon; +} + +void EditorTool::setToolIcon(const TQPixmap& icon) +{ + d->icon = icon; +} + +TQString EditorTool::toolName() const +{ + return d->name; +} + +void EditorTool::setToolName(const TQString& name) +{ + d->name = name; +} + +TQWidget* EditorTool::toolView() const +{ + return d->view; +} + +void EditorTool::setToolView(TQWidget *view) +{ + d->view = view; + // Will be unblocked in slotInit() + // This will prevent resize event signals emit during tool init. + d->view->blockSignals(true); +} + +EditorToolSettings* EditorTool::toolSettings() const +{ + return d->settings; +} + +void EditorTool::setToolSettings(EditorToolSettings *settings) +{ + d->settings = settings; + + connect(d->settings, TQ_SIGNAL(signalOkClicked()), + this, TQ_SLOT(slotOk())); + + connect(d->settings, TQ_SIGNAL(signalCancelClicked()), + this, TQ_SLOT(slotCancel())); + + connect(d->settings, TQ_SIGNAL(signalDefaultClicked()), + this, TQ_SLOT(slotResetSettings())); + + connect(d->settings, TQ_SIGNAL(signalSaveAsClicked()), + this, TQ_SLOT(slotSaveAsSettings())); + + connect(d->settings, TQ_SIGNAL(signalLoadClicked()), + this, TQ_SLOT(slotLoadSettings())); + + connect(d->settings, TQ_SIGNAL(signalTryClicked()), + this, TQ_SLOT(slotEffect())); + + // Will be unblocked in slotInit() + // This will prevent signals emit during tool init. + d->settings->blockSignals(true); +} + +void EditorTool::slotInit() +{ + readSettings(); + // Unlock signals from preview and settings widgets when init is done. + d->view->blockSignals(false); + d->settings->blockSignals(false); +} + +void EditorTool::setToolHelp(const TQString& anchor) +{ + d->helpAnchor = anchor; + // TODO: use this anchor with editor Help menu +} + +TQString EditorTool::toolHelp() const +{ + if (d->helpAnchor.isEmpty()) + return (name() + TQString(".anchor")); + + return d->helpAnchor; +} + +void EditorTool::setBusy(bool state) +{ + d->settings->setBusy(state); +} + +void EditorTool::readSettings() +{ + d->settings->readSettings(); +} + +void EditorTool::writeSettings() +{ + d->settings->writeSettings(); +} + +void EditorTool::slotResetSettings() +{ + d->settings->resetSettings(); +} + +void EditorTool::slotTimer() +{ + d->timer->start(500, true); +} + +void EditorTool::slotOk() +{ + writeSettings(); + finalRendering(); + emit okClicked(); +} + +void EditorTool::slotCancel() +{ + writeSettings(); + emit cancelClicked(); +} + +// ---------------------------------------------------------------- + +class EditorToolThreadedPriv +{ + +public: + + EditorToolThreadedPriv() + { + threadedFilter = 0; + currentRenderingMode = EditorToolThreaded::NoneRendering; + } + + EditorToolThreaded::RenderingMode currentRenderingMode; + + TQString progressMess; + + DImgThreadedFilter *threadedFilter; +}; + +EditorToolThreaded::EditorToolThreaded(TQObject *parent) + : EditorTool(parent) +{ + d = new EditorToolThreadedPriv; +} + +EditorToolThreaded::~EditorToolThreaded() +{ + delete d->threadedFilter; + delete d; +} + +EditorToolThreaded::RenderingMode EditorToolThreaded::renderingMode() const +{ + return d->currentRenderingMode; +} + +void EditorToolThreaded::setProgressMessage(const TQString& mess) +{ + d->progressMess = mess; +} + +DImgThreadedFilter* EditorToolThreaded::filter() const +{ + return d->threadedFilter; +} + +void EditorToolThreaded::setFilter(DImgThreadedFilter *filter) +{ + d->threadedFilter = filter; +} + +void EditorToolThreaded::slotResized() +{ + if (d->currentRenderingMode == EditorToolThreaded::FinalRendering) + { + toolView()->update(); + return; + } + else if (d->currentRenderingMode == EditorToolThreaded::PreviewRendering) + { + if (filter()) + filter()->stopComputation(); + } + + TQTimer::singleShot(0, this, TQ_SLOT(slotEffect())); +} + +void EditorToolThreaded::slotAbort() +{ + d->currentRenderingMode = EditorToolThreaded::NoneRendering; + + if (filter()) + filter()->stopComputation(); + + EditorToolIface::editorToolIface()->setToolStopProgress(); + + toolSettings()->enableButton(EditorToolSettings::Ok, true); + toolSettings()->enableButton(EditorToolSettings::Load, true); + toolSettings()->enableButton(EditorToolSettings::SaveAs, true); + toolSettings()->enableButton(EditorToolSettings::Try, true); + toolSettings()->enableButton(EditorToolSettings::Default, true); + + renderingFinished(); +} + +void EditorToolThreaded::customEvent(TQCustomEvent *e) +{ + if (!e) return; + + DImgThreadedFilter::EventData *ed = (DImgThreadedFilter::EventData*)e->data(); + + if (!ed) return; + + if (ed->starting) // Computation in progress ! + { + EditorToolIface::editorToolIface()->setToolProgress(ed->progress); + } + else + { + if (ed->success) // Computation Completed ! + { + switch (d->currentRenderingMode) + { + case EditorToolThreaded::PreviewRendering: + { + DDebug() << "Preview " << toolName() << " completed..." << endl; + putPreviewData(); + slotAbort(); + break; + } + + case EditorToolThreaded::FinalRendering: + { + DDebug() << "Final" << toolName() << " completed..." << endl; + putFinalData(); + EditorToolIface::editorToolIface()->setToolStopProgress(); + kapp->restoreOverrideCursor(); + emit okClicked(); + break; + } + + default: + break; + } + } + else // Computation Failed ! + { + switch (d->currentRenderingMode) + { + case EditorToolThreaded::PreviewRendering: + { + DDebug() << "Preview " << toolName() << " failed..." << endl; + slotAbort(); + break; + } + + case EditorToolThreaded::FinalRendering: + default: + break; + } + } + } + + delete ed; +} + +void EditorToolThreaded::setToolView(TQWidget *view) +{ + EditorTool::setToolView(view); + + if (dynamic_cast(view) || dynamic_cast(view) || + dynamic_cast(view)) + { + connect(view, TQ_SIGNAL(signalResized()), + this, TQ_SLOT(slotResized())); + } +} + +void EditorToolThreaded::slotOk() +{ + writeSettings(); + + d->currentRenderingMode = EditorToolThreaded::FinalRendering; + DDebug() << "Final " << toolName() << " started..." << endl; + writeSettings(); + + toolSettings()->enableButton(EditorToolSettings::Ok, false); + toolSettings()->enableButton(EditorToolSettings::SaveAs, false); + toolSettings()->enableButton(EditorToolSettings::Load, false); + toolSettings()->enableButton(EditorToolSettings::Default, false); + toolSettings()->enableButton(EditorToolSettings::Try, false); + + EditorToolIface::editorToolIface()->setToolStartProgress(d->progressMess.isEmpty() ? toolName() : d->progressMess); + kapp->setOverrideCursor( KCursor::waitCursor() ); + + if (d->threadedFilter) + { + delete d->threadedFilter; + d->threadedFilter = 0; + } + + prepareFinal(); +} + +void EditorToolThreaded::slotEffect() +{ + // Computation already in process. + if (d->currentRenderingMode != EditorToolThreaded::NoneRendering) + return; + + d->currentRenderingMode = EditorToolThreaded::PreviewRendering; + DDebug() << "Preview " << toolName() << " started..." << endl; + + toolSettings()->enableButton(EditorToolSettings::Ok, false); + toolSettings()->enableButton(EditorToolSettings::SaveAs, false); + toolSettings()->enableButton(EditorToolSettings::Load, false); + toolSettings()->enableButton(EditorToolSettings::Default, false); + toolSettings()->enableButton(EditorToolSettings::Try, false); + + EditorToolIface::editorToolIface()->setToolStartProgress(d->progressMess.isEmpty() ? toolName() : d->progressMess); + + if (d->threadedFilter) + { + delete d->threadedFilter; + d->threadedFilter = 0; + } + + prepareEffect(); +} + +void EditorToolThreaded::slotCancel() +{ + writeSettings(); + slotAbort(); + kapp->restoreOverrideCursor(); + emit cancelClicked(); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/editor/editortool.h b/src/utilities/imageeditor/editor/editortool.h new file mode 100644 index 00000000..120ff9f0 --- /dev/null +++ b/src/utilities/imageeditor/editor/editortool.h @@ -0,0 +1,164 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : editor tool template class. + * + * Copyright (C) 2008-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORTOOL_H +#define EDITORTOOL_H + +// TQt includes. + +#include +#include +#include + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DImgThreadedFilter; +class EditorToolSettings; +class EditorToolPriv; + +class DIGIKAM_EXPORT EditorTool : public TQObject +{ + TQ_OBJECT + + +public: + + EditorTool(TQObject *parent); + virtual ~EditorTool(); + + void init(); + + TQString toolHelp() const; + TQString toolName() const; + TQPixmap toolIcon() const; + TQWidget* toolView() const; + EditorToolSettings* toolSettings() const; + +signals: + + void okClicked(); + void cancelClicked(); + +protected: + + void setToolHelp(const TQString& anchor); + void setToolName(const TQString& name); + void setToolIcon(const TQPixmap& icon); + + virtual void setToolView(TQWidget *view); + virtual void setToolSettings(EditorToolSettings *settings); + virtual void setBusy(bool); + virtual void readSettings(); + virtual void writeSettings(); + virtual void finalRendering(){}; + +protected slots: + + void slotTimer(); + + virtual void slotOk(); + virtual void slotCancel(); + virtual void slotInit(); + virtual void slotLoadSettings(){}; + virtual void slotSaveAsSettings(){}; + virtual void slotResetSettings(); + virtual void slotEffect(){}; + +private: + + EditorToolPriv *d; +}; + +// ----------------------------------------------------------------- + +class EditorToolThreadedPriv; + +class DIGIKAM_EXPORT EditorToolThreaded : public EditorTool +{ + TQ_OBJECT + + +public: + + enum RenderingMode + { + NoneRendering=0, + PreviewRendering, + FinalRendering + }; + +public: + + EditorToolThreaded(TQObject *parent); + virtual ~EditorToolThreaded(); + + /** Set the small text to show in editor status progress bar during + tool computation. If it's not set, tool name is used instead. + */ + void setProgressMessage(const TQString& mess); + + /** return the current tool rendering mode. + */ + RenderingMode renderingMode() const; + +public slots: + + virtual void slotAbort(); + +protected: + + DImgThreadedFilter* filter() const; + void setFilter(DImgThreadedFilter *filter); + + void customEvent(TQCustomEvent *event); + + virtual void setToolView(TQWidget *view); + virtual void prepareEffect(){}; + virtual void prepareFinal(){}; + virtual void putPreviewData(){}; + virtual void putFinalData(){}; + virtual void renderingFinished(){}; + +protected slots: + + virtual void slotOk(); + virtual void slotCancel(); + virtual void slotEffect(); + +private slots: + + void slotResized(); + +private: + + EditorToolThreadedPriv *d; +}; + +} //namespace Digikam + +#endif /* IMAGEPLUGIN_H */ diff --git a/src/utilities/imageeditor/editor/editortooliface.cpp b/src/utilities/imageeditor/editor/editortooliface.cpp new file mode 100644 index 00000000..f666bbf2 --- /dev/null +++ b/src/utilities/imageeditor/editor/editortooliface.cpp @@ -0,0 +1,147 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : Image editor interface used by editor tools. + * + * Copyright (C) 2008-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include + +// Local includes. + +#include "sidebar.h" +#include "canvas.h" +#include "statusprogressbar.h" +#include "editortool.h" +#include "editortoolsettings.h" +#include "editorstackview.h" +#include "editorwindow.h" +#include "editortooliface.h" +#include "editortooliface.moc" + +namespace Digikam +{ + +class EditorToolIfacePriv +{ + +public: + + EditorToolIfacePriv() + { + prevTab = 0; + editor = 0; + tool = 0; + } + + TQWidget *prevTab; + + EditorTool *tool; + + EditorWindow *editor; +}; + +EditorToolIface* EditorToolIface::m_iface = 0; + +EditorToolIface* EditorToolIface::editorToolIface() +{ + return m_iface; +} + +EditorToolIface::EditorToolIface(EditorWindow *editor) + : TQObject() +{ + d = new EditorToolIfacePriv; + d->editor = editor; + m_iface = this; +} + +EditorToolIface::~EditorToolIface() +{ + delete d; + if (m_iface == this) + m_iface = 0; +} + +EditorTool* EditorToolIface::currentTool() const +{ + return d->tool; +} + +void EditorToolIface::loadTool(EditorTool* tool) +{ + if (d->tool) unLoadTool(); + + d->tool = tool; + d->editor->editorStackView()->setToolView(d->tool->toolView()); + d->editor->editorStackView()->setViewMode(EditorStackView::ToolViewMode); + d->prevTab = d->editor->rightSideBar()->getActiveTab(); + d->editor->rightSideBar()->appendTab(d->tool->toolSettings(), d->tool->toolIcon(), d->tool->toolName()); + d->editor->rightSideBar()->setActiveTab(d->tool->toolSettings()); + d->editor->toggleActions(false); + + // If editor tool has zoomable preview, switch on zoom actions. + if (d->editor->editorStackView()->previewWidget()) + d->editor->toggleZoomActions(true); +} + +void EditorToolIface::unLoadTool() +{ + if (!d->tool) return; + + d->editor->editorStackView()->setViewMode(EditorStackView::CanvasMode); + d->editor->editorStackView()->setToolView(0); + d->editor->rightSideBar()->deleteTab(d->tool->toolSettings()); + d->editor->rightSideBar()->setActiveTab(d->prevTab); + d->editor->toggleActions(true); + // To restore canvas zoom level in zoom combobox. + if (!d->editor->editorStackView()->canvas()->fitToWindow()) + d->editor->editorStackView()->setZoomFactor(d->editor->editorStackView()->canvas()->zoomFactor()); + delete d->tool; + d->tool = 0; +} + +void EditorToolIface::setToolStartProgress(const TQString& toolName) +{ + d->editor->setToolStartProgress(toolName); + if (d->editor->editorStackView()->previewWidget()) + d->editor->toggleZoomActions(false); +} + +void EditorToolIface::setToolProgress(int progress) +{ + d->editor->setToolProgress(progress); +} + +void EditorToolIface::setToolStopProgress() +{ + d->editor->setToolStopProgress(); + if (d->editor->editorStackView()->previewWidget()) + d->editor->toggleZoomActions(true); +} + +void EditorToolIface::slotToolAborted() +{ + EditorToolThreaded *tool = dynamic_cast(d->tool); + if (tool) tool->slotAbort(); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/editor/editortooliface.h b/src/utilities/imageeditor/editor/editortooliface.h new file mode 100644 index 00000000..ce8708cf --- /dev/null +++ b/src/utilities/imageeditor/editor/editortooliface.h @@ -0,0 +1,76 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : Image editor interface used by editor tools. + * + * Copyright (C) 2008-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORTOOLIFACE_H +#define EDITORTOOLIFACE_H + +// TQt includes. + +#include + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class EditorTool; +class EditorWindow; +class EditorToolIfacePriv; + +class DIGIKAM_EXPORT EditorToolIface : public TQObject +{ + TQ_OBJECT + + +public: + + static EditorToolIface* editorToolIface(); + + EditorToolIface(EditorWindow *editor); + ~EditorToolIface(); + + EditorTool* currentTool() const; + + void loadTool(EditorTool* tool); + void unLoadTool(); + + void setToolStartProgress(const TQString& toolName); + void setToolProgress(int progress); + void setToolStopProgress(); + +public slots: + + void slotToolAborted(); + +private: + + static EditorToolIface *m_iface; + + EditorToolIfacePriv *d; +}; + +} // namespace Digikam + +#endif /* EDITORTOOLIFACE_H */ diff --git a/src/utilities/imageeditor/editor/editortoolsettings.cpp b/src/utilities/imageeditor/editor/editortoolsettings.cpp new file mode 100644 index 00000000..3ac45ccf --- /dev/null +++ b/src/utilities/imageeditor/editor/editortoolsettings.cpp @@ -0,0 +1,331 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-21 + * Description : Editor tool settings template box + * + * Copyright (C) 2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include +#include +#include +#include +#include +#include +#include + +// KDE includes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// LibKDcraw includes. + +#include + +// Local includes. + +#include "ddebug.h" +#include "imagepaniconwidget.h" +#include "editortoolsettings.h" +#include "editortoolsettings.moc" + +using namespace KDcrawIface; + +namespace Digikam +{ + +class EditorToolSettingsPriv +{ + +public: + + EditorToolSettingsPriv() + { + okBtn = 0; + cancelBtn = 0; + tryBtn = 0; + defaultBtn = 0; + mainVBox = 0; + plainPage = 0; + btnBox1 = 0; + btnBox2 = 0; + btnBox3 = 0; + saveAsBtn = 0; + loadBtn = 0; + guideBox = 0; + guideColorBt = 0; + guideSize = 0; + panIconView = 0; + } + + TQHBox *btnBox1; + TQHBox *btnBox2; + TQHBox *btnBox3; + TQHBox *guideBox; + + TQVBox *mainVBox; + TQWidget *plainPage; + + KPushButton *okBtn; + KPushButton *cancelBtn; + KPushButton *tryBtn; + KPushButton *defaultBtn; + KPushButton *saveAsBtn; + KPushButton *loadBtn; + + KColorButton *guideColorBt; + + ImagePanIconWidget *panIconView; + + RIntNumInput *guideSize; +}; + +EditorToolSettings::EditorToolSettings(int buttonMask, int toolMask, TQWidget *parent) + : TQScrollView(parent) +{ + d = new EditorToolSettingsPriv; + + viewport()->setBackgroundMode(TQt::PaletteBackground); + setResizePolicy(TQScrollView::AutoOneFit); + setFrameStyle(TQFrame::NoFrame); + + d->mainVBox = new TQVBox(viewport()); + addChild(d->mainVBox); + + // --------------------------------------------------------------- + + TQFrame *frame = new TQFrame(d->mainVBox); + frame->setFrameStyle(TQFrame::Panel|TQFrame::Sunken); + TQVBoxLayout* vlay = new TQVBoxLayout(frame, 5, 0); + d->panIconView = new ImagePanIconWidget(360, 240, frame); + TQWhatsThis::add(d->panIconView, i18n("

Here you can see the original image panel " + "which can help you to select the clip preview." + "

Click and drag the mouse cursor in the " + "red rectangle to change the clip focus.")); + vlay->addWidget(d->panIconView, 0, TQt::AlignCenter); + + if (!(toolMask & PanIcon)) + frame->hide(); + + // --------------------------------------------------------------- + + d->plainPage = new TQWidget(d->mainVBox); + d->guideBox = new TQHBox(d->mainVBox); + d->btnBox1 = new TQHBox(d->mainVBox); + d->btnBox2 = new TQHBox(d->mainVBox); + + // --------------------------------------------------------------- + + new TQLabel(i18n("Guide:"), d->guideBox); + TQLabel *space4 = new TQLabel(d->guideBox); + d->guideColorBt = new KColorButton(TQColor(TQt::red), d->guideBox); + TQWhatsThis::add(d->guideColorBt, i18n("

Set here the color used to draw guides dashed-lines.")); + d->guideSize = new RIntNumInput(d->guideBox); + d->guideSize->setRange(1, 5, 1); + d->guideSize->setDefaultValue(1); + TQWhatsThis::add(d->guideSize, i18n("

Set here the width in pixels used to draw guides dashed-lines.")); + + d->guideBox->setStretchFactor(space4, 10); + d->guideBox->setSpacing(spacingHint()); + d->guideBox->setMargin(0); + + if (!(toolMask & ColorGuide)) + d->guideBox->hide(); + + // --------------------------------------------------------------- + + d->defaultBtn = new KPushButton(d->btnBox1); + d->defaultBtn->setGuiItem(KStdGuiItem::defaults()); + d->defaultBtn->setIconSet(SmallIconSet("reload_page")); + TQToolTip::add(d->defaultBtn, i18n("

Reset all settings to their default values.")); + if (!(buttonMask & Default)) + d->defaultBtn->hide(); + + TQLabel *space = new TQLabel(d->btnBox1); + + d->okBtn = new KPushButton(d->btnBox1); + d->okBtn->setGuiItem(KStdGuiItem::ok()); + if (!(buttonMask & Ok)) + d->okBtn->hide(); + + d->cancelBtn = new KPushButton(d->btnBox1); + d->cancelBtn->setGuiItem(KStdGuiItem::cancel()); + if (!(buttonMask & Cancel)) + d->cancelBtn->hide(); + + d->btnBox1->setStretchFactor(space, 10); + d->btnBox1->setSpacing(spacingHint()); + d->btnBox1->setMargin(0); + + if (!(buttonMask & Default) && !(buttonMask & Ok) && !(buttonMask & Cancel)) + d->btnBox1->hide(); + + // --------------------------------------------------------------- + + d->loadBtn = new KPushButton(d->btnBox2); + d->loadBtn->setGuiItem(KStdGuiItem::open()); + d->loadBtn->setText(i18n("Load...")); + TQToolTip::add(d->loadBtn, i18n("

Load all parameters from settings text file.")); + if (!(buttonMask & Load)) + d->loadBtn->hide(); + + d->saveAsBtn = new KPushButton(d->btnBox2); + d->saveAsBtn->setGuiItem(KStdGuiItem::saveAs()); + TQToolTip::add(d->saveAsBtn, i18n("

Save all parameters to settings text file.")); + if (!(buttonMask & SaveAs)) + d->saveAsBtn->hide(); + + TQLabel *space2 = new TQLabel(d->btnBox2); + + d->tryBtn = new KPushButton(d->btnBox2); + d->tryBtn->setGuiItem(KStdGuiItem::apply()); + d->tryBtn->setText(i18n("Try")); + TQToolTip::add(d->tryBtn, i18n("

Try all settings.")); + if (!(buttonMask & Try)) + d->tryBtn->hide(); + + d->btnBox2->setStretchFactor(space2, 10); + d->btnBox2->setSpacing(spacingHint()); + d->btnBox2->setMargin(0); + + if (!(buttonMask & Load) && !(buttonMask & SaveAs) && !(buttonMask & Try)) + d->btnBox2->hide(); + + // --------------------------------------------------------------- + + connect(d->okBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalOkClicked())); + + connect(d->cancelBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalCancelClicked())); + + connect(d->tryBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalTryClicked())); + + connect(d->defaultBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalDefaultClicked())); + + connect(d->saveAsBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalSaveAsClicked())); + + connect(d->loadBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalLoadClicked())); + + connect(d->guideColorBt, TQ_SIGNAL(changed(const TQColor&)), + this, TQ_SIGNAL(signalColorGuideChanged())); + + connect(d->guideSize, TQ_SIGNAL(valueChanged(int)), + this, TQ_SIGNAL(signalColorGuideChanged())); +} + +EditorToolSettings::~EditorToolSettings() +{ + delete d; +} + +TQSize EditorToolSettings::minimumSizeHint() const +{ + // Editor Tools usually require a larger horizontal space than other widgets in right side bar + // Set scroll area to a horizontal minimum size sufficient for the settings. + // Do not touch vertical size hint. + // Limit to 40% of the desktop width. + TQSize hint = TQScrollView::minimumSizeHint(); + TQRect desktopRect = TDEGlobalSettings::desktopGeometry(d->mainVBox); + hint.setWidth(TQMIN(d->mainVBox->minimumSizeHint().width(), desktopRect.width() * 2 / 5)); + return hint; +} + +int EditorToolSettings::marginHint() +{ + return KDialog::marginHint(); +} + +int EditorToolSettings::spacingHint() +{ + return KDialog::spacingHint(); +} + +TQWidget *EditorToolSettings::plainPage() const +{ + return d->plainPage; +} + +ImagePanIconWidget* EditorToolSettings::panIconView() const +{ + return d->panIconView; +} + +KPushButton* EditorToolSettings::button(int buttonCode) const +{ + if (buttonCode & Default) + return d->defaultBtn; + + if (buttonCode & Try) + return d->tryBtn; + + if (buttonCode & Ok) + return d->okBtn; + + if (buttonCode & Cancel) + return d->cancelBtn; + + if (buttonCode & Load) + return d->loadBtn; + + if (buttonCode & SaveAs) + return d->saveAsBtn; + + return 0; +} + +void EditorToolSettings::enableButton(int buttonCode, bool state) +{ + KPushButton *btn = button(buttonCode); + if (btn) btn->setEnabled(state); +} + +TQColor EditorToolSettings::guideColor() const +{ + return d->guideColorBt->color(); +} + +void EditorToolSettings::setGuideColor(const TQColor& color) +{ + d->guideColorBt->setColor(color); +} + +int EditorToolSettings::guideSize() const +{ + return d->guideSize->value(); +} + +void EditorToolSettings::setGuideSize(int size) +{ + d->guideSize->setValue(size); +} + +} // NameSpace Digikam diff --git a/src/utilities/imageeditor/editor/editortoolsettings.h b/src/utilities/imageeditor/editor/editortoolsettings.h new file mode 100644 index 00000000..062b2e34 --- /dev/null +++ b/src/utilities/imageeditor/editor/editortoolsettings.h @@ -0,0 +1,110 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-21 + * Description : Editor tool settings template box + * + * Copyright (C) 2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORTOOLSETTINGS_H +#define EDITORTOOLSETTINGS_H + +// TQt includes. + +#include + +// Local includes. + +#include "digikam_export.h" + +class KPushButton; + +namespace Digikam +{ + +class ImagePanIconWidget; +class EditorToolSettingsPriv; + +class DIGIKAM_EXPORT EditorToolSettings : public TQScrollView +{ + TQ_OBJECT + + +public: + + enum ButtonCode + { + Default = 0x00000001, + Try = 0x00000002, + Ok = 0x00000004, + Cancel = 0x00000008, + SaveAs = 0x00000010, + Load = 0x00000020 + }; + + enum ToolCode + { + NoTool = 0x00000001, + ColorGuide = 0x00000002, + PanIcon = 0x00000004 + }; + +public: + + EditorToolSettings(int buttonMask, int toolMask=NoTool, TQWidget *parent=0); + ~EditorToolSettings(); + + virtual void setBusy(bool){}; + virtual void writeSettings(){}; + virtual void readSettings(){}; + virtual void resetSettings(){}; + + int marginHint(); + int spacingHint(); + + TQWidget *plainPage() const; + + TQColor guideColor() const; + void setGuideColor(const TQColor& color); + + int guideSize() const; + void setGuideSize(int size); + + ImagePanIconWidget* panIconView() const; + KPushButton* button(int buttonCode) const; + void enableButton(int buttonCode, bool state); + + virtual TQSize minimumSizeHint() const; + +signals: + + void signalOkClicked(); + void signalCancelClicked(); + void signalTryClicked(); + void signalDefaultClicked(); + void signalSaveAsClicked(); + void signalLoadClicked(); + void signalColorGuideChanged(); + +private: + + EditorToolSettingsPriv *d; +}; + +} // NameSpace Digikam + +#endif // EDITORTOOLSETTINGS_H diff --git a/src/utilities/imageeditor/editor/editorwindow.cpp b/src/utilities/imageeditor/editor/editorwindow.cpp new file mode 100644 index 00000000..eed7cfea --- /dev/null +++ b/src/utilities/imageeditor/editor/editorwindow.cpp @@ -0,0 +1,1932 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-20 + * Description : main image editor GUI implementation + * + * Copyright (C) 2006-2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C Ansi includes. + +extern "C" +{ +#include +#include +} + +// C++ includes. + +#include + +// TQt includes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE includes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes. + +#include "ddebug.h" +#include "dpopupmenu.h" +#include "canvas.h" +#include "dimginterface.h" +#include "imagedialog.h" +#include "imageplugin.h" +#include "imagepluginloader.h" +#include "imageresize.h" +#include "imageprint.h" +#include "filesaveoptionsbox.h" +#include "statusprogressbar.h" +#include "iccsettingscontainer.h" +#include "exposurecontainer.h" +#include "iofilesettingscontainer.h" +#include "savingcontextcontainer.h" +#include "loadingcacheinterface.h" +#include "slideshowsettings.h" +#include "themeengine.h" +#include "rawcameradlg.h" +#include "editorstackview.h" +#include "editortooliface.h" +#include "editorwindowprivate.h" +#include "editorwindow.h" +#include "editorwindow.moc" + +void tqt_enter_modal( TQWidget *widget ); +void tqt_leave_modal( TQWidget *widget ); + +namespace Digikam +{ + +EditorWindow::EditorWindow(const char *name) + : TDEMainWindow(0, name, WType_TopLevel) +{ + d = new EditorWindowPriv; + + m_themeMenuAction = 0; + m_contextMenu = 0; + m_canvas = 0; + m_imagePluginLoader = 0; + m_undoAction = 0; + m_redoAction = 0; + m_fullScreenAction = 0; + m_saveAction = 0; + m_saveAsAction = 0; + m_revertAction = 0; + m_fileDeleteAction = 0; + m_forwardAction = 0; + m_backwardAction = 0; + m_firstAction = 0; + m_lastAction = 0; + m_undoAction = 0; + m_redoAction = 0; + m_stackView = 0; + m_fullScreen = false; + m_rotatedOrFlipped = false; + m_setExifOrientationTag = true; + m_cancelSlideShow = false; + + // Settings containers instance. + + d->ICCSettings = new ICCSettingsContainer(); + d->exposureSettings = new ExposureSettingsContainer(); + d->toolIface = new EditorToolIface(this); + m_IOFileSettings = new IOFileSettingsContainer(); + m_savingContext = new SavingContextContainer(); +} + +EditorWindow::~EditorWindow() +{ + delete m_canvas; + delete m_IOFileSettings; + delete m_savingContext; + delete d->ICCSettings; + delete d->exposureSettings; + delete d; +} + +EditorStackView* EditorWindow::editorStackView() const +{ + return m_stackView; +} + +void EditorWindow::setupContextMenu() +{ + m_contextMenu = new DPopupMenu(this); + TDEActionCollection *ac = actionCollection(); + if( ac->action("editorwindow_backward") ) ac->action("editorwindow_backward")->plug(m_contextMenu); + if( ac->action("editorwindow_forward") ) ac->action("editorwindow_forward")->plug(m_contextMenu); + m_contextMenu->insertSeparator(); + if( ac->action("editorwindow_slideshow") ) ac->action("editorwindow_slideshow")->plug(m_contextMenu); + if( ac->action("editorwindow_rotate_left") ) ac->action("editorwindow_rotate_left")->plug(m_contextMenu); + if( ac->action("editorwindow_rotate_right") ) ac->action("editorwindow_rotate_right")->plug(m_contextMenu); + if( ac->action("editorwindow_crop") ) ac->action("editorwindow_crop")->plug(m_contextMenu); + m_contextMenu->insertSeparator(); + if( ac->action("editorwindow_delete") ) ac->action("editorwindow_delete")->plug(m_contextMenu); +} + +void EditorWindow::setupStandardConnections() +{ + // -- Canvas connections ------------------------------------------------ + + connect(m_canvas, TQ_SIGNAL(signalToggleOffFitToWindow()), + this, TQ_SLOT(slotToggleOffFitToWindow())); + + connect(m_canvas, TQ_SIGNAL(signalShowNextImage()), + this, TQ_SLOT(slotForward())); + + connect(m_canvas, TQ_SIGNAL(signalShowPrevImage()), + this, TQ_SLOT(slotBackward())); + + connect(m_canvas, TQ_SIGNAL(signalRightButtonClicked()), + this, TQ_SLOT(slotContextMenu())); + + connect(m_stackView, TQ_SIGNAL(signalZoomChanged(bool, bool, double)), + this, TQ_SLOT(slotZoomChanged(bool, bool, double))); + + connect(m_canvas, TQ_SIGNAL(signalChanged()), + this, TQ_SLOT(slotChanged())); + + connect(m_canvas, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)), + this, TQ_SLOT(slotUndoStateChanged(bool, bool, bool))); + + connect(m_canvas, TQ_SIGNAL(signalSelected(bool)), + this, TQ_SLOT(slotSelected(bool))); + + connect(m_canvas, TQ_SIGNAL(signalPrepareToLoad()), + this, TQ_SLOT(slotPrepareToLoad())); + + connect(m_canvas, TQ_SIGNAL(signalLoadingStarted(const TQString &)), + this, TQ_SLOT(slotLoadingStarted(const TQString &))); + + connect(m_canvas, TQ_SIGNAL(signalLoadingFinished(const TQString &, bool)), + this, TQ_SLOT(slotLoadingFinished(const TQString &, bool))); + + connect(m_canvas, TQ_SIGNAL(signalLoadingProgress(const TQString &, float)), + this, TQ_SLOT(slotLoadingProgress(const TQString &, float))); + + connect(m_canvas, TQ_SIGNAL(signalSavingStarted(const TQString&)), + this, TQ_SLOT(slotSavingStarted(const TQString&))); + + connect(m_canvas, TQ_SIGNAL(signalSavingFinished(const TQString&, bool)), + this, TQ_SLOT(slotSavingFinished(const TQString&, bool))); + + connect(m_canvas, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), + this, TQ_SLOT(slotSavingProgress(const TQString&, float))); + + connect(m_canvas, TQ_SIGNAL(signalSelectionChanged(const TQRect&)), + this, TQ_SLOT(slotSelectionChanged(const TQRect&))); + + // -- if rotating/flipping set the rotatedflipped flag to true ----------- + + connect(d->rotateLeftAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + connect(d->rotateRightAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + connect(d->flipHorizAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + connect(d->flipVertAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + // -- status bar connections -------------------------------------- + + connect(m_nameLabel, TQ_SIGNAL(signalCancelButtonPressed()), + this, TQ_SLOT(slotNameLabelCancelButtonPressed())); + + connect(m_nameLabel, TQ_SIGNAL(signalCancelButtonPressed()), + d->toolIface, TQ_SLOT(slotToolAborted())); +} + +void EditorWindow::setupStandardActions() +{ + // -- Standard 'File' menu actions --------------------------------------------- + + m_backwardAction = KStdAction::back(this, TQ_SLOT(slotBackward()), + actionCollection(), "editorwindow_backward"); + + m_forwardAction = KStdAction::forward(this, TQ_SLOT(slotForward()), + actionCollection(), "editorwindow_forward"); + + m_firstAction = new TDEAction(i18n("&First"), "go-first", + TDEStdAccel::shortcut( TDEStdAccel::Home), + this, TQ_SLOT(slotFirst()), + actionCollection(), "editorwindow_first"); + + m_lastAction = new TDEAction(i18n("&Last"), "go-last", + TDEStdAccel::shortcut( TDEStdAccel::End), + this, TQ_SLOT(slotLast()), + actionCollection(), "editorwindow_last"); + + m_saveAction = KStdAction::save(this, TQ_SLOT(slotSave()), + actionCollection(), "editorwindow_save"); + + m_saveAsAction = KStdAction::saveAs(this, TQ_SLOT(slotSaveAs()), + actionCollection(), "editorwindow_saveas"); + + m_revertAction = KStdAction::revert(this, TQ_SLOT(slotRevert()), + actionCollection(), "editorwindow_revert"); + + m_saveAction->setEnabled(false); + m_saveAsAction->setEnabled(false); + m_revertAction->setEnabled(false); + + d->filePrintAction = new TDEAction(i18n("Print Image..."), "document-print", + CTRL+Key_P, + this, TQ_SLOT(slotFilePrint()), + actionCollection(), "editorwindow_print"); + + m_fileDeleteAction = new TDEAction(i18n("Move to Trash"), "edittrash", + Key_Delete, + this, TQ_SLOT(slotDeleteCurrentItem()), + actionCollection(), "editorwindow_delete"); + + KStdAction::close(this, TQ_SLOT(close()), actionCollection(), "editorwindow_close"); + + // -- Standard 'Edit' menu actions --------------------------------------------- + + d->copyAction = KStdAction::copy(m_canvas, TQ_SLOT(slotCopy()), + actionCollection(), "editorwindow_copy"); + + d->copyAction->setEnabled(false); + + m_undoAction = new TDEToolBarPopupAction(i18n("Undo"), "edit-undo", + TDEStdAccel::shortcut(TDEStdAccel::Undo), + m_canvas, TQ_SLOT(slotUndo()), + actionCollection(), "editorwindow_undo"); + + connect(m_undoAction->popupMenu(), TQ_SIGNAL(aboutToShow()), + this, TQ_SLOT(slotAboutToShowUndoMenu())); + + connect(m_undoAction->popupMenu(), TQ_SIGNAL(activated(int)), + m_canvas, TQ_SLOT(slotUndo(int))); + + m_undoAction->setEnabled(false); + + m_redoAction = new TDEToolBarPopupAction(i18n("Redo"), "edit-redo", + TDEStdAccel::shortcut(TDEStdAccel::Redo), + m_canvas, TQ_SLOT(slotRedo()), + actionCollection(), "editorwindow_redo"); + + connect(m_redoAction->popupMenu(), TQ_SIGNAL(aboutToShow()), + this, TQ_SLOT(slotAboutToShowRedoMenu())); + + connect(m_redoAction->popupMenu(), TQ_SIGNAL(activated(int)), + m_canvas, TQ_SLOT(slotRedo(int))); + + m_redoAction->setEnabled(false); + + d->selectAllAction = new TDEAction(i18n("Select All"), + 0, + CTRL+Key_A, + m_canvas, + TQ_SLOT(slotSelectAll()), + actionCollection(), + "editorwindow_selectAll"); + + d->selectNoneAction = new TDEAction(i18n("Select None"), + 0, + CTRL+SHIFT+Key_A, + m_canvas, + TQ_SLOT(slotSelectNone()), + actionCollection(), + "editorwindow_selectNone"); + + // -- Standard 'View' menu actions --------------------------------------------- + + d->zoomPlusAction = KStdAction::zoomIn(this, TQ_SLOT(slotIncreaseZoom()), + actionCollection(), "editorwindow_zoomplus"); + + d->zoomMinusAction = KStdAction::zoomOut(this, TQ_SLOT(slotDecreaseZoom()), + actionCollection(), "editorwindow_zoomminus"); + + d->zoomTo100percents = new TDEAction(i18n("Zoom to 100%"), "zoom-original", + ALT+CTRL+Key_0, // NOTE: Photoshop 7 use ALT+CTRL+0. + this, TQ_SLOT(slotZoomTo100Percents()), + actionCollection(), "editorwindow_zoomto100percents"); + + + d->zoomFitToWindowAction = new TDEToggleAction(i18n("Fit to &Window"), "view_fit_window", + CTRL+SHIFT+Key_E, // NOTE: Gimp 2 use CTRL+SHIFT+E. + this, TQ_SLOT(slotToggleFitToWindow()), + actionCollection(), "editorwindow_zoomfit2window"); + + d->zoomFitToSelectAction = new TDEAction(i18n("Fit to &Selection"), "zoom-fit-best", + ALT+CTRL+Key_S, this, TQ_SLOT(slotFitToSelect()), + actionCollection(), "editorwindow_zoomfit2select"); + d->zoomFitToSelectAction->setEnabled(false); + d->zoomFitToSelectAction->setWhatsThis(i18n("This option can be used to zoom the image to the " + "current selection area.")); + + d->zoomCombo = new KComboBox(true); + d->zoomCombo->setDuplicatesEnabled(false); + d->zoomCombo->setFocusPolicy(TQWidget::ClickFocus); + d->zoomCombo->setInsertionPolicy(TQComboBox::NoInsertion); + d->zoomComboAction = new KWidgetAction(d->zoomCombo, i18n("Zoom"), 0, 0, 0, + actionCollection(), "editorwindow_zoomto"); + + d->zoomCombo->insertItem(TQString("10%")); + d->zoomCombo->insertItem(TQString("25%")); + d->zoomCombo->insertItem(TQString("50%")); + d->zoomCombo->insertItem(TQString("75%")); + d->zoomCombo->insertItem(TQString("100%")); + d->zoomCombo->insertItem(TQString("150%")); + d->zoomCombo->insertItem(TQString("200%")); + d->zoomCombo->insertItem(TQString("300%")); + d->zoomCombo->insertItem(TQString("450%")); + d->zoomCombo->insertItem(TQString("600%")); + d->zoomCombo->insertItem(TQString("800%")); + d->zoomCombo->insertItem(TQString("1200%")); + + connect(d->zoomCombo, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotZoomSelected()) ); + + connect(d->zoomCombo, TQ_SIGNAL(returnPressed(const TQString&)), + this, TQ_SLOT(slotZoomTextChanged(const TQString &)) ); + + // Do not use std KDE action for full screen because action text is too large for app. toolbar. + m_fullScreenAction = new TDEToggleAction(i18n("Full Screen"), "view-fullscreen", + CTRL+SHIFT+Key_F, this, + TQ_SLOT(slotToggleFullScreen()), + actionCollection(), "editorwindow_fullscreen"); + m_fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode")); + + d->slideShowAction = new TDEAction(i18n("Slideshow"), "slideshow", Key_F9, + this, TQ_SLOT(slotToggleSlideShow()), + actionCollection(),"editorwindow_slideshow"); + + d->viewUnderExpoAction = new TDEToggleAction(i18n("Under-Exposure Indicator"), "underexposure", + Key_F10, this, + TQ_SLOT(slotToggleUnderExposureIndicator()), + actionCollection(),"editorwindow_underexposure"); + + d->viewOverExpoAction = new TDEToggleAction(i18n("Over-Exposure Indicator"), "overexposure", + Key_F11, this, + TQ_SLOT(slotToggleOverExposureIndicator()), + actionCollection(),"editorwindow_overexposure"); + + d->viewCMViewAction = new TDEToggleAction(i18n("Color Managed View"), "tv", + Key_F12, this, + TQ_SLOT(slotToggleColorManagedView()), + actionCollection(),"editorwindow_cmview"); + + // -- Standard 'Transform' menu actions --------------------------------------------- + + d->resizeAction = new TDEAction(i18n("&Resize..."), "resize_image", 0, + this, TQ_SLOT(slotResize()), + actionCollection(), "editorwindow_resize"); + + d->cropAction = new TDEAction(i18n("Crop"), "crop", + CTRL+Key_X, + m_canvas, TQ_SLOT(slotCrop()), + actionCollection(), "editorwindow_crop"); + + d->cropAction->setEnabled(false); + d->cropAction->setWhatsThis(i18n("This option can be used to crop the image. " + "Select a region of the image to enable this action.")); + + // -- Standard 'Flip' menu actions --------------------------------------------- + + d->flipHorizAction = new TDEAction(i18n("Flip Horizontally"), "mirror", CTRL+Key_Asterisk, + m_canvas, TQ_SLOT(slotFlipHoriz()), + actionCollection(), "editorwindow_flip_horiz"); + d->flipHorizAction->setEnabled(false); + + d->flipVertAction = new TDEAction(i18n("Flip Vertically"), "flip", CTRL+Key_Slash, + m_canvas, TQ_SLOT(slotFlipVert()), + actionCollection(), "editorwindow_flip_vert"); + d->flipVertAction->setEnabled(false); + + // -- Standard 'Rotate' menu actions ---------------------------------------- + + d->rotateLeftAction = new TDEAction(i18n("Rotate Left"), + "object-rotate-left", SHIFT+CTRL+Key_Left, + m_canvas, TQ_SLOT(slotRotate270()), + actionCollection(), + "editorwindow_rotate_left"); + d->rotateLeftAction->setEnabled(false); + d->rotateRightAction = new TDEAction(i18n("Rotate Right"), + "object-rotate-right", SHIFT+CTRL+Key_Right, + m_canvas, TQ_SLOT(slotRotate90()), + actionCollection(), + "editorwindow_rotate_right"); + d->rotateRightAction->setEnabled(false); + + // -- Standard 'Configure' menu actions ---------------------------------------- + + d->showMenuBarAction = KStdAction::showMenubar(this, TQ_SLOT(slotShowMenuBar()), actionCollection()); + + KStdAction::keyBindings(this, TQ_SLOT(slotEditKeys()), actionCollection()); + KStdAction::configureToolbars(this, TQ_SLOT(slotConfToolbars()), actionCollection()); + KStdAction::preferences(this, TQ_SLOT(slotSetup()), actionCollection()); + + // ----------------------------------------------------------------------------------------- + + m_themeMenuAction = new TDESelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu"); + m_themeMenuAction->setItems(ThemeEngine::instance()->themeNames()); + + connect(m_themeMenuAction, TQ_SIGNAL(activated(const TQString&)), + this, TQ_SLOT(slotChangeTheme(const TQString&))); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + // -- Standard 'Help' menu actions --------------------------------------------- + + d->donateMoneyAction = new TDEAction(i18n("Donate..."), + 0, 0, + this, TQ_SLOT(slotDonateMoney()), + actionCollection(), + "editorwindow_donatemoney"); + + d->contributeAction = new TDEAction(i18n("Contribute..."), + 0, 0, + this, TQ_SLOT(slotContribute()), + actionCollection(), + "editorwindow_contribute"); + + d->rawCameraListAction = new TDEAction(i18n("Supported RAW Cameras"), + "kdcraw", + 0, + this, + TQ_SLOT(slotRawCameraList()), + actionCollection(), + "editorwindow_rawcameralist"); +} + +void EditorWindow::setupStandardAccelerators() +{ + d->accelerators = new TDEAccel(this); + + d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"), + i18n("Exit out of the fullscreen mode"), + Key_Escape, this, TQ_SLOT(slotEscapePressed()), + false, true); + + d->accelerators->insert("Next Image Key_Space", i18n("Next Image"), + i18n("Load Next Image"), + Key_Space, this, TQ_SLOT(slotForward()), + false, true); + + d->accelerators->insert("Previous Image SHIFT+Key_Space", i18n("Previous Image"), + i18n("Load Previous Image"), + SHIFT+Key_Space, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Previous Image Key_Backspace", i18n("Previous Image"), + i18n("Load Previous Image"), + Key_Backspace, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Next Image Key_Next", i18n("Next Image"), + i18n("Load Next Image"), + Key_Next, this, TQ_SLOT(slotForward()), + false, true); + + d->accelerators->insert("Previous Image Key_Prior", i18n("Previous Image"), + i18n("Load Previous Image"), + Key_Prior, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Zoom Plus Key_Plus", i18n("Zoom In"), + i18n("Zoom in on Image"), + Key_Plus, this, TQ_SLOT(slotIncreaseZoom()), + false, true); + + d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom Out"), + i18n("Zoom out of Image"), + Key_Minus, this, TQ_SLOT(slotDecreaseZoom()), + false, true); + + d->accelerators->insert("Redo CTRL+Key_Y", i18n("Redo"), + i18n("Redo Last action"), + CTRL+Key_Y, m_canvas, TQ_SLOT(slotRedo()), + false, true); +} + +void EditorWindow::setupStatusBar() +{ + m_nameLabel = new StatusProgressBar(statusBar()); + m_nameLabel->setAlignment(TQt::AlignCenter); + m_nameLabel->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(m_nameLabel, 100); + + d->selectLabel = new TQLabel(i18n("No selection"), statusBar()); + d->selectLabel->setAlignment(TQt::AlignCenter); + d->selectLabel->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(d->selectLabel, 100); + TQToolTip::add(d->selectLabel, i18n("Information about current selection area")); + + m_resLabel = new TQLabel(statusBar()); + m_resLabel->setAlignment(TQt::AlignCenter); + m_resLabel->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(m_resLabel, 100); + TQToolTip::add(m_resLabel, i18n("Information about image size")); + + d->underExposureIndicator = new TQToolButton(statusBar()); + d->underExposureIndicator->setIconSet(SmallIcon("underexposure")); + d->underExposureIndicator->setToggleButton(true); + statusBar()->addWidget(d->underExposureIndicator, 1); + + d->overExposureIndicator = new TQToolButton(statusBar()); + d->overExposureIndicator->setIconSet(SmallIcon("overexposure")); + d->overExposureIndicator->setToggleButton(true); + statusBar()->addWidget(d->overExposureIndicator, 1); + + d->cmViewIndicator = new TQToolButton(statusBar()); + d->cmViewIndicator->setIconSet(SmallIcon("tv")); + d->cmViewIndicator->setToggleButton(true); + statusBar()->addWidget(d->cmViewIndicator, 1); + + connect(d->underExposureIndicator, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotToggleUnderExposureIndicator())); + + connect(d->overExposureIndicator, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotToggleOverExposureIndicator())); + + connect(d->cmViewIndicator, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotToggleColorManagedView())); +} + +void EditorWindow::printImage(KURL url) +{ + uchar* ptr = m_canvas->interface()->getImage(); + int w = m_canvas->interface()->origWidth(); + int h = m_canvas->interface()->origHeight(); + bool hasAlpha = m_canvas->interface()->hasAlpha(); + bool sixteenBit = m_canvas->interface()->sixteenBit(); + + if (!ptr || !w || !h) + return; + + DImg image(w, h, sixteenBit, hasAlpha, ptr); + + KPrinter printer; + TQString appName = TDEApplication::kApplication()->aboutData()->appName(); + printer.setDocName( url.filename() ); + printer.setCreator( appName ); +#if KDE_IS_VERSION(3,2,0) + printer.setUsePrinterResolution(true); +#endif + + KPrinter::addDialogPage( new ImageEditorPrintDialogPage(image, this, TQString(appName.append(" page")).ascii() )); + + if ( printer.setup( this, i18n("Print %1").arg(printer.docName().section('/', -1)) ) ) + { + ImagePrint printOperations(image, printer, url.filename()); + if (!printOperations.printImageWithTQt()) + { + KMessageBox::error(this, i18n("Failed to print file: '%1'") + .arg(url.filename())); + } + } +} + +void EditorWindow::slotEditKeys() +{ + KKeyDialog dialog(true, this); + dialog.insert( actionCollection(), i18n( "General" ) ); + + TQPtrList pluginList = ImagePluginLoader::instance()->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + dialog.insert( plugin->actionCollection(), plugin->name() ); + } + } + + dialog.configure(); +} + +void EditorWindow::slotResize() +{ + ImageResize dlg(this); + dlg.exec(); +} + +void EditorWindow::slotAboutToShowUndoMenu() +{ + m_undoAction->popupMenu()->clear(); + TQStringList titles; + m_canvas->getUndoHistory(titles); + + if(!titles.isEmpty()) + { + int id = 1; + TQStringList::Iterator iter = titles.begin(); + for(; iter != titles.end(); ++iter,++id) + { + m_undoAction->popupMenu()->insertItem(*iter, id); + } + } +} + +void EditorWindow::slotAboutToShowRedoMenu() +{ + m_redoAction->popupMenu()->clear(); + TQStringList titles; + m_canvas->getRedoHistory(titles); + + if(!titles.isEmpty()) + { + int id = 1; + TQStringList::Iterator iter = titles.begin(); + for(; iter != titles.end(); ++iter,++id) + { + m_redoAction->popupMenu()->insertItem(*iter, id); + } + } +} + +void EditorWindow::slotConfToolbars() +{ + saveMainWindowSettings(TDEGlobal::config(), "ImageViewer Settings"); + KEditToolbar dlg(factory(), this); + + connect(&dlg, TQ_SIGNAL(newToolbarConfig()), + this, TQ_SLOT(slotNewToolbarConfig())); + + dlg.exec(); +} + +void EditorWindow::slotNewToolbarConfig() +{ + applyMainWindowSettings(TDEGlobal::config(), "ImageViewer Settings"); +} + +void EditorWindow::slotIncreaseZoom() +{ + m_stackView->increaseZoom(); +} + +void EditorWindow::slotDecreaseZoom() +{ + m_stackView->decreaseZoom(); +} + +void EditorWindow::slotToggleFitToWindow() +{ + d->zoomPlusAction->setEnabled(true); + d->zoomComboAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + m_stackView->toggleFitToWindow(); +} + +void EditorWindow::slotFitToSelect() +{ + d->zoomPlusAction->setEnabled(true); + d->zoomComboAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + m_stackView->fitToSelect(); +} + +void EditorWindow::slotZoomTo100Percents() +{ + d->zoomPlusAction->setEnabled(true); + d->zoomComboAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + m_stackView->zoomTo100Percents(); +} + +void EditorWindow::slotZoomSelected() +{ + TQString txt = d->zoomCombo->currentText(); + txt = txt.left(txt.find('%')); + slotZoomTextChanged(txt); +} + +void EditorWindow::slotZoomTextChanged(const TQString &txt) +{ + bool r = false; + double zoom = TDEGlobal::locale()->readNumber(txt, &r) / 100.0; + if (r && zoom > 0.0) + m_stackView->setZoomFactor(zoom); +} + +void EditorWindow::slotZoomChanged(bool isMax, bool isMin, double zoom) +{ + d->zoomPlusAction->setEnabled(!isMax); + d->zoomMinusAction->setEnabled(!isMin); + + d->zoomCombo->blockSignals(true); + d->zoomCombo->setCurrentText(TQString::number(lround(zoom*100.0)) + TQString("%")); + d->zoomCombo->blockSignals(false); +} + +void EditorWindow::slotToggleOffFitToWindow() +{ + d->zoomFitToWindowAction->blockSignals(true); + d->zoomFitToWindowAction->setChecked(false); + d->zoomFitToWindowAction->blockSignals(false); +} + +void EditorWindow::slotEscapePressed() +{ + if (m_fullScreen) + m_fullScreenAction->activate(); +} + +void EditorWindow::plugActionAccel(TDEAction* action) +{ + if (!action) + return; + + d->accelerators->insert(action->text(), + action->text(), + action->whatsThis(), + action->shortcut(), + action, + TQ_SLOT(activate())); +} + +void EditorWindow::unplugActionAccel(TDEAction* action) +{ + d->accelerators->remove(action->text()); +} + +void EditorWindow::loadImagePlugins() +{ + TQPtrList pluginList = m_imagePluginLoader->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + guiFactory()->addClient(plugin); + plugin->setEnabledSelectionActions(false); + } + else + DDebug() << "Invalid plugin to add!" << endl; + } +} + +void EditorWindow::unLoadImagePlugins() +{ + TQPtrList pluginList = m_imagePluginLoader->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + guiFactory()->removeClient(plugin); + plugin->setEnabledSelectionActions(false); + } + } +} + +void EditorWindow::readStandardSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + + // Restore full screen Mode ? + + if (config->readBoolEntry("FullScreen", false)) + { + m_fullScreenAction->activate(); + m_fullScreen = true; + } + + // Restore Auto zoom action ? + bool autoZoom = config->readBoolEntry("AutoZoom", true); + if (autoZoom) + d->zoomFitToWindowAction->activate(); +} + +void EditorWindow::applyStandardSettings() +{ + TDEConfig* config = kapp->config(); + + // -- Settings for Color Management stuff ---------------------------------------------- + + config->setGroup("Color Management"); + + d->ICCSettings->enableCMSetting = config->readBoolEntry("EnableCM", false); + d->ICCSettings->askOrApplySetting = config->readBoolEntry("BehaviourICC", false); + d->ICCSettings->BPCSetting = config->readBoolEntry("BPCAlgorithm",false); + d->ICCSettings->managedViewSetting = config->readBoolEntry("ManagedView", false); + d->ICCSettings->renderingSetting = config->readNumEntry("RenderingIntent"); + d->ICCSettings->inputSetting = config->readPathEntry("InProfileFile", TQString()); + d->ICCSettings->workspaceSetting = config->readPathEntry("WorkProfileFile", TQString()); + d->ICCSettings->monitorSetting = config->readPathEntry("MonitorProfileFile", TQString()); + d->ICCSettings->proofSetting = config->readPathEntry("ProofProfileFile", TQString()); + + d->viewCMViewAction->setEnabled(d->ICCSettings->enableCMSetting); + d->viewCMViewAction->setChecked(d->ICCSettings->managedViewSetting); + d->cmViewIndicator->setEnabled(d->ICCSettings->enableCMSetting); + d->cmViewIndicator->setOn(d->ICCSettings->managedViewSetting); + setColorManagedViewIndicatorToolTip(d->ICCSettings->enableCMSetting, d->ICCSettings->managedViewSetting); + m_canvas->setICCSettings(d->ICCSettings); + + // -- JPEG, PNG, TIFF JPEG2000 files format settings -------------------------------------- + + config->setGroup("ImageViewer Settings"); + + // JPEG quality slider settings : 1 - 100 ==> libjpeg settings : 25 - 100. + m_IOFileSettings->JPEGCompression = (int)((75.0/100.0)* + (float)config->readNumEntry("JPEGCompression", 75) + + 26.0 - (75.0/100.0)); + + m_IOFileSettings->JPEGSubSampling = config->readNumEntry("JPEGSubSampling", 1); // Medium subsampling + + // PNG compression slider settings : 1 - 9 ==> libpng settings : 100 - 1. + m_IOFileSettings->PNGCompression = (int)(((1.0-100.0)/8.0)* + (float)config->readNumEntry("PNGCompression", 1) + + 100.0 - ((1.0-100.0)/8.0)); + + // TIFF compression setting. + m_IOFileSettings->TIFFCompression = config->readBoolEntry("TIFFCompression", false); + + // JPEG2000 quality slider settings : 1 - 100 + m_IOFileSettings->JPEG2000Compression = config->readNumEntry("JPEG2000Compression", 100); + + // JPEG2000 LossLess setting. + m_IOFileSettings->JPEG2000LossLess = config->readBoolEntry("JPEG2000LossLess", true); + + // -- RAW images decoding settings ------------------------------------------------------ + + // If digiKam Color Management is enable, no need to correct color of decoded RAW image, + // else, sRGB color workspace will be used. + + if (d->ICCSettings->enableCMSetting) + m_IOFileSettings->rawDecodingSettings.outputColorSpace = DRawDecoding::RAWCOLOR; + else + m_IOFileSettings->rawDecodingSettings.outputColorSpace = DRawDecoding::SRGB; + + m_IOFileSettings->rawDecodingSettings.sixteenBitsImage = config->readBoolEntry("SixteenBitsImage", false); + m_IOFileSettings->rawDecodingSettings.whiteBalance = (DRawDecoding::WhiteBalance)config->readNumEntry("WhiteBalance", + DRawDecoding::CAMERA); + m_IOFileSettings->rawDecodingSettings.customWhiteBalance = config->readNumEntry("CustomWhiteBalance", 6500); + m_IOFileSettings->rawDecodingSettings.customWhiteBalanceGreen = config->readDoubleNumEntry("CustomWhiteBalanceGreen", 1.0); + m_IOFileSettings->rawDecodingSettings.RGBInterpolate4Colors = config->readBoolEntry("RGBInterpolate4Colors", false); + m_IOFileSettings->rawDecodingSettings.DontStretchPixels = config->readBoolEntry("DontStretchPixels", false); + m_IOFileSettings->rawDecodingSettings.enableNoiseReduction = config->readBoolEntry("EnableNoiseReduction", false); + m_IOFileSettings->rawDecodingSettings.unclipColors = config->readNumEntry("UnclipColors", 0); + m_IOFileSettings->rawDecodingSettings.RAWQuality = (DRawDecoding::DecodingQuality)config->readNumEntry("RAWQuality", + DRawDecoding::BILINEAR); + m_IOFileSettings->rawDecodingSettings.NRThreshold = config->readNumEntry("NRThreshold", 100); + m_IOFileSettings->rawDecodingSettings.enableCACorrection = config->readBoolEntry("EnableCACorrection", false); + m_IOFileSettings->rawDecodingSettings.caMultiplier[0] = config->readDoubleNumEntry("caRedMultiplier", 1.0); + m_IOFileSettings->rawDecodingSettings.caMultiplier[1] = config->readDoubleNumEntry("caBlueMultiplier", 1.0); + m_IOFileSettings->rawDecodingSettings.brightness = config->readDoubleNumEntry("RAWBrightness", 1.0); + m_IOFileSettings->rawDecodingSettings.medianFilterPasses = config->readNumEntry("MedianFilterPasses", 0); + + m_IOFileSettings->useRAWImport = config->readBoolEntry("UseRawImportTool", false); + + // -- GUI Settings ------------------------------------------------------- + + TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); + if(config->hasKey("Splitter Sizes")) + m_splitter->setSizes(config->readIntListEntry("Splitter Sizes")); + else + m_canvas->setSizePolicy(rightSzPolicy); + + d->fullScreenHideToolBar = config->readBoolEntry("FullScreen Hide ToolBar", false); + + slotThemeChanged(); + + // -- Exposure Indicators Settings --------------------------------------- + + TQColor black(TQt::black); + TQColor white(TQt::white); + d->exposureSettings->underExposureIndicator = config->readBoolEntry("UnderExposureIndicator", false); + d->exposureSettings->overExposureIndicator = config->readBoolEntry("OverExposureIndicator", false); + d->exposureSettings->underExposureColor = config->readColorEntry("UnderExposureColor", &white); + d->exposureSettings->overExposureColor = config->readColorEntry("OverExposureColor", &black); + + d->viewUnderExpoAction->setChecked(d->exposureSettings->underExposureIndicator); + d->viewOverExpoAction->setChecked(d->exposureSettings->overExposureIndicator); + d->underExposureIndicator->setOn(d->exposureSettings->underExposureIndicator); + d->overExposureIndicator->setOn(d->exposureSettings->overExposureIndicator); + setUnderExposureToolTip(d->exposureSettings->underExposureIndicator); + setOverExposureToolTip(d->exposureSettings->overExposureIndicator); + m_canvas->setExposureSettings(d->exposureSettings); +} + +void EditorWindow::saveStandardSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + + config->writeEntry("AutoZoom", d->zoomFitToWindowAction->isChecked()); + config->writeEntry("Splitter Sizes", m_splitter->sizes()); + + config->writeEntry("FullScreen", m_fullScreenAction->isChecked()); + config->writeEntry("UnderExposureIndicator", d->exposureSettings->underExposureIndicator); + config->writeEntry("OverExposureIndicator", d->exposureSettings->overExposureIndicator); + + config->sync(); +} + +/** Method used by Editor Tools. Only Zoom+ and Zoom- are currently supported. + TODO: Fix this behavour when editor tool preview widgets will be factored. + */ +void EditorWindow::toggleZoomActions(bool val) +{ + d->zoomMinusAction->setEnabled(val); + d->zoomPlusAction->setEnabled(val); +} + +void EditorWindow::toggleStandardActions(bool val) +{ + d->zoomComboAction->setEnabled(val); + d->zoomTo100percents->setEnabled(val); + d->zoomFitToWindowAction->setEnabled(val); + d->zoomFitToSelectAction->setEnabled(val); + toggleZoomActions(val); + + d->rotateLeftAction->setEnabled(val); + d->rotateRightAction->setEnabled(val); + d->flipHorizAction->setEnabled(val); + d->flipVertAction->setEnabled(val); + d->filePrintAction->setEnabled(val); + d->resizeAction->setEnabled(val); + m_fileDeleteAction->setEnabled(val); + m_saveAsAction->setEnabled(val); + d->selectAllAction->setEnabled(val); + d->selectNoneAction->setEnabled(val); + d->slideShowAction->setEnabled(val); + + // these actions are special: They are turned off if val is false, + // but if val is true, they may be turned on or off. + if (val) + { + // Trigger sending of signalUndoStateChanged + // Note that for saving and loading, this is not necessary + // because the signal will be sent later anyway. + m_canvas->updateUndoState(); + } + else + { + m_saveAction->setEnabled(val); + m_undoAction->setEnabled(val); + m_redoAction->setEnabled(val); + } + + TQPtrList pluginList = m_imagePluginLoader->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + plugin->setEnabledActions(val); + } + } +} + +void EditorWindow::slotToggleFullScreen() +{ + if (m_fullScreen) // out of fullscreen + { + m_canvas->setBackgroundColor(m_bgColor); + + setWindowState( windowState() & ~WindowFullScreen ); + menuBar()->show(); + statusBar()->show(); + leftDock()->show(); + rightDock()->show(); + topDock()->show(); + bottomDock()->show(); + + TQObject* obj = child("ToolBar","TDEToolBar"); + + if (obj) + { + TDEToolBar* toolBar = static_cast(obj); + + if (m_fullScreenAction->isPlugged(toolBar) && d->removeFullScreenButton) + m_fullScreenAction->unplug(toolBar); + + if (toolBar->isHidden()) + showToolBars(); + } + + // -- remove the gui action accels ---- + + unplugActionAccel(m_forwardAction); + unplugActionAccel(m_backwardAction); + unplugActionAccel(m_firstAction); + unplugActionAccel(m_lastAction); + unplugActionAccel(m_saveAction); + unplugActionAccel(m_saveAsAction); + unplugActionAccel(d->zoomPlusAction); + unplugActionAccel(d->zoomMinusAction); + unplugActionAccel(d->zoomFitToWindowAction); + unplugActionAccel(d->zoomFitToSelectAction); + unplugActionAccel(d->cropAction); + unplugActionAccel(d->filePrintAction); + unplugActionAccel(m_fileDeleteAction); + unplugActionAccel(d->selectAllAction); + unplugActionAccel(d->selectNoneAction); + + toggleGUI2FullScreen(); + m_fullScreen = false; + } + else // go to fullscreen + { + m_canvas->setBackgroundColor(TQColor(TQt::black)); + + // hide the menubar and the statusbar + menuBar()->hide(); + statusBar()->hide(); + topDock()->hide(); + leftDock()->hide(); + rightDock()->hide(); + bottomDock()->hide(); + + TQObject* obj = child("ToolBar","TDEToolBar"); + + if (obj) + { + TDEToolBar* toolBar = static_cast(obj); + + if (d->fullScreenHideToolBar) + { + hideToolBars(); + } + else + { + showToolBars(); + + if ( !m_fullScreenAction->isPlugged(toolBar) ) + { + m_fullScreenAction->plug(toolBar); + d->removeFullScreenButton=true; + } + else + { + // If FullScreen button is enable in toolbar settings + // We don't remove it when we out of fullscreen mode. + d->removeFullScreenButton=false; + } + } + } + + // -- Insert all the gui actions into the accel -- + + plugActionAccel(m_forwardAction); + plugActionAccel(m_backwardAction); + plugActionAccel(m_firstAction); + plugActionAccel(m_lastAction); + plugActionAccel(m_saveAction); + plugActionAccel(m_saveAsAction); + plugActionAccel(d->zoomPlusAction); + plugActionAccel(d->zoomMinusAction); + plugActionAccel(d->zoomFitToWindowAction); + plugActionAccel(d->zoomFitToSelectAction); + plugActionAccel(d->cropAction); + plugActionAccel(d->filePrintAction); + plugActionAccel(m_fileDeleteAction); + plugActionAccel(d->selectAllAction); + plugActionAccel(d->selectNoneAction); + + toggleGUI2FullScreen(); + showFullScreen(); + m_fullScreen = true; + } +} + +void EditorWindow::slotRotatedOrFlipped() +{ + m_rotatedOrFlipped = true; +} + +void EditorWindow::slotLoadingProgress(const TQString&, float progress) +{ + m_nameLabel->setProgressValue((int)(progress*100.0)); +} + +void EditorWindow::slotSavingProgress(const TQString&, float progress) +{ + m_nameLabel->setProgressValue((int)(progress*100.0)); +} + +bool EditorWindow::promptForOverWrite() +{ + TQFileInfo fi(m_canvas->currentImageFilePath()); + TQString warnMsg(i18n("About to overwrite file \"%1\"\nAre you sure?") + .arg(fi.fileName())); + return (KMessageBox::warningContinueCancel(this, + warnMsg, + i18n("Warning"), + i18n("Overwrite"), + "editorWindowSaveOverwrite") + == KMessageBox::Continue); +} + +bool EditorWindow::promptUserSave(const KURL& url) +{ + if (m_saveAction->isEnabled()) + { + // if window is iconified, show it + if (isMinimized()) + { + KWin::deIconifyWindow(winId()); + } + + int result = KMessageBox::warningYesNoCancel(this, + i18n("The image '%1' has been modified.\n" + "Do you want to save it?") + .arg(url.filename()), + TQString(), + KStdGuiItem::save(), + KStdGuiItem::discard()); + + if (result == KMessageBox::Yes) + { + bool saving = false; + + if (m_canvas->isReadOnly()) + saving = saveAs(); + else if (promptForOverWrite()) + saving = save(); + + // save and saveAs return false if they were cancelled and did not enter saving at all + // In this case, do not call enter_loop because exit_loop will not be called. + if (saving) + { + // Waiting for asynchronous image file saving operation runing in separate thread. + m_savingContext->synchronizingState = SavingContextContainer::SynchronousSaving; + enter_loop(); + m_savingContext->synchronizingState = SavingContextContainer::NormalSaving; + return m_savingContext->synchronousSavingResult; + } + else + { + return false; + } + } + else if (result == KMessageBox::No) + { + m_saveAction->setEnabled(false); + return true; + } + else + { + return false; + } + } + + return true; +} + +bool EditorWindow::waitForSavingToComplete() +{ + // avoid reentrancy - return false means we have reentered the loop already. + if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving) + return false; + + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + { + // Waiting for asynchronous image file saving operation runing in separate thread. + m_savingContext->synchronizingState = SavingContextContainer::SynchronousSaving; + KMessageBox::queuedMessageBox(this, + KMessageBox::Information, + i18n("Please wait while the image is being saved...")); + enter_loop(); + m_savingContext->synchronizingState = SavingContextContainer::NormalSaving; + } + return true; +} + +void EditorWindow::enter_loop() +{ + TQWidget dummy(0, 0, WType_Dialog | WShowModal); + dummy.setFocusPolicy( TQWidget::NoFocus ); + tqt_enter_modal(&dummy); + tqApp->enter_loop(); + tqt_leave_modal(&dummy); +} + +void EditorWindow::slotSelected(bool val) +{ + // Update menu actions. + d->cropAction->setEnabled(val); + d->zoomFitToSelectAction->setEnabled(val); + d->copyAction->setEnabled(val); + + for (ImagePlugin* plugin = m_imagePluginLoader->pluginList().first(); + plugin; plugin = m_imagePluginLoader->pluginList().next()) + { + if (plugin) + { + plugin->setEnabledSelectionActions(val); + } + } + + TQRect sel = m_canvas->getSelectedArea(); + // Update histogram into sidebar. + emit signalSelectionChanged(sel); + + // Update status bar + if (val) + d->selectLabel->setText(TQString("(%1, %2) (%3 x %4)").arg(sel.x()).arg(sel.y()) + .arg(sel.width()).arg(sel.height())); + else + d->selectLabel->setText(i18n("No selection")); +} + +void EditorWindow::hideToolBars() +{ + TQPtrListIterator it = toolBarIterator(); + TDEToolBar* bar; + + for(;it.current()!=0L; ++it) + { + bar = it.current(); + + if (bar->area()) + bar->area()->hide(); + else + bar->hide(); + } +} + +void EditorWindow::showToolBars() +{ + TQPtrListIterator it = toolBarIterator(); + TDEToolBar* bar; + + for( ; it.current()!=0L ; ++it) + { + bar = it.current(); + + if (bar->area()) + bar->area()->show(); + else + bar->show(); + } +} + +void EditorWindow::slotPrepareToLoad() +{ + // Disable actions as appropriate during loading + emit signalNoCurrentItem(); + toggleActions(false); + slotUpdateItemInfo(); +} + +void EditorWindow::slotLoadingStarted(const TQString& /*filename*/) +{ + setCursor( KCursor::waitCursor() ); + + m_nameLabel->progressBarMode(StatusProgressBar::ProgressBarMode, i18n("Loading: ")); +} + +void EditorWindow::slotLoadingFinished(const TQString& filename, bool success) +{ + m_nameLabel->progressBarMode(StatusProgressBar::TextMode); + slotUpdateItemInfo(); + + // Enable actions as appropriate after loading + // No need to re-enable image properties sidebar here, it's will be done + // automatically by a signal from canvas + toggleActions(success); + unsetCursor(); + + // Note: in showfoto, we using a null filename to clear canvas. + if (!success && filename != TQString()) + { + TQFileInfo fi(filename); + TQString message = i18n("Failed to load image \"%1\"").arg(fi.fileName()); + KMessageBox::error(this, message); + DWarning() << "Failed to load image " << fi.fileName() << endl; + } +} + +void EditorWindow::slotNameLabelCancelButtonPressed() +{ + // If we saving an image... + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + { + m_savingContext->abortingSaving = true; + m_canvas->abortSaving(); + } + + // If we preparing SlideShow... + m_cancelSlideShow = true; +} + +void EditorWindow::slotSave() +{ + if (m_canvas->isReadOnly()) + saveAs(); + else if (promptForOverWrite()) + save(); +} + +void EditorWindow::slotSavingStarted(const TQString& /*filename*/) +{ + setCursor( KCursor::waitCursor() ); + + // Disable actions as appropriate during saving + emit signalNoCurrentItem(); + toggleActions(false); + + m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Saving: ")); +} + +void EditorWindow::slotSavingFinished(const TQString& filename, bool success) +{ + if (m_savingContext->savingState == SavingContextContainer::SavingStateSave) + { + // from save() + m_savingContext->savingState = SavingContextContainer::SavingStateNone; + + if (!success) + { + if (!m_savingContext->abortingSaving) + { + KMessageBox::error(this, i18n("Failed to save file\n\"%1\"\nto\n\"%2\".") + .arg(m_savingContext->destinationURL.filename()) + .arg(m_savingContext->destinationURL.path())); + } + finishSaving(false); + return; + } + + DDebug() << "renaming to " << m_savingContext->destinationURL.path() << endl; + + if (!moveFile()) + { + finishSaving(false); + return; + } + + m_canvas->setUndoHistoryOrigin(); + + // remove image from cache since it has changed + LoadingCacheInterface::cleanFromCache(m_savingContext->destinationURL.path()); + // this won't be in the cache, but does not hurt to do it anyway + LoadingCacheInterface::cleanFromCache(filename); + + // restore state of disabled actions. saveIsComplete can start any other task + // (loading!) which might itself in turn change states + finishSaving(true); + + saveIsComplete(); + + // Take all actions necessary to update information and re-enable sidebar + slotChanged(); + } + else if (m_savingContext->savingState == SavingContextContainer::SavingStateSaveAs) + { + m_savingContext->savingState = SavingContextContainer::SavingStateNone; + + // from saveAs() + if (!success) + { + if (!m_savingContext->abortingSaving) + { + KMessageBox::error(this, i18n("Failed to save file\n\"%1\"\nto\n\"%2\".") + .arg(m_savingContext->destinationURL.filename()) + .arg(m_savingContext->destinationURL.path())); + } + finishSaving(false); + return; + } + + // Only try to write exif if both src and destination are jpeg files + + DDebug() << "renaming to " << m_savingContext->destinationURL.path() << endl; + + if (!moveFile()) + { + finishSaving(false); + return; + } + + m_canvas->setUndoHistoryOrigin(); + + LoadingCacheInterface::cleanFromCache(m_savingContext->destinationURL.path()); + LoadingCacheInterface::cleanFromCache(filename); + + finishSaving(true); + saveAsIsComplete(); + + // Take all actions necessary to update information and re-enable sidebar + slotChanged(); + } +} + +void EditorWindow::finishSaving(bool success) +{ + m_savingContext->synchronousSavingResult = success; + + if (m_savingContext->saveTempFile) + { + delete m_savingContext->saveTempFile; + m_savingContext->saveTempFile = 0; + } + + // Exit of internal TQt event loop to unlock promptUserSave() method. + if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving) + tqApp->exit_loop(); + + // Enable actions as appropriate after saving + toggleActions(true); + unsetCursor(); + + m_nameLabel->progressBarMode(StatusProgressBar::TextMode); + + // On error, continue using current image + if (!success) + { + m_canvas->switchToLastSaved(m_savingContext->srcURL.path()); + } +} + +void EditorWindow::startingSave(const KURL& url) +{ + // avoid any reentrancy. Should be impossible anyway since actions will be disabled. + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + return; + + if (!checkPermissions(url)) + return; + + m_savingContext->srcURL = url; + m_savingContext->destinationURL = m_savingContext->srcURL; + m_savingContext->destinationExisted = true; + m_savingContext->originalFormat = m_canvas->currentImageFileFormat(); + m_savingContext->format = m_savingContext->originalFormat; + m_savingContext->abortingSaving = false; + m_savingContext->savingState = SavingContextContainer::SavingStateSave; + // use magic file extension which tells the digikamalbums ioslave to ignore the file + m_savingContext->saveTempFile = new KTempFile(m_savingContext->srcURL.directory(false), + ".digikamtempfile.tmp"); + m_savingContext->saveTempFile->setAutoDelete(true); + + m_canvas->saveAs(m_savingContext->saveTempFile->name(), m_IOFileSettings, + m_setExifOrientationTag && (m_rotatedOrFlipped || m_canvas->exifRotated())); +} + +bool EditorWindow::startingSaveAs(const KURL& url) +{ + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + return false; + + TQString mimetypes = KImageIO::mimeTypes(KImageIO::Writing).join(" "); + mimetypes.append(" image/tiff"); + DDebug () << "mimetypes=" << mimetypes << endl; + + m_savingContext->srcURL = url; + + FileSaveOptionsBox *options = new FileSaveOptionsBox(); + KFileDialog imageFileSaveDialog(m_savingContext->srcURL.isLocalFile() ? + m_savingContext->srcURL.directory() : TQDir::homeDirPath(), + TQString(), + this, + "imageFileSaveDialog", + false, + options); + + connect(&imageFileSaveDialog, TQ_SIGNAL(filterChanged(const TQString &)), + options, TQ_SLOT(slotImageFileFormatChanged(const TQString &))); + + connect(&imageFileSaveDialog, TQ_SIGNAL(fileSelected(const TQString &)), + options, TQ_SLOT(slotImageFileSelected(const TQString &))); + + ImageDialogPreview *preview = new ImageDialogPreview(&imageFileSaveDialog); + imageFileSaveDialog.setPreviewWidget(preview); + imageFileSaveDialog.setOperationMode(KFileDialog::Saving); + imageFileSaveDialog.setMode(KFile::File); + imageFileSaveDialog.setCaption(i18n("New Image File Name")); + imageFileSaveDialog.setFilter(mimetypes); + + TQFileInfo info(m_savingContext->srcURL.fileName()); + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + TQString ext = config->readEntry("LastSavedImageTypeMime", "png"); + TQString fileName = info.baseName(false) + TQString(".") + ext; + imageFileSaveDialog.setSelection(fileName); + + // Start dialog and check if canceled. + if ( imageFileSaveDialog.exec() != KFileDialog::Accepted ) + return false; + + // Update file save settings in editor instance. + options->applySettings(); + applyStandardSettings(); + + KURL newURL = imageFileSaveDialog.selectedURL(); + + // Check if target image format have been selected from Combo List of SaveAs dialog. + m_savingContext->format = KImageIO::typeForMime(imageFileSaveDialog.currentMimeFilter()); + + if ( m_savingContext->format.isEmpty() ) + { + // Else, check if target image format have been add to target image file name using extension. + + TQFileInfo fi(newURL.path()); + m_savingContext->format = fi.extension(false); + + if ( m_savingContext->format.isEmpty() ) + { + // If format is empty then file format is same as that of the original file. + m_savingContext->format = TQImageIO::imageFormat(m_savingContext->srcURL.path()); + } + else + { + // Else, check if format from file name extension is include on file mime type list. + + TQString imgExtPattern; + TQStringList imgExtList = TQStringList::split(" ", mimetypes); + for (TQStringList::ConstIterator it = imgExtList.begin() ; it != imgExtList.end() ; ++it) + { + imgExtPattern.append (KImageIO::typeForMime(*it).upper()); + imgExtPattern.append (" "); + } + imgExtPattern.append (" TIF TIFF"); + if ( imgExtPattern.contains("JPEG") ) + { + imgExtPattern.append (" JPG"); + imgExtPattern.append (" JPE"); + } + + if ( !imgExtPattern.contains( m_savingContext->format.upper() ) ) + { + KMessageBox::error(this, i18n("Target image file format \"%1\" unsupported.") + .arg(m_savingContext->format)); + DWarning() << k_funcinfo << "target image file format " << m_savingContext->format << " unsupported!" << endl; + return false; + } + } + } + + if (!newURL.isValid()) + { + KMessageBox::error(this, i18n("Failed to save file\n\"%1\" to\n\"%2\".") + .arg(newURL.filename()) + .arg(newURL.path().section('/', -2, -2))); + DWarning() << k_funcinfo << "target URL is not valid !" << endl; + return false; + } + + config->writeEntry("LastSavedImageTypeMime", m_savingContext->format); + config->sync(); + + // if new and original url are equal use slotSave() ------------------------------ + + KURL currURL(m_savingContext->srcURL); + currURL.cleanPath(); + newURL.cleanPath(); + + if (currURL.equals(newURL)) + { + slotSave(); + return false; + } + + // Check for overwrite ---------------------------------------------------------- + + TQFileInfo fi(newURL.path()); + m_savingContext->destinationExisted = fi.exists(); + if ( m_savingContext->destinationExisted ) + { + int result = + + KMessageBox::warningYesNo( this, i18n("A file named \"%1\" already " + "exists. Are you sure you want " + "to overwrite it?") + .arg(newURL.filename()), + i18n("Overwrite File?"), + i18n("Overwrite"), + KStdGuiItem::cancel() ); + + if (result != KMessageBox::Yes) + return false; + + // There will be two message boxes if the file is not writable. + // This may be controversial, and it may be changed, but it was a deliberate decision. + if (!checkPermissions(newURL)) + return false; + } + + // Now do the actual saving ----------------------------------------------------- + + // use magic file extension which tells the digikamalbums ioslave to ignore the file + m_savingContext->saveTempFile = new KTempFile(newURL.directory(false), ".digikamtempfile.tmp"); + m_savingContext->destinationURL = newURL; + m_savingContext->originalFormat = m_canvas->currentImageFileFormat(); + m_savingContext->savingState = SavingContextContainer::SavingStateSaveAs; + m_savingContext->saveTempFile->setAutoDelete(true); + m_savingContext->abortingSaving = false; + + m_canvas->saveAs(m_savingContext->saveTempFile->name(), m_IOFileSettings, + m_setExifOrientationTag && (m_rotatedOrFlipped || m_canvas->exifRotated()), + m_savingContext->format.lower()); + + return true; +} + +bool EditorWindow::checkPermissions(const KURL& url) +{ + //TODO: Check that the permissions can actually be changed + // if write permissions are not available. + + TQFileInfo fi(url.path()); + + if (fi.exists() && !fi.isWritable()) + { + int result = + + KMessageBox::warningYesNo( this, i18n("You do not have write permissions " + "for the file named \"%1\". " + "Are you sure you want " + "to overwrite it?") + .arg(url.filename()), + i18n("Overwrite File?"), + i18n("Overwrite"), + KStdGuiItem::cancel() ); + + if (result != KMessageBox::Yes) + return false; + } + + return true; +} + +bool EditorWindow::moveFile() +{ + TQCString dstFileName = TQFile::encodeName(m_savingContext->destinationURL.path()); + + // Store old permissions: + // Just get the current umask. + mode_t curr_umask = umask(S_IREAD | S_IWRITE); + // Restore the umask. + umask(curr_umask); + + // For new files respect the umask setting. + mode_t filePermissions = (S_IREAD | S_IWRITE | S_IROTH | S_IWOTH | S_IRGRP | S_IWGRP) & ~curr_umask; + + // For existing files, use the mode of the original file. + if (m_savingContext->destinationExisted) + { + struct stat stbuf; + if (::stat(dstFileName, &stbuf) == 0) + { + filePermissions = stbuf.st_mode; + } + } + + // rename tmp file to dest + if (::rename(TQFile::encodeName(m_savingContext->saveTempFile->name()), dstFileName) != 0) + { + KMessageBox::error(this, i18n("Failed to overwrite original file"), + i18n("Error Saving File")); + return false; + } + + // restore permissions + if (::chmod(dstFileName, filePermissions) != 0) + { + DWarning() << "Failed to restore file permissions for file " << dstFileName << endl; + } + + return true; +} + +void EditorWindow::slotToggleColorManagedView() +{ + d->cmViewIndicator->blockSignals(true); + d->viewCMViewAction->blockSignals(true); + bool cmv = false; + if (d->ICCSettings->enableCMSetting) + { + cmv = !d->ICCSettings->managedViewSetting; + d->ICCSettings->managedViewSetting = cmv; + m_canvas->setICCSettings(d->ICCSettings); + + // Save Color Managed View setting in config file. For performance + // reason, no need to flush file, it cached in memory and will be flushed + // to disk at end of session. + TDEConfig* config = kapp->config(); + config->setGroup("Color Management"); + config->writeEntry("ManagedView", cmv); + } + + d->cmViewIndicator->setOn(cmv); + d->viewCMViewAction->setChecked(cmv); + setColorManagedViewIndicatorToolTip(d->ICCSettings->enableCMSetting, cmv); + d->cmViewIndicator->blockSignals(false); + d->viewCMViewAction->blockSignals(false); +} + +void EditorWindow::setColorManagedViewIndicatorToolTip(bool available, bool cmv) +{ + TQToolTip::remove(d->cmViewIndicator); + TQString tooltip; + if (available) + { + if (cmv) + tooltip = i18n("Color Managed View is enabled"); + else + tooltip = i18n("Color Managed View is disabled"); + } + else + { + tooltip = i18n("Color Management is not configured, so the Color Managed View is not available"); + } + TQToolTip::add(d->cmViewIndicator, tooltip); +} + +void EditorWindow::slotToggleUnderExposureIndicator() +{ + d->underExposureIndicator->blockSignals(true); + d->viewUnderExpoAction->blockSignals(true); + bool uei = !d->exposureSettings->underExposureIndicator; + d->underExposureIndicator->setOn(uei); + d->viewUnderExpoAction->setChecked(uei); + d->exposureSettings->underExposureIndicator = uei; + m_canvas->setExposureSettings(d->exposureSettings); + setUnderExposureToolTip(uei); + d->underExposureIndicator->blockSignals(false); + d->viewUnderExpoAction->blockSignals(false); +} + +void EditorWindow::setUnderExposureToolTip(bool uei) +{ + TQToolTip::remove(d->underExposureIndicator); + TQToolTip::add(d->underExposureIndicator, + uei ? i18n("Under-Exposure indicator is enabled") + : i18n("Under-Exposure indicator is disabled")); +} + +void EditorWindow::slotToggleOverExposureIndicator() +{ + d->overExposureIndicator->blockSignals(true); + d->viewOverExpoAction->blockSignals(true); + bool oei = !d->exposureSettings->overExposureIndicator; + d->overExposureIndicator->setOn(oei); + d->viewOverExpoAction->setChecked(oei); + d->exposureSettings->overExposureIndicator = oei; + m_canvas->setExposureSettings(d->exposureSettings); + setOverExposureToolTip(oei); + d->overExposureIndicator->blockSignals(false); + d->viewOverExpoAction->blockSignals(false); +} + +void EditorWindow::setOverExposureToolTip(bool oei) +{ + TQToolTip::remove(d->overExposureIndicator); + TQToolTip::add(d->overExposureIndicator, + oei ? i18n("Over-Exposure indicator is enabled") + : i18n("Over-Exposure indicator is disabled")); +} + +void EditorWindow::slotDonateMoney() +{ + TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation"); +} + +void EditorWindow::slotContribute() +{ + TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=contrib"); +} + +void EditorWindow::slotToggleSlideShow() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + bool startWithCurrent = config->readBoolEntry("SlideShowStartCurrent", false); + + SlideShowSettings settings; + settings.delay = config->readNumEntry("SlideShowDelay", 5) * 1000; + settings.printName = config->readBoolEntry("SlideShowPrintName", true); + settings.printDate = config->readBoolEntry("SlideShowPrintDate", false); + settings.printApertureFocal = config->readBoolEntry("SlideShowPrintApertureFocal", false); + settings.printExpoSensitivity = config->readBoolEntry("SlideShowPrintExpoSensitivity", false); + settings.printMakeModel = config->readBoolEntry("SlideShowPrintMakeModel", false); + settings.printComment = config->readBoolEntry("SlideShowPrintComment", false); + settings.loop = config->readBoolEntry("SlideShowLoop", false); + slideShow(startWithCurrent, settings); +} + +void EditorWindow::slotSelectionChanged(const TQRect& sel) +{ + d->selectLabel->setText(TQString("(%1, %2) (%3 x %4)").arg(sel.x()).arg(sel.y()) + .arg(sel.width()).arg(sel.height())); +} + +void EditorWindow::slotRawCameraList() +{ + RawCameraDlg dlg(this); + dlg.exec(); +} + +void EditorWindow::slotThemeChanged() +{ + TQStringList themes(ThemeEngine::instance()->themeNames()); + int index = themes.findIndex(ThemeEngine::instance()->getCurrentThemeName()); + if (index == -1) + index = themes.findIndex(i18n("Default")); + + m_themeMenuAction->setCurrentItem(index); + + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + + if (!config->readBoolEntry("UseThemeBackgroundColor", true)) + m_bgColor = config->readColorEntry("BackgroundColor", &TQt::black); + else + m_bgColor = ThemeEngine::instance()->baseColor(); + + m_canvas->setBackgroundColor(m_bgColor); +} + +void EditorWindow::slotChangeTheme(const TQString& theme) +{ + ThemeEngine::instance()->slotChangeTheme(theme); +} + +void EditorWindow::setToolStartProgress(const TQString& toolName) +{ + m_nameLabel->setProgressValue(0); + m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, TQString("%1: ").arg(toolName)); +} + +void EditorWindow::setToolProgress(int progress) +{ + m_nameLabel->setProgressValue(progress); +} + +void EditorWindow::setToolStopProgress() +{ + m_nameLabel->setProgressValue(0); + m_nameLabel->progressBarMode(StatusProgressBar::TextMode); + slotUpdateItemInfo(); +} + + +void EditorWindow::slotShowMenuBar() +{ + if (menuBar()->isVisible()) + menuBar()->hide(); + else + menuBar()->show(); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/editor/editorwindow.h b/src/utilities/imageeditor/editor/editorwindow.h new file mode 100644 index 00000000..cbb06221 --- /dev/null +++ b/src/utilities/imageeditor/editor/editorwindow.h @@ -0,0 +1,263 @@ +/* ============================================================ + * + * 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-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORWINDOW_H +#define EDITORWINDOW_H + +// TQt includes. + +#include +#include +#include + +// KDE includes. + +#include +#include + +// Local includes. + +#include "sidebar.h" +#include "digikam_export.h" + +class TQSplitter; +class TQPopupMenu; +class TQLabel; + +class TDEToolBarPopupAction; +class TDEToggleAction; +class TDEAction; +class TDESelectAction; + +namespace Digikam +{ + +class Sidebar; +class DPopupMenu; +class Canvas; +class ImagePluginLoader; +class IOFileSettingsContainer; +class SavingContextContainer; +class StatusProgressBar; +class SlideShowSettings; +class EditorStackView; +class EditorWindowPriv; + +class DIGIKAM_EXPORT EditorWindow : public TDEMainWindow +{ + TQ_OBJECT + + +public: + + EditorWindow(const char *name); + ~EditorWindow(); + + virtual void applySettings(){}; + virtual bool setup(bool iccSetupPage=false)=0; + +signals: + + void signalSelectionChanged( const TQRect & ); + void signalNoCurrentItem(); + +protected: + + bool m_cancelSlideShow; + bool m_fullScreen; + bool m_rotatedOrFlipped; + bool m_setExifOrientationTag; + + TQLabel *m_resLabel; + + TQColor m_bgColor; + + TQSplitter *m_splitter; + + TDEAction *m_saveAction; + TDEAction *m_saveAsAction; + TDEAction *m_revertAction; + TDEAction *m_fileDeleteAction; + TDEAction *m_forwardAction; + TDEAction *m_backwardAction; + TDEAction *m_firstAction; + TDEAction *m_lastAction; + + TDEToggleAction *m_fullScreenAction; + + TDESelectAction *m_themeMenuAction; + + TDEToolBarPopupAction *m_undoAction; + TDEToolBarPopupAction *m_redoAction; + + DPopupMenu *m_contextMenu; + EditorStackView *m_stackView; + Canvas *m_canvas; + ImagePluginLoader *m_imagePluginLoader; + StatusProgressBar *m_nameLabel; + IOFileSettingsContainer *m_IOFileSettings; + SavingContextContainer *m_savingContext; + +protected: + + void saveStandardSettings(); + void readStandardSettings(); + void applyStandardSettings(); + + void setupStandardConnections(); + void setupStandardActions(); + void setupStandardAccelerators(); + void setupStatusBar(); + void setupContextMenu(); + void toggleStandardActions(bool val); + void toggleZoomActions(bool val); + + void printImage(KURL url); + + void plugActionAccel(TDEAction* action); + void unplugActionAccel(TDEAction* action); + + void unLoadImagePlugins(); + void loadImagePlugins(); + + bool promptForOverWrite(); + bool promptUserSave(const KURL& url); + bool waitForSavingToComplete(); + void startingSave(const KURL& url); + bool startingSaveAs(const KURL& url); + bool checkPermissions(const KURL& url); + bool moveFile(); + + EditorStackView* editorStackView() const; + + virtual void finishSaving(bool success); + + virtual void readSettings() { readStandardSettings(); }; + virtual void saveSettings() { saveStandardSettings(); }; + virtual void toggleActions(bool val) { toggleStandardActions(val); }; + virtual void toggleGUI2FullScreen() {}; + + virtual void slideShow(bool startWithCurrent, SlideShowSettings& settings)=0; + + virtual void setupConnections()=0; + virtual void setupActions()=0; + virtual void setupUserArea()=0; + virtual bool saveAs()=0; + virtual bool save()=0; + + virtual void saveIsComplete()=0; + virtual void saveAsIsComplete()=0; + + virtual Sidebar *rightSideBar() const=0; + +protected slots: + + void slotSave(); + void slotSaveAs() { saveAs(); }; + + void slotEditKeys(); + void slotResize(); + + void slotAboutToShowUndoMenu(); + void slotAboutToShowRedoMenu(); + + void slotConfToolbars(); + void slotNewToolbarConfig(); + + void slotToggleFullScreen(); + void slotEscapePressed(); + + void slotSelected(bool); + + void slotLoadingProgress(const TQString& filePath, float progress); + void slotSavingProgress(const TQString& filePath, float progress); + + void slotNameLabelCancelButtonPressed(); + + void slotThemeChanged(); + + virtual void slotLoadingStarted(const TQString& filename); + virtual void slotLoadingFinished(const TQString &filename, bool success); + virtual void slotSavingStarted(const TQString &filename); + + virtual void slotSetup(){ setup(); }; + virtual void slotChangeTheme(const TQString& theme); + + virtual void slotFilePrint()=0; + virtual void slotDeleteCurrentItem()=0; + virtual void slotBackward()=0; + virtual void slotForward()=0; + virtual void slotFirst()=0; + virtual void slotLast()=0; + virtual void slotUpdateItemInfo()=0; + virtual void slotChanged()=0; + virtual void slotContextMenu()=0; + virtual void slotRevert()=0; + +private slots: + + void slotToggleUnderExposureIndicator(); + void slotToggleOverExposureIndicator(); + void slotToggleColorManagedView(); + void slotRotatedOrFlipped(); + void slotSavingFinished(const TQString &filename, bool success); + void slotDonateMoney(); + void slotContribute(); + void slotToggleSlideShow(); + void slotZoomTo100Percents(); + void slotZoomSelected(); + void slotZoomTextChanged(const TQString &); + void slotZoomChanged(bool isMax, bool isMin, double zoom); + void slotSelectionChanged(const TQRect& sel); + void slotToggleFitToWindow(); + void slotToggleOffFitToWindow(); + void slotFitToSelect(); + void slotIncreaseZoom(); + void slotDecreaseZoom(); + void slotRawCameraList(); + void slotPrepareToLoad(); + void slotShowMenuBar(); + +private: + + void enter_loop(); + void hideToolBars(); + void showToolBars(); + void setColorManagedViewIndicatorToolTip(bool available, bool cmv); + void setUnderExposureToolTip(bool uei); + void setOverExposureToolTip(bool oei); + + void setToolStartProgress(const TQString& toolName); + void setToolProgress(int progress); + void setToolStopProgress(); + +private: + + EditorWindowPriv *d; + + friend class EditorToolIface; +}; + +} // namespace Digikam + +#endif /* EDITORWINDOW_H */ diff --git a/src/utilities/imageeditor/editor/editorwindowprivate.h b/src/utilities/imageeditor/editor/editorwindowprivate.h new file mode 100644 index 00000000..df07d0bd --- /dev/null +++ b/src/utilities/imageeditor/editor/editorwindowprivate.h @@ -0,0 +1,143 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-20 + * Description : main image editor GUI implementation + * private data. + * + * Copyright (C) 2006-2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORWINDOWPRIVATE_H +#define EDITORWINDOWPRIVATE_H + +class TQToolButton; +class TQLabel; + +class KComboBox; +class TDEAction; +class TDEToggleAction; +class KWidgetAction; +class TDESelectAction; +class TDEActionMenu; +class TDEAccel; + +namespace Digikam +{ + +class EditorToolIface; +class ExposureSettingsContainer; +class ICCSettingsContainer; + +class EditorWindowPriv +{ + +public: + + EditorWindowPriv() + { + removeFullScreenButton = false; + fullScreenHideToolBar = false; + selectLabel = 0; + donateMoneyAction = 0; + accelerators = 0; + viewCMViewAction = 0; + filePrintAction = 0; + copyAction = 0; + resizeAction = 0; + cropAction = 0; + rotateLeftAction = 0; + rotateRightAction = 0; + flipHorizAction = 0; + flipVertAction = 0; + ICCSettings = 0; + exposureSettings = 0; + underExposureIndicator = 0; + overExposureIndicator = 0; + cmViewIndicator = 0; + viewUnderExpoAction = 0; + viewOverExpoAction = 0; + slideShowAction = 0; + zoomFitToWindowAction = 0; + zoomFitToSelectAction = 0; + zoomPlusAction = 0; + zoomMinusAction = 0; + zoomTo100percents = 0; + zoomCombo = 0; + zoomComboAction = 0; + selectAllAction = 0; + selectNoneAction = 0; + rawCameraListAction = 0; + contributeAction = 0; + toolIface = 0; + showMenuBarAction = 0; + } + + ~EditorWindowPriv() + { + } + + bool removeFullScreenButton; + bool fullScreenHideToolBar; + + TQLabel *selectLabel; + + TQToolButton *cmViewIndicator; + TQToolButton *underExposureIndicator; + TQToolButton *overExposureIndicator; + + TDEAction *rawCameraListAction; + TDEAction *donateMoneyAction; + TDEAction *contributeAction; + TDEAction *filePrintAction; + TDEAction *copyAction; + TDEAction *resizeAction; + TDEAction *cropAction; + TDEAction *zoomPlusAction; + TDEAction *zoomMinusAction; + TDEAction *zoomTo100percents; + TDEAction *zoomFitToSelectAction; + TDEAction *rotateLeftAction; + TDEAction *rotateRightAction; + TDEAction *flipHorizAction; + TDEAction *flipVertAction; + TDEAction *slideShowAction; + TDEAction *selectAllAction; + TDEAction *selectNoneAction; + + TDEToggleAction *zoomFitToWindowAction; + TDEToggleAction *viewCMViewAction; + TDEToggleAction *viewUnderExpoAction; + TDEToggleAction *viewOverExpoAction; + TDEToggleAction *showMenuBarAction; + + KWidgetAction *zoomComboAction; + + KComboBox *zoomCombo; + + TDEAccel *accelerators; + + ICCSettingsContainer *ICCSettings; + + ExposureSettingsContainer *exposureSettings; + + EditorToolIface *toolIface; +}; + +} // NameSpace Digikam + +#endif /* EDITORWINDOWPRIVATE_H */ diff --git a/src/utilities/imageeditor/editor/imageiface.cpp b/src/utilities/imageeditor/editor/imageiface.cpp new file mode 100644 index 00000000..56cb559c --- /dev/null +++ b/src/utilities/imageeditor/editor/imageiface.cpp @@ -0,0 +1,444 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : image data interface for image plugins + * + * Copyright (C) 2004-2005 by Renchi Raju + * Copyright (C) 2004-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include +#include +#include +#include +#include + +// Local includes. + +#include "ddebug.h" +#include "exposurecontainer.h" +#include "iccsettingscontainer.h" +#include "icctransform.h" +#include "dimginterface.h" +#include "bcgmodifier.h" +#include "dmetadata.h" +#include "imageiface.h" + +namespace Digikam +{ + +class ImageIfacePriv +{ +public: + + ImageIfacePriv() + { + usePreviewSelection = false; + previewWidth = 0; + previewHeight = 0; + } + + bool usePreviewSelection; + + int originalWidth; + int originalHeight; + int originalBytesDepth; + + int constrainWidth; + int constrainHeight; + + int previewWidth; + int previewHeight; + + TQPixmap qcheck; + TQPixmap qpix; + TQBitmap qmask; + + DImg previewImage; + DImg targetPreviewImage; +}; + +ImageIface::ImageIface(int w, int h) +{ + d = new ImageIfacePriv; + + d->constrainWidth = w; + d->constrainHeight = h; + + d->originalWidth = DImgInterface::defaultInterface()->origWidth(); + d->originalHeight = DImgInterface::defaultInterface()->origHeight(); + d->originalBytesDepth = DImgInterface::defaultInterface()->bytesDepth(); + + d->qpix.setMask(d->qmask); + d->qcheck.resize(8, 8); + + TQPainter p; + p.begin(&d->qcheck); + p.fillRect(0, 0, 4, 4, TQColor(144,144,144)); + p.fillRect(4, 4, 4, 4, TQColor(144,144,144)); + p.fillRect(0, 4, 4, 4, TQColor(100,100,100)); + p.fillRect(4, 0, 4, 4, TQColor(100,100,100)); + p.end(); +} + +ImageIface::~ImageIface() +{ + delete d; +} + +void ImageIface::setPreviewType(bool useSelect) +{ + d->usePreviewSelection = useSelect; +} + +bool ImageIface::previewType() +{ + return d->usePreviewSelection; +} + +DColor ImageIface::getColorInfoFromOriginalImage(const TQPoint& point) +{ + if ( !DImgInterface::defaultInterface()->getImage() || point.x() > originalWidth() || point.y() > originalHeight() ) + { + DWarning() << k_funcinfo << "Coordinate out of range or no image data available!" << endl; + return DColor(); + } + + return DImgInterface::defaultInterface()->getImg()->getPixelColor(point.x(), point.y()); +} + +DColor ImageIface::getColorInfoFromPreviewImage(const TQPoint& point) +{ + if ( d->previewImage.isNull() || point.x() > previewWidth() || point.y() > previewHeight() ) + { + DWarning() << k_funcinfo << "Coordinate out of range or no image data available!" << endl; + return DColor(); + } + + return d->previewImage.getPixelColor(point.x(), point.y()); +} + +DColor ImageIface::getColorInfoFromTargetPreviewImage(const TQPoint& point) +{ + if ( d->targetPreviewImage.isNull() || point.x() > previewWidth() || point.y() > previewHeight() ) + { + DWarning() << k_funcinfo << "Coordinate out of range or no image data available!" << endl; + return DColor(); + } + + return d->targetPreviewImage.getPixelColor(point.x(), point.y()); +} + +uchar* ImageIface::setPreviewImageSize(int w, int h) const +{ + d->previewImage.reset(); + d->targetPreviewImage.reset(); + + d->constrainWidth = w; + d->constrainHeight = h; + + return (getPreviewImage()); +} + +uchar* ImageIface::getPreviewImage() const +{ + if (d->previewImage.isNull()) + { + DImg *im = 0; + + if (!d->usePreviewSelection) + { + im = DImgInterface::defaultInterface()->getImg(); + if (!im || im->isNull()) + return 0; + } + else + { + int x, y, w, h; + bool s = DImgInterface::defaultInterface()->sixteenBit(); + bool a = DImgInterface::defaultInterface()->hasAlpha(); + uchar *data = DImgInterface::defaultInterface()->getImageSelection(); + DImgInterface::defaultInterface()->getSelectedArea(x, y, w, h); + im = new DImg(w, h, s, a, data, true); + delete [] data; + + if (!im) + return 0; + + if (im->isNull()) + { + delete im; + return 0; + } + } + + TQSize sz(im->width(), im->height()); + sz.scale(d->constrainWidth, d->constrainHeight, TQSize::ScaleMin); + + d->previewImage = im->smoothScale(sz.width(), sz.height()); + d->previewWidth = d->previewImage.width(); + d->previewHeight = d->previewImage.height(); + + // only create another copy if needed, in putPreviewImage + d->targetPreviewImage = d->previewImage; + + d->qmask.resize(d->previewWidth, d->previewHeight); + d->qpix.resize(d->previewWidth, d->previewHeight); + + if (d->usePreviewSelection) + delete im; + } + + DImg previewData = d->previewImage.copyImageData(); + return previewData.stripImageData(); +} + +uchar* ImageIface::getOriginalImage() const +{ + DImg *im = DImgInterface::defaultInterface()->getImg(); + + if (!im || im->isNull()) + return 0; + + DImg origData = im->copyImageData(); + return origData.stripImageData(); +} + +DImg* ImageIface::getOriginalImg() const +{ + return DImgInterface::defaultInterface()->getImg(); +} + +uchar* ImageIface::getImageSelection() const +{ + return DImgInterface::defaultInterface()->getImageSelection(); +} + +void ImageIface::putPreviewImage(uchar* data) +{ + if (!data) + return; + + if (d->targetPreviewImage == d->previewImage) + { + d->targetPreviewImage = DImg(d->previewImage.width(), d->previewImage.height(), + d->previewImage.sixteenBit(), d->previewImage.hasAlpha(), data); + d->targetPreviewImage.setICCProfil( d->previewImage.getICCProfil() ); + } + else + { + d->targetPreviewImage.putImageData(data); + } +} + +void ImageIface::putOriginalImage(const TQString &caller, uchar* data, int w, int h) +{ + if (!data) + return; + + DImgInterface::defaultInterface()->putImage(caller, data, w, h); +} + +void ImageIface::setEmbeddedICCToOriginalImage(const TQString& profilePath) +{ + DImgInterface::defaultInterface()->setEmbeddedICCToOriginalImage( profilePath ); +} + +void ImageIface::putImageSelection(const TQString &caller, uchar* data) +{ + if (!data) + return; + + DImgInterface::defaultInterface()->putImageSelection(caller, data); +} + +int ImageIface::previewWidth() +{ + return d->previewWidth; +} + +int ImageIface::previewHeight() +{ + return d->previewHeight; +} + +bool ImageIface::previewSixteenBit() +{ + return originalSixteenBit(); +} + +bool ImageIface::previewHasAlpha() +{ + return originalHasAlpha(); +} + +int ImageIface::originalWidth() +{ + return DImgInterface::defaultInterface()->origWidth(); +} + +int ImageIface::originalHeight() +{ + return DImgInterface::defaultInterface()->origHeight(); +} + +bool ImageIface::originalSixteenBit() +{ + return DImgInterface::defaultInterface()->sixteenBit(); +} + +bool ImageIface::originalHasAlpha() +{ + return DImgInterface::defaultInterface()->hasAlpha(); +} + +int ImageIface::selectedWidth() +{ + int x, y, w, h; + DImgInterface::defaultInterface()->getSelectedArea(x, y, w, h); + return w; +} + +int ImageIface::selectedHeight() +{ + int x, y, w, h; + DImgInterface::defaultInterface()->getSelectedArea(x, y, w, h); + return h; +} + +int ImageIface::selectedXOrg() +{ + int x, y, w, h; + DImgInterface::defaultInterface()->getSelectedArea(x, y, w, h); + return x; +} + +int ImageIface::selectedYOrg() +{ + int x, y, w, h; + DImgInterface::defaultInterface()->getSelectedArea(x, y, w, h); + return y; +} + +void ImageIface::setPreviewBCG(double brightness, double contrast, double gamma) +{ + DImg preview = d->targetPreviewImage.copyImageData(); + BCGModifier cmod; + cmod.setGamma(gamma); + cmod.setBrightness(brightness); + cmod.setContrast(contrast); + cmod.applyBCG(preview); + putPreviewImage(preview.bits()); +} + +void ImageIface::setOriginalBCG(double brightness, double contrast, double gamma) +{ + DImgInterface::defaultInterface()->setBCG(brightness, contrast, gamma); +} + +void ImageIface::convertOriginalColorDepth(int depth) +{ + DImgInterface::defaultInterface()->convertDepth(depth); +} + +TQPixmap ImageIface::convertToPixmap(DImg& img) +{ + return DImgInterface::defaultInterface()->convertToPixmap(img); +} + +TQByteArray ImageIface::getEmbeddedICCFromOriginalImage() +{ + return DImgInterface::defaultInterface()->getEmbeddedICC(); +} + +TQByteArray ImageIface::getExifFromOriginalImage() +{ + return DImgInterface::defaultInterface()->getExif(); +} + +TQByteArray ImageIface::getIptcFromOriginalImage() +{ + return DImgInterface::defaultInterface()->getIptc(); +} + +PhotoInfoContainer ImageIface::getPhotographInformations() const +{ + DMetadata meta; + meta.setExif(DImgInterface::defaultInterface()->getExif()); + meta.setIptc(DImgInterface::defaultInterface()->getIptc()); + return meta.getPhotographInformations(); +} + +void ImageIface::paint(TQPaintDevice* device, int x, int y, int w, int h, + bool underExposure, bool overExposure) +{ + if ( !d->targetPreviewImage.isNull() ) + { + if (d->targetPreviewImage.hasAlpha()) + { + TQPainter p(&d->qpix); + p.drawTiledPixmap(0, 0, d->qpix.width(), d->qpix.height(), d->qcheck); + p.end(); + } + + TQPixmap pixImage; + ICCSettingsContainer *iccSettings = DImgInterface::defaultInterface()->getICCSettings(); + + if (iccSettings) + { + IccTransform monitorICCtrans; + monitorICCtrans.setProfiles(iccSettings->workspaceSetting, iccSettings->monitorSetting); + + if (iccSettings->enableCMSetting && iccSettings->managedViewSetting) + { + pixImage = d->targetPreviewImage.convertToPixmap(&monitorICCtrans); + } + else + { + pixImage = d->targetPreviewImage.convertToPixmap(); + } + } + else + { + pixImage = d->targetPreviewImage.convertToPixmap(); + } + + bitBlt(&d->qpix, 0, 0, static_cast(&pixImage), 0, 0, w, h, TQt::CopyROP, false); + + // Show the Over/Under exposure pixels indicators + + if (underExposure || overExposure) + { + ExposureSettingsContainer expoSettings; + expoSettings.underExposureIndicator = underExposure; + expoSettings.overExposureIndicator = overExposure; + expoSettings.underExposureColor = DImgInterface::defaultInterface()->underExposureColor(); + expoSettings.overExposureColor = DImgInterface::defaultInterface()->overExposureColor(); + + TQImage pureColorMask = d->targetPreviewImage.pureColorMask(&expoSettings); + TQPixmap pixMask(pureColorMask); + bitBlt(&d->qpix, 0, 0, static_cast(&pixMask), 0, 0, w, h, TQt::CopyROP, false); + } + } + + bitBlt(device, x, y, static_cast(&d->qpix), 0, 0, -1, -1, TQt::CopyROP, false); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/editor/imageiface.h b/src/utilities/imageeditor/editor/imageiface.h new file mode 100644 index 00000000..272c62a5 --- /dev/null +++ b/src/utilities/imageeditor/editor/imageiface.h @@ -0,0 +1,198 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-14 + * Description : image data interface for image plugins + * + * Copyright (C) 2004-2005 by Renchi Raju + * Copyright (C) 2004-2009 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEIFACE_H +#define IMAGEIFACE_H + +// TQt includes. + +#include +#include + +// KDE includes. + +#include + +// Local includes. + +#include "dimg.h" +#include "dcolor.h" +#include "photoinfocontainer.h" +#include "digikam_export.h" + +#define MAX3(a, b, c) (TQMAX(TQMAX(a,b),b)) +#define MIN3(a, b, c) (TQMIN(TQMIN(a,b),b)) +#define ROUND(x) ((int) ((x) + 0.5)) + +class TQPaintDevice; + +namespace Digikam +{ + +class ImageIfacePriv; + +class DIGIKAM_EXPORT ImageIface +{ +public: + + ImageIface(int w=0, int h=0); + ~ImageIface(); + + /** Use this method to use the current selection in editor instead the full + image to render the preview. + */ + void setPreviewType(bool useSelect=false); + + /** Return 'true' if the preview is rendered using the current selection in editor. + Return 'false' if the preview is rendered using the full image in editor. + */ + bool previewType(); + + /** Return image data for the current, scaled preview image. + The preview...() methods provide the characteristics of the data + (width, heigh, sixteen bit, alpha). + Ownership of the returned buffer is passed to the caller. + */ + uchar* getPreviewImage() const; + + /** Return image data for the current original image selection. + The selectionWidth(), selectionHeight(), originalSixteenBit() + and originalHasAlpha() methods provide the characteristics of the data. + Ownership of the returned buffer is passed to the caller. + */ + uchar* getImageSelection() const; + + /** Return image data for the original image. + The preview...() methods provide the characteristics of the data. + Ownership of the returned buffer is passed to the caller. + */ + uchar* getOriginalImage() const; + + /** Return a pointer to the DImg object representing the original image. + This object may not be modified or stored. Make copies if you need. + */ + DImg* getOriginalImg() const; + + /** Replace the image data of the original image with the given data. + The characteristics of the data must match the characteristics of + the original image as returned by the original...() methods, + respectively the given width and height parameters. + No ownership of the data pointer is assumed. + If w == -1 and h == -1, the size is unchanged. + Caller is an i18n'ed string that will be shown as the undo/redo action name. + */ + void putOriginalImage(const TQString &caller, uchar* data, int w=-1, int h=-1); + + /** Embed the Color Profile we have used in ICC plugin when this option is + selected + */ + void setEmbeddedICCToOriginalImage(const TQString& profilePath); + + /** Replace the data of the current original image selection with the given data. + The characteristics of the data must match the characteristics of the current + selection as returned by the selectionWidth(), selectionHeight(), + originalSixteenBit() and originalHasAlpha() methods. + No ownership of the data pointer is assumed. + Caller is an i18n'ed string that will be shown as the undo/redo action name. + */ + void putImageSelection(const TQString &caller, uchar* data); + + /** Replace the stored target preview data with the given data. + The characteristics of the data must match the characteristics of the current + as returned by the preview...() methods. + The target preview data is used by the paint() and + getColorInfoFromTargetPreviewImage() methods. + The data returned by getPreviewImage() is unaffected. + No ownership of the data pointer is assumed. + */ + void putPreviewImage(uchar* data); + + /** Get colors from original, (unchanged) preview + or target preview (set by putPreviewImage) image. + */ + + DColor getColorInfoFromOriginalImage(const TQPoint& point); + DColor getColorInfoFromPreviewImage(const TQPoint& point); + DColor getColorInfoFromTargetPreviewImage(const TQPoint& point); + + /** Original image information.*/ + int originalWidth(); + int originalHeight(); + bool originalSixteenBit(); + bool originalHasAlpha(); + + /** Original image metadata.*/ + TQByteArray getEmbeddedICCFromOriginalImage(); + TQByteArray getExifFromOriginalImage(); + TQByteArray getIptcFromOriginalImage(); + + /** Get photograph information from original image.*/ + PhotoInfoContainer getPhotographInformations() const; + + /** Standard methods to get/set preview information.*/ + int previewWidth(); + int previewHeight(); + bool previewHasAlpha(); + bool previewSixteenBit(); + + /** Sets preview size and returns new preview data as with getPreviewImage. + The parameters are only hints, previewWidth() and previewHeight() + may differ from w and h. + */ + uchar* setPreviewImageSize(int w, int h) const; + + /** Standard methods to get image selection information.*/ + int selectedWidth(); + int selectedHeight(); + + /** Get selected (X, Y) position on the top/left corner of the original image.*/ + int selectedXOrg(); + int selectedYOrg(); + + /** Set BCG correction for preview and original image */ + void setPreviewBCG(double brightness, double contrast, double gamma); + void setOriginalBCG(double brightness, double contrast, double gamma); + + /** Convert depth of original image */ + void convertOriginalColorDepth(int depth); + + /** Convert a DImg image to a pixmap for screen using color + managemed view if necessary */ + TQPixmap convertToPixmap(DImg& img); + + /** Paint the current target preview image (or the preview image, + if putPreviewImage has not been called) on the given paint device. + at x|y, with given maximum width and height. + */ + void paint(TQPaintDevice* device, int x, int y, int w, int h, + bool underExposure=false, bool overExposure=false); + +private: + + ImageIfacePriv* d; +}; + +} // namespace Digikam + +#endif /* IMAGEIFACE_H */ diff --git a/src/utilities/imageeditor/editor/imagewindow.cpp b/src/utilities/imageeditor/editor/imagewindow.cpp new file mode 100644 index 00000000..2c10a6f6 --- /dev/null +++ b/src/utilities/imageeditor/editor/imagewindow.cpp @@ -0,0 +1,1263 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-12 + * Description : digiKam image editor GUI + * + * Copyright (C) 2004-2005 by Renchi Raju + * Copyright (C) 2004-2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include + +// TQt includes. + +#include +#include +#include +#include +#include +#include +#include + +// KDE includes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes. + +#include "constants.h" +#include "ddebug.h" +#include "dlogoaction.h" +#include "dpopupmenu.h" +#include "dragobjects.h" +#include "canvas.h" +#include "dimginterface.h" +#include "dimg.h" +#include "dmetadata.h" +#include "imageplugin.h" +#include "imagepluginloader.h" +#include "imageprint.h" +#include "albummanager.h" +#include "album.h" +#include "albumdb.h" +#include "albumsettings.h" +#include "syncjob.h" +#include "imageinfo.h" +#include "imagepropertiessidebardb.h" +#include "tagspopupmenu.h" +#include "ratingpopupmenu.h" +#include "slideshow.h" +#include "setup.h" +#include "iccsettingscontainer.h" +#include "iofilesettingscontainer.h" +#include "loadingcacheinterface.h" +#include "savingcontextcontainer.h" +#include "statusprogressbar.h" +#include "imageattributeswatch.h" +#include "deletedialog.h" +#include "metadatahub.h" +#include "themeengine.h" +#include "editorstackview.h" +#include "imagewindow.h" +#include "imagewindow.moc" + +namespace Digikam +{ + +class ImageWindowPriv +{ + +public: + + ImageWindowPriv() + { + allowSaving = true; + star0 = 0; + star1 = 0; + star2 = 0; + star3 = 0; + star4 = 0; + star5 = 0; + fileDeletePermanentlyAction = 0; + fileDeletePermanentlyDirectlyAction = 0; + fileTrashDirectlyAction = 0; + imageInfoCurrent = 0; + rightSidebar = 0; + } + + // If image editor is launched by camera interface, current + // image cannot be saved. + bool allowSaving; + + KURL::List urlList; + KURL urlCurrent; + + // Rating actions. + TDEAction *star0; + TDEAction *star1; + TDEAction *star2; + TDEAction *star3; + TDEAction *star4; + TDEAction *star5; + + // Delete actions + TDEAction *fileDeletePermanentlyAction; + TDEAction *fileDeletePermanentlyDirectlyAction; + TDEAction *fileTrashDirectlyAction; + + ImageInfoList imageInfoList; + ImageInfo *imageInfoCurrent; + + ImagePropertiesSideBarDB *rightSidebar; +}; + +ImageWindow* ImageWindow::m_instance = 0; + +ImageWindow* ImageWindow::imagewindow() +{ + if (!m_instance) + new ImageWindow(); + + return m_instance; +} + +bool ImageWindow::imagewindowCreated() +{ + return m_instance; +} + +ImageWindow::ImageWindow() + : EditorWindow( "Image Editor" ) +{ + d = new ImageWindowPriv; + m_instance = this; + setAcceptDrops(true); + + // -- Build the GUI ------------------------------- + + setupUserArea(); + setupStatusBar(); + setupActions(); + + // Load image plugins to GUI + + m_imagePluginLoader = ImagePluginLoader::instance(); + loadImagePlugins(); + + // Create context menu. + + setupContextMenu(); + + // Make signals/slots connections + + setupConnections(); + + // -- Read settings -------------------------------- + + readSettings(); + applySettings(); + setAutoSaveSettings("ImageViewer Settings"); + + //------------------------------------------------------------- + + d->rightSidebar->loadViewState(); + d->rightSidebar->populateTags(); +} + +ImageWindow::~ImageWindow() +{ + m_instance = 0; + + unLoadImagePlugins(); + + // No need to delete m_imagePluginLoader instance here, it will be done by main interface. + + delete d->rightSidebar; + delete d; +} + +Sidebar* ImageWindow::rightSideBar() const +{ + return dynamic_cast(d->rightSidebar); +} + +void ImageWindow::closeEvent(TQCloseEvent* e) +{ + if (!e) + return; + + if (!queryClose()) + return; + + // put right side bar in a defined state + emit signalNoCurrentItem(); + + m_canvas->resetImage(); + + saveSettings(); + + e->accept(); +} + +bool ImageWindow::queryClose() +{ + // Note: we reimplement closeEvent above for this window. + // Additionally, queryClose is called from DigikamApp. + + // wait if a save operation is currently running + if (!waitForSavingToComplete()) + return false; + + return promptUserSave(d->urlCurrent); +} + +void ImageWindow::setupConnections() +{ + setupStandardConnections(); + + // To toggle properly keyboards shortcuts from comments & tags side bar tab. + + connect(d->rightSidebar, TQ_SIGNAL(signalNextItem()), + this, TQ_SLOT(slotForward())); + + connect(d->rightSidebar, TQ_SIGNAL(signalPrevItem()), + this, TQ_SLOT(slotBackward())); + + connect(this, TQ_SIGNAL(signalSelectionChanged( const TQRect &)), + d->rightSidebar, TQ_SLOT(slotImageSelectionChanged( const TQRect &))); + + connect(this, TQ_SIGNAL(signalNoCurrentItem()), + d->rightSidebar, TQ_SLOT(slotNoCurrentItem())); + + ImageAttributesWatch *watch = ImageAttributesWatch::instance(); + + connect(watch, TQ_SIGNAL(signalFileMetadataChanged(const KURL &)), + this, TQ_SLOT(slotFileMetadataChanged(const KURL &))); +} + +void ImageWindow::setupUserArea() +{ + TQWidget* widget = new TQWidget(this); + TQHBoxLayout *lay = new TQHBoxLayout(widget); + + m_splitter = new TQSplitter(widget); + m_stackView = new EditorStackView(m_splitter); + m_canvas = new Canvas(m_stackView); + m_stackView->setCanvas(m_canvas); + m_stackView->setViewMode(EditorStackView::CanvasMode); + + m_canvas->makeDefaultEditingCanvas(); + + TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); + m_canvas->setSizePolicy(rightSzPolicy); + + d->rightSidebar = new ImagePropertiesSideBarDB(widget, "ImageEditor Right Sidebar", m_splitter, + Sidebar::Right, true); + lay->addWidget(m_splitter); + lay->addWidget(d->rightSidebar); + + m_splitter->setFrameStyle( TQFrame::NoFrame ); + m_splitter->setFrameShadow( TQFrame::Plain ); + m_splitter->setFrameShape( TQFrame::NoFrame ); + m_splitter->setOpaqueResize(false); + setCentralWidget(widget); +} + +void ImageWindow::setupActions() +{ + setupStandardActions(); + + // Provides a menu entry that allows showing/hiding the toolbar(s) + setStandardToolBarMenuEnabled(true); + + // Provides a menu entry that allows showing/hiding the statusbar + createStandardStatusBarAction(); + + // -- Rating actions --------------------------------------------------------------- + + d->star0 = new TDEAction(i18n("Assign Rating \"No Stars\""), CTRL+Key_0, + this, TQ_SLOT(slotAssignRatingNoStar()), + actionCollection(), "imageview_ratenostar"); + d->star1 = new TDEAction(i18n("Assign Rating \"One Star\""), CTRL+Key_1, + this, TQ_SLOT(slotAssignRatingOneStar()), + actionCollection(), "imageview_rateonestar"); + d->star2 = new TDEAction(i18n("Assign Rating \"Two Stars\""), CTRL+Key_2, + this, TQ_SLOT(slotAssignRatingTwoStar()), + actionCollection(), "imageview_ratetwostar"); + d->star3 = new TDEAction(i18n("Assign Rating \"Three Stars\""), CTRL+Key_3, + this, TQ_SLOT(slotAssignRatingThreeStar()), + actionCollection(), "imageview_ratethreestar"); + d->star4 = new TDEAction(i18n("Assign Rating \"Four Stars\""), CTRL+Key_4, + this, TQ_SLOT(slotAssignRatingFourStar()), + actionCollection(), "imageview_ratefourstar"); + d->star5 = new TDEAction(i18n("Assign Rating \"Five Stars\""), CTRL+Key_5, + this, TQ_SLOT(slotAssignRatingFiveStar()), + actionCollection(), "imageview_ratefivestar"); + + // -- Special Delete actions --------------------------------------------------------------- + + // Pop up dialog to ask user whether to permanently delete + d->fileDeletePermanentlyAction = new TDEAction(i18n("Delete File Permanently"), + "edit-delete", + SHIFT+Key_Delete, + this, + TQ_SLOT(slotDeleteCurrentItemPermanently()), + actionCollection(), + "image_delete_permanently"); + + // These two actions are hidden, no menu entry, no toolbar entry, no shortcut. + // Power users may add them. + d->fileDeletePermanentlyDirectlyAction = new TDEAction(i18n("Delete Permanently without Confirmation"), + "edit-delete", + 0, + this, + TQ_SLOT(slotDeleteCurrentItemPermanentlyDirectly()), + actionCollection(), + "image_delete_permanently_directly"); + + d->fileTrashDirectlyAction = new TDEAction(i18n("Move to Trash without Confirmation"), + "edittrash", + 0, + this, + TQ_SLOT(slotTrashCurrentItemDirectly()), + actionCollection(), + "image_trash_directly"); + + // --------------------------------------------------------------------------------- + + new DLogoAction(actionCollection(), "logo_action"); + + createGUI("digikamimagewindowui.rc", false); + + setupStandardAccelerators(); +} + +void ImageWindow::applySettings() +{ + applyStandardSettings(); + + AlbumSettings *settings = AlbumSettings::instance(); + m_canvas->setExifOrient(settings->getExifRotate()); + m_setExifOrientationTag = settings->getExifSetOrientation(); + refreshView(); +} + +void ImageWindow::refreshView() +{ + d->rightSidebar->refreshTagsView(); +} + +void ImageWindow::loadURL(const KURL::List& urlList, const KURL& urlCurrent, + const TQString& caption, bool allowSaving) +{ + if (!promptUserSave(d->urlCurrent)) + return; + + d->urlList = urlList; + d->urlCurrent = urlCurrent; + d->imageInfoList = ImageInfoList(); + d->imageInfoCurrent = 0; + + loadCurrentList(caption, allowSaving); +} + +void ImageWindow::loadImageInfos(const ImageInfoList &imageInfoList, ImageInfo *imageInfoCurrent, + const TQString& caption, bool allowSaving) +{ + // The ownership of objects of imageInfoList is passed to us. + // imageInfoCurrent is contained in imageInfoList. + + // Very first thing is to check for changes, user may choose to cancel operation + if (!promptUserSave(d->urlCurrent)) + { + // delete objects from list + for (ImageInfoList::iterator it = imageInfoList.begin(); it != imageInfoList.end(); ++it) + delete *it; + return; + } + + // take over ImageInfo list + d->imageInfoList = imageInfoList; + d->imageInfoCurrent = imageInfoCurrent; + + d->imageInfoList.setAutoDelete(true); + + // create URL list + d->urlList = KURL::List(); + + ImageInfoListIterator it(d->imageInfoList); + ImageInfo *info; + for (; (info = it.current()); ++it) + { + d->urlList.append(info->kurl()); + } + + d->urlCurrent = d->imageInfoCurrent->kurl(); + + loadCurrentList(caption, allowSaving); +} + +void ImageWindow::loadCurrentList(const TQString& caption, bool allowSaving) +{ + // this method contains the code shared by loadURL and loadImageInfos + + // if window is iconified, show it + if (isMinimized()) + { + KWin::deIconifyWindow(winId()); + } + + if (!caption.isEmpty()) + setCaption(i18n("Image Editor - %1").arg(caption)); + else + setCaption(i18n("Image Editor")); + + d->allowSaving = allowSaving; + + m_saveAction->setEnabled(false); + m_revertAction->setEnabled(false); + m_undoAction->setEnabled(false); + m_redoAction->setEnabled(false); + + TQTimer::singleShot(0, this, TQ_SLOT(slotLoadCurrent())); +} + +void ImageWindow::slotLoadCurrent() +{ + KURL::List::iterator it = d->urlList.find(d->urlCurrent); + + if (it != d->urlList.end()) + { + m_canvas->load(d->urlCurrent.path(), m_IOFileSettings); + + ++it; + if (it != d->urlList.end()) + m_canvas->preload((*it).path()); + } + + // Do this _after_ the canvas->load(), so that the main view histogram does not load + // a smaller version if a raw image, and after that the DImgInterface loads the full version. + // So first let DImgInterface create its loading task, only then any external objects. + setViewToURL(d->urlCurrent); +} + +void ImageWindow::setViewToURL(const KURL &url) +{ + emit signalURLChanged(url); +} + +void ImageWindow::slotForward() +{ + if(!promptUserSave(d->urlCurrent)) + return; + + KURL::List::iterator it = d->urlList.find(d->urlCurrent); + int index = d->imageInfoList.find(d->imageInfoCurrent); + + if (it != d->urlList.end()) + { + if (d->urlCurrent != d->urlList.last()) + { + KURL urlNext = *(++it); + d->imageInfoCurrent = d->imageInfoList.at(index + 1); + d->urlCurrent = urlNext; + slotLoadCurrent(); + } + } +} + +void ImageWindow::slotBackward() +{ + if(!promptUserSave(d->urlCurrent)) + return; + + KURL::List::iterator it = d->urlList.find(d->urlCurrent); + int index = d->imageInfoList.find(d->imageInfoCurrent); + + if (it != d->urlList.begin()) + { + if (d->urlCurrent != d->urlList.first()) + { + KURL urlPrev = *(--it); + d->imageInfoCurrent = d->imageInfoList.at(index - 1); + d->urlCurrent = urlPrev; + slotLoadCurrent(); + } + } +} + +void ImageWindow::slotFirst() +{ + if(!promptUserSave(d->urlCurrent)) + return; + + d->urlCurrent = d->urlList.first(); + d->imageInfoCurrent = d->imageInfoList.first(); + slotLoadCurrent(); +} + +void ImageWindow::slotLast() +{ + if(!promptUserSave(d->urlCurrent)) + return; + + d->urlCurrent = d->urlList.last(); + d->imageInfoCurrent = d->imageInfoList.last(); + slotLoadCurrent(); +} + +void ImageWindow::slotContextMenu() +{ + if (m_contextMenu) + { + RatingPopupMenu *ratingMenu = 0; + TagsPopupMenu *assignTagsMenu = 0; + TagsPopupMenu *removeTagsMenu = 0; + int separatorID1 = -1; + int separatorID2 = -1; + + if (d->imageInfoCurrent) + { + // Bulk assignment/removal of tags -------------------------- + + TQ_LLONG id = d->imageInfoCurrent->id(); + TQValueList idList; + idList.append(id); + + assignTagsMenu = new TagsPopupMenu(idList, 1000, TagsPopupMenu::ASSIGN); + removeTagsMenu = new TagsPopupMenu(idList, 2000, TagsPopupMenu::REMOVE); + + separatorID1 = m_contextMenu->insertSeparator(); + + m_contextMenu->insertItem(i18n("Assign Tag"), assignTagsMenu); + int i = m_contextMenu->insertItem(i18n("Remove Tag"), removeTagsMenu); + + connect(assignTagsMenu, TQ_SIGNAL(signalTagActivated(int)), + this, TQ_SLOT(slotAssignTag(int))); + + connect(removeTagsMenu, TQ_SIGNAL(signalTagActivated(int)), + this, TQ_SLOT(slotRemoveTag(int))); + + AlbumDB* db = AlbumManager::instance()->albumDB(); + if (!db->hasTags( idList )) + m_contextMenu->setItemEnabled(i, false); + + separatorID2 = m_contextMenu->insertSeparator(); + + // Assign Star Rating ------------------------------------------- + + ratingMenu = new RatingPopupMenu(); + + connect(ratingMenu, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotAssignRating(int))); + + m_contextMenu->insertItem(i18n("Assign Rating"), ratingMenu); + } + + m_contextMenu->exec(TQCursor::pos()); + + if (separatorID1 != -1) + m_contextMenu->removeItem(separatorID1); + if (separatorID2 != -1) + m_contextMenu->removeItem(separatorID2); + + delete assignTagsMenu; + delete removeTagsMenu; + delete ratingMenu; + } +} + +void ImageWindow::slotChanged() +{ + TQString mpixels; + TQSize dims(m_canvas->imageWidth(), m_canvas->imageHeight()); + mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2); + TQString str = (!dims.isValid()) ? i18n("Unknown") : i18n("%1x%2 (%3Mpx)") + .arg(dims.width()).arg(dims.height()).arg(mpixels); + m_resLabel->setText(str); + + if (d->urlCurrent.isValid()) + { + KURL u(d->urlCurrent.directory()); + + DImg* img = m_canvas->interface()->getImg(); + + if (d->imageInfoCurrent) + { + d->rightSidebar->itemChanged(d->imageInfoCurrent, + m_canvas->getSelectedArea(), img); + } + else + { + d->rightSidebar->itemChanged(d->urlCurrent, m_canvas->getSelectedArea(), img); + } + } +} + +void ImageWindow::slotUndoStateChanged(bool moreUndo, bool moreRedo, bool canSave) +{ + m_revertAction->setEnabled(canSave); + m_undoAction->setEnabled(moreUndo); + m_redoAction->setEnabled(moreRedo); + + if (d->allowSaving) + m_saveAction->setEnabled(canSave); + + if (!moreUndo) + m_rotatedOrFlipped = false; +} + +void ImageWindow::slotAssignTag(int tagID) +{ + if (d->imageInfoCurrent) + { + MetadataHub hub; + hub.load(d->imageInfoCurrent); + hub.setTag(tagID, true); + hub.write(d->imageInfoCurrent, MetadataHub::PartialWrite); + hub.write(d->imageInfoCurrent->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void ImageWindow::slotRemoveTag(int tagID) +{ + if (d->imageInfoCurrent) + { + MetadataHub hub; + hub.load(d->imageInfoCurrent); + hub.setTag(tagID, false); + hub.write(d->imageInfoCurrent, MetadataHub::PartialWrite); + hub.write(d->imageInfoCurrent->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void ImageWindow::slotAssignRatingNoStar() +{ + slotAssignRating(0); +} + +void ImageWindow::slotAssignRatingOneStar() +{ + slotAssignRating(1); +} + +void ImageWindow::slotAssignRatingTwoStar() +{ + slotAssignRating(2); +} + +void ImageWindow::slotAssignRatingThreeStar() +{ + slotAssignRating(3); +} + +void ImageWindow::slotAssignRatingFourStar() +{ + slotAssignRating(4); +} + +void ImageWindow::slotAssignRatingFiveStar() +{ + slotAssignRating(5); +} + +void ImageWindow::slotAssignRating(int rating) +{ + rating = TQMIN(RatingMax, TQMAX(RatingMin, rating)); + if (d->imageInfoCurrent) + { + MetadataHub hub; + hub.load(d->imageInfoCurrent); + hub.setRating(rating); + hub.write(d->imageInfoCurrent, MetadataHub::PartialWrite); + hub.write(d->imageInfoCurrent->filePath(), MetadataHub::FullWriteIfChanged); + } +} + +void ImageWindow::slotUpdateItemInfo() +{ + uint index = d->urlList.findIndex(d->urlCurrent); + + m_rotatedOrFlipped = false; + + TQString text = d->urlCurrent.filename() + i18n(" (%2 of %3)") + .arg(TQString::number(index+1)) + .arg(TQString::number(d->urlList.count())); + m_nameLabel->setText(text); + + if (d->urlList.count() == 1) + { + m_backwardAction->setEnabled(false); + m_forwardAction->setEnabled(false); + m_firstAction->setEnabled(false); + m_lastAction->setEnabled(false); + } + else + { + m_backwardAction->setEnabled(true); + m_forwardAction->setEnabled(true); + m_firstAction->setEnabled(true); + m_lastAction->setEnabled(true); + } + + if (index == 0) + { + m_backwardAction->setEnabled(false); + m_firstAction->setEnabled(false); + } + + if (index == d->urlList.count()-1) + { + m_forwardAction->setEnabled(false); + m_lastAction->setEnabled(false); + } + + // Disable some menu actions if the current root image URL + // is not include in the digiKam Albums library database. + // This is necessary when ImageEditor is opened from cameraclient. + + KURL u(d->urlCurrent.directory()); + PAlbum *palbum = AlbumManager::instance()->findPAlbum(u); + + if (!palbum) + { + m_fileDeleteAction->setEnabled(false); + } + else + { + m_fileDeleteAction->setEnabled(true); + } +} + +bool ImageWindow::setup(bool iccSetupPage) +{ + Setup setup(this, 0, iccSetupPage ? Setup::IccProfiles : Setup::LastPageUsed); + + if (setup.exec() != TQDialog::Accepted) + return false; + + kapp->config()->sync(); + + applySettings(); + return true; +} + +void ImageWindow::toggleGUI2FullScreen() +{ + if (m_fullScreen) + d->rightSidebar->restore(); + else + d->rightSidebar->backup(); +} + +void ImageWindow::saveIsComplete() +{ + // With save(), we do not reload the image but just continue using the data. + // This means that a saving operation does not lead to quality loss for + // subsequent editing operations. + + // put image in cache, the LoadingCacheInterface cares for the details + LoadingCacheInterface::putImage(m_savingContext->destinationURL.path(), m_canvas->currentImage()); + + // notify main app that file changed + emit signalFileModified(m_savingContext->destinationURL); + + // all that is done in slotLoadCurrent, except for loading + KURL::List::iterator it = d->urlList.find(d->urlCurrent); + setViewToURL(*it); + + if (++it != d->urlList.end()) + { + m_canvas->preload((*it).path()); + } + //slotLoadCurrent(); +} + +void ImageWindow::saveAsIsComplete() +{ + // Nothing to be done if operating without database + if (!d->imageInfoCurrent) + return; + + // Find the src and dest albums ------------------------------------------ + + KURL srcDirURL(TQDir::cleanDirPath(m_savingContext->srcURL.directory())); + PAlbum* srcAlbum = AlbumManager::instance()->findPAlbum(srcDirURL); + + KURL dstDirURL(TQDir::cleanDirPath(m_savingContext->destinationURL.directory())); + PAlbum* dstAlbum = AlbumManager::instance()->findPAlbum(dstDirURL); + + if (dstAlbum && srcAlbum) + { + // Now copy the metadata of the original file to the new file ------------ + + ImageInfo newInfo(d->imageInfoCurrent->copyItem(dstAlbum, m_savingContext->destinationURL.fileName())); + + if ( d->urlList.find(m_savingContext->destinationURL) == d->urlList.end() ) + { // The image file did not exist in the list. + KURL::List::iterator it = d->urlList.find(m_savingContext->srcURL); + int index = d->urlList.findIndex(m_savingContext->srcURL); + d->urlList.insert(it, m_savingContext->destinationURL); + d->imageInfoCurrent = new ImageInfo(newInfo); + d->imageInfoList.insert(index, d->imageInfoCurrent); + } + else if (d->urlCurrent != m_savingContext->destinationURL) + { + for (ImageInfo *info = d->imageInfoList.first(); info; info = d->imageInfoList.next()) + { + if (info->kurl() == m_savingContext->destinationURL) + { + d->imageInfoCurrent = new ImageInfo(newInfo); + // setAutoDelete is true + d->imageInfoList.replace(d->imageInfoList.at(), d->imageInfoCurrent); + break; + } + } + } + + d->urlCurrent = m_savingContext->destinationURL; + m_canvas->switchToLastSaved(m_savingContext->destinationURL.path()); + + slotUpdateItemInfo(); + + // If the DImg is put in the cache under the new name, this means the new file will not be reloaded. + // This may irritate users who want to check for quality loss in lossy formats. + // In any case, only do that if the format did not change - too many assumptions otherwise (see bug #138949). + if (m_savingContext->originalFormat == m_savingContext->format) + LoadingCacheInterface::putImage(m_savingContext->destinationURL.path(), m_canvas->currentImage()); + + // notify main app that file changed or a file is added + if(m_savingContext->destinationExisted) + emit signalFileModified(m_savingContext->destinationURL); + else + emit signalFileAdded(m_savingContext->destinationURL); + + // all that is done in slotLoadCurrent, except for loading + KURL::List::iterator it = d->urlList.find(d->urlCurrent); + + if (it != d->urlList.end()) + { + setViewToURL(*it); + m_canvas->preload((*++it).path()); + } + } + else + { + //TODO: make the user aware that the new path has not been used as new current filename + // because it is outside the digikam album hierachy + } +} + +bool ImageWindow::save() +{ + // Sanity check. Just to be homogenous with SaveAs. + if (d->imageInfoCurrent) + { + // Write metadata from database to DImg + MetadataHub hub; + hub.load(d->imageInfoCurrent); + DImg image(m_canvas->currentImage()); + hub.write(image, MetadataHub::FullWrite); + } + + startingSave(d->urlCurrent); + return true; +} + +bool ImageWindow::saveAs() +{ + // If image editor is started from CameraGUI, there is no ImageInfo instance to use. + if (d->imageInfoCurrent) + { + // Write metadata from database to DImg + MetadataHub hub; + hub.load(d->imageInfoCurrent); + DImg image(m_canvas->currentImage()); + hub.write(image, MetadataHub::FullWrite); + } + + return ( startingSaveAs(d->urlCurrent) ); +} + +void ImageWindow::slotDeleteCurrentItem() +{ + deleteCurrentItem(true, false); +} + +void ImageWindow::slotDeleteCurrentItemPermanently() +{ + deleteCurrentItem(true, true); +} + +void ImageWindow::slotDeleteCurrentItemPermanentlyDirectly() +{ + deleteCurrentItem(false, true); +} + +void ImageWindow::slotTrashCurrentItemDirectly() +{ + deleteCurrentItem(false, false); +} + +void ImageWindow::deleteCurrentItem(bool ask, bool permanently) +{ + // This function implements all four of the above slots. + // The meaning of permanently differs depending on the value of ask + + KURL u; + u.setPath(d->urlCurrent.directory()); + PAlbum *palbum = AlbumManager::instance()->findPAlbum(u); + + // if available, provide a digikamalbums:// URL to TDEIO + KURL kioURL; + if (d->imageInfoCurrent) + kioURL = d->imageInfoCurrent->kurlForKIO(); + else + kioURL = d->urlCurrent; + KURL fileURL = d->urlCurrent; + + if (!palbum) + return; + + bool useTrash; + + if (ask) + { + bool preselectDeletePermanently = permanently; + + DeleteDialog dialog(this); + + KURL::List urlList; + urlList.append(d->urlCurrent); + if (!dialog.confirmDeleteList(urlList, + DeleteDialogMode::Files, + preselectDeletePermanently ? + DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) + return; + + useTrash = !dialog.shouldDelete(); + } + else + { + useTrash = !permanently; + } + + // bring all (sidebar) to a defined state without letting them sit on the deleted file + emit signalNoCurrentItem(); + + // trash does not like non-local URLs, put is not implemented + if (useTrash) + kioURL = fileURL; + + if (!SyncJob::del(kioURL, useTrash)) + { + TQString errMsg(SyncJob::lastErrorMsg()); + KMessageBox::error(this, errMsg, errMsg); + return; + } + + emit signalFileDeleted(d->urlCurrent); + + KURL CurrentToRemove = d->urlCurrent; + KURL::List::iterator it = d->urlList.find(d->urlCurrent); + int index = d->imageInfoList.find(d->imageInfoCurrent); + + if (it != d->urlList.end()) + { + if (d->urlCurrent != d->urlList.last()) + { + // Try to get the next image in the current Album... + + KURL urlNext = *(++it); + d->urlCurrent = urlNext; + d->imageInfoCurrent = d->imageInfoList.at(index + 1); + d->urlList.remove(CurrentToRemove); + d->imageInfoList.remove(index); + slotLoadCurrent(); + return; + } + else if (d->urlCurrent != d->urlList.first()) + { + // Try to get the previous image in the current Album. + + KURL urlPrev = *(--it); + d->urlCurrent = urlPrev; + d->imageInfoCurrent = d->imageInfoList.at(index - 1); + d->urlList.remove(CurrentToRemove); + d->imageInfoList.remove(index); + slotLoadCurrent(); + return; + } + } + + // No image in the current Album -> Quit ImageEditor... + + KMessageBox::information(this, + i18n("There is no image to show in the current album.\n" + "The image editor will be closed."), + i18n("No Image in Current Album")); + + close(); +} + +void ImageWindow::slotFileMetadataChanged(const KURL &url) +{ + if (url == d->urlCurrent) + { + m_canvas->readMetadataFromFile(url.path()); + } +} + +void ImageWindow::slotFilePrint() +{ + printImage(d->urlCurrent); +}; + +void ImageWindow::slideShow(bool startWithCurrent, SlideShowSettings& settings) +{ + float cnt; + DMetadata meta; + int i = 0; + m_cancelSlideShow = false; + settings.exifRotate = AlbumSettings::instance()->getExifRotate(); + + if (!d->imageInfoList.isEmpty()) + { + // We have started image editor from Album GUI. we get picture comments from database. + + m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, + i18n("Preparing slideshow. Please wait...")); + + cnt = (float)d->imageInfoList.count(); + + for (ImageInfo *info = d->imageInfoList.first() ; + !m_cancelSlideShow && info ; info = d->imageInfoList.next()) + { + SlidePictureInfo pictInfo; + pictInfo.comment = info->caption(); + + // Perform optimizations: only read pictures metadata if necessary. + if (settings.printApertureFocal || settings.printExpoSensitivity || settings.printMakeModel) + { + meta.load(info->kurl().path()); + pictInfo.photoInfo = meta.getPhotographInformations(); + } + + // In case of dateTime extraction from metadata failed + pictInfo.photoInfo.dateTime = info->dateTime(); + settings.pictInfoMap.insert(info->kurl(), pictInfo); + + m_nameLabel->setProgressValue((int)((i++/cnt)*100.0)); + kapp->processEvents(); + } + } + else + { + // We have started image editor from Camera GUI. we get picture comments from metadata. + + m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, + i18n("Preparing slideshow. Please wait...")); + + cnt = (float)d->urlList.count(); + + for (KURL::List::Iterator it = d->urlList.begin() ; + !m_cancelSlideShow && (it != d->urlList.end()) ; ++it) + { + SlidePictureInfo pictInfo; + meta.load((*it).path()); + pictInfo.comment = meta.getImageComment(); + pictInfo.photoInfo = meta.getPhotographInformations(); + settings.pictInfoMap.insert(*it, pictInfo); + + m_nameLabel->setProgressValue((int)((i++/cnt)*100.0)); + kapp->processEvents(); + } + } + + m_nameLabel->progressBarMode(StatusProgressBar::TextMode, TQString()); + + if (!m_cancelSlideShow) + { + settings.exifRotate = AlbumSettings::instance()->getExifRotate(); + settings.fileList = d->urlList; + + SlideShow *slide = new SlideShow(settings); + if (startWithCurrent) + slide->setCurrent(d->urlCurrent); + + slide->show(); + } +} + +void ImageWindow::dragMoveEvent(TQDragMoveEvent *e) +{ + int albumID; + TQValueList albumIDs; + TQValueList imageIDs; + KURL::List urls; + KURL::List kioURLs; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs) || + AlbumDrag::decode(e, urls, albumID) || + TagDrag::canDecode(e)) + { + e->accept(); + return; + } + + e->ignore(); +} + +void ImageWindow::dropEvent(TQDropEvent *e) +{ + int albumID; + TQValueList albumIDs; + TQValueList imageIDs; + KURL::List urls; + KURL::List kioURLs; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs)) + { + ImageInfoList imageInfoList; + + for (TQValueList::const_iterator it = imageIDs.begin(); + it != imageIDs.end(); ++it) + { + ImageInfo *info = new ImageInfo(*it); + imageInfoList.append(info); + } + + if (imageInfoList.isEmpty()) + { + e->ignore(); + return; + } + + TQString ATitle; + AlbumManager* man = AlbumManager::instance(); + PAlbum* palbum = man->findPAlbum(albumIDs.first()); + if (palbum) ATitle = palbum->title(); + + TAlbum* talbum = man->findTAlbum(albumIDs.first()); + if (talbum) ATitle = talbum->title(); + + loadImageInfos(imageInfoList, imageInfoList.first(), + i18n("Album \"%1\"").arg(ATitle), true); + e->accept(); + } + else if (AlbumDrag::decode(e, urls, albumID)) + { + AlbumManager* man = AlbumManager::instance(); + TQValueList itemIDs = man->albumDB()->getItemIDsInAlbum(albumID); + ImageInfoList imageInfoList; + + for (TQValueList::const_iterator it = itemIDs.begin(); + it != itemIDs.end(); ++it) + { + ImageInfo *info = new ImageInfo(*it); + imageInfoList.append(info); + } + + if (imageInfoList.isEmpty()) + { + e->ignore(); + return; + } + + TQString ATitle; + PAlbum* palbum = man->findPAlbum(albumIDs.first()); + if (palbum) ATitle = palbum->title(); + + loadImageInfos(imageInfoList, imageInfoList.first(), + i18n("Album \"%1\"").arg(ATitle), true); + e->accept(); + } + else if(TagDrag::canDecode(e)) + { + TQByteArray ba = e->encodedData("digikam/tag-id"); + TQDataStream ds(ba, IO_ReadOnly); + int tagID; + ds >> tagID; + + AlbumManager* man = AlbumManager::instance(); + TQValueList itemIDs = man->albumDB()->getItemIDsInTag(tagID, true); + ImageInfoList imageInfoList; + + for (TQValueList::const_iterator it = itemIDs.begin(); + it != itemIDs.end(); ++it) + { + ImageInfo *info = new ImageInfo(*it); + imageInfoList.append(info); + } + + if (imageInfoList.isEmpty()) + { + e->ignore(); + return; + } + + TQString ATitle; + TAlbum* talbum = man->findTAlbum(tagID); + if (talbum) ATitle = talbum->title(); + + loadImageInfos(imageInfoList, imageInfoList.first(), + i18n("Album \"%1\"").arg(ATitle), true); + e->accept(); + } + else + { + e->ignore(); + } +} + +void ImageWindow::slotRevert() +{ + if(!promptUserSave(d->urlCurrent)) + return; + + m_canvas->slotRestore(); +} + +void ImageWindow::slotChangeTheme(const TQString& theme) +{ + AlbumSettings::instance()->setCurrentTheme(theme); + ThemeEngine::instance()->slotChangeTheme(theme); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/editor/imagewindow.h b/src/utilities/imageeditor/editor/imagewindow.h new file mode 100644 index 00000000..389518a8 --- /dev/null +++ b/src/utilities/imageeditor/editor/imagewindow.h @@ -0,0 +1,155 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-02-12 + * Description : digiKam image editor GUI + * + * Copyright (C) 2004-2005 by Renchi Raju + * Copyright (C) 2004-2008 by Gilles Caulier + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEWINDOW_H +#define IMAGEWINDOW_H + +// TQt includes. + +#include + +// KDE includes. + +#include + +// Local includes. + +#include "editorwindow.h" +#include "imageinfo.h" + +class TQDragMoveEvent; +class TQDropEvent; + +namespace Digikam +{ + +class AlbumIconView; +class ImageWindowPriv; +class SlideShowSettings; + +class ImageWindow : public EditorWindow +{ + TQ_OBJECT + + +public: + + ~ImageWindow(); + + void loadURL(const KURL::List& urlList, const KURL& urlCurrent, + const TQString& caption=TQString(), + bool allowSaving=true); + + void loadImageInfos(const ImageInfoList &imageInfoList, + ImageInfo *imageInfoCurrent, + const TQString& caption, bool allowSaving); + + static ImageWindow* imagewindow(); + static bool imagewindowCreated(); + + void applySettings(); + void refreshView(); + bool setup(bool iccSetupPage=false); + + bool queryClose(); + +signals: + + void signalFileDeleted(const KURL& url); + void signalFileAdded(const KURL& url); + void signalFileModified(const KURL& url); + void signalURLChanged(const KURL& url); + +private: + + void loadCurrentList(const TQString& caption, bool allowSaving); + void closeEvent(TQCloseEvent* e); + + void dragMoveEvent(TQDragMoveEvent *e); + void dropEvent(TQDropEvent *e); + + void setupActions(); + void setupConnections(); + void setupUserArea(); + void toggleGUI2FullScreen(); + + bool save(); + bool saveAs(); + + void saveIsComplete(); + void saveAsIsComplete(); + void setViewToURL(const KURL &url); + void deleteCurrentItem(bool ask, bool permanently); + + void slideShow(bool startWithCurrent, SlideShowSettings& settings); + + Sidebar* rightSideBar() const; + + ImageWindow(); + +private slots: + + void slotForward(); + void slotBackward(); + void slotFirst(); + void slotLast(); + void slotFilePrint(); + + void slotLoadCurrent(); + void slotDeleteCurrentItem(); + void slotDeleteCurrentItemPermanently(); + void slotDeleteCurrentItemPermanentlyDirectly(); + void slotTrashCurrentItemDirectly(); + + void slotChanged(); + void slotUndoStateChanged(bool, bool, bool); + void slotUpdateItemInfo(); + + void slotContextMenu(); + void slotRevert(); + + void slotAssignTag(int tagID); + void slotRemoveTag(int tagID); + + void slotAssignRatingNoStar(); + void slotAssignRatingOneStar(); + void slotAssignRatingTwoStar(); + void slotAssignRatingThreeStar(); + void slotAssignRatingFourStar(); + void slotAssignRatingFiveStar(); + void slotAssignRating(int rating); + + void slotFileMetadataChanged(const KURL &); + void slotChangeTheme(const TQString& theme); + +private: + + ImageWindowPriv *d; + + static ImageWindow *m_instance; +}; + +} // namespace Digikam + +#endif /* IMAGEWINDOW_H */ diff --git a/src/utilities/imageeditor/editor/savingcontextcontainer.h b/src/utilities/imageeditor/editor/savingcontextcontainer.h new file mode 100644 index 00000000..c747a357 --- /dev/null +++ b/src/utilities/imageeditor/editor/savingcontextcontainer.h @@ -0,0 +1,89 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-20 + * Description : image editor GUI saving context container + * + * Copyright (C) 2006-2007 by Gilles Caulier + * Copyright (C) 2006-2007 by Marcel Wiesweg + * + * 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. + * + * ============================================================ */ + +#ifndef SAVINGCONTEXTCONTAINER_H +#define SAVINGCONTEXTCONTAINER_H + +// TQt includes. + +#include + +// KDE includes. + +#include +#include + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT SavingContextContainer +{ + +public: + + SavingContextContainer() + { + savingState = SavingStateNone; + synchronizingState = NormalSaving; + saveTempFile = 0; + destinationExisted = false; + synchronousSavingResult = false; + abortingSaving = false; + } + + enum SavingState + { + SavingStateNone, + SavingStateSave, + SavingStateSaveAs + }; + + enum SynchronizingState + { + NormalSaving, + SynchronousSaving + }; + + SavingState savingState; + SynchronizingState synchronizingState; + bool synchronousSavingResult; + bool destinationExisted; + bool abortingSaving; + + TQString originalFormat; + TQString format; + + KURL srcURL; + KURL destinationURL; + + KTempFile *saveTempFile; +}; + +} // namespace Digikam + +#endif /* SAVINGCONTEXTCONTAINER_H */ -- cgit v1.2.1