diff options
Diffstat (limited to 'src/utilities/imageeditor')
53 files changed, 14743 insertions, 0 deletions
diff --git a/src/utilities/imageeditor/Makefile.am b/src/utilities/imageeditor/Makefile.am new file mode 100644 index 00000000..c324c683 --- /dev/null +++ b/src/utilities/imageeditor/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = canvas tools rawimport editor diff --git a/src/utilities/imageeditor/canvas/Makefile.am b/src/utilities/imageeditor/canvas/Makefile.am new file mode 100644 index 00000000..740f854e --- /dev/null +++ b/src/utilities/imageeditor/canvas/Makefile.am @@ -0,0 +1,28 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdimgcanvas.la + +libdimgcanvas_la_SOURCES = dimginterface.cpp colorcorrectiondlg.cpp \ + canvas.cpp undocache.cpp \ + undoaction.cpp undomanager.cpp \ + imagepluginloader.cpp imageplugin.cpp + +libdimgcanvas_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TIFF) + +INCLUDES = -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/threadimageio \ + -I$(top_srcdir)/src/utilities/splashscreen \ + -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/rawimport \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/widgets/common \ + $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes) + +digikaminclude_HEADERS = imageplugin.h + +digikamincludedir = $(includedir)/digikam diff --git a/src/utilities/imageeditor/canvas/canvas.cpp b/src/utilities/imageeditor/canvas/canvas.cpp new file mode 100644 index 00000000..89758c3d --- /dev/null +++ b/src/utilities/imageeditor/canvas/canvas.cpp @@ -0,0 +1,1421 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-09 + * Description : image editor canvas management class + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> +#include <cmath> + +// TQt includes. + +#include <tqtooltip.h> +#include <tqfile.h> +#include <tqstring.h> +#include <tqevent.h> +#include <tqpoint.h> +#include <tqpainter.h> +#include <tqpen.h> +#include <tqpixmap.h> +#include <tqstyle.h> +#include <tqapplication.h> +#include <tqcursor.h> +#include <tqimage.h> +#include <tqregion.h> +#include <tqtimer.h> +#include <tqcache.h> +#include <tqcolor.h> +#include <tqdragobject.h> +#include <tqclipboard.h> +#include <tqtoolbutton.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <kdatetbl.h> +#include <tdeglobalsettings.h> + +// Local includes. + +#include "ddebug.h" +#include "imagehistogram.h" +#include "imagepaniconwidget.h" +#include "dimginterface.h" +#include "iccsettingscontainer.h" +#include "exposurecontainer.h" +#include "iofilesettingscontainer.h" +#include "loadingcacheinterface.h" +#include "canvas.h" +#include "canvas.moc" + +namespace Digikam +{ + +class CanvasPrivate +{ + +public: + + CanvasPrivate() : + tileSize(128), minZoom(0.1), maxZoom(12.0), zoomMultiplier(1.2) + { + rubber = 0; + pressedMoved = false; + pressedMoving = false; + ltActive = false; + rtActive = false; + lbActive = false; + rbActive = false; + midButtonPressed = false; + midButtonX = 0; + midButtonY = 0; + panIconPopup = 0; + panIconWidget = 0; + cornerButton = 0; + parent = 0; + im = 0; + rubber = 0; + autoZoom = false; + fullScreen = false; + zoom = 1.0; + tileTmpPix = new TQPixmap(tileSize, tileSize); + + tileCache.setMaxCost((10*1024*1024)/(tileSize*tileSize*4)); + tileCache.setAutoDelete(true); + } + + bool autoZoom; + bool fullScreen; + bool pressedMoved; + bool pressedMoving; + bool ltActive; + bool rtActive; + bool lbActive; + bool rbActive; + bool midButtonPressed; + + const int tileSize; + int midButtonX; + int midButtonY; + + double zoom; + const double minZoom; + const double maxZoom; + const double zoomMultiplier; + + TQToolButton *cornerButton; + + TQRect *rubber; + TQRect pixmapRect; + + TQCache<TQPixmap> tileCache; + + TQPixmap* tileTmpPix; + TQPixmap qcheck; + + TQColor bgColor; + + TQWidget *parent; + + TDEPopupFrame *panIconPopup; + + DImgInterface *im; + + ImagePanIconWidget *panIconWidget; +}; + +Canvas::Canvas(TQWidget *parent) + : TQScrollView(parent) +{ + d = new CanvasPrivate; + d->im = new DImgInterface(); + d->parent = parent; + d->bgColor.setRgb(0, 0, 0); + + d->qcheck.resize(16, 16); + TQPainter p(&d->qcheck); + p.fillRect(0, 0, 8, 8, TQColor(144, 144, 144)); + p.fillRect(8, 8, 8, 8, TQColor(144, 144, 144)); + p.fillRect(0, 8, 8, 8, TQColor(100, 100, 100)); + p.fillRect(8, 0, 8, 8, TQColor(100, 100, 100)); + p.end(); + + d->cornerButton = new TQToolButton(this); + d->cornerButton->setIconSet(SmallIcon("move")); + d->cornerButton->hide(); + TQToolTip::add(d->cornerButton, i18n("Pan the image to a region")); + setCornerWidget(d->cornerButton); + + viewport()->setBackgroundMode(TQt::NoBackground); + viewport()->setMouseTracking(false); + setFrameStyle( TQFrame::NoFrame ); + + // ------------------------------------------------------------ + + connect(this, TQ_SIGNAL(signalZoomChanged(double)), + this, TQ_SLOT(slotZoomChanged(double))); + + connect(d->cornerButton, TQ_SIGNAL(pressed()), + this, TQ_SLOT(slotCornerButtonPressed())); + + connect(d->im, TQ_SIGNAL(signalModified()), + this, TQ_SLOT(slotModified())); + + connect(d->im, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)), + this, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool))); + + connect(d->im, TQ_SIGNAL(signalLoadingStarted(const TQString&)), + this, TQ_SIGNAL(signalLoadingStarted(const TQString&))); + + connect(d->im, TQ_SIGNAL(signalImageLoaded(const TQString&, bool)), + this, TQ_SLOT(slotImageLoaded(const TQString&, bool))); + + connect(d->im, TQ_SIGNAL(signalImageSaved(const TQString&, bool)), + this, TQ_SLOT(slotImageSaved(const TQString&, bool))); + + connect(d->im, TQ_SIGNAL(signalLoadingProgress(const TQString&, float)), + this, TQ_SIGNAL(signalLoadingProgress(const TQString&, float))); + + connect(d->im, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), + this, TQ_SIGNAL(signalSavingProgress(const TQString&, float))); + + connect(this, TQ_SIGNAL(signalSelected(bool)), + this, TQ_SLOT(slotSelected())); +} + +Canvas::~Canvas() +{ + delete d->tileTmpPix; + delete d->im; + + if (d->rubber) + delete d->rubber; + + delete d; +} + +void Canvas::resetImage() +{ + reset(); + viewport()->setUpdatesEnabled(false); + d->im->resetImage(); +} + +void Canvas::reset() +{ + if (d->rubber) + { + delete d->rubber; + d->rubber = 0; + if (d->im->imageValid()) + emit signalSelected(false); + } + + d->tileCache.clear(); +} + +void Canvas::load(const TQString& filename, IOFileSettingsContainer *IOFileSettings) +{ + reset(); + + viewport()->setUpdatesEnabled(false); + + d->im->load( filename, IOFileSettings, d->parent ); + + emit signalPrepareToLoad(); +} + +void Canvas::slotImageLoaded(const TQString& filePath, bool success) +{ + d->zoom = 1.0; + d->im->zoom(d->zoom); + + if (d->autoZoom) + updateAutoZoom(); + + updateContentsSize(true); + + viewport()->setUpdatesEnabled(true); + viewport()->update(); + + emit signalZoomChanged(d->zoom); + + emit signalLoadingFinished(filePath, success); +} + +void Canvas::preload(const TQString& /*filename*/) +{ +// d->im->preload(filename); +} + +/* +These code part are unused and untested +void Canvas::save(const TQString& filename, IOFileSettingsContainer *IOFileSettings) +{ + d->im->save(filename, IOFileSettings); + emit signalSavingStarted(filename); +} + +void Canvas::saveAs(const TQString& filename,IOFileSettingsContainer *IOFileSettings, + const TQString& mimeType) +{ + d->im->saveAs(filename, IOFileSettings, mimeType); + emit signalSavingStarted(filename); +} +*/ + +void Canvas::saveAs(const TQString& filename, IOFileSettingsContainer *IOFileSettings, + bool setExifOrientationTag, const TQString& mimeType) +{ + d->im->saveAs(filename, IOFileSettings, setExifOrientationTag, mimeType); + emit signalSavingStarted(filename); +} + +void Canvas::slotImageSaved(const TQString& filePath, bool success) +{ + emit signalSavingFinished(filePath, success); +} + +void Canvas::switchToLastSaved(const TQString& newFilename) +{ + d->im->switchToLastSaved(newFilename); +} + +void Canvas::abortSaving() +{ + d->im->abortSaving(); +} + +void Canvas::setModified() +{ + d->im->setModified(); +} + +void Canvas::readMetadataFromFile(const TQString &file) +{ + d->im->readMetadataFromFile(file); +} + +void Canvas::clearUndoHistory() +{ + d->im->clearUndoManager(); +} + +void Canvas::setUndoHistoryOrigin() +{ + d->im->setUndoManagerOrigin(); +} + +void Canvas::updateUndoState() +{ + d->im->updateUndoState(); +} + +DImg Canvas::currentImage() +{ + return DImg(*d->im->getImg()); +} + +TQString Canvas::currentImageFileFormat() +{ + return d->im->getImageFormat(); +} + +TQString Canvas::currentImageFilePath() +{ + return d->im->getImageFilePath(); +} + +int Canvas::imageWidth() +{ + return d->im->origWidth(); +} + +int Canvas::imageHeight() +{ + return d->im->origHeight(); +} + +bool Canvas::isReadOnly() +{ + return d->im->isReadOnly(); +} + +TQRect Canvas::getSelectedArea() +{ + int x, y, w, h; + d->im->getSelectedArea(x, y, w, h); + return ( TQRect(x, y, w, h) ); +} + +DImgInterface *Canvas::interface() const +{ + return d->im; +} + +void Canvas::makeDefaultEditingCanvas() +{ + DImgInterface::setDefaultInterface(d->im); +} + +double Canvas::calcAutoZoomFactor() +{ + if (!d->im->imageValid()) return d->zoom; + + double srcWidth = d->im->origWidth(); + double srcHeight = d->im->origHeight(); + double dstWidth = contentsRect().width(); + double dstHeight = contentsRect().height(); + return TQMIN(dstWidth/srcWidth, dstHeight/srcHeight); +} + +void Canvas::updateAutoZoom() +{ + d->zoom = calcAutoZoomFactor(); + d->im->zoom(d->zoom); + emit signalZoomChanged(d->zoom); +} + +void Canvas::updateContentsSize(bool deleteRubber) +{ + viewport()->setUpdatesEnabled(false); + + if (deleteRubber && d->rubber) + { + delete d->rubber; + d->rubber = 0; + d->ltActive = false; + d->rtActive = false; + d->lbActive = false; + d->rbActive = false; + d->pressedMoved = false; + viewport()->unsetCursor(); + viewport()->setMouseTracking(false); + if (d->im->imageValid()) + emit signalSelected(false); + } + + int wZ = d->im->width(); + int hZ = d->im->height(); + + if (visibleWidth() > wZ || visibleHeight() > hZ) + { + // Center the image + int centerx = contentsRect().width()/2; + int centery = contentsRect().height()/2; + int xoffset = int(centerx - wZ/2); + int yoffset = int(centery - hZ/2); + xoffset = TQMAX(xoffset, 0); + yoffset = TQMAX(yoffset, 0); + + d->pixmapRect = TQRect(xoffset, yoffset, wZ, hZ); + } + else + { + d->pixmapRect = TQRect(0, 0, wZ, hZ); + } + + if (!deleteRubber && d->rubber) + { + int xSel, ySel, wSel, hSel; + d->im->getSelectedArea(xSel, ySel, wSel, hSel); + xSel = (int)((xSel * d->tileSize) / floor(d->tileSize / d->zoom)); + ySel = (int)((ySel * d->tileSize) / floor(d->tileSize / d->zoom)); + wSel = (int)((wSel * d->tileSize) / floor(d->tileSize / d->zoom)); + hSel = (int)((hSel * d->tileSize) / floor(d->tileSize / d->zoom)); + d->rubber->setX(xSel); + d->rubber->setY(ySel); + d->rubber->setWidth(wSel); + d->rubber->setHeight(hSel); + d->rubber->moveBy(d->pixmapRect.x(), d->pixmapRect.y()); + } + + d->tileCache.clear(); + resizeContents(wZ, hZ); + viewport()->setUpdatesEnabled(true); +} + +void Canvas::resizeEvent(TQResizeEvent* e) +{ + if (!e) + return; + + TQScrollView::resizeEvent(e); + + if (d->autoZoom) + updateAutoZoom(); + + updateContentsSize(false); + + // No need to repaint. its called + // automatically after resize + + // To be sure than corner widget used to pan image will be hide/show + // accordinly with resize event. + slotZoomChanged(d->zoom); +} + +void Canvas::viewportPaintEvent(TQPaintEvent *e) +{ + TQRect er(e->rect()); + er = TQRect(TQMAX(er.x() - 1, 0), + TQMAX(er.y() - 1, 0), + TQMIN(er.width() + 2, contentsRect().width()), + TQMIN(er.height() + 2, contentsRect().height())); + + paintViewport(er, (d->zoom <= 1.0) ? true : false); +} + +void Canvas::paintViewport(const TQRect& er, bool antialias) +{ + TQRect o_cr(viewportToContents(er.topLeft()), viewportToContents(er.bottomRight())); + TQRect cr = o_cr; + + TQRegion clipRegion(er); + cr = d->pixmapRect.intersect(cr); + + if (!cr.isEmpty() && d->im->imageValid()) + { + clipRegion -= TQRect(contentsToViewport(cr.topLeft()), cr.size()); + + TQRect pr = TQRect(cr.x() - d->pixmapRect.x(), cr.y() - d->pixmapRect.y(), + cr.width(), cr.height()); + + int x1 = (int)floor((double)pr.x() / (double)d->tileSize) * d->tileSize; + int y1 = (int)floor((double)pr.y() / (double)d->tileSize) * d->tileSize; + int x2 = (int)ceilf((double)pr.right() / (double)d->tileSize) * d->tileSize; + int y2 = (int)ceilf((double)pr.bottom() / (double)d->tileSize) * d->tileSize; + + TQPixmap pix(d->tileSize, d->tileSize); + int sx, sy, sw, sh; + int step = (int)floor(d->tileSize / d->zoom); + + bool hasRubber = (d->rubber && d->pressedMoved && d->pressedMoving && d->rubber->intersects(pr)); + if (hasRubber) + { + // remove rubber + drawRubber(); + } + + for (int j = y1 ; j < y2 ; j += d->tileSize) + { + for (int i = x1 ; i < x2 ; i += d->tileSize) + { + TQString key = TQString("%1,%2").arg(i).arg(j); + TQPixmap *pix = d->tileCache.find(key); + + if (!pix) + { + if (antialias) + { + pix = new TQPixmap(d->tileSize, d->tileSize); + d->tileCache.insert(key, pix); + } + else + { + pix = d->tileTmpPix; + } + + if (d->im->hasAlpha()) + { + TQPainter p(pix); + p.drawTiledPixmap(0, 0, d->tileSize, d->tileSize, + d->qcheck, 0, 0); + p.end(); + } + else + { + pix->fill(d->bgColor); + } + + // NOTE : with implementations <= 0.9.1, the canvas doesn't work properly using high zoom level (> 500). + // The sx, sy, sw, sh values haven't be computed properly and "tile" artefacts been appears + // over the image. Look the example here: + // http://digikam3rdparty.free.fr/Screenshots/editorhighzoomartefact.png + // Note than these "tile" artifacts are not the real tiles of canvas. + // The new implementation below fix this problem to handle properly the areas to + // use from the source image to generate the canvas pixmap tiles. + + sx = (int)floor((double)i / d->tileSize) * step; + sy = (int)floor((double)j / d->tileSize) * step; + sw = step; + sh = step; + + if (d->rubber && d->pressedMoved && !d->pressedMoving) + { + TQRect rr(d->rubber->normalize()); + TQRect r(i, j, d->tileSize, d->tileSize); + + d->im->paintOnDevice(pix, sx, sy, sw, sh, + 0, 0, d->tileSize, d->tileSize, + rr.x() - i - d->pixmapRect.x(), + rr.y() - j - d->pixmapRect.y(), + rr.width(), rr.height(), + antialias); + + rr.moveBy(-i -d->pixmapRect.x(), -j -d->pixmapRect.y()); + + TQPainter p(pix); + p.setPen(TQPen(TQColor(250, 250, 255), 1)); + p.drawRect(rr); + if (rr.width() >= 10 && rr.height() >= 10) + { + p.drawRect(rr.x(), rr.y(), 5, 5); + p.drawRect(rr.x(), rr.y()+rr.height()-5, 5, 5); + p.drawRect(rr.x()+rr.width()-5, rr.y()+rr.height()-5, 5, 5); + p.drawRect(rr.x()+rr.width()-5, rr.y(), 5, 5); + } + p.end(); + } + else + { + d->im->paintOnDevice(pix, sx, sy, sw, sh, + 0, 0, d->tileSize, d->tileSize, + antialias); + } + } + + TQRect r(i, j, d->tileSize, d->tileSize); + TQRect ir = pr.intersect(r); + TQPoint pt(contentsToViewport(TQPoint(ir.x() + d->pixmapRect.x(), + ir.y() + d->pixmapRect.y()))); + + bitBlt(viewport(), pt.x(), pt.y(), + pix, + ir.x()-r.x(), ir.y()-r.y(), + ir.width(), ir.height()); + } + } + + if (hasRubber) + { + // restore rubber + drawRubber(); + } + } + + TQPainter painter(viewport()); + painter.setClipRegion(clipRegion); + painter.fillRect(er, d->bgColor); + painter.end(); +} + +void Canvas::drawRubber() +{ + if (!d->rubber || !d->im->imageValid()) + return; + + TQPainter p(viewport()); + p.setRasterOp(TQt::NotROP ); + p.setPen(TQPen(TQt::color0, 1)); + p.setBrush(NoBrush); + + TQRect r(d->rubber->normalize()); + r = TQRect(contentsToViewport(TQPoint(r.x(), r.y())), r.size()); + + TQPoint pnt(r.x(), r.y()); + + style().drawPrimitive(TQStyle::PE_FocusRect, &p, + TQRect(pnt.x(), pnt.y(), r.width(), r.height()), + colorGroup(), TQStyle::Style_Default, + TQStyleOption(colorGroup().base())); + p.end(); +} + +void Canvas::contentsMousePressEvent(TQMouseEvent *e) +{ + if (!e || e->button() == TQt::RightButton) + return; + + d->midButtonPressed = false; + + if (e->button() == TQt::LeftButton) + { + if (d->ltActive || d->rtActive || + d->lbActive || d->rbActive) + { + Q_ASSERT( d->rubber ); + if (!d->rubber) + return; + + // Set diagonally opposite corner as anchor + + TQRect r(d->rubber->normalize()); + + if (d->ltActive) + { + d->rubber->setTopLeft(r.bottomRight()); + d->rubber->setBottomRight(r.topLeft()); + } + else if (d->rtActive) + { + d->rubber->setTopLeft(r.bottomLeft()); + d->rubber->setBottomRight(r.topRight()); + } + else if (d->lbActive) + { + d->rubber->setTopLeft(r.topRight()); + d->rubber->setBottomRight(r.bottomLeft()); + } + else if (d->rbActive) + { + d->rubber->setTopLeft(r.topLeft()); + d->rubber->setBottomRight(r.bottomLeft()); + } + + viewport()->setMouseTracking(false); + d->pressedMoved = false; + d->pressedMoving = true; + + d->tileCache.clear(); + viewport()->repaint(false); + + return; + } + } + else if (e->button() == TQt::MidButton) + { + if (visibleWidth() < d->im->width() || + visibleHeight() < d->im->height()) + { + viewport()->setCursor(TQt::SizeAllCursor); + d->midButtonPressed = true; + d->midButtonX = e->x(); + d->midButtonY = e->y(); + } + return; + } + + if (d->rubber) + { + delete d->rubber; + d->rubber = 0; + } + + d->rubber = new TQRect(e->x(), e->y(), 0, 0); + + if (d->pressedMoved) + { + d->tileCache.clear(); + viewport()->update(); + } + + d->pressedMoved = false; + d->pressedMoving = true; + + viewport()->setMouseTracking(false); +} + +void Canvas::contentsMouseMoveEvent(TQMouseEvent *e) +{ + if (!e) + return; + + if (e->state() & TQt::MidButton) + { + if (d->midButtonPressed) + { + scrollBy(d->midButtonX - e->x(), + d->midButtonY - e->y()); + } + } + else if (!viewport()->hasMouseTracking()) + { + if (!d->rubber) + return; + + if (e->state() != TQt::LeftButton && + !(d->ltActive || d->rtActive || + d->lbActive || d->rbActive)) + return; + + // Clear old rubber. + if (d->pressedMoved) + drawRubber(); + + // Move content if necessary. + blockSignals(true); + setUpdatesEnabled(false); + ensureVisible(e->x(), e->y(), 10, 10); + setUpdatesEnabled(true); + blockSignals(false); + + // draw the new rubber position. + int r, b; + r = (e->x() > d->pixmapRect.left()) ? e->x() : d->pixmapRect.left(); + r = (r < d->pixmapRect.right()) ? r : d->pixmapRect.right(); + b = (e->y() > d->pixmapRect.top()) ? e->y() : d->pixmapRect.top(); + b = (b < d->pixmapRect.bottom()) ? b : d->pixmapRect.bottom(); + d->rubber->setRight(r); + d->rubber->setBottom(b); + drawRubber(); + + d->pressedMoved = true; + d->pressedMoving = true; + + // To refresh editor status bar with current selection. + emit signalSelectionChanged(calcSeletedArea()); + } + else + { + if (!d->rubber) + return; + + TQRect r(d->rubber->normalize()); + + TQRect lt(r.x()-5, r.y()-5, 10, 10); + TQRect rt(r.x()+r.width()-5, r.y()-5, 10, 10); + TQRect lb(r.x()-5, r.y()+r.height()-5, 10, 10); + TQRect rb(r.x()+r.width()-5, r.y()+r.height()-5, 10, 10); + + d->ltActive = false; + d->rtActive = false; + d->lbActive = false; + d->rbActive = false; + + if (lt.contains(e->x(), e->y())) + { + viewport()->setCursor(TQt::SizeFDiagCursor); + d->ltActive = true; + } + else if (rb.contains(e->x(), e->y())) + { + viewport()->setCursor(TQt::SizeFDiagCursor); + d->rbActive = true; + } + else if (lb.contains(e->x(), e->y())) + { + viewport()->setCursor(TQt::SizeBDiagCursor); + d->lbActive = true; + } + else if (rt.contains(e->x(), e->y())) + { + viewport()->setCursor(TQt::SizeBDiagCursor); + d->rtActive = true; + } + else + viewport()->unsetCursor(); + } +} + +void Canvas::contentsMouseReleaseEvent(TQMouseEvent *e) +{ + if (!e) + return; + + d->midButtonPressed = false; + + if (d->pressedMoving) + { + d->pressedMoving = false; + viewport()->update(); + } + + if (d->pressedMoved && d->rubber) + { + // Normalize rubber rectangle to always have the selection into the image + TQRect rec = d->rubber->normalize(); + + if (rec.left() < d->pixmapRect.left()) rec.setLeft(d->pixmapRect.left()); + if (rec.right() > d->pixmapRect.right()) rec.setRight(d->pixmapRect.right()); + if (rec.top() < d->pixmapRect.top()) rec.setTop(d->pixmapRect.top()); + if (rec.bottom() > d->pixmapRect.bottom()) rec.setBottom(d->pixmapRect.bottom()); + + d->rubber->setLeft(rec.left()); + d->rubber->setRight(rec.right()); + d->rubber->setTop(rec.top()); + d->rubber->setBottom(rec.bottom()); + + d->tileCache.clear(); + viewport()->setMouseTracking(true); + if (d->im->imageValid()) + emit signalSelected(true); + } + else + { + d->ltActive = false; + d->rtActive = false; + d->lbActive = false; + d->rbActive = false; + viewport()->setMouseTracking(false); + viewport()->unsetCursor(); + if (d->im->imageValid()) + emit signalSelected(false); + } + + if (e->button() != TQt::LeftButton) + { + viewport()->unsetCursor(); + } + + if (e->button() == TQt::RightButton) + { + emit signalRightButtonClicked(); + } +} + +void Canvas::contentsWheelEvent(TQWheelEvent *e) +{ + e->accept(); + + if (e->state() & TQt::ShiftButton) + { + if (e->delta() < 0) + emit signalShowNextImage(); + else if (e->delta() > 0) + emit signalShowPrevImage(); + return; + } + else if (e->state() & TQt::ControlButton) + { + if (e->delta() < 0) + slotDecreaseZoom(); + else if (e->delta() > 0) + slotIncreaseZoom(); + return; + } + + TQScrollView::contentsWheelEvent(e); +} + +bool Canvas::maxZoom() +{ + return ((d->zoom * d->zoomMultiplier) >= d->maxZoom); +} + +bool Canvas::minZoom() +{ + return ((d->zoom / d->zoomMultiplier) <= d->minZoom); +} + +bool Canvas::exifRotated() +{ + return d->im->exifRotated(); +} + +double Canvas::snapZoom(double zoom) +{ + // If the zoom value gets changed from d->zoom to zoom + // across 50%, 100% or fit-to-window, then return the + // the corresponding special value. Otherwise zoom is returned unchanged. + double fit = calcAutoZoomFactor(); + TQValueList<double> snapValues; + snapValues.append(0.5); + snapValues.append(1.0); + snapValues.append(fit); + + qHeapSort(snapValues); + TQValueList<double>::const_iterator it; + + if (d->zoom < zoom) + { + for(it = snapValues.constBegin(); it != snapValues.constEnd(); ++it) + { + double z = *it; + if ((d->zoom < z) && (zoom > z)) + { + zoom = z; + break; + } + } + } + else + { + // We need to go through the list in reverse order, + // however, tqCopyBackward does not seem to work here, so + // a simple for loop over integers is used instead. + for(int i=snapValues.size()-1; i>=0; i--) + { + double z = snapValues[i]; + if ((d->zoom > z) && (zoom < z)) + { + zoom = z; + break; + } + } + } + + return zoom; +} + +void Canvas::slotIncreaseZoom() +{ + if (maxZoom()) + return; + + double zoom = d->zoom * d->zoomMultiplier; + zoom = snapZoom(zoom); + setZoomFactor(zoom); +} + +void Canvas::slotDecreaseZoom() +{ + if (minZoom()) + return; + + double zoom = d->zoom / d->zoomMultiplier; + zoom = snapZoom(zoom); + setZoomFactor(zoom); +} + +void Canvas::setZoomFactorSnapped(double zoom) +{ + double fit = calcAutoZoomFactor(); + + if (fabs(zoom-fit) < 0.05) + { + // If 1.0 or 0.5 are even closer to zoom than fit, then choose these. + if (fabs(zoom-fit) > fabs(zoom-1.0) ) + { + zoom = 1.0; + } + else if (fabs(zoom-fit) > fabs(zoom-0.5) ) + { + zoom = 0.5; + } + else + { + zoom = fit; + } + } + else + { + if (fabs(zoom-1.0) < 0.05) + { + zoom = 1.0; + } + if (fabs(zoom-0.5) < 0.05) + { + zoom = 0.5; + } + } + setZoomFactor(zoom); +} + +double Canvas::zoomFactor() +{ + return d->zoom; +} + +void Canvas::setZoomFactor(double zoom) +{ + if (d->autoZoom) + { + d->autoZoom = false; + emit signalToggleOffFitToWindow(); + } + + // Zoom using center of canvas and given zoom factor. + + double cpx = contentsX() + visibleWidth() / 2.0; + double cpy = contentsY() + visibleHeight() / 2.0; + + cpx = (cpx / d->tileSize) * floor(d->tileSize / d->zoom); + cpy = (cpy / d->tileSize) * floor(d->tileSize / d->zoom); + + d->zoom = zoom; + + d->im->zoom(d->zoom); + updateContentsSize(false); + + viewport()->setUpdatesEnabled(false); + center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)), + (int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom))); + viewport()->setUpdatesEnabled(true); + viewport()->update(); + + emit signalZoomChanged(d->zoom); +} + +void Canvas::fitToSelect() +{ + int xSel, ySel, wSel, hSel; + d->im->getSelectedArea(xSel, ySel, wSel, hSel); + + if (wSel && hSel ) + { + // If selected area, use center of selection + // and recompute zoom factor accordinly. + double cpx = xSel + wSel / 2.0; + double cpy = ySel + hSel / 2.0; + + double srcWidth = wSel; + double srcHeight = hSel; + double dstWidth = contentsRect().width(); + double dstHeight = contentsRect().height(); + + d->zoom = TQMIN(dstWidth/srcWidth, dstHeight/srcHeight); + + d->autoZoom = false; + emit signalToggleOffFitToWindow(); + d->im->zoom(d->zoom); + updateContentsSize(true); + + viewport()->setUpdatesEnabled(false); + center((int)((cpx * d->tileSize) / floor(d->tileSize / d->zoom)), + (int)((cpy * d->tileSize) / floor(d->tileSize / d->zoom))); + viewport()->setUpdatesEnabled(true); + viewport()->update(); + + emit signalZoomChanged(d->zoom); + } +} + +bool Canvas::fitToWindow() +{ + return d->autoZoom; +} + +void Canvas::toggleFitToWindow() +{ + d->autoZoom = !d->autoZoom; + + if (d->autoZoom) + updateAutoZoom(); + else + { + d->zoom = 1.0; + emit signalZoomChanged(d->zoom); + } + + d->im->zoom(d->zoom); + updateContentsSize(false); + slotZoomChanged(d->zoom); + viewport()->update(); +} + +void Canvas::slotRotate90() +{ + d->im->rotate90(); +} + +void Canvas::slotRotate180() +{ + d->im->rotate180(); +} + +void Canvas::slotRotate270() +{ + d->im->rotate270(); +} + +void Canvas::slotFlipHoriz() +{ + d->im->flipHoriz(); +} + +void Canvas::slotFlipVert() +{ + d->im->flipVert(); +} + +void Canvas::slotCrop() +{ + int x, y, w, h; + d->im->getSelectedArea(x, y, w, h); + + if (!w && !h ) // No current selection. + return; + + d->im->crop(x, y, w, h); +} + +void Canvas::resizeImage(int w, int h) +{ + d->im->resize(w, h); +} + +void Canvas::setBackgroundColor(const TQColor& color) +{ + if (d->bgColor == color) + return; + + d->bgColor = color; + viewport()->update(); +} + +void Canvas::setICCSettings(ICCSettingsContainer *cmSettings) +{ + d->im->setICCSettings(cmSettings); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::setExposureSettings(ExposureSettingsContainer *expoSettings) +{ + d->im->setExposureSettings(expoSettings); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::setExifOrient(bool exifOrient) +{ + d->im->setExifOrient(exifOrient); + viewport()->update(); +} + +void Canvas::increaseGamma() +{ + d->im->changeGamma(1); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::decreaseGamma() +{ + d->im->changeGamma(-1); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::increaseBrightness() +{ + d->im->changeBrightness(1); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::decreaseBrightness() +{ + d->im->changeBrightness(-1); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::increaseContrast() +{ + d->im->changeContrast(5); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::decreaseContrast() +{ + d->im->changeContrast(-5); + d->tileCache.clear(); + viewport()->update(); +} + +void Canvas::slotRestore() +{ + d->im->restore(); +} + +void Canvas::slotUndo(int steps) +{ + while(steps > 0) + { + d->im->undo(); + --steps; + } +} + +void Canvas::getUndoHistory(TQStringList &titles) +{ + d->im->getUndoHistory(titles); +} + +void Canvas::getRedoHistory(TQStringList &titles) +{ + d->im->getRedoHistory(titles); +} + +void Canvas::slotRedo(int steps) +{ + while(steps > 0) + { + d->im->redo(); + --steps; + } +} + +void Canvas::slotCopy() +{ + int x, y, w, h; + d->im->getSelectedArea(x, y, w, h); + + if (!w && !h ) // No current selection. + return; + + TQApplication::setOverrideCursor (TQt::waitCursor); + uchar* data = d->im->getImageSelection(); + DImg selDImg = DImg(w, h, d->im->sixteenBit(), d->im->hasAlpha(), data); + delete [] data; + + TQImage selImg = selDImg.copyTQImage(); + TQApplication::clipboard()->setData(new TQImageDrag(selImg), TQClipboard::Clipboard); + TQApplication::restoreOverrideCursor (); +} + +void Canvas::slotSelected() +{ + int x=0, y=0, w=0, h=0; + + if (d->rubber && d->pressedMoved) + { + TQRect sel = calcSeletedArea(); + x = sel.x(); + y = sel.y(); + w = sel.width(); + h = sel.height(); + } + + d->im->setSelectedArea(x, y, w, h); +} + +TQRect Canvas::calcSeletedArea() +{ + int x=0, y=0, w=0, h=0; + TQRect r(d->rubber->normalize()); + + if (r.isValid()) + { + r.moveBy(- d->pixmapRect.x(), - d->pixmapRect.y()); + + x = (int)(((double)r.x() / d->tileSize) * floor(d->tileSize / d->zoom)); + y = (int)(((double)r.y() / d->tileSize) * floor(d->tileSize / d->zoom)); + w = (int)(((double)r.width() / d->tileSize) * floor(d->tileSize / d->zoom)); + h = (int)(((double)r.height() / d->tileSize) * floor(d->tileSize / d->zoom)); + + x = TQMIN(imageWidth(), TQMAX(x, 0)); + y = TQMIN(imageHeight(), TQMAX(y, 0)); + w = TQMIN(imageWidth(), TQMAX(w, 0)); + h = TQMIN(imageHeight(), TQMAX(h, 0)); + + // Avoid empty selection by rubberband - at least mark one pixel + // At high zoom factors, the rubberband may operate at subpixel level! + if (w == 0) + w = 1; + if (h == 0) + h = 1; + } + + return TQRect(x, y, w, h); +} + +void Canvas::slotModified() +{ + if (d->autoZoom) + updateAutoZoom(); + d->im->zoom(d->zoom); + + updateContentsSize(true); + viewport()->update(); + + // To be sure than corner widget used to pan image will be hide/show + // accordinly with new image size (if changed). + slotZoomChanged(d->zoom); + + emit signalChanged(); +} + +void Canvas::slotCornerButtonPressed() +{ + if (d->panIconPopup) + { + d->panIconPopup->hide(); + delete d->panIconPopup; + d->panIconPopup = 0; + } + + d->panIconPopup = new TDEPopupFrame(this); + ImagePanIconWidget *pan = new ImagePanIconWidget(180, 120, d->panIconPopup); + d->panIconPopup->setMainWidget(pan); + + TQRect r((int)(contentsX() / d->zoom), (int)(contentsY() / d->zoom), + (int)(visibleWidth() / d->zoom), (int)(visibleHeight() / d->zoom)); + pan->setRegionSelection(r); + pan->setMouseFocus(); + + connect(pan, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), + this, TQ_SLOT(slotPanIconSelectionMoved(const TQRect&, bool))); + + connect(pan, TQ_SIGNAL(signalHiden()), + this, TQ_SLOT(slotPanIconHiden())); + + TQPoint g = mapToGlobal(viewport()->pos()); + g.setX(g.x()+ viewport()->size().width()); + g.setY(g.y()+ viewport()->size().height()); + d->panIconPopup->popup(TQPoint(g.x() - d->panIconPopup->width(), + g.y() - d->panIconPopup->height())); + + pan->setCursorToLocalRegionSelectionCenter(); +} + +void Canvas::slotPanIconHiden() +{ + d->cornerButton->blockSignals(true); + d->cornerButton->animateClick(); + d->cornerButton->blockSignals(false); +} + +void Canvas::slotPanIconSelectionMoved(const TQRect& r, bool b) +{ + setContentsPos((int)(r.x()*d->zoom), (int)(r.y()*d->zoom)); + + if (b) + { + d->panIconPopup->hide(); + delete d->panIconPopup; + d->panIconPopup = 0; + slotPanIconHiden(); + } +} + +void Canvas::slotZoomChanged(double /*zoom*/) +{ + updateScrollBars(); + + if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible()) + d->cornerButton->show(); + else + d->cornerButton->hide(); +} + +void Canvas::slotSelectAll() +{ + if (d->rubber) + { + delete d->rubber; + d->rubber = 0; + } + + d->rubber = new TQRect(d->pixmapRect); + d->pressedMoved = true; + d->tileCache.clear(); + viewport()->setMouseTracking(true); + viewport()->update(); + + if (d->im->imageValid()) + emit signalSelected(true); +} + +void Canvas::slotSelectNone() +{ + reset(); + viewport()->update(); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/canvas/canvas.h b/src/utilities/imageeditor/canvas/canvas.h new file mode 100644 index 00000000..c772098d --- /dev/null +++ b/src/utilities/imageeditor/canvas/canvas.h @@ -0,0 +1,209 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-09 + * Description : image editor canvas management class + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef CANVAS_H +#define CANVAS_H + +// TQt includes. + +#include <tqscrollview.h> +#include <tqrect.h> + +// Local includes. + +#include "digikam_export.h" +#include "dimg.h" + +class TQString; +class TQStringList; +class TQPixmap; +class TQPaintEvent; +class TQResizeEvent; +class TQWheelEvent; +class TQKeyEvent; +class TQColor; + +namespace Digikam +{ + +class CanvasPrivate; +class DImgInterface; +class ExposureSettingsContainer; +class ICCSettingsContainer; +class IOFileSettingsContainer; + +class DIGIKAM_EXPORT Canvas : public TQScrollView +{ + TQ_OBJECT + + +public: + + Canvas(TQWidget *parent=0); + ~Canvas(); + + void load(const TQString& filename, IOFileSettingsContainer *IOFileSettings); + void preload(const TQString& filename); + + void saveAs(const TQString& filename, IOFileSettingsContainer *IOFileSettings, + bool setExifOrientationTag, const TQString& mimeType=TQString()); + void resetImage(); + void switchToLastSaved(const TQString& newFilename); + void abortSaving(); + void setModified(); + void readMetadataFromFile(const TQString &file); + void clearUndoHistory(); + void setUndoHistoryOrigin(); + void updateUndoState(); + DImg currentImage(); + TQString currentImageFileFormat(); + TQString currentImageFilePath(); + + DImgInterface *interface() const; + void makeDefaultEditingCanvas(); + + double snapZoom(double z); + void setZoomFactorSnapped(double zoom); + + double zoomFactor(); + void setZoomFactor(double z); + bool fitToWindow(); + bool maxZoom(); + bool minZoom(); + bool exifRotated(); + int imageWidth(); + int imageHeight(); + TQRect getSelectedArea(); + + // If current image file format is only available in read only, + // typicially all RAW image file formats. + bool isReadOnly(); + + void resizeImage(int w, int h); + + void setBackgroundColor(const TQColor& color); + void setICCSettings(ICCSettingsContainer *cmSettings); + void setExposureSettings(ExposureSettingsContainer *expoSettings); + + void setExifOrient(bool exifOrient); + + void increaseGamma(); + void decreaseGamma(); + void increaseBrightness(); + void decreaseBrightness(); + void increaseContrast(); + void decreaseContrast(); + + void getUndoHistory(TQStringList &titles); + void getRedoHistory(TQStringList &titles); + + void toggleFitToWindow(); + void fitToSelect(); + +signals: + + void signalZoomChanged(double zoom); + void signalMaxZoom(); + void signalMinZoom(); + void signalChanged(); + void signalUndoStateChanged(bool, bool, bool); + void signalSelected(bool); + void signalRightButtonClicked(); + void signalShowNextImage(); + void signalShowPrevImage(); + void signalPrepareToLoad(); + void signalLoadingStarted(const TQString &filename); + void signalLoadingFinished(const TQString &filename, bool success); + void signalLoadingProgress(const TQString& filePath, float progress); + void signalSavingStarted(const TQString &filename); + void signalSavingFinished(const TQString &filename, bool success); + void signalSavingProgress(const TQString& filePath, float progress); + void signalSelectionChanged(const TQRect&); + void signalToggleOffFitToWindow(); + +public slots: + + void slotIncreaseZoom(); + void slotDecreaseZoom(); + + // image modifiers + void slotRotate90(); + void slotRotate180(); + void slotRotate270(); + + void slotFlipHoriz(); + void slotFlipVert(); + + void slotCrop(); + + void slotRestore(); + void slotUndo(int steps=1); + void slotRedo(int steps=1); + + void slotCopy(); + + void slotSelectAll(); + void slotSelectNone(); + +protected: + + void resizeEvent(TQResizeEvent* e); + void viewportPaintEvent(TQPaintEvent *e); + void contentsMousePressEvent(TQMouseEvent *e); + void contentsMouseMoveEvent(TQMouseEvent *e); + void contentsMouseReleaseEvent(TQMouseEvent *e); + void contentsWheelEvent(TQWheelEvent *e); + +private: + + TQRect calcSeletedArea(); + double calcAutoZoomFactor(); + void updateAutoZoom(); + void updateContentsSize(bool deleteRubber); + + void drawRubber(); + void paintViewport(const TQRect& er, bool antialias); + + void reset(); + +private slots: + + void slotSelected(); + void slotModified(); + void slotImageLoaded(const TQString& filePath, bool success); + void slotImageSaved(const TQString& filePath, bool success); + void slotCornerButtonPressed(); + void slotZoomChanged(double); + void slotPanIconSelectionMoved(const TQRect&, bool); + void slotPanIconHiden(); + +private: + + CanvasPrivate *d; +}; + +} // namespace Digikam + +#endif /* CANVAS_H */ + diff --git a/src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp b/src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp new file mode 100644 index 00000000..1403773f --- /dev/null +++ b/src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp @@ -0,0 +1,186 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-05-15 + * Description : a dialog to see preview ICC color correction + * before to apply color profile. + * + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqstring.h> +#include <tqfileinfo.h> +#include <tqpushbutton.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <kseparator.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "icctransform.h" +#include "iccprofileinfodlg.h" +#include "colorcorrectiondlg.h" +#include "colorcorrectiondlg.moc" + +namespace Digikam +{ + +ColorCorrectionDlg::ColorCorrectionDlg(TQWidget* parent, DImg *preview, + IccTransform *iccTrans, const TQString& file) + : KDialogBase(parent, "", true, TQString(), + Help|Ok|Apply|Cancel, Ok, true) +{ + m_iccTrans = iccTrans; + m_parent = parent; + setHelp("iccprofile.anchor", "digikam"); + setButtonText(Ok, i18n("Convert")); + setButtonTip(Ok, i18n("Apply the default color workspace profile to the image")); + setButtonText(Cancel, i18n("Do Nothing")); + setButtonTip(Cancel, i18n("Do not change the image")); + setButtonText(Apply, i18n("Assign")); + setButtonTip(Apply, i18n("Only embed the color workspace profile in the image, don't change the image")); + + TQFileInfo fi(file); + setCaption(fi.fileName()); + + TQWidget *page = new TQWidget(this); + TQGridLayout* grid = new TQGridLayout(page, 3, 2, 0, KDialog::spacingHint()); + + TQLabel *originalTitle = new TQLabel(i18n("Original Image:"), page); + TQLabel *previewOriginal = new TQLabel(page); + TQLabel *targetTitle = new TQLabel(i18n("Corrected Image:"), page); + TQLabel *previewTarget = new TQLabel(page); + TQLabel *logo = new TQLabel(page); + TQLabel *message = new TQLabel(page); + TQLabel *currentProfileTitle = new TQLabel(i18n("Current workspace color profile:"), page); + TQLabel *currentProfileDesc = new TQLabel(TQString("<b>%1</b>").arg(m_iccTrans->getOutpoutProfileDescriptor()), page); + TQPushButton *currentProfInfo = new TQPushButton(i18n("Info..."), page); + TQLabel *embeddedProfileTitle = new TQLabel(i18n("Embedded color profile:"), page); + TQLabel *embeddedProfileDesc = new TQLabel(TQString("<b>%1</b>").arg(m_iccTrans->getEmbeddedProfileDescriptor()), page); + TQPushButton *embeddedProfInfo = new TQPushButton(i18n("Info..."), page); + KSeparator *line = new KSeparator(TQt::Horizontal, page); + + if (m_iccTrans->embeddedProfile().isEmpty()) + { + message->setText(i18n("<p>This image has not been assigned a color profile.</p>" + "<p>Do you want to convert it to your workspace color profile?</p>")); + + line->hide(); + embeddedProfileTitle->hide(); + embeddedProfileDesc->hide(); + embeddedProfInfo->hide(); + } + else + { + message->setText(i18n("<p>This image has been assigned to a color profile that does not " + "match your default workspace color profile.</p>" + "<p>Do you want to convert it to your workspace color profile?</p>")); + } + + previewOriginal->setPixmap(preview->convertToPixmap()); + previewTarget->setPixmap(preview->convertToPixmap(m_iccTrans)); + TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader(); + logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 128, TDEIcon::DefaultState, 0, true)); + + grid->addMultiCellWidget(originalTitle, 0, 0, 0, 0); + grid->addMultiCellWidget(previewOriginal, 1, 1, 0, 0); + grid->addMultiCellWidget(targetTitle, 2, 2, 0, 0); + grid->addMultiCellWidget(previewTarget, 3, 3, 0, 0); + + TQVBoxLayout *vlay = new TQVBoxLayout( KDialog::spacingHint() ); + vlay->addWidget(logo); + vlay->addWidget(message); + + vlay->addWidget(new KSeparator(TQt::Horizontal, page)); + vlay->addWidget(currentProfileTitle); + vlay->addWidget(currentProfileDesc); + + TQHBoxLayout *hlay1 = new TQHBoxLayout( KDialog::spacingHint() ); + hlay1->addWidget(currentProfInfo); + hlay1->addStretch(); + vlay->addLayout(hlay1); + + vlay->addWidget(line); + vlay->addWidget(embeddedProfileTitle); + vlay->addWidget(embeddedProfileDesc); + + TQHBoxLayout *hlay2 = new TQHBoxLayout( KDialog::spacingHint() ); + hlay2->addWidget(embeddedProfInfo); + hlay2->addStretch(); + vlay->addLayout(hlay2); + vlay->addStretch(); + + grid->addMultiCell(new TQSpacerItem(KDialog::spacingHint(), KDialog::spacingHint(), + TQSizePolicy::Minimum, TQSizePolicy::Expanding), 0, 3, 1, 1); + grid->addMultiCellLayout(vlay, 0, 3, 2, 2); + + setMainWidget(page); + + // -------------------------------------------------------------------- + + connect(currentProfInfo, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotCurrentProfInfo()) ); + + connect(embeddedProfInfo, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotEmbeddedProfInfo()) ); + + connect(this, TQ_SIGNAL(applyClicked()), + this, TQ_SLOT(slotApplyClicked())); +} + +ColorCorrectionDlg::~ColorCorrectionDlg() +{ +} + +void ColorCorrectionDlg::slotCurrentProfInfo() +{ + if (m_iccTrans->outputProfile().isEmpty()) + return; + + ICCProfileInfoDlg infoDlg(m_parent, TQString(), m_iccTrans->outputProfile()); + infoDlg.exec(); +} + +void ColorCorrectionDlg::slotEmbeddedProfInfo() +{ + if (m_iccTrans->embeddedProfile().isEmpty()) + return; + + ICCProfileInfoDlg infoDlg(m_parent, TQString(), m_iccTrans->embeddedProfile()); + infoDlg.exec(); +} + +void ColorCorrectionDlg::slotApplyClicked() +{ + DDebug() << "colorcorrectiondlg: Apply pressed" << endl; + done(-1); +} + +} // NameSpace Digikam + diff --git a/src/utilities/imageeditor/canvas/colorcorrectiondlg.h b/src/utilities/imageeditor/canvas/colorcorrectiondlg.h new file mode 100644 index 00000000..7cc4c19d --- /dev/null +++ b/src/utilities/imageeditor/canvas/colorcorrectiondlg.h @@ -0,0 +1,72 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-05-15 + * Description : a dialog to see preview ICC color correction + * before to apply color profile. + * + * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef COLORCORRECTIONDLG_H +#define COLORCORRECTIONDLG_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kdialogbase.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class IccTransform; +class DImg; + +class DIGIKAM_EXPORT ColorCorrectionDlg : public KDialogBase +{ + TQ_OBJECT + + +public: + + ColorCorrectionDlg(TQWidget *parent, DImg *preview, + IccTransform *iccTrans, const TQString& file); + ~ColorCorrectionDlg(); + +private slots: + + void slotCurrentProfInfo(); + void slotEmbeddedProfInfo(); + void slotApplyClicked(); + +private: + + TQWidget *m_parent; + + IccTransform *m_iccTrans; +}; + +} // Namespace Digikam + +#endif /* COLORCORRECTIONDLG_H */ diff --git a/src/utilities/imageeditor/canvas/dimginterface.cpp b/src/utilities/imageeditor/canvas/dimginterface.cpp new file mode 100644 index 00000000..8ce1c114 --- /dev/null +++ b/src/utilities/imageeditor/canvas/dimginterface.cpp @@ -0,0 +1,1270 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-15 + * Description : DImg interface for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#define OPACITY 0.7 +#define RCOL 0xAA +#define GCOL 0xAA +#define BCOL 0xAA + +// C++ includes. + +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <iostream> + +// TQt includes. + +#include <tqwidget.h> +#include <tqimage.h> +#include <tqpixmap.h> +#include <tqbitmap.h> +#include <tqcolor.h> +#include <tqfile.h> +#include <tqvariant.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdemessagebox.h> + +// Local includes. + +#include "ddebug.h" +#include "bcgmodifier.h" +#include "colorcorrectiondlg.h" +#include "undomanager.h" +#include "undoaction.h" +#include "iccsettingscontainer.h" +#include "icctransform.h" +#include "exposurecontainer.h" +#include "iofilesettingscontainer.h" +#include "rawimport.h" +#include "editortooliface.h" +#include "sharedloadsavethread.h" +#include "dmetadata.h" +#include "dimginterface.h" +#include "dimginterface.moc" + +namespace Digikam +{ + +class UndoManager; + +class DImgInterfacePrivate +{ + +public: + + DImgInterfacePrivate() + { + parent = 0; + undoMan = 0; + cmSettings = 0; + expoSettings = 0; + iofileSettings = 0; + thread = 0; + width = 0; + height = 0; + origWidth = 0; + origHeight = 0; + selX = 0; + selY = 0; + selW = 0; + selH = 0; + zoom = 1.0; + exifOrient = false; + valid = false; + rotatedOrFlipped = false; + } + + bool valid; + bool rotatedOrFlipped; + bool exifOrient; + bool changedBCG; + + int width; + int height; + int origWidth; + int origHeight; + int selX; + int selY; + int selW; + int selH; + + float gamma; + float brightness; + float contrast; + + double zoom; + + // Used by ICC color profile dialog. + TQWidget *parent; + + TQString filename; + TQString savingFilename; + + DImg image; + + UndoManager *undoMan; + + BCGModifier cmod; + + ICCSettingsContainer *cmSettings; + + ExposureSettingsContainer *expoSettings; + + IOFileSettingsContainer *iofileSettings; + + SharedLoadSaveThread *thread; + + IccTransform monitorICCtrans; +}; + +DImgInterface* DImgInterface::m_defaultInterface = 0; + +DImgInterface* DImgInterface::defaultInterface() +{ + return m_defaultInterface; +} + +void DImgInterface::setDefaultInterface(DImgInterface *defaultInterface) +{ + m_defaultInterface = defaultInterface; +} + +DImgInterface::DImgInterface() + : TQObject() +{ + d = new DImgInterfacePrivate; + + d->undoMan = new UndoManager(this); + d->thread = new SharedLoadSaveThread; + + connect( d->thread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg&)), + this, TQ_SLOT(slotImageLoaded(const LoadingDescription &, const DImg&)) ); + + connect( d->thread, TQ_SIGNAL(signalImageSaved(const TQString&, bool)), + this, TQ_SLOT(slotImageSaved(const TQString&, bool)) ); + + connect( d->thread, TQ_SIGNAL(signalLoadingProgress(const LoadingDescription &, float)), + this, TQ_SLOT(slotLoadingProgress(const LoadingDescription &, float)) ); + + connect( d->thread, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), + this, TQ_SLOT(slotSavingProgress(const TQString&, float)) ); +} + +DImgInterface::~DImgInterface() +{ + delete d->undoMan; + delete d->thread; + delete d; + if (m_defaultInterface == this) + m_defaultInterface = 0; +} + +void DImgInterface::load(const TQString& filename, IOFileSettingsContainer *iofileSettings, + TQWidget *parent) +{ + // store here in case filename == d->fileName, and is then reset by resetValues + TQString newFileName = filename; + + resetValues(); + + d->filename = newFileName; + d->iofileSettings = iofileSettings; + d->parent = parent; + + if (d->iofileSettings->useRAWImport && DImg::fileFormat(d->filename) == DImg::RAW) + { + RawImport *rawImport = new RawImport(KURL(d->filename), this); + EditorToolIface::editorToolIface()->loadTool(rawImport); + + connect(rawImport, TQ_SIGNAL(okClicked()), + this, TQ_SLOT(slotUseRawImportSettings())); + + connect(rawImport, TQ_SIGNAL(cancelClicked()), + this, TQ_SLOT(slotUseDefaultSettings())); + } + else + { + slotUseDefaultSettings(); + } +} + +void DImgInterface::slotUseRawImportSettings() +{ + RawImport *rawImport = dynamic_cast<RawImport*>(EditorToolIface::editorToolIface()->currentTool()); + + d->thread->load(LoadingDescription(d->filename, + rawImport->rawDecodingSettings()), + SharedLoadSaveThread::AccessModeReadWrite, + SharedLoadSaveThread::LoadingPolicyFirstRemovePrevious); + emit signalLoadingStarted(d->filename); + + EditorToolIface::editorToolIface()->unLoadTool(); +} + +void DImgInterface::slotUseDefaultSettings() +{ + d->thread->load(LoadingDescription(d->filename, + d->iofileSettings->rawDecodingSettings), + SharedLoadSaveThread::AccessModeReadWrite, + SharedLoadSaveThread::LoadingPolicyFirstRemovePrevious); + emit signalLoadingStarted(d->filename); + + EditorToolIface::editorToolIface()->unLoadTool(); +} + +void DImgInterface::resetImage() +{ + EditorToolIface::editorToolIface()->unLoadTool(); + resetValues(); + d->image.reset(); +} + +void DImgInterface::resetValues() +{ + d->valid = false; + d->filename = TQString(); + d->width = 0; + d->height = 0; + d->origWidth = 0; + d->origHeight = 0; + d->selX = 0; + d->selY = 0; + d->selW = 0; + d->selH = 0; + d->gamma = 1.0; + d->contrast = 1.0; + d->brightness = 0.0; + d->changedBCG = false; + d->iofileSettings = 0; + d->parent = 0; + + d->cmod.reset(); + d->undoMan->clear(); +} + +void DImgInterface::setICCSettings(ICCSettingsContainer *cmSettings) +{ + d->cmSettings = cmSettings; + d->monitorICCtrans.setProfiles(d->cmSettings->workspaceSetting, d->cmSettings->monitorSetting); +} + +void DImgInterface::setExposureSettings(ExposureSettingsContainer *expoSettings) +{ + d->expoSettings = expoSettings; +} + +void DImgInterface::slotImageLoaded(const LoadingDescription &loadingDescription, const DImg& img) +{ + const TQString &fileName = loadingDescription.filePath; + + if (fileName != d->filename) + return; + + bool valRet = false; + d->image = img; + + if (!d->image.isNull()) + { + d->origWidth = d->image.width(); + d->origHeight = d->image.height(); + d->valid = true; + d->width = d->origWidth; + d->height = d->origHeight; + valRet = true; + + // Raw files are already rotated properlly by dcraw. Only perform auto-rotation with JPEG/PNG/TIFF file. + // We don't have a feedback from dcraw about auto-rotated RAW file during decoding. Well set transformed + // flag as well. + + if (d->image.attribute("format").toString() == TQString("RAW")) + d->rotatedOrFlipped = true; + + if (d->exifOrient && + (d->image.attribute("format").toString() == TQString("JPEG") || + d->image.attribute("format").toString() == TQString("PNG") || + d->image.attribute("format").toString() == TQString("TIFF"))) + exifRotate(d->filename); + + if (d->cmSettings->enableCMSetting) + { + if (TQFile::exists(d->cmSettings->workspaceSetting)) + { + IccTransform trans; + TQByteArray fakeProfile; + + // First possibility: image has no embedded profile + if(d->image.getICCProfil().isNull()) + { + // Ask or apply? + if (d->cmSettings->askOrApplySetting) + { + if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + trans.setProfiles(TQFile::encodeName(d->cmSettings->inputSetting), + TQFile::encodeName(d->cmSettings->workspaceSetting)); + + // NOTE: If Input color profile do not exist, using built-in sRGB intead. + trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, + d->cmSettings->BPCSetting, false, + TQFile::exists(d->cmSettings->inputSetting)); + + d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); + if (d->parent) d->parent->unsetCursor(); + } + else + { + // To repaint image in canvas before to ask about to apply ICC profile. + emit signalImageLoaded(d->filename, valRet); + + DImg preview = d->image.smoothScale(240, 180, TQSize::ScaleMin); + trans.setProfiles(TQFile::encodeName(d->cmSettings->inputSetting), + TQFile::encodeName(d->cmSettings->workspaceSetting)); + ColorCorrectionDlg dlg(d->parent, &preview, &trans, fileName); + + switch (dlg.exec()) + { + case TQDialog::Accepted: + if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + + // NOTE: If Input color profile do not exist, using built-in sRGB intead. + trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, + d->cmSettings->BPCSetting, false, + TQFile::exists(d->cmSettings->inputSetting)); + + d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); + if (d->parent) d->parent->unsetCursor(); + break; + case -1: + if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); + if (d->parent) d->parent->unsetCursor(); + DDebug() << "dimginterface.cpp: Apply pressed" << endl; + break; + } + } + } + // Second possibility: image has an embedded profile + else + { + trans.getEmbeddedProfile( d->image ); + + // Ask or apply? + if (d->cmSettings->askOrApplySetting) + { + if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + trans.setProfiles(TQFile::encodeName(d->cmSettings->workspaceSetting)); + trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, + d->cmSettings->BPCSetting, false, false); + if (d->parent) d->parent->unsetCursor(); + } + else + { + if (trans.getEmbeddedProfileDescriptor() + != trans.getProfileDescription( d->cmSettings->workspaceSetting )) + { + // Embedded profile and default workspace profile are different: ask to user! + + DDebug() << "Embedded profile: " << trans.getEmbeddedProfileDescriptor() << endl; + + // To repaint image in canvas before to ask about to apply ICC profile. + emit signalImageLoaded(d->filename, valRet); + + DImg preview = d->image.smoothScale(240, 180, TQSize::ScaleMin); + trans.setProfiles(TQFile::encodeName(d->cmSettings->workspaceSetting)); + ColorCorrectionDlg dlg(d->parent, &preview, &trans, fileName); + + switch (dlg.exec()) + { + case TQDialog::Accepted: + if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + trans.apply(d->image, fakeProfile, d->cmSettings->renderingSetting, + d->cmSettings->BPCSetting, false, false); + d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); + if (d->parent) d->parent->unsetCursor(); + break; + case -1: + if (d->parent) d->parent->setCursor( KCursor::waitCursor() ); + d->image.getICCProfilFromFile(TQFile::encodeName(d->cmSettings->workspaceSetting)); + if (d->parent) d->parent->unsetCursor(); + DDebug() << "dimginterface.cpp: Apply pressed" << endl; + break; + } + } + } + } + } + else + { + TQString message = i18n("Cannot find the ICC color-space profile file. " + "The ICC profiles path seems to be invalid. " + "No color transform will be applied. " + "Please check the \"Color Management\" " + "configuration in digiKam's setup to verify the ICC path."); + KMessageBox::information(d->parent, message); + } + } + } + else + { + valRet = false; + } + + emit signalImageLoaded(d->filename, valRet); + setModified(); +} + +void DImgInterface::slotLoadingProgress(const LoadingDescription &loadingDescription, float progress) +{ + if (loadingDescription.filePath == d->filename) + emit signalLoadingProgress(loadingDescription.filePath, progress); +} + +bool DImgInterface::exifRotated() +{ + return d->rotatedOrFlipped; +} + +void DImgInterface::exifRotate(const TQString& filename) +{ + // Rotate image based on EXIF rotate tag + + DMetadata metadata(filename); + DMetadata::ImageOrientation orientation = metadata.getImageOrientation(); + + if(orientation != DMetadata::ORIENTATION_NORMAL) + { + switch (orientation) + { + case DMetadata::ORIENTATION_NORMAL: + case DMetadata::ORIENTATION_UNSPECIFIED: + break; + + case DMetadata::ORIENTATION_HFLIP: + flipHoriz(false); + break; + + case DMetadata::ORIENTATION_ROT_180: + rotate180(false); + break; + + case DMetadata::ORIENTATION_VFLIP: + flipVert(false); + break; + + case DMetadata::ORIENTATION_ROT_90_HFLIP: + rotate90(false); + flipHoriz(false); + break; + + case DMetadata::ORIENTATION_ROT_90: + rotate90(false); + break; + + case DMetadata::ORIENTATION_ROT_90_VFLIP: + rotate90(false); + flipVert(false); + break; + + case DMetadata::ORIENTATION_ROT_270: + rotate270(false); + break; + } + + d->rotatedOrFlipped = true; + } +} + +void DImgInterface::setExifOrient(bool exifOrient) +{ + d->exifOrient = exifOrient; +} + +void DImgInterface::undo() +{ + if (!d->undoMan->anyMoreUndo()) + { + emit signalUndoStateChanged(false, d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); + return; + } + + d->undoMan->undo(); + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::redo() +{ + if (!d->undoMan->anyMoreRedo()) + { + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), false, !d->undoMan->isAtOrigin()); + return; + } + + d->undoMan->redo(); + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::restore() +{ + d->undoMan->clear(); + load(d->filename, d->iofileSettings); +} + +/* +This code is unused and untested +void DImgInterface::save(const TQString& file, IOFileSettingsContainer *iofileSettings) +{ + d->cmod.reset(); + d->cmod.setGamma(d->gamma); + d->cmod.setBrightness(d->brightness); + d->cmod.setContrast(d->contrast); + d->cmod.applyBCG(d->image); + + d->cmod.reset(); + d->gamma = 1.0; + d->contrast = 1.0; + d->brightness = 0.0; + + TQString currentMimeType(TQImageIO::imageFormat(d->filename)); + + d->needClearUndoManager = true; + + saveAction(file, iofileSettings, currentMimeType); +} +*/ + +void DImgInterface::saveAs(const TQString& fileName, IOFileSettingsContainer *iofileSettings, + bool setExifOrientationTag, const TQString& givenMimeType) +{ + // No need to toggle off undo, redo or save action during saving using + // signalUndoStateChanged(), this is will done by GUI implementation directly. + + if (d->changedBCG) + { + d->cmod.reset(); + d->cmod.setGamma(d->gamma); + d->cmod.setBrightness(d->brightness); + d->cmod.setContrast(d->contrast); + d->cmod.applyBCG(d->image); + } + + // Try hard to find a mimetype. + TQString mimeType = givenMimeType; + + // This is possibly empty + if (mimeType.isEmpty()) + mimeType = getImageFormat(); + + DDebug() << "Saving to :" << TQFile::encodeName(fileName).data() << " (" + << mimeType << ")" << endl; + + // JPEG file format. + if ( mimeType.upper() == TQString("JPG") || mimeType.upper() == TQString("JPEG") || + mimeType.upper() == TQString("JPE")) + { + d->image.setAttribute("quality", iofileSettings->JPEGCompression); + d->image.setAttribute("subsampling", iofileSettings->JPEGSubSampling); + } + + // PNG file format. + if ( mimeType.upper() == TQString("PNG") ) + d->image.setAttribute("quality", iofileSettings->PNGCompression); + + // TIFF file format. + if ( mimeType.upper() == TQString("TIFF") || mimeType.upper() == TQString("TIF") ) + d->image.setAttribute("compress", iofileSettings->TIFFCompression); + + // JPEG 2000 file format. + if ( mimeType.upper() == TQString("JP2") || mimeType.upper() == TQString("JPX") || + mimeType.upper() == TQString("JPC") || mimeType.upper() == TQString("PGX")) + { + if (iofileSettings->JPEG2000LossLess) + d->image.setAttribute("quality", 100); // LossLess compression + else + d->image.setAttribute("quality", iofileSettings->JPEG2000Compression); + } + + d->savingFilename = fileName; + + // Get image Exif/Iptc data. + DMetadata meta; + meta.setExif(d->image.getExif()); + meta.setIptc(d->image.getIptc()); + + // Update Iptc preview. + // NOTE: see B.K.O #130525. a JPEG segment is limited to 64K. If the IPTC byte array is + // bigger than 64K duing of image preview tag size, the target JPEG image will be + // broken. Note that IPTC image preview tag is limited to 256K!!! + // There is no limitation with TIFF and PNG about IPTC byte array size. + + TQImage preview = d->image.smoothScale(1280, 1024, TQSize::ScaleMin).copyTQImage(); + + if ( mimeType.upper() != TQString("JPG") && mimeType.upper() != TQString("JPEG") && + mimeType.upper() != TQString("JPE")) + { + // Non JPEG file, we update IPTC preview + meta.setImagePreview(preview); + } + else + { + // JPEG file, we remove IPTC preview. + meta.removeIptcTag("Iptc.Application2.Preview"); + meta.removeIptcTag("Iptc.Application2.PreviewFormat"); + meta.removeIptcTag("Iptc.Application2.PreviewVersion"); + } + + // Update Exif thumbnail. + TQImage thumb = preview.smoothScale(160, 120, TQImage::ScaleMin); + meta.setExifThumbnail(thumb); + + // Update Exif Image dimensions. + meta.setImageDimensions(d->image.size()); + + // Update Exif Document Name tag with the original file name. + meta.setExifTagString("Exif.Image.DocumentName", getImageFileName()); + + // Update Exif Orientation tag if necessary. + if( setExifOrientationTag ) + meta.setImageOrientation(DMetadata::ORIENTATION_NORMAL); + + // Store new Exif/Iptc data into image. + d->image.setExif(meta.getExif()); + d->image.setIptc(meta.getIptc()); + + d->thread->save(d->image, fileName, mimeType); +} + +void DImgInterface::slotImageSaved(const TQString& filePath, bool success) +{ + if (filePath != d->savingFilename) + return; + + if (!success) + DWarning() << "error saving image '" << TQFile::encodeName(filePath).data() << endl; + + emit signalImageSaved(filePath, success); + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::slotSavingProgress(const TQString& filePath, float progress) +{ + if (filePath == d->savingFilename) + emit signalSavingProgress(filePath, progress); +} + +void DImgInterface::abortSaving() +{ + // failure will be reported by a signal + d->thread->stopSaving(d->savingFilename); +} + +void DImgInterface::switchToLastSaved(const TQString& newFilename) +{ + // Higher level wants to use the current DImg object to represent the file + // it has previously been saved to. + d->filename = newFilename; + + // Currently the only place where a DImg is connected to the file it originates from + // is the format attribute. + TQString savedformat = d->image.attribute("savedformat").toString(); + if (!savedformat.isEmpty()) + d->image.setAttribute("format", savedformat); +} + +void DImgInterface::setModified() +{ + emit signalModified(); + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::readMetadataFromFile(const TQString &file) +{ + DMetadata meta(file); + + //TODO: code is essentially the same as DImgLoader::readMetadata, + // put both in a common place. + if (!meta.getComments().isNull()) + d->image.setComments(meta.getComments()); + if (!meta.getExif().isNull()) + d->image.setExif(meta.getExif()); + if (!meta.getIptc().isNull()) + d->image.setIptc(meta.getIptc()); +} + +void DImgInterface::clearUndoManager() +{ + d->undoMan->clear(); + d->undoMan->setOrigin(); + emit signalUndoStateChanged(false, false, false); +} + +void DImgInterface::setUndoManagerOrigin() +{ + d->undoMan->setOrigin(); + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +void DImgInterface::updateUndoState() +{ + emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin()); +} + +bool DImgInterface::imageValid() +{ + return !d->image.isNull(); +} + +int DImgInterface::width() +{ + return d->width; +} + +int DImgInterface::height() +{ + return d->height; +} + +int DImgInterface::origWidth() +{ + return d->origWidth; +} + +int DImgInterface::origHeight() +{ + return d->origHeight; +} + +int DImgInterface::bytesDepth() +{ + return d->image.bytesDepth(); +} + +bool DImgInterface::sixteenBit() +{ + return d->image.sixteenBit(); +} + +bool DImgInterface::hasAlpha() +{ + return d->image.hasAlpha(); +} + +bool DImgInterface::isReadOnly() +{ + if (d->image.isNull()) + return true; + else + return d->image.isReadOnly(); +} + +void DImgInterface::setSelectedArea(int x, int y, int w, int h) +{ + d->selX = x; + d->selY = y; + d->selW = w; + d->selH = h; +} + +void DImgInterface::getSelectedArea(int& x, int& y, int& w, int& h) +{ + x = d->selX; + y = d->selY; + w = d->selW; + h = d->selH; +} + +void DImgInterface::paintOnDevice(TQPaintDevice* p, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + int /*antialias*/) +{ + if (d->image.isNull()) + return; + + DImg img = d->image.smoothScaleSection(sx, sy, sw, sh, dw, dh); + d->cmod.applyBCG(img); + img.convertDepth(32); + + if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting) + { + TQPixmap pix(img.convertToPixmap(&d->monitorICCtrans)); + bitBlt(p, dx, dy, &pix, 0, 0); + } + else + { + TQPixmap pix(img.convertToPixmap()); + bitBlt(p, dx, dy, &pix, 0, 0); + } + + // Show the Over/Under exposure pixels indicators + + if (d->expoSettings->underExposureIndicator || d->expoSettings->overExposureIndicator) + { + TQImage pureColorMask = d->image.copy(sx, sy, sw, sh).pureColorMask(d->expoSettings); + TQPixmap pixMask(pureColorMask.scale(dw, dh)); + bitBlt(p, dx, dy, &pixMask, 0, 0); + } +} + +void DImgInterface::paintOnDevice(TQPaintDevice* p, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + int mx, int my, int mw, int mh, + int /*antialias*/) +{ + if (d->image.isNull()) + return; + + DImg img = d->image.smoothScaleSection(sx, sy, sw, sh, dw, dh); + d->cmod.applyBCG(img); + img.convertDepth(32); + + uint* data = (uint*)img.bits(); + uchar r, g, b, a; + + for (int j=0; j < (int)img.height(); j++) + { + for (int i=0; i < (int)img.width(); i++) + { + if (i < (mx-dx) || i > (mx-dx+mw-1) || + j < (my-dy) || j > (my-dy+mh-1)) + { + a = (*data >> 24) & 0xff; + r = (*data >> 16) & 0xff; + g = (*data >> 8) & 0xff; + b = (*data ) & 0xff; + + r += (uchar)((RCOL - r) * OPACITY); + g += (uchar)((GCOL - g) * OPACITY); + b += (uchar)((BCOL - b) * OPACITY); + + *data = (a << 24) | (r << 16) | (g << 8) | b; + } + + data++; + } + } + + if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting) + { + TQPixmap pix(img.convertToPixmap(&d->monitorICCtrans)); + bitBlt(p, dx, dy, &pix, 0, 0); + } + else + { + TQPixmap pix(img.convertToPixmap()); + bitBlt(p, dx, dy, &pix, 0, 0); + } + + // Show the Over/Under exposure pixels indicators + + if (d->expoSettings->underExposureIndicator || d->expoSettings->overExposureIndicator) + { + TQImage pureColorMask = d->image.copy(sx, sy, sw, sh).pureColorMask(d->expoSettings); + TQPixmap pixMask(pureColorMask.scale(dw, dh)); + bitBlt(p, dx, dy, &pixMask, 0, 0); + } +} + +void DImgInterface::zoom(double val) +{ + d->zoom = val; + d->width = (int)(d->origWidth * val); + d->height = (int)(d->origHeight * val); +} + +void DImgInterface::rotate90(bool saveUndo) +{ + if (saveUndo) + { + d->undoMan->addAction(new UndoActionRotate(this, UndoActionRotate::R90)); + } + + d->image.rotate(DImg::ROT90); + d->origWidth = d->image.width(); + d->origHeight = d->image.height(); + + setModified(); +} + +void DImgInterface::rotate180(bool saveUndo) +{ + if (saveUndo) + { + d->undoMan->addAction(new UndoActionRotate(this, UndoActionRotate::R180)); + } + + d->image.rotate(DImg::ROT180); + d->origWidth = d->image.width(); + d->origHeight = d->image.height(); + + setModified(); +} + +void DImgInterface::rotate270(bool saveUndo) +{ + if (saveUndo) + { + d->undoMan->addAction(new UndoActionRotate(this, UndoActionRotate::R270)); + } + + d->image.rotate(DImg::ROT270); + d->origWidth = d->image.width(); + d->origHeight = d->image.height(); + + setModified(); +} + +void DImgInterface::flipHoriz(bool saveUndo) +{ + if (saveUndo) + { + d->undoMan->addAction(new UndoActionFlip(this, UndoActionFlip::Horizontal)); + } + + d->image.flip(DImg::HORIZONTAL); + + setModified(); +} + +void DImgInterface::flipVert(bool saveUndo) +{ + if (saveUndo) + { + d->undoMan->addAction(new UndoActionFlip(this, UndoActionFlip::Vertical)); + } + + d->image.flip(DImg::VERTICAL); + + setModified(); +} + +void DImgInterface::crop(int x, int y, int w, int h) +{ + d->undoMan->addAction(new UndoActionIrreversible(this, "Crop")); + + d->image.crop(x, y, w, h); + + d->origWidth = d->image.width(); + d->origHeight = d->image.height(); + + setModified(); +} + +void DImgInterface::resize(int w, int h) +{ + d->undoMan->addAction(new UndoActionIrreversible(this, "Resize")); + + d->image.resize(w, h); + + d->origWidth = d->image.width(); + d->origHeight = d->image.height(); + + setModified(); +} + +void DImgInterface::changeGamma(double gamma) +{ + d->undoMan->addAction(new UndoActionBCG(this, d->gamma, d->brightness, + d->contrast, gamma, d->brightness, + d->contrast)); + + d->gamma += gamma/10.0; + + d->cmod.reset(); + d->cmod.setGamma(d->gamma); + d->cmod.setBrightness(d->brightness); + d->cmod.setContrast(d->contrast); + d->changedBCG = true; + + setModified(); +} + +void DImgInterface::changeBrightness(double brightness) +{ + d->undoMan->addAction(new UndoActionBCG(this, d->gamma, d->brightness, + d->contrast, d->gamma, brightness, + d->contrast)); + + d->brightness += brightness/100.0; + + d->cmod.reset(); + d->cmod.setGamma(d->gamma); + d->cmod.setBrightness(d->brightness); + d->cmod.setContrast(d->contrast); + d->changedBCG = true; + + setModified(); +} + +void DImgInterface::changeContrast(double contrast) +{ + d->undoMan->addAction(new UndoActionBCG(this, d->gamma, d->brightness, + d->contrast, d->gamma, d->brightness, + contrast)); + + d->contrast += contrast/100.0; + + d->cmod.reset(); + d->cmod.setGamma(d->gamma); + d->cmod.setBrightness(d->brightness); + d->cmod.setContrast(d->contrast); + d->changedBCG = true; + + setModified(); +} + +void DImgInterface::changeBCG(double gamma, double brightness, double contrast) +{ + d->gamma = gamma; + d->brightness = brightness; + d->contrast = contrast; + + d->cmod.reset(); + d->cmod.setGamma(d->gamma); + d->cmod.setBrightness(d->brightness); + d->cmod.setContrast(d->contrast); + d->changedBCG = true; + + setModified(); +} + +void DImgInterface::setBCG(double brightness, double contrast, double gamma) +{ + d->undoMan->addAction(new UndoActionIrreversible(this, "Brightness, Contrast, Gamma")); + + d->cmod.reset(); + d->cmod.setGamma(gamma); + d->cmod.setBrightness(brightness); + d->cmod.setContrast(contrast); + d->cmod.applyBCG(d->image); + + d->cmod.reset(); + d->gamma = 1.0; + d->contrast = 1.0; + d->brightness = 0.0; + d->changedBCG = false; + + setModified(); +} + +void DImgInterface::convertDepth(int depth) +{ + d->undoMan->addAction(new UndoActionIrreversible(this, "Convert Color Depth")); + d->image.convertDepth(depth); + + setModified(); +} + +DImg* DImgInterface::getImg() +{ + if (!d->image.isNull()) + { + return &d->image; + } + else + { + DWarning() << k_funcinfo << "d->image is NULL" << endl; + return 0; + } +} + +uchar* DImgInterface::getImage() +{ + if (!d->image.isNull()) + { + return d->image.bits(); + } + else + { + DWarning() << k_funcinfo << "d->image is NULL" << endl; + return 0; + } +} + +void DImgInterface::putImage(const TQString &caller, uchar* data, int w, int h) +{ + putImage(caller, data, w, h, d->image.sixteenBit()); +} + +void DImgInterface::putImage(const TQString &caller, uchar* data, int w, int h, bool sixteenBit) +{ + d->undoMan->addAction(new UndoActionIrreversible(this, caller)); + putImage(data, w, h, sixteenBit); +} + +void DImgInterface::putImage(uchar* data, int w, int h) +{ + putImage(data, w, h, d->image.sixteenBit()); +} + +void DImgInterface::putImage(uchar* data, int w, int h, bool sixteenBit) +{ + if (d->image.isNull()) + { + DWarning() << k_funcinfo << "d->image is NULL" << endl; + return; + } + + if (!data) + { + DWarning() << k_funcinfo << "New image is NULL" << endl; + return; + } + + if (w == -1 && h == -1) + { + // New image size + w = d->origWidth; + h = d->origHeight; + } + else + { + // New image size == original size + d->origWidth = w; + d->origHeight = h; + } + + //DDebug() << k_funcinfo << data << " " << w << " " << h << endl; + d->image.putImageData(w, h, sixteenBit, d->image.hasAlpha(), data); + + setModified(); +} + +void DImgInterface::setEmbeddedICCToOriginalImage( TQString profilePath) +{ + if (d->image.isNull()) + { + DWarning() << k_funcinfo << "d->image is NULL" << endl; + return; + } + + DDebug() << k_funcinfo << "Embedding profile: " << profilePath << endl; + d->image.getICCProfilFromFile( TQFile::encodeName(profilePath)); + setModified(); +} + +uchar* DImgInterface::getImageSelection() +{ + if (!d->selW || !d->selH) + return 0; + + if (!d->image.isNull()) + { + DImg im = d->image.copy(d->selX, d->selY, d->selW, d->selH); + return im.stripImageData(); + } + + return 0; +} + +void DImgInterface::putImageSelection(const TQString &caller, uchar* data) +{ + if (!data || d->image.isNull()) + return; + + d->undoMan->addAction(new UndoActionIrreversible(this, caller)); + + d->image.bitBltImage(data, 0, 0, d->selW, d->selH, d->selX, d->selY, d->selW, d->selH, d->image.bytesDepth()); + + setModified(); +} + +void DImgInterface::getUndoHistory(TQStringList &titles) +{ + d->undoMan->getUndoHistory(titles); +} + +void DImgInterface::getRedoHistory(TQStringList &titles) +{ + d->undoMan->getRedoHistory(titles); +} + +TQByteArray DImgInterface::getEmbeddedICC() +{ + return d->image.getICCProfil(); +} + +TQByteArray DImgInterface::getExif() +{ + return d->image.getExif(); +} + +TQByteArray DImgInterface::getIptc() +{ + return d->image.getIptc(); +} + +TQString DImgInterface::getImageFilePath() +{ + return d->filename; +} + +TQString DImgInterface::getImageFileName() +{ + return d->filename.section( '/', -1 ); +} + +TQString DImgInterface::getImageFormat() +{ + if (d->image.isNull()) + return TQString(); + + TQString mimeType = d->image.attribute("format").toString(); + // It is a bug in the loader if format attribute is not given + if (mimeType.isEmpty()) + { + DWarning() << "DImg object does not contain attribute \"format\"" << endl; + mimeType = TQImageIO::imageFormat(d->filename); + } + return mimeType; +} + +ICCSettingsContainer* DImgInterface::getICCSettings() +{ + return d->cmSettings; +} + +TQPixmap DImgInterface::convertToPixmap(DImg& img) +{ + if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting) + return img.convertToPixmap(&d->monitorICCtrans); + + return img.convertToPixmap(); +} + +TQColor DImgInterface::underExposureColor() +{ + return d->expoSettings->underExposureColor; +} + +TQColor DImgInterface::overExposureColor() +{ + return d->expoSettings->overExposureColor; +} + +} // namespace Digikam + diff --git a/src/utilities/imageeditor/canvas/dimginterface.h b/src/utilities/imageeditor/canvas/dimginterface.h new file mode 100644 index 00000000..9a41eb05 --- /dev/null +++ b/src/utilities/imageeditor/canvas/dimginterface.h @@ -0,0 +1,200 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2003-01-15 + * Description : DImg interface for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef DIMGINTERFACE_H +#define DIMGINTERFACE_H + +// TQt includes. + +#include <tqobject.h> +#include <tqstring.h> + +// Local includes. + +#include "digikam_export.h" +#include "dimg.h" + +class TQWidget; +class TQPixmap; + +namespace Digikam +{ + +class ICCSettingsContainer; +class ExposureSettingsContainer; +class IOFileSettingsContainer; +class LoadingDescription; +class DImgInterfacePrivate; + +class DIGIKAM_EXPORT DImgInterface : public TQObject +{ + TQ_OBJECT + + +public: + + static DImgInterface* defaultInterface(); + static void setDefaultInterface(DImgInterface *defaultInterface); + + DImgInterface(); + ~DImgInterface(); + + void load(const TQString& filename, IOFileSettingsContainer *iofileSettings, TQWidget *parent=0); + + void setICCSettings(ICCSettingsContainer *cmSettings); + void setExposureSettings(ExposureSettingsContainer *expoSettings); + void setExifOrient(bool exifOrient); + + void undo(); + void redo(); + void restore(); + + void saveAs(const TQString& file, IOFileSettingsContainer *iofileSettings, + bool setExifOrientationTag, const TQString& mimeType=TQString()); + + void switchToLastSaved(const TQString& newFilename); + void abortSaving(); + void setModified(); + void readMetadataFromFile(const TQString &file); + void clearUndoManager(); + void setUndoManagerOrigin(); + void updateUndoState(); + void resetImage(); + + void zoom(double val); + + void paintOnDevice(TQPaintDevice* p, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + int antialias); + void paintOnDevice(TQPaintDevice* p, + int sx, int sy, int sw, int sh, + int dx, int dy, int dw, int dh, + int mx, int my, int mw, int mh, + int antialias); + + bool imageValid(); + int width(); + int height(); + int origWidth(); + int origHeight(); + int bytesDepth(); + bool hasAlpha(); + bool sixteenBit(); + bool exifRotated(); + bool isReadOnly(); + + void setSelectedArea(int x, int y, int w, int h); + void getSelectedArea(int& x, int& y, int& w, int& h); + + void rotate90(bool saveUndo=true); + void rotate180(bool saveUndo=true); + void rotate270(bool saveUndo=true); + + void flipHoriz(bool saveUndo=true); + void flipVert(bool saveUndo=true); + + void crop(int x, int y, int w, int h); + + void resize(int w, int h); + + void changeGamma(double gamma); + void changeBrightness(double brightness); + void changeContrast(double contrast); + void changeBCG(double gamma, double brightness, double contrast); + + void setBCG(double brightness, double contrast, double gamma); + + void convertDepth(int depth); + + void getUndoHistory(TQStringList &titles); + void getRedoHistory(TQStringList &titles); + + DImg* getImg(); + uchar* getImage(); + + void putImage(uchar* data, int w, int h); + void putImage(uchar* data, int w, int h, bool sixteenBit); + void putImage(const TQString &caller, uchar* data, int w, int h); + void putImage(const TQString &caller, uchar* data, int w, int h, bool sixteenBit); + + uchar* getImageSelection(); + void putImageSelection(const TQString &caller, uchar* data); + + void setEmbeddedICCToOriginalImage( TQString profilePath); + + /** Convert a DImg image to a pixmap for screen using color + managemed view if necessary */ + TQPixmap convertToPixmap(DImg& img); + + TQByteArray getEmbeddedICC(); + TQByteArray getExif(); + TQByteArray getIptc(); + + ICCSettingsContainer *getICCSettings(); + + TQString getImageFileName(); + TQString getImageFilePath(); + TQString getImageFormat(); + + TQColor underExposureColor(); + TQColor overExposureColor(); + +protected slots: + + void slotImageLoaded(const LoadingDescription &loadingDescription, const DImg& img); + void slotImageSaved(const TQString& filePath, bool success); + void slotLoadingProgress(const LoadingDescription &loadingDescription, float progress); + void slotSavingProgress(const TQString& filePath, float progress); + +signals: + + void signalModified(); + void signalUndoStateChanged(bool moreUndo, bool moreRedo, bool canSave); + void signalLoadingStarted(const TQString& filename); + void signalLoadingProgress(const TQString& filePath, float progress); + void signalImageLoaded(const TQString& filePath, bool success); + void signalSavingProgress(const TQString& filePath, float progress); + void signalImageSaved(const TQString& filePath, bool success); + +private slots: + + void slotUseRawImportSettings(); + void slotUseDefaultSettings(); + +private: + + void exifRotate(const TQString& filename); + void resetValues(); + +private: + + static DImgInterface *m_defaultInterface; + + DImgInterfacePrivate *d; +}; + +} // namespace Digikam + +#endif /* DIMGINTERFACE_H */ diff --git a/src/utilities/imageeditor/canvas/iccsettingscontainer.h b/src/utilities/imageeditor/canvas/iccsettingscontainer.h new file mode 100644 index 00000000..eadb12fb --- /dev/null +++ b/src/utilities/imageeditor/canvas/iccsettingscontainer.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-12-08 + * Description : ICC Settings Container. + * + * Copyright (C) 2005-2007 by F.J. Cruz <fj.cruz@supercable.es> + * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef ICCSETTINGSCONTAINER_H +#define ICCSETTINGSCONTAINER_H + +// TQt includes. + +#include <tqstring.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT ICCSettingsContainer +{ + +public: + + ICCSettingsContainer() + { + enableCMSetting = false; // NOTE: by default, ICC color management is disable. + + askOrApplySetting = false; + BPCSetting = false; + managedViewSetting = false; + + renderingSetting = 0; + + workspaceSetting = TQString(); + monitorSetting = TQString(); + inputSetting = TQString(); + proofSetting = TQString(); + }; + + ~ICCSettingsContainer(){}; + +public: + + bool enableCMSetting; + + // FALSE -> apply + // TRUE -> ask + bool askOrApplySetting; + bool BPCSetting; + bool managedViewSetting; + + int renderingSetting; + + TQString workspaceSetting; + TQString monitorSetting; + TQString inputSetting; + TQString proofSetting; +}; + +} // namespace Digikam + +#endif // ICCSETTINGSCONTAINER_H diff --git a/src/utilities/imageeditor/canvas/imageplugin.cpp b/src/utilities/imageeditor/canvas/imageplugin.cpp new file mode 100644 index 00000000..b330cb5a --- /dev/null +++ b/src/utilities/imageeditor/canvas/imageplugin.cpp @@ -0,0 +1,68 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : image plugins interface for image editor + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// Local includes. + +#include "editortool.h" +#include "editortooliface.h" +#include "imageplugin.h" +#include "imageplugin.moc" + +namespace Digikam +{ + +ImagePlugin::ImagePlugin(TQObject *parent, const char* name) + : TQObject(parent, name) +{ +} + +ImagePlugin::~ImagePlugin() +{ +} + +void ImagePlugin::setEnabledSelectionActions(bool) +{ +} + +void ImagePlugin::setEnabledActions(bool) +{ +} + +void ImagePlugin::loadTool(EditorTool* tool) +{ + EditorToolIface::editorToolIface()->loadTool(tool); + + connect(tool, TQ_SIGNAL(okClicked()), + this, TQ_SLOT(slotToolDone())); + + connect(tool, TQ_SIGNAL(cancelClicked()), + this, TQ_SLOT(slotToolDone())); +} + +void ImagePlugin::slotToolDone() +{ + EditorToolIface::editorToolIface()->unLoadTool(); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/canvas/imageplugin.h b/src/utilities/imageeditor/canvas/imageplugin.h new file mode 100644 index 00000000..ef506256 --- /dev/null +++ b/src/utilities/imageeditor/canvas/imageplugin.h @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : image plugins interface for image editor. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_H +#define IMAGEPLUGIN_H + +// TQt includes. + +#include <tqobject.h> + +// KDE includes. + +#include <kxmlguiclient.h> + +// Local includes. + +#include "digikam_export.h" + +class TQWidget; + +namespace Digikam +{ + +class EditorTool; + +class DIGIKAM_EXPORT ImagePlugin : public TQObject, public KXMLGUIClient +{ + TQ_OBJECT + + +public: + + ImagePlugin(TQObject *parent, const char* name=0); + virtual ~ImagePlugin(); + + virtual void setEnabledSelectionActions(bool enable); + virtual void setEnabledActions(bool enable); + + void loadTool(EditorTool* tool); + +private slots: + + void slotToolDone(); +}; + +} //namespace Digikam + +#endif /* IMAGEPLUGIN_H */ + diff --git a/src/utilities/imageeditor/canvas/imagepluginloader.cpp b/src/utilities/imageeditor/canvas/imagepluginloader.cpp new file mode 100644 index 00000000..43c8a16c --- /dev/null +++ b/src/utilities/imageeditor/canvas/imagepluginloader.cpp @@ -0,0 +1,278 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : image plugins loader for image editor. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// KDE includes. + +#include <ktrader.h> +#include <tdeparts/componentfactory.h> +#include <tdeapplication.h> +#include <tdelocale.h> +#include <kxmlguiclient.h> + +// Local includes. + +#include "ddebug.h" +#include "splashscreen.h" +#include "imagepluginloader.h" + +namespace Digikam +{ + +// List of obsolete image plugins name. + +static const char* ObsoleteImagePluginsList[] = +{ + "digikamimageplugin_blowup", // Merged with "Resize" tool since 0.9.2. + "digikamimageplugin_solarize", // Renamed "ColorFx" since 0.9.2. + "digikamimageplugin_unsharp", // Merged with "Sharpen" tool since 0.9.2. + "digikamimageplugin_refocus", // Merged with "Sharpen" tool since 0.9.2. + "digikamimageplugin_despeckle", // Renamed "Noise Reduction" since 0.9.2. + "-1" +}; + +class ImagePluginLoaderPrivate +{ + +public: + + typedef TQPair<TQString, ImagePlugin*> PluginType; + typedef TQValueList< PluginType > PluginList; + +public: + + ImagePluginLoaderPrivate() + { + splash = 0; + + for (int i=0 ; TQString(ObsoleteImagePluginsList[i]) != TQString("-1") ; i++) + obsoleteImagePluginsList << ObsoleteImagePluginsList[i]; + } + + TQStringList obsoleteImagePluginsList; + + SplashScreen *splash; + + PluginList pluginList; +}; + +ImagePluginLoader* ImagePluginLoader::m_instance=0; + +ImagePluginLoader* ImagePluginLoader::instance() +{ + return m_instance; +} + +ImagePluginLoader::ImagePluginLoader(TQObject *parent, SplashScreen *splash) + : TQObject(parent) +{ + m_instance = this; + d = new ImagePluginLoaderPrivate; + d->splash = splash; + + TQStringList imagePluginsList2Load; + + TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin"); + TDETrader::OfferList::ConstIterator iter; + + for (iter = offers.begin() ; iter != offers.end() ; ++iter) + { + KService::Ptr service = *iter; + if (!d->obsoleteImagePluginsList.contains(service->library())) + imagePluginsList2Load.append(service->library()); + } + + loadPluginsFromList(imagePluginsList2Load); +} + +ImagePluginLoader::~ImagePluginLoader() +{ + delete d; + m_instance = 0; +} + +void ImagePluginLoader::loadPluginsFromList(const TQStringList& list) +{ + if (d->splash) + d->splash->message(i18n("Loading Image Plugins")); + + TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin"); + TDETrader::OfferList::ConstIterator iter; + + int cpt = 0; + + // Load plugin core at the first time. + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + ImagePlugin *plugin; + + if (service->library() == "digikamimageplugin_core") + { + if (!pluginIsLoaded(service->name()) ) + { + int error=-1; + plugin = KParts::ComponentFactory::createInstanceFromService<ImagePlugin>( + service, this, service->name().local8Bit(), 0, &error); + + if (plugin && (dynamic_cast<KXMLGUIClient*>(plugin) != 0)) + { + d->pluginList.append(ImagePluginLoaderPrivate::PluginType(service->name(), plugin)); + + DDebug() << "ImagePluginLoader: Loaded plugin " << service->name() << endl; + + ++cpt; + } + else + { + DWarning() << "ImagePluginLoader:: createInstanceFromLibrary returned 0 for " + << service->name() + << " (" << service->library() << ")" + << " with error code " + << error << endl; + if (error == KParts::ComponentFactory::ErrNoLibrary) + DWarning() << "KLibLoader says: " + << KLibLoader::self()->lastErrorMessage() << endl; + } + } + break; + } + } + + // Load all other image plugins after (make a coherant menu construction in Image Editor). + + for (iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + ImagePlugin *plugin; + + if (!list.contains(service->library()) && service->library() != "digikamimageplugin_core") + { + if ((plugin = pluginIsLoaded(service->name())) != NULL) + d->pluginList.remove(ImagePluginLoaderPrivate::PluginType(service->name(),plugin)); + } + else + { + if( pluginIsLoaded(service->name()) ) + continue; + else + { + int error=-1; + plugin = KParts::ComponentFactory::createInstanceFromService<ImagePlugin>( + service, this, service->name().local8Bit(), 0); + + if (plugin && (dynamic_cast<KXMLGUIClient*>(plugin) != 0)) + { + d->pluginList.append(ImagePluginLoaderPrivate::PluginType(service->name(), plugin)); + + DDebug() << "ImagePluginLoader: Loaded plugin " << service->name() << endl; + + ++cpt; + } + else + { + DWarning() << "ImagePluginLoader:: createInstanceFromLibrary returned 0 for " + << service->name() + << " (" << service->library() << ")" + << " with error code " + << error << endl; + if (error == KParts::ComponentFactory::ErrNoLibrary) + DWarning() << "KLibLoader says: " + << KLibLoader::self()->lastErrorMessage() << endl; + } + } + } + } + + d->splash = 0; // Splashcreen is only lanched at the first time. + // If user change plugins list to use in setup, don't try to + // use the old splashscreen instance. +} + +ImagePlugin* ImagePluginLoader::pluginIsLoaded(const TQString& name) +{ + if ( d->pluginList.isEmpty() ) + return 0; + + for (ImagePluginLoaderPrivate::PluginList::iterator it = d->pluginList.begin(); + it != d->pluginList.end(); ++it) + { + if ((*it).first == name ) + return (*it).second; + } + + return 0; +} + +ImagePlugin* ImagePluginLoader::pluginInstance(const TQString& libraryName) +{ + TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin"); + TDETrader::OfferList::ConstIterator iter; + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + + if(service->library() == libraryName) + { + return ( pluginIsLoaded(service->name()) ); + } + } + + return 0; +} + +bool ImagePluginLoader::pluginLibraryIsLoaded(const TQString& libraryName) +{ + TDETrader::OfferList offers = TDETrader::self()->query("Digikam/ImagePlugin"); + TDETrader::OfferList::ConstIterator iter; + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + + if(service->library() == libraryName) + { + if( pluginIsLoaded(service->name()) ) + return true; + } + } + + return false; +} + +TQPtrList<ImagePlugin> ImagePluginLoader::pluginList() +{ + TQPtrList<ImagePlugin> list; + + for (ImagePluginLoaderPrivate::PluginList::iterator it = d->pluginList.begin(); + it != d->pluginList.end(); ++it) + { + list.append((*it).second); + } + + return list; +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/canvas/imagepluginloader.h b/src/utilities/imageeditor/canvas/imagepluginloader.h new file mode 100644 index 00000000..55ffe933 --- /dev/null +++ b/src/utilities/imageeditor/canvas/imagepluginloader.h @@ -0,0 +1,79 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-06-04 + * Description : image plugins loader for image editor. + * + * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEPLUGINLOADER_H +#define IMAGEPLUGINLOADER_H + +// TQt includes. + +#include <tqobject.h> +#include <tqptrlist.h> +#include <tqstring.h> +#include <tqvaluelist.h> +#include <tqpair.h> + +// Local includes. + +#include "digikam_export.h" +#include "imageplugin.h" + +namespace Digikam +{ + +class SplashScreen; +class ImagePluginLoaderPrivate; + +class DIGIKAM_EXPORT ImagePluginLoader : public TQObject +{ + +public: + + ImagePluginLoader(TQObject *parent, SplashScreen *splash=0); + ~ImagePluginLoader(); + + static ImagePluginLoader* instance(); + + TQPtrList<ImagePlugin> pluginList(); + void loadPluginsFromList(const TQStringList& list); + + // Return true if plugin library is loaded in memory. + // 'libraryName' is internal plugin library name not i18n. + bool pluginLibraryIsLoaded(const TQString& libraryName); + + ImagePlugin* pluginInstance(const TQString& libraryName); + +private: + + ImagePlugin* pluginIsLoaded(const TQString& name); + +private: + + static ImagePluginLoader *m_instance; + + ImagePluginLoaderPrivate *d; +}; + +} // namespace Digikam + +#endif /* IMAGEPLUGINLOADER_H */ diff --git a/src/utilities/imageeditor/canvas/iofilesettingscontainer.h b/src/utilities/imageeditor/canvas/iofilesettingscontainer.h new file mode 100644 index 00000000..360299b3 --- /dev/null +++ b/src/utilities/imageeditor/canvas/iofilesettingscontainer.h @@ -0,0 +1,84 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2006-01-03 + * Description : IO file Settings Container. + * + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IOFILESETTINGSCONTAINER_H +#define IOFILESETTINGSCONTAINER_H + +// Local includes. + +#include "drawdecoding.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT IOFileSettingsContainer +{ + +public: + + IOFileSettingsContainer() + { + JPEGCompression = 75; + JPEGSubSampling = 1; // Medium subsampling + PNGCompression = 9; + TIFFCompression = false; + JPEG2000Compression = 75; + JPEG2000LossLess = true; + useRAWImport = true; + }; + + ~IOFileSettingsContainer(){}; + +public: + + // JPEG quality value. + int JPEGCompression; + + // JPEG chroma subsampling value. + int JPEGSubSampling; + + // PNG compression value. + int PNGCompression; + + // TIFF deflat compression. + bool TIFFCompression; + + // JPEG2000 quality value. + int JPEG2000Compression; + + // JPEG2000 lossless compression. + bool JPEG2000LossLess; + + // Use Raw Import tool to load a RAW picture. + bool useRAWImport; + + // ------------------------------------------------------ + // RAW File decoding options : + + DRawDecoding rawDecodingSettings; +}; + +} // namespace Digikam + +#endif // IOFILESETTINGSCONTAINER_H diff --git a/src/utilities/imageeditor/canvas/undoaction.cpp b/src/utilities/imageeditor/canvas/undoaction.cpp new file mode 100644 index 00000000..bb4ff756 --- /dev/null +++ b/src/utilities/imageeditor/canvas/undoaction.cpp @@ -0,0 +1,185 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-06 + * Description : undo actions manager for image editor. + * + * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net> + * + * 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 "ddebug.h" +#include "dimginterface.h" +#include "undoaction.h" + +namespace Digikam +{ + +UndoAction::UndoAction(DImgInterface* iface) + : m_iface(iface) +{ + m_title = i18n("unknown"); +} + +UndoAction::~UndoAction() +{ +} + +TQString UndoAction::getTitle() const +{ + return m_title; +} + +UndoActionRotate::UndoActionRotate(DImgInterface* iface, + UndoActionRotate::Angle angle) + : UndoAction(iface), m_angle(angle) +{ + switch(m_angle) + { + case(R90): + m_title = i18n("Rotate 90 Degrees"); + break; + case(R180): + m_title = i18n("Rotate 180 Degrees"); + break; + case(R270): + m_title = i18n("Rotate 270 Degrees"); + break; + } +} + +UndoActionRotate::~UndoActionRotate() +{ +} + +void UndoActionRotate::rollBack() +{ + switch(m_angle) + { + case(R90): + m_iface->rotate270(false); + return; + case(R180): + m_iface->rotate180(false); + return; + case(R270): + m_iface->rotate90(false); + return; + default: + DWarning() << "Unknown rotate angle specified" << endl; + } +} + +void UndoActionRotate::execute() +{ + switch(m_angle) + { + case R90: + m_iface->rotate90(false); + return; + case R180: + m_iface->rotate180(false); + return; + case R270: + m_iface->rotate270(false); + return; + default: + DWarning() << "Unknown rotate angle specified" << endl; + } +} + +UndoActionFlip::UndoActionFlip(DImgInterface* iface, + UndoActionFlip::Direction dir) + : UndoAction(iface), m_dir(dir) +{ + if(m_dir ==TQt::Horizontal) + m_title = i18n("Flip Horizontal"); + else if(m_dir ==TQt::Vertical) + m_title = i18n("Flip Vertical"); +} + +UndoActionFlip::~UndoActionFlip() +{ +} + +void UndoActionFlip::rollBack() +{ + switch(m_dir) + { + case TQt::Horizontal: + m_iface->flipHoriz(false); + return; + case TQt::Vertical: + m_iface->flipVert(false); + return; + default: + DWarning() << "Unknown flip direction specified" << endl; + } +} + +void UndoActionFlip::execute() +{ + rollBack(); +} + +UndoActionBCG::UndoActionBCG(DImgInterface* iface, + double oldGamma, double oldBrightness, + double oldContrast, double newGamma, + double newBrightness, double newContrast) + : UndoAction(iface), m_oldGamma(oldGamma), m_oldBrightness(oldBrightness), + m_oldContrast(oldContrast), m_newGamma(newGamma), m_newBrightness(newBrightness), + m_newContrast(newContrast) +{ + m_title = i18n("Brightness,Contrast,Gamma"); +} + +UndoActionBCG::~UndoActionBCG() +{ +} + +void UndoActionBCG::rollBack() +{ + m_iface->changeBCG(m_oldGamma, m_oldBrightness, m_oldContrast); +} + +void UndoActionBCG::execute() +{ + m_iface->changeBCG(m_newGamma, m_newBrightness, m_newContrast); +} + +UndoActionIrreversible::UndoActionIrreversible(DImgInterface* iface, + const TQString &title) + : UndoAction(iface) +{ + m_title = title; +} + +UndoActionIrreversible::~UndoActionIrreversible() +{ +} + +void UndoActionIrreversible::rollBack() +{ +} + +void UndoActionIrreversible::execute() +{ +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/canvas/undoaction.h b/src/utilities/imageeditor/canvas/undoaction.h new file mode 100644 index 00000000..5f29486e --- /dev/null +++ b/src/utilities/imageeditor/canvas/undoaction.h @@ -0,0 +1,144 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-06 + * Description : undo actions manager for image editor. + * + * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net> + * + * 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 UNDOACTION_H +#define UNDOACTION_H + +// KDE includes. + +#include <tdelocale.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DImgInterface; + +class DIGIKAM_EXPORT UndoAction +{ + +public: + + UndoAction(DImgInterface* iface); + virtual ~UndoAction(); + + virtual void rollBack() = 0; + virtual void execute() = 0; + + TQString getTitle() const; + +protected: + + DImgInterface *m_iface; + TQString m_title; +}; + +class DIGIKAM_EXPORT UndoActionRotate : public UndoAction +{ + +public: + + enum Angle + { + R90, + R180, + R270 + }; + + UndoActionRotate(DImgInterface* iface, Angle angle); + ~UndoActionRotate(); + + void rollBack(); + void execute(); + +private: + + int m_angle; +}; + +class DIGIKAM_EXPORT UndoActionFlip : public UndoAction +{ + +public: + + enum Direction + { + Horizontal, + Vertical + }; + + UndoActionFlip(DImgInterface* iface, Direction dir); + ~UndoActionFlip(); + + void rollBack(); + void execute(); + +private: + + int m_dir; +}; + +class DIGIKAM_EXPORT UndoActionBCG : public UndoAction +{ + +public: + + UndoActionBCG(DImgInterface* iface, + double oldGamma, double oldBrightness, + double oldContrast, double newGamma, + double newBrightness, double newContrast); + ~UndoActionBCG(); + + void rollBack(); + void execute(); + +private: + + double m_oldGamma; + double m_oldBrightness; + double m_oldContrast; + double m_newGamma; + double m_newBrightness; + double m_newContrast; +}; + +class DIGIKAM_EXPORT UndoActionIrreversible : public UndoAction +{ + +public: + + UndoActionIrreversible(DImgInterface* iface, + const TQString &caller=i18n("Unknown")); + ~UndoActionIrreversible(); + + void rollBack(); + void execute(); +}; + +} // namespace Digikam + +#endif /* UNDOACTION_H */ diff --git a/src/utilities/imageeditor/canvas/undocache.cpp b/src/utilities/imageeditor/canvas/undocache.cpp new file mode 100644 index 00000000..5f36ae75 --- /dev/null +++ b/src/utilities/imageeditor/canvas/undocache.cpp @@ -0,0 +1,178 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-05 + * Description : undo cache manager for image editor + * + * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net> + * + * 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 <unistd.h> +} + +// TQt includes. + +#include <tqcstring.h> +#include <tqstring.h> +#include <tqfile.h> +#include <tqdatastream.h> +#include <tqstringlist.h> + +// KDE includes. + +#include <kstandarddirs.h> +#include <tdeaboutdata.h> +#include <kinstance.h> +#include <tdeglobal.h> + +// Local includes. + +#include "ddebug.h" +#include "undocache.h" + +namespace Digikam +{ + +class UndoCachePriv +{ +public: + + TQString cachePrefix; + TQStringList cacheFilenames; +}; + +UndoCache::UndoCache() +{ + d = new UndoCachePriv; + + TQString cacheDir; + cacheDir = locateLocal("cache", + TDEGlobal::instance()->aboutData()->programName() + '/'); + + d->cachePrefix = TQString("%1undocache-%2") + .arg(cacheDir) + .arg(getpid()); +} + +UndoCache::~UndoCache() +{ + clear(); + delete d; +} + +/** + * delete all cache files + */ +void UndoCache::clear() +{ + for (TQStringList::iterator it = d->cacheFilenames.begin(); + it != d->cacheFilenames.end(); ++it) + { + ::unlink(TQFile::encodeName(*it)); + } + + d->cacheFilenames.clear(); +} + +/** + * write the data into a cache file + */ +bool UndoCache::putData(int level, int w, int h, int bytesDepth, uchar* data) +{ + TQString cacheFile = TQString("%1-%2.bin") + .arg(d->cachePrefix) + .arg(level); + + TQFile file(cacheFile); + + if (file.exists() || !file.open(IO_WriteOnly)) + return false; + + TQDataStream ds(&file); + ds << w; + ds << h; + ds << bytesDepth; + + TQByteArray ba(w*h*bytesDepth); + memcpy (ba.data(), data, w*h*bytesDepth); + ds << ba; + + file.close(); + + d->cacheFilenames.append(cacheFile); + + return true; +} + +/** + * get the data from a cache file + */ +uchar* UndoCache::getData(int level, int& w, int& h, int& bytesDepth, bool del) +{ + TQString cacheFile = TQString("%1-%2.bin") + .arg(d->cachePrefix) + .arg(level); + + TQFile file(cacheFile); + if (!file.open(IO_ReadOnly)) + return 0; + + TQDataStream ds(&file); + ds >> w; + ds >> h; + ds >> bytesDepth; + + uchar *data = new uchar[w*h*bytesDepth]; + if (!data) + return 0; + + TQByteArray ba(w*h*bytesDepth); + ds >> ba; + memcpy (data, ba.data(), w*h*bytesDepth); + + file.close(); + + if(del) + { + ::unlink(TQFile::encodeName(cacheFile)); + d->cacheFilenames.remove(cacheFile); + } + + return data; +} + +/** + * delete a cache file + */ +void UndoCache::erase(int level) +{ + TQString cacheFile = TQString("%1-%2.bin") + .arg(d->cachePrefix) + .arg(level); + + if(d->cacheFilenames.find(cacheFile) == d->cacheFilenames.end()) + return; + + ::unlink(TQFile::encodeName(cacheFile)); +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/canvas/undocache.h b/src/utilities/imageeditor/canvas/undocache.h new file mode 100644 index 00000000..732c7c3e --- /dev/null +++ b/src/utilities/imageeditor/canvas/undocache.h @@ -0,0 +1,62 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-05 + * Description : undo cache manager for image editor. + * + * Copyright (C) 2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005 by Joern Ahrens <joern.ahrens@kdemail.net> + * + * 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 UNDOCACHE_H +#define UNDOCACHE_H + +// TQt includes. + +#include <tqglobal.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class UndoCachePriv; + +class DIGIKAM_EXPORT UndoCache +{ + +public: + + UndoCache(); + ~UndoCache(); + + void clear(); + bool putData(int level, int w, int h, int bytesDepth, uchar* data); + uchar *getData(int level, int& w, int& h, int& bytesDepth, bool del=true); + + void erase(int level); + +private: + + UndoCachePriv *d; +}; + +} // namespace Digikam + +#endif /* UNDOCACHE_H */ diff --git a/src/utilities/imageeditor/canvas/undomanager.cpp b/src/utilities/imageeditor/canvas/undomanager.cpp new file mode 100644 index 00000000..87085d5d --- /dev/null +++ b/src/utilities/imageeditor/canvas/undomanager.cpp @@ -0,0 +1,253 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-06 + * Description : an image editor actions undo/redo manager + * + * Copyright (C) 2005-2006 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-2006 Joern Ahrens <joern.ahrens@kdemail.net> + * + * 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 <typeinfo> +#include <climits> + +// Local includes. + +#include "ddebug.h" +#include "dimginterface.h" +#include "undoaction.h" +#include "undocache.h" +#include "undomanager.h" + +namespace Digikam +{ + +class UndoManagerPriv +{ + +public: + + UndoManagerPriv() + { + dimgiface = 0; + undoCache = 0; + origin = 0; + } + + TQValueList<UndoAction*> undoActions; + TQValueList<UndoAction*> redoActions; + int origin; + + UndoCache *undoCache; + + DImgInterface *dimgiface; +}; + +UndoManager::UndoManager(DImgInterface* iface) +{ + d = new UndoManagerPriv; + d->dimgiface = iface; + d->undoCache = new UndoCache; +} + +UndoManager::~UndoManager() +{ + clear(true); + delete d->undoCache; + delete d; +} + +void UndoManager::addAction(UndoAction* action) +{ + if (!action) + return; + + // All redo actions are invalid now + clearRedoActions(); + + d->undoActions.push_back(action); + + if (typeid(*action) == typeid(UndoActionIrreversible)) + { + int w = d->dimgiface->origWidth(); + int h = d->dimgiface->origHeight(); + int bytesDepth = d->dimgiface->bytesDepth(); + uchar* data = d->dimgiface->getImage(); + + d->undoCache->putData(d->undoActions.size(), w, h, bytesDepth, data); + } + + // if origin is at one of the redo action that are now invalid, + // it is no longer reachable + if (d->origin < 0) + d->origin = INT_MAX; + else + d->origin++; +} + +void UndoManager::undo() +{ + if (d->undoActions.isEmpty()) + return; + + UndoAction* action = d->undoActions.back(); + + if (typeid(*action) == typeid(UndoActionIrreversible)) + { + // Save the current state for the redo operation + + int w = d->dimgiface->origWidth(); + int h = d->dimgiface->origHeight(); + int bytesDepth = d->dimgiface->bytesDepth(); + uchar* data = d->dimgiface->getImage(); + + d->undoCache->putData(d->undoActions.size() + 1, w, h, bytesDepth, data); + + // And now, undo the action + + int newW, newH, newBytesDepth; + uchar *newData = d->undoCache->getData(d->undoActions.size(), newW, newH, newBytesDepth, false); + if (newData) + { + d->dimgiface->putImage(newData, newW, newH, newBytesDepth == 8 ? true : false); + delete [] newData; + } + } + else + { + action->rollBack(); + } + + d->undoActions.pop_back(); + d->redoActions.push_back(action); + d->origin--; +} + +void UndoManager::redo() +{ + if(d->redoActions.isEmpty()) + return; + + UndoAction *action = d->redoActions.back(); + + if(typeid(*action) == typeid(UndoActionIrreversible)) + { + int w, h, bytesDepth; + uchar *data = d->undoCache->getData(d->undoActions.size() + 2, w, h, bytesDepth, false); + if (data) + { + d->dimgiface->putImage(data, w, h, bytesDepth == 8 ? true : false); + delete[] data; + } + } + else + { + action->execute(); + } + + d->redoActions.pop_back(); + d->undoActions.push_back(action); + d->origin++; +} + +void UndoManager::clear(bool clearCache) +{ + clearUndoActions(); + clearRedoActions(); + setOrigin(); + + if(clearCache) + d->undoCache->clear(); +} + +void UndoManager::clearUndoActions() +{ + UndoAction *action; + TQValueList<UndoAction*>::iterator it; + + for(it = d->undoActions.begin(); it != d->undoActions.end(); ++it) + { + action = *it; + delete action; + } + d->undoActions.clear(); +} + +void UndoManager::clearRedoActions() +{ + if(!anyMoreRedo()) + return; + + UndoAction *action; + TQValueList<UndoAction*>::iterator it; + + // get the level of the first redo action + int level = d->undoActions.size() + 1; + for(it = d->redoActions.begin(); it != d->redoActions.end(); ++it) + { + action = *it; + d->undoCache->erase(level); + delete action; + level++; + } + d->undoCache->erase(level); + d->redoActions.clear(); +} + +bool UndoManager::anyMoreUndo() +{ + return !d->undoActions.isEmpty(); +} + +bool UndoManager::anyMoreRedo() +{ + return !d->redoActions.isEmpty(); +} + +void UndoManager::getUndoHistory(TQStringList &titles) +{ + TQValueList<UndoAction*>::iterator it; + + for(it = d->undoActions.begin(); it != d->undoActions.end(); ++it) + { + titles.push_front((*it)->getTitle()); + } +} + +void UndoManager::getRedoHistory(TQStringList &titles) +{ + TQValueList<UndoAction*>::iterator it; + + for(it = d->redoActions.begin(); it != d->redoActions.end(); ++it) + { + titles.push_front((*it)->getTitle()); + } +} + +bool UndoManager::isAtOrigin() +{ + return d->origin == 0; +} + +void UndoManager::setOrigin() +{ + d->origin = 0; +} + +} // namespace Digikam diff --git a/src/utilities/imageeditor/canvas/undomanager.h b/src/utilities/imageeditor/canvas/undomanager.h new file mode 100644 index 00000000..a36ba12f --- /dev/null +++ b/src/utilities/imageeditor/canvas/undomanager.h @@ -0,0 +1,76 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-06 + * Description : an image editor actions undo/redo manager + * + * Copyright (C) 2005-2006 by Renchi Raju <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2005-2006 by Joern Ahrens <joern.ahrens@kdemail.net> + * + * 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 UNDOMANAGER_H +#define UNDOMANAGER_H + +// TQt includes. + +#include <tqstringlist.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class DImgInterface; +class UndoManagerPriv; +class UndoAction; + +class DIGIKAM_EXPORT UndoManager +{ + +public: + + UndoManager(DImgInterface* iface); + ~UndoManager(); + + void undo(); + void redo(); + + void clear(bool clearCache=true); + bool anyMoreUndo(); + bool anyMoreRedo(); + void getUndoHistory(TQStringList &titles); + void getRedoHistory(TQStringList &titles); + bool isAtOrigin(); + void setOrigin(); + + void addAction(UndoAction* action); + +private: + + void clearUndoActions(); + void clearRedoActions(); + +private: + + UndoManagerPriv *d; +}; + +} // namespace Digikam + +#endif /* UNDOMANAGER_H */ 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 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<gui version="24" name="digikamimagewindow" > + +<MenuBar> + + <Menu name="File" ><text>&File</text> + <Action name="editorwindow_backward" /> + <Action name="editorwindow_forward" /> + <Separator/> + <Action name="editorwindow_first" /> + <Action name="editorwindow_last" /> + <Separator/> + <Action name="editorwindow_print" /> + <Separator/> + <Action name="editorwindow_save" /> + <Action name="editorwindow_saveas" /> + <Action name="editorwindow_revert" /> + <Separator/> + <Action name="editorwindow_delete" /> + <Separator/> + <Action name="editorwindow_close" /> + </Menu> + + <Menu name="Edit" ><text>&Edit</text> + <Action name="editorwindow_copy" /> + <Separator/> + <Action name="editorwindow_undo" /> + <Action name="editorwindow_redo" /> + <Separator/> + <Action name="editorwindow_selectAll" /> + <Action name="editorwindow_selectNone" /> + </Menu> + + <Menu name="View" ><text>&View</text> + <Action name="editorwindow_fullscreen" /> + <Action name="editorwindow_slideshow" /> + <Separator/> + <Action name="editorwindow_zoomplus" /> + <Action name="editorwindow_zoomminus" /> + <Action name="editorwindow_zoomto100percents" /> + <Action name="editorwindow_zoomfit2window" /> + <Action name="editorwindow_zoomfit2select" /> + <Separator/> + <Action name="editorwindow_underexposure" /> + <Action name="editorwindow_overexposure" /> + <Action name="editorwindow_cmview" /> + </Menu> + + <Menu name="Color" ><text>&Color</text> + </Menu> + + <Menu name="Enhance" ><text>Enh&ance</text> + </Menu> + + <Menu name="Transform" ><text>Tra&nsform</text> + <Action name="editorwindow_rotate_left" /> + <Action name="editorwindow_rotate_right" /> + <Separator/> + <Action name="editorwindow_flip_horiz" /> + <Action name="editorwindow_flip_vert" /> + <Separator/> + <Action name="editorwindow_crop" /> + <Action name="editorwindow_resize" /> + </Menu> + + <Menu name="Decorate" ><text>&Decorate</text> + </Menu> + + <Menu name="Filters" ><text>F&ilters</text> + </Menu> + + <Menu name="help" ><text>&Help</text> + <Action name="editorwindow_rawcameralist"/> + <Action name="editorwindow_donatemoney" /> + <Action name="editorwindow_contribute" /> + </Menu> + + <Merge/> + + <Menu name="settings" noMerge="1"><Text>&Settings</Text> + <Merge name="StandardToolBarMenuHandler" /> + <Action name="options_show_menubar"/> + <Action name="options_show_statusbar"/> + <Action name="options_show_toolbar"/> + <Separator/> + <Action name="theme_menu" /> + <Action name="options_configure_keybinding"/> + <Action name="options_configure_toolbars"/> + <Action name="options_configure" /> + </Menu> + +</MenuBar> + +<ToolBar name="ToolBar" ><text>Main Toolbar</text> + <Action name="editorwindow_first" /> + <Action name="editorwindow_backward" /> + <Action name="editorwindow_forward" /> + <Action name="editorwindow_last" /> + <Separator/> + <Action name="editorwindow_save" /> + <Action name="editorwindow_saveas" /> + <Action name="editorwindow_undo" /> + <Action name="editorwindow_redo" /> + <Action name="editorwindow_revert" /> + <Separator/> + <Action name="editorwindow_zoomplus" /> + <Action name="editorwindow_zoomto" /> + <Action name="editorwindow_zoomminus" /> + <Action name="editorwindow_zoomfit2window" /> + <Action name="editorwindow_zoomfit2select" /> + <Separator/> + <Action name="editorwindow_rotate_left" /> + <Action name="editorwindow_rotate_right" /> + <Action name="editorwindow_crop" /> + <Separator/> + <Action name="editorwindow_fullscreen" /> + <Action name="editorwindow_slideshow" /> + <Merge /> + <WeakSeparator/> + <Action name="logo_action" /> +</ToolBar> + +<ActionProperties/> + +</gui> 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// 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<PreviewWidget*>(d->toolView); + if (preview) return preview; + + ImagePanelWidget *panel = dynamic_cast<ImagePanelWidget*>(d->toolView); + if (panel) return (dynamic_cast<PreviewWidget*>(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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORSTACKVIEW_H +#define EDITORSTACKVIEW_H + +// KDE includes. + +#include <tqwidgetstack.h> + +// 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqwidget.h> +#include <tqtimer.h> + +// KDE includes. + +#include <kcursor.h> + +// 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<ImageWidget*>(view) || dynamic_cast<ImageGuideWidget*>(view) || + dynamic_cast<ImagePanelWidget*>(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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORTOOL_H +#define EDITORTOOL_H + +// TQt includes. + +#include <tqobject.h> +#include <tqstring.h> +#include <tqpixmap.h> + +// 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqwidget.h> + +// 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<EditorToolThreaded*>(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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORTOOLIFACE_H +#define EDITORTOOLIFACE_H + +// TQt includes. + +#include <tqobject.h> + +// 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqhbox.h> +#include <tqvbox.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqstring.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <kcolorbutton.h> +#include <kdialog.h> +#include <tdeglobalsettings.h> +#include <kiconloader.h> +#include <tdelocale.h> +#include <kpushbutton.h> +#include <kstandarddirs.h> +#include <kstdguiitem.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// 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("<p>Here you can see the original image panel " + "which can help you to select the clip preview." + "<p>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("<p>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("<p>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("<p>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("<p>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("<p>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("<p>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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORTOOLSETTINGS_H +#define EDITORTOOLSETTINGS_H + +// TQt includes. + +#include <tqscrollview.h> + +// 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C Ansi includes. + +extern "C" +{ +#include <sys/types.h> +#include <sys/stat.h> +} + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqlabel.h> +#include <tqdockarea.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqtoolbutton.h> +#include <tqsplitter.h> +#include <tqdir.h> +#include <tqfileinfo.h> +#include <tqfile.h> +#include <tqcursor.h> +#include <tqtimer.h> +#include <tqfileinfo.h> + +// KDE includes. + +#include <kprinter.h> +#include <kkeydialog.h> +#include <tdeversion.h> +#include <tdeaction.h> +#include <kedittoolbar.h> +#include <tdeaboutdata.h> +#include <kcursor.h> +#include <kstdaction.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdefiledialog.h> +#include <tdemenubar.h> +#include <kimageio.h> +#include <tdeaccel.h> +#include <tdemessagebox.h> +#include <tdeglobal.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <tdeio/netaccess.h> +#include <tdeio/job.h> +#include <kprotocolinfo.h> +#include <tdeglobalsettings.h> +#include <tdetoolbar.h> +#include <kstatusbar.h> +#include <kprogress.h> +#include <twin.h> +#include <kcombobox.h> + +// Local includes. + +#include "ddebug.h" +#include "dpopupmenu.h" +#include "canvas.h" +#include "dimginterface.h" +#include "imagedialog.h" +#include "imageplugin.h" +#include "imagepluginloader.h" +#include "imageresize.h" +#include "imageprint.h" +#include "filesaveoptionsbox.h" +#include "statusprogressbar.h" +#include "iccsettingscontainer.h" +#include "exposurecontainer.h" +#include "iofilesettingscontainer.h" +#include "savingcontextcontainer.h" +#include "loadingcacheinterface.h" +#include "slideshowsettings.h" +#include "themeengine.h" +#include "rawcameradlg.h" +#include "editorstackview.h" +#include "editortooliface.h" +#include "editorwindowprivate.h" +#include "editorwindow.h" +#include "editorwindow.moc" + +void tqt_enter_modal( TQWidget *widget ); +void tqt_leave_modal( TQWidget *widget ); + +namespace Digikam +{ + +EditorWindow::EditorWindow(const char *name) + : TDEMainWindow(0, name, WType_TopLevel) +{ + d = new EditorWindowPriv; + + m_themeMenuAction = 0; + m_contextMenu = 0; + m_canvas = 0; + m_imagePluginLoader = 0; + m_undoAction = 0; + m_redoAction = 0; + m_fullScreenAction = 0; + m_saveAction = 0; + m_saveAsAction = 0; + m_revertAction = 0; + m_fileDeleteAction = 0; + m_forwardAction = 0; + m_backwardAction = 0; + m_firstAction = 0; + m_lastAction = 0; + m_undoAction = 0; + m_redoAction = 0; + m_stackView = 0; + m_fullScreen = false; + m_rotatedOrFlipped = false; + m_setExifOrientationTag = true; + m_cancelSlideShow = false; + + // Settings containers instance. + + d->ICCSettings = new ICCSettingsContainer(); + d->exposureSettings = new ExposureSettingsContainer(); + d->toolIface = new EditorToolIface(this); + m_IOFileSettings = new IOFileSettingsContainer(); + m_savingContext = new SavingContextContainer(); +} + +EditorWindow::~EditorWindow() +{ + delete m_canvas; + delete m_IOFileSettings; + delete m_savingContext; + delete d->ICCSettings; + delete d->exposureSettings; + delete d; +} + +EditorStackView* EditorWindow::editorStackView() const +{ + return m_stackView; +} + +void EditorWindow::setupContextMenu() +{ + m_contextMenu = new DPopupMenu(this); + TDEActionCollection *ac = actionCollection(); + if( ac->action("editorwindow_backward") ) ac->action("editorwindow_backward")->plug(m_contextMenu); + if( ac->action("editorwindow_forward") ) ac->action("editorwindow_forward")->plug(m_contextMenu); + m_contextMenu->insertSeparator(); + if( ac->action("editorwindow_slideshow") ) ac->action("editorwindow_slideshow")->plug(m_contextMenu); + if( ac->action("editorwindow_rotate_left") ) ac->action("editorwindow_rotate_left")->plug(m_contextMenu); + if( ac->action("editorwindow_rotate_right") ) ac->action("editorwindow_rotate_right")->plug(m_contextMenu); + if( ac->action("editorwindow_crop") ) ac->action("editorwindow_crop")->plug(m_contextMenu); + m_contextMenu->insertSeparator(); + if( ac->action("editorwindow_delete") ) ac->action("editorwindow_delete")->plug(m_contextMenu); +} + +void EditorWindow::setupStandardConnections() +{ + // -- Canvas connections ------------------------------------------------ + + connect(m_canvas, TQ_SIGNAL(signalToggleOffFitToWindow()), + this, TQ_SLOT(slotToggleOffFitToWindow())); + + connect(m_canvas, TQ_SIGNAL(signalShowNextImage()), + this, TQ_SLOT(slotForward())); + + connect(m_canvas, TQ_SIGNAL(signalShowPrevImage()), + this, TQ_SLOT(slotBackward())); + + connect(m_canvas, TQ_SIGNAL(signalRightButtonClicked()), + this, TQ_SLOT(slotContextMenu())); + + connect(m_stackView, TQ_SIGNAL(signalZoomChanged(bool, bool, double)), + this, TQ_SLOT(slotZoomChanged(bool, bool, double))); + + connect(m_canvas, TQ_SIGNAL(signalChanged()), + this, TQ_SLOT(slotChanged())); + + connect(m_canvas, TQ_SIGNAL(signalUndoStateChanged(bool, bool, bool)), + this, TQ_SLOT(slotUndoStateChanged(bool, bool, bool))); + + connect(m_canvas, TQ_SIGNAL(signalSelected(bool)), + this, TQ_SLOT(slotSelected(bool))); + + connect(m_canvas, TQ_SIGNAL(signalPrepareToLoad()), + this, TQ_SLOT(slotPrepareToLoad())); + + connect(m_canvas, TQ_SIGNAL(signalLoadingStarted(const TQString &)), + this, TQ_SLOT(slotLoadingStarted(const TQString &))); + + connect(m_canvas, TQ_SIGNAL(signalLoadingFinished(const TQString &, bool)), + this, TQ_SLOT(slotLoadingFinished(const TQString &, bool))); + + connect(m_canvas, TQ_SIGNAL(signalLoadingProgress(const TQString &, float)), + this, TQ_SLOT(slotLoadingProgress(const TQString &, float))); + + connect(m_canvas, TQ_SIGNAL(signalSavingStarted(const TQString&)), + this, TQ_SLOT(slotSavingStarted(const TQString&))); + + connect(m_canvas, TQ_SIGNAL(signalSavingFinished(const TQString&, bool)), + this, TQ_SLOT(slotSavingFinished(const TQString&, bool))); + + connect(m_canvas, TQ_SIGNAL(signalSavingProgress(const TQString&, float)), + this, TQ_SLOT(slotSavingProgress(const TQString&, float))); + + connect(m_canvas, TQ_SIGNAL(signalSelectionChanged(const TQRect&)), + this, TQ_SLOT(slotSelectionChanged(const TQRect&))); + + // -- if rotating/flipping set the rotatedflipped flag to true ----------- + + connect(d->rotateLeftAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + connect(d->rotateRightAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + connect(d->flipHorizAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + connect(d->flipVertAction, TQ_SIGNAL(activated()), + this, TQ_SLOT(slotRotatedOrFlipped())); + + // -- status bar connections -------------------------------------- + + connect(m_nameLabel, TQ_SIGNAL(signalCancelButtonPressed()), + this, TQ_SLOT(slotNameLabelCancelButtonPressed())); + + connect(m_nameLabel, TQ_SIGNAL(signalCancelButtonPressed()), + d->toolIface, TQ_SLOT(slotToolAborted())); +} + +void EditorWindow::setupStandardActions() +{ + // -- Standard 'File' menu actions --------------------------------------------- + + m_backwardAction = KStdAction::back(this, TQ_SLOT(slotBackward()), + actionCollection(), "editorwindow_backward"); + + m_forwardAction = KStdAction::forward(this, TQ_SLOT(slotForward()), + actionCollection(), "editorwindow_forward"); + + m_firstAction = new TDEAction(i18n("&First"), "go-first", + TDEStdAccel::shortcut( TDEStdAccel::Home), + this, TQ_SLOT(slotFirst()), + actionCollection(), "editorwindow_first"); + + m_lastAction = new TDEAction(i18n("&Last"), "go-last", + TDEStdAccel::shortcut( TDEStdAccel::End), + this, TQ_SLOT(slotLast()), + actionCollection(), "editorwindow_last"); + + m_saveAction = KStdAction::save(this, TQ_SLOT(slotSave()), + actionCollection(), "editorwindow_save"); + + m_saveAsAction = KStdAction::saveAs(this, TQ_SLOT(slotSaveAs()), + actionCollection(), "editorwindow_saveas"); + + m_revertAction = KStdAction::revert(this, TQ_SLOT(slotRevert()), + actionCollection(), "editorwindow_revert"); + + m_saveAction->setEnabled(false); + m_saveAsAction->setEnabled(false); + m_revertAction->setEnabled(false); + + d->filePrintAction = new TDEAction(i18n("Print Image..."), "document-print", + CTRL+Key_P, + this, TQ_SLOT(slotFilePrint()), + actionCollection(), "editorwindow_print"); + + m_fileDeleteAction = new TDEAction(i18n("Move to Trash"), "edittrash", + Key_Delete, + this, TQ_SLOT(slotDeleteCurrentItem()), + actionCollection(), "editorwindow_delete"); + + KStdAction::close(this, TQ_SLOT(close()), actionCollection(), "editorwindow_close"); + + // -- Standard 'Edit' menu actions --------------------------------------------- + + d->copyAction = KStdAction::copy(m_canvas, TQ_SLOT(slotCopy()), + actionCollection(), "editorwindow_copy"); + + d->copyAction->setEnabled(false); + + m_undoAction = new TDEToolBarPopupAction(i18n("Undo"), "edit-undo", + TDEStdAccel::shortcut(TDEStdAccel::Undo), + m_canvas, TQ_SLOT(slotUndo()), + actionCollection(), "editorwindow_undo"); + + connect(m_undoAction->popupMenu(), TQ_SIGNAL(aboutToShow()), + this, TQ_SLOT(slotAboutToShowUndoMenu())); + + connect(m_undoAction->popupMenu(), TQ_SIGNAL(activated(int)), + m_canvas, TQ_SLOT(slotUndo(int))); + + m_undoAction->setEnabled(false); + + m_redoAction = new TDEToolBarPopupAction(i18n("Redo"), "edit-redo", + TDEStdAccel::shortcut(TDEStdAccel::Redo), + m_canvas, TQ_SLOT(slotRedo()), + actionCollection(), "editorwindow_redo"); + + connect(m_redoAction->popupMenu(), TQ_SIGNAL(aboutToShow()), + this, TQ_SLOT(slotAboutToShowRedoMenu())); + + connect(m_redoAction->popupMenu(), TQ_SIGNAL(activated(int)), + m_canvas, TQ_SLOT(slotRedo(int))); + + m_redoAction->setEnabled(false); + + d->selectAllAction = new TDEAction(i18n("Select All"), + 0, + CTRL+Key_A, + m_canvas, + TQ_SLOT(slotSelectAll()), + actionCollection(), + "editorwindow_selectAll"); + + d->selectNoneAction = new TDEAction(i18n("Select None"), + 0, + CTRL+SHIFT+Key_A, + m_canvas, + TQ_SLOT(slotSelectNone()), + actionCollection(), + "editorwindow_selectNone"); + + // -- Standard 'View' menu actions --------------------------------------------- + + d->zoomPlusAction = KStdAction::zoomIn(this, TQ_SLOT(slotIncreaseZoom()), + actionCollection(), "editorwindow_zoomplus"); + + d->zoomMinusAction = KStdAction::zoomOut(this, TQ_SLOT(slotDecreaseZoom()), + actionCollection(), "editorwindow_zoomminus"); + + d->zoomTo100percents = new TDEAction(i18n("Zoom to 100%"), "zoom-original", + ALT+CTRL+Key_0, // NOTE: Photoshop 7 use ALT+CTRL+0. + this, TQ_SLOT(slotZoomTo100Percents()), + actionCollection(), "editorwindow_zoomto100percents"); + + + d->zoomFitToWindowAction = new TDEToggleAction(i18n("Fit to &Window"), "view_fit_window", + CTRL+SHIFT+Key_E, // NOTE: Gimp 2 use CTRL+SHIFT+E. + this, TQ_SLOT(slotToggleFitToWindow()), + actionCollection(), "editorwindow_zoomfit2window"); + + d->zoomFitToSelectAction = new TDEAction(i18n("Fit to &Selection"), "zoom-fit-best", + ALT+CTRL+Key_S, this, TQ_SLOT(slotFitToSelect()), + actionCollection(), "editorwindow_zoomfit2select"); + d->zoomFitToSelectAction->setEnabled(false); + d->zoomFitToSelectAction->setWhatsThis(i18n("This option can be used to zoom the image to the " + "current selection area.")); + + d->zoomCombo = new KComboBox(true); + d->zoomCombo->setDuplicatesEnabled(false); + d->zoomCombo->setFocusPolicy(TQWidget::ClickFocus); + d->zoomCombo->setInsertionPolicy(TQComboBox::NoInsertion); + d->zoomComboAction = new KWidgetAction(d->zoomCombo, i18n("Zoom"), 0, 0, 0, + actionCollection(), "editorwindow_zoomto"); + + d->zoomCombo->insertItem(TQString("10%")); + d->zoomCombo->insertItem(TQString("25%")); + d->zoomCombo->insertItem(TQString("50%")); + d->zoomCombo->insertItem(TQString("75%")); + d->zoomCombo->insertItem(TQString("100%")); + d->zoomCombo->insertItem(TQString("150%")); + d->zoomCombo->insertItem(TQString("200%")); + d->zoomCombo->insertItem(TQString("300%")); + d->zoomCombo->insertItem(TQString("450%")); + d->zoomCombo->insertItem(TQString("600%")); + d->zoomCombo->insertItem(TQString("800%")); + d->zoomCombo->insertItem(TQString("1200%")); + + connect(d->zoomCombo, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotZoomSelected()) ); + + connect(d->zoomCombo, TQ_SIGNAL(returnPressed(const TQString&)), + this, TQ_SLOT(slotZoomTextChanged(const TQString &)) ); + + // Do not use std KDE action for full screen because action text is too large for app. toolbar. + m_fullScreenAction = new TDEToggleAction(i18n("Full Screen"), "view-fullscreen", + CTRL+SHIFT+Key_F, this, + TQ_SLOT(slotToggleFullScreen()), + actionCollection(), "editorwindow_fullscreen"); + m_fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode")); + + d->slideShowAction = new TDEAction(i18n("Slideshow"), "slideshow", Key_F9, + this, TQ_SLOT(slotToggleSlideShow()), + actionCollection(),"editorwindow_slideshow"); + + d->viewUnderExpoAction = new TDEToggleAction(i18n("Under-Exposure Indicator"), "underexposure", + Key_F10, this, + TQ_SLOT(slotToggleUnderExposureIndicator()), + actionCollection(),"editorwindow_underexposure"); + + d->viewOverExpoAction = new TDEToggleAction(i18n("Over-Exposure Indicator"), "overexposure", + Key_F11, this, + TQ_SLOT(slotToggleOverExposureIndicator()), + actionCollection(),"editorwindow_overexposure"); + + d->viewCMViewAction = new TDEToggleAction(i18n("Color Managed View"), "tv", + Key_F12, this, + TQ_SLOT(slotToggleColorManagedView()), + actionCollection(),"editorwindow_cmview"); + + // -- Standard 'Transform' menu actions --------------------------------------------- + + d->resizeAction = new TDEAction(i18n("&Resize..."), "resize_image", 0, + this, TQ_SLOT(slotResize()), + actionCollection(), "editorwindow_resize"); + + d->cropAction = new TDEAction(i18n("Crop"), "crop", + CTRL+Key_X, + m_canvas, TQ_SLOT(slotCrop()), + actionCollection(), "editorwindow_crop"); + + d->cropAction->setEnabled(false); + d->cropAction->setWhatsThis(i18n("This option can be used to crop the image. " + "Select a region of the image to enable this action.")); + + // -- Standard 'Flip' menu actions --------------------------------------------- + + d->flipHorizAction = new TDEAction(i18n("Flip Horizontally"), "mirror", CTRL+Key_Asterisk, + m_canvas, TQ_SLOT(slotFlipHoriz()), + actionCollection(), "editorwindow_flip_horiz"); + d->flipHorizAction->setEnabled(false); + + d->flipVertAction = new TDEAction(i18n("Flip Vertically"), "flip", CTRL+Key_Slash, + m_canvas, TQ_SLOT(slotFlipVert()), + actionCollection(), "editorwindow_flip_vert"); + d->flipVertAction->setEnabled(false); + + // -- Standard 'Rotate' menu actions ---------------------------------------- + + d->rotateLeftAction = new TDEAction(i18n("Rotate Left"), + "object-rotate-left", SHIFT+CTRL+Key_Left, + m_canvas, TQ_SLOT(slotRotate270()), + actionCollection(), + "editorwindow_rotate_left"); + d->rotateLeftAction->setEnabled(false); + d->rotateRightAction = new TDEAction(i18n("Rotate Right"), + "object-rotate-right", SHIFT+CTRL+Key_Right, + m_canvas, TQ_SLOT(slotRotate90()), + actionCollection(), + "editorwindow_rotate_right"); + d->rotateRightAction->setEnabled(false); + + // -- Standard 'Configure' menu actions ---------------------------------------- + + d->showMenuBarAction = KStdAction::showMenubar(this, TQ_SLOT(slotShowMenuBar()), actionCollection()); + + KStdAction::keyBindings(this, TQ_SLOT(slotEditKeys()), actionCollection()); + KStdAction::configureToolbars(this, TQ_SLOT(slotConfToolbars()), actionCollection()); + KStdAction::preferences(this, TQ_SLOT(slotSetup()), actionCollection()); + + // ----------------------------------------------------------------------------------------- + + m_themeMenuAction = new TDESelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu"); + m_themeMenuAction->setItems(ThemeEngine::instance()->themeNames()); + + connect(m_themeMenuAction, TQ_SIGNAL(activated(const TQString&)), + this, TQ_SLOT(slotChangeTheme(const TQString&))); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + // -- Standard 'Help' menu actions --------------------------------------------- + + d->donateMoneyAction = new TDEAction(i18n("Donate..."), + 0, 0, + this, TQ_SLOT(slotDonateMoney()), + actionCollection(), + "editorwindow_donatemoney"); + + d->contributeAction = new TDEAction(i18n("Contribute..."), + 0, 0, + this, TQ_SLOT(slotContribute()), + actionCollection(), + "editorwindow_contribute"); + + d->rawCameraListAction = new TDEAction(i18n("Supported RAW Cameras"), + "kdcraw", + 0, + this, + TQ_SLOT(slotRawCameraList()), + actionCollection(), + "editorwindow_rawcameralist"); +} + +void EditorWindow::setupStandardAccelerators() +{ + d->accelerators = new TDEAccel(this); + + d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"), + i18n("Exit out of the fullscreen mode"), + Key_Escape, this, TQ_SLOT(slotEscapePressed()), + false, true); + + d->accelerators->insert("Next Image Key_Space", i18n("Next Image"), + i18n("Load Next Image"), + Key_Space, this, TQ_SLOT(slotForward()), + false, true); + + d->accelerators->insert("Previous Image SHIFT+Key_Space", i18n("Previous Image"), + i18n("Load Previous Image"), + SHIFT+Key_Space, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Previous Image Key_Backspace", i18n("Previous Image"), + i18n("Load Previous Image"), + Key_Backspace, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Next Image Key_Next", i18n("Next Image"), + i18n("Load Next Image"), + Key_Next, this, TQ_SLOT(slotForward()), + false, true); + + d->accelerators->insert("Previous Image Key_Prior", i18n("Previous Image"), + i18n("Load Previous Image"), + Key_Prior, this, TQ_SLOT(slotBackward()), + false, true); + + d->accelerators->insert("Zoom Plus Key_Plus", i18n("Zoom In"), + i18n("Zoom in on Image"), + Key_Plus, this, TQ_SLOT(slotIncreaseZoom()), + false, true); + + d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom Out"), + i18n("Zoom out of Image"), + Key_Minus, this, TQ_SLOT(slotDecreaseZoom()), + false, true); + + d->accelerators->insert("Redo CTRL+Key_Y", i18n("Redo"), + i18n("Redo Last action"), + CTRL+Key_Y, m_canvas, TQ_SLOT(slotRedo()), + false, true); +} + +void EditorWindow::setupStatusBar() +{ + m_nameLabel = new StatusProgressBar(statusBar()); + m_nameLabel->setAlignment(TQt::AlignCenter); + m_nameLabel->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(m_nameLabel, 100); + + d->selectLabel = new TQLabel(i18n("No selection"), statusBar()); + d->selectLabel->setAlignment(TQt::AlignCenter); + d->selectLabel->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(d->selectLabel, 100); + TQToolTip::add(d->selectLabel, i18n("Information about current selection area")); + + m_resLabel = new TQLabel(statusBar()); + m_resLabel->setAlignment(TQt::AlignCenter); + m_resLabel->setMaximumHeight(fontMetrics().height()+2); + statusBar()->addWidget(m_resLabel, 100); + TQToolTip::add(m_resLabel, i18n("Information about image size")); + + d->underExposureIndicator = new TQToolButton(statusBar()); + d->underExposureIndicator->setIconSet(SmallIcon("underexposure")); + d->underExposureIndicator->setToggleButton(true); + statusBar()->addWidget(d->underExposureIndicator, 1); + + d->overExposureIndicator = new TQToolButton(statusBar()); + d->overExposureIndicator->setIconSet(SmallIcon("overexposure")); + d->overExposureIndicator->setToggleButton(true); + statusBar()->addWidget(d->overExposureIndicator, 1); + + d->cmViewIndicator = new TQToolButton(statusBar()); + d->cmViewIndicator->setIconSet(SmallIcon("tv")); + d->cmViewIndicator->setToggleButton(true); + statusBar()->addWidget(d->cmViewIndicator, 1); + + connect(d->underExposureIndicator, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotToggleUnderExposureIndicator())); + + connect(d->overExposureIndicator, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotToggleOverExposureIndicator())); + + connect(d->cmViewIndicator, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotToggleColorManagedView())); +} + +void EditorWindow::printImage(KURL url) +{ + uchar* ptr = m_canvas->interface()->getImage(); + int w = m_canvas->interface()->origWidth(); + int h = m_canvas->interface()->origHeight(); + bool hasAlpha = m_canvas->interface()->hasAlpha(); + bool sixteenBit = m_canvas->interface()->sixteenBit(); + + if (!ptr || !w || !h) + return; + + DImg image(w, h, sixteenBit, hasAlpha, ptr); + + KPrinter printer; + TQString appName = TDEApplication::kApplication()->aboutData()->appName(); + printer.setDocName( url.filename() ); + printer.setCreator( appName ); +#if KDE_IS_VERSION(3,2,0) + printer.setUsePrinterResolution(true); +#endif + + KPrinter::addDialogPage( new ImageEditorPrintDialogPage(image, this, TQString(appName.append(" page")).ascii() )); + + if ( printer.setup( this, i18n("Print %1").arg(printer.docName().section('/', -1)) ) ) + { + ImagePrint printOperations(image, printer, url.filename()); + if (!printOperations.printImageWithTQt()) + { + KMessageBox::error(this, i18n("Failed to print file: '%1'") + .arg(url.filename())); + } + } +} + +void EditorWindow::slotEditKeys() +{ + KKeyDialog dialog(true, this); + dialog.insert( actionCollection(), i18n( "General" ) ); + + TQPtrList<ImagePlugin> pluginList = ImagePluginLoader::instance()->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + dialog.insert( plugin->actionCollection(), plugin->name() ); + } + } + + dialog.configure(); +} + +void EditorWindow::slotResize() +{ + ImageResize dlg(this); + dlg.exec(); +} + +void EditorWindow::slotAboutToShowUndoMenu() +{ + m_undoAction->popupMenu()->clear(); + TQStringList titles; + m_canvas->getUndoHistory(titles); + + if(!titles.isEmpty()) + { + int id = 1; + TQStringList::Iterator iter = titles.begin(); + for(; iter != titles.end(); ++iter,++id) + { + m_undoAction->popupMenu()->insertItem(*iter, id); + } + } +} + +void EditorWindow::slotAboutToShowRedoMenu() +{ + m_redoAction->popupMenu()->clear(); + TQStringList titles; + m_canvas->getRedoHistory(titles); + + if(!titles.isEmpty()) + { + int id = 1; + TQStringList::Iterator iter = titles.begin(); + for(; iter != titles.end(); ++iter,++id) + { + m_redoAction->popupMenu()->insertItem(*iter, id); + } + } +} + +void EditorWindow::slotConfToolbars() +{ + saveMainWindowSettings(TDEGlobal::config(), "ImageViewer Settings"); + KEditToolbar dlg(factory(), this); + + connect(&dlg, TQ_SIGNAL(newToolbarConfig()), + this, TQ_SLOT(slotNewToolbarConfig())); + + dlg.exec(); +} + +void EditorWindow::slotNewToolbarConfig() +{ + applyMainWindowSettings(TDEGlobal::config(), "ImageViewer Settings"); +} + +void EditorWindow::slotIncreaseZoom() +{ + m_stackView->increaseZoom(); +} + +void EditorWindow::slotDecreaseZoom() +{ + m_stackView->decreaseZoom(); +} + +void EditorWindow::slotToggleFitToWindow() +{ + d->zoomPlusAction->setEnabled(true); + d->zoomComboAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + m_stackView->toggleFitToWindow(); +} + +void EditorWindow::slotFitToSelect() +{ + d->zoomPlusAction->setEnabled(true); + d->zoomComboAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + m_stackView->fitToSelect(); +} + +void EditorWindow::slotZoomTo100Percents() +{ + d->zoomPlusAction->setEnabled(true); + d->zoomComboAction->setEnabled(true); + d->zoomMinusAction->setEnabled(true); + m_stackView->zoomTo100Percents(); +} + +void EditorWindow::slotZoomSelected() +{ + TQString txt = d->zoomCombo->currentText(); + txt = txt.left(txt.find('%')); + slotZoomTextChanged(txt); +} + +void EditorWindow::slotZoomTextChanged(const TQString &txt) +{ + bool r = false; + double zoom = TDEGlobal::locale()->readNumber(txt, &r) / 100.0; + if (r && zoom > 0.0) + m_stackView->setZoomFactor(zoom); +} + +void EditorWindow::slotZoomChanged(bool isMax, bool isMin, double zoom) +{ + d->zoomPlusAction->setEnabled(!isMax); + d->zoomMinusAction->setEnabled(!isMin); + + d->zoomCombo->blockSignals(true); + d->zoomCombo->setCurrentText(TQString::number(lround(zoom*100.0)) + TQString("%")); + d->zoomCombo->blockSignals(false); +} + +void EditorWindow::slotToggleOffFitToWindow() +{ + d->zoomFitToWindowAction->blockSignals(true); + d->zoomFitToWindowAction->setChecked(false); + d->zoomFitToWindowAction->blockSignals(false); +} + +void EditorWindow::slotEscapePressed() +{ + if (m_fullScreen) + m_fullScreenAction->activate(); +} + +void EditorWindow::plugActionAccel(TDEAction* action) +{ + if (!action) + return; + + d->accelerators->insert(action->text(), + action->text(), + action->whatsThis(), + action->shortcut(), + action, + TQ_SLOT(activate())); +} + +void EditorWindow::unplugActionAccel(TDEAction* action) +{ + d->accelerators->remove(action->text()); +} + +void EditorWindow::loadImagePlugins() +{ + TQPtrList<ImagePlugin> pluginList = m_imagePluginLoader->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + guiFactory()->addClient(plugin); + plugin->setEnabledSelectionActions(false); + } + else + DDebug() << "Invalid plugin to add!" << endl; + } +} + +void EditorWindow::unLoadImagePlugins() +{ + TQPtrList<ImagePlugin> pluginList = m_imagePluginLoader->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + guiFactory()->removeClient(plugin); + plugin->setEnabledSelectionActions(false); + } + } +} + +void EditorWindow::readStandardSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + + // Restore full screen Mode ? + + if (config->readBoolEntry("FullScreen", false)) + { + m_fullScreenAction->activate(); + m_fullScreen = true; + } + + // Restore Auto zoom action ? + bool autoZoom = config->readBoolEntry("AutoZoom", true); + if (autoZoom) + d->zoomFitToWindowAction->activate(); +} + +void EditorWindow::applyStandardSettings() +{ + TDEConfig* config = kapp->config(); + + // -- Settings for Color Management stuff ---------------------------------------------- + + config->setGroup("Color Management"); + + d->ICCSettings->enableCMSetting = config->readBoolEntry("EnableCM", false); + d->ICCSettings->askOrApplySetting = config->readBoolEntry("BehaviourICC", false); + d->ICCSettings->BPCSetting = config->readBoolEntry("BPCAlgorithm",false); + d->ICCSettings->managedViewSetting = config->readBoolEntry("ManagedView", false); + d->ICCSettings->renderingSetting = config->readNumEntry("RenderingIntent"); + d->ICCSettings->inputSetting = config->readPathEntry("InProfileFile", TQString()); + d->ICCSettings->workspaceSetting = config->readPathEntry("WorkProfileFile", TQString()); + d->ICCSettings->monitorSetting = config->readPathEntry("MonitorProfileFile", TQString()); + d->ICCSettings->proofSetting = config->readPathEntry("ProofProfileFile", TQString()); + + d->viewCMViewAction->setEnabled(d->ICCSettings->enableCMSetting); + d->viewCMViewAction->setChecked(d->ICCSettings->managedViewSetting); + d->cmViewIndicator->setEnabled(d->ICCSettings->enableCMSetting); + d->cmViewIndicator->setOn(d->ICCSettings->managedViewSetting); + setColorManagedViewIndicatorToolTip(d->ICCSettings->enableCMSetting, d->ICCSettings->managedViewSetting); + m_canvas->setICCSettings(d->ICCSettings); + + // -- JPEG, PNG, TIFF JPEG2000 files format settings -------------------------------------- + + config->setGroup("ImageViewer Settings"); + + // JPEG quality slider settings : 1 - 100 ==> libjpeg settings : 25 - 100. + m_IOFileSettings->JPEGCompression = (int)((75.0/100.0)* + (float)config->readNumEntry("JPEGCompression", 75) + + 26.0 - (75.0/100.0)); + + m_IOFileSettings->JPEGSubSampling = config->readNumEntry("JPEGSubSampling", 1); // Medium subsampling + + // PNG compression slider settings : 1 - 9 ==> libpng settings : 100 - 1. + m_IOFileSettings->PNGCompression = (int)(((1.0-100.0)/8.0)* + (float)config->readNumEntry("PNGCompression", 1) + + 100.0 - ((1.0-100.0)/8.0)); + + // TIFF compression setting. + m_IOFileSettings->TIFFCompression = config->readBoolEntry("TIFFCompression", false); + + // JPEG2000 quality slider settings : 1 - 100 + m_IOFileSettings->JPEG2000Compression = config->readNumEntry("JPEG2000Compression", 100); + + // JPEG2000 LossLess setting. + m_IOFileSettings->JPEG2000LossLess = config->readBoolEntry("JPEG2000LossLess", true); + + // -- RAW images decoding settings ------------------------------------------------------ + + // If digiKam Color Management is enable, no need to correct color of decoded RAW image, + // else, sRGB color workspace will be used. + + if (d->ICCSettings->enableCMSetting) + m_IOFileSettings->rawDecodingSettings.outputColorSpace = DRawDecoding::RAWCOLOR; + else + m_IOFileSettings->rawDecodingSettings.outputColorSpace = DRawDecoding::SRGB; + + m_IOFileSettings->rawDecodingSettings.sixteenBitsImage = config->readBoolEntry("SixteenBitsImage", false); + m_IOFileSettings->rawDecodingSettings.whiteBalance = (DRawDecoding::WhiteBalance)config->readNumEntry("WhiteBalance", + DRawDecoding::CAMERA); + m_IOFileSettings->rawDecodingSettings.customWhiteBalance = config->readNumEntry("CustomWhiteBalance", 6500); + m_IOFileSettings->rawDecodingSettings.customWhiteBalanceGreen = config->readDoubleNumEntry("CustomWhiteBalanceGreen", 1.0); + m_IOFileSettings->rawDecodingSettings.RGBInterpolate4Colors = config->readBoolEntry("RGBInterpolate4Colors", false); + m_IOFileSettings->rawDecodingSettings.DontStretchPixels = config->readBoolEntry("DontStretchPixels", false); + m_IOFileSettings->rawDecodingSettings.enableNoiseReduction = config->readBoolEntry("EnableNoiseReduction", false); + m_IOFileSettings->rawDecodingSettings.unclipColors = config->readNumEntry("UnclipColors", 0); + m_IOFileSettings->rawDecodingSettings.RAWQuality = (DRawDecoding::DecodingQuality)config->readNumEntry("RAWQuality", + DRawDecoding::BILINEAR); + m_IOFileSettings->rawDecodingSettings.NRThreshold = config->readNumEntry("NRThreshold", 100); + m_IOFileSettings->rawDecodingSettings.enableCACorrection = config->readBoolEntry("EnableCACorrection", false); + m_IOFileSettings->rawDecodingSettings.caMultiplier[0] = config->readDoubleNumEntry("caRedMultiplier", 1.0); + m_IOFileSettings->rawDecodingSettings.caMultiplier[1] = config->readDoubleNumEntry("caBlueMultiplier", 1.0); + m_IOFileSettings->rawDecodingSettings.brightness = config->readDoubleNumEntry("RAWBrightness", 1.0); + m_IOFileSettings->rawDecodingSettings.medianFilterPasses = config->readNumEntry("MedianFilterPasses", 0); + + m_IOFileSettings->useRAWImport = config->readBoolEntry("UseRawImportTool", false); + + // -- GUI Settings ------------------------------------------------------- + + TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); + if(config->hasKey("Splitter Sizes")) + m_splitter->setSizes(config->readIntListEntry("Splitter Sizes")); + else + m_canvas->setSizePolicy(rightSzPolicy); + + d->fullScreenHideToolBar = config->readBoolEntry("FullScreen Hide ToolBar", false); + + slotThemeChanged(); + + // -- Exposure Indicators Settings --------------------------------------- + + TQColor black(TQt::black); + TQColor white(TQt::white); + d->exposureSettings->underExposureIndicator = config->readBoolEntry("UnderExposureIndicator", false); + d->exposureSettings->overExposureIndicator = config->readBoolEntry("OverExposureIndicator", false); + d->exposureSettings->underExposureColor = config->readColorEntry("UnderExposureColor", &white); + d->exposureSettings->overExposureColor = config->readColorEntry("OverExposureColor", &black); + + d->viewUnderExpoAction->setChecked(d->exposureSettings->underExposureIndicator); + d->viewOverExpoAction->setChecked(d->exposureSettings->overExposureIndicator); + d->underExposureIndicator->setOn(d->exposureSettings->underExposureIndicator); + d->overExposureIndicator->setOn(d->exposureSettings->overExposureIndicator); + setUnderExposureToolTip(d->exposureSettings->underExposureIndicator); + setOverExposureToolTip(d->exposureSettings->overExposureIndicator); + m_canvas->setExposureSettings(d->exposureSettings); +} + +void EditorWindow::saveStandardSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + + config->writeEntry("AutoZoom", d->zoomFitToWindowAction->isChecked()); + config->writeEntry("Splitter Sizes", m_splitter->sizes()); + + config->writeEntry("FullScreen", m_fullScreenAction->isChecked()); + config->writeEntry("UnderExposureIndicator", d->exposureSettings->underExposureIndicator); + config->writeEntry("OverExposureIndicator", d->exposureSettings->overExposureIndicator); + + config->sync(); +} + +/** Method used by Editor Tools. Only Zoom+ and Zoom- are currently supported. + TODO: Fix this behavour when editor tool preview widgets will be factored. + */ +void EditorWindow::toggleZoomActions(bool val) +{ + d->zoomMinusAction->setEnabled(val); + d->zoomPlusAction->setEnabled(val); +} + +void EditorWindow::toggleStandardActions(bool val) +{ + d->zoomComboAction->setEnabled(val); + d->zoomTo100percents->setEnabled(val); + d->zoomFitToWindowAction->setEnabled(val); + d->zoomFitToSelectAction->setEnabled(val); + toggleZoomActions(val); + + d->rotateLeftAction->setEnabled(val); + d->rotateRightAction->setEnabled(val); + d->flipHorizAction->setEnabled(val); + d->flipVertAction->setEnabled(val); + d->filePrintAction->setEnabled(val); + d->resizeAction->setEnabled(val); + m_fileDeleteAction->setEnabled(val); + m_saveAsAction->setEnabled(val); + d->selectAllAction->setEnabled(val); + d->selectNoneAction->setEnabled(val); + d->slideShowAction->setEnabled(val); + + // these actions are special: They are turned off if val is false, + // but if val is true, they may be turned on or off. + if (val) + { + // Trigger sending of signalUndoStateChanged + // Note that for saving and loading, this is not necessary + // because the signal will be sent later anyway. + m_canvas->updateUndoState(); + } + else + { + m_saveAction->setEnabled(val); + m_undoAction->setEnabled(val); + m_redoAction->setEnabled(val); + } + + TQPtrList<ImagePlugin> pluginList = m_imagePluginLoader->pluginList(); + + for (ImagePlugin* plugin = pluginList.first(); + plugin; plugin = pluginList.next()) + { + if (plugin) + { + plugin->setEnabledActions(val); + } + } +} + +void EditorWindow::slotToggleFullScreen() +{ + if (m_fullScreen) // out of fullscreen + { + m_canvas->setBackgroundColor(m_bgColor); + + setWindowState( windowState() & ~WindowFullScreen ); + menuBar()->show(); + statusBar()->show(); + leftDock()->show(); + rightDock()->show(); + topDock()->show(); + bottomDock()->show(); + + TQObject* obj = child("ToolBar","TDEToolBar"); + + if (obj) + { + TDEToolBar* toolBar = static_cast<TDEToolBar*>(obj); + + if (m_fullScreenAction->isPlugged(toolBar) && d->removeFullScreenButton) + m_fullScreenAction->unplug(toolBar); + + if (toolBar->isHidden()) + showToolBars(); + } + + // -- remove the gui action accels ---- + + unplugActionAccel(m_forwardAction); + unplugActionAccel(m_backwardAction); + unplugActionAccel(m_firstAction); + unplugActionAccel(m_lastAction); + unplugActionAccel(m_saveAction); + unplugActionAccel(m_saveAsAction); + unplugActionAccel(d->zoomPlusAction); + unplugActionAccel(d->zoomMinusAction); + unplugActionAccel(d->zoomFitToWindowAction); + unplugActionAccel(d->zoomFitToSelectAction); + unplugActionAccel(d->cropAction); + unplugActionAccel(d->filePrintAction); + unplugActionAccel(m_fileDeleteAction); + unplugActionAccel(d->selectAllAction); + unplugActionAccel(d->selectNoneAction); + + toggleGUI2FullScreen(); + m_fullScreen = false; + } + else // go to fullscreen + { + m_canvas->setBackgroundColor(TQColor(TQt::black)); + + // hide the menubar and the statusbar + menuBar()->hide(); + statusBar()->hide(); + topDock()->hide(); + leftDock()->hide(); + rightDock()->hide(); + bottomDock()->hide(); + + TQObject* obj = child("ToolBar","TDEToolBar"); + + if (obj) + { + TDEToolBar* toolBar = static_cast<TDEToolBar*>(obj); + + if (d->fullScreenHideToolBar) + { + hideToolBars(); + } + else + { + showToolBars(); + + if ( !m_fullScreenAction->isPlugged(toolBar) ) + { + m_fullScreenAction->plug(toolBar); + d->removeFullScreenButton=true; + } + else + { + // If FullScreen button is enable in toolbar settings + // We don't remove it when we out of fullscreen mode. + d->removeFullScreenButton=false; + } + } + } + + // -- Insert all the gui actions into the accel -- + + plugActionAccel(m_forwardAction); + plugActionAccel(m_backwardAction); + plugActionAccel(m_firstAction); + plugActionAccel(m_lastAction); + plugActionAccel(m_saveAction); + plugActionAccel(m_saveAsAction); + plugActionAccel(d->zoomPlusAction); + plugActionAccel(d->zoomMinusAction); + plugActionAccel(d->zoomFitToWindowAction); + plugActionAccel(d->zoomFitToSelectAction); + plugActionAccel(d->cropAction); + plugActionAccel(d->filePrintAction); + plugActionAccel(m_fileDeleteAction); + plugActionAccel(d->selectAllAction); + plugActionAccel(d->selectNoneAction); + + toggleGUI2FullScreen(); + showFullScreen(); + m_fullScreen = true; + } +} + +void EditorWindow::slotRotatedOrFlipped() +{ + m_rotatedOrFlipped = true; +} + +void EditorWindow::slotLoadingProgress(const TQString&, float progress) +{ + m_nameLabel->setProgressValue((int)(progress*100.0)); +} + +void EditorWindow::slotSavingProgress(const TQString&, float progress) +{ + m_nameLabel->setProgressValue((int)(progress*100.0)); +} + +bool EditorWindow::promptForOverWrite() +{ + TQFileInfo fi(m_canvas->currentImageFilePath()); + TQString warnMsg(i18n("About to overwrite file \"%1\"\nAre you sure?") + .arg(fi.fileName())); + return (KMessageBox::warningContinueCancel(this, + warnMsg, + i18n("Warning"), + i18n("Overwrite"), + "editorWindowSaveOverwrite") + == KMessageBox::Continue); +} + +bool EditorWindow::promptUserSave(const KURL& url) +{ + if (m_saveAction->isEnabled()) + { + // if window is iconified, show it + if (isMinimized()) + { + KWin::deIconifyWindow(winId()); + } + + int result = KMessageBox::warningYesNoCancel(this, + i18n("The image '%1' has been modified.\n" + "Do you want to save it?") + .arg(url.filename()), + TQString(), + KStdGuiItem::save(), + KStdGuiItem::discard()); + + if (result == KMessageBox::Yes) + { + bool saving = false; + + if (m_canvas->isReadOnly()) + saving = saveAs(); + else if (promptForOverWrite()) + saving = save(); + + // save and saveAs return false if they were cancelled and did not enter saving at all + // In this case, do not call enter_loop because exit_loop will not be called. + if (saving) + { + // Waiting for asynchronous image file saving operation runing in separate thread. + m_savingContext->synchronizingState = SavingContextContainer::SynchronousSaving; + enter_loop(); + m_savingContext->synchronizingState = SavingContextContainer::NormalSaving; + return m_savingContext->synchronousSavingResult; + } + else + { + return false; + } + } + else if (result == KMessageBox::No) + { + m_saveAction->setEnabled(false); + return true; + } + else + { + return false; + } + } + + return true; +} + +bool EditorWindow::waitForSavingToComplete() +{ + // avoid reentrancy - return false means we have reentered the loop already. + if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving) + return false; + + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + { + // Waiting for asynchronous image file saving operation runing in separate thread. + m_savingContext->synchronizingState = SavingContextContainer::SynchronousSaving; + KMessageBox::queuedMessageBox(this, + KMessageBox::Information, + i18n("Please wait while the image is being saved...")); + enter_loop(); + m_savingContext->synchronizingState = SavingContextContainer::NormalSaving; + } + return true; +} + +void EditorWindow::enter_loop() +{ + TQWidget dummy(0, 0, WType_Dialog | WShowModal); + dummy.setFocusPolicy( TQWidget::NoFocus ); + tqt_enter_modal(&dummy); + tqApp->enter_loop(); + tqt_leave_modal(&dummy); +} + +void EditorWindow::slotSelected(bool val) +{ + // Update menu actions. + d->cropAction->setEnabled(val); + d->zoomFitToSelectAction->setEnabled(val); + d->copyAction->setEnabled(val); + + for (ImagePlugin* plugin = m_imagePluginLoader->pluginList().first(); + plugin; plugin = m_imagePluginLoader->pluginList().next()) + { + if (plugin) + { + plugin->setEnabledSelectionActions(val); + } + } + + TQRect sel = m_canvas->getSelectedArea(); + // Update histogram into sidebar. + emit signalSelectionChanged(sel); + + // Update status bar + if (val) + d->selectLabel->setText(TQString("(%1, %2) (%3 x %4)").arg(sel.x()).arg(sel.y()) + .arg(sel.width()).arg(sel.height())); + else + d->selectLabel->setText(i18n("No selection")); +} + +void EditorWindow::hideToolBars() +{ + TQPtrListIterator<TDEToolBar> it = toolBarIterator(); + TDEToolBar* bar; + + for(;it.current()!=0L; ++it) + { + bar = it.current(); + + if (bar->area()) + bar->area()->hide(); + else + bar->hide(); + } +} + +void EditorWindow::showToolBars() +{ + TQPtrListIterator<TDEToolBar> it = toolBarIterator(); + TDEToolBar* bar; + + for( ; it.current()!=0L ; ++it) + { + bar = it.current(); + + if (bar->area()) + bar->area()->show(); + else + bar->show(); + } +} + +void EditorWindow::slotPrepareToLoad() +{ + // Disable actions as appropriate during loading + emit signalNoCurrentItem(); + toggleActions(false); + slotUpdateItemInfo(); +} + +void EditorWindow::slotLoadingStarted(const TQString& /*filename*/) +{ + setCursor( KCursor::waitCursor() ); + + m_nameLabel->progressBarMode(StatusProgressBar::ProgressBarMode, i18n("Loading: ")); +} + +void EditorWindow::slotLoadingFinished(const TQString& filename, bool success) +{ + m_nameLabel->progressBarMode(StatusProgressBar::TextMode); + slotUpdateItemInfo(); + + // Enable actions as appropriate after loading + // No need to re-enable image properties sidebar here, it's will be done + // automatically by a signal from canvas + toggleActions(success); + unsetCursor(); + + // Note: in showfoto, we using a null filename to clear canvas. + if (!success && filename != TQString()) + { + TQFileInfo fi(filename); + TQString message = i18n("Failed to load image \"%1\"").arg(fi.fileName()); + KMessageBox::error(this, message); + DWarning() << "Failed to load image " << fi.fileName() << endl; + } +} + +void EditorWindow::slotNameLabelCancelButtonPressed() +{ + // If we saving an image... + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + { + m_savingContext->abortingSaving = true; + m_canvas->abortSaving(); + } + + // If we preparing SlideShow... + m_cancelSlideShow = true; +} + +void EditorWindow::slotSave() +{ + if (m_canvas->isReadOnly()) + saveAs(); + else if (promptForOverWrite()) + save(); +} + +void EditorWindow::slotSavingStarted(const TQString& /*filename*/) +{ + setCursor( KCursor::waitCursor() ); + + // Disable actions as appropriate during saving + emit signalNoCurrentItem(); + toggleActions(false); + + m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, i18n("Saving: ")); +} + +void EditorWindow::slotSavingFinished(const TQString& filename, bool success) +{ + if (m_savingContext->savingState == SavingContextContainer::SavingStateSave) + { + // from save() + m_savingContext->savingState = SavingContextContainer::SavingStateNone; + + if (!success) + { + if (!m_savingContext->abortingSaving) + { + KMessageBox::error(this, i18n("Failed to save file\n\"%1\"\nto\n\"%2\".") + .arg(m_savingContext->destinationURL.filename()) + .arg(m_savingContext->destinationURL.path())); + } + finishSaving(false); + return; + } + + DDebug() << "renaming to " << m_savingContext->destinationURL.path() << endl; + + if (!moveFile()) + { + finishSaving(false); + return; + } + + m_canvas->setUndoHistoryOrigin(); + + // remove image from cache since it has changed + LoadingCacheInterface::cleanFromCache(m_savingContext->destinationURL.path()); + // this won't be in the cache, but does not hurt to do it anyway + LoadingCacheInterface::cleanFromCache(filename); + + // restore state of disabled actions. saveIsComplete can start any other task + // (loading!) which might itself in turn change states + finishSaving(true); + + saveIsComplete(); + + // Take all actions necessary to update information and re-enable sidebar + slotChanged(); + } + else if (m_savingContext->savingState == SavingContextContainer::SavingStateSaveAs) + { + m_savingContext->savingState = SavingContextContainer::SavingStateNone; + + // from saveAs() + if (!success) + { + if (!m_savingContext->abortingSaving) + { + KMessageBox::error(this, i18n("Failed to save file\n\"%1\"\nto\n\"%2\".") + .arg(m_savingContext->destinationURL.filename()) + .arg(m_savingContext->destinationURL.path())); + } + finishSaving(false); + return; + } + + // Only try to write exif if both src and destination are jpeg files + + DDebug() << "renaming to " << m_savingContext->destinationURL.path() << endl; + + if (!moveFile()) + { + finishSaving(false); + return; + } + + m_canvas->setUndoHistoryOrigin(); + + LoadingCacheInterface::cleanFromCache(m_savingContext->destinationURL.path()); + LoadingCacheInterface::cleanFromCache(filename); + + finishSaving(true); + saveAsIsComplete(); + + // Take all actions necessary to update information and re-enable sidebar + slotChanged(); + } +} + +void EditorWindow::finishSaving(bool success) +{ + m_savingContext->synchronousSavingResult = success; + + if (m_savingContext->saveTempFile) + { + delete m_savingContext->saveTempFile; + m_savingContext->saveTempFile = 0; + } + + // Exit of internal TQt event loop to unlock promptUserSave() method. + if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving) + tqApp->exit_loop(); + + // Enable actions as appropriate after saving + toggleActions(true); + unsetCursor(); + + m_nameLabel->progressBarMode(StatusProgressBar::TextMode); + + // On error, continue using current image + if (!success) + { + m_canvas->switchToLastSaved(m_savingContext->srcURL.path()); + } +} + +void EditorWindow::startingSave(const KURL& url) +{ + // avoid any reentrancy. Should be impossible anyway since actions will be disabled. + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + return; + + if (!checkPermissions(url)) + return; + + m_savingContext->srcURL = url; + m_savingContext->destinationURL = m_savingContext->srcURL; + m_savingContext->destinationExisted = true; + m_savingContext->originalFormat = m_canvas->currentImageFileFormat(); + m_savingContext->format = m_savingContext->originalFormat; + m_savingContext->abortingSaving = false; + m_savingContext->savingState = SavingContextContainer::SavingStateSave; + // use magic file extension which tells the digikamalbums ioslave to ignore the file + m_savingContext->saveTempFile = new KTempFile(m_savingContext->srcURL.directory(false), + ".digikamtempfile.tmp"); + m_savingContext->saveTempFile->setAutoDelete(true); + + m_canvas->saveAs(m_savingContext->saveTempFile->name(), m_IOFileSettings, + m_setExifOrientationTag && (m_rotatedOrFlipped || m_canvas->exifRotated())); +} + +bool EditorWindow::startingSaveAs(const KURL& url) +{ + if (m_savingContext->savingState != SavingContextContainer::SavingStateNone) + return false; + + TQString mimetypes = KImageIO::mimeTypes(KImageIO::Writing).join(" "); + mimetypes.append(" image/tiff"); + DDebug () << "mimetypes=" << mimetypes << endl; + + m_savingContext->srcURL = url; + + FileSaveOptionsBox *options = new FileSaveOptionsBox(); + KFileDialog imageFileSaveDialog(m_savingContext->srcURL.isLocalFile() ? + m_savingContext->srcURL.directory() : TQDir::homeDirPath(), + TQString(), + this, + "imageFileSaveDialog", + false, + options); + + connect(&imageFileSaveDialog, TQ_SIGNAL(filterChanged(const TQString &)), + options, TQ_SLOT(slotImageFileFormatChanged(const TQString &))); + + connect(&imageFileSaveDialog, TQ_SIGNAL(fileSelected(const TQString &)), + options, TQ_SLOT(slotImageFileSelected(const TQString &))); + + ImageDialogPreview *preview = new ImageDialogPreview(&imageFileSaveDialog); + imageFileSaveDialog.setPreviewWidget(preview); + imageFileSaveDialog.setOperationMode(KFileDialog::Saving); + imageFileSaveDialog.setMode(KFile::File); + imageFileSaveDialog.setCaption(i18n("New Image File Name")); + imageFileSaveDialog.setFilter(mimetypes); + + TQFileInfo info(m_savingContext->srcURL.fileName()); + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + TQString ext = config->readEntry("LastSavedImageTypeMime", "png"); + TQString fileName = info.baseName(false) + TQString(".") + ext; + imageFileSaveDialog.setSelection(fileName); + + // Start dialog and check if canceled. + if ( imageFileSaveDialog.exec() != KFileDialog::Accepted ) + return false; + + // Update file save settings in editor instance. + options->applySettings(); + applyStandardSettings(); + + KURL newURL = imageFileSaveDialog.selectedURL(); + + // Check if target image format have been selected from Combo List of SaveAs dialog. + m_savingContext->format = KImageIO::typeForMime(imageFileSaveDialog.currentMimeFilter()); + + if ( m_savingContext->format.isEmpty() ) + { + // Else, check if target image format have been add to target image file name using extension. + + TQFileInfo fi(newURL.path()); + m_savingContext->format = fi.extension(false); + + if ( m_savingContext->format.isEmpty() ) + { + // If format is empty then file format is same as that of the original file. + m_savingContext->format = TQImageIO::imageFormat(m_savingContext->srcURL.path()); + } + else + { + // Else, check if format from file name extension is include on file mime type list. + + TQString imgExtPattern; + TQStringList imgExtList = TQStringList::split(" ", mimetypes); + for (TQStringList::ConstIterator it = imgExtList.begin() ; it != imgExtList.end() ; ++it) + { + imgExtPattern.append (KImageIO::typeForMime(*it).upper()); + imgExtPattern.append (" "); + } + imgExtPattern.append (" TIF TIFF"); + if ( imgExtPattern.contains("JPEG") ) + { + imgExtPattern.append (" JPG"); + imgExtPattern.append (" JPE"); + } + + if ( !imgExtPattern.contains( m_savingContext->format.upper() ) ) + { + KMessageBox::error(this, i18n("Target image file format \"%1\" unsupported.") + .arg(m_savingContext->format)); + DWarning() << k_funcinfo << "target image file format " << m_savingContext->format << " unsupported!" << endl; + return false; + } + } + } + + if (!newURL.isValid()) + { + KMessageBox::error(this, i18n("Failed to save file\n\"%1\" to\n\"%2\".") + .arg(newURL.filename()) + .arg(newURL.path().section('/', -2, -2))); + DWarning() << k_funcinfo << "target URL is not valid !" << endl; + return false; + } + + config->writeEntry("LastSavedImageTypeMime", m_savingContext->format); + config->sync(); + + // if new and original url are equal use slotSave() ------------------------------ + + KURL currURL(m_savingContext->srcURL); + currURL.cleanPath(); + newURL.cleanPath(); + + if (currURL.equals(newURL)) + { + slotSave(); + return false; + } + + // Check for overwrite ---------------------------------------------------------- + + TQFileInfo fi(newURL.path()); + m_savingContext->destinationExisted = fi.exists(); + if ( m_savingContext->destinationExisted ) + { + int result = + + KMessageBox::warningYesNo( this, i18n("A file named \"%1\" already " + "exists. Are you sure you want " + "to overwrite it?") + .arg(newURL.filename()), + i18n("Overwrite File?"), + i18n("Overwrite"), + KStdGuiItem::cancel() ); + + if (result != KMessageBox::Yes) + return false; + + // There will be two message boxes if the file is not writable. + // This may be controversial, and it may be changed, but it was a deliberate decision. + if (!checkPermissions(newURL)) + return false; + } + + // Now do the actual saving ----------------------------------------------------- + + // use magic file extension which tells the digikamalbums ioslave to ignore the file + m_savingContext->saveTempFile = new KTempFile(newURL.directory(false), ".digikamtempfile.tmp"); + m_savingContext->destinationURL = newURL; + m_savingContext->originalFormat = m_canvas->currentImageFileFormat(); + m_savingContext->savingState = SavingContextContainer::SavingStateSaveAs; + m_savingContext->saveTempFile->setAutoDelete(true); + m_savingContext->abortingSaving = false; + + m_canvas->saveAs(m_savingContext->saveTempFile->name(), m_IOFileSettings, + m_setExifOrientationTag && (m_rotatedOrFlipped || m_canvas->exifRotated()), + m_savingContext->format.lower()); + + return true; +} + +bool EditorWindow::checkPermissions(const KURL& url) +{ + //TODO: Check that the permissions can actually be changed + // if write permissions are not available. + + TQFileInfo fi(url.path()); + + if (fi.exists() && !fi.isWritable()) + { + int result = + + KMessageBox::warningYesNo( this, i18n("You do not have write permissions " + "for the file named \"%1\". " + "Are you sure you want " + "to overwrite it?") + .arg(url.filename()), + i18n("Overwrite File?"), + i18n("Overwrite"), + KStdGuiItem::cancel() ); + + if (result != KMessageBox::Yes) + return false; + } + + return true; +} + +bool EditorWindow::moveFile() +{ + TQCString dstFileName = TQFile::encodeName(m_savingContext->destinationURL.path()); + + // Store old permissions: + // Just get the current umask. + mode_t curr_umask = umask(S_IREAD | S_IWRITE); + // Restore the umask. + umask(curr_umask); + + // For new files respect the umask setting. + mode_t filePermissions = (S_IREAD | S_IWRITE | S_IROTH | S_IWOTH | S_IRGRP | S_IWGRP) & ~curr_umask; + + // For existing files, use the mode of the original file. + if (m_savingContext->destinationExisted) + { + struct stat stbuf; + if (::stat(dstFileName, &stbuf) == 0) + { + filePermissions = stbuf.st_mode; + } + } + + // rename tmp file to dest + if (::rename(TQFile::encodeName(m_savingContext->saveTempFile->name()), dstFileName) != 0) + { + KMessageBox::error(this, i18n("Failed to overwrite original file"), + i18n("Error Saving File")); + return false; + } + + // restore permissions + if (::chmod(dstFileName, filePermissions) != 0) + { + DWarning() << "Failed to restore file permissions for file " << dstFileName << endl; + } + + return true; +} + +void EditorWindow::slotToggleColorManagedView() +{ + d->cmViewIndicator->blockSignals(true); + d->viewCMViewAction->blockSignals(true); + bool cmv = false; + if (d->ICCSettings->enableCMSetting) + { + cmv = !d->ICCSettings->managedViewSetting; + d->ICCSettings->managedViewSetting = cmv; + m_canvas->setICCSettings(d->ICCSettings); + + // Save Color Managed View setting in config file. For performance + // reason, no need to flush file, it cached in memory and will be flushed + // to disk at end of session. + TDEConfig* config = kapp->config(); + config->setGroup("Color Management"); + config->writeEntry("ManagedView", cmv); + } + + d->cmViewIndicator->setOn(cmv); + d->viewCMViewAction->setChecked(cmv); + setColorManagedViewIndicatorToolTip(d->ICCSettings->enableCMSetting, cmv); + d->cmViewIndicator->blockSignals(false); + d->viewCMViewAction->blockSignals(false); +} + +void EditorWindow::setColorManagedViewIndicatorToolTip(bool available, bool cmv) +{ + TQToolTip::remove(d->cmViewIndicator); + TQString tooltip; + if (available) + { + if (cmv) + tooltip = i18n("Color Managed View is enabled"); + else + tooltip = i18n("Color Managed View is disabled"); + } + else + { + tooltip = i18n("Color Management is not configured, so the Color Managed View is not available"); + } + TQToolTip::add(d->cmViewIndicator, tooltip); +} + +void EditorWindow::slotToggleUnderExposureIndicator() +{ + d->underExposureIndicator->blockSignals(true); + d->viewUnderExpoAction->blockSignals(true); + bool uei = !d->exposureSettings->underExposureIndicator; + d->underExposureIndicator->setOn(uei); + d->viewUnderExpoAction->setChecked(uei); + d->exposureSettings->underExposureIndicator = uei; + m_canvas->setExposureSettings(d->exposureSettings); + setUnderExposureToolTip(uei); + d->underExposureIndicator->blockSignals(false); + d->viewUnderExpoAction->blockSignals(false); +} + +void EditorWindow::setUnderExposureToolTip(bool uei) +{ + TQToolTip::remove(d->underExposureIndicator); + TQToolTip::add(d->underExposureIndicator, + uei ? i18n("Under-Exposure indicator is enabled") + : i18n("Under-Exposure indicator is disabled")); +} + +void EditorWindow::slotToggleOverExposureIndicator() +{ + d->overExposureIndicator->blockSignals(true); + d->viewOverExpoAction->blockSignals(true); + bool oei = !d->exposureSettings->overExposureIndicator; + d->overExposureIndicator->setOn(oei); + d->viewOverExpoAction->setChecked(oei); + d->exposureSettings->overExposureIndicator = oei; + m_canvas->setExposureSettings(d->exposureSettings); + setOverExposureToolTip(oei); + d->overExposureIndicator->blockSignals(false); + d->viewOverExpoAction->blockSignals(false); +} + +void EditorWindow::setOverExposureToolTip(bool oei) +{ + TQToolTip::remove(d->overExposureIndicator); + TQToolTip::add(d->overExposureIndicator, + oei ? i18n("Over-Exposure indicator is enabled") + : i18n("Over-Exposure indicator is disabled")); +} + +void EditorWindow::slotDonateMoney() +{ + TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation"); +} + +void EditorWindow::slotContribute() +{ + TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=contrib"); +} + +void EditorWindow::slotToggleSlideShow() +{ + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + bool startWithCurrent = config->readBoolEntry("SlideShowStartCurrent", false); + + SlideShowSettings settings; + settings.delay = config->readNumEntry("SlideShowDelay", 5) * 1000; + settings.printName = config->readBoolEntry("SlideShowPrintName", true); + settings.printDate = config->readBoolEntry("SlideShowPrintDate", false); + settings.printApertureFocal = config->readBoolEntry("SlideShowPrintApertureFocal", false); + settings.printExpoSensitivity = config->readBoolEntry("SlideShowPrintExpoSensitivity", false); + settings.printMakeModel = config->readBoolEntry("SlideShowPrintMakeModel", false); + settings.printComment = config->readBoolEntry("SlideShowPrintComment", false); + settings.loop = config->readBoolEntry("SlideShowLoop", false); + slideShow(startWithCurrent, settings); +} + +void EditorWindow::slotSelectionChanged(const TQRect& sel) +{ + d->selectLabel->setText(TQString("(%1, %2) (%3 x %4)").arg(sel.x()).arg(sel.y()) + .arg(sel.width()).arg(sel.height())); +} + +void EditorWindow::slotRawCameraList() +{ + RawCameraDlg dlg(this); + dlg.exec(); +} + +void EditorWindow::slotThemeChanged() +{ + TQStringList themes(ThemeEngine::instance()->themeNames()); + int index = themes.findIndex(ThemeEngine::instance()->getCurrentThemeName()); + if (index == -1) + index = themes.findIndex(i18n("Default")); + + m_themeMenuAction->setCurrentItem(index); + + TDEConfig* config = kapp->config(); + config->setGroup("ImageViewer Settings"); + + if (!config->readBoolEntry("UseThemeBackgroundColor", true)) + m_bgColor = config->readColorEntry("BackgroundColor", &TQt::black); + else + m_bgColor = ThemeEngine::instance()->baseColor(); + + m_canvas->setBackgroundColor(m_bgColor); +} + +void EditorWindow::slotChangeTheme(const TQString& theme) +{ + ThemeEngine::instance()->slotChangeTheme(theme); +} + +void EditorWindow::setToolStartProgress(const TQString& toolName) +{ + m_nameLabel->setProgressValue(0); + m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, TQString("%1: ").arg(toolName)); +} + +void EditorWindow::setToolProgress(int progress) +{ + m_nameLabel->setProgressValue(progress); +} + +void EditorWindow::setToolStopProgress() +{ + m_nameLabel->setProgressValue(0); + m_nameLabel->progressBarMode(StatusProgressBar::TextMode); + slotUpdateItemInfo(); +} + + +void EditorWindow::slotShowMenuBar() +{ + if (menuBar()->isVisible()) + menuBar()->hide(); + else + menuBar()->show(); +} + +} // namespace Digikam 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef EDITORWINDOW_H +#define EDITORWINDOW_H + +// TQt includes. + +#include <tqcolor.h> +#include <tqstring.h> +#include <tqrect.h> + +// KDE includes. + +#include <tdemainwindow.h> +#include <kurl.h> + +// 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 <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#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 <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqwidget.h> +#include <tqsize.h> +#include <tqpixmap.h> +#include <tqbitmap.h> +#include <tqpainter.h> + +// 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<TQPaintDevice*>(&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<TQPaintDevice*>(&pixMask), 0, 0, w, h, TQt::CopyROP, false); + } + } + + bitBlt(device, x, y, static_cast<TQPaintDevice*>(&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 <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEIFACE_H +#define IMAGEIFACE_H + +// TQt includes. + +#include <tqglobal.h> +#include <tqstring.h> + +// KDE includes. + +#include <tdelocale.h> + +// 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 <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include <cstdio> + +// TQt includes. + +#include <tqcursor.h> +#include <tqtimer.h> +#include <tqlabel.h> +#include <tqimage.h> +#include <tqsplitter.h> +#include <tqpainter.h> +#include <tqpixmap.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeconfig.h> +#include <kstandarddirs.h> +#include <tdeapplication.h> +#include <tdemessagebox.h> +#include <tdetempfile.h> +#include <kimageio.h> +#include <tdefiledialog.h> +#include <tdeversion.h> +#include <tdemenubar.h> +#include <tdetoolbar.h> +#include <tdeaccel.h> +#include <tdeaction.h> +#include <tdestdaccel.h> +#include <kstdaction.h> +#include <kstdguiitem.h> +#include <kstatusbar.h> +#include <kprogress.h> +#include <twin.h> + +// 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<Sidebar*>(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<TQ_LLONG> 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<int> albumIDs; + TQValueList<int> 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<int> albumIDs; + TQValueList<int> imageIDs; + KURL::List urls; + KURL::List kioURLs; + + if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs)) + { + ImageInfoList imageInfoList; + + for (TQValueList<int>::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<TQ_LLONG> itemIDs = man->albumDB()->getItemIDsInAlbum(albumID); + ImageInfoList imageInfoList; + + for (TQValueList<TQ_LLONG>::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<TQ_LLONG> itemIDs = man->albumDB()->getItemIDsInTag(tagID, true); + ImageInfoList imageInfoList; + + for (TQValueList<TQ_LLONG>::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 <renchi@pooh.tam.uiuc.edu> + * Copyright (C) 2004-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEWINDOW_H +#define IMAGEWINDOW_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kurl.h> + +// 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 <caulier dot gilles at gmail dot com> + * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel.wiesweg@gmx.de> + * + * 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 <tqstring.h> + +// KDE includes. + +#include <kurl.h> +#include <tdetempfile.h> + +// 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 */ diff --git a/src/utilities/imageeditor/rawimport/Makefile.am b/src/utilities/imageeditor/rawimport/Makefile.am new file mode 100644 index 00000000..19071935 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/Makefile.am @@ -0,0 +1,27 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = librawimport.la + +librawimport_la_SOURCES = rawpreview.cpp rawsettingsbox.cpp rawimport.cpp \ + rawpostprocessing.cpp + +librawimport_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TDEPRINT) + +INCLUDES= -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/threadimageio \ + -I$(top_srcdir)/src/libs/themeengine \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + diff --git a/src/utilities/imageeditor/rawimport/rawimport.cpp b/src/utilities/imageeditor/rawimport/rawimport.cpp new file mode 100644 index 00000000..a9254ce8 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawimport.cpp @@ -0,0 +1,223 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : Raw import tool + * + * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqstring.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <kcursor.h> +#include <tdelocale.h> +#include <tdeconfig.h> +#include <tdeapplication.h> +#include <kiconloader.h> +#include <kstandarddirs.h> + +// Local includes. + +#include "ddebug.h" +#include "drawdecoding.h" +#include "histogramwidget.h" +#include "curveswidget.h" +#include "imagehistogram.h" +#include "rawsettingsbox.h" +#include "rawpostprocessing.h" +#include "editortooliface.h" +#include "rawpreview.h" +#include "rawimport.h" +#include "rawimport.moc" + +namespace Digikam +{ + +class RawImportPriv +{ +public: + + RawImportPriv() + { + previewWidget = 0; + settingsBox = 0; + } + + RawSettingsBox *settingsBox; + + RawPreview *previewWidget; +}; + +RawImport::RawImport(const KURL& url, TQObject *parent) + : EditorToolThreaded(parent) +{ + d = new RawImportPriv; + d->previewWidget = new RawPreview(url, 0); + d->settingsBox = new RawSettingsBox(url, 0); + + setToolName(i18n("Raw Import")); + setToolIcon(SmallIcon("kdcraw")); + setProgressMessage(i18n("Post Processing")); + setToolView(d->previewWidget); + setToolSettings(d->settingsBox); + + init(); +} + +RawImport::~RawImport() +{ + delete d; +} + +void RawImport::slotInit() +{ + EditorToolThreaded::slotInit(); + + // --------------------------------------------------------------- + + connect(d->previewWidget, TQ_SIGNAL(signalLoadingStarted()), + this, TQ_SLOT(slotLoadingStarted())); + + connect(d->previewWidget, TQ_SIGNAL(signalDemosaicedImage()), + this, TQ_SLOT(slotDemosaicedImage())); + + connect(d->previewWidget, TQ_SIGNAL(signalLoadingStarted()), + this, TQ_SLOT(slotLoadingStarted())); + + connect(d->previewWidget, TQ_SIGNAL(signalLoadingProgress(float)), + this, TQ_SLOT(slotLoadingProgress(float))); + + connect(d->previewWidget, TQ_SIGNAL(signalLoadingFailed()), + this, TQ_SLOT(slotLoadingFailed())); + + connect(d->settingsBox, TQ_SIGNAL(signalDemosaicingChanged()), + this, TQ_SLOT(slotDemosaicingChanged())); + + connect(d->settingsBox, TQ_SIGNAL(signalPostProcessingChanged()), + this, TQ_SLOT(slotTimer())); + + connect(d->settingsBox, TQ_SIGNAL(signalUpdatePreview()), + this, TQ_SLOT(slotUpdatePreview())); + + connect(d->settingsBox, TQ_SIGNAL(signalAbortPreview()), + this, TQ_SLOT(slotAbort())); + + // --------------------------------------------------------------- + + setBusy(true); + slotUpdatePreview(); +} + +void RawImport::setBusy(bool val) +{ + if (val) d->previewWidget->setCursor(KCursor::waitCursor()); + else d->previewWidget->unsetCursor(); + d->settingsBox->setBusy(val); +} + +DRawDecoding RawImport::rawDecodingSettings() +{ + return d->settingsBox->settings(); +} + +void RawImport::slotUpdatePreview() +{ + DRawDecoding settings = rawDecodingSettings(); + // We will load an half size image to speed up preview computing. + settings.halfSizeColorImage = true; + + d->previewWidget->setDecodingSettings(settings); +} + +void RawImport::slotAbort() +{ + // If preview loading, don't play with threaded filter interface. + if (renderingMode() == EditorToolThreaded::NoneRendering) + { + d->previewWidget->cancelLoading(); + d->settingsBox->histogram()->stopHistogramComputation(); + EditorToolIface::editorToolIface()->setToolStopProgress(); + setBusy(false); + return; + } + + EditorToolThreaded::slotAbort(); +} + +void RawImport::slotLoadingStarted() +{ + d->settingsBox->enableUpdateBtn(false); + d->settingsBox->histogram()->setDataLoading(); + d->settingsBox->curve()->setDataLoading(); + EditorToolIface::editorToolIface()->setToolStartProgress(i18n("Raw Decoding")); + setBusy(true); +} + +void RawImport::slotDemosaicedImage() +{ + d->settingsBox->setDemosaicedImage(d->previewWidget->demosaicedImage()); + slotEffect(); +} + +void RawImport::prepareEffect() +{ + DImg postImg = d->previewWidget->demosaicedImage(); + setFilter(dynamic_cast<DImgThreadedFilter*>(new RawPostProcessing(&postImg, this, rawDecodingSettings()))); +} + +void RawImport::putPreviewData() +{ + d->previewWidget->setPostProcessedImage(filter()->getTargetImage()); + d->settingsBox->setPostProcessedImage(d->previewWidget->postProcessedImage()); + EditorToolIface::editorToolIface()->setToolStopProgress(); + setBusy(false); +} + +void RawImport::slotLoadingFailed() +{ + d->settingsBox->histogram()->setLoadingFailed(); + EditorToolIface::editorToolIface()->setToolStopProgress(); + setBusy(false); +} + +void RawImport::slotDemosaicingChanged() +{ + d->settingsBox->enableUpdateBtn(true); +} + +void RawImport::slotLoadingProgress(float v) +{ + EditorToolIface::editorToolIface()->setToolProgress((int)(v*100)); +} + +void RawImport::slotOk() +{ + EditorTool::slotOk(); +} + +void RawImport::slotCancel() +{ + EditorTool::slotCancel(); +} + +} // NameSpace Digikam diff --git a/src/utilities/imageeditor/rawimport/rawimport.h b/src/utilities/imageeditor/rawimport/rawimport.h new file mode 100644 index 00000000..85255bc8 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawimport.h @@ -0,0 +1,88 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-20 + * Description : Raw import tool + * + * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef RAWIMPORTDLG_H +#define RAWIMPORTDLG_H + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "editortool.h" +#include "dimg.h" +#include "digikam_export.h" + +namespace KDcrawIface +{ +class RawDecodingSettings; +} + +namespace Digikam +{ + +class RawImportPriv; + +class DIGIKAM_EXPORT RawImport : public EditorToolThreaded +{ + TQ_OBJECT + + +public: + + RawImport(const KURL& url, TQObject *parent); + ~RawImport(); + + DRawDecoding rawDecodingSettings(); + +private: + + void setBusy(bool busy); + void prepareEffect(); + void putPreviewData(); + +private slots: + + void slotInit(); + + void slotLoadingStarted(); + void slotDemosaicedImage(); + void slotLoadingFailed(); + void slotLoadingProgress(float); + + void slotUpdatePreview(); + void slotAbort(); + + void slotDemosaicingChanged(); + + void slotOk(); + void slotCancel(); + +private: + + RawImportPriv *d; +}; + +} // NameSpace Digikam + +#endif // RAWIMPORTDLG_H diff --git a/src/utilities/imageeditor/rawimport/rawpostprocessing.cpp b/src/utilities/imageeditor/rawimport/rawpostprocessing.cpp new file mode 100644 index 00000000..d45dd5e4 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawpostprocessing.cpp @@ -0,0 +1,137 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-13-08 + * Description : Raw post processing corrections. + * + * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// Local includes. + +#include "ddebug.h" +#include "imagehistogram.h" +#include "imagecurves.h" +#include "imagelevels.h" +#include "bcgmodifier.h" +#include "whitebalance.h" +#include "dimgimagefilters.h" +#include "rawpostprocessing.h" + +namespace Digikam +{ + +RawPostProcessing::RawPostProcessing(DImg *orgImage, TQObject *parent, const DRawDecoding& settings) + : DImgThreadedFilter(orgImage, parent, "RawPostProcessing") +{ + m_customRawSettings = settings; + initFilter(); +} + +RawPostProcessing::RawPostProcessing(DImgThreadedFilter *parentFilter, + const DImg &orgImage, const DImg &destImage, + int progressBegin, int progressEnd, const DRawDecoding& settings) + : DImgThreadedFilter(parentFilter, orgImage, destImage, progressBegin, progressEnd, + parentFilter->filterName() + ": RawPostProcessing") +{ + m_customRawSettings = settings; + filterImage(); +} + +void RawPostProcessing::filterImage() +{ + rawPostProcessing(); +} + +void RawPostProcessing::rawPostProcessing() +{ + if (!m_orgImage.bits() || !m_orgImage.width() || !m_orgImage.height()) + { + DWarning() << ("RawPostProcessing::rawPostProcessing: no image m_orgImage.bits() available!") + << endl; + return; + } + + if (!m_customRawSettings.postProcessingSettingsIsDirty()) + { + m_destImage = m_orgImage; + return; + } + + postProgress(15); + + if (m_customRawSettings.exposureComp != 0.0 || m_customRawSettings.saturation != 1.0) + { + WhiteBalance wb(m_orgImage.sixteenBit()); + wb.whiteBalance(m_orgImage.bits(), m_orgImage.width(), m_orgImage.height(), m_orgImage.sixteenBit(), + 0.0, // black + m_customRawSettings.exposureComp, // exposure + 6500.0, // temperature (neutral) + 1.0, // green + 0.5, // dark + 1.0, // gamma + m_customRawSettings.saturation); // saturation + } + postProgress(30); + + if (m_customRawSettings.lightness != 0.0 || m_customRawSettings.contrast != 1.0 || m_customRawSettings.gamma != 1.0) + { + BCGModifier bcg; + bcg.setBrightness(m_customRawSettings.lightness); + bcg.setContrast(m_customRawSettings.contrast); + bcg.setGamma(m_customRawSettings.gamma); + bcg.applyBCG(m_orgImage.bits(), m_orgImage.width(), m_orgImage.height(), m_orgImage.sixteenBit()); + } + postProgress(45); + + if (!m_customRawSettings.curveAdjust.isEmpty()) + { + DImg tmp(m_orgImage.width(), m_orgImage.height(), m_orgImage.sixteenBit()); + ImageCurves curves(m_orgImage.sixteenBit()); + curves.setCurvePoints(ImageHistogram::ValueChannel, m_customRawSettings.curveAdjust); + curves.curvesCalculateCurve(ImageHistogram::ValueChannel); + curves.curvesLutSetup(ImageHistogram::AlphaChannel); + curves.curvesLutProcess(m_orgImage.bits(), tmp.bits(), m_orgImage.width(), m_orgImage.height()); + memcpy(m_orgImage.bits(), tmp.bits(), tmp.numBytes()); + } + postProgress(60); + + if (!m_customRawSettings.levelsAdjust.isEmpty()) + { + DImg tmp(m_orgImage.width(), m_orgImage.height(), m_orgImage.sixteenBit()); + ImageLevels levels(m_orgImage.sixteenBit()); + int j=0; + for (int i = 0 ; i < 4; i++) + { + levels.setLevelLowInputValue(i, m_customRawSettings.levelsAdjust[j++]); + levels.setLevelHighInputValue(i, m_customRawSettings.levelsAdjust[j++]); + levels.setLevelLowOutputValue(i, m_customRawSettings.levelsAdjust[j++]); + levels.setLevelHighOutputValue(i, m_customRawSettings.levelsAdjust[j++]); + } + + levels.levelsLutSetup(ImageHistogram::AlphaChannel); + levels.levelsLutProcess(m_orgImage.bits(), tmp.bits(), m_orgImage.width(), m_orgImage.height()); + memcpy(m_orgImage.bits(), tmp.bits(), tmp.numBytes()); + } + postProgress(75); + + m_destImage = m_orgImage; + + postProgress(100); +} + +} // NameSpace Digikam diff --git a/src/utilities/imageeditor/rawimport/rawpostprocessing.h b/src/utilities/imageeditor/rawimport/rawpostprocessing.h new file mode 100644 index 00000000..3b3c7761 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawpostprocessing.h @@ -0,0 +1,63 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-13-08 + * Description : Raw post processing corrections. + * + * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef RAWPOSTPROCESSING_H +#define RAWPOSTPROCESSING_H + +// Digikam includes. + +#include "digikam_export.h" + +// Local includes. + +#include "dimgthreadedfilter.h" + +namespace Digikam +{ + +class DIGIKAM_EXPORT RawPostProcessing : public DImgThreadedFilter +{ + +public: + + RawPostProcessing(DImg *orgImage, TQObject *parent=0, const DRawDecoding& settings=DRawDecoding()); + + // Constructor for slave mode: execute immediately in current thread with specified master filter + RawPostProcessing(DImgThreadedFilter *parentFilter, const DImg &orgImage, const DImg &destImage, + int progressBegin=0, int progressEnd=100, const DRawDecoding& settings=DRawDecoding()); + + ~RawPostProcessing(){}; + +private: + + virtual void filterImage(); + void rawPostProcessing(); + +private: + + DRawDecoding m_customRawSettings; +}; + +} // NameSpace Digikam + +#endif /* RAWPOSTPROCESSING_H */ diff --git a/src/utilities/imageeditor/rawimport/rawpreview.cpp b/src/utilities/imageeditor/rawimport/rawpreview.cpp new file mode 100644 index 00000000..3207ba14 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawpreview.cpp @@ -0,0 +1,336 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-04 + * Description : RAW postProcessedImg widget. + * + * Copyright (C) 2008 Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqstring.h> +#include <tqpainter.h> +#include <tqtoolbutton.h> +#include <tqtooltip.h> +#include <tqpixmap.h> +#include <tqfileinfo.h> + +// KDE includes. + +#include <tdelocale.h> +#include <kcursor.h> +#include <kdatetbl.h> +#include <kiconloader.h> + +// Local includes. + +#include "ddebug.h" +#include "paniconwidget.h" +#include "managedloadsavethread.h" +#include "loadingdescription.h" +#include "themeengine.h" +#include "rawpreview.h" +#include "rawpreview.moc" + +namespace Digikam +{ + +class RawPreviewPriv +{ +public: + + RawPreviewPriv() + { + panIconPopup = 0; + panIconWidget = 0; + cornerButton = 0; + thread = 0; + url = 0; + currentFitWindowZoom = 0; + } + + double currentFitWindowZoom; + + TQToolButton *cornerButton; + + TDEPopupFrame *panIconPopup; + + KURL url; + + PanIconWidget *panIconWidget; + + DImg demosaicedImg; + + DImg postProcessedImg; + + DRawDecoding settings; + + ManagedLoadSaveThread *thread; + + LoadingDescription loadingDesc; +}; + +RawPreview::RawPreview(const KURL& url, TQWidget *parent) + : PreviewWidget(parent) +{ + d = new RawPreviewPriv; + d->thread = new ManagedLoadSaveThread; + d->url = url; + + setMinimumWidth(500); + setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); + + d->cornerButton = new TQToolButton(this); + d->cornerButton->setIconSet(SmallIcon("move")); + d->cornerButton->hide(); + TQToolTip::add(d->cornerButton, i18n("Pan the image to a region")); + setCornerWidget(d->cornerButton); + + // ------------------------------------------------------------ + + connect(d->thread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription&, const DImg&)), + this, TQ_SLOT(slotImageLoaded(const LoadingDescription&, const DImg&))); + + connect(d->thread, TQ_SIGNAL(signalLoadingProgress(const LoadingDescription&, float)), + this, TQ_SLOT(slotLoadingProgress(const LoadingDescription&, float))); + + connect(d->cornerButton, TQ_SIGNAL(pressed()), + this, TQ_SLOT(slotCornerButtonPressed())); + + connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()), + this, TQ_SLOT(slotThemeChanged())); + + // ------------------------------------------------------------ + + slotReset(); +} + +RawPreview::~RawPreview() +{ + delete d; +} + +void RawPreview::setPostProcessedImage(const DImg& image) +{ + d->postProcessedImg = image; + + updateZoomAndSize(false); + + viewport()->setUpdatesEnabled(true); + viewport()->update(); +} + +DImg& RawPreview::postProcessedImage() const +{ + return d->postProcessedImg; +} + +DImg& RawPreview::demosaicedImage() const +{ + return d->demosaicedImg; +} + +void RawPreview::setDecodingSettings(const DRawDecoding& settings) +{ + // Save post processing settings. + d->settings = settings; + + // All post processing settings will be used after demosaicing. + DRawDecoding demosaisedSettings = settings; + demosaisedSettings.resetPostProcessingSettings(); + + d->loadingDesc = LoadingDescription(d->url.path(), demosaisedSettings); + d->thread->load(d->loadingDesc, ManagedLoadSaveThread::LoadingPolicyFirstRemovePrevious); + emit signalLoadingStarted(); +} + +void RawPreview::cancelLoading() +{ + d->thread->stopLoading(d->loadingDesc); +} + +void RawPreview::slotLoadingProgress(const LoadingDescription& description, float progress) +{ + if (description.filePath != d->loadingDesc.filePath) + return; + + emit signalLoadingProgress(progress); +} + +void RawPreview::slotImageLoaded(const LoadingDescription& description, const DImg& image) +{ + if (description.filePath != d->loadingDesc.filePath) + return; + + if (image.isNull()) + { + TQPixmap pix(visibleWidth(), visibleHeight()); + pix.fill(ThemeEngine::instance()->baseColor()); + TQPainter p(&pix); + p.setPen(TQPen(ThemeEngine::instance()->textRegColor())); + p.drawText(0, 0, pix.width(), pix.height(), + TQt::AlignCenter|TQt::WordBreak, + i18n("Cannot decode RAW image for\n\"%1\"") + .arg(TQFileInfo(d->loadingDesc.filePath).fileName())); + p.end(); + // three copies - but the image is small + setPostProcessedImage(DImg(pix.convertToImage())); + emit signalLoadingFailed(); + } + else + { + d->demosaicedImg = image; + emit signalDemosaicedImage(); + // NOTE: we will apply all Raw post processing corrections into RawImport class. + } +} + +void RawPreview::slotThemeChanged() +{ + setBackgroundColor(ThemeEngine::instance()->baseColor()); +} + +void RawPreview::slotCornerButtonPressed() +{ + if (d->panIconPopup) + { + d->panIconPopup->hide(); + delete d->panIconPopup; + d->panIconPopup = 0; + } + + d->panIconPopup = new TDEPopupFrame(this); + PanIconWidget *pan = new PanIconWidget(d->panIconPopup); + pan->setImage(180, 120, postProcessedImage()); + d->panIconPopup->setMainWidget(pan); + + TQRect r((int)(contentsX() / zoomFactor()), (int)(contentsY() / zoomFactor()), + (int)(visibleWidth() / zoomFactor()), (int)(visibleHeight() / zoomFactor())); + pan->setRegionSelection(r); + pan->setMouseFocus(); + + connect(pan, TQ_SIGNAL(signalSelectionMoved(const TQRect&, bool)), + this, TQ_SLOT(slotPanIconSelectionMoved(const TQRect&, bool))); + + connect(pan, TQ_SIGNAL(signalHiden()), + this, TQ_SLOT(slotPanIconHiden())); + + TQPoint g = mapToGlobal(viewport()->pos()); + g.setX(g.x()+ viewport()->size().width()); + g.setY(g.y()+ viewport()->size().height()); + d->panIconPopup->popup(TQPoint(g.x() - d->panIconPopup->width(), + g.y() - d->panIconPopup->height())); + + pan->setCursorToLocalRegionSelectionCenter(); +} + +void RawPreview::slotPanIconHiden() +{ + d->cornerButton->blockSignals(true); + d->cornerButton->animateClick(); + d->cornerButton->blockSignals(false); +} + +void RawPreview::slotPanIconSelectionMoved(const TQRect& r, bool b) +{ + setContentsPos((int)(r.x()*zoomFactor()), (int)(r.y()*zoomFactor())); + + if (b) + { + d->panIconPopup->hide(); + delete d->panIconPopup; + d->panIconPopup = 0; + slotPanIconHiden(); + } +} + +void RawPreview::zoomFactorChanged(double zoom) +{ + updateScrollBars(); + + if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible()) + d->cornerButton->show(); + else + d->cornerButton->hide(); + + PreviewWidget::zoomFactorChanged(zoom); +} + +void RawPreview::resizeEvent(TQResizeEvent* e) +{ + if (!e) return; + + TQScrollView::resizeEvent(e); + + if (!d->loadingDesc.filePath.isEmpty()) + d->cornerButton->hide(); + + updateZoomAndSize(false); +} + +void RawPreview::updateZoomAndSize(bool alwaysFitToWindow) +{ + // Set zoom for fit-in-window as minimum, but dont scale up images + // that are smaller than the available space, only scale down. + double zoom = calcAutoZoomFactor(ZoomInOnly); + setZoomMin(zoom); + setZoomMax(zoom*12.0); + + // Is currently the zoom factor set to fit to window? Then set it again to fit the new size. + if (zoomFactor() < zoom || alwaysFitToWindow || zoomFactor() == d->currentFitWindowZoom) + { + setZoomFactor(zoom); + } + + // store which zoom factor means it is fit to window + d->currentFitWindowZoom = zoom; + + updateContentsSize(); +} + +int RawPreview::previewWidth() +{ + return d->postProcessedImg.width(); +} + +int RawPreview::previewHeight() +{ + return d->postProcessedImg.height(); +} + +bool RawPreview::previewIsNull() +{ + return d->postProcessedImg.isNull(); +} + +void RawPreview::resetPreview() +{ + d->postProcessedImg = DImg(); + d->loadingDesc = LoadingDescription(); + + updateZoomAndSize(false); +} + +void RawPreview::paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh) +{ + DImg img = d->postProcessedImg.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize()); + TQPixmap pix2 = img.convertToPixmap(); + bitBlt(pix, 0, 0, &pix2, 0, 0); +} + +} // NameSpace Digikam diff --git a/src/utilities/imageeditor/rawimport/rawpreview.h b/src/utilities/imageeditor/rawimport/rawpreview.h new file mode 100644 index 00000000..6c7e5379 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawpreview.h @@ -0,0 +1,108 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-04 + * Description : RAW preview widget. + * + * Copyright (C) 2008 Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef RAWPREVIEW_H +#define RAWPREVIEW_H + +// TQt includes. + +#include <tqimage.h> + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "dimg.h" +#include "previewwidget.h" +#include "digikam_export.h" + +class TQPixmap; + +namespace Digikam +{ + +class LoadingDescription; +class RawPreviewPriv; + +class DIGIKAM_EXPORT RawPreview : public PreviewWidget +{ + +TQ_OBJECT + + +public: + + RawPreview(const KURL& url, TQWidget *parent); + ~RawPreview(); + + DImg& demosaicedImage() const; + DImg& postProcessedImage() const; + + void setDecodingSettings(const DRawDecoding& settings); + void setPostProcessedImage(const DImg& image); + + void cancelLoading(); + +signals: + + void signalLoadingStarted(); + void signalLoadingProgress(float); + void signalLoadingFailed(); + void signalDemosaicedImage(); + void signalPostProcessedImage(); + +protected: + + void resizeEvent(TQResizeEvent* e); + +private slots: + + void slotLoadingProgress(const LoadingDescription& description, float progress); + void slotImageLoaded(const LoadingDescription& description, const DImg &image); + void slotThemeChanged(); + void slotCornerButtonPressed(); + void slotPanIconSelectionMoved(const TQRect&, bool); + void slotPanIconHiden(); + +private: + + void setdemosaicedImg(const DImg& image); + void postProcessing(const DRawDecoding& settings); + int previewWidth(); + int previewHeight(); + bool previewIsNull(); + void resetPreview(); + void zoomFactorChanged(double zoom); + void updateZoomAndSize(bool alwaysFitToWindow); + inline void paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh); + +private: + + RawPreviewPriv* d; +}; + +} // NameSpace Digikam + +#endif /* RAWPREVIEW_H */ diff --git a/src/utilities/imageeditor/rawimport/rawsettingsbox.cpp b/src/utilities/imageeditor/rawimport/rawsettingsbox.cpp new file mode 100644 index 00000000..bf0ee67e --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawsettingsbox.cpp @@ -0,0 +1,741 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-11 + * Description : Raw import settings box + * + * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// TQt includes. + +#include <tqstring.h> +#include <tqlayout.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqhbuttongroup.h> +#include <tqcombobox.h> +#include <tqlabel.h> +#include <tqvbox.h> +#include <tqtoolbutton.h> +#include <tqtoolbox.h> +#include <tqpushbutton.h> + +// KDE includes. + +#include <tdeapplication.h> +#include <ktabwidget.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeconfig.h> +#include <kstandarddirs.h> +#include <tdefiledialog.h> + +// LibKDcraw includes. + +#include <libkdcraw/dcrawsettingswidget.h> +#include <libkdcraw/rnuminput.h> + +// Local includes. + +#include "ddebug.h" +#include "imagedialog.h" +#include "imagehistogram.h" +#include "imagecurves.h" +#include "iccpreviewwidget.h" +#include "histogramwidget.h" +#include "curveswidget.h" +#include "colorgradientwidget.h" +#include "rawsettingsbox.h" +#include "rawsettingsbox.moc" + +using namespace KDcrawIface; + +namespace Digikam +{ + +class RawSettingsBoxPriv +{ +public: + + enum ColorChannel + { + LuminosityChannel=0, + RedChannel, + GreenChannel, + BlueChannel, + ColorChannels + }; + + enum AllColorsColorType + { + AllColorsRed=0, + AllColorsGreen, + AllColorsBlue + }; + +public: + + RawSettingsBoxPriv() + { + channelCB = 0; + colorsCB = 0; + scaleBG = 0; + hGradient = 0; + histogramWidget = 0; + infoBox = 0; + advExposureBox = 0; + gammaLabel = 0; + gammaInput = 0; + saturationLabel = 0; + saturationInput = 0; + fineExposureLabel = 0; + fineExposureInput = 0; + contrastInput = 0; + contrastLabel = 0; + curveBox = 0; + curveWidget = 0; + resetCurveBtn = 0; + decodingSettingsBox = 0; + postProcessSettingsBox = 0; + tabView = 0; + abortBtn = 0; + updateBtn = 0; + rawdecodingBox = 0; + brightnessLabel = 0; + brightnessInput = 0; + } + + TQWidget *advExposureBox; + TQWidget *curveBox; + TQWidget *rawdecodingBox; + + TQComboBox *channelCB; + TQComboBox *colorsCB; + + TQLabel *brightnessLabel; + TQLabel *contrastLabel; + TQLabel *gammaLabel; + TQLabel *saturationLabel; + TQLabel *fineExposureLabel; + + TQHButtonGroup *scaleBG; + + TQPushButton *abortBtn; + TQPushButton *updateBtn; + + TQToolButton *resetCurveBtn; + + TQToolBox *postProcessSettingsBox; + + KTabWidget *tabView; + + ColorGradientWidget *hGradient; + + CurvesWidget *curveWidget; + + HistogramWidget *histogramWidget; + + ImageDialogPreview *infoBox; + + RIntNumInput *contrastInput; + RIntNumInput *brightnessInput; + + RDoubleNumInput *gammaInput; + RDoubleNumInput *saturationInput; + RDoubleNumInput *fineExposureInput; + + DcrawSettingsWidget *decodingSettingsBox; +}; + +RawSettingsBox::RawSettingsBox(const KURL& url, TQWidget *parent) + : EditorToolSettings(Default|Ok|Cancel, NoTool, parent) +{ + d = new RawSettingsBoxPriv; + + // --------------------------------------------------------------- + + TQGridLayout* gridSettings = new TQGridLayout(plainPage(), 5, 4); + + TQLabel *label1 = new TQLabel(i18n("Channel:"), plainPage()); + label1->setAlignment( TQt::AlignRight | TQt::AlignVCenter ); + d->channelCB = new TQComboBox(false, plainPage()); + d->channelCB->insertItem( i18n("Luminosity") ); + d->channelCB->insertItem( i18n("Red") ); + d->channelCB->insertItem( i18n("Green") ); + d->channelCB->insertItem( i18n("Blue") ); + d->channelCB->insertItem( i18n("Colors") ); + TQWhatsThis::add(d->channelCB, i18n("<p>Select the histogram channel to display here:<p>" + "<b>Luminosity</b>: display the image's luminosity values.<p>" + "<b>Red</b>: display the red image-channel values.<p>" + "<b>Green</b>: display the green image-channel values.<p>" + "<b>Blue</b>: display the blue image-channel values.<p>" + "<b>Colors</b>: Display all color channel values at the same time.")); + + d->scaleBG = new TQHButtonGroup(plainPage()); + d->scaleBG->setExclusive(true); + d->scaleBG->setFrameShape(TQFrame::NoFrame); + d->scaleBG->setInsideMargin( 0 ); + TQWhatsThis::add(d->scaleBG, i18n("<p>Select the histogram scale here.<p>" + "If the image's maximal counts are small, you can use the linear scale.<p>" + "Logarithmic scale can be used when the maximal counts are big; " + "if it is used, all values (small and large) will be visible on the graph.")); + + TQPushButton *linHistoButton = new TQPushButton( d->scaleBG ); + TQToolTip::add( linHistoButton, i18n( "<p>Linear" ) ); + d->scaleBG->insert(linHistoButton, HistogramWidget::LinScaleHistogram); + TDEGlobal::dirs()->addResourceType("histogram-lin", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("histogram-lin", "histogram-lin.png"); + linHistoButton->setPixmap( TQPixmap( directory + "histogram-lin.png" ) ); + linHistoButton->setToggleButton(true); + + TQPushButton *logHistoButton = new TQPushButton( d->scaleBG ); + TQToolTip::add( logHistoButton, i18n( "<p>Logarithmic" ) ); + d->scaleBG->insert(logHistoButton, HistogramWidget::LogScaleHistogram); + TDEGlobal::dirs()->addResourceType("histogram-log", TDEGlobal::dirs()->kde_default("data") + "digikam/data"); + directory = TDEGlobal::dirs()->findResourceDir("histogram-log", "histogram-log.png"); + logHistoButton->setPixmap( TQPixmap( directory + "histogram-log.png" ) ); + logHistoButton->setToggleButton(true); + + TQLabel *label10 = new TQLabel(i18n("Colors:"), plainPage()); + label10->setAlignment( TQt::AlignRight | TQt::AlignVCenter ); + d->colorsCB = new TQComboBox(false, plainPage()); + d->colorsCB->insertItem( i18n("Red") ); + d->colorsCB->insertItem( i18n("Green") ); + d->colorsCB->insertItem( i18n("Blue") ); + d->colorsCB->setEnabled( false ); + TQWhatsThis::add( d->colorsCB, i18n("<p>Select the main color displayed with Colors Channel mode here:<p>" + "<b>Red</b>: Draw the red image channel in the foreground.<p>" + "<b>Green</b>: Draw the green image channel in the foreground.<p>" + "<b>Blue</b>: Draw the blue image channel in the foreground.<p>")); + + // --------------------------------------------------------------- + + TQVBox *histoBox = new TQVBox(plainPage()); + d->histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true); + TQWhatsThis::add(d->histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing " + "of the selected image channel. This one is re-computed at any " + "settings changes.")); + TQLabel *space = new TQLabel(histoBox); + space->setFixedHeight(1); + d->hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, histoBox ); + d->hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + // --------------------------------------------------------------- + + d->tabView = new KTabWidget(plainPage()); + d->rawdecodingBox = new TQWidget(d->tabView); + TQGridLayout* rawGrid = new TQGridLayout(d->rawdecodingBox, 1, 2); + d->decodingSettingsBox = new DcrawSettingsWidget(d->rawdecodingBox, true, true, false); + + KFileDialog *inputDlg = d->decodingSettingsBox->inputProfileUrlEdit()->fileDialog(); + inputDlg->setPreviewWidget(new ICCPreviewWidget(inputDlg)); + + KFileDialog *outputDlg = d->decodingSettingsBox->outputProfileUrlEdit()->fileDialog(); + outputDlg->setPreviewWidget(new ICCPreviewWidget(outputDlg)); + + d->abortBtn = new TQPushButton(d->rawdecodingBox); + d->abortBtn->setText(i18n("Abort")); + d->abortBtn->setIconSet(SmallIconSet("process-stop")); + d->abortBtn->setEnabled(false); + TQToolTip::add(d->abortBtn, i18n("Abort the current Raw image preview.")); + + d->updateBtn = new TQPushButton(d->rawdecodingBox); + d->updateBtn->setText(i18n("Update")); + d->updateBtn->setIconSet(SmallIconSet("reload_page")); + d->updateBtn->setEnabled(false); + TQToolTip::add(d->updateBtn, i18n("Generate a Raw image preview using current settings.")); + + rawGrid->addMultiCellWidget(d->decodingSettingsBox, 0, 0, 0, 2); + rawGrid->addMultiCellWidget(d->abortBtn, 1, 1, 0, 0); + rawGrid->addMultiCellWidget(d->updateBtn, 1, 1, 2, 2); + rawGrid->setColStretch(1, 10); + rawGrid->setSpacing(spacingHint()); + rawGrid->setMargin(spacingHint()); + + // --------------------------------------------------------------- + + d->postProcessSettingsBox = new TQToolBox(d->tabView); + d->infoBox = new ImageDialogPreview(d->postProcessSettingsBox); + d->infoBox->showPreview(url); + + // --------------------------------------------------------------- + + d->advExposureBox = new TQWidget(d->postProcessSettingsBox); + TQGridLayout* advExposureLayout = new TQGridLayout(d->advExposureBox, 5, 2); + + d->brightnessLabel = new TQLabel(i18n("Brightness:"), d->advExposureBox); + d->brightnessInput = new RIntNumInput(d->advExposureBox); + d->brightnessInput->setRange(-100, 100, 1); + d->brightnessInput->setDefaultValue(0); + TQWhatsThis::add(d->brightnessInput->input(), i18n("<p>Set here the brightness adjustment of the image.")); + + d->contrastLabel = new TQLabel(i18n("Contrast:"), d->advExposureBox); + d->contrastInput = new RIntNumInput(d->advExposureBox); + d->contrastInput->setRange(-100, 100, 1); + d->contrastInput->setDefaultValue(0); + TQWhatsThis::add(d->contrastInput->input(), i18n("<p>Set here the contrast adjustment of the image.")); + + d->gammaLabel = new TQLabel(i18n("Gamma:"), d->advExposureBox); + d->gammaInput = new RDoubleNumInput(d->advExposureBox); + d->gammaInput->setPrecision(2); + d->gammaInput->setRange(0.1, 3.0, 0.01); + d->gammaInput->setDefaultValue(1.0); + TQWhatsThis::add(d->gammaInput->input(), i18n("Set here the gamma adjustement of the image")); + + d->saturationLabel = new TQLabel(i18n("Saturation:"), d->advExposureBox); + d->saturationInput = new RDoubleNumInput(d->advExposureBox); + d->saturationInput->setPrecision(2); + d->saturationInput->setRange(0.0, 2.0, 0.01); + d->saturationInput->setDefaultValue(1.0); + TQWhatsThis::add(d->saturationInput->input(), i18n("<p>Set here the color saturation correction.")); + + d->fineExposureLabel = new TQLabel(i18n("Exposure (E.V):"), d->advExposureBox); + d->fineExposureInput = new RDoubleNumInput(d->advExposureBox); + d->fineExposureInput->setPrecision(2); + d->fineExposureInput->setRange(-3.0, 3.0, 0.1); + d->fineExposureInput->setDefaultValue(0.0); + TQWhatsThis::add(d->fineExposureInput->input(), i18n("<p>This value in E.V will be used to perform " + "an exposure compensation of the image.")); + + advExposureLayout->addMultiCellWidget(d->brightnessLabel, 0, 0, 0, 0); + advExposureLayout->addMultiCellWidget(d->brightnessInput, 0, 0, 1, 2); + advExposureLayout->addMultiCellWidget(d->contrastLabel, 1, 1, 0, 0); + advExposureLayout->addMultiCellWidget(d->contrastInput, 1, 1, 1, 2); + advExposureLayout->addMultiCellWidget(d->gammaLabel, 2, 2, 0, 0); + advExposureLayout->addMultiCellWidget(d->gammaInput, 2, 2, 1, 2); + advExposureLayout->addMultiCellWidget(d->saturationLabel, 3, 3, 0, 0); + advExposureLayout->addMultiCellWidget(d->saturationInput, 3, 3, 1, 2); + advExposureLayout->addMultiCellWidget(d->fineExposureLabel, 4, 4, 0, 0); + advExposureLayout->addMultiCellWidget(d->fineExposureInput, 4, 4, 1, 2); + advExposureLayout->setRowStretch(5, 10); + advExposureLayout->setSpacing(0); + advExposureLayout->setMargin(spacingHint()); + + // --------------------------------------------------------------- + + d->curveBox = new TQWidget(d->postProcessSettingsBox); + TQGridLayout* curveLayout = new TQGridLayout(d->curveBox, 3, 2); + + ColorGradientWidget* vGradient = new ColorGradientWidget(ColorGradientWidget::Vertical, 10, d->curveBox); + vGradient->setColors( TQColor( "white" ), TQColor( "black" ) ); + + TQLabel *spacev = new TQLabel(d->curveBox); + spacev->setFixedWidth(1); + + d->curveWidget = new CurvesWidget(256, 192, d->curveBox); + TQWhatsThis::add(d->curveWidget, i18n("<p>This is the curve adjustment of the image luminosity")); + + d->resetCurveBtn = new TQToolButton(d->curveBox); + d->resetCurveBtn->setFixedSize(11, 11); + d->resetCurveBtn->setIconSet(SmallIconSet("reload_page", 8)); + d->resetCurveBtn->setFocusPolicy(TQWidget::NoFocus); + d->resetCurveBtn->setAutoRaise(true); + TQToolTip::add(d->resetCurveBtn, i18n("Reset curve to linear")); + + TQLabel *spaceh = new TQLabel(d->curveBox); + spaceh->setFixedHeight(1); + + ColorGradientWidget *hGradient = new ColorGradientWidget(ColorGradientWidget::Horizontal, 10, d->curveBox); + hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + + curveLayout->addMultiCellWidget(vGradient, 0, 0, 0, 0); + curveLayout->addMultiCellWidget(spacev, 0, 0, 1, 1); + curveLayout->addMultiCellWidget(d->curveWidget, 0, 0, 2, 2); + curveLayout->addMultiCellWidget(spaceh, 1, 1, 2, 2); + curveLayout->addMultiCellWidget(d->resetCurveBtn, 1, 2, 0, 1); + curveLayout->addMultiCellWidget(hGradient, 2, 2, 2, 2); + curveLayout->setRowStretch(3, 10); + curveLayout->setSpacing(0); + curveLayout->setMargin(spacingHint()); + + // --------------------------------------------------------------- + + d->postProcessSettingsBox->addItem(d->advExposureBox, i18n("Exposure")); + d->postProcessSettingsBox->addItem(d->curveBox, i18n("Luminosity Curve")); + d->postProcessSettingsBox->setItemIconSet(0, SmallIconSet("contrast")); + d->postProcessSettingsBox->setItemIconSet(1, SmallIconSet("adjustcurves")); + + d->decodingSettingsBox->setItemIconSet(DcrawSettingsWidget::DEMOSAICING, SmallIconSet("kdcraw")); + d->decodingSettingsBox->setItemIconSet(DcrawSettingsWidget::WHITEBALANCE, SmallIconSet("whitebalance")); + d->decodingSettingsBox->setItemIconSet(DcrawSettingsWidget::CORRECTIONS, SmallIconSet("lensdistortion")); + d->decodingSettingsBox->setItemIconSet(DcrawSettingsWidget::COLORMANAGEMENT, SmallIconSet("colormanagement")); + d->decodingSettingsBox->updateMinimumWidth(); + + d->tabView->insertTab(d->rawdecodingBox, i18n("Raw Decoding"), 0); + d->tabView->insertTab(d->postProcessSettingsBox, i18n("Post Processing"), 1); + d->tabView->insertTab(d->infoBox, i18n("Info"), 2); + + // --------------------------------------------------------------- + + button(Default)->setText(i18n("Reset")); + button(Default)->setIconSet(SmallIconSet("reload_page")); + TQToolTip::add(button(Default), i18n("<p>Reset all settings to default values.")); + + button(Ok)->setText(i18n("Import")); + button(Ok)->setIconSet(SmallIconSet("ok")); + TQToolTip::add(button(Ok), i18n("<p>Import image to editor using current settings.")); + + button(Cancel)->setText(i18n("Use Default")); + button(Cancel)->setIconSet(SmallIconSet("go-home")); + TQToolTip::add(button(Cancel), i18n("<p>Use general Raw decoding settings to load this image in editor.")); + + // --------------------------------------------------------------- + + gridSettings->addMultiCellWidget(label1, 0, 0, 0, 0); + gridSettings->addMultiCellWidget(d->channelCB, 0, 0, 1, 1); + gridSettings->addMultiCellWidget(d->scaleBG, 0, 0, 4, 4); + gridSettings->addMultiCellWidget(label10, 1, 1, 0, 0); + gridSettings->addMultiCellWidget(d->colorsCB, 1, 1, 1, 1); + gridSettings->addMultiCellWidget(histoBox, 2, 3, 0, 4); + gridSettings->addMultiCellWidget(d->tabView, 4, 4, 0, 4); + gridSettings->setRowStretch(5, 10); + gridSettings->setColStretch(2, 10); + gridSettings->setSpacing(spacingHint()); + gridSettings->setMargin(0); + + // --------------------------------------------------------------- + + connect(d->channelCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotChannelChanged(int))); + + connect(d->scaleBG, TQ_SIGNAL(released(int)), + this, TQ_SLOT(slotScaleChanged(int))); + + connect(d->colorsCB, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotColorsChanged(int))); + + connect(d->resetCurveBtn, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotResetCurve())); + + connect(d->updateBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalUpdatePreview())); + + connect(d->abortBtn, TQ_SIGNAL(clicked()), + this, TQ_SIGNAL(signalAbortPreview())); + + connect(d->decodingSettingsBox, TQ_SIGNAL(signalSettingsChanged()), + this, TQ_SIGNAL(signalDemosaicingChanged())); + + connect(d->curveWidget, TQ_SIGNAL(signalCurvesChanged()), + this, TQ_SIGNAL(signalPostProcessingChanged())); + + connect(d->brightnessInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SIGNAL(signalPostProcessingChanged())); + + connect(d->contrastInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SIGNAL(signalPostProcessingChanged())); + + connect(d->gammaInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SIGNAL(signalPostProcessingChanged())); + + connect(d->saturationInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SIGNAL(signalPostProcessingChanged())); + + connect(d->fineExposureInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SIGNAL(signalPostProcessingChanged())); +} + +RawSettingsBox::~RawSettingsBox() +{ + delete d->curveWidget; + delete d; +} + +void RawSettingsBox::enableUpdateBtn(bool b) +{ + d->updateBtn->setEnabled(b); +} + +void RawSettingsBox::setBusy(bool b) +{ + d->decodingSettingsBox->setEnabled(!b); + d->abortBtn->setEnabled(b); +} + +void RawSettingsBox::setDemosaicedImage(DImg& img) +{ + d->curveWidget->stopHistogramComputation(); + d->curveWidget->updateData(img.bits(), img.width(), img.height(), img.sixteenBit()); +} + +void RawSettingsBox::setPostProcessedImage(DImg& img) +{ + d->histogramWidget->stopHistogramComputation(); + d->histogramWidget->updateData(img.bits(), img.width(), img.height(), img.sixteenBit()); +} + +void RawSettingsBox::resetSettings() +{ + d->decodingSettingsBox->setDefaultSettings(); + d->brightnessInput->slotReset(); + d->contrastInput->slotReset(); + d->gammaInput->slotReset(); + d->saturationInput->slotReset(); + d->fineExposureInput->slotReset(); + slotResetCurve(); +} + +void RawSettingsBox::slotResetCurve() +{ + d->curveWidget->reset(); + emit signalPostProcessingChanged(); +} + +HistogramWidget* RawSettingsBox::histogram() const +{ + return d->histogramWidget; +} + +CurvesWidget* RawSettingsBox::curve() const +{ + return d->curveWidget; +} + +void RawSettingsBox::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("RAW Import Settings"); + + d->channelCB->setCurrentItem(config->readNumEntry("Histogram Channel", RawSettingsBoxPriv::LuminosityChannel)); + d->scaleBG->setButton(config->readNumEntry("Histogram Scale", HistogramWidget::LogScaleHistogram)); + d->colorsCB->setCurrentItem(config->readNumEntry("Histogram Color", RawSettingsBoxPriv::AllColorsRed)); + + d->decodingSettingsBox->setSixteenBits(config->readBoolEntry("SixteenBitsImage", false)); + d->decodingSettingsBox->setWhiteBalance((DRawDecoding::WhiteBalance) + config->readNumEntry("White Balance", + DRawDecoding::CAMERA)); + d->decodingSettingsBox->setCustomWhiteBalance(config->readNumEntry("Custom White Balance", 6500)); + d->decodingSettingsBox->setCustomWhiteBalanceGreen(config->readDoubleNumEntry("Custom White Balance Green", 1.0)); + d->decodingSettingsBox->setFourColor(config->readBoolEntry("Four Color RGB", false)); + d->decodingSettingsBox->setUnclipColor(config->readNumEntry("Unclip Color", 0)); + d->decodingSettingsBox->setDontStretchPixels(config->readBoolEntry("Dont Stretch Pixels", false)); + d->decodingSettingsBox->setNoiseReduction(config->readBoolEntry("Use Noise Reduction", false)); + d->decodingSettingsBox->setUseBlackPoint(config->readBoolEntry("Use Black Point", false)); + d->decodingSettingsBox->setBlackPoint(config->readNumEntry("Black Point", 0)); + d->decodingSettingsBox->setUseWhitePoint(config->readBoolEntry("Use White Point", false)); + d->decodingSettingsBox->setWhitePoint(config->readNumEntry("White Point", 0)); + d->decodingSettingsBox->setMedianFilterPasses(config->readNumEntry("Median Filter Passes", 0)); + d->decodingSettingsBox->setNRThreshold(config->readNumEntry("NR Threshold", 100)); + d->decodingSettingsBox->setUseCACorrection(config->readBoolEntry("EnableCACorrection", false)); + d->decodingSettingsBox->setcaRedMultiplier(config->readDoubleNumEntry("caRedMultiplier", 1.0)); + d->decodingSettingsBox->setcaBlueMultiplier(config->readDoubleNumEntry("caBlueMultiplier", 1.0)); + + d->decodingSettingsBox->setQuality( + (DRawDecoding::DecodingQuality)config->readNumEntry("Decoding Quality", + (int)(DRawDecoding::BILINEAR))); + + d->decodingSettingsBox->setInputColorSpace( + (DRawDecoding::InputColorSpace)config->readNumEntry("Input Color Space", + (int)(DRawDecoding::NOINPUTCS))); + + d->decodingSettingsBox->setOutputColorSpace( + (DRawDecoding::OutputColorSpace)config->readNumEntry("Output Color Space", + (int)(DRawDecoding::SRGB))); + + d->decodingSettingsBox->setInputColorProfile(config->readPathEntry("Input Color Profile", TQString())); + d->decodingSettingsBox->setOutputColorProfile(config->readPathEntry("Output Color Profile", TQString())); + + d->brightnessInput->setValue(config->readNumEntry("Brightness", 0)); + d->contrastInput->setValue(config->readNumEntry("Contrast", 0)); + d->gammaInput->setValue(config->readDoubleNumEntry("Gamma", 1.0)); + d->saturationInput->setValue(config->readDoubleNumEntry("Saturation", 1.0)); + d->fineExposureInput->setValue(config->readDoubleNumEntry("FineExposure", 0.0)); + + d->curveWidget->reset(); + + for (int j = 0 ; j <= 17 ; j++) + { + TQPoint disable(-1, -1); + TQPoint p = config->readPointEntry(TQString("CurveAjustmentPoint%1").arg(j), &disable); + if (!d->decodingSettingsBox->sixteenBits() && p != disable) + { + // Restore point as 16 bits depth. + p.setX(p.x()/255); + p.setY(p.y()/255); + } + d->curveWidget->curves()->setCurvePoint(ImageHistogram::ValueChannel, j, p); + } + d->curveWidget->curves()->curvesCalculateCurve(ImageHistogram::ValueChannel); + + d->tabView->setCurrentPage(config->readNumEntry("Settings Page", 0)); + d->decodingSettingsBox->setCurrentIndex(config->readNumEntry("Decoding Settings Tab", DcrawSettingsWidget::DEMOSAICING)); + d->postProcessSettingsBox->setCurrentIndex(config->readNumEntry("Post Processing Settings Tab", 0)); + + slotChannelChanged(d->channelCB->currentItem()); + slotScaleChanged(d->scaleBG->selectedId()); + slotColorsChanged(d->colorsCB->currentItem()); +} + +void RawSettingsBox::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("RAW Import Settings"); + + config->writeEntry("Histogram Channel", d->channelCB->currentItem()); + config->writeEntry("Histogram Scale", d->scaleBG->selectedId()); + config->writeEntry("Histogram Color", d->colorsCB->currentItem()); + + config->writeEntry("SixteenBitsImage", d->decodingSettingsBox->sixteenBits()); + config->writeEntry("White Balance", d->decodingSettingsBox->whiteBalance()); + config->writeEntry("Custom White Balance", d->decodingSettingsBox->customWhiteBalance()); + config->writeEntry("Custom White Balance Green", d->decodingSettingsBox->customWhiteBalanceGreen()); + config->writeEntry("Four Color RGB", d->decodingSettingsBox->useFourColor()); + config->writeEntry("Unclip Color", d->decodingSettingsBox->unclipColor()); + config->writeEntry("Dont Stretch Pixels", d->decodingSettingsBox->useDontStretchPixels()); + config->writeEntry("Use Noise Reduction", d->decodingSettingsBox->useNoiseReduction()); + config->writeEntry("Use Black Point", d->decodingSettingsBox->useBlackPoint()); + config->writeEntry("Black Point", d->decodingSettingsBox->blackPoint()); + config->writeEntry("Use White Point", d->decodingSettingsBox->useWhitePoint()); + config->writeEntry("White Point", d->decodingSettingsBox->whitePoint()); + config->writeEntry("MedianFilterPasses", d->decodingSettingsBox->medianFilterPasses()); + config->writeEntry("NR Threshold", d->decodingSettingsBox->NRThreshold()); + config->writeEntry("EnableCACorrection", d->decodingSettingsBox->useCACorrection()); + config->writeEntry("caRedMultiplier", d->decodingSettingsBox->caRedMultiplier()); + config->writeEntry("caBlueMultiplier", d->decodingSettingsBox->caBlueMultiplier()); + config->writeEntry("Decoding Quality", (int)d->decodingSettingsBox->quality()); + config->writeEntry("Input Color Space", (int)d->decodingSettingsBox->inputColorSpace()); + config->writeEntry("Output Color Space", (int)d->decodingSettingsBox->outputColorSpace()); + config->writeEntry("Input Color Profile", d->decodingSettingsBox->inputColorProfile()); + config->writeEntry("Output Color Profile", d->decodingSettingsBox->outputColorProfile()); + + config->writeEntry("Brightness", d->brightnessInput->value()); + config->writeEntry("Contrast", d->contrastInput->value()); + config->writeEntry("Gamma", d->gammaInput->value()); + config->writeEntry("Saturation", d->saturationInput->value()); + config->writeEntry("FineExposure", d->fineExposureInput->value()); + + for (int j = 0 ; j <= 17 ; j++) + { + TQPoint p = d->curveWidget->curves()->getCurvePoint(ImageHistogram::ValueChannel, j); + if (!d->curveWidget->curves()->isSixteenBits()) + { + // Store point as 16 bits depth. + p.setX(p.x()*255); + p.setY(p.y()*255); + } + config->writeEntry(TQString("CurveAjustmentPoint%1").arg(j), p); + } + + config->writeEntry("Settings Page", d->tabView->currentPage()); + config->writeEntry("Decoding Settings Tab", d->decodingSettingsBox->currentIndex()); + config->writeEntry("Post Processing Settings Tab", d->postProcessSettingsBox->currentIndex()); + config->sync(); +} + +DRawDecoding RawSettingsBox::settings() +{ + DRawDecoding settings; + settings.sixteenBitsImage = d->decodingSettingsBox->sixteenBits(); + settings.whiteBalance = d->decodingSettingsBox->whiteBalance(); + settings.customWhiteBalance = d->decodingSettingsBox->customWhiteBalance(); + settings.customWhiteBalanceGreen = d->decodingSettingsBox->customWhiteBalanceGreen(); + settings.RGBInterpolate4Colors = d->decodingSettingsBox->useFourColor(); + settings.unclipColors = d->decodingSettingsBox->unclipColor(); + settings.DontStretchPixels = d->decodingSettingsBox->useDontStretchPixels(); + settings.enableNoiseReduction = d->decodingSettingsBox->useNoiseReduction(); + settings.enableBlackPoint = d->decodingSettingsBox->useBlackPoint(); + settings.blackPoint = d->decodingSettingsBox->blackPoint(); + settings.enableWhitePoint = d->decodingSettingsBox->useWhitePoint(); + settings.whitePoint = d->decodingSettingsBox->whitePoint(); + settings.medianFilterPasses = d->decodingSettingsBox->medianFilterPasses(); + settings.NRThreshold = d->decodingSettingsBox->NRThreshold(); + settings.enableCACorrection = d->decodingSettingsBox->useCACorrection(); + settings.caMultiplier[0] = d->decodingSettingsBox->caRedMultiplier(); + settings.caMultiplier[1] = d->decodingSettingsBox->caBlueMultiplier(); + settings.RAWQuality = d->decodingSettingsBox->quality(); + settings.inputColorSpace = d->decodingSettingsBox->inputColorSpace(); + settings.outputColorSpace = d->decodingSettingsBox->outputColorSpace(); + settings.inputProfile = d->decodingSettingsBox->inputColorProfile(); + settings.outputProfile = d->decodingSettingsBox->outputColorProfile(); + + settings.lightness = (double)d->brightnessInput->value()/250.0; + settings.contrast = (double)(d->contrastInput->value()/100.0) + 1.00; + settings.gamma = d->gammaInput->value(); + settings.saturation = d->saturationInput->value(); + settings.exposureComp = d->fineExposureInput->value(); + + if (d->curveWidget->curves()->isDirty()) + settings.curveAdjust = d->curveWidget->curves()->getCurvePoints(ImageHistogram::ValueChannel); + + return settings; +} + +void RawSettingsBox::slotChannelChanged(int channel) +{ + switch(channel) + { + case RawSettingsBoxPriv::LuminosityChannel: + d->histogramWidget->m_channelType = HistogramWidget::ValueHistogram; + d->hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + d->colorsCB->setEnabled(false); + break; + + case RawSettingsBoxPriv::RedChannel: + d->histogramWidget->m_channelType = HistogramWidget::RedChannelHistogram; + d->hGradient->setColors( TQColor( "black" ), TQColor( "red" ) ); + d->colorsCB->setEnabled(false); + break; + + case RawSettingsBoxPriv::GreenChannel: + d->histogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram; + d->hGradient->setColors( TQColor( "black" ), TQColor( "green" ) ); + d->colorsCB->setEnabled(false); + break; + + case RawSettingsBoxPriv::BlueChannel: + d->histogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram; + d->hGradient->setColors( TQColor( "black" ), TQColor( "blue" ) ); + d->colorsCB->setEnabled(false); + break; + + case RawSettingsBoxPriv::ColorChannels: + d->histogramWidget->m_channelType = HistogramWidget::ColorChannelsHistogram; + d->hGradient->setColors( TQColor( "black" ), TQColor( "white" ) ); + d->colorsCB->setEnabled(true); + break; + } + + d->histogramWidget->repaint(false); +} + +void RawSettingsBox::slotScaleChanged(int scale) +{ + d->histogramWidget->m_scaleType = scale; + d->histogramWidget->repaint(false); +} + +void RawSettingsBox::slotColorsChanged(int color) +{ + switch(color) + { + case RawSettingsBoxPriv::AllColorsGreen: + d->histogramWidget->m_colorType = HistogramWidget::GreenColor; + break; + + case RawSettingsBoxPriv::AllColorsBlue: + d->histogramWidget->m_colorType = HistogramWidget::BlueColor; + break; + + default: // Red. + d->histogramWidget->m_colorType = HistogramWidget::RedColor; + break; + } + + d->histogramWidget->repaint(false); +} + +} // NameSpace Digikam diff --git a/src/utilities/imageeditor/rawimport/rawsettingsbox.h b/src/utilities/imageeditor/rawimport/rawsettingsbox.h new file mode 100644 index 00000000..546ce1e5 --- /dev/null +++ b/src/utilities/imageeditor/rawimport/rawsettingsbox.h @@ -0,0 +1,91 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2008-08-11 + * Description : Raw import settings box + * + * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef RAWSETTINGSBOX_H +#define RAWSETTINGSBOX_H + +// KDE includes. + +#include <kurl.h> + +// Local includes. + +#include "editortoolsettings.h" +#include "dimg.h" +#include "digikam_export.h" + +namespace Digikam +{ + +class HistogramWidget; +class CurvesWidget; +class RawSettingsBoxPriv; + +class DIGIKAM_EXPORT RawSettingsBox : public EditorToolSettings +{ + TQ_OBJECT + + +public: + + RawSettingsBox(const KURL& url, TQWidget *parent); + ~RawSettingsBox(); + + void setBusy(bool b); + + HistogramWidget* histogram() const; + CurvesWidget* curve() const; + DRawDecoding settings(); + + void writeSettings(); + void readSettings(); + + void setDemosaicedImage(DImg& img); + void setPostProcessedImage(DImg& img); + + void enableUpdateBtn(bool b); + + void resetSettings(); + +signals: + + void signalUpdatePreview(); + void signalAbortPreview(); + void signalDemosaicingChanged(); + void signalPostProcessingChanged(); + +private slots: + + void slotChannelChanged(int channel); + void slotScaleChanged(int scale); + void slotColorsChanged(int color); + + void slotResetCurve(); + +private: + + RawSettingsBoxPriv *d; +}; + +} // NameSpace Digikam + +#endif // RAWSETTINGSBOX_H diff --git a/src/utilities/imageeditor/tools/Makefile.am b/src/utilities/imageeditor/tools/Makefile.am new file mode 100644 index 00000000..b76207ff --- /dev/null +++ b/src/utilities/imageeditor/tools/Makefile.am @@ -0,0 +1,19 @@ +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdimgeditortools.la + +libdimgeditortools_la_SOURCES = imageresize.cpp imageprint.cpp + +libdimgeditortools_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TDEPRINT) + +INCLUDES= -I$(top_srcdir)/src/digikam \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/greycstoration \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/utilities/imageeditor/editor \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + diff --git a/src/utilities/imageeditor/tools/imageprint.cpp b/src/utilities/imageeditor/tools/imageprint.cpp new file mode 100644 index 00000000..5cab236b --- /dev/null +++ b/src/utilities/imageeditor/tools/imageprint.cpp @@ -0,0 +1,814 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-13 + * Description : image editor printing interface. + * + * Copyright (C) 2006 by F.J. Cruz <fj.cruz@supercable.es> + * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * KeepRatio and Alignment options imported from Gwenview program. + * Copyright (c) 2003 Angelo Naselli <anaselli at linux dot it> + * + * Original printing code from Kuickshow program. + * Copyright (C) 2002 Carsten Pfeiffer <pfeiffer at kde.org> + * + * 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 <tqobject.h> +#include <tqpixmap.h> +#include <tqlayout.h> +#include <tqgroupbox.h> +#include <tqbuttongroup.h> +#include <tqstring.h> +#include <tqsize.h> +#include <tqcursor.h> +#include <tqlabel.h> +#include <tqhbox.h> +#include <tqcheckbox.h> +#include <tqfont.h> +#include <tqgrid.h> +#include <tqimage.h> +#include <tqpaintdevicemetrics.h> +#include <tqpainter.h> +#include <tqradiobutton.h> +#include <tqvbuttongroup.h> +#include <tqcolor.h> +#include <tqcombobox.h> +#include <tqstyle.h> +#include <tqpushbutton.h> + +// KDE includes. + +#include <tdelocale.h> +#include <tdemessagebox.h> +#include <kstandarddirs.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <kimageio.h> +#include <kcombobox.h> +#include <tdeglobalsettings.h> +#include <knuminput.h> +#include <kprinter.h> +#include <tdetempfile.h> +#include <kpropertiesdialog.h> + +// Local includes. + +#include "ddebug.h" +#include "dimg.h" +#include "editorwindow.h" +#include "icctransform.h" +#include "imageprint.h" +#include "imageprint.moc" + +namespace Digikam +{ + +class ImagePrintPrivate +{ + +public: + + ImagePrintPrivate(){} + + TQString filename; + TQString inProfilePath; + TQString outputProfilePath; + + DImg image; +}; + +ImagePrint::ImagePrint(DImg& image, KPrinter& printer, const TQString& filename) + : m_printer(printer) +{ + d = new ImagePrintPrivate(); + d->image = image; + d->filename = filename; +} + +ImagePrint::~ImagePrint() +{ + delete d; +} + +bool ImagePrint::printImageWithTQt() +{ + if ( d->image.isNull() ) + { + DWarning() << "Supplied Image for printing is null" << endl; + return false; + } + + TQString t = "true"; + TQString f = "false"; + + if (m_printer.option( "app-imageeditor-color-managed") != f) + { + IccTransform *transform = new IccTransform(); + readSettings(); + + if (d->image.getICCProfil().isNull()) + { + transform->setProfiles( d->inProfilePath, d->outputProfilePath ); + } + else + { + transform->setProfiles(d->outputProfilePath); + } + + transform->apply( d->image ); + } + + TQImage image2Print = d->image.copyTQImage(); + + // Black & white print ? + if ( m_printer.option( "app-imageeditor-blackwhite" ) != f) + { + image2Print = image2Print.convertDepth( 1, TQt::MonoOnly | + TQt::ThresholdDither | + TQt::AvoidDither ); + } + + TQPainter p; + p.begin( &m_printer ); + + TQPaintDeviceMetrics metrics( &m_printer ); + p.setFont( TDEGlobalSettings::generalFont() ); + TQFontMetrics fm = p.fontMetrics(); + + int w, h; // will be set to the width and height of the printer + // when the orientation is decided. + w = metrics.width(); + h = metrics.height(); + int filenameOffset = 0; + + TQSize size = image2Print.size(); + + bool printFilename = m_printer.option( "app-imageeditor-printFilename" ) != f; + if ( printFilename ) + { + // filename goes into one line! + filenameOffset = fm.lineSpacing() + 14; + h -= filenameOffset; + } + + if ( m_printer.option( "app-imageeditor-scaleToFit" ) != f ) + { + if ( m_printer.option( "app-imageeditor-auto-rotate" ) == t ) + m_printer.setOrientation( size.width() <= size.height() ? KPrinter::Portrait + : KPrinter::Landscape ); + + // Scale image to fit pagesize + size.scale( w, h, TQSize::ScaleMin ); + } + else + { + int unit = (m_printer.option("app-imageeditor-scale-unit").isEmpty() ? + ImageEditorPrintDialogPage::DK_INCHES : m_printer.option("app-imageeditor-scale-unit").toInt()); + double inches = 1; + + if (unit == ImageEditorPrintDialogPage::DK_MILLIMETERS) + { + inches = 1/25.4; + } + else if (unit == ImageEditorPrintDialogPage::DK_CENTIMETERS) + { + inches = 1/2.54; + } + + double wImg = (m_printer.option("app-imageeditor-scale-width").isEmpty() ? + 1 : m_printer.option("app-imageeditor-scale-width").toDouble()) * inches; + double hImg = (m_printer.option("app-imageeditor-scale-height").isEmpty() ? + 1 : m_printer.option("app-imageeditor-scale-height").toDouble()) * inches; + size.setWidth( int(wImg * m_printer.resolution()) ); + size.setHeight( int(hImg * m_printer.resolution()) ); + + if ( m_printer.option( "app-imageeditor-auto-rotate" ) == t ) + m_printer.setOrientation( wImg <= hImg ? KPrinter::Portrait : KPrinter::Landscape ); + + if (size.width() > w || size.height() > h) + { + int resp = KMessageBox::warningYesNoCancel(TDEApplication::kApplication()->mainWidget(), + i18n("The image will not fit on the page, what do you want to do?"), + TQString(),KStdGuiItem::cont(), + i18n("Shrink") ); + + if (resp==KMessageBox::Cancel) + { + m_printer.abort(); + // no need to return false, user decided to abort + return true; + } + else if (resp == KMessageBox::No) + { // Shrink + size.scale(w, h, TQSize::ScaleMin); + } + } + } + + // Align image. + int alignment = (m_printer.option("app-imageeditor-alignment").isEmpty() ? + TQt::AlignCenter : m_printer.option("app-imageeditor-alignment").toInt()); + + int x = 0; + int y = 0; + + // x - alignment + if ( alignment & TQt::AlignHCenter ) + x = (w - size.width())/2; + else if ( alignment & TQt::AlignLeft ) + x = 0; + else if ( alignment & TQt::AlignRight ) + x = w - size.width(); + + // y - alignment + if ( alignment & TQt::AlignVCenter ) + y = (h - size.height())/2; + else if ( alignment & TQt::AlignTop ) + y = 0; + else if ( alignment & TQt::AlignBottom ) + y = h - size.height(); + + // Perform the actual drawing. + p.drawImage( TQRect( x, y, size.width(), size.height()), image2Print ); + + if ( printFilename ) + { + TQString fname = minimizeString( d->filename, fm, w ); + + if ( !fname.isEmpty() ) + { + int fw = fm.width( fname ); + int x = (w - fw)/2; + int y = metrics.height() - filenameOffset/2; + p.drawText( x, y, fname ); + } + } + + p.end(); + + return true; +} + +TQString ImagePrint::minimizeString( TQString text, const TQFontMetrics& metrics, + int maxWidth ) +{ + // no sense to cut that tiny little string + if ( text.length() <= 5 ) + return TQString(); + + bool changed = false; + + while ( metrics.width( text ) > maxWidth ) + { + int mid = text.length() / 2; + // remove 2 characters in the middle + text.remove( mid, 2 ); + changed = true; + } + + // add "..." in the middle + if ( changed ) + { + int mid = text.length() / 2; + + // sanity check + if ( mid <= 5 ) + return TQString(); + + text.replace( mid - 1, 3, "..." ); + } + + return text; +} + +void ImagePrint::readSettings() +{ + TDEConfig* config = kapp->config(); + + config->setGroup("Color Management"); + + d->inProfilePath = config->readPathEntry("WorkSpaceProfile"); + d->outputProfilePath = config->readPathEntry("ProofProfileFile"); +} + +// Image print dialog class ------------------------------------------------------------- + +class ImageEditorPrintDialogPagePrivate +{ + +public: + + ImageEditorPrintDialogPagePrivate() + { + cmEnabled = false; + position = 0; + keepRatio = 0; + scaleToFit = 0; + scale = 0; + addFileName = 0; + blackwhite = 0; + autoRotate = 0; + colorManaged = 0; + cmPreferences = 0; + parent = 0; + width = 0; + height = 0; + units = 0; + } + + bool cmEnabled; + + TQRadioButton *scaleToFit; + TQRadioButton *scale; + + TQCheckBox *keepRatio; + TQCheckBox *addFileName; + TQCheckBox *blackwhite; + TQCheckBox *autoRotate; + TQCheckBox *colorManaged; + + TQPushButton *cmPreferences; + + TQWidget *parent; + + KDoubleNumInput *width; + KDoubleNumInput *height; + + KComboBox *position; + KComboBox *units; + + DImg image; + + ImageEditorPrintDialogPage::Unit previousUnit; +}; + +ImageEditorPrintDialogPage::ImageEditorPrintDialogPage(DImg& image, TQWidget *parent, const char *name ) + : KPrintDialogPage( parent, name ) +{ + d = new ImageEditorPrintDialogPagePrivate; + d->image = image; + d->parent = parent; + setTitle( i18n("Image Settings") ); + + readSettings(); + + TQVBoxLayout *layout = new TQVBoxLayout( this ); + layout->setMargin( KDialog::marginHint() ); + layout->setSpacing( KDialog::spacingHint() ); + + // ------------------------------------------------------------------------ + + TQHBoxLayout *layout2 = new TQHBoxLayout( layout ); + layout2->setSpacing(3); + + TQLabel* textLabel = new TQLabel( this, "Image position:" ); + textLabel->setText( i18n( "Image position:" ) ); + layout2->addWidget( textLabel ); + d->position = new KComboBox( false, this, "Print position" ); + d->position->clear(); + d->position->insertItem( i18n( "Top-Left" ) ); + d->position->insertItem( i18n( "Top-Central" ) ); + d->position->insertItem( i18n( "Top-Right" ) ); + d->position->insertItem( i18n( "Central-Left" ) ); + d->position->insertItem( i18n( "Central" ) ); + d->position->insertItem( i18n( "Central-Right" ) ); + d->position->insertItem( i18n( "Bottom-Left" ) ); + d->position->insertItem( i18n( "Bottom-Central" ) ); + d->position->insertItem( i18n( "Bottom-Right" ) ); + layout2->addWidget( d->position ); + TQSpacerItem *spacer1 = new TQSpacerItem( 101, 21, TQSizePolicy::Expanding, TQSizePolicy::Minimum ); + layout2->addItem( spacer1 ); + + d->addFileName = new TQCheckBox( i18n("Print fi&lename below image"), this); + d->addFileName->setChecked( false ); + layout->addWidget( d->addFileName ); + + d->blackwhite = new TQCheckBox ( i18n("Print image in &black and white"), this); + d->blackwhite->setChecked( false ); + layout->addWidget (d->blackwhite ); + + d->autoRotate = new TQCheckBox( i18n("&Auto-rotate page"), this ); + d->autoRotate->setChecked( false ); + layout->addWidget( d->autoRotate ); + + // ------------------------------------------------------------------------ + + TQHBox *cmbox = new TQHBox(this); + + d->colorManaged = new TQCheckBox(i18n("Use Color Management for Printing"), cmbox); + d->colorManaged->setChecked( false ); + + d->cmPreferences = new TQPushButton(i18n("Settings..."), cmbox); + + TQWidget *space = new TQWidget(cmbox); + cmbox->setStretchFactor(space, 10); + cmbox->setSpacing(KDialog::spacingHint()); + + layout->addWidget(cmbox); + + // ------------------------------------------------------------------------ + + TQVButtonGroup *group = new TQVButtonGroup( i18n("Scaling"), this ); + group->setRadioButtonExclusive( true ); + layout->addWidget( group ); + + d->scaleToFit = new TQRadioButton( i18n("Scale image to &fit"), group ); + d->scaleToFit->setChecked( true ); + + d->scale = new TQRadioButton( i18n("Print e&xact size: "), group ); + + TQHBox *hb = new TQHBox( group ); + hb->setSpacing( KDialog::spacingHint() ); + TQWidget *w = new TQWidget(hb); + w->setFixedWidth(d->scale->style().subRect( TQStyle::SR_RadioButtonIndicator, d->scale ).width()); + + d->width = new KDoubleNumInput( hb, "exact width" ); + d->width->setMinValue( 1 ); + + new TQLabel( "x", hb ); + + d->height = new KDoubleNumInput( hb, "exact height" ); + d->height->setMinValue( 1 ); + + d->units = new KComboBox( false, hb, "unit combobox" ); + d->units->insertItem( i18n("Millimeters") ); + d->units->insertItem( i18n("Centimeters") ); + d->units->insertItem( i18n("Inches") ); + + d->keepRatio = new TQCheckBox( i18n("Keep ratio"), hb); + + w = new TQWidget(hb); + hb->setStretchFactor( w, 1 ); + d->previousUnit = DK_MILLIMETERS; + + // ------------------------------------------------------------------------ + + connect( d->colorManaged, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotAlertSettings( bool )) ); + + connect( d->cmPreferences, TQ_SIGNAL(clicked()), + this, TQ_SLOT(slotSetupDlg()) ); + + connect( d->scale, TQ_SIGNAL( toggled( bool )), + this, TQ_SLOT( toggleScaling( bool ))); + + connect(d->width, TQ_SIGNAL( valueChanged( double )), + this, TQ_SLOT( slotWidthChanged( double ))); + + connect(d->height, TQ_SIGNAL( valueChanged( double )), + this, TQ_SLOT( slotHeightChanged( double ))); + + connect(d->keepRatio, TQ_SIGNAL( toggled( bool )), + this, TQ_SLOT( toggleRatio( bool ))); + + connect(d->units, TQ_SIGNAL(activated(const TQString &)), + this, TQ_SLOT(slotUnitChanged(const TQString& ))); +} + +ImageEditorPrintDialogPage::~ImageEditorPrintDialogPage() +{ + delete d; +} + +void ImageEditorPrintDialogPage::getOptions( TQMap<TQString,TQString>& opts, bool /*incldef*/ ) +{ + TQString t = "true"; + TQString f = "false"; + + opts["app-imageeditor-alignment"] = TQString::number(getPosition(d->position->currentText())); + opts["app-imageeditor-printFilename"] = d->addFileName->isChecked() ? t : f; + opts["app-imageeditor-blackwhite"] = d->blackwhite->isChecked() ? t : f; + opts["app-imageeditor-scaleToFit"] = d->scaleToFit->isChecked() ? t : f; + opts["app-imageeditor-scale"] = d->scale->isChecked() ? t : f; + opts["app-imageeditor-scale-unit"] = TQString::number(stringToUnit(d->units->currentText())); + opts["app-imageeditor-scale-width"] = TQString::number( d->width->value() ); + opts["app-imageeditor-scale-height"] = TQString::number( d->height->value() ); + opts["app-imageeditor-scale-KeepRatio"] = d->keepRatio->isChecked() ? t : f; + opts["app-imageeditor-auto-rotate"] = d->autoRotate->isChecked() ? t : f; + opts["app-imageeditor-color-managed"] = d->colorManaged->isChecked() ? t : f; +} + +void ImageEditorPrintDialogPage::setOptions( const TQMap<TQString,TQString>& opts ) +{ + TQString t = "true"; + TQString f = "false"; + TQString stVal; + bool ok; + double dVal; + int iVal; + + iVal = opts["app-imageeditor-alignment"].toInt( &ok ); + if (ok) + { + stVal = setPosition(iVal); + d->position->setCurrentItem(stVal); + } + + d->addFileName->setChecked( opts["app-imageeditor-printFilename"] != f ); + // This sound strange, but if I copy the code on the line above, the checkbox + // was always checked. And this is not the wanted behavior. So, with this works. + // KPrint magic ;-) + d->blackwhite->setChecked ( false ); + d->scaleToFit->setChecked( opts["app-imageeditor-scaleToFit"] != f ); + d->scale->setChecked( opts["app-imageeditor-scale"] == t ); + d->autoRotate->setChecked( opts["app-imageeditor-auto-rotate"] == t ); + + d->colorManaged->setChecked( false ); + + Unit unit = static_cast<Unit>( opts["app-imageeditor-scale-unit"].toInt( &ok ) ); + if (ok) + { + stVal = unitToString(unit); + d->units->setCurrentItem(stVal); + d->previousUnit = unit; + } + else + { + //for back compatibility + d->units->setCurrentItem(i18n("Millimeters")); + } + + dVal = opts["app-imageeditor-scale-width"].toDouble( &ok ); + + if ( ok ) + d->width->setValue( dVal ); + + dVal = opts["app-imageeditor-scale-height"].toDouble( &ok ); + + if ( ok ) + d->height->setValue( dVal ); + + if ( d->scale->isChecked() == d->scaleToFit->isChecked() ) + d->scaleToFit->setChecked( !d->scale->isChecked() ); + + d->keepRatio->setChecked( opts["app-imageeditor-scale-KeepRatio"] == t ); + +} +int ImageEditorPrintDialogPage::getPosition(const TQString& align) +{ + int alignment; + + if (align == i18n("Central-Left")) + { + alignment = TQt::AlignLeft | TQt::AlignVCenter; + } + else if (align == i18n("Central-Right")) + { + alignment = TQt::AlignRight | TQt::AlignVCenter; + } + else if (align == i18n("Top-Left")) + { + alignment = TQt::AlignTop | TQt::AlignLeft; + } + else if (align == i18n("Top-Right")) + { + alignment = TQt::AlignTop | TQt::AlignRight; + } + else if (align == i18n("Bottom-Left")) + { + alignment = TQt::AlignBottom | TQt::AlignLeft; + } + else if (align == i18n("Bottom-Right")) + { + alignment = TQt::AlignBottom | TQt::AlignRight; + } + else if (align == i18n("Top-Central")) + { + alignment = TQt::AlignTop | TQt::AlignHCenter; + } + else if (align == i18n("Bottom-Central")) + { + alignment = TQt::AlignBottom | TQt::AlignHCenter; + } + else + { + // Central + alignment = TQt::AlignCenter; // TQt::AlignHCenter || TQt::AlignVCenter + } + + return alignment; +} + +TQString ImageEditorPrintDialogPage::setPosition(int align) +{ + TQString alignment; + + if (align == (TQt::AlignLeft | TQt::AlignVCenter)) + { + alignment = i18n("Central-Left"); + } + else if (align == (TQt::AlignRight | TQt::AlignVCenter)) + { + alignment = i18n("Central-Right"); + } + else if (align == (TQt::AlignTop | TQt::AlignLeft)) + { + alignment = i18n("Top-Left"); + } + else if (align == (TQt::AlignTop | TQt::AlignRight)) + { + alignment = i18n("Top-Right"); + } + else if (align == (TQt::AlignBottom | TQt::AlignLeft)) + { + alignment = i18n("Bottom-Left"); + } + else if (align == (TQt::AlignBottom | TQt::AlignRight)) + { + alignment = i18n("Bottom-Right"); + } + else if (align == (TQt::AlignTop | TQt::AlignHCenter)) + { + alignment = i18n("Top-Central"); + } + else if (align == (TQt::AlignBottom | TQt::AlignHCenter)) + { + alignment = i18n("Bottom-Central"); + } + else + { + // Central: TQt::AlignCenter or (TQt::AlignHCenter || TQt::AlignVCenter) + alignment = i18n("Central"); + } + + return alignment; +} + +void ImageEditorPrintDialogPage::toggleScaling( bool enable ) +{ + d->width->setEnabled( enable ); + d->height->setEnabled( enable ); + d->units->setEnabled( enable ); + d->keepRatio->setEnabled( enable ); +} + +void ImageEditorPrintDialogPage::slotHeightChanged (double value) +{ + d->width->blockSignals(true); + d->height->blockSignals(true); + + if (d->keepRatio->isChecked()) + { + double width = (d->image.width() * value) / d->image.height(); + d->width->setValue( width ? width : 1.); + } + d->height->setValue(value); + + d->width->blockSignals(false); + d->height->blockSignals(false); +} + +void ImageEditorPrintDialogPage::slotWidthChanged (double value) +{ + d->width->blockSignals(true); + d->height->blockSignals(true); + + if (d->keepRatio->isChecked()) + { + double height = (d->image.height() * value) / d->image.width(); + d->height->setValue( height ? height : 1); + } + d->width->setValue(value); + + d->width->blockSignals(false); + d->height->blockSignals(false); +} + +void ImageEditorPrintDialogPage::toggleRatio( bool enable ) +{ + if (!enable) return; + // choosing a startup value of 15x10 cm (common photo dimention) + // mContent->mHeight->value() or mContent->mWidth->value() + // are usually empty at startup and hxw (0x0) is not good IMO keeping ratio + double hValue, wValue; + if (d->image.height() > d->image.width()) + { + hValue = d->height->value(); + if (!hValue) hValue = 150*unitToMM(d->previousUnit); + wValue = (d->image.width() * hValue)/ d->image.height(); + } + else + { + wValue = d->width->value(); + if (!wValue) wValue = 150*unitToMM(d->previousUnit); + hValue = (d->image.height() * wValue)/ d->image.width(); + } + + d->width->blockSignals(true); + d->height->blockSignals(true); + + d->width->setValue(wValue); + d->height->setValue(hValue); + + d->width->blockSignals(false); + d->height->blockSignals(false); +} + +void ImageEditorPrintDialogPage::slotUnitChanged(const TQString& string) +{ + Unit newUnit = stringToUnit(string); + double ratio = unitToMM(d->previousUnit) / unitToMM(newUnit); + + d->width->blockSignals(true); + d->height->blockSignals(true); + + d->width->setValue( d->width->value() * ratio); + d->height->setValue( d->height->value() * ratio); + + d->width->blockSignals(false); + d->height->blockSignals(false); + + d->previousUnit = newUnit; +} + +void ImageEditorPrintDialogPage::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("Color Management"); + d->cmEnabled = config->readBoolEntry("EnableCM", false); +} + +void ImageEditorPrintDialogPage::slotSetupDlg() +{ + EditorWindow* editor = dynamic_cast<EditorWindow*>(d->parent); + editor->setup(true); +} + +void ImageEditorPrintDialogPage::slotAlertSettings( bool t) +{ + if (t && !d->cmEnabled) + { + TQString message = i18n("<p>Color Management is disabled.</p> \ + <p>You can enable it now by clicking on the \"Settings\" button.</p>"); + KMessageBox::information(this, message); + d->colorManaged->setChecked(!t); + } +} + +double ImageEditorPrintDialogPage::unitToMM(Unit unit) +{ + if (unit == DK_MILLIMETERS) + { + return 1.; + } + else if (unit == DK_CENTIMETERS) + { + return 10.; + } + else + { //DK_INCHES + return 25.4; + } +} + +ImageEditorPrintDialogPage::Unit ImageEditorPrintDialogPage::stringToUnit(const TQString& unit) +{ + if (unit == i18n("Millimeters")) + { + return DK_MILLIMETERS; + } + else if (unit == i18n("Centimeters")) + { + return DK_CENTIMETERS; + } + else + {//Inches + return DK_INCHES; + } +} + +TQString ImageEditorPrintDialogPage::unitToString(Unit unit) +{ + if (unit == DK_MILLIMETERS) + { + return i18n("Millimeters"); + } + else if (unit == DK_CENTIMETERS) + { + return i18n("Centimeters"); + } + else + { //DK_INCHES + return i18n("Inches"); + } +} + +} // namespace Digikam + diff --git a/src/utilities/imageeditor/tools/imageprint.h b/src/utilities/imageeditor/tools/imageprint.h new file mode 100644 index 00000000..66276701 --- /dev/null +++ b/src/utilities/imageeditor/tools/imageprint.h @@ -0,0 +1,122 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2004-07-13 + * Description : image editor printing interface. + * + * Copyright (C) 2006 by F.J. Cruz <fj.cruz@supercable.es> + * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGEPRINT_H +#define IMAGEPRINT_H + +// TQt includes. + +#include <tqwidget.h> +#include <tqstring.h> + +// KDE includes. + +#include <kurl.h> +#include <kprinter.h> +#include <tdeprint/kprintdialogpage.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class ImagePrintPrivate; + +class DIGIKAM_EXPORT ImagePrint +{ +public: + + ImagePrint(DImg& image, KPrinter& printer, const TQString& fileName); + ~ImagePrint(); + + bool printImageWithTQt(); + +private: + + TQString minimizeString(TQString text, const TQFontMetrics& metrics, int maxWidth); + void readSettings(); + +private: + + KPrinter& m_printer; + + ImagePrintPrivate *d; +}; + +//----------------------------------------------------------------------------- + +class ImageEditorPrintDialogPagePrivate; + +class DIGIKAM_EXPORT ImageEditorPrintDialogPage : public KPrintDialogPage +{ + TQ_OBJECT + + +public: + + enum Unit + { + DK_MILLIMETERS = 1, + DK_CENTIMETERS, + DK_INCHES + }; + + static inline double unitToMM(Unit unit); + static inline Unit stringToUnit(const TQString& unit); + static inline TQString unitToString(Unit unit); + +public: + + ImageEditorPrintDialogPage(DImg& image, TQWidget *parent=0L, const char *name=0); + ~ImageEditorPrintDialogPage(); + + virtual void getOptions(TQMap<TQString,TQString>& opts, bool incldef = false); + virtual void setOptions(const TQMap<TQString,TQString>& opts); + +private slots: + + void toggleScaling( bool enable ); + void toggleRatio( bool enable ); + void slotUnitChanged(const TQString& string); + void slotHeightChanged(double value); + void slotWidthChanged(double value); + void slotSetupDlg(); + void slotAlertSettings(bool t); + +private: + + void readSettings(); + int getPosition(const TQString& align); + TQString setPosition(int align); + +private: + + ImageEditorPrintDialogPagePrivate *d; +}; + +} // namespace Digikam + +#endif // IMAGEPRINT_H diff --git a/src/utilities/imageeditor/tools/imageresize.cpp b/src/utilities/imageeditor/tools/imageresize.cpp new file mode 100644 index 00000000..c779b71e --- /dev/null +++ b/src/utilities/imageeditor/tools/imageresize.cpp @@ -0,0 +1,650 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-04-07 + * Description : a tool to resize an image + * + * Copyright (C) 2005-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include <cmath> + +// TQt includes. + +#include <tqvgroupbox.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqtooltip.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqframe.h> +#include <tqcheckbox.h> +#include <tqcombobox.h> +#include <tqtabwidget.h> +#include <tqtimer.h> +#include <tqevent.h> +#include <tqpixmap.h> +#include <tqbrush.h> +#include <tqfile.h> +#include <tqimage.h> + +// KDE includes. + +#include <kseparator.h> +#include <kcursor.h> +#include <kurllabel.h> +#include <tdelocale.h> +#include <kiconloader.h> +#include <tdeapplication.h> +#include <tdefiledialog.h> +#include <kstandarddirs.h> +#include <kprogress.h> +#include <tdemessagebox.h> +#include <knuminput.h> +#include <tdeglobalsettings.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> + +// Digikam includes. + +#include "dimg.h" +#include "ddebug.h" +#include "imageiface.h" +#include "dimgthreadedfilter.h" +#include "greycstorationiface.h" +#include "greycstorationwidget.h" +#include "greycstorationsettings.h" + +// Local includes. + +#include "imageresize.h" +#include "imageresize.moc" + +using namespace KDcrawIface; + +namespace Digikam +{ + +class ImageResizePriv +{ +public: + + enum RunningMode + { + NoneRendering=0, + FinalRendering + }; + + ImageResizePriv() + { + currentRenderingMode = NoneRendering; + parent = 0; + preserveRatioBox = 0; + useGreycstorationBox = 0; + mainTab = 0; + wInput = 0; + hInput = 0; + wpInput = 0; + hpInput = 0; + progressBar = 0; + greycstorationIface = 0; + settingsWidget = 0; + cimgLogoLabel = 0; + restorationTips = 0; + } + + int currentRenderingMode; + int orgWidth; + int orgHeight; + int prevW; + int prevH; + + double prevWP; + double prevHP; + + TQWidget *parent; + + TQLabel *restorationTips; + + TQCheckBox *preserveRatioBox; + TQCheckBox *useGreycstorationBox; + + TQTabWidget *mainTab; + + RIntNumInput *wInput; + RIntNumInput *hInput; + + RDoubleNumInput *wpInput; + RDoubleNumInput *hpInput; + + KProgress *progressBar; + + KURLLabel *cimgLogoLabel; + + GreycstorationIface *greycstorationIface; + GreycstorationWidget *settingsWidget; +}; + +ImageResize::ImageResize(TQWidget* parent) + : KDialogBase(Plain, i18n("Resize Image"), + Help|Default|User2|User3|Ok|Cancel, Ok, + parent, 0, true, false, + TQString(), + i18n("&Save As..."), + i18n("&Load...")) +{ + d = new ImageResizePriv; + d->parent = parent; + setHelp("resizetool.anchor", "digikam"); + TQString whatsThis; + setButtonWhatsThis( Default, i18n("<p>Reset all filter parameters to their default values.") ); + setButtonWhatsThis( User3, i18n("<p>Load all filter parameters from settings text file.") ); + setButtonWhatsThis( User2, i18n("<p>Save all filter parameters to settings text file.") ); + enableButton(Ok, false); + + ImageIface iface(0, 0); + d->orgWidth = iface.originalWidth(); + d->orgHeight = iface.originalHeight(); + d->prevW = d->orgWidth; + d->prevH = d->orgHeight; + d->prevWP = 100.0; + d->prevHP = 100.0; + + // ------------------------------------------------------------- + + TQVBoxLayout *vlay = new TQVBoxLayout(plainPage(), 0, spacingHint()); + d->mainTab = new TQTabWidget( plainPage() ); + + TQWidget* firstPage = new TQWidget( d->mainTab ); + TQGridLayout* grid = new TQGridLayout( firstPage, 8, 2, spacingHint()); + d->mainTab->addTab( firstPage, i18n("New Size") ); + + TQLabel *label1 = new TQLabel(i18n("Width:"), firstPage); + d->wInput = new RIntNumInput(firstPage); + d->wInput->setRange(1, TQMAX(d->orgWidth * 10, 9999), 1); + d->wInput->setName("d->wInput"); + d->wInput->setDefaultValue(d->orgWidth); + TQWhatsThis::add( d->wInput, i18n("<p>Set here the new image width in pixels.")); + + TQLabel *label2 = new TQLabel(i18n("Height:"), firstPage); + d->hInput = new RIntNumInput(firstPage); + d->hInput->setRange(1, TQMAX(d->orgHeight * 10, 9999), 1); + d->hInput->setName("d->hInput"); + d->hInput->setDefaultValue(d->orgHeight); + TQWhatsThis::add( d->hInput, i18n("<p>Set here the new image height in pixels.")); + + TQLabel *label3 = new TQLabel(i18n("Width (%):"), firstPage); + d->wpInput = new RDoubleNumInput(firstPage); + d->wpInput->setRange(1.0, 999.0, 1.0); + d->wpInput->setName("d->wpInput"); + d->wpInput->setDefaultValue(100.0); + TQWhatsThis::add( d->wpInput, i18n("<p>Set here the new image width in percent.")); + + TQLabel *label4 = new TQLabel(i18n("Height (%):"), firstPage); + d->hpInput = new RDoubleNumInput(firstPage); + d->hpInput->setRange(1.0, 999.0, 1.0); + d->hpInput->setName("d->hpInput"); + d->hpInput->setDefaultValue(100.0); + TQWhatsThis::add( d->hpInput, i18n("<p>Set here the new image height in percent.")); + + d->preserveRatioBox = new TQCheckBox(i18n("Maintain aspect ratio"), firstPage); + TQWhatsThis::add( d->preserveRatioBox, i18n("<p>Enable this option to maintain aspect " + "ratio with new image sizes.")); + + d->cimgLogoLabel = new KURLLabel(firstPage); + d->cimgLogoLabel->setText(TQString()); + d->cimgLogoLabel->setURL("http://cimg.sourceforge.net"); + TDEGlobal::dirs()->addResourceType("logo-cimg", TDEGlobal::dirs()->kde_default("data") + + "digikam/data"); + TQString directory = TDEGlobal::dirs()->findResourceDir("logo-cimg", "logo-cimg.png"); + d->cimgLogoLabel->setPixmap( TQPixmap( directory + "logo-cimg.png" ) ); + TQToolTip::add(d->cimgLogoLabel, i18n("Visit CImg library website")); + + d->useGreycstorationBox = new TQCheckBox(i18n("Restore photograph"), firstPage); + TQWhatsThis::add( d->useGreycstorationBox, i18n("<p>Enable this option to restore photograph content. " + "This way is usefull to scale-up an image to an huge size. " + "Warning: this process can take a while.")); + + d->restorationTips = new TQLabel(i18n("<b>Note: use Restoration Mode to only scale-up an image to huge size. " + "Warning, this process can take a while.</b>"), firstPage); + + d->progressBar = new KProgress(100, firstPage); + d->progressBar->setValue(0); + TQWhatsThis::add(d->progressBar, i18n("<p>This shows the current progress when you use Restoration mode.")); + + grid->addMultiCellWidget(d->preserveRatioBox, 0, 0, 0, 2); + grid->addMultiCellWidget(label1, 1, 1, 0, 0); + grid->addMultiCellWidget(d->wInput, 1, 1, 1, 2); + grid->addMultiCellWidget(label2, 2, 2, 0, 0); + grid->addMultiCellWidget(d->hInput, 2, 2, 1, 2); + grid->addMultiCellWidget(label3, 3, 3, 0, 0); + grid->addMultiCellWidget(d->wpInput, 3, 3, 1, 2); + grid->addMultiCellWidget(label4, 4, 4, 0, 0); + grid->addMultiCellWidget(d->hpInput, 4, 4, 1, 2); + grid->addMultiCellWidget(new KSeparator(firstPage), 5, 5, 0, 2); + grid->addMultiCellWidget(d->cimgLogoLabel, 6, 8, 0, 0); + grid->addMultiCellWidget(d->useGreycstorationBox, 6, 6, 1, 2); + grid->addMultiCellWidget(d->restorationTips, 7, 7, 1, 2); + grid->addMultiCellWidget(d->progressBar, 8, 8, 1, 2); + grid->setRowStretch(8, 10); + + // ------------------------------------------------------------- + + d->settingsWidget = new GreycstorationWidget(d->mainTab); + vlay->addWidget(d->mainTab); + + // ------------------------------------------------------------- + + adjustSize(); + disableResize(); + TQTimer::singleShot(0, this, TQ_SLOT(readUserSettings())); + + // ------------------------------------------------------------- + + connect(d->cimgLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)), + this, TQ_SLOT(processCImgURL(const TQString&))); + + connect(d->wInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotValuesChanged())); + + connect(d->hInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotValuesChanged())); + + connect(d->wpInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotValuesChanged())); + + connect(d->hpInput, TQ_SIGNAL(valueChanged(double)), + this, TQ_SLOT(slotValuesChanged())); + + connect(d->useGreycstorationBox, TQ_SIGNAL(toggled(bool)), + this, TQ_SLOT(slotRestorationToggled(bool)) ); + + // ------------------------------------------------------------- + + Digikam::GreycstorationSettings defaults; + defaults.setResizeDefaultSettings(); + d->settingsWidget->setDefaultSettings(defaults); +} + +ImageResize::~ImageResize() +{ + if (d->greycstorationIface) + delete d->greycstorationIface; + + delete d; +} + +void ImageResize::slotRestorationToggled(bool b) +{ + d->settingsWidget->setEnabled(b); + d->progressBar->setEnabled(b); + d->cimgLogoLabel->setEnabled(b); + enableButton(User2, b); + enableButton(User3, b); +} + +void ImageResize::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("resize Tool Dialog"); + + GreycstorationSettings settings; + GreycstorationSettings defaults; + defaults.setResizeDefaultSettings(); + + settings.fastApprox = config->readBoolEntry("FastApprox", defaults.fastApprox); + settings.interp = config->readNumEntry("Interpolation", defaults.interp); + settings.amplitude = config->readDoubleNumEntry("Amplitude", defaults.amplitude); + settings.sharpness = config->readDoubleNumEntry("Sharpness", defaults.sharpness); + settings.anisotropy = config->readDoubleNumEntry("Anisotropy", defaults.anisotropy); + settings.alpha = config->readDoubleNumEntry("Alpha", defaults.alpha); + settings.sigma = config->readDoubleNumEntry("Sigma", defaults.sigma); + settings.gaussPrec = config->readDoubleNumEntry("GaussPrec", defaults.gaussPrec); + settings.dl = config->readDoubleNumEntry("Dl", defaults.dl); + settings.da = config->readDoubleNumEntry("Da", defaults.da); + settings.nbIter = config->readNumEntry("Iteration", defaults.nbIter); + settings.tile = config->readNumEntry("Tile", defaults.tile); + settings.btile = config->readNumEntry("BTile", defaults.btile); + d->settingsWidget->setSettings(settings); + + d->useGreycstorationBox->setChecked(config->readBoolEntry("RestorePhotograph", false)); + slotRestorationToggled(d->useGreycstorationBox->isChecked()); + + d->preserveRatioBox->blockSignals(true); + d->wInput->blockSignals(true); + d->hInput->blockSignals(true); + d->wpInput->blockSignals(true); + d->hpInput->blockSignals(true); + + d->preserveRatioBox->setChecked(true); + d->wInput->slotReset(); + d->hInput->slotReset(); + d->wpInput->slotReset(); + d->hpInput->slotReset(); + + d->preserveRatioBox->blockSignals(false); + d->wInput->blockSignals(false); + d->hInput->blockSignals(false); + d->wpInput->blockSignals(false); + d->hpInput->blockSignals(false); +} + +void ImageResize::writeUserSettings() +{ + GreycstorationSettings settings = d->settingsWidget->getSettings(); + TDEConfig* config = kapp->config(); + config->setGroup("resize Tool Dialog"); + config->writeEntry("FastApprox", settings.fastApprox); + config->writeEntry("Interpolation", settings.interp); + config->writeEntry("Amplitude", settings.amplitude); + config->writeEntry("Sharpness", settings.sharpness); + config->writeEntry("Anisotropy", settings.anisotropy); + config->writeEntry("Alpha", settings.alpha); + config->writeEntry("Sigma", settings.sigma); + config->writeEntry("GaussPrec", settings.gaussPrec); + config->writeEntry("Dl", settings.dl); + config->writeEntry("Da", settings.da); + config->writeEntry("Iteration", settings.nbIter); + config->writeEntry("Tile", settings.tile); + config->writeEntry("BTile", settings.btile); + config->writeEntry("RestorePhotograph", d->useGreycstorationBox->isChecked()); + config->sync(); +} + +void ImageResize::slotDefault() +{ + GreycstorationSettings settings; + settings.setResizeDefaultSettings(); + + d->settingsWidget->setSettings(settings); + d->useGreycstorationBox->setChecked(false); + slotRestorationToggled(d->useGreycstorationBox->isChecked()); + + d->preserveRatioBox->blockSignals(true); + d->wInput->blockSignals(true); + d->hInput->blockSignals(true); + d->wpInput->blockSignals(true); + d->hpInput->blockSignals(true); + d->preserveRatioBox->setChecked(true); + d->wInput->setValue(d->orgWidth); + d->hInput->setValue(d->orgHeight); + d->wpInput->setValue(100.0); + d->hpInput->setValue(100.0); + d->preserveRatioBox->blockSignals(false); + d->wInput->blockSignals(false); + d->hInput->blockSignals(false); + d->wpInput->blockSignals(false); + d->hpInput->blockSignals(false); +} + +void ImageResize::slotValuesChanged() +{ + enableButton(Ok, true); + d->wInput->blockSignals(true); + d->hInput->blockSignals(true); + d->wpInput->blockSignals(true); + d->hpInput->blockSignals(true); + + TQString s(sender()->name()); + + if (s == "d->wInput") + { + double val = d->wInput->value(); + double wp = val/(double)(d->orgWidth) * 100.0; + d->wpInput->setValue(wp); + + if (d->preserveRatioBox->isChecked()) + { + d->hpInput->setValue(wp); + int h = (int)(wp*d->orgHeight/100); + d->hInput->setValue(h); + } + } + else if (s == "d->hInput") + { + double val = d->hInput->value(); + double hp = val/(double)(d->orgHeight) * 100.0; + d->hpInput->setValue(hp); + + if (d->preserveRatioBox->isChecked()) + { + d->wpInput->setValue(hp); + int w = (int)(hp*d->orgWidth/100); + d->wInput->setValue(w); + } + } + else if (s == "d->wpInput") + { + double val = d->wpInput->value(); + int w = (int)(val*d->orgWidth/100); + d->wInput->setValue(w); + + if (d->preserveRatioBox->isChecked()) + { + d->hpInput->setValue(val); + int h = (int)(val*d->orgHeight/100); + d->hInput->setValue(h); + } + } + else if (s == "d->hpInput") + { + double val = d->hpInput->value(); + int h = (int)(val*d->orgHeight/100); + d->hInput->setValue(h); + + if (d->preserveRatioBox->isChecked()) + { + d->wpInput->setValue(val); + int w = (int)(val*d->orgWidth/100); + d->wInput->setValue(w); + } + } + + d->prevW = d->wInput->value(); + d->prevH = d->hInput->value(); + d->prevWP = d->wpInput->value(); + d->prevHP = d->hpInput->value(); + + d->wInput->blockSignals(false); + d->hInput->blockSignals(false); + d->wpInput->blockSignals(false); + d->hpInput->blockSignals(false); +} + +void ImageResize::slotCancel() +{ + if (d->currentRenderingMode != ImageResizePriv::NoneRendering) + { + d->greycstorationIface->stopComputation(); + d->parent->unsetCursor(); + } + + done(Cancel); +} + +void ImageResize::processCImgURL(const TQString& url) +{ + TDEApplication::kApplication()->invokeBrowser(url); +} + +void ImageResize::closeEvent(TQCloseEvent *e) +{ + if (d->currentRenderingMode != ImageResizePriv::NoneRendering) + { + d->greycstorationIface->stopComputation(); + d->parent->unsetCursor(); + } + + e->accept(); +} + +void ImageResize::slotOk() +{ + if (d->prevW != d->wInput->value() || d->prevH != d->hInput->value() || + d->prevWP != d->wpInput->value() || d->prevHP != d->hpInput->value()) + slotValuesChanged(); + + d->currentRenderingMode = ImageResizePriv::FinalRendering; + d->mainTab->setCurrentPage(0); + d->settingsWidget->setEnabled(false); + d->preserveRatioBox->setEnabled(false); + d->useGreycstorationBox->setEnabled(false); + d->wInput->setEnabled(false); + d->hInput->setEnabled(false); + d->wpInput->setEnabled(false); + d->hpInput->setEnabled(false); + enableButton(Ok, false); + enableButton(Default, false); + enableButton(User2, false); + enableButton(User3, false); + + d->parent->setCursor( KCursor::waitCursor() ); + writeUserSettings(); + ImageIface iface(0, 0); + uchar *data = iface.getOriginalImage(); + DImg image = DImg(iface.originalWidth(), iface.originalHeight(), + iface.originalSixteenBit(), iface.originalHasAlpha(), data); + delete [] data; + + if (d->useGreycstorationBox->isChecked()) + { + d->progressBar->setValue(0); + d->progressBar->setEnabled(true); + + if (d->greycstorationIface) + { + delete d->greycstorationIface; + d->greycstorationIface = 0; + } + + d->greycstorationIface = new GreycstorationIface( + &image, d->settingsWidget->getSettings(), + GreycstorationIface::Resize, + d->wInput->value(), + d->hInput->value(), + 0, this); + } + else + { + // See B.K.O #152192: CImg resize() sound like bugous or unadapted + // to resize image without good quality. + + image.resize(d->wInput->value(), d->hInput->value()); + iface.putOriginalImage(i18n("Resize"), image.bits(), + image.width(), image.height()); + d->parent->unsetCursor(); + accept(); + } +} + +void ImageResize::customEvent(TQCustomEvent *event) +{ + if (!event) return; + + GreycstorationIface::EventData *data = (GreycstorationIface::EventData*) event->data(); + + if (!data) return; + + if (data->starting) // Computation in progress ! + { + d->progressBar->setValue(data->progress); + } + else + { + if (data->success) // Computation Completed ! + { + switch (d->currentRenderingMode) + { + case ImageResizePriv::FinalRendering: + { + DDebug() << "Final resizing completed..." << endl; + + ImageIface iface(0, 0); + DImg resizedImage = d->greycstorationIface->getTargetImage(); + + iface.putOriginalImage(i18n("Resize"), resizedImage.bits(), + resizedImage.width(), resizedImage.height()); + d->parent->unsetCursor(); + accept(); + break; + } + } + } + else // Computation Failed ! + { + switch (d->currentRenderingMode) + { + case ImageResizePriv::FinalRendering: + break; + } + } + } + + delete data; +} + +void ImageResize::slotUser3() +{ + KURL loadBlowupFile = KFileDialog::getOpenURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Resizing Settings File to Load")) ); + if( loadBlowupFile.isEmpty() ) + return; + + TQFile file(loadBlowupFile.path()); + + if ( file.open(IO_ReadOnly) ) + { + if (!d->settingsWidget->loadSettings(file, TQString("# Photograph Resizing Configuration File"))) + { + KMessageBox::error(this, + i18n("\"%1\" is not a Photograph Resizing settings text file.") + .arg(loadBlowupFile.fileName())); + file.close(); + return; + } + } + else + KMessageBox::error(this, i18n("Cannot load settings from the Photograph Resizing text file.")); + + file.close(); +} + +void ImageResize::slotUser2() +{ + KURL saveBlowupFile = KFileDialog::getSaveURL(TDEGlobalSettings::documentPath(), + TQString( "*" ), this, + TQString( i18n("Photograph Resizing Settings File to Save")) ); + if( saveBlowupFile.isEmpty() ) + return; + + TQFile file(saveBlowupFile.path()); + + if ( file.open(IO_WriteOnly) ) + d->settingsWidget->saveSettings(file, TQString("# Photograph Resizing Configuration File")); + else + KMessageBox::error(this, i18n("Cannot save settings to the Photograph Resizing text file.")); + + file.close(); +} + +} // NameSpace Digikam + diff --git a/src/utilities/imageeditor/tools/imageresize.h b/src/utilities/imageeditor/tools/imageresize.h new file mode 100644 index 00000000..3f8b1c23 --- /dev/null +++ b/src/utilities/imageeditor/tools/imageresize.h @@ -0,0 +1,82 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-04-07 + * Description : a tool to resize an image + * + * Copyright (C) 2005-2009 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef IMAGE_RESIZE_H +#define IMAGE_RESIZE_H + +// TQt includes. + +#include <tqstring.h> + +// KDE includes. + +#include <kdialogbase.h> + +// Local includes. + +#include "digikam_export.h" + +namespace Digikam +{ + +class ImageResizePriv; + +class DIGIKAM_EXPORT ImageResize : public KDialogBase +{ + TQ_OBJECT + + +public: + + ImageResize(TQWidget* parent); + ~ImageResize(); + +protected: + + void closeEvent(TQCloseEvent *e); + +private: + + void customEvent(TQCustomEvent *event); + void writeUserSettings(); + +private slots: + + void slotOk(); + void slotCancel(); + void slotDefault(); + void slotUser2(); + void slotUser3(); + void processCImgURL(const TQString&); + void slotValuesChanged(); + void readUserSettings(); + void slotRestorationToggled(bool); + +private: + + ImageResizePriv *d; +}; + +} // NameSpace Digikam + +#endif /* IMAGE_RESIZE_H */ |