summaryrefslogtreecommitdiffstats
path: root/src/utilities
diff options
context:
space:
mode:
Diffstat (limited to 'src/utilities')
-rw-r--r--src/utilities/Makefile.am1
-rw-r--r--src/utilities/batch/Makefile.am20
-rw-r--r--src/utilities/batch/batchalbumssyncmetadata.cpp183
-rw-r--r--src/utilities/batch/batchalbumssyncmetadata.h82
-rw-r--r--src/utilities/batch/batchsyncmetadata.cpp166
-rw-r--r--src/utilities/batch/batchsyncmetadata.h89
-rw-r--r--src/utilities/batch/batchthumbsgenerator.cpp233
-rw-r--r--src/utilities/batch/batchthumbsgenerator.h83
-rw-r--r--src/utilities/batch/imageinfoalbumsjob.cpp125
-rw-r--r--src/utilities/batch/imageinfoalbumsjob.h80
-rw-r--r--src/utilities/batch/imageinfojob.cpp163
-rw-r--r--src/utilities/batch/imageinfojob.h78
-rw-r--r--src/utilities/cameragui/Makefile.am30
-rw-r--r--src/utilities/cameragui/albumselectdialog.cpp417
-rw-r--r--src/utilities/cameragui/albumselectdialog.h80
-rw-r--r--src/utilities/cameragui/animwidget.cpp131
-rw-r--r--src/utilities/cameragui/animwidget.h66
-rw-r--r--src/utilities/cameragui/cameracontroller.cpp1227
-rw-r--r--src/utilities/cameragui/cameracontroller.h111
-rw-r--r--src/utilities/cameragui/camerafolderdialog.cpp138
-rw-r--r--src/utilities/cameragui/camerafolderdialog.h68
-rw-r--r--src/utilities/cameragui/camerafolderitem.cpp108
-rw-r--r--src/utilities/cameragui/camerafolderitem.h69
-rw-r--r--src/utilities/cameragui/camerafolderview.cpp169
-rw-r--r--src/utilities/cameragui/camerafolderview.h83
-rw-r--r--src/utilities/cameragui/cameraiconitem.cpp302
-rw-r--r--src/utilities/cameragui/cameraiconitem.h81
-rw-r--r--src/utilities/cameragui/cameraiconview.cpp900
-rw-r--r--src/utilities/cameragui/cameraiconview.h141
-rw-r--r--src/utilities/cameragui/camerainfodialog.cpp85
-rw-r--r--src/utilities/cameragui/camerainfodialog.h50
-rw-r--r--src/utilities/cameragui/cameraui.cpp1734
-rw-r--r--src/utilities/cameragui/cameraui.h155
-rw-r--r--src/utilities/cameragui/dkcamera.cpp113
-rw-r--r--src/utilities/cameragui/dkcamera.h97
-rw-r--r--src/utilities/cameragui/downloadsettingscontainer.h79
-rw-r--r--src/utilities/cameragui/freespacewidget.cpp252
-rw-r--r--src/utilities/cameragui/freespacewidget.h75
-rw-r--r--src/utilities/cameragui/gpcamera.cpp1223
-rw-r--r--src/utilities/cameragui/gpcamera.h107
-rw-r--r--src/utilities/cameragui/gpiteminfo.cpp68
-rw-r--r--src/utilities/cameragui/gpiteminfo.h80
-rw-r--r--src/utilities/cameragui/mtqueue.h116
-rw-r--r--src/utilities/cameragui/renamecustomizer.cpp532
-rw-r--r--src/utilities/cameragui/renamecustomizer.h91
-rw-r--r--src/utilities/cameragui/umscamera.cpp519
-rw-r--r--src/utilities/cameragui/umscamera.h78
-rw-r--r--src/utilities/hotplug/Makefile.am7
-rw-r--r--src/utilities/hotplug/configure.in.in7
-rwxr-xr-xsrc/utilities/hotplug/digikam-camera40
-rw-r--r--src/utilities/hotplug/digikam-download.desktop.in27
-rw-r--r--src/utilities/hotplug/digikam-gphoto2-camera.desktop.in27
-rw-r--r--src/utilities/hotplug/digikam-mount-and-download.desktop.in27
-rw-r--r--src/utilities/imageeditor/Makefile.am1
-rw-r--r--src/utilities/imageeditor/canvas/Makefile.am28
-rw-r--r--src/utilities/imageeditor/canvas/canvas.cpp1421
-rw-r--r--src/utilities/imageeditor/canvas/canvas.h209
-rw-r--r--src/utilities/imageeditor/canvas/colorcorrectiondlg.cpp186
-rw-r--r--src/utilities/imageeditor/canvas/colorcorrectiondlg.h72
-rw-r--r--src/utilities/imageeditor/canvas/dimginterface.cpp1270
-rw-r--r--src/utilities/imageeditor/canvas/dimginterface.h200
-rw-r--r--src/utilities/imageeditor/canvas/iccsettingscontainer.h82
-rw-r--r--src/utilities/imageeditor/canvas/imageplugin.cpp68
-rw-r--r--src/utilities/imageeditor/canvas/imageplugin.h70
-rw-r--r--src/utilities/imageeditor/canvas/imagepluginloader.cpp278
-rw-r--r--src/utilities/imageeditor/canvas/imagepluginloader.h79
-rw-r--r--src/utilities/imageeditor/canvas/iofilesettingscontainer.h84
-rw-r--r--src/utilities/imageeditor/canvas/undoaction.cpp185
-rw-r--r--src/utilities/imageeditor/canvas/undoaction.h144
-rw-r--r--src/utilities/imageeditor/canvas/undocache.cpp178
-rw-r--r--src/utilities/imageeditor/canvas/undocache.h62
-rw-r--r--src/utilities/imageeditor/canvas/undomanager.cpp253
-rw-r--r--src/utilities/imageeditor/canvas/undomanager.h76
-rw-r--r--src/utilities/imageeditor/editor/Makefile.am51
-rw-r--r--src/utilities/imageeditor/editor/digikamimageplugin.desktop39
-rw-r--r--src/utilities/imageeditor/editor/digikamimagewindowui.rc125
-rw-r--r--src/utilities/imageeditor/editor/editorstackview.cpp233
-rw-r--r--src/utilities/imageeditor/editor/editorstackview.h97
-rw-r--r--src/utilities/imageeditor/editor/editortool.cpp436
-rw-r--r--src/utilities/imageeditor/editor/editortool.h164
-rw-r--r--src/utilities/imageeditor/editor/editortooliface.cpp147
-rw-r--r--src/utilities/imageeditor/editor/editortooliface.h76
-rw-r--r--src/utilities/imageeditor/editor/editortoolsettings.cpp331
-rw-r--r--src/utilities/imageeditor/editor/editortoolsettings.h110
-rw-r--r--src/utilities/imageeditor/editor/editorwindow.cpp1932
-rw-r--r--src/utilities/imageeditor/editor/editorwindow.h263
-rw-r--r--src/utilities/imageeditor/editor/editorwindowprivate.h143
-rw-r--r--src/utilities/imageeditor/editor/imageiface.cpp444
-rw-r--r--src/utilities/imageeditor/editor/imageiface.h198
-rw-r--r--src/utilities/imageeditor/editor/imagewindow.cpp1263
-rw-r--r--src/utilities/imageeditor/editor/imagewindow.h155
-rw-r--r--src/utilities/imageeditor/editor/savingcontextcontainer.h89
-rw-r--r--src/utilities/imageeditor/rawimport/Makefile.am27
-rw-r--r--src/utilities/imageeditor/rawimport/rawimport.cpp223
-rw-r--r--src/utilities/imageeditor/rawimport/rawimport.h88
-rw-r--r--src/utilities/imageeditor/rawimport/rawpostprocessing.cpp137
-rw-r--r--src/utilities/imageeditor/rawimport/rawpostprocessing.h63
-rw-r--r--src/utilities/imageeditor/rawimport/rawpreview.cpp336
-rw-r--r--src/utilities/imageeditor/rawimport/rawpreview.h108
-rw-r--r--src/utilities/imageeditor/rawimport/rawsettingsbox.cpp741
-rw-r--r--src/utilities/imageeditor/rawimport/rawsettingsbox.h91
-rw-r--r--src/utilities/imageeditor/tools/Makefile.am19
-rw-r--r--src/utilities/imageeditor/tools/imageprint.cpp814
-rw-r--r--src/utilities/imageeditor/tools/imageprint.h122
-rw-r--r--src/utilities/imageeditor/tools/imageresize.cpp650
-rw-r--r--src/utilities/imageeditor/tools/imageresize.h82
-rw-r--r--src/utilities/lighttable/Makefile.am28
-rw-r--r--src/utilities/lighttable/lighttablebar.cpp881
-rw-r--r--src/utilities/lighttable/lighttablebar.h153
-rw-r--r--src/utilities/lighttable/lighttablepreview.cpp777
-rw-r--r--src/utilities/lighttable/lighttablepreview.h125
-rw-r--r--src/utilities/lighttable/lighttableview.cpp446
-rw-r--r--src/utilities/lighttable/lighttableview.h137
-rw-r--r--src/utilities/lighttable/lighttablewindow.cpp1676
-rw-r--r--src/utilities/lighttable/lighttablewindow.h162
-rw-r--r--src/utilities/lighttable/lighttablewindowprivate.h158
-rw-r--r--src/utilities/lighttable/lighttablewindowui.rc83
-rw-r--r--src/utilities/scripts/Makefile.am4
-rw-r--r--src/utilities/scripts/digitaglinktree568
-rw-r--r--src/utilities/scripts/digitaglinktree.1182
-rw-r--r--src/utilities/setup/Makefile.am29
-rw-r--r--src/utilities/setup/cameraselection.cpp494
-rw-r--r--src/utilities/setup/cameraselection.h88
-rw-r--r--src/utilities/setup/setup.cpp266
-rw-r--r--src/utilities/setup/setup.h81
-rw-r--r--src/utilities/setup/setupcamera.cpp315
-rw-r--r--src/utilities/setup/setupcamera.h73
-rw-r--r--src/utilities/setup/setupcollections.cpp218
-rw-r--r--src/utilities/setup/setupcollections.h66
-rw-r--r--src/utilities/setup/setupdcraw.cpp150
-rw-r--r--src/utilities/setup/setupdcraw.h67
-rw-r--r--src/utilities/setup/setupeditor.cpp176
-rw-r--r--src/utilities/setup/setupeditor.h63
-rw-r--r--src/utilities/setup/setupgeneral.cpp313
-rw-r--r--src/utilities/setup/setupgeneral.h67
-rw-r--r--src/utilities/setup/setupicc.cpp727
-rw-r--r--src/utilities/setup/setupicc.h86
-rw-r--r--src/utilities/setup/setupidentity.cpp217
-rw-r--r--src/utilities/setup/setupidentity.h60
-rw-r--r--src/utilities/setup/setupiofiles.cpp137
-rw-r--r--src/utilities/setup/setupiofiles.h63
-rw-r--r--src/utilities/setup/setuplighttable.cpp133
-rw-r--r--src/utilities/setup/setuplighttable.h59
-rw-r--r--src/utilities/setup/setupmetadata.cpp238
-rw-r--r--src/utilities/setup/setupmetadata.h67
-rw-r--r--src/utilities/setup/setupmime.cpp280
-rw-r--r--src/utilities/setup/setupmime.h66
-rw-r--r--src/utilities/setup/setupmisc.cpp124
-rw-r--r--src/utilities/setup/setupmisc.h58
-rw-r--r--src/utilities/setup/setupplugins.cpp104
-rw-r--r--src/utilities/setup/setupplugins.h56
-rw-r--r--src/utilities/setup/setupslideshow.cpp165
-rw-r--r--src/utilities/setup/setupslideshow.h64
-rw-r--r--src/utilities/setup/setuptooltip.cpp272
-rw-r--r--src/utilities/setup/setuptooltip.h59
-rw-r--r--src/utilities/slideshow/Makefile.am17
-rw-r--r--src/utilities/slideshow/slideshow.cpp679
-rw-r--r--src/utilities/slideshow/slideshow.h91
-rw-r--r--src/utilities/slideshow/slideshowsettings.h125
-rw-r--r--src/utilities/slideshow/toolbar.cpp217
-rw-r--r--src/utilities/slideshow/toolbar.h85
161 files changed, 37851 insertions, 0 deletions
diff --git a/src/utilities/Makefile.am b/src/utilities/Makefile.am
new file mode 100644
index 00000000..fe4c1532
--- /dev/null
+++ b/src/utilities/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = imageeditor setup cameragui hotplug scripts batch slideshow lighttable
diff --git a/src/utilities/batch/Makefile.am b/src/utilities/batch/Makefile.am
new file mode 100644
index 00000000..355643da
--- /dev/null
+++ b/src/utilities/batch/Makefile.am
@@ -0,0 +1,20 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/src/digikam \
+ -I$(top_srcdir)/src/libs/dialogs \
+ -I$(top_srcdir)/src/libs/dimg \
+ -I$(top_srcdir)/src/libs/dmetadata \
+ -I$(top_srcdir)/src/libs/thumbbar \
+ -I$(top_srcdir)/src/libs/widgets/common \
+ $(LIBKDCRAW_CFLAGS) \
+ $(LIBKEXIV2_CFLAGS) \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libbatch.la
+
+libbatch_la_SOURCES = batchthumbsgenerator.cpp batchalbumssyncmetadata.cpp \
+ imageinfojob.cpp imageinfoalbumsjob.cpp batchsyncmetadata.cpp
+
+libbatch_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
+
diff --git a/src/utilities/batch/batchalbumssyncmetadata.cpp b/src/utilities/batch/batchalbumssyncmetadata.cpp
new file mode 100644
index 00000000..fba18d34
--- /dev/null
+++ b/src/utilities/batch/batchalbumssyncmetadata.cpp
@@ -0,0 +1,183 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-22-01
+ * Description : batch sync pictures metadata from all Albums
+ * with digiKam database
+ *
+ * Copyright (C) 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 <tqstring.h>
+#include <tqtimer.h>
+#include <tqdatetime.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <tdeapplication.h>
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "album.h"
+#include "albummanager.h"
+#include "imageinfojob.h"
+#include "metadatahub.h"
+#include "batchalbumssyncmetadata.h"
+#include "batchalbumssyncmetadata.moc"
+
+namespace Digikam
+{
+
+class BatchAlbumsSyncMetadataPriv
+{
+public:
+
+ BatchAlbumsSyncMetadataPriv()
+ {
+ cancel = false;
+ imageInfoJob = 0;
+ palbumList = AlbumManager::instance()->allPAlbums();
+ duration.start();
+ }
+
+ bool cancel;
+
+ TQTime duration;
+
+ ImageInfoJob *imageInfoJob;
+
+ AlbumList palbumList;
+ AlbumList::Iterator albumsIt;
+};
+
+BatchAlbumsSyncMetadata::BatchAlbumsSyncMetadata(TQWidget* parent)
+ : DProgressDlg(parent)
+{
+ d = new BatchAlbumsSyncMetadataPriv;
+ d->imageInfoJob = new ImageInfoJob();
+ setValue(0);
+ setCaption(i18n("Sync All Images' Metadata"));
+ setLabel(i18n("<b>Syncing the metadata of all images with the digiKam database. Please wait...</b>"));
+ setButtonText(i18n("&Abort"));
+ resize(600, 300);
+ TQTimer::singleShot(500, this, TQ_SLOT(slotStart()));
+}
+
+BatchAlbumsSyncMetadata::~BatchAlbumsSyncMetadata()
+{
+ delete d;
+}
+
+void BatchAlbumsSyncMetadata::slotStart()
+{
+ setTitle(i18n("Parsing all albums"));
+ setTotalSteps(d->palbumList.count());
+
+ connect(d->imageInfoJob, TQ_SIGNAL(signalItemsInfo(const ImageInfoList&)),
+ this, TQ_SLOT(slotAlbumParsed(const ImageInfoList&)));
+
+ connect(d->imageInfoJob, TQ_SIGNAL(signalCompleted()),
+ this, TQ_SLOT(slotComplete()));
+
+ d->albumsIt = d->palbumList.begin();
+ parseAlbum();
+}
+
+void BatchAlbumsSyncMetadata::parseAlbum()
+{
+ if (d->albumsIt == d->palbumList.end()) // All is done.
+ {
+ TQTime t;
+ t = t.addMSecs(d->duration.elapsed());
+ setLabel(i18n("<b>The metadata of all images has been synchronized with the digiKam database.</b>"));
+ setTitle(i18n("Duration: %1").arg(t.toString()));
+ setButtonText(i18n("&Close"));
+ advance(1);
+ abort();
+ }
+ else if (!(*d->albumsIt)->isRoot())
+ {
+ d->imageInfoJob->allItemsFromAlbum(*d->albumsIt);
+ DDebug() << "Sync Items from Album :" << (*d->albumsIt)->kurl().directory() << endl;
+ }
+ else
+ {
+ d->albumsIt++;
+ parseAlbum();
+ }
+}
+
+void BatchAlbumsSyncMetadata::slotAlbumParsed(const ImageInfoList& list)
+{
+ TQPixmap pix = TDEApplication::kApplication()->iconLoader()->loadIcon(
+ "folder_image", TDEIcon::NoGroup, 32);
+
+ ImageInfoList imageInfoList = list;
+
+ if (!imageInfoList.isEmpty())
+ {
+ addedAction(pix, imageInfoList.first()->kurl().directory());
+
+ for (ImageInfo *info = imageInfoList.first(); info; info = imageInfoList.next())
+ {
+ MetadataHub fileHub;
+ // read in from database
+ fileHub.load(info);
+ // write out to file DMetadata
+ fileHub.write(info->filePath());
+ }
+ }
+
+ advance(1);
+ d->albumsIt++;
+ parseAlbum();
+}
+
+void BatchAlbumsSyncMetadata::slotComplete()
+{
+ advance(1);
+ d->albumsIt++;
+ parseAlbum();
+}
+
+void BatchAlbumsSyncMetadata::slotCancel()
+{
+ abort();
+ done(Cancel);
+}
+
+void BatchAlbumsSyncMetadata::closeEvent(TQCloseEvent *e)
+{
+ abort();
+ e->accept();
+}
+
+void BatchAlbumsSyncMetadata::abort()
+{
+ d->cancel = true;
+ d->imageInfoJob->stop();
+ emit signalComplete();
+}
+
+} // namespace Digikam
+
+
diff --git a/src/utilities/batch/batchalbumssyncmetadata.h b/src/utilities/batch/batchalbumssyncmetadata.h
new file mode 100644
index 00000000..8363ce4d
--- /dev/null
+++ b/src/utilities/batch/batchalbumssyncmetadata.h
@@ -0,0 +1,82 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-22-01
+ * Description : batch sync pictures metadata with
+ * digiKam database
+ *
+ * Copyright (C) 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 BATCHALBUMSSYNCMETADATA_H
+#define BATCHALBUMSSYNCMETADATA_H
+
+// Local includes.
+
+#include "imageinfo.h"
+#include "dprogressdlg.h"
+
+class TQWidget;
+
+class KURL;
+
+namespace Digikam
+{
+
+class BatchAlbumsSyncMetadataPriv;
+
+class BatchAlbumsSyncMetadata : public DProgressDlg
+{
+ TQ_OBJECT
+
+
+public:
+
+ BatchAlbumsSyncMetadata(TQWidget* parent);
+ ~BatchAlbumsSyncMetadata();
+
+signals:
+
+ void signalComplete();
+
+private:
+
+ void abort();
+ void parseAlbum();
+
+protected:
+
+ void closeEvent(TQCloseEvent *e);
+
+protected slots:
+
+ void slotCancel();
+
+private slots:
+
+ void slotStart();
+ void slotAlbumParsed(const ImageInfoList&);
+ void slotComplete();
+
+private:
+
+ BatchAlbumsSyncMetadataPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* BATCHALBUMSSYNCMETADATA_H */
diff --git a/src/utilities/batch/batchsyncmetadata.cpp b/src/utilities/batch/batchsyncmetadata.cpp
new file mode 100644
index 00000000..50e2ad7a
--- /dev/null
+++ b/src/utilities/batch/batchsyncmetadata.cpp
@@ -0,0 +1,166 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-22-01
+ * Description : batch sync pictures metadata from all Albums
+ * with digiKam database
+ *
+ * Copyright (C) 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 <tqstring.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "album.h"
+#include "imageinfojob.h"
+#include "metadatahub.h"
+#include "statusprogressbar.h"
+#include "batchsyncmetadata.h"
+#include "batchsyncmetadata.moc"
+
+namespace Digikam
+{
+
+class BatchSyncMetadataPriv
+{
+public:
+
+ BatchSyncMetadataPriv()
+ {
+ cancel = false;
+ imageInfoJob = new ImageInfoJob();
+ album = 0;
+ count = 0;
+ imageInfo = 0;
+ }
+
+ bool cancel;
+
+ int count;
+
+ Album *album;
+
+ ImageInfoJob *imageInfoJob;
+
+ ImageInfoList imageInfoList;
+
+ ImageInfo *imageInfo;
+};
+
+BatchSyncMetadata::BatchSyncMetadata(TQObject* parent, Album *album)
+ : TQObject(parent)
+{
+ d = new BatchSyncMetadataPriv;
+ d->album = album;
+}
+
+BatchSyncMetadata::BatchSyncMetadata(TQObject* parent, const ImageInfoList& list)
+ : TQObject(parent)
+{
+ d = new BatchSyncMetadataPriv;
+ d->imageInfoList = list;
+}
+
+BatchSyncMetadata::~BatchSyncMetadata()
+{
+ delete d;
+}
+
+void BatchSyncMetadata::parseAlbum()
+{
+ d->imageInfoJob->allItemsFromAlbum(d->album);
+
+ connect(d->imageInfoJob, TQ_SIGNAL(signalItemsInfo(const ImageInfoList&)),
+ this, TQ_SLOT(slotAlbumParsed(const ImageInfoList&)));
+
+ connect(d->imageInfoJob, TQ_SIGNAL(signalCompleted()),
+ this, TQ_SLOT(slotComplete()));
+}
+
+void BatchSyncMetadata::slotComplete()
+{
+ if (d->imageInfoList.isEmpty())
+ complete();
+}
+
+void BatchSyncMetadata::slotAlbumParsed(const ImageInfoList& list)
+{
+ d->imageInfoList = list;
+ parseList();
+}
+
+void BatchSyncMetadata::parseList()
+{
+ emit signalProgressBarMode(StatusProgressBar::CancelProgressBarMode,
+ i18n("Synchonizing images' Metadata with database. Please wait..."));
+
+ d->imageInfo = d->imageInfoList.first();
+ parsePicture();
+}
+
+void BatchSyncMetadata::parsePicture()
+{
+ if (!d->imageInfo) // All is done.
+ {
+ complete();
+ slotAbort();
+ }
+ else if (d->cancel)
+ {
+ complete();
+ }
+ else
+ {
+ MetadataHub fileHub;
+ // read in from database
+ fileHub.load(d->imageInfo);
+ // write out to file DMetadata
+ fileHub.write(d->imageInfo->filePath());
+
+ emit signalProgressValue((int)((d->count++/(float)d->imageInfoList.count())*100.0));
+
+ d->imageInfo = d->imageInfoList.next();
+
+ kapp->processEvents();
+ parsePicture();
+ }
+}
+
+void BatchSyncMetadata::slotAbort()
+{
+ d->cancel = true;
+ d->imageInfoJob->stop();
+}
+
+void BatchSyncMetadata::complete()
+{
+ emit signalProgressBarMode(StatusProgressBar::TextMode, TQString());
+ emit signalComplete();
+}
+
+} // namespace Digikam
+
+
diff --git a/src/utilities/batch/batchsyncmetadata.h b/src/utilities/batch/batchsyncmetadata.h
new file mode 100644
index 00000000..c9b69ac7
--- /dev/null
+++ b/src/utilities/batch/batchsyncmetadata.h
@@ -0,0 +1,89 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-22-01
+ * Description : batch sync pictures metadata with
+ * digiKam database
+ *
+ * Copyright (C) 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 BATCHSYNCMETADATA_H
+#define BATCHSYNCMETADATA_H
+
+// TQt includes.
+
+#include <tqobject.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+
+class KURL;
+
+namespace Digikam
+{
+
+class Album;
+class BatchSyncMetadataPriv;
+
+class BatchSyncMetadata : public TQObject
+{
+ TQ_OBJECT
+
+
+public:
+
+ /** Constructor witch sync all metatada pictures from an Album */
+ BatchSyncMetadata(TQObject* parent, Album *album);
+
+ /** Constructor witch sync all metatada from an images list */
+ BatchSyncMetadata(TQObject* parent, const ImageInfoList& list);
+
+ ~BatchSyncMetadata();
+
+ void parseList();
+ void parseAlbum();
+
+signals:
+
+ void signalComplete();
+ void signalProgressValue(int);
+ void signalProgressBarMode(int, const TQString&);
+
+public slots:
+
+ void slotAbort();
+
+private:
+
+ void parsePicture();
+ void complete();
+
+private slots:
+
+ void slotAlbumParsed(const ImageInfoList&);
+ void slotComplete();
+
+private:
+
+ BatchSyncMetadataPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* BATCHSYNCMETADATA_H */
diff --git a/src/utilities/batch/batchthumbsgenerator.cpp b/src/utilities/batch/batchthumbsgenerator.cpp
new file mode 100644
index 00000000..f0bd0103
--- /dev/null
+++ b/src/utilities/batch/batchthumbsgenerator.cpp
@@ -0,0 +1,233 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-30-08
+ * Description : batch thumbnails generator
+ *
+ * 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 <unistd.h>
+}
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqtimer.h>
+#include <tqdir.h>
+#include <tqfileinfo.h>
+#include <tqdatetime.h>
+
+// KDE includes.
+
+#include <kmdcodec.h>
+#include <tdelocale.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "album.h"
+#include "albumdb.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "thumbnailjob.h"
+#include "batchthumbsgenerator.h"
+#include "batchthumbsgenerator.moc"
+
+namespace Digikam
+{
+
+class BatchThumbsGeneratorPriv
+{
+public:
+
+ BatchThumbsGeneratorPriv()
+ {
+ cancel = false;
+ thumbJob = 0;
+ duration.start();
+ }
+
+ bool cancel;
+
+ TQTime duration;
+
+ TQGuardedPtr<ThumbnailJob> thumbJob;
+};
+
+BatchThumbsGenerator::BatchThumbsGenerator(TQWidget* parent)
+ : DProgressDlg(parent)
+{
+ d = new BatchThumbsGeneratorPriv;
+ setValue(0);
+ setCaption(i18n("Thumbnails processing"));
+ setLabel(i18n("<b>Updating thumbnails database. Please wait...</b>"));
+ setButtonText(i18n("&Abort"));
+ TQTimer::singleShot(500, this, TQ_SLOT(slotRebuildThumbs128()));
+ resize(600, 300);
+}
+
+BatchThumbsGenerator::~BatchThumbsGenerator()
+{
+ if (!d->thumbJob.isNull())
+ {
+ d->thumbJob->kill();
+ d->thumbJob = 0;
+ }
+
+ delete d;
+}
+
+void BatchThumbsGenerator::slotRebuildThumbs128()
+{
+ setTitle(i18n("Processing small thumbs"));
+ rebuildAllThumbs(128);
+
+ connect(this, TQ_SIGNAL(signalRebuildThumbsDone()),
+ this, TQ_SLOT(slotRebuildThumbs256()));
+}
+
+void BatchThumbsGenerator::slotRebuildThumbs256()
+{
+ setTitle(i18n("Processing large thumbs"));
+ rebuildAllThumbs(256);
+
+ disconnect(this, TQ_SIGNAL(signalRebuildThumbsDone()),
+ this, TQ_SLOT(slotRebuildThumbs256()));
+
+ connect(this, TQ_SIGNAL(signalRebuildThumbsDone()),
+ this, TQ_SLOT(slotRebuildAllThumbComplete()));
+}
+
+void BatchThumbsGenerator::slotRebuildAllThumbComplete()
+{
+ TQTime t;
+ t = t.addMSecs(d->duration.elapsed());
+ setLabel(i18n("<b>The thumbnails database has been updated.</b>"));
+ setTitle(i18n("Duration: %1").arg(t.toString()));
+ setButtonText(i18n("&Close"));
+}
+
+void BatchThumbsGenerator::rebuildAllThumbs(int size)
+{
+ TQStringList allPicturesPath;
+ TQString thumbCacheDir = TQDir::homeDirPath() + "/.thumbnails/";
+ TQString filesFilter = AlbumSettings::instance()->getAllFileFilter();
+ bool exifRotate = AlbumSettings::instance()->getExifRotate();
+ AlbumDB *db = AlbumManager::instance()->albumDB();
+ AlbumList palbumList = AlbumManager::instance()->allPAlbums();
+
+ // Get all digiKam albums collection pictures path.
+
+ for (AlbumList::Iterator it = palbumList.begin();
+ !d->cancel && (it != palbumList.end()); ++it )
+ {
+ // Don't use the root album
+ if ((*it)->isRoot())
+ continue;
+
+ db->beginTransaction();
+ TQStringList albumItemsPath = db->getItemURLsInAlbum((*it)->id());
+ db->commitTransaction();
+
+ TQStringList pathSorted;
+ for (TQStringList::iterator it2 = albumItemsPath.begin();
+ !d->cancel && (it2 != albumItemsPath.end()); ++it2)
+ {
+ TQFileInfo fi(*it2);
+ if (filesFilter.contains(fi.extension(false)))
+ pathSorted.append(*it2);
+ }
+
+ allPicturesPath += pathSorted;
+ }
+
+ setTotalSteps(allPicturesPath.count()*2);
+
+ // Remove all current album item thumbs from disk cache.
+
+ for (TQStringList::iterator it = allPicturesPath.begin();
+ !d->cancel && (it != allPicturesPath.end()); ++it)
+ {
+ TQString uri = "file://" + TQDir::cleanDirPath(*it);
+ KMD5 md5(TQFile::encodeName(uri).data());
+ uri = md5.hexDigest();
+
+ TQString smallThumbPath = thumbCacheDir + "normal/" + uri + ".png";
+ TQString bigThumbPath = thumbCacheDir + "large/" + uri + ".png";
+
+ if (size <= 128)
+ ::unlink(TQFile::encodeName(smallThumbPath));
+ else
+ ::unlink(TQFile::encodeName(bigThumbPath));
+ }
+
+ if (!d->thumbJob.isNull())
+ {
+ d->thumbJob->kill();
+ d->thumbJob = 0;
+ }
+
+ d->thumbJob = new ThumbnailJob(KURL::List(allPicturesPath), size, true, exifRotate);
+
+ connect(d->thumbJob, TQ_SIGNAL(signalThumbnail(const KURL&, const TQPixmap&)),
+ this, TQ_SLOT(slotRebuildThumbDone(const KURL&, const TQPixmap&)));
+
+ connect(d->thumbJob, TQ_SIGNAL(signalFailed(const KURL&)),
+ this, TQ_SLOT(slotRebuildThumbDone(const KURL&)));
+
+ connect(d->thumbJob, TQ_SIGNAL(signalCompleted()),
+ this, TQ_SIGNAL(signalRebuildThumbsDone()));
+}
+
+void BatchThumbsGenerator::slotRebuildThumbDone(const KURL& url, const TQPixmap& pix)
+{
+ addedAction(pix, url.path());
+ advance(1);
+}
+
+void BatchThumbsGenerator::slotCancel()
+{
+ abort();
+ done(Cancel);
+}
+
+void BatchThumbsGenerator::closeEvent(TQCloseEvent *e)
+{
+ abort();
+ e->accept();
+}
+
+void BatchThumbsGenerator::abort()
+{
+ d->cancel = true;
+
+ if (!d->thumbJob.isNull())
+ {
+ d->thumbJob->kill();
+ d->thumbJob = 0;
+ }
+
+ emit signalRebuildAllThumbsDone();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/batch/batchthumbsgenerator.h b/src/utilities/batch/batchthumbsgenerator.h
new file mode 100644
index 00000000..091c2783
--- /dev/null
+++ b/src/utilities/batch/batchthumbsgenerator.h
@@ -0,0 +1,83 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-30-08
+ * Description : batch thumbnails generator
+ *
+ * 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 BATCHTHUMBSGENERATOR_H
+#define BATCHTHUMBSGENERATOR_H
+
+// Local includes.
+
+#include "dprogressdlg.h"
+
+class TQWidget;
+class TQPixmap;
+
+class KURL;
+
+namespace Digikam
+{
+
+class BatchThumbsGeneratorPriv;
+
+class BatchThumbsGenerator : public DProgressDlg
+{
+ TQ_OBJECT
+
+
+public:
+
+ BatchThumbsGenerator(TQWidget* parent);
+ ~BatchThumbsGenerator();
+
+signals:
+
+ void signalRebuildThumbsDone();
+ void signalRebuildAllThumbsDone();
+
+private:
+
+ void rebuildAllThumbs(int size);
+ void abort();
+
+protected:
+
+ void closeEvent(TQCloseEvent *e);
+
+protected slots:
+
+ void slotCancel();
+
+private slots:
+
+ void slotRebuildThumbs128();
+ void slotRebuildThumbs256();
+ void slotRebuildThumbDone(const KURL& url, const TQPixmap& pix=TQPixmap());
+ void slotRebuildAllThumbComplete();
+
+private:
+
+ BatchThumbsGeneratorPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* BATCHTHUMBSGENERATOR_H */
diff --git a/src/utilities/batch/imageinfoalbumsjob.cpp b/src/utilities/batch/imageinfoalbumsjob.cpp
new file mode 100644
index 00000000..4d0e3c55
--- /dev/null
+++ b/src/utilities/batch/imageinfoalbumsjob.cpp
@@ -0,0 +1,125 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-14-02
+ * Description : interface to get image info from an albums list.
+ *
+ * Copyright (C) 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 <tqstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "album.h"
+#include "albummanager.h"
+#include "imageinfojob.h"
+#include "imageinfoalbumsjob.h"
+#include "imageinfoalbumsjob.moc"
+
+namespace Digikam
+{
+
+class ImageInfoAlbumsJobPriv
+{
+public:
+
+ ImageInfoAlbumsJobPriv(){}
+
+ AlbumList albumsList;
+ AlbumList::Iterator albumIt;
+
+ ImageInfoList itemsList;
+
+ ImageInfoJob imageInfoJob;
+};
+
+ImageInfoAlbumsJob::ImageInfoAlbumsJob()
+{
+ d = new ImageInfoAlbumsJobPriv;
+
+ connect(&d->imageInfoJob, TQ_SIGNAL(signalItemsInfo(const ImageInfoList&)),
+ this, TQ_SLOT(slotItemsInfo(const ImageInfoList&)));
+
+ connect(&d->imageInfoJob, TQ_SIGNAL(signalCompleted()),
+ this, TQ_SLOT(slotComplete()));
+}
+
+ImageInfoAlbumsJob::~ImageInfoAlbumsJob()
+{
+ delete d;
+}
+
+void ImageInfoAlbumsJob::allItemsFromAlbums(const AlbumList& albumsList)
+{
+ if (albumsList.isEmpty())
+ return;
+
+ d->albumsList = albumsList;
+ d->albumIt = d->albumsList.begin();
+ parseAlbum();
+}
+
+void ImageInfoAlbumsJob::parseAlbum()
+{
+ d->imageInfoJob.allItemsFromAlbum(*d->albumIt);
+}
+
+void ImageInfoAlbumsJob::stop()
+{
+ d->imageInfoJob.stop();
+ d->albumsList.clear();
+}
+
+void ImageInfoAlbumsJob::slotItemsInfo(const ImageInfoList& items)
+{
+ ImageInfo* item;
+ for (ImageInfoListIterator it(items); (item = it.current()); ++it)
+ d->itemsList.append(item);
+
+ ++d->albumIt;
+ if (d->albumIt == d->albumsList.end())
+ {
+ stop();
+ emit signalCompleted(d->itemsList);
+ return;
+ }
+
+ parseAlbum();
+}
+
+void ImageInfoAlbumsJob::slotComplete()
+{
+ ++d->albumIt;
+ if (d->albumIt == d->albumsList.end())
+ {
+ stop();
+ emit signalCompleted(d->itemsList);
+ return;
+ }
+
+ parseAlbum();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/batch/imageinfoalbumsjob.h b/src/utilities/batch/imageinfoalbumsjob.h
new file mode 100644
index 00000000..7b9f477f
--- /dev/null
+++ b/src/utilities/batch/imageinfoalbumsjob.h
@@ -0,0 +1,80 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-14-02
+ * Description : interface to get image info from an albums list.
+ *
+ * Copyright (C) 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 IMAGEINFOALBUMSJOB_H
+#define IMAGEINFOALBUMSJOB_H
+
+// TQt includes.
+
+#include <tqobject.h>
+#include <tqcstring.h>
+
+// Local includes.
+
+#include "albummanager.h"
+#include "imageinfo.h"
+
+namespace TDEIO
+{
+class Job;
+}
+
+namespace Digikam
+{
+
+class ImageInfoAlbumsJobPriv;
+
+class ImageInfoAlbumsJob : public TQObject
+{
+ TQ_OBJECT
+
+
+public:
+
+ ImageInfoAlbumsJob();
+ ~ImageInfoAlbumsJob();
+
+ void allItemsFromAlbums(const AlbumList& albumsList);
+ void stop();
+
+signals:
+
+ void signalCompleted(const ImageInfoList& items);
+
+private slots:
+
+ void slotItemsInfo(const ImageInfoList&);
+ void slotComplete();
+
+private:
+
+ void parseAlbum();
+
+private:
+
+ ImageInfoAlbumsJobPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* IMAGEINFOALBUMSJOB_H */
diff --git a/src/utilities/batch/imageinfojob.cpp b/src/utilities/batch/imageinfojob.cpp
new file mode 100644
index 00000000..58660697
--- /dev/null
+++ b/src/utilities/batch/imageinfojob.cpp
@@ -0,0 +1,163 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-22-01
+ * Description : digikamalbum TDEIO slave interface to get image
+ * info from database.
+ *
+ * Copyright (C) 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 <tqstring.h>
+#include <tqdatastream.h>
+
+// KDE includes.
+
+#include <tdeio/job.h>
+#include <kurl.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "album.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "imageinfojob.h"
+#include "imageinfojob.moc"
+
+namespace Digikam
+{
+
+class ImageInfoJobPriv
+{
+public:
+
+ ImageInfoJobPriv()
+ {
+ job = 0;
+
+ AlbumSettings *settings = AlbumSettings::instance();
+ imagefilter = settings->getImageFileFilter().lower() +
+ settings->getImageFileFilter().upper() +
+ settings->getRawFileFilter().lower() +
+ settings->getRawFileFilter().upper();
+ }
+
+ TQString imagefilter;
+
+ TDEIO::TransferJob *job;
+};
+
+ImageInfoJob::ImageInfoJob()
+{
+ d = new ImageInfoJobPriv;
+}
+
+ImageInfoJob::~ImageInfoJob()
+{
+ delete d;
+}
+
+void ImageInfoJob::allItemsFromAlbum(Album *album)
+{
+ if (d->job)
+ {
+ d->job->kill();
+ d->job = 0;
+ }
+
+ if (!album)
+ return;
+
+ TQByteArray ba;
+ TQDataStream ds(ba, IO_WriteOnly);
+ ds << AlbumManager::instance()->getLibraryPath();
+ ds << album->kurl();
+ ds << d->imagefilter;
+ ds << 0; // getting dimensions (not needed here)
+ ds << 0; // recursive sub-album (not needed here)
+ ds << 0; // recursive sub-tags (not needed here)
+
+ // Protocol = digikamalbums -> tdeio_digikamalbums
+ d->job = new TDEIO::TransferJob(album->kurl(), TDEIO::CMD_SPECIAL,
+ ba, TQByteArray(), false);
+
+ connect(d->job, TQ_SIGNAL(result(TDEIO::Job*)),
+ this, TQ_SLOT(slotResult(TDEIO::Job*)));
+
+ connect(d->job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
+ this, TQ_SLOT(slotData(TDEIO::Job*, const TQByteArray&)));
+}
+
+void ImageInfoJob::stop()
+{
+ if (d->job)
+ {
+ d->job->kill();
+ d->job = 0;
+ }
+}
+
+void ImageInfoJob::slotResult(TDEIO::Job* job)
+{
+ d->job = 0;
+
+ if (job->error())
+ {
+ DWarning() << "Failed to list url: " << job->errorString() << endl;
+ return;
+ }
+
+ emit signalCompleted();
+}
+
+void ImageInfoJob::slotData(TDEIO::Job*, const TQByteArray& data)
+{
+ if (data.isEmpty())
+ return;
+
+ TQ_LLONG imageID;
+ int albumID;
+ TQString name;
+ TQString date;
+ size_t size;
+ TQSize dims;
+ ImageInfoList itemsList;
+ TQDataStream ds(data, IO_ReadOnly);
+
+ while (!ds.atEnd())
+ {
+ ds >> imageID;
+ ds >> albumID;
+ ds >> name;
+ ds >> date;
+ ds >> size;
+ ds >> dims;
+
+ ImageInfo* info = new ImageInfo(imageID, albumID, name,
+ TQDateTime::fromString(date, TQt::ISODate),
+ size, dims);
+
+ itemsList.append(info);
+ }
+
+ emit signalItemsInfo(itemsList);
+}
+
+} // namespace Digikam
diff --git a/src/utilities/batch/imageinfojob.h b/src/utilities/batch/imageinfojob.h
new file mode 100644
index 00000000..0227a628
--- /dev/null
+++ b/src/utilities/batch/imageinfojob.h
@@ -0,0 +1,78 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-22-01
+ * Description : digikamalbum TDEIO slave interface to get image
+ * info from database.
+ *
+ * Copyright (C) 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 IMAGEINFOJOB_H
+#define IMAGEINFOJOB_H
+
+// TQt includes.
+
+#include <tqobject.h>
+#include <tqcstring.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+
+namespace TDEIO
+{
+class Job;
+}
+
+namespace Digikam
+{
+
+class Album;
+class ImageInfoJobPriv;
+
+class ImageInfoJob : public TQObject
+{
+ TQ_OBJECT
+
+
+public:
+
+ ImageInfoJob();
+ ~ImageInfoJob();
+
+ void allItemsFromAlbum(Album *album);
+ void stop();
+
+signals:
+
+ void signalItemsInfo(const ImageInfoList& items);
+ void signalCompleted();
+
+private slots:
+
+ void slotResult(TDEIO::Job* job);
+ void slotData(TDEIO::Job* job, const TQByteArray& data);
+
+private:
+
+ ImageInfoJobPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* IMAGEINFOJOB_H */
diff --git a/src/utilities/cameragui/Makefile.am b/src/utilities/cameragui/Makefile.am
new file mode 100644
index 00000000..83f810f4
--- /dev/null
+++ b/src/utilities/cameragui/Makefile.am
@@ -0,0 +1,30 @@
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libcameragui.la
+
+# NOTE from Gilles (06-12-06): gpcamera.cpp must be placed on the top of source file list
+# to unbreak compilation with './configure -enable-final' option. I suspect a problem with
+# Gphoto2 C Ansi header.
+libcameragui_la_SOURCES = gpcamera.cpp cameraui.cpp cameraiconview.cpp \
+ cameraiconitem.cpp cameracontroller.cpp \
+ camerafolderview.cpp camerafolderitem.cpp \
+ animwidget.cpp renamecustomizer.cpp \
+ dkcamera.cpp umscamera.cpp gpiteminfo.cpp \
+ camerainfodialog.cpp albumselectdialog.cpp \
+ camerafolderdialog.cpp freespacewidget.cpp
+
+libcameragui_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
+libcameragui_la_LIBADD = $(top_builddir)/src/libs/imageproperties/libimagepropertiescamgui.la \
+ $(LIB_GPHOTO) $(LIBJPEG)
+
+INCLUDES = -I$(top_srcdir)/src/digikam \
+ -I$(top_srcdir)/src/utilities/imageeditor/editor \
+ -I$(top_srcdir)/src/libs/jpegutils \
+ -I$(top_srcdir)/src/libs/themeengine \
+ -I$(top_srcdir)/src/libs/imageproperties \
+ -I$(top_srcdir)/src/libs/widgets/common \
+ -I$(top_srcdir)/src/libs/dimg \
+ -I$(top_srcdir)/src/libs/dmetadata \
+ $(LIBKEXIV2_CFLAGS) \
+ $(GPHOTO_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes)
diff --git a/src/utilities/cameragui/albumselectdialog.cpp b/src/utilities/cameragui/albumselectdialog.cpp
new file mode 100644
index 00000000..486c4711
--- /dev/null
+++ b/src/utilities/cameragui/albumselectdialog.cpp
@@ -0,0 +1,417 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-06-16
+ * Description : a dialog to select a target album to download
+ * pictures from camera
+ *
+ * Copyright (C) 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqlabel.h>
+#include <tqframe.h>
+#include <tqlayout.h>
+#include <tqpopupmenu.h>
+#include <tqcursor.h>
+#include <tqdatetime.h>
+#include <tqmap.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <tdeapplication.h>
+#include <tdeaction.h>
+#include <kinputdialog.h>
+#include <tdemessagebox.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "folderview.h"
+#include "folderitem.h"
+#include "album.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "searchtextbar.h"
+#include "albumselectdialog.h"
+#include "albumselectdialog.moc"
+
+namespace Digikam
+{
+
+class AlbumSelectDialogPrivate
+{
+
+public:
+
+ AlbumSelectDialogPrivate()
+ {
+ allowRootSelection = false;
+ folderView = 0;
+ searchBar = 0;
+ }
+
+ bool allowRootSelection;
+
+ TQString newAlbumString;
+
+ TQMap<FolderItem*, PAlbum*> albumMap;
+
+ FolderView *folderView;
+
+ SearchTextBar *searchBar;
+};
+
+AlbumSelectDialog::AlbumSelectDialog(TQWidget* parent, PAlbum* albumToSelect,
+ const TQString& header,
+ const TQString& newAlbumString,
+ bool allowRootSelection )
+ : KDialogBase(Plain, i18n("Select Album"),
+ Help|User1|Ok|Cancel, Ok,
+ parent, 0, true, true,
+ i18n("&New Album"))
+{
+ d = new AlbumSelectDialogPrivate;
+ setHelp("targetalbumdialog.anchor", "digikam");
+ enableButtonOK(false);
+
+ d->allowRootSelection = allowRootSelection;
+ d->newAlbumString = newAlbumString;
+
+ // -------------------------------------------------------------
+
+ TQGridLayout* grid = new TQGridLayout(plainPage(), 2, 1, 0, spacingHint());
+
+ TQLabel *logo = new TQLabel(plainPage());
+ TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 128, TDEIcon::DefaultState, 0, true));
+
+ TQLabel *message = new TQLabel(plainPage());
+ if (!header.isEmpty())
+ message->setText(header);
+
+ d->folderView = new FolderView(plainPage());
+ d->folderView->addColumn(i18n("My Albums"));
+ d->folderView->setColumnWidthMode( 0, TQListView::Maximum );
+ d->folderView->setResizeMode( TQListView::AllColumns );
+ d->folderView->setRootIsDecorated(true);
+
+ d->searchBar = new SearchTextBar(plainPage(), "AlbumSelectDialogSearchBar");
+
+ // -------------------------------------------------------------
+
+ TQPixmap icon = iconLoader->loadIcon("folder", TDEIcon::NoGroup,
+ AlbumSettings::instance()->getDefaultTreeIconSize(), TDEIcon::DefaultState, 0, true);
+
+ AlbumList aList = AlbumManager::instance()->allPAlbums();
+
+ for (AlbumList::const_iterator it = aList.begin(); it != aList.end(); ++it)
+ {
+ PAlbum* album = (PAlbum*)(*it);
+
+ FolderItem* viewItem = 0;
+
+ if (album->isRoot())
+ {
+ viewItem = new FolderItem(d->folderView, album->title());
+ viewItem->setOpen(true);
+ }
+ else
+ {
+ FolderItem* parentItem = (FolderItem*)(album->parent()->extraData(d->folderView));
+
+ if (!parentItem)
+ {
+ DWarning() << "Failed to find parent for Album "
+ << album->title() << endl;
+ continue;
+ }
+
+ viewItem = new FolderItem(parentItem, album->title());
+ }
+
+ if (viewItem)
+ {
+ viewItem->setPixmap(0, icon);
+ album->setExtraData(d->folderView, viewItem);
+ d->albumMap.insert(viewItem, album);
+
+ if (album == albumToSelect)
+ {
+ viewItem->setOpen(true);
+ d->folderView->setSelected(viewItem, true);
+ d->folderView->ensureItemVisible(viewItem);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------
+
+ grid->addMultiCellWidget(logo, 0, 0, 0, 0);
+ grid->addMultiCellWidget(message, 1, 1, 0, 0);
+ grid->addMultiCellWidget(d->folderView, 0, 2, 1, 1);
+ grid->addMultiCellWidget(d->searchBar, 3, 3, 1, 1);
+ grid->setRowStretch(2, 10);
+
+ // -------------------------------------------------------------
+
+ connect(AlbumManager::instance(), TQ_SIGNAL(signalAlbumAdded(Album*)),
+ this, TQ_SLOT(slotAlbumAdded(Album*)));
+
+ connect(AlbumManager::instance(), TQ_SIGNAL(signalAlbumDeleted(Album*)),
+ this, TQ_SLOT(slotAlbumDeleted(Album*)));
+
+ connect(AlbumManager::instance(), TQ_SIGNAL(signalAlbumsCleared()),
+ this, TQ_SLOT(slotAlbumsCleared()));
+
+ connect(d->folderView, TQ_SIGNAL(selectionChanged()),
+ this, TQ_SLOT(slotSelectionChanged()));
+
+ connect(d->folderView, TQ_SIGNAL(contextMenuRequested(TQListViewItem*, const TQPoint&, int)),
+ this, TQ_SLOT(slotContextMenu(TQListViewItem*, const TQPoint&, int)));
+
+ connect(d->searchBar, TQ_SIGNAL(signalTextChanged(const TQString&)),
+ this, TQ_SLOT(slotSearchTextChanged(const TQString&)));
+
+ // -------------------------------------------------------------
+
+ resize(650, 650);
+ slotSelectionChanged();
+}
+
+AlbumSelectDialog::~AlbumSelectDialog()
+{
+ delete d;
+}
+
+void AlbumSelectDialog::slotAlbumAdded(Album* album)
+{
+ if (!album || album->type() != Album::PHYSICAL)
+ return;
+
+ FolderItem* parentItem = (FolderItem*)(album->parent()->extraData(d->folderView));
+
+ if (!parentItem)
+ {
+ DWarning() << "Failed to find parent for Album "
+ << album->title() << endl;
+ return;
+ }
+
+ TDEIconLoader *iconLoader = TDEApplication::kApplication()->iconLoader();
+ TQPixmap icon = iconLoader->loadIcon("folder", TDEIcon::NoGroup,
+ AlbumSettings::instance()->getDefaultTreeIconSize(),
+ TDEIcon::DefaultState, 0, true);
+
+ FolderItem* viewItem = new FolderItem(parentItem, album->title());
+ viewItem->setPixmap(0, icon);
+ album->setExtraData(d->folderView, viewItem);
+ d->albumMap.insert(viewItem, (PAlbum*)album);
+}
+
+void AlbumSelectDialog::slotAlbumDeleted(Album* album)
+{
+ if (!album || album->type() != Album::PHYSICAL)
+ return;
+
+ FolderItem* viewItem = (FolderItem*)(album->extraData(d->folderView));
+
+ if (viewItem)
+ {
+ delete viewItem;
+ album->removeExtraData(d->folderView);
+ d->albumMap.remove(viewItem);
+ }
+}
+
+void AlbumSelectDialog::slotAlbumsCleared()
+{
+ d->folderView->clear();
+}
+
+void AlbumSelectDialog::slotSelectionChanged()
+{
+ TQListViewItem* selItem = 0;
+ TQListViewItemIterator it(d->folderView);
+
+ while (it.current())
+ {
+ if (it.current()->isSelected())
+ {
+ selItem = it.current();
+ break;
+ }
+ ++it;
+ }
+
+ if (!selItem || (selItem == d->folderView->firstChild()) &&
+ !d->allowRootSelection)
+ {
+ enableButtonOK(false);
+ return;
+ }
+
+ enableButtonOK(true);
+}
+
+void AlbumSelectDialog::slotContextMenu(TQListViewItem *, const TQPoint &, int)
+{
+ TQPopupMenu popmenu(d->folderView);
+ TDEAction *action = new TDEAction(i18n( "Create New Album" ),
+ "albumfolder-new", 0, this,
+ TQ_SLOT( slotUser1() ),
+ &popmenu);
+ action->plug(&popmenu);
+ popmenu.exec(TQCursor::pos());
+}
+
+void AlbumSelectDialog::slotUser1()
+{
+ TQListViewItem* item = d->folderView->currentItem();
+ if (!item)
+ item = d->folderView->firstChild();
+
+ if (!item)
+ return;
+
+ PAlbum* album = d->albumMap[(FolderItem*)item];
+ if (!album)
+ return;
+
+ bool ok;
+ TQString newAlbumName = KInputDialog::getText(i18n("New Album Name"),
+ i18n("Creating new album in '%1'\n"
+ "Enter album name:")
+ .arg(album->prettyURL()),
+ d->newAlbumString, &ok, this);
+ if (!ok)
+ return;
+
+ TQString errMsg;
+ PAlbum* newAlbum = AlbumManager::instance()->createPAlbum(album, newAlbumName,
+ TQString(), TQDate::currentDate(),
+ TQString(), errMsg);
+ if (!newAlbum)
+ {
+ KMessageBox::error(this, errMsg);
+ return;
+ }
+
+ FolderItem* newItem = (FolderItem*)newAlbum->extraData(d->folderView);
+ if (newItem)
+ {
+ d->folderView->ensureItemVisible(newItem);
+ d->folderView->setSelected(newItem, true);
+ }
+}
+
+PAlbum* AlbumSelectDialog::selectAlbum(TQWidget* parent,
+ PAlbum* albumToSelect,
+ const TQString& header,
+ const TQString& newAlbumString,
+ bool allowRootSelection )
+{
+ AlbumSelectDialog dlg(parent, albumToSelect,
+ header, newAlbumString,
+ allowRootSelection);
+
+ if (dlg.exec() != KDialogBase::Accepted)
+ return 0;
+
+ FolderItem* item = (FolderItem*) dlg.d->folderView->currentItem();
+ if (!item || (item == dlg.d->folderView->firstChild()) &&
+ !allowRootSelection)
+ {
+ return 0;
+ }
+
+ return dlg.d->albumMap[item];
+}
+
+void AlbumSelectDialog::slotSearchTextChanged(const TQString& filter)
+{
+ TQString search = filter.lower();
+
+ bool atleastOneMatch = false;
+
+ AlbumList pList = AlbumManager::instance()->allPAlbums();
+ for (AlbumList::iterator it = pList.begin(); it != pList.end(); ++it)
+ {
+ PAlbum* palbum = (PAlbum*)(*it);
+
+ // don't touch the root Album
+ if (palbum->isRoot())
+ continue;
+
+ bool match = palbum->title().lower().contains(search);
+ if (!match)
+ {
+ // check if any of the parents match the search
+ Album* parent = palbum->parent();
+ while (parent && !parent->isRoot())
+ {
+ if (parent->title().lower().contains(search))
+ {
+ match = true;
+ break;
+ }
+
+ parent = parent->parent();
+ }
+ }
+
+ if (!match)
+ {
+ // check if any of the children match the search
+ AlbumIterator it(palbum);
+ while (it.current())
+ {
+ if ((*it)->title().lower().contains(search))
+ {
+ match = true;
+ break;
+ }
+ ++it;
+ }
+ }
+
+ FolderItem* viewItem = (FolderItem*) palbum->extraData(d->folderView);
+
+ if (match)
+ {
+ atleastOneMatch = true;
+
+ if (viewItem)
+ viewItem->setVisible(true);
+ }
+ else
+ {
+ if (viewItem)
+ {
+ viewItem->setVisible(false);
+ }
+ }
+ }
+
+ d->searchBar->slotSearchResult(atleastOneMatch);
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/albumselectdialog.h b/src/utilities/cameragui/albumselectdialog.h
new file mode 100644
index 00000000..aea53319
--- /dev/null
+++ b/src/utilities/cameragui/albumselectdialog.h
@@ -0,0 +1,80 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-06-16
+ * Description : a dialog to select a target album to download
+ * pictures from camera
+ *
+ * Copyright (C) 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 ALBUMSELECTDIALOG_H
+#define ALBUMSELECTDIALOG_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class PAlbum;
+class AlbumSelectDialogPrivate;
+
+class AlbumSelectDialog : public KDialogBase
+{
+ TQ_OBJECT
+
+
+public:
+
+ AlbumSelectDialog(TQWidget* parent, PAlbum* albumToSelect,
+ const TQString& header=TQString(),
+ const TQString& newAlbumString=TQString(),
+ bool allowRootSelection=false);
+ ~AlbumSelectDialog();
+
+
+ static PAlbum* selectAlbum(TQWidget* parent,
+ PAlbum* albumToSelect,
+ const TQString& header=TQString(),
+ const TQString& newAlbumString=TQString(),
+ bool allowRootSelection=false);
+
+private slots:
+
+ void slotAlbumAdded(Album*);
+ void slotAlbumDeleted(Album*);
+ void slotAlbumsCleared();
+ void slotSelectionChanged();
+ void slotContextMenu(TQListViewItem *item, const TQPoint&, int);
+ void slotUser1();
+ void slotSearchTextChanged(const TQString&);
+
+private:
+
+ AlbumSelectDialogPrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* ALBUMSELECTDIALOG_H */
diff --git a/src/utilities/cameragui/animwidget.cpp b/src/utilities/cameragui/animwidget.cpp
new file mode 100644
index 00000000..1d869cd9
--- /dev/null
+++ b/src/utilities/cameragui/animwidget.cpp
@@ -0,0 +1,131 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-21
+ * Description : an animated busy widget
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqpalette.h>
+#include <tqcolor.h>
+#include <tqtimer.h>
+
+// Local includes.
+
+#include "animwidget.h"
+#include "animwidget.moc"
+
+namespace Digikam
+{
+
+class AnimWidgetPriv
+{
+public:
+
+ AnimWidgetPriv()
+ {
+ timer = 0;
+ pos = 0;
+ }
+
+ int pos;
+ int size;
+
+ TQTimer *timer;
+
+ TQPixmap pix;
+};
+
+AnimWidget::AnimWidget(TQWidget* parent, int size)
+ : TQWidget(parent, 0, WResizeNoErase|WRepaintNoErase)
+{
+ d = new AnimWidgetPriv;
+ setBackgroundMode(TQt::NoBackground);
+
+ d->size = size;
+ d->pix = TQPixmap(d->size, d->size);
+ setFixedSize(d->size, d->size);
+
+ d->timer = new TQTimer(this);
+
+ connect(d->timer, TQ_SIGNAL(timeout()),
+ this, TQ_SLOT(slotTimeout()));
+}
+
+AnimWidget::~AnimWidget()
+{
+ delete d;
+}
+
+void AnimWidget::start()
+{
+ d->pos = 0;
+ d->timer->start(100);
+}
+
+void AnimWidget::stop()
+{
+ d->pos = 0;
+ d->timer->stop();
+ repaint();
+}
+
+void AnimWidget::paintEvent(TQPaintEvent*)
+{
+ d->pix.fill(colorGroup().background());
+ TQPainter p(&d->pix);
+
+ p.translate(d->size/2, d->size/2);
+
+ if (d->timer->isActive())
+ {
+ p.setPen(TQPen(colorGroup().text()));
+ p.rotate( d->pos );
+ }
+ else
+ {
+ p.setPen(TQPen(colorGroup().dark()));
+ }
+
+ for ( int i=0 ; i<12 ; i++ )
+ {
+ p.drawLine(d->size/2-4, 0, d->size/2-2, 0);
+ p.rotate(30);
+ }
+
+ p.end();
+ bitBlt(this, 0, 0, &d->pix);
+}
+
+void AnimWidget::slotTimeout()
+{
+ d->pos = (d->pos + 10) % 360;
+ repaint();
+}
+
+bool AnimWidget::running() const
+{
+ return d->timer->isActive();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/animwidget.h b/src/utilities/cameragui/animwidget.h
new file mode 100644
index 00000000..6a93f410
--- /dev/null
+++ b/src/utilities/cameragui/animwidget.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-21
+ * Description : an animated busy widget
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 ANIMWIDGET_H
+#define ANIMWIDGET_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class AnimWidgetPriv;
+
+class AnimWidget : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ AnimWidget(TQWidget* parent, int size=28);
+ ~AnimWidget();
+
+ void start();
+ void stop();
+ bool running() const;
+
+protected:
+
+ void paintEvent(TQPaintEvent*);
+
+private slots:
+
+ void slotTimeout();
+
+private:
+
+ AnimWidgetPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* ANIMWIDGET_H */
diff --git a/src/utilities/cameragui/cameracontroller.cpp b/src/utilities/cameragui/cameracontroller.cpp
new file mode 100644
index 00000000..34afa8ab
--- /dev/null
+++ b/src/utilities/cameragui/cameracontroller.cpp
@@ -0,0 +1,1227 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-17
+ * Description : digital camera controller
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+extern "C"
+{
+#include <unistd.h>
+}
+
+// C++ includes.
+
+#include <typeinfo>
+#include <cstdio>
+
+// TQt includes.
+
+#include <tqthread.h>
+#include <tqmutex.h>
+#include <tqwaitcondition.h>
+#include <tqevent.h>
+#include <tqapplication.h>
+#include <tqdeepcopy.h>
+#include <tqvariant.h>
+#include <tqimage.h>
+#include <tqdatastream.h>
+#include <tqfile.h>
+#include <tqtimer.h>
+#include <tqregexp.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kurl.h>
+#include <tdemessagebox.h>
+#include <tdeio/renamedlg.h>
+#include <kstandarddirs.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "thumbnailsize.h"
+#include "imagewindow.h"
+#include "gpcamera.h"
+#include "umscamera.h"
+#include "dmetadata.h"
+#include "jpegutils.h"
+#include "mtqueue.h"
+#include "cameracontroller.h"
+#include "cameracontroller.moc"
+
+namespace Digikam
+{
+
+class CameraThread;
+
+class CameraCommand
+{
+public:
+
+ enum Action
+ {
+ gp_none = 0,
+ gp_connect,
+ gp_cancel,
+ gp_cameraInformations,
+ gp_listfolders,
+ gp_listfiles,
+ gp_download,
+ gp_upload,
+ gp_delete,
+ gp_lock,
+ gp_thumbnail,
+ gp_exif,
+ gp_open
+ };
+
+ Action action;
+ TQStringVariantMap map;
+};
+
+class CameraEvent : public TQCustomEvent
+{
+public:
+
+ enum State
+ {
+ gp_connected = 0,
+ gp_busy,
+ gp_listedfolders,
+ gp_listedfiles,
+ gp_downloadstarted,
+ gp_downloaded,
+ gp_downloadFailed,
+ gp_opened,
+ gp_uploaded,
+ gp_uploadFailed,
+ gp_deleted,
+ gp_deleteFailed,
+ gp_locked,
+ gp_lockFailed,
+ gp_thumbnailed,
+ gp_exif,
+ gp_cameraInformations,
+ gp_infomsg,
+ gp_errormsg
+ };
+
+ CameraEvent(State state) :
+ TQCustomEvent(TQEvent::User+state)
+ {}
+
+ bool result;
+ TQString msg;
+ TQStringVariantMap map;
+};
+
+class CameraControllerPriv
+{
+public:
+
+ CameraControllerPriv()
+ {
+ close = false;
+ overwriteAll = false;
+ skipAll = false;
+ canceled = false;
+ downloadTotal = 0;
+ parent = 0;
+ timer = 0;
+ camera = 0;
+ thread = 0;
+ }
+
+ bool close;
+ bool overwriteAll;
+ bool skipAll;
+ bool canceled;
+
+ int downloadTotal;
+
+ TQWidget *parent;
+
+ TQTimer *timer;
+
+ CameraThread *thread;
+
+ DKCamera *camera;
+
+ MTQueue<CameraCommand> cmdQueue;
+};
+
+class CameraThread : public TQThread
+{
+public:
+
+ CameraThread(CameraController* controller);
+ ~CameraThread();
+
+ void sendBusy(bool busy);
+ void sendError(const TQString& msg);
+ void sendInfo(const TQString& msg);
+
+protected:
+
+ void run();
+
+private:
+
+ CameraControllerPriv *d;
+
+ TQObject *parent;
+};
+
+CameraThread::CameraThread(CameraController* controller)
+ : d(controller->d), parent(controller)
+{
+}
+
+CameraThread::~CameraThread()
+{
+}
+
+void CameraThread::run()
+{
+ if (d->close)
+ return;
+
+ sendBusy(true);
+
+ CameraCommand* cmd = d->cmdQueue.dequeue();
+ if (cmd)
+ {
+ switch (cmd->action)
+ {
+ case(CameraCommand::gp_connect):
+ {
+ sendInfo(i18n("Connecting to camera..."));
+
+ bool result = d->camera->doConnect();
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_connected);
+ event->result = result;
+ TQApplication::postEvent(parent, event);
+
+ if (result)
+ sendInfo(i18n("Connection established"));
+ else
+ sendInfo(i18n("Connection failed"));
+
+ break;
+ }
+ case(CameraCommand::gp_cameraInformations):
+ {
+ sendInfo(i18n("Getting camera information..."));
+
+ TQString summary, manual, about;
+
+ d->camera->cameraSummary(summary);
+ d->camera->cameraManual(manual);
+ d->camera->cameraAbout(about);
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_cameraInformations);
+ event->map.insert("summary", TQVariant(summary));
+ event->map.insert("manual", TQVariant(manual));
+ event->map.insert("about", TQVariant(about));
+ TQApplication::postEvent(parent, event);
+ break;
+ }
+ case(CameraCommand::gp_listfolders):
+ {
+ sendInfo(i18n("Listing folders..."));
+
+ TQStringList folderList;
+ folderList.append(d->camera->path());
+ d->camera->getAllFolders(d->camera->path(), folderList);
+
+ /* TODO: ugly hack since qt <= 3.1.2 does not define
+ TQStringList with TQDeepCopy as a friend. */
+ TQValueList<TQString> flist(folderList);
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_listedfolders);
+ event->map.insert("folders", TQVariant(flist));
+ TQApplication::postEvent(parent, event);
+
+ sendInfo(i18n("The folders have been listed."));
+
+ break;
+ }
+ case(CameraCommand::gp_listfiles):
+ {
+ TQString folder = cmd->map["folder"].asString();
+
+ sendInfo(i18n("The files in %1 have been listed.").arg(folder));
+
+ GPItemInfoList itemsList;
+ // setting getImageDimensions to false is a huge speedup for UMSCamera
+ if (!d->camera->getItemsInfoList(folder, itemsList, false))
+ {
+ sendError(i18n("Failed to list files in %1").arg(folder));
+ }
+
+ if (!itemsList.isEmpty())
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_listedfiles);
+ event->map.insert("folder", TQVariant(folder));
+
+ TQByteArray ba;
+ TQDataStream ds(ba, IO_WriteOnly);
+ ds << itemsList;
+
+ event->map.insert("files", TQVariant(ba));
+ TQApplication::postEvent(parent, event);
+ }
+
+ sendInfo(i18n("Listing files in %1 is complete").arg(folder));
+
+ break;
+ }
+ case(CameraCommand::gp_thumbnail):
+ {
+ TQString folder = cmd->map["folder"].asString();
+ TQString file = cmd->map["file"].asString();
+
+ sendInfo(i18n("Getting thumbnails..."));
+
+ TQImage thumbnail;
+ d->camera->getThumbnail(folder, file, thumbnail);
+
+ if (!thumbnail.isNull())
+ {
+ thumbnail = thumbnail.smoothScale(ThumbnailSize::Huge, ThumbnailSize::Huge, TQImage::ScaleMin);
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_thumbnailed);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("thumbnail", TQVariant(thumbnail));
+ TQApplication::postEvent(parent, event);
+ }
+
+ break;
+ }
+ case(CameraCommand::gp_exif):
+ {
+ TQString folder = cmd->map["folder"].asString();
+ TQString file = cmd->map["file"].asString();
+
+ sendInfo(i18n("Getting EXIF information for %1/%2...").arg(folder).arg(file));
+
+ char* edata = 0;
+ int esize = 0;
+ d->camera->getExif(folder, file, &edata, esize);
+
+ if (edata || esize)
+ {
+ TQByteArray ba;
+ TQDataStream ds(ba, IO_WriteOnly);
+ ds.writeRawBytes(edata, esize);
+ delete [] edata;
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_exif);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("exifSize", TQVariant(esize));
+ event->map.insert("exifData", TQVariant(ba));
+ TQApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_download):
+ {
+ TQString folder = cmd->map["folder"].asString();
+ TQString file = cmd->map["file"].asString();
+ TQString dest = cmd->map["dest"].asString();
+ bool autoRotate = cmd->map["autoRotate"].asBool();
+ bool fixDateTime = cmd->map["fixDateTime"].asBool();
+ TQDateTime newDateTime = cmd->map["newDateTime"].asDateTime();
+ bool setPhotographerId = cmd->map["setPhotographerId"].asBool();
+ TQString author = cmd->map["author"].asString();
+ TQString authorTitle = cmd->map["authorTitle"].asString();
+ bool setCredits = cmd->map["setCredits"].asBool();
+ TQString credit = cmd->map["credit"].asString();
+ TQString source = cmd->map["source"].asString();
+ TQString copyright = cmd->map["copyright"].asString();
+ bool convertJpeg = cmd->map["convertJpeg"].asBool();
+ TQString losslessFormat = cmd->map["losslessFormat"].asString();
+ sendInfo(i18n("Downloading file %1...").arg(file));
+
+ // download to a temp file
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_downloadstarted);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("dest", TQVariant(dest));
+ TQApplication::postEvent(parent, event);
+
+ KURL tempURL(dest);
+ tempURL = tempURL.upURL();
+ tempURL.addPath( TQString(".digikam-camera-tmp1-%1").arg(getpid()).append(file));
+ DDebug() << "Downloading: " << file << " using (" << tempURL.path() << ")" << endl;
+ TQString temp = tempURL.path();
+
+ bool result = d->camera->downloadItem(folder, file, tempURL.path());
+
+ if (result && isJpegImage(tempURL.path()))
+ {
+ if (autoRotate)
+ {
+ DDebug() << "Exif autorotate: " << file << " using (" << tempURL.path() << ")" << endl;
+ sendInfo(i18n("EXIF rotating file %1...").arg(file));
+ exifRotate(tempURL.path(), file);
+ }
+
+ if (fixDateTime || setPhotographerId || setCredits)
+ {
+ DDebug() << "Set Metadata from: " << file << " using (" << tempURL.path() << ")" << endl;
+ sendInfo(i18n("Setting Metadata tags to file %1...").arg(file));
+ DMetadata metadata(tempURL.path());
+
+ if (fixDateTime)
+ metadata.setImageDateTime(newDateTime, true);
+
+ if (setPhotographerId)
+ metadata.setImagePhotographerId(author, authorTitle);
+
+ if (setCredits)
+ metadata.setImageCredits(credit, source, copyright);
+
+ metadata.applyChanges();
+ }
+
+ // Convert Jpeg file to lossless format if necessary,
+ // and move converted image to destination.
+
+ if (convertJpeg)
+ {
+ DDebug() << "Convert to LossLess: " << file << " using (" << tempURL.path() << ")" << endl;
+ sendInfo(i18n("Converting %1 to lossless file format...").arg(file));
+
+ KURL tempURL2(dest);
+ tempURL2 = tempURL2.upURL();
+ tempURL2.addPath( TQString(".digikam-camera-tmp2-%1").arg(getpid()).append(file));
+ temp = tempURL2.path();
+
+ if (!jpegConvert(tempURL.path(), tempURL2.path(), file, losslessFormat))
+ {
+ // convert failed. delete the temp file
+ unlink(TQFile::encodeName(tempURL.path()));
+ unlink(TQFile::encodeName(tempURL2.path()));
+ result = false;
+ }
+ else
+ {
+ // Else remove only the first temp file.
+ unlink(TQFile::encodeName(tempURL.path()));
+ }
+ }
+ }
+
+ if (result)
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_downloaded);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("dest", TQVariant(dest));
+ event->map.insert("temp", TQVariant(temp));
+ TQApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_downloadFailed);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("dest", TQVariant(dest));
+ TQApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_open):
+ {
+ TQString folder = cmd->map["folder"].asString();
+ TQString file = cmd->map["file"].asString();
+ TQString dest = cmd->map["dest"].asString();
+
+ sendInfo(i18n("Retrieving file %1 from camera...").arg(file));
+
+ bool result = d->camera->downloadItem(folder, file, dest);
+
+ if (result)
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_opened);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("dest", TQVariant(dest));
+ TQApplication::postEvent(parent, event);
+ }
+ else
+ {
+ sendError(i18n("Failed to retrieve file %1 from camera").arg(file));
+ }
+ break;
+ }
+ case(CameraCommand::gp_upload):
+ {
+ TQString folder = cmd->map["destFolder"].asString();
+
+ // We will using the same source file name to create the dest file
+ // name in camera.
+ TQString file = cmd->map["destFile"].asString();
+
+ // The source file path to download in camera.
+ TQString src = cmd->map["srcFilePath"].asString();
+
+ sendInfo(i18n("Uploading file %1 to camera...").arg(file));
+
+ GPItemInfo itemsInfo;
+
+ bool result = d->camera->uploadItem(folder, file, src, itemsInfo);
+
+ if (result)
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_uploaded);
+ TQByteArray ba;
+ TQDataStream ds(ba, IO_WriteOnly);
+ ds << itemsInfo;
+ event->map.insert("info", TQVariant(ba));
+
+ TQApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_uploadFailed);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ event->map.insert("src", TQVariant(src));
+ TQApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_delete):
+ {
+ TQString folder = cmd->map["folder"].asString();
+ TQString file = cmd->map["file"].asString();
+
+ sendInfo(i18n("Deleting file %1...").arg(file));
+
+ bool result = d->camera->deleteItem(folder, file);
+
+ if (result)
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_deleted);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ TQApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_deleteFailed);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ TQApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_lock):
+ {
+ TQString folder = cmd->map["folder"].asString();
+ TQString file = cmd->map["file"].asString();
+ bool lock = cmd->map["lock"].asBool();
+
+ sendInfo(i18n("Toggle lock file %1...").arg(file));
+
+ bool result = d->camera->setLockItem(folder, file, lock);
+
+ if (result)
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_locked);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ TQApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_lockFailed);
+ event->map.insert("folder", TQVariant(folder));
+ event->map.insert("file", TQVariant(file));
+ TQApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ default:
+ DWarning() << k_funcinfo << " unknown action specified" << endl;
+ }
+
+ delete cmd;
+ }
+
+ sendBusy(false);
+}
+
+void CameraThread::sendBusy(bool val)
+{
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_busy);
+ event->result = val;
+ TQApplication::postEvent(parent, event);
+}
+
+void CameraThread::sendError(const TQString& msg)
+{
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_errormsg);
+ event->msg = msg;
+ TQApplication::postEvent(parent, event);
+}
+
+void CameraThread::sendInfo(const TQString& msg)
+{
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_infomsg);
+ event->msg = msg;
+ TQApplication::postEvent(parent, event);
+}
+
+
+//-- Camera Controller ------------------------------------------------------
+
+
+CameraController::CameraController(TQWidget* parent, const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path)
+ : TQObject(parent)
+{
+ d = new CameraControllerPriv;
+ d->parent = parent;
+ d->canceled = false;
+ d->close = false;
+ d->overwriteAll = false;
+ d->skipAll = false;
+ d->downloadTotal = 0;
+ d->camera = 0;
+
+ // URL parsing (c) Stephan Kulow
+ if (path.startsWith("camera:/"))
+ {
+ KURL url(path);
+ DDebug() << "path " << path << " " << url << " " << url.host() << endl;
+ TQString xport = url.host();
+ if (xport.startsWith("usb:"))
+ {
+ DDebug() << "xport " << xport << endl;
+ TQRegExp x = TQRegExp("(usb:[0-9,]*)");
+
+ if (x.search(xport) != -1)
+ {
+ TQString usbport = x.cap(1);
+ DDebug() << "USB " << xport << " " << usbport << endl;
+ // if ((xport == usbport) || ((count == 1) && (xport == "usb:"))) {
+ // model = xmodel;
+ d->camera = new GPCamera(title, url.user(), "usb:", "/");
+ // }
+ }
+ }
+ }
+
+ if (!d->camera)
+ {
+ if (model.lower() == "directory browse")
+ d->camera = new UMSCamera(title, model, port, path);
+ else
+ d->camera = new GPCamera(title, model, port, path);
+ }
+
+ d->thread = new CameraThread(this);
+ d->timer = new TQTimer(this);
+
+ connect(d->timer, TQ_SIGNAL(timeout()),
+ this, TQ_SLOT(slotProcessNext()));
+
+ d->timer->start(50, false);
+}
+
+CameraController::~CameraController()
+{
+ if (d->timer->isActive())
+ {
+ d->timer->stop();
+ delete d->timer;
+ }
+
+ d->camera->cancel();
+ d->canceled = true;
+ d->close = true;
+
+ while (d->thread->running())
+ d->thread->wait();
+
+ delete d->thread;
+ delete d->camera;
+ delete d;
+}
+
+TQString CameraController::getCameraPath()
+{
+ if (!d->camera) return TQString();
+ return d->camera->path();
+}
+
+TQString CameraController::getCameraTitle()
+{
+ if (!d->camera) return TQString();
+ return d->camera->title();
+}
+
+void CameraController::slotConnect()
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_connect;
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::listFolders()
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_listfolders;
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::listFiles(const TQString& folder)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_listfiles;
+ cmd->map.insert("folder", TQVariant(folder));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::getThumbnail(const TQString& folder, const TQString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_thumbnail;
+ cmd->map.insert("folder", TQVariant(folder));
+ cmd->map.insert("file", TQVariant(file));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::getExif(const TQString& folder, const TQString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_exif;
+ cmd->map.insert("folder", TQVariant(folder));
+ cmd->map.insert("file", TQVariant(file));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::getCameraInformations()
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_cameraInformations;
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::upload(const TQFileInfo& srcFileInfo, const TQString& destFile, const TQString& destFolder)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_upload;
+ cmd->map.insert("srcFilePath", TQVariant(srcFileInfo.filePath()));
+ cmd->map.insert("destFile", TQVariant(destFile));
+ cmd->map.insert("destFolder", TQVariant(destFolder));
+ d->cmdQueue.enqueue(cmd);
+ DDebug() << "Uploading '" << srcFileInfo.filePath() << "' into camera : '" << destFolder <<
+ "' (" << destFile << ")" << endl;
+}
+
+void CameraController::downloadPrep()
+{
+ d->overwriteAll = false;
+ d->skipAll = false;
+ d->downloadTotal = 0;
+}
+
+void CameraController::download(DownloadSettingsContainer downloadSettings)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_download;
+ cmd->map.insert("folder", TQVariant(downloadSettings.folder));
+ cmd->map.insert("file", TQVariant(downloadSettings.file));
+ cmd->map.insert("dest", TQVariant(downloadSettings.dest));
+ cmd->map.insert("autoRotate", TQVariant(downloadSettings.autoRotate));
+ cmd->map.insert("fixDateTime", TQVariant(downloadSettings.fixDateTime));
+ cmd->map.insert("newDateTime", TQVariant(downloadSettings.newDateTime));
+ cmd->map.insert("setPhotographerId", TQVariant(downloadSettings.setPhotographerId));
+ cmd->map.insert("author", TQVariant(downloadSettings.author));
+ cmd->map.insert("authorTitle", TQVariant(downloadSettings.authorTitle));
+ cmd->map.insert("setCredits", TQVariant(downloadSettings.setCredits));
+ cmd->map.insert("credit", TQVariant(downloadSettings.credit));
+ cmd->map.insert("source", TQVariant(downloadSettings.source));
+ cmd->map.insert("copyright", TQVariant(downloadSettings.copyright));
+ cmd->map.insert("convertJpeg", TQVariant(downloadSettings.convertJpeg));
+ cmd->map.insert("losslessFormat", TQVariant(downloadSettings.losslessFormat));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::deleteFile(const TQString& folder, const TQString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_delete;
+ cmd->map.insert("folder", TQVariant(folder));
+ cmd->map.insert("file", TQVariant(file));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::lockFile(const TQString& folder, const TQString& file, bool lock)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_lock;
+ cmd->map.insert("folder", TQVariant(folder));
+ cmd->map.insert("file", TQVariant(file));
+ cmd->map.insert("lock", TQVariant(lock));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::openFile(const TQString& folder, const TQString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_open;
+ cmd->map.insert("folder", TQVariant(folder));
+ cmd->map.insert("file", TQVariant(file));
+ cmd->map.insert("dest", TQVariant(locateLocal("tmp", file)));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::slotCancel()
+{
+ d->canceled = true;
+ d->cmdQueue.flush();
+ d->camera->cancel();
+}
+
+void CameraController::customEvent(TQCustomEvent* e)
+{
+ CameraEvent* event = dynamic_cast<CameraEvent*>(e);
+ if (!event)
+ {
+ return;
+ }
+
+ switch(event->type()-TQEvent::User)
+ {
+ case (CameraEvent::gp_connected) :
+ {
+ emit signalConnected(event->result);
+ break;
+ }
+ case (CameraEvent::gp_cameraInformations) :
+ {
+ TQString summary = TQDeepCopy<TQString>(event->map["summary"].asString());
+ TQString manual = TQDeepCopy<TQString>(event->map["manual"].asString());
+ TQString about = TQDeepCopy<TQString>(event->map["about"].asString());
+ emit signalCameraInformations(summary, manual, about);
+ break;
+ }
+ case (CameraEvent::gp_errormsg) :
+ {
+ emit signalErrorMsg(TQDeepCopy<TQString>(event->msg));
+ break;
+ }
+ case (CameraEvent::gp_busy) :
+ {
+ if (event->result)
+ emit signalBusy(true);
+ break;
+ }
+ case (CameraEvent::gp_infomsg) :
+ {
+ if (!d->canceled)
+ emit signalInfoMsg(TQDeepCopy<TQString>(event->msg));
+ break;
+ }
+ case (CameraEvent::gp_listedfolders) :
+ {
+ /* TODO: ugly hack since qt <= 3.1.2 does not define
+ TQStringList with TQDeepCopy as a friend. */
+ TQValueList<TQVariant> flist = TQDeepCopy< TQValueList<TQVariant> >(event->map["folders"].toList());
+
+ TQStringList folderList;
+ TQValueList<TQVariant>::Iterator it;
+ for (it = flist.begin(); it != flist.end(); ++it )
+ {
+ folderList.append(TQDeepCopy<TQString>((*it).asString()));
+ }
+
+ emit signalFolderList(folderList);
+ break;
+ }
+ case (CameraEvent::gp_listedfiles) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQByteArray ba = TQDeepCopy<TQByteArray>(event->map["files"].asByteArray());
+ TQDataStream ds(ba, IO_ReadOnly);
+ GPItemInfoList items;
+ ds >> items;
+ emit signalFileList(items);
+ break;
+ }
+ case (CameraEvent::gp_thumbnailed) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ TQImage thumb = TQDeepCopy<TQImage>(event->map["thumbnail"].asImage());
+ emit signalThumbnail(folder, file, thumb);
+ break;
+ }
+ case (CameraEvent::gp_exif) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ TQByteArray ba = TQDeepCopy<TQByteArray>(event->map["exifData"].asByteArray());
+ emit signalExifData(ba);
+ break;
+ }
+ case (CameraEvent::gp_downloadstarted) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ emit signalDownloaded(folder, file, GPItemInfo::DownloadStarted);
+ break;
+ }
+ case (CameraEvent::gp_downloaded) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ TQString dest = TQDeepCopy<TQString>(event->map["dest"].asString());
+ TQString temp = TQDeepCopy<TQString>(event->map["temp"].asString());
+
+ d->timer->stop();
+
+ bool skip = false;
+ bool cancel = false;
+ bool overwrite = false;
+
+ // Check if dest file already exist.
+
+ if (!d->overwriteAll)
+ {
+ TQFileInfo info(dest);
+
+ while (info.exists())
+ {
+ if (d->skipAll)
+ {
+ skip = true;
+ break;
+ }
+
+ TDEIO::RenameDlg dlg(d->parent, i18n("Rename File"),
+ folder + TQString("/") + file, dest,
+ TDEIO::RenameDlg_Mode(TDEIO::M_MULTI | TDEIO::M_OVERWRITE | TDEIO::M_SKIP));
+
+ int result = dlg.exec();
+ dest = dlg.newDestURL().path();
+ info = TQFileInfo(dest);
+
+ switch (result)
+ {
+ case TDEIO::R_CANCEL:
+ {
+ cancel = true;
+ break;
+ }
+ case TDEIO::R_SKIP:
+ {
+ skip = true;
+ break;
+ }
+ case TDEIO::R_AUTO_SKIP:
+ {
+ d->skipAll = true;
+ skip = true;
+ break;
+ }
+ case TDEIO::R_OVERWRITE:
+ {
+ overwrite = true;
+ break;
+ }
+ case TDEIO::R_OVERWRITE_ALL:
+ {
+ d->overwriteAll = true;
+ overwrite = true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (cancel || skip || overwrite)
+ break;
+ }
+ }
+
+ if (cancel)
+ {
+ unlink(TQFile::encodeName(temp));
+ slotCancel();
+ d->timer->start(50);
+ emit signalSkipped(folder, file);
+ return;
+ }
+ else if (skip)
+ {
+ unlink(TQFile::encodeName(temp));
+ d->timer->start(50);
+ emit signalInfoMsg(i18n("Skipped file %1").arg(file));
+ emit signalSkipped(folder, file);
+ return;
+ }
+
+ // move the file to the destination file
+ if (rename(TQFile::encodeName(temp), TQFile::encodeName(dest)) != 0)
+ {
+ // rename failed. delete the temp file
+ unlink(TQFile::encodeName(temp));
+ d->timer->start(50);
+ emit signalDownloaded(folder, file, GPItemInfo::DownloadFailed);
+ }
+ else
+ {
+ d->timer->start(50);
+ emit signalDownloaded(folder, file, GPItemInfo::DownloadedYes);
+ }
+ break;
+ }
+ case (CameraEvent::gp_downloadFailed) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+
+ d->timer->stop();
+
+ TQString msg = i18n("Failed to download file \"%1\".").arg(file);
+
+ if (!d->canceled)
+ {
+ if (d->cmdQueue.isEmpty())
+ {
+ KMessageBox::error(d->parent, msg);
+ }
+ else
+ {
+ msg += i18n(" Do you want to continue?");
+ int result = KMessageBox::warningContinueCancel(d->parent, msg);
+ if (result != KMessageBox::Continue)
+ slotCancel();
+ }
+ }
+
+ d->timer->start(50);
+ emit signalDownloaded(folder, file, GPItemInfo::DownloadFailed);
+ break;
+ }
+ case (CameraEvent::gp_uploaded) :
+ {
+ TQByteArray ba = TQDeepCopy<TQByteArray>(event->map["info"].asByteArray());
+ TQDataStream ds(ba, IO_ReadOnly);
+ GPItemInfo itemInfo;
+ ds >> itemInfo;
+
+ emit signalUploaded(itemInfo);
+ break;
+ }
+ case (CameraEvent::gp_uploadFailed) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ TQString src = TQDeepCopy<TQString>(event->map["src"].asString());
+
+ d->timer->stop();
+
+ TQString msg = i18n("Failed to upload file \"%1\".").arg(file);
+
+ if (!d->canceled)
+ {
+ if (d->cmdQueue.isEmpty())
+ {
+ KMessageBox::error(d->parent, msg);
+ }
+ else
+ {
+ msg += i18n(" Do you want to continue?");
+ int result = KMessageBox::warningContinueCancel(d->parent, msg);
+ if (result != KMessageBox::Continue)
+ slotCancel();
+ }
+ }
+
+ d->timer->start(50);
+ break;
+ }
+ case (CameraEvent::gp_deleted) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ emit signalDeleted(folder, file, true);
+ break;
+ }
+ case (CameraEvent::gp_deleteFailed) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+
+ d->timer->stop();
+ emit signalDeleted(folder, file, false);
+
+ TQString msg = i18n("Failed to delete file \"%1\".").arg(file);
+
+ if (!d->canceled)
+ {
+ if (d->cmdQueue.isEmpty())
+ {
+ KMessageBox::error(d->parent, msg);
+ }
+ else
+ {
+ msg += i18n(" Do you want to continue?");
+ int result = KMessageBox::warningContinueCancel(d->parent, msg);
+ if (result != KMessageBox::Continue)
+ slotCancel();
+ }
+ }
+
+ d->timer->start(50);
+ break;
+ }
+ case (CameraEvent::gp_locked) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ emit signalLocked(folder, file, true);
+ break;
+ }
+ case (CameraEvent::gp_lockFailed) :
+ {
+ TQString folder = TQDeepCopy<TQString>(event->map["folder"].asString());
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+
+ d->timer->stop();
+ emit signalLocked(folder, file, false);
+
+ TQString msg = i18n("Failed to toggle lock file \"%1\".").arg(file);
+
+ if (!d->canceled)
+ {
+ if (d->cmdQueue.isEmpty())
+ {
+ KMessageBox::error(d->parent, msg);
+ }
+ else
+ {
+ msg += i18n(" Do you want to continue?");
+ int result = KMessageBox::warningContinueCancel(d->parent, msg);
+ if (result != KMessageBox::Continue)
+ slotCancel();
+ }
+ }
+
+ d->timer->start(50);
+ break;
+ }
+ case (CameraEvent::gp_opened) :
+ {
+ TQString file = TQDeepCopy<TQString>(event->map["file"].asString());
+ TQString dest = TQDeepCopy<TQString>(event->map["dest"].asString());
+
+ KURL url(dest);
+ KURL::List urlList;
+ urlList << url;
+
+ ImageWindow *im = ImageWindow::imagewindow();
+ im->loadURL(urlList, url, i18n("Camera \"%1\"").arg(d->camera->model()), false);
+
+ if (im->isHidden())
+ im->show();
+ else
+ im->raise();
+
+ im->setFocus();
+ break;
+ }
+ default:
+ {
+ DWarning() << k_funcinfo << "Unknown event" << endl;
+ }
+ }
+}
+
+void CameraController::slotProcessNext()
+{
+ if (d->thread->running())
+ return;
+
+ if (d->cmdQueue.isEmpty())
+ {
+ emit signalBusy(false);
+ return;
+ }
+
+ d->timer->stop();
+ emit signalBusy(true);
+
+ CameraCommand* cmd = d->cmdQueue.head();
+
+ TQString folder;
+ TQString file;
+ TQString dest;
+
+ if ((cmd->action == CameraCommand::gp_exif) &&
+ (typeid(*(d->camera)) == typeid(UMSCamera)))
+ {
+ folder = TQDeepCopy<TQString>(cmd->map["folder"].asString());
+ file = TQDeepCopy<TQString>(cmd->map["file"].asString());
+
+ emit signalExifFromFile(folder, file);
+
+ d->cmdQueue.dequeue();
+ d->timer->start(50, false);
+ return;
+ }
+
+ if (cmd->action == CameraCommand::gp_download)
+ {
+ folder = TQDeepCopy<TQString>(cmd->map["folder"].asString());
+ file = TQDeepCopy<TQString>(cmd->map["file"].asString());
+ dest = TQDeepCopy<TQString>(cmd->map["dest"].asString());
+ cmd->map["dest"] = TQVariant(TQDeepCopy<TQString>(dest));
+ }
+
+ d->thread->start();
+ d->timer->start(50, false);
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/cameracontroller.h b/src/utilities/cameragui/cameracontroller.h
new file mode 100644
index 00000000..45e7fede
--- /dev/null
+++ b/src/utilities/cameragui/cameracontroller.h
@@ -0,0 +1,111 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-17
+ * Description : digital camera controller
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 CAMERACONTROLLER_H
+#define CAMERACONTROLLER_H
+
+// TQt includes.
+
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqfileinfo.h>
+
+// Local includes.
+
+#include "downloadsettingscontainer.h"
+#include "gpiteminfo.h"
+
+namespace Digikam
+{
+
+class CameraControllerPriv;
+
+class CameraController : public TQObject
+{
+ TQ_OBJECT
+
+
+public:
+
+ CameraController(TQWidget* parent, const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path);
+ ~CameraController();
+
+ void listFolders();
+ void listFiles(const TQString& folder);
+ void getThumbnail(const TQString& folder, const TQString& file);
+ void getExif(const TQString& folder, const TQString& file);
+ void getCameraInformations();
+ TQString getCameraPath();
+ TQString getCameraTitle();
+
+ void downloadPrep();
+ void download(DownloadSettingsContainer downloadSettings);
+ void upload(const TQFileInfo& srcFileInfo, const TQString& destFile, const TQString& destFolder);
+ void deleteFile(const TQString& folder, const TQString& file);
+ void lockFile(const TQString& folder, const TQString& file, bool lock);
+ void openFile(const TQString& folder, const TQString& file);
+
+signals:
+
+ void signalBusy(bool val);
+ void signalInfoMsg(const TQString& msg);
+ void signalErrorMsg(const TQString& msg);
+ void signalCameraInformations(const TQString& summary, const TQString& manual, const TQString& about);
+
+ void signalConnected(bool val);
+ void signalFolderList(const TQStringList& folderList);
+ void signalFileList(const GPItemInfoList& infoList);
+ void signalUploaded(const GPItemInfo& itemInfo);
+ void signalDownloaded(const TQString& folder, const TQString& file, int status);
+ void signalSkipped(const TQString& folder, const TQString& file);
+ void signalDeleted(const TQString& folder, const TQString& file, bool status);
+ void signalLocked(const TQString& folder, const TQString& file, bool status);
+ void signalThumbnail(const TQString& folder, const TQString& file, const TQImage& thumb);
+ void signalExifFromFile(const TQString& folder, const TQString& file);
+ void signalExifData(const TQByteArray& exifData);
+
+protected:
+
+ void customEvent(TQCustomEvent* e);
+
+public slots:
+
+ void slotCancel();
+ void slotConnect();
+
+private slots:
+
+ void slotProcessNext();
+
+private:
+
+ CameraControllerPriv *d;
+
+ friend class CameraThread;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERACONTROLLER_H */
diff --git a/src/utilities/cameragui/camerafolderdialog.cpp b/src/utilities/cameragui/camerafolderdialog.cpp
new file mode 100644
index 00000000..93feb0ab
--- /dev/null
+++ b/src/utilities/cameragui/camerafolderdialog.cpp
@@ -0,0 +1,138 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-07-24
+ * Description : a dialog to select a camera folders.
+ *
+ * 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 <tqlayout.h>
+#include <tqframe.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "cameraiconview.h"
+#include "camerafolderitem.h"
+#include "camerafolderview.h"
+#include "camerafolderdialog.h"
+#include "camerafolderdialog.moc"
+
+namespace Digikam
+{
+
+CameraFolderDialog::CameraFolderDialog(TQWidget *parent, CameraIconView *cameraView,
+ const TQStringList& cameraFolderList,
+ const TQString& cameraName, const TQString& rootPath)
+ : KDialogBase(parent, 0, true,
+ i18n("%1 - Select Camera Folder").arg(cameraName),
+ Help|Ok|Cancel, Ok, true)
+{
+ setHelp("camerainterface.anchor", "digikam");
+ enableButtonOK(false);
+
+ m_rootPath = rootPath;
+
+ TQFrame *page = makeMainWidget();
+ TQGridLayout* grid = new TQGridLayout(page, 2, 1, 0, spacingHint());
+
+ m_folderView = new CameraFolderView(page);
+ TQLabel *logo = new TQLabel(page);
+ TQLabel *message = new TQLabel(page);
+
+ TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 128, TDEIcon::DefaultState, 0, true));
+ message->setText(i18n("<p>Please select the camera folder "
+ "where you want to upload the images.</p>"));
+
+ grid->addMultiCellWidget(logo, 0, 0, 0, 0);
+ grid->addMultiCellWidget(message, 1, 1, 0, 0);
+ grid->addMultiCellWidget(m_folderView, 0, 2, 1, 1);
+ grid->setRowStretch(2, 10);
+
+ m_folderView->addVirtualFolder(cameraName);
+ m_folderView->addRootFolder("/", cameraView->countItemsByFolder(rootPath));
+
+ for (TQStringList::const_iterator it = cameraFolderList.begin();
+ it != cameraFolderList.end(); ++it)
+ {
+ TQString folder(*it);
+ if (folder.startsWith(rootPath) && rootPath != TQString("/"))
+ folder.remove(0, rootPath.length());
+
+ if (folder != TQString("/") && !folder.isEmpty())
+ {
+ TQString root = folder.section( '/', 0, -2 );
+ if (root.isEmpty()) root = TQString("/");
+
+ TQString sub = folder.section( '/', -1 );
+ m_folderView->addFolder(root, sub, cameraView->countItemsByFolder(*it));
+ DDebug() << "Camera folder: '" << folder << "' (root='" << root << "', sub='" <<sub <<"')" << endl;
+ }
+ }
+
+ connect(m_folderView, TQ_SIGNAL(signalFolderChanged(CameraFolderItem*)),
+ this, TQ_SLOT(slotFolderPathSelectionChanged(CameraFolderItem*)));
+
+ resize(500, 500);
+}
+
+CameraFolderDialog::~CameraFolderDialog()
+{
+}
+
+TQString CameraFolderDialog::selectedFolderPath()
+{
+ TQListViewItem *item = m_folderView->currentItem();
+ if (!item) return TQString();
+
+ CameraFolderItem *folderItem = static_cast<CameraFolderItem *>(item);
+ if (folderItem->isVirtualFolder())
+ return TQString(m_rootPath);
+
+ // Case of Gphoto2 cameras. No need to duplicate root '/'.
+ if (m_rootPath == TQString("/"))
+ return(folderItem->folderPath());
+
+ return(m_rootPath + folderItem->folderPath());
+}
+
+void CameraFolderDialog::slotFolderPathSelectionChanged(CameraFolderItem* item)
+{
+ if (item)
+ {
+ enableButtonOK(true);
+ DDebug() << "Camera folder path: " << selectedFolderPath() << endl;
+ }
+ else
+ {
+ enableButtonOK(false);
+ }
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/cameragui/camerafolderdialog.h b/src/utilities/cameragui/camerafolderdialog.h
new file mode 100644
index 00000000..efc7586a
--- /dev/null
+++ b/src/utilities/cameragui/camerafolderdialog.h
@@ -0,0 +1,68 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-07-24
+ * Description : a dialog to select a camera folders.
+ *
+ * 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 CAMERAFOLDERDIALOG_H
+#define CAMERAFOLDERDIALOG_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class CameraIconView;
+class CameraFolderView;
+class CameraFolderItem;
+
+class CameraFolderDialog : public KDialogBase
+{
+ TQ_OBJECT
+
+
+public:
+
+ CameraFolderDialog(TQWidget *parent, CameraIconView *cameraView, const TQStringList& cameraFolderList,
+ const TQString& cameraName, const TQString& rootPath);
+ ~CameraFolderDialog();
+
+ TQString selectedFolderPath();
+
+private slots:
+
+ void slotFolderPathSelectionChanged(CameraFolderItem* item);
+
+private:
+
+ TQString m_rootPath;
+
+ CameraFolderView *m_folderView;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAFOLDERDIALOG_H */
diff --git a/src/utilities/cameragui/camerafolderitem.cpp b/src/utilities/cameragui/camerafolderitem.cpp
new file mode 100644
index 00000000..f53508a6
--- /dev/null
+++ b/src/utilities/cameragui/camerafolderitem.cpp
@@ -0,0 +1,108 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-23
+ * Description : A widget to display a camera folder.
+ *
+ * Copyright (C) 2003-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 bythe 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 "camerafolderitem.h"
+
+namespace Digikam
+{
+
+class CameraFolderItemPriv
+{
+public:
+
+ CameraFolderItemPriv()
+ {
+ count = 0;
+ }
+
+ bool virtualFolder;
+
+ int count;
+
+ TQString folderName;
+ TQString folderPath;
+ TQString name;
+};
+
+CameraFolderItem::CameraFolderItem(TQListView* parent, const TQString& name, const TQPixmap& pixmap)
+ : TQListViewItem(parent, name)
+{
+ d = new CameraFolderItemPriv;
+ d->virtualFolder = true;
+ d->name = name;
+ setPixmap(0, pixmap);
+}
+
+CameraFolderItem::CameraFolderItem(TQListViewItem* parent, const TQString& folderName,
+ const TQString& folderPath, const TQPixmap& pixmap)
+ : TQListViewItem(parent, folderName)
+{
+ d = new CameraFolderItemPriv;
+ d->folderName = folderName;
+ d->folderPath = folderPath;
+ d->virtualFolder = false;
+ d->name = folderName;
+ setPixmap(0, pixmap);
+}
+
+CameraFolderItem::~CameraFolderItem()
+{
+ delete d;
+}
+
+bool CameraFolderItem::isVirtualFolder()
+{
+ return d->virtualFolder;
+}
+
+TQString CameraFolderItem::folderName()
+{
+ return d->folderName;
+}
+
+TQString CameraFolderItem::folderPath()
+{
+ return d->folderPath;
+}
+
+void CameraFolderItem::changeCount(int val)
+{
+ d->count += val;
+ setText(0, TQString("%1 (%2)").arg(d->name).arg(TQString::number(d->count)));
+}
+
+void CameraFolderItem::setCount(int val)
+{
+ d->count = val;
+ setText(0, TQString("%1 (%2)").arg(d->name).arg(TQString::number(d->count)));
+}
+
+int CameraFolderItem::count()
+{
+ return d->count;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/camerafolderitem.h b/src/utilities/cameragui/camerafolderitem.h
new file mode 100644
index 00000000..dde2c5c6
--- /dev/null
+++ b/src/utilities/cameragui/camerafolderitem.h
@@ -0,0 +1,69 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-23
+ * Description : A widget to display a camera folder.
+ *
+ * Copyright (C) 2003-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 bythe 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 CAMERAFOLDERITEM_H
+#define CAMERAFOLDERITEM_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqlistview.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+
+namespace Digikam
+{
+
+class CameraFolderItemPriv;
+
+class CameraFolderItem : public TQListViewItem
+{
+
+public:
+
+ CameraFolderItem(TQListView* parent, const TQString& name,
+ const TQPixmap& pixmap=SmallIcon("folder"));
+
+ CameraFolderItem(TQListViewItem* parent, const TQString& folderName, const TQString& folderPath,
+ const TQPixmap& pixmap=SmallIcon("folder"));
+
+ ~CameraFolderItem();
+
+ TQString folderName();
+ TQString folderPath();
+ bool isVirtualFolder();
+ void changeCount(int val);
+ void setCount(int val);
+ int count();
+
+private:
+
+ CameraFolderItemPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAFOLDERITEM_H */
diff --git a/src/utilities/cameragui/camerafolderview.cpp b/src/utilities/cameragui/camerafolderview.cpp
new file mode 100644
index 00000000..877c4b51
--- /dev/null
+++ b/src/utilities/cameragui/camerafolderview.cpp
@@ -0,0 +1,169 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-23
+ * Description : A widget to display a list of camera folders.
+ *
+ * Copyright (C) 2003-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 bythe 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 <tdelocale.h>
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "camerafolderitem.h"
+#include "camerafolderview.h"
+#include "camerafolderview.moc"
+
+namespace Digikam
+{
+
+class CameraFolderViewPriv
+{
+public:
+
+ CameraFolderViewPriv()
+ {
+ virtualFolder = 0;
+ rootFolder = 0;
+ cameraName = TQString("Camera");
+ }
+
+ TQString cameraName;
+
+ CameraFolderItem *virtualFolder;
+ CameraFolderItem *rootFolder;
+};
+
+CameraFolderView::CameraFolderView(TQWidget* parent)
+ : TQListView(parent)
+{
+ d = new CameraFolderViewPriv;
+
+ addColumn(i18n("Camera Folders"));
+ setColumnWidthMode( 0, TQListView::Maximum );
+ setResizeMode( TQListView::AllColumns );
+ setSelectionMode(TQListView::Single);
+
+ connect(this, TQ_SIGNAL(currentChanged(TQListViewItem*)),
+ this, TQ_SLOT(slotCurrentChanged(TQListViewItem*)));
+
+ connect(this, TQ_SIGNAL(clicked(TQListViewItem*)),
+ this, TQ_SLOT(slotCurrentChanged(TQListViewItem*)));
+}
+
+CameraFolderView::~CameraFolderView()
+{
+ delete d;
+}
+
+void CameraFolderView::addVirtualFolder(const TQString& name, const TQPixmap& pixmap)
+{
+ d->cameraName = name;
+ d->virtualFolder = new CameraFolderItem(this, d->cameraName, pixmap);
+ d->virtualFolder->setOpen(true);
+ d->virtualFolder->setSelected(false);
+ d->virtualFolder->setSelectable(false);
+}
+
+void CameraFolderView::addRootFolder(const TQString& folder, int nbItems, const TQPixmap& pixmap)
+{
+ d->rootFolder = new CameraFolderItem(d->virtualFolder, folder, folder, pixmap);
+ d->rootFolder->setOpen(true);
+ d->rootFolder->setCount(nbItems);
+}
+
+CameraFolderItem* CameraFolderView::addFolder(const TQString& folder, const TQString& subFolder,
+ int nbItems, const TQPixmap& pixmap)
+{
+ CameraFolderItem *parentItem = findFolder(folder);
+
+ DDebug() << "CameraFolderView: Adding Subfolder " << subFolder
+ << " of folder " << folder << endl;
+
+ if (parentItem)
+ {
+ TQString path(folder);
+
+ if (!folder.endsWith("/"))
+ path += '/';
+
+ path += subFolder;
+ CameraFolderItem* item = new CameraFolderItem(parentItem, subFolder, path, pixmap);
+
+ DDebug() << "CameraFolderView: Added ViewItem with path "
+ << item->folderPath() << endl;
+
+ item->setCount(nbItems);
+ item->setOpen(true);
+ return item;
+ }
+ else
+ {
+ DWarning() << "CameraFolderView: Couldn't find parent for subFolder "
+ << subFolder << " of folder " << folder << endl;
+ return 0;
+ }
+}
+
+CameraFolderItem* CameraFolderView::findFolder(const TQString& folderPath)
+{
+
+ TQListViewItemIterator it(this);
+ for ( ; it.current(); ++it)
+ {
+ CameraFolderItem* item = static_cast<CameraFolderItem*>(it.current());
+
+ if (item->folderPath() == folderPath)
+ return item;
+ }
+
+ return 0;
+}
+
+void CameraFolderView::slotCurrentChanged(TQListViewItem* item)
+{
+ if (!item)
+ emit signalFolderChanged(0);
+ else
+ emit signalFolderChanged(static_cast<CameraFolderItem *>(item));
+}
+
+CameraFolderItem* CameraFolderView::virtualFolder()
+{
+ return d->virtualFolder;
+}
+
+CameraFolderItem* CameraFolderView::rootFolder()
+{
+ return d->rootFolder;
+}
+
+void CameraFolderView::clear()
+{
+ TQListView::clear();
+ d->virtualFolder = 0;
+ d->rootFolder = 0;
+ emit signalCleared();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/camerafolderview.h b/src/utilities/cameragui/camerafolderview.h
new file mode 100644
index 00000000..1b02fc9c
--- /dev/null
+++ b/src/utilities/cameragui/camerafolderview.h
@@ -0,0 +1,83 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-23
+ * Description : A widget to display a list of camera folders.
+ *
+ * Copyright (C) 2003-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 bythe 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 CAMERAFOLDERVIEW_H
+#define CAMERAFOLDERVIEW_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqlistview.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+
+namespace Digikam
+{
+
+class CameraFolderItem;
+class CameraFolderViewPriv;
+
+class CameraFolderView : public TQListView
+{
+ TQ_OBJECT
+
+
+public:
+
+ CameraFolderView(TQWidget* parent);
+ ~CameraFolderView();
+
+ void addVirtualFolder(const TQString& name, const TQPixmap& pixmap=SmallIcon("camera-photo"));
+ void addRootFolder(const TQString& folder, int nbItems, const TQPixmap& pixmap=SmallIcon("folder"));
+
+ CameraFolderItem* addFolder(const TQString& folder, const TQString& subFolder, int nbItems,
+ const TQPixmap& pixmap=SmallIcon("folder"));
+
+ CameraFolderItem* findFolder(const TQString& folderPath);
+
+ CameraFolderItem* virtualFolder();
+ CameraFolderItem* rootFolder();
+
+ virtual void clear();
+
+signals:
+
+ void signalFolderChanged(CameraFolderItem*);
+ void signalCleared();
+
+private slots:
+
+ void slotCurrentChanged(TQListViewItem*);
+
+private:
+
+ CameraFolderViewPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAFOLDERVIEW_H */
diff --git a/src/utilities/cameragui/cameraiconitem.cpp b/src/utilities/cameragui/cameraiconitem.cpp
new file mode 100644
index 00000000..c68f7855
--- /dev/null
+++ b/src/utilities/cameragui/cameraiconitem.cpp
@@ -0,0 +1,302 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-21
+ * Description : camera icon view item
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqpainter.h>
+#include <tqpixmap.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "iconview.h"
+#include "thumbnailsize.h"
+#include "albumiconitem.h"
+#include "gpiteminfo.h"
+#include "themeengine.h"
+#include "cameraiconview.h"
+#include "cameraiconitem.h"
+
+namespace Digikam
+{
+
+class CameraIconViewItemPriv
+{
+
+public:
+
+ CameraIconViewItemPriv()
+ {
+ itemInfo = 0;
+ }
+
+ TQString downloadName;
+
+ TQPixmap pixmap;
+ TQPixmap thumbnail;
+
+ TQRect pixRect;
+ TQRect textRect;
+ TQRect extraRect;
+
+ GPItemInfo *itemInfo;
+};
+
+CameraIconViewItem::CameraIconViewItem(IconGroupItem* parent, const GPItemInfo& itemInfo,
+ const TQImage& thumbnail, const TQString& downloadName)
+ : IconItem(parent)
+{
+ d = new CameraIconViewItemPriv;
+ d->itemInfo = new GPItemInfo(itemInfo);
+ d->downloadName = downloadName;
+ setThumbnail(thumbnail);
+}
+
+CameraIconViewItem::~CameraIconViewItem()
+{
+ delete d->itemInfo;
+ delete d;
+}
+
+void CameraIconViewItem::setThumbnail(const TQImage& thumbnail)
+{
+ d->thumbnail = TQPixmap(thumbnail);
+}
+
+GPItemInfo* CameraIconViewItem::itemInfo() const
+{
+ return d->itemInfo;
+}
+
+void CameraIconViewItem::paintItem()
+{
+ CameraIconView* view = (CameraIconView*)iconView();
+ TQFont fn(view->font());
+
+ TQPixmap pix;
+ TQRect r(rect());
+
+ if (isSelected())
+ pix = *(view->itemBaseSelPixmap());
+ else
+ pix = *(view->itemBaseRegPixmap());
+
+ ThemeEngine* te = ThemeEngine::instance();
+
+ TQPainter p(&pix);
+
+ TQString itemName = AlbumIconItem::squeezedText(&p, r.width()-5, d->itemInfo->name);
+ TQString downloadName = AlbumIconItem::squeezedText(&p, r.width()-5, d->downloadName);
+ calcRect(itemName, downloadName);
+
+ p.setPen(isSelected() ? te->textSelColor() : te->textRegColor());
+
+ p.drawPixmap(d->pixRect.x() + (d->pixRect.width() - d->pixmap.width()) /2,
+ d->pixRect.y() + (d->pixRect.height() - d->pixmap.height()) /2,
+ d->pixmap);
+
+ p.drawText(d->textRect, TQt::AlignHCenter|TQt::AlignTop, itemName);
+
+ if (!d->downloadName.isEmpty())
+ {
+ if (fn.pointSize() > 0)
+ fn.setPointSize(TQMAX(fn.pointSize()-2, 6));
+
+ p.setFont(fn);
+ p.setPen(isSelected() ? te->textSpecialSelColor() : te->textSpecialRegColor());
+ p.drawText(d->extraRect, TQt::AlignHCenter|TQt::AlignTop, downloadName);
+ }
+
+ if (this == iconView()->currentItem())
+ {
+ p.setPen(TQPen(isSelected() ? TQt::white : TQt::black, 1, TQt::DotLine));
+ p.drawRect(0, 0, r.width(), r.height());
+ }
+
+ // Draw download status icon.
+ TQPixmap downloaded;
+
+ switch (d->itemInfo->downloaded)
+ {
+ case GPItemInfo::NewPicture:
+ {
+ downloaded = TQPixmap(view->newPicturePixmap());
+ break;
+ }
+ case GPItemInfo::DownloadedYes:
+ {
+ downloaded = SmallIcon( "button_ok" );
+ break;
+ }
+ case GPItemInfo::DownloadStarted:
+ {
+ downloaded = SmallIcon( "system-run" );
+ break;
+ }
+ case GPItemInfo::DownloadFailed:
+ {
+ downloaded = SmallIcon( "button_cancel" );
+ break;
+ }
+ /* TODO: see B.K.O #107316 : disable temporally the unknow download status until
+ a new method to identify the already downloaded pictures from camera is
+ implemented.
+
+ case GPItemInfo::DownloadUnknow:
+ {
+ downloaded = view->unknowPicturePixmap();
+ break;
+ }
+ */
+ }
+
+ if (!downloaded.isNull())
+ p.drawPixmap(rect().width() - downloaded.width() - 5, 5, downloaded);
+
+ // If camera item is locked (read only), draw a "Lock" icon.
+ if (d->itemInfo->writePermissions == 0)
+ p.drawPixmap(5, 5, SmallIcon( "encrypted" ));
+
+ p.end();
+
+ r = TQRect(view->contentsToViewport(TQPoint(r.x(), r.y())),
+ TQSize(r.width(), r.height()));
+
+ bitBlt(view->viewport(), r.x(), r.y(), &pix);
+}
+
+void CameraIconViewItem::setDownloadName(const TQString& downloadName)
+{
+ d->downloadName = downloadName;
+ repaint();
+}
+
+TQString CameraIconViewItem::getDownloadName() const
+{
+ return d->downloadName;
+}
+
+void CameraIconViewItem::setDownloaded(int status)
+{
+ d->itemInfo->downloaded = status;
+ repaint();
+}
+
+bool CameraIconViewItem::isDownloaded() const
+{
+ return (d->itemInfo->downloaded == GPItemInfo::DownloadedYes);
+}
+
+void CameraIconViewItem::toggleLock()
+{
+ if (d->itemInfo->writePermissions == 0)
+ d->itemInfo->writePermissions = 1;
+ else
+ d->itemInfo->writePermissions = 0;
+
+ repaint();
+}
+
+void CameraIconViewItem::calcRect(const TQString& itemName, const TQString& downloadName)
+{
+ CameraIconView* view = (CameraIconView*)iconView();
+ int thumbSize = view->thumbnailSize().size();
+ d->pixmap = TQPixmap(d->thumbnail.convertToImage().smoothScale(thumbSize, thumbSize, TQImage::ScaleMin));
+ d->pixRect = TQRect(0,0,0,0);
+ d->textRect = TQRect(0,0,0,0);
+ d->extraRect = TQRect(0,0,0,0);
+ TQRect itemRect = rect();
+ itemRect.moveTopLeft(TQPoint(0, 0));
+
+ d->pixRect.setWidth(thumbSize);
+ d->pixRect.setHeight(thumbSize);
+
+ TQFontMetrics fm(iconView()->font());
+ TQRect r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ TQt::AlignHCenter | TQt::AlignTop,
+ itemName));
+ d->textRect.setWidth(r.width());
+ d->textRect.setHeight(r.height());
+
+ if (!d->downloadName.isEmpty())
+ {
+ TQFont fn(iconView()->font());
+ if (fn.pointSize() > 0)
+ {
+ fn.setPointSize(TQMAX(fn.pointSize()-2, 6));
+ }
+
+ fm = TQFontMetrics(fn);
+ r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ TQt::AlignHCenter | TQt::WordBreak,
+ downloadName));
+ d->extraRect.setWidth(r.width());
+ d->extraRect.setHeight(r.height());
+
+ d->textRect.setWidth(TQMAX(d->textRect.width(), d->extraRect.width()));
+ d->textRect.setHeight(d->textRect.height() + d->extraRect.height());
+ }
+
+ int w = TQMAX(d->textRect.width(), d->pixRect.width() );
+ int h = d->textRect.height() + d->pixRect.height() ;
+
+ itemRect.setWidth(w+4);
+ itemRect.setHeight(h+4);
+
+ // Center the pix and text rect
+ d->pixRect = TQRect(2, 2, d->pixRect.width(), d->pixRect.height());
+ d->textRect = TQRect((itemRect.width() - d->textRect.width())/2,
+ itemRect.height() - d->textRect.height(),
+ d->textRect.width(), d->textRect.height());
+
+ if (!d->extraRect.isEmpty())
+ {
+ d->extraRect = TQRect((itemRect.width() - d->extraRect.width())/2,
+ itemRect.height() - d->extraRect.height(),
+ d->extraRect.width(), d->extraRect.height());
+ }
+}
+
+TQRect CameraIconViewItem::clickToOpenRect()
+{
+ TQRect r(rect());
+
+ if (d->pixmap.isNull())
+ {
+ TQRect pixRect(d->pixRect);
+ pixRect.moveBy(r.x(), r.y());
+ return pixRect;
+ }
+
+ TQRect pixRect(d->pixRect.x() + (d->pixRect.width() - d->pixmap.width())/2,
+ d->pixRect.y() + (d->pixRect.height() - d->pixmap.height())/2,
+ d->pixmap.width(), d->pixmap.height());
+ pixRect.moveBy(r.x(), r.y());
+ return pixRect;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/cameraiconitem.h b/src/utilities/cameragui/cameraiconitem.h
new file mode 100644
index 00000000..961bc1a3
--- /dev/null
+++ b/src/utilities/cameragui/cameraiconitem.h
@@ -0,0 +1,81 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-21
+ * Description : camera icon view item
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 CAMERAICONITEM_H
+#define CAMERAICONITEM_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqimage.h>
+
+// Local includes.
+
+#include "iconitem.h"
+
+namespace Digikam
+{
+
+class GPItemInfo;
+class CameraIconViewItemPriv;
+
+class CameraIconViewItem : public IconItem
+{
+
+public:
+
+ CameraIconViewItem(IconGroupItem* parent, const GPItemInfo& itemInfo,
+ const TQImage& thumbnail, const TQString& downloadName=TQString());
+ ~CameraIconViewItem();
+
+ void setThumbnail(const TQImage& thumbnail);
+
+ void setDownloadName(const TQString& downloadName);
+ TQString getDownloadName() const;
+ void setDownloaded(int status);
+ bool isDownloaded() const;
+
+ void toggleLock();
+
+ GPItemInfo* itemInfo() const;
+
+ // reimplemented from IconItem
+ virtual TQRect clickToOpenRect();
+
+protected:
+
+ virtual void paintItem();
+
+private:
+
+ void calcRect(const TQString& itemName, const TQString& downloadName);
+
+private:
+
+ CameraIconViewItemPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAICONITEM_H */
diff --git a/src/utilities/cameragui/cameraiconview.cpp b/src/utilities/cameragui/cameraiconview.cpp
new file mode 100644
index 00000000..ba496217
--- /dev/null
+++ b/src/utilities/cameragui/cameraiconview.cpp
@@ -0,0 +1,900 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-18
+ * Description : camera icon view
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqfile.h>
+#include <tqfileinfo.h>
+#include <tqtimer.h>
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqcursor.h>
+#include <tqfontmetrics.h>
+#include <tqfont.h>
+#include <tqdragobject.h>
+#include <tqclipboard.h>
+
+// KDE includes.
+
+#include <kurldrag.h>
+#include <kmimetype.h>
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <tdeaction.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "themeengine.h"
+#include "thumbnailsize.h"
+#include "gpiteminfo.h"
+#include "renamecustomizer.h"
+#include "icongroupitem.h"
+#include "dpopupmenu.h"
+#include "dragobjects.h"
+#include "cameraui.h"
+#include "cameraiconitem.h"
+#include "cameraiconview.h"
+#include "cameraiconview.moc"
+
+namespace Digikam
+{
+
+class CameraIconViewPriv
+{
+public:
+
+ CameraIconViewPriv()
+ {
+ renamer = 0;
+ groupItem = 0;
+ cameraUI = 0;
+ thumbSize = ThumbnailSize::Large;
+ pixmapNewPicture = TQPixmap(newPicture_xpm);
+ pixmapUnknowPicture = TQPixmap(unknowPicture_xpm);
+ }
+
+ static const char *newPicture_xpm[];
+ static const char *unknowPicture_xpm[];
+
+ TQDict<CameraIconViewItem> itemDict;
+
+ TQRect itemRect;
+
+ TQPixmap itemRegPixmap;
+ TQPixmap itemSelPixmap;
+ TQPixmap pixmapNewPicture;
+ TQPixmap pixmapUnknowPicture;
+
+ RenameCustomizer *renamer;
+
+ IconGroupItem *groupItem;
+
+ ThumbnailSize thumbSize;
+
+ CameraUI *cameraUI;
+};
+
+const char *CameraIconViewPriv::newPicture_xpm[] =
+{
+ "13 13 8 1",
+ " c None",
+ ". c #232300",
+ "+ c #F6F611",
+ "@ c #000000",
+ "# c #DBDA4D",
+ "$ c #FFFF00",
+ "% c #AAA538",
+ "& c #E8E540",
+ " . ",
+ " . .+. . ",
+ " @#@ .$. .#. ",
+ " @$@#$#@$. ",
+ " @$%&%$@ ",
+ " ..#%&&&%#.. ",
+ ".+$$&&&&&$$+@",
+ " ..#%&&&%#@@ ",
+ " @$%&%$@ ",
+ " .$@#$#@$. ",
+ " @#. @$@ @#. ",
+ " . @+@ . ",
+ " @ "
+};
+
+const char *CameraIconViewPriv::unknowPicture_xpm[] =
+{
+ "16 16 78 1",
+ " g None",
+ ". g #777777",
+ "+ g #7A7A7A",
+ "@ g #8C8C8C",
+ "# g #787878",
+ "$ g #707070",
+ "% g #878787",
+ "& g #C3C3C3",
+ "* g #EAEAEA",
+ "= g #E4E4E4",
+ "- g #E2E2E2",
+ "; g #E6E6E6",
+ "> g #CECECE",
+ ", g #888888",
+ "' g #6B6B6B",
+ ") g #969696",
+ "! g #DEDEDE",
+ "~ g #D8D8D8",
+ "{ g #FFFFFF",
+ "] g #F2F2F2",
+ "^ g #DFDFDF",
+ "/ g #9D9D9D",
+ "( g #686868",
+ "_ g #848484",
+ ": g #D0D0D0",
+ "< g #F1F1F1",
+ "[ g #F0F0F0",
+ "} g #EBEBEB",
+ "| g #FDFDFD",
+ "1 g #DDDDDD",
+ "2 g #D4D4D4",
+ "3 g #838383",
+ "4 g #ABABAB",
+ "5 g #C8C8C8",
+ "6 g #CCCCCC",
+ "7 g #F4F4F4",
+ "8 g #D6D6D6",
+ "9 g #E8E8E8",
+ "0 g #C4C4C4",
+ "a g #A4A4A4",
+ "b g #656565",
+ "c g #B4B4B4",
+ "d g #B9B9B9",
+ "e g #BDBDBD",
+ "f g #B7B7B7",
+ "g g #898989",
+ "h g #6D6D6D",
+ "i g #808080",
+ "j g #AAAAAA",
+ "k g #A9A9A9",
+ "l g #737373",
+ "m g #7F7F7F",
+ "n g #9A9A9A",
+ "o g #D3D3D3",
+ "p g #909090",
+ "q g #727272",
+ "r g #8F8F8F",
+ "s g #8E8E8E",
+ "t g #8D8D8D",
+ "u g #EEEEEE",
+ "v g #FAFAFA",
+ "w g #929292",
+ "x g #C5C5C5",
+ "y g #5F5F5F",
+ "z g #989898",
+ "A g #CFCFCF",
+ "B g #9C9C9C",
+ "C g #A0A0A0",
+ "D g #FEFEFE",
+ "E g #ACACAC",
+ "F g #5E5E5E",
+ "G g #868686",
+ "H g #AFAFAF",
+ "I g #C1C1C1",
+ "J g #818181",
+ "K g #7E7E7E",
+ "L g #7B7B7B",
+ "M g #636363",
+ " ",
+ " .+@@#$ ",
+ " .%&*=-;>,' ",
+ " .)!~={{]^-/( ",
+ " _::<{[}|{123 ",
+ " .456{7558{90ab ",
+ " +cde96df={&g,h ",
+ " ijjjjjk;{=@,,l ",
+ " mnnnnno{-pgggq ",
+ " #rprstuvwtttt' ",
+ " $tpppp6xpppp@y ",
+ " mnnnzA~Bnnn. ",
+ " 'taaCD{Eaa,F ",
+ " (GjHI0HjJF ",
+ " (K,,LM ",
+ " "
+};
+
+CameraIconView::CameraIconView(CameraUI* ui, TQWidget* parent)
+ : IconView(parent)
+{
+ d = new CameraIconViewPriv;
+ d->cameraUI = ui;
+ d->groupItem = new IconGroupItem(this);
+
+ setHScrollBarMode(TQScrollView::AlwaysOff);
+ setMinimumSize(400, 300);
+
+ setAcceptDrops(true);
+ viewport()->setAcceptDrops(true);
+
+ // ----------------------------------------------------------------
+
+ connect(this, TQ_SIGNAL(signalSelectionChanged()),
+ this, TQ_SLOT(slotSelectionChanged()));
+
+ connect(this, TQ_SIGNAL(signalNewSelection(bool)),
+ this, TQ_SLOT(slotUpdateDownloadNames(bool)));
+
+ connect(this, TQ_SIGNAL(signalRightButtonClicked(IconItem*, const TQPoint&)),
+ this, TQ_SLOT(slotContextMenu(IconItem*, const TQPoint&)));
+
+ connect(this, TQ_SIGNAL(signalRightButtonClicked(const TQPoint &)),
+ this, TQ_SLOT(slotRightButtonClicked(const TQPoint &)));
+
+ connect(this, TQ_SIGNAL(signalDoubleClicked(IconItem*)),
+ this, TQ_SLOT(slotDoubleClicked(IconItem*)));
+
+ connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()),
+ this, TQ_SLOT(slotThemeChanged()));
+
+ // ----------------------------------------------------------------
+
+ updateItemRectsPixmap();
+ slotThemeChanged();
+}
+
+CameraIconView::~CameraIconView()
+{
+ clear();
+ delete d;
+}
+
+TQPixmap* CameraIconView::itemBaseRegPixmap() const
+{
+ return &d->itemRegPixmap;
+}
+
+TQPixmap* CameraIconView::itemBaseSelPixmap() const
+{
+ return &d->itemSelPixmap;
+}
+
+TQPixmap CameraIconView::newPicturePixmap() const
+{
+ return d->pixmapNewPicture;
+}
+
+TQPixmap CameraIconView::unknowPicturePixmap() const
+{
+ return d->pixmapUnknowPicture;
+}
+
+void CameraIconView::setRenameCustomizer(RenameCustomizer* renamer)
+{
+ d->renamer = renamer;
+
+ connect(d->renamer, TQ_SIGNAL(signalChanged()),
+ this, TQ_SLOT(slotDownloadNameChanged()));
+}
+
+void CameraIconView::addItem(const GPItemInfo& info)
+{
+ TQImage thumb;
+ // Just to have a generic image thumb from desktop with KDE < 3.5.0
+ KMimeType::Ptr mime = KMimeType::mimeType(info.mime == TQString("image/x-raw") ?
+ TQString("image/tiff") : info.mime);
+
+ if (mime)
+ {
+ thumb = TQImage(mime->pixmap(TDEIcon::Desktop, ThumbnailSize::Huge, TDEIcon::DefaultState)
+ .convertToImage());
+ }
+ else
+ {
+ TDEIconLoader *iconLoader = TDEApplication::kApplication()->iconLoader();
+ thumb = iconLoader->loadIcon("application-x-zerosize", TDEIcon::Desktop,
+ ThumbnailSize::Huge, TDEIcon::DefaultState, 0, true)
+ .convertToImage();
+ }
+
+ TQString downloadName;
+
+ if (d->renamer)
+ {
+ if (!d->renamer->useDefault())
+ {
+ downloadName = getTemplatedName( &info, d->itemDict.count() );
+ }
+ else
+ {
+ downloadName = getCasedName( d->renamer->changeCase(), &info);
+ }
+ }
+
+ CameraIconViewItem* item = new CameraIconViewItem(d->groupItem, info, thumb, downloadName);
+ d->itemDict.insert(info.folder+info.name, item);
+}
+
+void CameraIconView::removeItem(const TQString& folder, const TQString& file)
+{
+ CameraIconViewItem* item = d->itemDict.find(folder+file);
+ if (!item)
+ return;
+ d->itemDict.remove(folder+file);
+
+ setDelayedRearrangement(true);
+ delete item;
+ setDelayedRearrangement(false);
+}
+
+CameraIconViewItem* CameraIconView::findItem(const TQString& folder, const TQString& file)
+{
+ return d->itemDict.find(folder+file);
+}
+
+int CameraIconView::countItemsByFolder(TQString folder)
+{
+ int count = 0;
+ if (folder.endsWith("/")) folder.truncate(folder.length()-1);
+
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ TQString itemFolder = iconItem->itemInfo()->folder;
+ if (itemFolder.endsWith("/")) itemFolder.truncate(itemFolder.length()-1);
+
+ if (folder == itemFolder)
+ count++;
+ }
+
+ return count;
+}
+
+void CameraIconView::setThumbnail(const TQString& folder, const TQString& filename, const TQImage& image)
+{
+ CameraIconViewItem* item = d->itemDict.find(folder+filename);
+ if (!item)
+ return;
+
+ item->setThumbnail(image);
+ item->repaint();
+}
+
+void CameraIconView::ensureItemVisible(CameraIconViewItem *item)
+{
+ IconView::ensureItemVisible(item);
+}
+
+void CameraIconView::ensureItemVisible(const GPItemInfo& itemInfo)
+{
+ ensureItemVisible(itemInfo.folder, itemInfo.name);
+}
+
+void CameraIconView::ensureItemVisible(const TQString& folder, const TQString& file)
+{
+ CameraIconViewItem* item = d->itemDict.find(folder+file);
+ if (!item)
+ return;
+
+ ensureItemVisible(item);
+}
+
+void CameraIconView::slotDownloadNameChanged()
+{
+ bool hasSelection = false;
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ if (item->isSelected())
+ {
+ hasSelection = true;
+ break;
+ }
+ }
+
+ // connected to slotUpdateDownloadNames, and used externally
+ emit signalNewSelection(hasSelection);
+}
+
+void CameraIconView::slotUpdateDownloadNames(bool hasSelection)
+{
+ bool useDefault = true;
+ int startIndex = 0;
+
+ if (d->renamer)
+ {
+ useDefault = d->renamer->useDefault();
+ startIndex = d->renamer->startIndex() -1;
+ }
+
+ bool convertLossLessJpeg = d->cameraUI->convertLosslessJpegFiles();
+ TQString losslessFormat = d->cameraUI->losslessFormat();
+
+ viewport()->setUpdatesEnabled(false);
+
+ // NOTE: see B.K.O #182352: ordering of item count must be adapted sort of icon view,
+ // since items are ordered from the most rescent to the older one.
+
+ if (hasSelection)
+ {
+ // Camera items selection.
+
+ for (IconItem* item = lastItem(); item; item = item->prevItem())
+ {
+ TQString downloadName;
+ CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item);
+
+ if (item->isSelected())
+ {
+ if (!useDefault)
+ downloadName = getTemplatedName( viewItem->itemInfo(), startIndex );
+ else
+ downloadName = getCasedName( d->renamer->changeCase(), viewItem->itemInfo() );
+
+ startIndex++;
+ }
+
+ if (convertLossLessJpeg && !downloadName.isEmpty())
+ {
+ TQFileInfo fi(downloadName);
+ TQString ext = fi.extension(false).upper();
+ if (ext == TQString("JPEG") || ext == TQString("JPG") || ext == TQString("JPE"))
+ {
+ downloadName.truncate(downloadName.length() - ext.length());
+ downloadName.append(losslessFormat.lower());
+ }
+ }
+
+ viewItem->setDownloadName( downloadName );
+ }
+ }
+ else
+ {
+ // No camera item selection.
+
+ for (IconItem* item = lastItem(); item; item = item->prevItem())
+ {
+ TQString downloadName;
+ CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item);
+
+ if (!useDefault)
+ downloadName = getTemplatedName( viewItem->itemInfo(), startIndex );
+ else
+ downloadName = getCasedName( d->renamer->changeCase(), viewItem->itemInfo() );
+
+ if (convertLossLessJpeg)
+ {
+ TQFileInfo fi(downloadName);
+ TQString ext = fi.extension(false).upper();
+ if (ext == TQString("JPEG") || ext == TQString("JPG") || ext == TQString("JPE"))
+ {
+ downloadName.truncate(downloadName.length() - ext.length());
+ downloadName.append(losslessFormat.lower());
+ }
+ }
+
+ viewItem->setDownloadName( downloadName );
+ startIndex++;
+ }
+ }
+
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+}
+
+TQString CameraIconView::defaultDownloadName(CameraIconViewItem *viewItem)
+{
+ RenameCustomizer::Case renamecase = RenameCustomizer::NONE;
+ if (d->renamer)
+ renamecase = d->renamer->changeCase();
+
+ return getCasedName( renamecase, viewItem->itemInfo() );
+}
+
+TQString CameraIconView::getTemplatedName(const GPItemInfo* itemInfo, int position)
+{
+ TQString ext = itemInfo->name;
+ int pos = ext.findRev('.');
+ if (pos < 0)
+ ext = "";
+ else
+ ext = ext.right( ext.length() - pos );
+
+ TQDateTime mtime;
+ mtime.setTime_t(itemInfo->mtime);
+
+ return d->renamer->newName(mtime, position+1, ext);
+}
+
+TQString CameraIconView::getCasedName(const RenameCustomizer::Case ccase,
+ const GPItemInfo* itemInfo)
+{
+ TQString dname;
+
+ switch (ccase)
+ {
+ case(RenameCustomizer::UPPER):
+ {
+ dname = itemInfo->name.upper();
+ break;
+ }
+ case(RenameCustomizer::LOWER):
+ {
+ dname = itemInfo->name.lower();
+ break;
+ }
+ default:
+ {
+ dname = itemInfo->name;
+ break;
+ }
+ };
+
+ return dname;
+}
+
+void CameraIconView::slotSelectionChanged()
+{
+ bool selected = false;
+ CameraIconViewItem* camItem = 0;
+
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ if (item->isSelected())
+ {
+ camItem = static_cast<CameraIconViewItem*>(item);
+ selected = true;
+ break;
+ }
+ }
+
+ emit signalNewSelection(selected);
+ emit signalSelected(camItem, selected);
+
+ viewport()->update();
+}
+
+void CameraIconView::slotContextMenu(IconItem * item, const TQPoint&)
+{
+ if (!item)
+ return;
+
+ // don't popup context menu if the camera is busy
+ if (d->cameraUI->isBusy())
+ return;
+
+ CameraIconViewItem* camItem = static_cast<CameraIconViewItem*>(item);
+
+ DPopupMenu menu(this);
+ menu.insertItem(SmallIcon("editimage"), i18n("&View"), 0);
+ menu.insertSeparator(-1);
+ menu.insertItem(SmallIcon("go-down"),i18n("Download"), 1);
+ menu.insertItem(SmallIcon("go-down"),i18n("Download && Delete"), 4);
+ menu.insertItem(SmallIcon("encrypted"), i18n("Toggle lock"), 3);
+ menu.insertSeparator(-1);
+ menu.insertItem(SmallIcon("edit-delete"), i18n("Delete"), 2);
+
+ int result = menu.exec(TQCursor::pos());
+
+ switch (result)
+ {
+ case(0):
+ {
+ emit signalFileView(camItem);
+ break;
+ }
+ case(1):
+ {
+ emit signalDownload();
+ break;
+ }
+ case(2):
+ {
+ emit signalDelete();
+ break;
+ }
+ case(3):
+ {
+ emit signalToggleLock();
+ break;
+ }
+ case(4):
+ {
+ emit signalDownloadAndDelete();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void CameraIconView::slotDoubleClicked(IconItem* item)
+{
+ if (!item)
+ return;
+
+ if (d->cameraUI->isBusy())
+ return;
+
+ emit signalFileView(static_cast<CameraIconViewItem*>(item));
+}
+
+void CameraIconView::slotSelectAll()
+{
+ selectAll();
+}
+
+void CameraIconView::slotSelectNone()
+{
+ clearSelection();
+}
+
+void CameraIconView::slotSelectInvert()
+{
+ invertSelection();
+}
+
+void CameraIconView::slotSelectNew()
+{
+ blockSignals(true);
+ clearSelection();
+
+ for (IconItem* item = firstItem(); item;
+ item = item->nextItem())
+ {
+ CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item);
+ if (viewItem->itemInfo()->downloaded == GPItemInfo::NewPicture)
+ {
+ viewItem->setSelected(true, false);
+ }
+ }
+
+ blockSignals(false);
+ emit signalSelectionChanged();
+}
+
+void CameraIconView::startDrag()
+{
+ TQStringList lst;
+
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ if (!item->isSelected())
+ continue;
+
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ TQString itemPath = iconItem->itemInfo()->folder + iconItem->itemInfo()->name;
+ lst.append(itemPath);
+ }
+
+ TQDragObject * drag = new CameraItemListDrag(lst, d->cameraUI);
+ if (drag)
+ {
+ TQPixmap icon(DesktopIcon("image-x-generic", 48));
+ int w = icon.width();
+ int h = icon.height();
+
+ TQPixmap pix(w+4,h+4);
+ TQString text(TQString::number(lst.count()));
+
+ TQPainter p(&pix);
+ p.fillRect(0, 0, w+4, h+4, TQColor(TQt::white));
+ p.setPen(TQPen(TQt::black, 1));
+ p.drawRect(0, 0, w+4, h+4);
+ p.drawPixmap(2, 2, icon);
+ TQRect r = p.boundingRect(2,2,w,h,TQt::AlignLeft|TQt::AlignTop,text);
+ r.setWidth(TQMAX(r.width(),r.height()));
+ r.setHeight(TQMAX(r.width(),r.height()));
+ p.fillRect(r, TQColor(0,80,0));
+ p.setPen(TQt::white);
+ TQFont f(font());
+ f.setBold(true);
+ p.setFont(f);
+ p.drawText(r, TQt::AlignCenter, text);
+ p.end();
+
+ drag->setPixmap(pix);
+ drag->drag();
+ }
+}
+
+void CameraIconView::contentsDropEvent(TQDropEvent *event)
+{
+ // don't popup context menu if the camera is busy
+ if (d->cameraUI->isBusy())
+ return;
+
+ if ( (!TQUriDrag::canDecode(event) && !CameraDragObject::canDecode(event) )
+ || event->source() == this)
+ {
+ event->ignore();
+ return;
+ }
+
+ KURL::List srcURLs;
+ KURLDrag::decode(event, srcURLs);
+ uploadItemPopupMenu(srcURLs);
+}
+
+void CameraIconView::slotRightButtonClicked(const TQPoint&)
+{
+ // don't popup context menu if the camera is busy
+ if (d->cameraUI->isBusy())
+ return;
+
+ TQMimeSource *data = kapp->clipboard()->data(TQClipboard::Clipboard);
+ if(!data || !TQUriDrag::canDecode(data))
+ return;
+
+ KURL::List srcURLs;
+ KURLDrag::decode(data, srcURLs);
+ uploadItemPopupMenu(srcURLs);
+}
+
+void CameraIconView::uploadItemPopupMenu(const KURL::List& srcURLs)
+{
+ TDEPopupMenu popMenu(this);
+ popMenu.insertTitle(SmallIcon("digikam"), d->cameraUI->cameraTitle());
+ popMenu.insertItem( SmallIcon("goto"), i18n("&Upload to camera"), 10 );
+ popMenu.insertSeparator(-1);
+ popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") );
+
+ popMenu.setMouseTracking(true);
+ int id = popMenu.exec(TQCursor::pos());
+ switch(id)
+ {
+ case 10:
+ {
+ emit signalUpload(srcURLs);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+TQRect CameraIconView::itemRect() const
+{
+ return d->itemRect;
+}
+
+void CameraIconView::setThumbnailSize(const ThumbnailSize& thumbSize)
+{
+ if ( d->thumbSize != thumbSize)
+ {
+ d->thumbSize = thumbSize;
+ updateItemRectsPixmap();
+ triggerRearrangement();
+ }
+}
+
+ThumbnailSize CameraIconView::thumbnailSize() const
+{
+ return d->thumbSize;
+}
+
+void CameraIconView::updateItemRectsPixmap()
+{
+ int thumbSize = d->thumbSize.size();
+
+ TQRect pixRect;
+ TQRect textRect;
+ TQRect extraRect;
+
+ pixRect.setWidth(thumbSize);
+ pixRect.setHeight(thumbSize);
+
+ TQFontMetrics fm(font());
+ TQRect r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ TQt::AlignHCenter | TQt::AlignTop,
+ "XXXXXXXXX"));
+ textRect.setWidth(r.width());
+ textRect.setHeight(r.height());
+
+ TQFont fn(font());
+ if (fn.pointSize() > 0)
+ {
+ fn.setPointSize(TQMAX(fn.pointSize()-2, 6));
+ }
+
+ fm = TQFontMetrics(fn);
+ r = TQRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ TQt::AlignHCenter | TQt::AlignTop,
+ "XXXXXXXXX"));
+ extraRect.setWidth(r.width());
+ extraRect.setHeight(r.height());
+
+ r = TQRect();
+ r.setWidth(TQMAX(TQMAX(pixRect.width(), textRect.width()), extraRect.width()) + 4);
+ r.setHeight(pixRect.height() + textRect.height() + extraRect.height() + 4);
+
+ d->itemRect = r;
+
+ d->itemRegPixmap = ThemeEngine::instance()->thumbRegPixmap(d->itemRect.width(),
+ d->itemRect.height());
+
+ d->itemSelPixmap = ThemeEngine::instance()->thumbSelPixmap(d->itemRect.width(),
+ d->itemRect.height());
+}
+
+void CameraIconView::slotThemeChanged()
+{
+ updateItemRectsPixmap();
+ viewport()->update();
+}
+
+int CameraIconView::itemsDownloaded()
+{
+ int downloaded = 0;
+
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+
+ if (iconItem->itemInfo()->downloaded == GPItemInfo::DownloadedYes)
+ downloaded++;
+ }
+
+ return downloaded;
+}
+
+void CameraIconView::itemsSelectionSizeInfo(unsigned long& fSizeKB, unsigned long& dSizeKB)
+{
+ long long fSize = 0; // Files size
+ long long dSize = 0; // Estimated space requires to download and process files.
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ if (item->isSelected())
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ long long size = iconItem->itemInfo()->size;
+ if (size < 0) // -1 if size is not provided by camera
+ continue;
+ fSize += size;
+
+ if (iconItem->itemInfo()->mime == TQString("image/jpeg"))
+ {
+ if (d->cameraUI->convertLosslessJpegFiles())
+ {
+ // Estimated size is aroud 5 x original size when JPEG=>PNG.
+ dSize += size*5;
+ }
+ else if (d->cameraUI->autoRotateJpegFiles())
+ {
+ // We need a double size to perform rotation.
+ dSize += size*2;
+ }
+ else
+ {
+ // Real file size is added.
+ dSize += size;
+ }
+ }
+ else
+ dSize += size;
+
+ }
+ }
+
+ fSizeKB = fSize / 1024;
+ dSizeKB = dSize / 1024;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/cameraiconview.h b/src/utilities/cameragui/cameraiconview.h
new file mode 100644
index 00000000..f621fedf
--- /dev/null
+++ b/src/utilities/cameragui/cameraiconview.h
@@ -0,0 +1,141 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-18
+ * Description : camera icon view
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 CAMERAICONVIEW_H
+#define CAMERAICONVIEW_H
+
+// TQt includes.
+
+#include <tqdict.h>
+#include <tqrect.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "iconview.h"
+#include "renamecustomizer.h"
+
+class TQPixmap;
+
+namespace Digikam
+{
+
+class ThumbnailSize;
+class GPItemInfo;
+class RenameCustomizer;
+class CameraUI;
+class CameraIconViewItem;
+class CameraIconViewPriv;
+
+class CameraIconView : public IconView
+{
+ TQ_OBJECT
+
+
+public:
+
+ CameraIconView(CameraUI* ui, TQWidget* parent);
+ ~CameraIconView();
+
+ void setRenameCustomizer(RenameCustomizer* renamer);
+
+ void addItem(const GPItemInfo& itemInfo);
+ void removeItem(const TQString& folder, const TQString& file);
+ void setThumbnail(const TQString& folder, const TQString& filename, const TQImage& image);
+
+ void ensureItemVisible(CameraIconViewItem *item);
+ void ensureItemVisible(const GPItemInfo& itemInfo);
+ void ensureItemVisible(const TQString& folder, const TQString& file);
+
+ void setThumbnailSize(const ThumbnailSize& thumbSize);
+ ThumbnailSize thumbnailSize() const;
+
+ CameraIconViewItem* findItem(const TQString& folder, const TQString& file);
+
+ int countItemsByFolder(TQString folder);
+ int itemsDownloaded();
+
+ TQPixmap* itemBaseRegPixmap() const;
+ TQPixmap* itemBaseSelPixmap() const;
+ TQPixmap newPicturePixmap() const;
+ TQPixmap unknowPicturePixmap() const;
+
+ virtual TQRect itemRect() const;
+
+ TQString defaultDownloadName(CameraIconViewItem *item);
+
+ void itemsSelectionSizeInfo(unsigned long& fSize, unsigned long& dSize);
+
+signals:
+
+ void signalSelected(CameraIconViewItem*, bool);
+ void signalFileView(CameraIconViewItem*);
+
+ void signalUpload(const KURL::List&);
+ void signalDownload();
+ void signalDownloadAndDelete();
+ void signalDelete();
+ void signalToggleLock();
+ void signalNewSelection(bool);
+
+public slots:
+
+ void slotDownloadNameChanged();
+ void slotSelectionChanged();
+ void slotSelectAll();
+ void slotSelectNone();
+ void slotSelectInvert();
+ void slotSelectNew();
+
+private slots:
+
+ void slotRightButtonClicked(const TQPoint& pos);
+ void slotContextMenu(IconItem* item, const TQPoint& pos);
+ void slotDoubleClicked(IconItem* item);
+ void slotThemeChanged();
+ void slotUpdateDownloadNames(bool hasSelection);
+
+protected:
+
+ void startDrag();
+ void contentsDropEvent(TQDropEvent *event);
+ void updateItemRectsPixmap();
+
+private:
+
+ TQString getTemplatedName(const GPItemInfo* itemInfo, int position);
+ TQString getCasedName(const RenameCustomizer::Case ccase, const GPItemInfo* itemInfo);
+ void uploadItemPopupMenu(const KURL::List& srcURLs);
+
+private:
+
+ CameraIconViewPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAICONVIEW_H */
diff --git a/src/utilities/cameragui/camerainfodialog.cpp b/src/utilities/cameragui/camerainfodialog.cpp
new file mode 100644
index 00000000..ba565a59
--- /dev/null
+++ b/src/utilities/cameragui/camerainfodialog.cpp
@@ -0,0 +1,85 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-28
+ * Description : a dialog to display camera information.
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 <tqlayout.h>
+#include <tqframe.h>
+#include <tqtextedit.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "camerainfodialog.h"
+
+namespace Digikam
+{
+
+CameraInfoDialog::CameraInfoDialog(TQWidget *parent, const TQString& summary, const TQString& manual,
+ const TQString& about)
+ : KDialogBase(IconList, i18n("Camera Information"), Help|Ok, Ok, parent, 0, true, true)
+{
+ setHelp("digitalstillcamera.anchor", "digikam");
+ resize(500, 400);
+
+ // ----------------------------------------------------------
+
+ TQFrame *p1 = addPage( i18n("Summary"), i18n("Camera Summary"), BarIcon("contents2", TDEIcon::SizeMedium) );
+ TQVBoxLayout *p1layout = new TQVBoxLayout( p1, 0, 6 );
+
+ TQTextEdit *summaryView = new TQTextEdit(summary, TQString(), p1);
+ summaryView->setWordWrap(TQTextEdit::WidgetWidth);
+ summaryView->setReadOnly(true);
+ p1layout->addWidget(summaryView);
+
+ // ----------------------------------------------------------
+
+ TQFrame *p2 = addPage( i18n("Manual"), i18n("Camera Manual"), BarIcon("contents", TDEIcon::SizeMedium) );
+ TQVBoxLayout *p2layout = new TQVBoxLayout( p2, 0, 6 );
+
+ TQTextEdit *manualView = new TQTextEdit(manual, TQString(), p2);
+ manualView->setWordWrap(TQTextEdit::WidgetWidth);
+ manualView->setReadOnly(true);
+ p2layout->addWidget(manualView);
+
+ // ----------------------------------------------------------
+
+ TQFrame *p3 = addPage( i18n("About"), i18n("About Driver"), BarIcon("camera-photo", TDEIcon::SizeMedium) );
+ TQVBoxLayout *p3layout = new TQVBoxLayout( p3, 0, 6 );
+
+ TQTextEdit *aboutView = new TQTextEdit(about, TQString(), p3);
+ aboutView->setWordWrap(TQTextEdit::WidgetWidth);
+ aboutView->setReadOnly(true);
+ p3layout->addWidget(aboutView);
+}
+
+CameraInfoDialog::~CameraInfoDialog()
+{
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/camerainfodialog.h b/src/utilities/cameragui/camerainfodialog.h
new file mode 100644
index 00000000..7ec3120f
--- /dev/null
+++ b/src/utilities/cameragui/camerainfodialog.h
@@ -0,0 +1,50 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-28
+ * Description : a dialog to display camera information.
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 CAMERAINFODIALOG_H
+#define CAMERAINFODIALOG_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class CameraInfoDialog : public KDialogBase
+{
+public:
+
+ CameraInfoDialog(TQWidget *parent, const TQString& summary, const TQString& manual,
+ const TQString& about);
+ ~CameraInfoDialog();
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAINFODIALOG_H */
diff --git a/src/utilities/cameragui/cameraui.cpp b/src/utilities/cameragui/cameraui.cpp
new file mode 100644
index 00000000..8b531ea2
--- /dev/null
+++ b/src/utilities/cameragui/cameraui.cpp
@@ -0,0 +1,1734 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-16
+ * Description : Camera interface dialog
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+#define CAMERA_INFO_MENU_ID 255
+
+// TQt includes.
+
+#include <tqvgroupbox.h>
+#include <tqlayout.h>
+#include <tqpushbutton.h>
+#include <tqtoolbutton.h>
+#include <tqiconview.h>
+#include <tqvbox.h>
+#include <tqhbox.h>
+#include <tqpopupmenu.h>
+#include <tqsplitter.h>
+#include <tqpixmap.h>
+#include <tqcombobox.h>
+#include <tqtoolbox.h>
+#include <tqframe.h>
+#include <tqvbuttongroup.h>
+#include <tqradiobutton.h>
+#include <tqcheckbox.h>
+#include <tqlineedit.h>
+#include <tqtooltip.h>
+#include <tqtimer.h>
+#include <tqwhatsthis.h>
+#include <tqfile.h>
+#include <tqfileinfo.h>
+
+// KDE includes.
+
+#include <tdefiledialog.h>
+#include <kimageio.h>
+#include <tdeaboutdata.h>
+#include <tdemessagebox.h>
+#include <kprogress.h>
+#include <tdeglobal.h>
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+#include <kiconloader.h>
+#include <tdepopupmenu.h>
+#include <kstandarddirs.h>
+#include <khelpmenu.h>
+#include <kcalendarsystem.h>
+#include <kurllabel.h>
+#include <ksqueezedtextlabel.h>
+
+#if KDE_IS_VERSION(3,2,0)
+#include <kinputdialog.h>
+#else
+#include <klineeditdlg.h>
+#endif
+
+// LibKDcraw includes.
+
+#include <libkdcraw/version.h>
+#include <libkdcraw/kdcraw.h>
+
+#if KDCRAW_VERSION < 0x000106
+#include <libkdcraw/dcrawbinary.h>
+#endif
+
+// Local includes.
+
+#include "daboutdata.h"
+#include "ddebug.h"
+#include "thumbnailsize.h"
+#include "kdatetimeedit.h"
+#include "sidebar.h"
+#include "scanlib.h"
+#include "downloadsettingscontainer.h"
+#include "imagepropertiessidebarcamgui.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "album.h"
+#include "albumselectdialog.h"
+#include "renamecustomizer.h"
+#include "animwidget.h"
+#include "freespacewidget.h"
+#include "camerafolderdialog.h"
+#include "camerainfodialog.h"
+#include "cameraiconview.h"
+#include "cameraiconitem.h"
+#include "cameracontroller.h"
+#include "cameralist.h"
+#include "cameratype.h"
+#include "cameraui.h"
+#include "cameraui.moc"
+
+namespace Digikam
+{
+
+class CameraUIPriv
+{
+public:
+
+ enum SettingsTab
+ {
+ RENAMEFILEPAGE=0,
+ AUTOALBUMPAGE,
+ ONFLYPAGE
+ };
+
+ enum DateFormatOptions
+ {
+ IsoDateFormat=0,
+ TextDateFormat,
+ LocalDateFormat
+ };
+
+ CameraUIPriv()
+ {
+ deleteAfter = false;
+ busy = false;
+ closed = false;
+ helpMenu = 0;
+ advBox = 0;
+ downloadMenu = 0;
+ deleteMenu = 0;
+ imageMenu = 0;
+ cancelBtn = 0;
+ splitter = 0;
+ rightSidebar = 0;
+ fixDateTimeCheck = 0;
+ autoRotateCheck = 0;
+ autoAlbumDateCheck = 0;
+ autoAlbumExtCheck = 0;
+ status = 0;
+ progress = 0;
+ controller = 0;
+ view = 0;
+ renameCustomizer = 0;
+ anim = 0;
+ dateTimeEdit = 0;
+ setPhotographerId = 0;
+ setCredits = 0;
+ losslessFormat = 0;
+ convertJpegCheck = 0;
+ formatLabel = 0;
+ folderDateLabel = 0;
+ folderDateFormat = 0;
+ freeSpaceWidget = 0;
+ }
+
+ bool deleteAfter;
+ bool busy;
+ bool closed;
+
+ TQString cameraTitle;
+
+ TQStringList currentlyDeleting;
+ TQStringList foldersToScan;
+ TQStringList cameraFolderList;
+
+ TQPopupMenu *downloadMenu;
+ TQPopupMenu *deleteMenu;
+ TQPopupMenu *imageMenu;
+
+ TQToolButton *cancelBtn;
+
+ TQToolBox *advBox;
+
+ TQCheckBox *autoRotateCheck;
+ TQCheckBox *autoAlbumDateCheck;
+ TQCheckBox *autoAlbumExtCheck;
+ TQCheckBox *fixDateTimeCheck;
+ TQCheckBox *setPhotographerId;
+ TQCheckBox *setCredits;
+ TQCheckBox *convertJpegCheck;
+
+ TQLabel *formatLabel;
+ TQLabel *folderDateLabel;
+
+ TQComboBox *losslessFormat;
+ TQComboBox *folderDateFormat;
+
+ TQSplitter *splitter;
+
+ TQDateTime lastAccess;
+
+ KProgress *progress;
+
+ KSqueezedTextLabel *status;
+
+ KURL lastDestURL;
+
+ KHelpMenu *helpMenu;
+
+ KDateTimeEdit *dateTimeEdit;
+
+ CameraController *controller;
+
+ CameraIconView *view;
+
+ RenameCustomizer *renameCustomizer;
+
+ AnimWidget *anim;
+
+ ImagePropertiesSideBarCamGui *rightSidebar;
+
+ FreeSpaceWidget *freeSpaceWidget;
+};
+
+CameraUI::CameraUI(TQWidget* /*parent*/, const TQString& cameraTitle,
+ const TQString& model, const TQString& port,
+ const TQString& path, const TQDateTime lastAccess)
+ : KDialogBase(Plain, cameraTitle,
+ Help|User1|User2|User3|Close, Close,
+ 0, // B.K.O # 116485: no parent for this modal dialog.
+ 0, false, true,
+ i18n("D&elete"),
+ i18n("&Download"),
+ i18n("&Images"))
+{
+ d = new CameraUIPriv;
+ d->lastAccess = lastAccess;
+ d->cameraTitle = cameraTitle;
+ setHelp("camerainterface.anchor", "digikam");
+
+ // -------------------------------------------------------------------------
+
+ TQGridLayout* viewBoxLayout = new TQGridLayout(plainPage(), 2, 7);
+
+ TQHBox* widget = new TQHBox(plainPage());
+ d->splitter = new TQSplitter(widget);
+ d->view = new CameraIconView(this, d->splitter);
+
+ TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1);
+ d->view->setSizePolicy(rightSzPolicy);
+
+ d->rightSidebar = new ImagePropertiesSideBarCamGui(widget, "CameraGui Sidebar Right", d->splitter,
+ Sidebar::Right, true);
+ d->splitter->setFrameStyle( TQFrame::NoFrame );
+ d->splitter->setFrameShadow( TQFrame::Plain );
+ d->splitter->setFrameShape( TQFrame::NoFrame );
+ d->splitter->setOpaqueResize(false);
+
+ // -------------------------------------------------------------------------
+
+ d->advBox = new TQToolBox(d->rightSidebar);
+ d->renameCustomizer = new RenameCustomizer(d->advBox, d->cameraTitle);
+ d->view->setRenameCustomizer(d->renameCustomizer);
+
+ TQWhatsThis::add( d->advBox, i18n("<p>Set how digiKam will rename files as they are downloaded."));
+
+ d->advBox->insertItem(CameraUIPriv::RENAMEFILEPAGE, d->renameCustomizer,
+ SmallIconSet("fileimport"), i18n("File Renaming Options"));
+
+ // -- Albums Auto-creation options -----------------------------------------
+
+ TQWidget* albumBox = new TQWidget(d->advBox);
+ TQVBoxLayout* albumVlay = new TQVBoxLayout(albumBox, marginHint(), spacingHint());
+ d->autoAlbumExtCheck = new TQCheckBox(i18n("Extension-based sub-albums"), albumBox);
+ d->autoAlbumDateCheck = new TQCheckBox(i18n("Date-based sub-albums"), albumBox);
+ TQHBox *hbox1 = new TQHBox(albumBox);
+ d->folderDateLabel = new TQLabel(i18n("Date format:"), hbox1);
+ d->folderDateFormat = new TQComboBox(hbox1);
+ d->folderDateFormat->insertItem(i18n("ISO"), CameraUIPriv::IsoDateFormat);
+ d->folderDateFormat->insertItem(i18n("Full Text"), CameraUIPriv::TextDateFormat);
+ d->folderDateFormat->insertItem(i18n("Local Settings"), CameraUIPriv::LocalDateFormat);
+ albumVlay->addWidget(d->autoAlbumExtCheck);
+ albumVlay->addWidget(d->autoAlbumDateCheck);
+ albumVlay->addWidget(hbox1);
+ albumVlay->addStretch();
+
+ TQWhatsThis::add( albumBox, i18n("<p>Set how digiKam creates albums automatically when downloading."));
+ TQWhatsThis::add( d->autoAlbumExtCheck, i18n("<p>Enable this option if you want to download your "
+ "pictures into automatically created file extension-based sub-albums of the destination "
+ "album. This way, you can separate JPEG and RAW files as they are downloaded from your camera."));
+ TQWhatsThis::add( d->autoAlbumDateCheck, i18n("<p>Enable this option if you want to "
+ "download your pictures into automatically created file date-based sub-albums "
+ "of the destination album."));
+ TQWhatsThis::add( d->folderDateFormat, i18n("<p>Select your preferred date format used to "
+ "create new albums. The options available are:<p>"
+ "<b>ISO</b>: the date format is in accordance with ISO 8601 "
+ "(YYYY-MM-DD). E.g.: <i>2006-08-24</i><p>"
+ "<b>Full Text</b>: the date format is in a user-readable string. "
+ "E.g.: <i>Thu Aug 24 2006</i><p>"
+ "<b>Local Settings</b>: the date format depending on TDE control panel settings.<p>"));
+
+ d->advBox->insertItem(CameraUIPriv::AUTOALBUMPAGE, albumBox, SmallIconSet("folder-new"),
+ i18n("Auto-creation of Albums"));
+
+ // -- On the Fly options ---------------------------------------------------
+
+ TQWidget* onFlyBox = new TQWidget(d->advBox);
+ TQVBoxLayout* onFlyVlay = new TQVBoxLayout(onFlyBox, marginHint(), spacingHint());
+ d->setPhotographerId = new TQCheckBox(i18n("Set default photographer identity"), onFlyBox);
+ d->setCredits = new TQCheckBox(i18n("Set default credit and copyright"), onFlyBox);
+ d->fixDateTimeCheck = new TQCheckBox(i18n("Fix internal date && time"), onFlyBox);
+ d->dateTimeEdit = new KDateTimeEdit(onFlyBox, "datepicker");
+ d->autoRotateCheck = new TQCheckBox(i18n("Auto-rotate/flip image"), onFlyBox);
+ d->convertJpegCheck = new TQCheckBox(i18n("Convert to lossless file format"), onFlyBox);
+ TQHBox *hbox2 = new TQHBox(onFlyBox);
+ d->formatLabel = new TQLabel(i18n("New image format:"), hbox2);
+ d->losslessFormat = new TQComboBox(hbox2);
+ d->losslessFormat->insertItem("PNG", 0);
+ onFlyVlay->addWidget(d->setPhotographerId);
+ onFlyVlay->addWidget(d->setCredits);
+ onFlyVlay->addWidget(d->fixDateTimeCheck);
+ onFlyVlay->addWidget(d->dateTimeEdit);
+ onFlyVlay->addWidget(d->autoRotateCheck);
+ onFlyVlay->addWidget(d->convertJpegCheck);
+ onFlyVlay->addWidget(hbox2);
+ onFlyVlay->addStretch();
+
+ TQWhatsThis::add( onFlyBox, i18n("<p>Set here all options to fix/transform JPEG files automatically "
+ "as they are downloaded."));
+ TQWhatsThis::add( d->autoRotateCheck, i18n("<p>Enable this option if you want images automatically "
+ "rotated or flipped using EXIF information provided by the camera."));
+ TQWhatsThis::add( d->setPhotographerId, i18n("<p>Enable this option to store the default "
+ "photographer identity in the IPTC tags using digiKam's metadata settings."));
+ TQWhatsThis::add( d->setCredits, i18n("<p>Enable this option to store the default credit "
+ "and copyright information in the IPTC tags using digiKam's metadata settings."));
+ TQWhatsThis::add( d->fixDateTimeCheck, i18n("<p>Enable this option to set date and time metadata "
+ "tags to the right values if your camera does not set "
+ "these tags correctly when pictures are taken. The values will "
+ "be saved in the DateTimeDigitized and DateTimeCreated EXIF/IPTC fields."));
+ TQWhatsThis::add( d->convertJpegCheck, i18n("<p>Enable this option to automatically convert "
+ "all JPEG files to a lossless image format. <b>Note:</b> Image conversion can take a "
+ "while on a slow computer."));
+ TQWhatsThis::add( d->losslessFormat, i18n("<p>Select your preferred lossless image file format to "
+ "convert to. <b>Note:</b> All metadata will be preserved during the conversion."));
+
+ d->advBox->insertItem(CameraUIPriv::ONFLYPAGE, onFlyBox, SmallIconSet("system-run"),
+ i18n("On the Fly Operations (JPEG only)"));
+
+ d->rightSidebar->appendTab(d->advBox, SmallIcon("configure"), i18n("Settings"));
+ d->rightSidebar->loadViewState();
+
+ // -------------------------------------------------------------------------
+
+ d->cancelBtn = new TQToolButton(plainPage());
+ d->cancelBtn->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ) );
+ d->cancelBtn->setPixmap( SmallIcon( "cancel" ) );
+ d->cancelBtn->setEnabled(false);
+
+ d->status = new KSqueezedTextLabel(plainPage());
+ d->progress = new KProgress(plainPage());
+ d->progress->setMaximumHeight( fontMetrics().height()+4 );
+ d->progress->hide();
+
+ TQWidget *frame = new TQWidget(plainPage());
+ TQHBoxLayout* layout = new TQHBoxLayout(frame);
+ frame->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum));
+
+ KURLLabel *pixmapLogo = new KURLLabel( Digikam::webProjectUrl(), TQString(), frame );
+ pixmapLogo->setMargin(0);
+ pixmapLogo->setScaledContents( false );
+ pixmapLogo->setSizePolicy(TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum));
+ TQToolTip::add(pixmapLogo, i18n("Visit digiKam project website"));
+ TDEGlobal::dirs()->addResourceType("logo-digikam", TDEGlobal::dirs()->kde_default("data") + "digikam/data");
+ TQString directory = TDEGlobal::dirs()->findResourceDir("logo-digikam", "logo-digikam.png");
+ pixmapLogo->setPixmap( TQPixmap( directory + "logo-digikam.png" ) );
+ pixmapLogo->setFocusPolicy(TQWidget::NoFocus);
+
+ d->anim = new AnimWidget(frame, pixmapLogo->height()-2);
+
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget( pixmapLogo );
+ layout->addWidget( d->anim );
+
+ d->freeSpaceWidget = new FreeSpaceWidget(plainPage(), 100);
+
+ viewBoxLayout->addMultiCellWidget(widget, 0, 0, 0, 7);
+ viewBoxLayout->addMultiCellWidget(d->cancelBtn, 2, 2, 0, 0);
+ viewBoxLayout->addMultiCellWidget(d->status, 2, 2, 2, 2);
+ viewBoxLayout->addMultiCellWidget(d->progress, 2, 2, 3, 3);
+ viewBoxLayout->addMultiCellWidget(d->freeSpaceWidget, 2, 2, 5, 5);
+ viewBoxLayout->addMultiCellWidget(frame, 2, 2, 7, 7);
+ viewBoxLayout->setRowSpacing(1, spacingHint());
+ viewBoxLayout->setColSpacing(1, spacingHint());
+ viewBoxLayout->setColSpacing(4, spacingHint());
+ viewBoxLayout->setColSpacing(6, spacingHint());
+ viewBoxLayout->setColStretch( 0, 0 );
+ viewBoxLayout->setColStretch( 1, 0 );
+ viewBoxLayout->setColStretch( 2, 3 );
+ viewBoxLayout->setColStretch( 3, 1 );
+ viewBoxLayout->setColStretch( 4, 0 );
+ viewBoxLayout->setColStretch( 5, 0 );
+ viewBoxLayout->setColStretch( 6, 0 );
+ viewBoxLayout->setColStretch( 7, 0 );
+
+ // -------------------------------------------------------------------------
+
+ d->imageMenu = new TQPopupMenu(this);
+ d->imageMenu->insertItem(i18n("Select &All"), d->view, TQ_SLOT(slotSelectAll()), CTRL+Key_A, 0);
+ d->imageMenu->insertItem(i18n("Select N&one"), d->view, TQ_SLOT(slotSelectNone()), CTRL+Key_U, 1);
+ d->imageMenu->insertItem(i18n("&Invert Selection"), d->view, TQ_SLOT(slotSelectInvert()), CTRL+Key_Asterisk, 2);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Select &New Items"), d->view, TQ_SLOT(slotSelectNew()), 0, 3);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Increase Thumbnail Size"), this, TQ_SLOT(slotIncreaseThumbSize()), CTRL+Key_Plus, 4);
+ d->imageMenu->insertItem(i18n("Decrease Thumbnail Size"), this, TQ_SLOT(slotDecreaseThumbSize()), CTRL+Key_Minus, 5);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Toggle Lock"), this, TQ_SLOT(slotToggleLock()), 0, 6);
+ actionButton(User3)->setPopup(d->imageMenu);
+
+ // -------------------------------------------------------------------------
+
+ d->downloadMenu = new TQPopupMenu(this);
+ d->downloadMenu->insertItem(i18n("Download Selected"),
+ this, TQ_SLOT(slotDownloadSelected()), 0, 0);
+ d->downloadMenu->insertItem(i18n("Download All"),
+ this, TQ_SLOT(slotDownloadAll()), 0, 1);
+ d->downloadMenu->insertSeparator();
+ d->downloadMenu->insertItem(i18n("Download/Delete Selected"),
+ this, TQ_SLOT(slotDownloadAndDeleteSelected()), 0, 2);
+ d->downloadMenu->insertItem(i18n("Download/Delete All"),
+ this, TQ_SLOT(slotDownloadAndDeleteAll()), 0, 3);
+ d->downloadMenu->insertSeparator();
+ d->downloadMenu->insertItem(i18n("Upload..."),
+ this, TQ_SLOT(slotUpload()), 0, 4);
+ d->downloadMenu->setItemEnabled(0, false);
+ d->downloadMenu->setItemEnabled(2, false);
+ actionButton(User2)->setPopup(d->downloadMenu);
+
+ // -------------------------------------------------------------------------
+
+ d->deleteMenu = new TQPopupMenu(this);
+ d->deleteMenu->insertItem(i18n("Delete Selected"), this, TQ_SLOT(slotDeleteSelected()), 0, 0);
+ d->deleteMenu->insertItem(i18n("Delete All"), this, TQ_SLOT(slotDeleteAll()), 0, 1);
+ d->deleteMenu->setItemEnabled(0, false);
+ actionButton(User1)->setPopup(d->deleteMenu);
+
+ // -------------------------------------------------------------------------
+
+ TQPushButton *helpButton = actionButton( Help );
+ d->helpMenu = new KHelpMenu(this, kapp->aboutData(), false);
+ d->helpMenu->menu()->insertItem(SmallIcon("camera-photo"), i18n("Camera Information"),
+ this, TQ_SLOT(slotInformations()), 0, CAMERA_INFO_MENU_ID, 0);
+ helpButton->setPopup( d->helpMenu->menu() );
+
+ // -------------------------------------------------------------------------
+
+ connect(d->autoAlbumDateCheck, TQ_SIGNAL(toggled(bool)),
+ d->folderDateFormat, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->autoAlbumDateCheck, TQ_SIGNAL(toggled(bool)),
+ d->folderDateLabel, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)),
+ d->losslessFormat, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)),
+ d->formatLabel, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)),
+ d->view, TQ_SLOT(slotDownloadNameChanged()));
+
+ connect(d->fixDateTimeCheck, TQ_SIGNAL(toggled(bool)),
+ d->dateTimeEdit, TQ_SLOT(setEnabled(bool)));
+
+ connect(pixmapLogo, TQ_SIGNAL(leftClickedURL(const TQString&)),
+ this, TQ_SLOT(slotProcessURL(const TQString&)));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->view, TQ_SIGNAL(signalSelected(CameraIconViewItem*, bool)),
+ this, TQ_SLOT(slotItemsSelected(CameraIconViewItem*, bool)));
+
+ connect(d->view, TQ_SIGNAL(signalFileView(CameraIconViewItem*)),
+ this, TQ_SLOT(slotFileView(CameraIconViewItem*)));
+
+ connect(d->view, TQ_SIGNAL(signalUpload(const KURL::List&)),
+ this, TQ_SLOT(slotUploadItems(const KURL::List&)));
+
+ connect(d->view, TQ_SIGNAL(signalDownload()),
+ this, TQ_SLOT(slotDownloadSelected()));
+
+ connect(d->view, TQ_SIGNAL(signalDownloadAndDelete()),
+ this, TQ_SLOT(slotDownloadAndDeleteSelected()));
+
+ connect(d->view, TQ_SIGNAL(signalDelete()),
+ this, TQ_SLOT(slotDeleteSelected()));
+
+ connect(d->view, TQ_SIGNAL(signalToggleLock()),
+ this, TQ_SLOT(slotToggleLock()));
+
+ connect(d->view, TQ_SIGNAL(signalNewSelection(bool)),
+ this, TQ_SLOT(slotNewSelection(bool)));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalFirstItem()),
+ this, TQ_SLOT(slotFirstItem()));
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalNextItem()),
+ this, TQ_SLOT(slotNextItem()));
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalPrevItem()),
+ this, TQ_SLOT(slotPrevItem()));
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalLastItem()),
+ this, TQ_SLOT(slotLastItem()));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->cancelBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotCancelButton()));
+
+ // -- Read settings & Check free space availability on album root path -----
+
+ readSettings();
+
+ // -- camera controller ----------------------------------------------------
+
+ d->controller = new CameraController(this, d->cameraTitle, model, port, path);
+
+ connect(d->controller, TQ_SIGNAL(signalConnected(bool)),
+ this, TQ_SLOT(slotConnected(bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalInfoMsg(const TQString&)),
+ d->status, TQ_SLOT(setText(const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalErrorMsg(const TQString&)),
+ this, TQ_SLOT(slotErrorMsg(const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalCameraInformations(const TQString&, const TQString&, const TQString&)),
+ this, TQ_SLOT(slotCameraInformations(const TQString&, const TQString&, const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalBusy(bool)),
+ this, TQ_SLOT(slotBusy(bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalFolderList(const TQStringList&)),
+ this, TQ_SLOT(slotFolderList(const TQStringList&)));
+
+ connect(d->controller, TQ_SIGNAL(signalFileList(const GPItemInfoList&)),
+ this, TQ_SLOT(slotFileList(const GPItemInfoList&)));
+
+ connect(d->controller, TQ_SIGNAL(signalThumbnail(const TQString&, const TQString&, const TQImage&)),
+ this, TQ_SLOT(slotThumbnail(const TQString&, const TQString&, const TQImage&)));
+
+ connect(d->controller, TQ_SIGNAL(signalDownloaded(const TQString&, const TQString&, int)),
+ this, TQ_SLOT(slotDownloaded(const TQString&, const TQString&, int)));
+
+ connect(d->controller, TQ_SIGNAL(signalSkipped(const TQString&, const TQString&)),
+ this, TQ_SLOT(slotSkipped(const TQString&, const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalDeleted(const TQString&, const TQString&, bool)),
+ this, TQ_SLOT(slotDeleted(const TQString&, const TQString&, bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalLocked(const TQString&, const TQString&, bool)),
+ this, TQ_SLOT(slotLocked(const TQString&, const TQString&, bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalExifFromFile(const TQString&, const TQString&)),
+ this, TQ_SLOT(slotExifFromFile(const TQString&, const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalExifData(const TQByteArray&)),
+ this, TQ_SLOT(slotExifFromData(const TQByteArray&)));
+
+ connect(d->controller, TQ_SIGNAL(signalUploaded(const GPItemInfo&)),
+ this, TQ_SLOT(slotUploaded(const GPItemInfo&)));
+
+ // -------------------------------------------------------------------------
+
+ d->view->setFocus();
+ TQTimer::singleShot(0, d->controller, TQ_SLOT(slotConnect()));
+}
+
+CameraUI::~CameraUI()
+{
+ delete d->rightSidebar;
+ delete d->controller;
+ delete d;
+}
+
+void CameraUI::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("Camera Settings");
+ d->advBox->setCurrentIndex(config->readNumEntry("Settings Tab", CameraUIPriv::RENAMEFILEPAGE));
+ d->autoRotateCheck->setChecked(config->readBoolEntry("AutoRotate", true));
+ d->autoAlbumDateCheck->setChecked(config->readBoolEntry("AutoAlbumDate", false));
+ d->autoAlbumExtCheck->setChecked(config->readBoolEntry("AutoAlbumExt", false));
+ d->fixDateTimeCheck->setChecked(config->readBoolEntry("FixDateTime", false));
+ d->setPhotographerId->setChecked(config->readBoolEntry("SetPhotographerId", false));
+ d->setCredits->setChecked(config->readBoolEntry("SetCredits", false));
+ d->convertJpegCheck->setChecked(config->readBoolEntry("ConvertJpeg", false));
+ d->losslessFormat->setCurrentItem(config->readNumEntry("LossLessFormat", 0)); // PNG by default
+ d->folderDateFormat->setCurrentItem(config->readNumEntry("FolderDateFormat", CameraUIPriv::IsoDateFormat));
+
+ d->view->setThumbnailSize(ThumbnailSize((ThumbnailSize::Size)config->readNumEntry("ThumbnailSize",
+ ThumbnailSize::Large)));
+
+ if(config->hasKey("Splitter Sizes"))
+ d->splitter->setSizes(config->readIntListEntry("Splitter Sizes"));
+
+ d->dateTimeEdit->setEnabled(d->fixDateTimeCheck->isChecked());
+ d->losslessFormat->setEnabled(convertLosslessJpegFiles());
+ d->formatLabel->setEnabled(convertLosslessJpegFiles());
+ d->folderDateFormat->setEnabled(d->autoAlbumDateCheck->isChecked());
+ d->folderDateLabel->setEnabled(d->autoAlbumDateCheck->isChecked());
+
+ resize(configDialogSize("Camera Settings"));
+}
+
+void CameraUI::saveSettings()
+{
+ saveDialogSize("Camera Settings");
+
+ TDEConfig* config = kapp->config();
+ config->setGroup("Camera Settings");
+ config->writeEntry("Settings Tab", d->advBox->currentIndex());
+ config->writeEntry("AutoRotate", d->autoRotateCheck->isChecked());
+ config->writeEntry("AutoAlbumDate", d->autoAlbumDateCheck->isChecked());
+ config->writeEntry("AutoAlbumExt", d->autoAlbumExtCheck->isChecked());
+ config->writeEntry("FixDateTime", d->fixDateTimeCheck->isChecked());
+ config->writeEntry("SetPhotographerId", d->setPhotographerId->isChecked());
+ config->writeEntry("SetCredits", d->setCredits->isChecked());
+ config->writeEntry("ConvertJpeg", convertLosslessJpegFiles());
+ config->writeEntry("LossLessFormat", d->losslessFormat->currentItem());
+ config->writeEntry("ThumbnailSize", d->view->thumbnailSize().size());
+ config->writeEntry("Splitter Sizes", d->splitter->sizes());
+ config->writeEntry("FolderDateFormat", d->folderDateFormat->currentItem());
+ config->sync();
+}
+
+void CameraUI::slotProcessURL(const TQString& url)
+{
+ TDEApplication::kApplication()->invokeBrowser(url);
+}
+
+bool CameraUI::isBusy() const
+{
+ return d->busy;
+}
+
+bool CameraUI::isClosed() const
+{
+ return d->closed;
+}
+
+bool CameraUI::convertLosslessJpegFiles() const
+{
+ return d->convertJpegCheck->isChecked();
+}
+
+bool CameraUI::autoRotateJpegFiles() const
+{
+ return d->autoRotateCheck->isChecked();
+}
+
+TQString CameraUI::losslessFormat()
+{
+ return d->losslessFormat->currentText();
+}
+
+TQString CameraUI::cameraTitle() const
+{
+ return d->cameraTitle;
+}
+
+void CameraUI::slotCancelButton()
+{
+ d->status->setText(i18n("Cancelling current operation, please wait..."));
+ d->progress->hide();
+ TQTimer::singleShot(0, d->controller, TQ_SLOT(slotCancel()));
+ d->currentlyDeleting.clear();
+}
+
+void CameraUI::closeEvent(TQCloseEvent* e)
+{
+ if (dialogClosed())
+ e->accept();
+ else
+ e->ignore();
+}
+
+void CameraUI::slotClose()
+{
+ if (dialogClosed())
+ reject();
+}
+
+bool CameraUI::dialogClosed()
+{
+ if (d->closed)
+ return true;
+
+ if (isBusy())
+ {
+ if (KMessageBox::questionYesNo(this,
+ i18n("Do you want to close the dialog "
+ "and cancel the current operation?"))
+ == KMessageBox::No)
+ return false;
+ }
+
+ d->status->setText(i18n("Disconnecting from camera, please wait..."));
+ d->progress->hide();
+
+ if (isBusy())
+ {
+ d->controller->slotCancel();
+ // will be read in slotBusy later and finishDialog
+ // will be called only when everything is finished
+ d->closed = true;
+ }
+ else
+ {
+ d->closed = true;
+ finishDialog();
+ }
+
+ return true;
+}
+
+void CameraUI::finishDialog()
+{
+ // Look if an item have been downloaded to computer during camera gui session.
+ // If yes, update the lastAccess date property of camera in digiKam camera list.
+
+ if (d->view->itemsDownloaded() > 0)
+ {
+ CameraList* clist = CameraList::instance();
+ if (clist)
+ clist->changeCameraAccessTime(d->cameraTitle, TQDateTime::TQDateTime::currentDateTime());
+ }
+
+ // When a directory is created, a watch is put on it to spot new files
+ // but it can occur that the file is copied there before the watch is
+ // completely setup. That is why as an extra safeguard run scanlib
+ // over the folders we used. Bug: 119201
+
+ d->status->setText(i18n("Scanning for new files, please wait..."));
+ ScanLib sLib;
+ for (TQStringList::iterator it = d->foldersToScan.begin();
+ it != d->foldersToScan.end(); ++it)
+ {
+ //DDebug() << "Scanning " << (*it) << endl;
+ sLib.findMissingItems( (*it) );
+ }
+
+ // Never call finalScan after deleteLater() - ScanLib will call processEvent(),
+ // and the delete event may be executed!
+ deleteLater();
+
+ if(!d->lastDestURL.isEmpty())
+ emit signalLastDestination(d->lastDestURL);
+
+ saveSettings();
+}
+
+void CameraUI::slotBusy(bool val)
+{
+ if (!val)
+ {
+ if (!d->busy)
+ return;
+
+ d->busy = false;
+ d->cancelBtn->setEnabled(false);
+ d->view->viewport()->setEnabled(true);
+
+ d->advBox->setEnabled(true);
+ // B.K.O #127614: The Focus need to be restored in custom prefix widget.
+ //commenting this out again: If we do not disable, no need to restore focus
+ //d->renameCustomizer->restoreFocus();
+
+ enableButton(User3, true);
+ enableButton(User2, true);
+ enableButton(User1, true);
+ d->helpMenu->menu()->setItemEnabled(CAMERA_INFO_MENU_ID, true);
+
+ d->anim->stop();
+ d->status->setText(i18n("Ready"));
+ d->progress->hide();
+
+ // like WDestructiveClose, but after camera controller operation has safely finished
+ if (d->closed)
+ {
+ finishDialog();
+ }
+ }
+ else
+ {
+ if (d->busy)
+ return;
+
+ if (!d->anim->running())
+ d->anim->start();
+
+ d->busy = true;
+ d->cancelBtn->setEnabled(true);
+
+ // Has camera icon view item selection is used to control download post processing,
+ // all selection actions are disable when camera interface is busy.
+ d->view->viewport()->setEnabled(false);
+
+ // Settings tab is disabled in slotDownload, selectively when downloading
+ // Fast dis/enabling would create the impression of flicker, e.g. when retrieving EXIF from camera
+ //d->advBox->setEnabled(false);
+
+ enableButton(User3, false);
+ enableButton(User2, false);
+ enableButton(User1, false);
+ d->helpMenu->menu()->setItemEnabled(CAMERA_INFO_MENU_ID, false);
+ }
+}
+
+void CameraUI::slotIncreaseThumbSize()
+{
+ int thumbSize = d->view->thumbnailSize().size();
+ if (thumbSize >= ThumbnailSize::Huge) return;
+
+ thumbSize += ThumbnailSize::Step;
+
+ if (thumbSize >= ThumbnailSize::Huge)
+ {
+ d->imageMenu->setItemEnabled(4, false);
+ }
+ d->imageMenu->setItemEnabled(5, true);
+
+ d->view->setThumbnailSize(thumbSize);
+}
+
+void CameraUI::slotDecreaseThumbSize()
+{
+ int thumbSize = d->view->thumbnailSize().size();
+ if (thumbSize <= ThumbnailSize::Small) return;
+
+ thumbSize -= ThumbnailSize::Step;
+
+ if (thumbSize <= ThumbnailSize::Small)
+ {
+ d->imageMenu->setItemEnabled(5, false);
+ }
+ d->imageMenu->setItemEnabled(4, true);
+
+ d->view->setThumbnailSize(thumbSize);
+}
+
+void CameraUI::slotConnected(bool val)
+{
+ if (!val)
+ {
+ if (KMessageBox::warningYesNo(this,
+ i18n("Failed to connect to the camera. "
+ "Please make sure it is connected "
+ "properly and turned on. "
+ "Would you like to try again?"),
+ i18n("Connection Failed"),
+ i18n("Retry"),
+ i18n("Abort"))
+ == KMessageBox::Yes)
+ TQTimer::singleShot(0, d->controller, TQ_SLOT(slotConnect()));
+ else
+ close();
+ }
+ else
+ {
+ d->controller->listFolders();
+ }
+}
+
+void CameraUI::slotFolderList(const TQStringList& folderList)
+{
+ if (d->closed)
+ return;
+
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(0);
+ d->progress->show();
+
+ d->cameraFolderList = folderList;
+ for (TQStringList::const_iterator it = folderList.begin();
+ it != folderList.end(); ++it)
+ {
+ d->controller->listFiles(*it);
+ }
+}
+
+void CameraUI::slotFileList(const GPItemInfoList& fileList)
+{
+ if (d->closed)
+ return;
+
+ if (fileList.empty())
+ return;
+
+ kdDebug() << fileList.count() << endl;
+
+ // We sort the map by time stamp
+ // and we remove internal camera files which are not image/video/sounds.
+ TQStringList fileNames, fileExts;
+ TQFileInfo info;
+
+ // JVC camera (see B.K.O #133185).
+ fileNames.append("mgr_data");
+ fileNames.append("pgr_mgr");
+
+ // HP Photosmart camera (see B.K.O #156338).
+ fileExts.append("dsp");
+
+ // Minolta camera in PTP mode
+ fileExts.append("dps");
+
+ // We sort the map by time stamp.
+ GPItemInfoList sfileList;
+ GPItemInfoList::const_iterator it;
+ GPItemInfoList::iterator it2;
+
+ for(it = fileList.begin() ; it != fileList.end() ; ++it)
+ {
+ info.setFile((*it).name);
+ if (!fileNames.contains(info.fileName().lower()) &&
+ !fileExts.contains(info.extension(false).lower()))
+ {
+ kdDebug() << info.fileName() << " : " << (*it).mtime << endl;
+
+ for(it2 = sfileList.begin() ; it2 != sfileList.end() ; ++it2)
+ if ((*it2).mtime <= (*it).mtime) break;
+
+ sfileList.insert(it2, *it);
+ }
+ }
+
+ if (sfileList.empty())
+ return;
+
+ kdDebug() << sfileList.count() << endl;
+
+ GPItemInfoList::const_iterator it3 = sfileList.begin();
+
+ do
+ {
+ GPItemInfo item = *it3;
+
+ if (item.mtime > (time_t)d->lastAccess.toTime_t() && item.downloaded == GPItemInfo::DownloadUnknow)
+ item.downloaded = GPItemInfo::NewPicture;
+
+ d->view->addItem(item);
+ d->controller->getThumbnail(item.folder, item.name);
+ ++it3;
+ }
+ while(it3 != sfileList.end());
+
+ d->progress->setTotalSteps(d->progress->totalSteps() + fileList.count());
+}
+
+void CameraUI::slotThumbnail(const TQString& folder, const TQString& file,
+ const TQImage& thumbnail)
+{
+ d->view->setThumbnail(folder, file, thumbnail);
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::slotInformations()
+{
+ if (d->busy)
+ return;
+
+ d->controller->getCameraInformations();
+}
+
+void CameraUI::slotCameraInformations(const TQString& summary, const TQString& manual, const TQString& about)
+{
+ CameraInfoDialog *infoDlg = new CameraInfoDialog(this, summary, manual, about);
+ infoDlg->show();
+}
+
+void CameraUI::slotErrorMsg(const TQString& msg)
+{
+ KMessageBox::error(this, msg);
+}
+
+void CameraUI::slotUpload()
+{
+ if (d->busy)
+ return;
+
+ TQString fileformats;
+
+ TQStringList patternList = TQStringList::split('\n', KImageIO::pattern(KImageIO::Reading));
+
+ // All Images from list must been always the first entry given by KDE API
+ TQString allPictures = patternList[0];
+
+ // Add RAW file format to All Images" type mime and remplace current.
+#if KDCRAW_VERSION < 0x000106
+ allPictures.insert(allPictures.find("|"), TQString(KDcrawIface::DcrawBinary::instance()->rawFiles()));
+#else
+ allPictures.insert(allPictures.find("|"), TQString(KDcrawIface::KDcraw::rawFiles()));
+#endif
+ patternList.remove(patternList[0]);
+ patternList.prepend(allPictures);
+
+ // Added RAW file formats supported by dcraw program like a type mime.
+ // Nota: we cannot use here "image/x-raw" type mime from KDE because it uncomplete
+ // or unavailable(dcraw_0)(see file #121242 in B.K.O).
+#if KDCRAW_VERSION < 0x000106
+ patternList.append(TQString("\n%1|Camera RAW files").arg(TQString(KDcrawIface::DcrawBinary::instance()->rawFiles())));
+#else
+ patternList.append(TQString("\n%1|Camera RAW files").arg(TQString(KDcrawIface::KDcraw::rawFiles())));
+#endif
+
+ fileformats = patternList.join("\n");
+
+ DDebug () << "fileformats=" << fileformats << endl;
+
+ KURL::List urls = KFileDialog::getOpenURLs(AlbumManager::instance()->getLibraryPath(),
+ fileformats, this, i18n("Select Image to Upload"));
+ if (!urls.isEmpty())
+ slotUploadItems(urls);
+}
+
+void CameraUI::slotUploadItems(const KURL::List& urls)
+{
+ if (d->busy)
+ return;
+
+ if (urls.isEmpty())
+ return;
+
+ CameraFolderDialog dlg(this, d->view, d->cameraFolderList, d->controller->getCameraTitle(),
+ d->controller->getCameraPath());
+
+ if (dlg.exec() != TQDialog::Accepted)
+ return;
+
+ TQString cameraFolder = dlg.selectedFolderPath();
+
+ for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it)
+ {
+ TQFileInfo fi((*it).path());
+ if (!fi.exists()) continue;
+ if (fi.isDir()) continue;
+
+ TQString ext = TQString(".") + fi.extension();
+ TQString name = fi.fileName();
+ name.truncate(fi.fileName().length() - ext.length());
+
+ bool ok;
+
+ while (d->view->findItem(cameraFolder, name + ext))
+ {
+ TQString msg(i18n("Camera Folder <b>%1</b> already contains item <b>%2</b><br>"
+ "Please enter a new file name (without extension):")
+ .arg(cameraFolder).arg(fi.fileName()));
+#if KDE_IS_VERSION(3,2,0)
+ name = KInputDialog::getText(i18n("File already exists"), msg, name, &ok, this);
+
+#else
+ name = KLineEditDlg::getText(i18n("File already exists"), msg, name, &ok, this);
+#endif
+ if (!ok)
+ return;
+ }
+
+ d->controller->upload(fi, name + ext, cameraFolder);
+ }
+}
+
+void CameraUI::slotUploaded(const GPItemInfo& itemInfo)
+{
+ if (d->closed)
+ return;
+
+ d->view->addItem(itemInfo);
+ d->controller->getThumbnail(itemInfo.folder, itemInfo.name);
+}
+
+void CameraUI::slotDownloadSelected()
+{
+ slotDownload(true, false);
+}
+
+void CameraUI::slotDownloadAndDeleteSelected()
+{
+ slotDownload(true, true);
+}
+
+void CameraUI::slotDownloadAll()
+{
+ slotDownload(false, false);
+}
+
+void CameraUI::slotDownloadAndDeleteAll()
+{
+ slotDownload(false, true);
+}
+
+void CameraUI::slotDownload(bool onlySelected, bool deleteAfter, Album *album)
+{
+ // See B.K.O #143934: force to select all items to prevent problem
+ // when !renameCustomizer->useDefault() ==> iconItem->getDownloadName()
+ // can return an empty string in this case because it depends on selection.
+ if (!onlySelected)
+ d->view->slotSelectAll();
+
+ // See B.K.O #139519: Always check free space available before to
+ // download items selection from camera.
+ unsigned long fSize = 0;
+ unsigned long dSize = 0;
+ d->view->itemsSelectionSizeInfo(fSize, dSize);
+ if (d->freeSpaceWidget->isValid() && (dSize >= d->freeSpaceWidget->kBAvail()))
+ {
+ KMessageBox::error(this, i18n("There is no enough free space on Album Library Path "
+ "to download and process selected pictures from camera.\n\n"
+ "Estimated space require: %1\n"
+ "Available free space: %2")
+ .arg(TDEIO::convertSizeFromKB(dSize))
+ .arg(TDEIO::convertSizeFromKB(d->freeSpaceWidget->kBAvail())));
+ return;
+ }
+
+ TQString newDirName;
+ IconItem* firstItem = d->view->firstItem();
+ if (firstItem)
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(firstItem);
+
+ TQDateTime dateTime;
+ dateTime.setTime_t(iconItem->itemInfo()->mtime);
+
+ switch(d->folderDateFormat->currentItem())
+ {
+ case CameraUIPriv::TextDateFormat:
+ newDirName = dateTime.date().toString(TQt::TextDate);
+ break;
+ case CameraUIPriv::LocalDateFormat:
+ newDirName = dateTime.date().toString(TQt::LocalDate);
+ break;
+ default: // IsoDateFormat
+ newDirName = dateTime.date().toString(TQt::ISODate);
+ break;
+ }
+ }
+
+ // -- Get the destination album from digiKam library if necessary ---------------
+
+ if (!album)
+ {
+ AlbumManager* man = AlbumManager::instance();
+ album = man->currentAlbum();
+
+ if (album && album->type() != Album::PHYSICAL)
+ album = 0;
+
+ TQString header(i18n("<p>Please select the destination album from the digiKam library to "
+ "import the camera pictures into.</p>"));
+
+ album = AlbumSelectDialog::selectAlbum(this, (PAlbum*)album, header, newDirName,
+ d->autoAlbumDateCheck->isChecked());
+
+ if (!album) return;
+ }
+
+ PAlbum *pAlbum = dynamic_cast<PAlbum*>(album);
+ if (!pAlbum) return;
+
+ // -- Prepare downloading of camera items ------------------------
+
+ KURL url;
+ url.setPath(pAlbum->folderPath());
+
+ d->controller->downloadPrep();
+
+ DownloadSettingsContainer downloadSettings;
+ TQString downloadName;
+ time_t mtime;
+ int total = 0;
+
+ downloadSettings.autoRotate = d->autoRotateCheck->isChecked();
+ downloadSettings.fixDateTime = d->fixDateTimeCheck->isChecked();
+ downloadSettings.newDateTime = d->dateTimeEdit->dateTime();
+ downloadSettings.setPhotographerId = d->setPhotographerId->isChecked();
+ downloadSettings.setCredits = d->setCredits->isChecked();
+ downloadSettings.convertJpeg = convertLosslessJpegFiles();
+ downloadSettings.losslessFormat = losslessFormat();
+
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (settings)
+ {
+ downloadSettings.author = settings->getIptcAuthor();
+ downloadSettings.authorTitle = settings->getIptcAuthorTitle();
+ downloadSettings.credit = settings->getIptcCredit();
+ downloadSettings.source = settings->getIptcSource();
+ downloadSettings.copyright = settings->getIptcCopyright();
+ }
+
+ // -- Download camera items -------------------------------
+ // Since we show camera items in reverse order, downloading need to be done also in reverse order.
+
+ for (IconItem* item = d->view->lastItem(); item;
+ item = item->prevItem())
+ {
+ if (onlySelected && !(item->isSelected()))
+ continue;
+
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ downloadSettings.folder = iconItem->itemInfo()->folder;
+ downloadSettings.file = iconItem->itemInfo()->name;
+ downloadName = iconItem->getDownloadName();
+ mtime = iconItem->itemInfo()->mtime;
+
+ KURL u(url);
+ TQString errMsg;
+ TQDateTime dateTime;
+ dateTime.setTime_t(mtime);
+
+ // Auto sub-albums creation based on file date.
+
+ if (d->autoAlbumDateCheck->isChecked())
+ {
+ TQString dirName;
+
+ switch(d->folderDateFormat->currentItem())
+ {
+ case CameraUIPriv::TextDateFormat:
+ dirName = dateTime.date().toString(TQt::TextDate);
+ break;
+ case CameraUIPriv::LocalDateFormat:
+ dirName = dateTime.date().toString(TQt::LocalDate);
+ break;
+ default: // IsoDateFormat
+ dirName = dateTime.date().toString(TQt::ISODate);
+ break;
+ }
+ // See B.K.O #136927 : we need to support file system which do not
+ // handle upper case properly.
+ dirName = dirName.lower();
+ if (!createAutoAlbum(url, dirName, dateTime.date(), errMsg))
+ {
+ KMessageBox::error(this, errMsg);
+ return;
+ }
+
+ u.addPath(dirName);
+ }
+
+ // Auto sub-albums creation based on file extensions.
+
+ if (d->autoAlbumExtCheck->isChecked())
+ {
+ // We use the target file name to compute sub-albums name to take a care about
+ // convertion on the fly option.
+ TQFileInfo fi(downloadName);
+
+ TQString subAlbum = fi.extension(false).upper();
+ if (fi.extension(false).upper() == TQString("JPEG") ||
+ fi.extension(false).upper() == TQString("JPE"))
+ subAlbum = TQString("JPG");
+ if (fi.extension(false).upper() == TQString("TIFF"))
+ subAlbum = TQString("TIF");
+ if (fi.extension(false).upper() == TQString("MPEG") ||
+ fi.extension(false).upper() == TQString("MPE") ||
+ fi.extension(false).upper() == TQString("MPO"))
+ subAlbum = TQString("MPG");
+
+ // See B.K.O #136927 : we need to support file system which do not
+ // handle upper case properly.
+ subAlbum = subAlbum.lower();
+ if (!createAutoAlbum(u, subAlbum, dateTime.date(), errMsg))
+ {
+ KMessageBox::error(this, errMsg);
+ return;
+ }
+
+ u.addPath(subAlbum);
+ }
+
+ d->foldersToScan.append(u.path());
+ u.addPath(downloadName.isEmpty() ? downloadSettings.file : downloadName);
+
+ downloadSettings.dest = u.path();
+
+ d->controller->download(downloadSettings);
+ addFileExtension(TQFileInfo(u.path()).extension(false));
+ total++;
+ }
+
+ if (total <= 0)
+ return;
+
+ d->lastDestURL = url;
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(total);
+ d->progress->show();
+
+ // disable settings tab here instead of slotBusy:
+ // Only needs to be disabled while downloading
+ d->advBox->setEnabled(false);
+
+ d->deleteAfter = deleteAfter;
+}
+
+void CameraUI::slotDownloaded(const TQString& folder, const TQString& file, int status)
+{
+ CameraIconViewItem* iconItem = d->view->findItem(folder, file);
+ if (iconItem)
+ iconItem->setDownloaded(status);
+
+ if (status == GPItemInfo::DownloadedYes || status == GPItemInfo::DownloadFailed)
+ {
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+ }
+
+ // Download all items is complete.
+ if (d->progress->progress() == d->progress->totalSteps())
+ {
+ if (d->deleteAfter)
+ deleteItems(true, true);
+ }
+}
+
+void CameraUI::slotSkipped(const TQString& folder, const TQString& file)
+{
+ CameraIconViewItem* iconItem = d->view->findItem(folder, file);
+ if (iconItem)
+ iconItem->setDownloaded(GPItemInfo::DownloadedNo);
+
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::slotToggleLock()
+{
+ int count = 0;
+ for (IconItem* item = d->view->firstItem(); item;
+ item = item->nextItem())
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ if (iconItem->isSelected())
+ {
+ TQString folder = iconItem->itemInfo()->folder;
+ TQString file = iconItem->itemInfo()->name;
+ int writePerm = iconItem->itemInfo()->writePermissions;
+ bool lock = true;
+
+ // If item is currently locked, unlock it.
+ if (writePerm == 0)
+ lock = false;
+
+ d->controller->lockFile(folder, file, lock);
+ count++;
+ }
+ }
+
+ if (count > 0)
+ {
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(count);
+ d->progress->show();
+ }
+}
+
+void CameraUI::slotLocked(const TQString& folder, const TQString& file, bool status)
+{
+ if (status)
+ {
+ CameraIconViewItem* iconItem = d->view->findItem(folder, file);
+ if (iconItem)
+ {
+ iconItem->toggleLock();
+ //if (iconItem->isSelected())
+ // slotItemsSelected(iconItem, true);
+ }
+ }
+
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::checkItem4Deletion(CameraIconViewItem* iconItem, TQStringList& folders, TQStringList& files,
+ TQStringList& deleteList, TQStringList& lockedList)
+{
+ if (iconItem->itemInfo()->writePermissions != 0) // Item not locked ?
+ {
+ TQString folder = iconItem->itemInfo()->folder;
+ TQString file = iconItem->itemInfo()->name;
+ folders.append(folder);
+ files.append(file);
+ deleteList.append(folder + TQString("/") + file);
+ }
+ else
+ {
+ lockedList.append(iconItem->itemInfo()->name);
+ }
+}
+
+void CameraUI::deleteItems(bool onlySelected, bool onlyDownloaded)
+{
+ TQStringList folders;
+ TQStringList files;
+ TQStringList deleteList;
+ TQStringList lockedList;
+
+ for (IconItem* item = d->view->firstItem(); item; item = item->nextItem())
+ {
+ CameraIconViewItem* iconItem = dynamic_cast<CameraIconViewItem*>(item);
+ if (iconItem)
+ {
+ if (onlySelected)
+ {
+ if (iconItem->isSelected())
+ {
+ if (onlyDownloaded)
+ {
+ if (iconItem->isDownloaded())
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ else
+ {
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ }
+ }
+ else // All items
+ {
+ if (onlyDownloaded)
+ {
+ if (iconItem->isDownloaded())
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ else
+ {
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ }
+ }
+ }
+
+ // If we want to delete some locked files, just give a feedback to user.
+ if (!lockedList.isEmpty())
+ {
+ TQString infoMsg(i18n("The items listed below are locked by camera (read-only). "
+ "These items will not be deleted. If you really want to delete these items, "
+ "please unlock them and try again."));
+ KMessageBox::informationList(this, infoMsg, lockedList, i18n("Information"));
+ }
+
+ if (folders.isEmpty())
+ return;
+
+ TQString warnMsg(i18n("About to delete this image. "
+ "Deleted files are unrecoverable. "
+ "Are you sure?",
+ "About to delete these %n images. "
+ "Deleted files are unrecoverable. "
+ "Are you sure?",
+ deleteList.count()));
+ if (KMessageBox::warningContinueCancelList(this, warnMsg,
+ deleteList,
+ i18n("Warning"),
+ i18n("Delete"))
+ == KMessageBox::Continue)
+ {
+ TQStringList::iterator itFolder = folders.begin();
+ TQStringList::iterator itFile = files.begin();
+
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(deleteList.count());
+ d->progress->show();
+
+ for ( ; itFolder != folders.end(); ++itFolder, ++itFile)
+ {
+ d->controller->deleteFile(*itFolder, *itFile);
+ // the currentlyDeleting list is used to prevent loading items which
+ // will immenently be deleted into the sidebar and wasting time
+ d->currentlyDeleting.append(*itFolder + *itFile);
+ }
+ }
+}
+
+void CameraUI::slotDeleteSelected()
+{
+ deleteItems(true, false);
+}
+
+void CameraUI::slotDeleteAll()
+{
+ deleteItems(false, false);
+}
+
+void CameraUI::slotDeleted(const TQString& folder, const TQString& file, bool status)
+{
+ if (status)
+ {
+ d->view->removeItem(folder, file);
+ // do this after removeItem, which will signal to slotItemsSelected, which checks for the list
+ d->currentlyDeleting.remove(folder + file);
+ }
+
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::slotFileView(CameraIconViewItem* item)
+{
+ d->controller->openFile(item->itemInfo()->folder, item->itemInfo()->name);
+}
+
+void CameraUI::slotExifFromFile(const TQString& folder, const TQString& file)
+{
+ CameraIconViewItem* item = d->view->findItem(folder, file);
+ if (!item)
+ return;
+
+ d->rightSidebar->itemChanged(item->itemInfo(), folder + TQString("/") + file,
+ TQByteArray(), d->view, item);
+}
+
+void CameraUI::slotExifFromData(const TQByteArray& exifData)
+{
+ CameraIconViewItem* item = dynamic_cast<CameraIconViewItem*>(d->view->currentItem());
+
+ if (!item)
+ return;
+
+ KURL url(item->itemInfo()->folder + '/' + item->itemInfo()->name);
+
+ // Sometimes, GPhoto2 drivers return complete APP1 JFIF section. Exiv2 cannot
+ // decode (yet) exif metadata from APP1. We will find Exif header to get data at this place
+ // to please with Exiv2...
+
+ DDebug() << "Size of Exif metadata from camera = " << exifData.size() << endl;
+ char exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
+
+ if (!exifData.isEmpty())
+ {
+ int i = exifData.find(*exifHeader);
+ if (i != -1)
+ {
+ DDebug() << "Exif header found at position " << i << endl;
+ i = i + sizeof(exifHeader);
+ TQByteArray data(exifData.size()-i);
+ memcpy(data.data(), exifData.data()+i, data.size());
+ d->rightSidebar->itemChanged(item->itemInfo(), url, data, d->view, item);
+ return;
+ }
+ }
+
+ d->rightSidebar->itemChanged(item->itemInfo(), url, exifData, d->view, item);
+}
+
+void CameraUI::slotNewSelection(bool hasSelection)
+{
+ if (!d->renameCustomizer->useDefault())
+ {
+ d->downloadMenu->setItemEnabled(0, hasSelection);
+ d->downloadMenu->setItemEnabled(2, hasSelection);
+ }
+ else
+ {
+ d->downloadMenu->setItemEnabled(0, hasSelection);
+ d->downloadMenu->setItemEnabled(2, hasSelection);
+ }
+
+ unsigned long fSize = 0;
+ unsigned long dSize = 0;
+ d->view->itemsSelectionSizeInfo(fSize, dSize);
+ d->freeSpaceWidget->setEstimatedDSizeKb(dSize);
+}
+
+void CameraUI::slotItemsSelected(CameraIconViewItem* item, bool selected)
+{
+ d->downloadMenu->setItemEnabled(0, selected);
+ d->downloadMenu->setItemEnabled(2, selected);
+ d->deleteMenu->setItemEnabled(0, selected);
+
+ if (selected)
+ {
+ // if selected item is in the list of item which will be deleted, set no current item
+ if (d->currentlyDeleting.find(item->itemInfo()->folder + item->itemInfo()->name)
+ == d->currentlyDeleting.end())
+ {
+ KURL url(item->itemInfo()->folder + '/' + item->itemInfo()->name);
+ d->rightSidebar->itemChanged(item->itemInfo(), url, TQByteArray(), d->view, item);
+ d->controller->getExif(item->itemInfo()->folder, item->itemInfo()->name);
+ }
+ else
+ {
+ d->rightSidebar->slotNoCurrentItem();
+ }
+ }
+ else
+ d->rightSidebar->slotNoCurrentItem();
+}
+
+bool CameraUI::createAutoAlbum(const KURL& parentURL, const TQString& sub,
+ const TQDate& date, TQString& errMsg)
+{
+ KURL u(parentURL);
+ u.addPath(sub);
+
+ // first stat to see if the album exists
+ TQFileInfo info(u.path());
+ if (info.exists())
+ {
+ // now check if its really a directory
+ if (info.isDir())
+ return true;
+ else
+ {
+ errMsg = i18n("A file with same name (%1) exists in folder %2")
+ .arg(sub)
+ .arg(parentURL.path());
+ return false;
+ }
+ }
+
+ // looks like the directory does not exist, try to create it
+
+ AlbumManager* aman = AlbumManager::instance();
+ PAlbum* parent = aman->findPAlbum(parentURL);
+ if (!parent)
+ {
+ errMsg = i18n("Failed to find Album for path '%1'")
+ .arg(parentURL.path());
+ return false;
+ }
+
+ return aman->createPAlbum(parent, sub, TQString(""), date, TQString(""), errMsg);
+}
+
+void CameraUI::addFileExtension(const TQString& ext)
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings)
+ return;
+
+ if (settings->getImageFileFilter().upper().contains(ext.upper()) ||
+ settings->getMovieFileFilter().upper().contains(ext.upper()) ||
+ settings->getAudioFileFilter().upper().contains(ext.upper()) ||
+ settings->getRawFileFilter().upper().contains(ext.upper()))
+ return;
+
+ settings->setImageFileFilter(settings->getImageFileFilter() + TQString(" *.") + ext);
+ emit signalAlbumSettingsChanged();
+}
+
+void CameraUI::slotFirstItem()
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->firstItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem);
+}
+
+void CameraUI::slotPrevItem()
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->currentItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem->prevItem());
+}
+
+void CameraUI::slotNextItem()
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->currentItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem->nextItem());
+}
+
+void CameraUI::slotLastItem(void)
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->lastItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem);
+}
+
+// Backport KDialog::keyPressEvent() implementation from KDELibs to ignore Enter/Return Key events
+// to prevent any conflicts between dialog keys events and SpinBox keys events.
+
+void CameraUI::keyPressEvent(TQKeyEvent *e)
+{
+ if ( e->state() == 0 )
+ {
+ switch ( e->key() )
+ {
+ case Key_Escape:
+ e->accept();
+ reject();
+ break;
+ case Key_Enter:
+ case Key_Return:
+ e->ignore();
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ }
+ else
+ {
+ // accept the dialog when Ctrl-Return is pressed
+ if ( e->state() == ControlButton &&
+ (e->key() == Key_Return || e->key() == Key_Enter) )
+ {
+ e->accept();
+ accept();
+ }
+ else
+ {
+ e->ignore();
+ }
+ }
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/cameraui.h b/src/utilities/cameragui/cameraui.h
new file mode 100644
index 00000000..df9c7885
--- /dev/null
+++ b/src/utilities/cameragui/cameraui.h
@@ -0,0 +1,155 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-16
+ * Description : Camera interface dialog
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 CAMERAUI_H
+#define CAMERAUI_H
+
+// TQt includes.
+
+#include <tqdatetime.h>
+#include <tqstring.h>
+#include <tqimage.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+// Local includes.
+
+#include "gpiteminfo.h"
+
+namespace Digikam
+{
+
+class Album;
+class CameraIconViewItem;
+class CameraUIPriv;
+
+class CameraUI : public KDialogBase
+{
+ TQ_OBJECT
+
+
+public:
+
+ CameraUI(TQWidget* parent, const TQString& cameraTitle,
+ const TQString& model, const TQString& port,
+ const TQString& path, const TQDateTime lastAccess);
+ ~CameraUI();
+
+ bool isBusy() const;
+ bool isClosed() const;
+
+ bool autoRotateJpegFiles() const;
+
+ /** Get status of JPEG conversion files to lossless format during download.*/
+ bool convertLosslessJpegFiles() const;
+ TQString losslessFormat();
+
+ TQString cameraTitle() const;
+
+signals:
+
+ void signalLastDestination(const KURL&);
+ void signalAlbumSettingsChanged();
+
+public slots:
+
+ void slotDownload(bool onlySelected, bool deleteAfter, Album *album=0);
+
+protected:
+
+ void closeEvent(TQCloseEvent* e);
+ void keyPressEvent(TQKeyEvent *e);
+
+private:
+
+ void readSettings();
+ void saveSettings();
+ bool dialogClosed();
+ bool createAutoAlbum(const KURL& parentURL, const TQString& sub,
+ const TQDate& date, TQString& errMsg);
+ void addFileExtension(const TQString& ext);
+ void finishDialog();
+ void deleteItems(bool onlySelected, bool onlyDownloaded);
+ void checkItem4Deletion(CameraIconViewItem* iconItem, TQStringList& folders, TQStringList& files,
+ TQStringList& deleteList, TQStringList& lockedList);
+
+private slots:
+
+ void slotClose();
+ void slotCancelButton();
+ void slotProcessURL(const TQString& url);
+
+ void slotConnected(bool val);
+ void slotBusy(bool val);
+ void slotErrorMsg(const TQString& msg);
+ void slotInformations();
+ void slotCameraInformations(const TQString&, const TQString&, const TQString&);
+
+ void slotFolderList(const TQStringList& folderList);
+ void slotFileList(const GPItemInfoList& fileList);
+ void slotThumbnail(const TQString&, const TQString&, const TQImage&);
+
+ void slotIncreaseThumbSize();
+ void slotDecreaseThumbSize();
+
+ void slotUpload();
+ void slotUploadItems(const KURL::List&);
+ void slotDownloadSelected();
+ void slotDownloadAll();
+ void slotDeleteSelected();
+ void slotDownloadAndDeleteSelected();
+ void slotDeleteAll();
+ void slotDownloadAndDeleteAll();
+ void slotToggleLock();
+
+ void slotFileView(CameraIconViewItem* item);
+
+ void slotUploaded(const GPItemInfo&);
+ void slotDownloaded(const TQString&, const TQString&, int);
+ void slotSkipped(const TQString&, const TQString&);
+ void slotDeleted(const TQString&, const TQString&, bool);
+ void slotLocked(const TQString&, const TQString&, bool);
+
+ void slotNewSelection(bool);
+ void slotItemsSelected(CameraIconViewItem* item, bool selected);
+
+ void slotExifFromFile(const TQString& folder, const TQString& file);
+ void slotExifFromData(const TQByteArray& exifData);
+
+ void slotFirstItem(void);
+ void slotPrevItem(void);
+ void slotNextItem(void);
+ void slotLastItem(void);
+
+private:
+
+ CameraUIPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAUI_H */
diff --git a/src/utilities/cameragui/dkcamera.cpp b/src/utilities/cameragui/dkcamera.cpp
new file mode 100644
index 00000000..8f318855
--- /dev/null
+++ b/src/utilities/cameragui/dkcamera.cpp
@@ -0,0 +1,113 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-12-21
+ * Description : abstract camera interface class
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqdeepcopy.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "dkcamera.h"
+
+namespace Digikam
+{
+
+DKCamera::DKCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path)
+{
+ m_title = title;
+ m_model = model;
+ m_port = port;
+ m_path = path;
+
+ AlbumSettings* settings = AlbumSettings::instance();
+ m_imageFilter = TQDeepCopy<TQString>(settings->getImageFileFilter());
+ m_movieFilter = TQDeepCopy<TQString>(settings->getMovieFileFilter());
+ m_audioFilter = TQDeepCopy<TQString>(settings->getAudioFileFilter());
+ m_rawFilter = TQDeepCopy<TQString>(settings->getRawFileFilter());
+
+ m_imageFilter = m_imageFilter.lower();
+ m_movieFilter = m_movieFilter.lower();
+ m_audioFilter = m_audioFilter.lower();
+ m_rawFilter = m_rawFilter.lower();
+}
+
+DKCamera::~DKCamera()
+{
+}
+
+TQString DKCamera::title() const
+{
+ return m_title;
+}
+
+TQString DKCamera::model() const
+{
+ return m_model;
+}
+
+TQString DKCamera::port() const
+{
+ return m_port;
+}
+
+TQString DKCamera::path() const
+{
+ return m_path;
+}
+
+TQString DKCamera::mimeType(const TQString& fileext) const
+{
+ if (fileext.isEmpty()) return TQString();
+
+ TQString ext = fileext;
+ TQString mime;
+
+ // Massage known variations of known mimetypes into KDE specific ones
+ if (ext == "jpg" || ext == "jpe")
+ ext = "jpeg";
+ else if (ext == "tif")
+ ext = "tiff";
+
+ if (m_rawFilter.contains(ext))
+ {
+ mime = TQString("image/x-raw");
+ }
+ else if (m_imageFilter.contains(ext))
+ {
+ mime = TQString("image/") + ext;
+ }
+ else if (m_movieFilter.contains(ext))
+ {
+ mime = TQString("video/") + ext;
+ }
+ else if (m_audioFilter.contains(ext))
+ {
+ mime = TQString("audio/") + ext;
+ }
+
+ return mime;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/dkcamera.h b/src/utilities/cameragui/dkcamera.h
new file mode 100644
index 00000000..2ef76723
--- /dev/null
+++ b/src/utilities/cameragui/dkcamera.h
@@ -0,0 +1,97 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-12-21
+ * Description : abstract camera interface class
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 DKCAMERA_H
+#define DKCAMERA_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// Local includes.
+
+#include "gpiteminfo.h"
+
+class TQStringList;
+class TQImage;
+
+namespace Digikam
+{
+
+class DKCamera
+{
+public:
+
+ DKCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path);
+ virtual ~DKCamera();
+
+ virtual bool doConnect() = 0;
+ virtual void cancel() = 0;
+
+ virtual void getAllFolders(const TQString& folder, TQStringList& subFolderList) = 0;
+
+ /// If getImageDimensions is false, the camera shall set width and height to -1
+ /// if the values are not immediately available
+ virtual bool getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions = true) = 0;
+
+ virtual bool getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail) = 0;
+ virtual bool getExif(const TQString& folder, const TQString& itemName, char **edata, int& esize) = 0;
+
+ virtual bool downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile) = 0;
+ virtual bool deleteItem(const TQString& folder, const TQString& itemName) = 0;
+ virtual bool uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile,
+ GPItemInfo& itemInfo, bool getImageDimensions=true) = 0;
+ virtual bool cameraSummary(TQString& summary) = 0;
+ virtual bool cameraManual(TQString& manual) = 0;
+ virtual bool cameraAbout(TQString& about) = 0;
+
+ virtual bool setLockItem(const TQString& folder, const TQString& itemName, bool lock) = 0;
+
+ TQString title() const;
+ TQString model() const;
+ TQString port() const;
+ TQString path() const;
+
+protected:
+
+ TQString mimeType(const TQString& fileext) const;
+
+protected:
+
+ TQString m_imageFilter;
+ TQString m_movieFilter;
+ TQString m_audioFilter;
+ TQString m_rawFilter;
+
+private:
+
+ TQString m_title;
+ TQString m_model;
+ TQString m_port;
+ TQString m_path;
+};
+
+} // namespace Digikam
+
+#endif /* DKCAMERA_H */
diff --git a/src/utilities/cameragui/downloadsettingscontainer.h b/src/utilities/cameragui/downloadsettingscontainer.h
new file mode 100644
index 00000000..b3e59501
--- /dev/null
+++ b/src/utilities/cameragui/downloadsettingscontainer.h
@@ -0,0 +1,79 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-21-07
+ * Description : Camera item download settings container.
+ *
+ * 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 DOWNLOADSETTINGSCONTAINER_H
+#define DOWNLOADSETTINGSCONTAINER_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqdatetime.h>
+
+namespace Digikam
+{
+
+class DownloadSettingsContainer
+{
+
+public:
+
+ DownloadSettingsContainer()
+ {
+ autoRotate = true;
+ fixDateTime = false;
+ setPhotographerId = false;
+ setCredits = false;
+ convertJpeg = false;
+ };
+
+ ~DownloadSettingsContainer(){};
+
+public:
+
+ bool autoRotate;
+ bool fixDateTime;
+ bool setPhotographerId;
+ bool setCredits;
+ bool convertJpeg;
+
+ TQDateTime newDateTime;
+
+ // File path to download.
+ TQString folder;
+ TQString file;
+ TQString dest;
+
+ // New format to convert Jpeg files.
+ TQString losslessFormat;
+
+ // IPTC settings
+ TQString author;
+ TQString authorTitle;
+ TQString credit;
+ TQString source;
+ TQString copyright;
+};
+
+} // namespace Digikam
+
+#endif // DOWNLOADSETTINGSCONTAINER_H
diff --git a/src/utilities/cameragui/freespacewidget.cpp b/src/utilities/cameragui/freespacewidget.cpp
new file mode 100644
index 00000000..0d7a26b1
--- /dev/null
+++ b/src/utilities/cameragui/freespacewidget.cpp
@@ -0,0 +1,252 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-08-31
+ * Description : a widget to display free space for a mount-point.
+ *
+ * Copyright (C) 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 <tqwhatsthis.h>
+#include <tqtooltip.h>
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqpalette.h>
+#include <tqcolor.h>
+#include <tqtimer.h>
+#include <tqfont.h>
+#include <tqfontmetrics.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <tdelocale.h>
+#include <kdiskfreesp.h>
+#include <tdeio/global.h>
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "freespacewidget.h"
+#include "freespacewidget.moc"
+
+namespace Digikam
+{
+
+class FreeSpaceWidgetPriv
+{
+public:
+
+ FreeSpaceWidgetPriv()
+ {
+ timer = 0;
+ isValid = false;
+ kBSize = 0;
+ kBUsed = 0;
+ kBAvail = 0;
+ dSizeKb = 0;
+ percentUsed = 0;
+ }
+
+ bool isValid;
+
+ int percentUsed;
+
+ unsigned long dSizeKb;
+ unsigned long kBSize;
+ unsigned long kBUsed;
+ unsigned long kBAvail;
+
+ TQString mountPoint;
+
+ TQTimer *timer;
+
+ TQPixmap pix;
+};
+
+FreeSpaceWidget::FreeSpaceWidget(TQWidget* parent, int width)
+ : TQWidget(parent, 0, WResizeNoErase|WRepaintNoErase)
+{
+ d = new FreeSpaceWidgetPriv;
+ setBackgroundMode(TQt::NoBackground);
+ setFixedWidth(width);
+ setMaximumHeight(fontMetrics().height()+4);
+ slotTimeout();
+
+ d->timer = new TQTimer(this);
+
+ connect(d->timer, TQ_SIGNAL(timeout()),
+ this, TQ_SLOT(slotTimeout()));
+
+ d->timer->start(10000);
+}
+
+FreeSpaceWidget::~FreeSpaceWidget()
+{
+ d->timer->stop();
+ delete d->timer;
+ delete d;
+}
+
+void FreeSpaceWidget::setEstimatedDSizeKb(unsigned long dSize)
+{
+ d->dSizeKb = dSize;
+ updatePixmap();
+ repaint();
+}
+
+unsigned long FreeSpaceWidget::estimatedDSizeKb()
+{
+ return d->dSizeKb;
+}
+
+bool FreeSpaceWidget::isValid()
+{
+ return d->isValid;
+}
+
+int FreeSpaceWidget::percentUsed()
+{
+ return d->percentUsed;
+}
+
+unsigned long FreeSpaceWidget::kBSize()
+{
+ return d->kBSize;
+}
+
+unsigned long FreeSpaceWidget::kBUsed()
+{
+ return d->kBUsed;
+}
+
+unsigned long FreeSpaceWidget::kBAvail()
+{
+ return d->kBAvail;
+}
+
+TQString FreeSpaceWidget::mountPoint()
+{
+ return d->mountPoint;
+}
+
+void FreeSpaceWidget::updatePixmap()
+{
+ TQPixmap fimgPix = SmallIcon("folder_image");
+ d->pix = TQPixmap(size());
+ d->pix.fill(colorGroup().background());
+
+ TQPainter p(&d->pix);
+ p.setPen(colorGroup().mid());
+ p.drawRect(0, 0, d->pix.width(), d->pix.height());
+ p.drawPixmap(2, d->pix.height()/2-fimgPix.height()/2,
+ fimgPix, 0, 0, fimgPix.width(), fimgPix.height());
+
+ if (isValid())
+ {
+ // We will compute the estimated % of space size used to download and process.
+ unsigned long eUsedKb = d->dSizeKb + d->kBUsed;
+ int peUsed = (int)(100.0*((double)eUsedKb/(double)d->kBSize));
+ int pClamp = peUsed > 100 ? 100 : peUsed;
+ p.setBrush(peUsed > 95 ? TQt::red : TQt::darkGreen);
+ p.setPen(TQt::white);
+ TQRect gRect(fimgPix.height()+2, 1,
+ (int)(((double)d->pix.width()-2.0-fimgPix.width()-2.0)*(pClamp/100.0)),
+ d->pix.height()-2);
+ p.drawRect(gRect);
+
+ TQRect tRect(fimgPix.height()+2, 1, d->pix.width()-2-fimgPix.width()-2, d->pix.height()-2);
+ TQString text = TQString("%1%").arg(peUsed);
+ p.setPen(colorGroup().text());
+ TQFontMetrics fontMt = p.fontMetrics();
+ TQRect fontRect = fontMt.boundingRect(tRect.x(), tRect.y(),
+ tRect.width(), tRect.height(), 0, text);
+ p.drawText(tRect, TQt::AlignCenter, text);
+
+ TQString tipText, value;
+ TQString header = i18n("Album Library");
+ TQString headBeg("<tr bgcolor=\"orange\"><td colspan=\"2\">"
+ "<nobr><font size=\"-1\" color=\"black\"><b>");
+ TQString headEnd("</b></font></nobr></td></tr>");
+ TQString cellBeg("<tr><td><nobr><font size=-1>");
+ TQString cellMid("</font></nobr></td><td><nobr><font size=-1>");
+ TQString cellEnd("</font></nobr></td></tr>");
+ tipText = "<table cellspacing=0 cellpadding=0>";
+ tipText += headBeg + header + headEnd;
+
+ if (d->dSizeKb > 0)
+ {
+ tipText += cellBeg + i18n("Capacity:") + cellMid;
+ tipText += TDEIO::convertSizeFromKB(d->kBSize) + cellEnd;
+
+ tipText += cellBeg + i18n("Available:") + cellMid;
+ tipText += TDEIO::convertSizeFromKB(d->kBAvail) + cellEnd;
+
+ tipText += cellBeg + i18n("Require:") + cellMid;
+ tipText += TDEIO::convertSizeFromKB(d->dSizeKb) + cellEnd;
+ }
+ else
+ {
+ tipText += cellBeg + i18n("Capacity:") + cellMid;
+ tipText += TDEIO::convertSizeFromKB(d->kBSize) + cellEnd;
+
+ tipText += cellBeg + i18n("Available:") + cellMid;
+ tipText += TDEIO::convertSizeFromKB(d->kBAvail) + cellEnd;
+ }
+
+ tipText += "</table>";
+
+ TQWhatsThis::add(this, tipText);
+ TQToolTip::add(this, tipText);
+ }
+
+ p.end();
+}
+
+void FreeSpaceWidget::paintEvent(TQPaintEvent*)
+{
+ bitBlt(this, 0, 0, &d->pix);
+}
+
+void FreeSpaceWidget::slotTimeout()
+{
+ TQString mountPoint = TDEIO::findPathMountPoint(AlbumSettings::instance()->getAlbumLibraryPath());
+ KDiskFreeSp *job = new KDiskFreeSp;
+ connect(job, TQ_SIGNAL(foundMountPoint(const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString&)),
+ this, TQ_SLOT(slotAvailableFreeSpace(const unsigned long&, const unsigned long&,
+ const unsigned long&, const TQString&)));
+ job->readDF(mountPoint);
+}
+
+void FreeSpaceWidget::slotAvailableFreeSpace(const unsigned long& kBSize, const unsigned long& kBUsed,
+ const unsigned long& kBAvail, const TQString& mountPoint)
+{
+ d->mountPoint = mountPoint;
+ d->kBSize = kBSize;
+ d->kBUsed = kBUsed;
+ d->kBAvail = kBAvail;
+ d->percentUsed = 100 - (int)(100.0*kBAvail/kBSize);
+ d->isValid = true;
+ updatePixmap();
+ repaint();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/freespacewidget.h b/src/utilities/cameragui/freespacewidget.h
new file mode 100644
index 00000000..2111791a
--- /dev/null
+++ b/src/utilities/cameragui/freespacewidget.h
@@ -0,0 +1,75 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-08-31
+ * Description : a widget to display free space for a mount-point.
+ *
+ * Copyright (C) 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 FREESPACEWIDGET_H
+#define FREESPACEWIDGET_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class FreeSpaceWidgetPriv;
+
+class FreeSpaceWidget : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ FreeSpaceWidget(TQWidget* parent, int width);
+ ~FreeSpaceWidget();
+
+ void setEstimatedDSizeKb(unsigned long dSize);
+ unsigned long estimatedDSizeKb();
+
+ bool isValid() ;
+ int percentUsed();
+ unsigned long kBSize();
+ unsigned long kBUsed();
+ unsigned long kBAvail();
+ TQString mountPoint();
+
+protected:
+
+ void paintEvent(TQPaintEvent*);
+ void updatePixmap();
+
+private slots:
+
+ void slotTimeout();
+ void slotAvailableFreeSpace(const unsigned long& kBSize, const unsigned long& kBUsed,
+ const unsigned long& kBAvail, const TQString& mountPoint);
+
+private:
+
+ FreeSpaceWidgetPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* FREESPACEWIDGET_H */
diff --git a/src/utilities/cameragui/gpcamera.cpp b/src/utilities/cameragui/gpcamera.cpp
new file mode 100644
index 00000000..e03d92d0
--- /dev/null
+++ b/src/utilities/cameragui/gpcamera.cpp
@@ -0,0 +1,1223 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-21
+ * Description : Gphoto2 camera interface
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <cstdio>
+#include <iostream>
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+#include <tqimage.h>
+#include <tqpixmap.h>
+#include <tqdom.h>
+#include <tqfile.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+
+// C Ansi includes.
+extern "C"
+{
+#include <gphoto2.h>
+}
+
+// Local includes.
+
+#include "ddebug.h"
+#include "gpcamera.h"
+
+namespace Digikam
+{
+
+class GPCameraPrivate
+{
+
+public:
+
+ GPCameraPrivate()
+ {
+ camera = 0;
+ }
+
+ bool cameraInitialized;
+
+ bool thumbnailSupport;
+ bool deleteSupport;
+ bool uploadSupport;
+ bool mkDirSupport;
+ bool delDirSupport;
+
+ TQString model;
+ TQString port;
+ TQString globalPath;
+
+ Camera *camera;
+ CameraAbilities cameraAbilities;
+};
+
+class GPStatus
+{
+
+public:
+
+ GPStatus()
+ {
+ context = gp_context_new();
+ cancel = false;
+ gp_context_set_cancel_func(context, cancel_func, 0);
+ }
+
+ ~GPStatus()
+ {
+ gp_context_unref(context);
+ cancel = false;
+ }
+
+ GPContext *context;
+ static bool cancel;
+
+ static GPContextFeedback cancel_func(GPContext *, void *)
+ {
+ return (cancel ? GP_CONTEXT_FEEDBACK_CANCEL :
+ GP_CONTEXT_FEEDBACK_OK);
+ }
+};
+
+bool GPStatus::cancel = false;
+
+GPCamera::GPCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path)
+ : DKCamera(title, model, port, path)
+{
+ m_status = 0;
+
+ d = new GPCameraPrivate;
+ d->camera = 0;
+ d->model = model;
+ d->port = port;
+ d->globalPath = path;
+ d->cameraInitialized = false;
+ d->thumbnailSupport = false;
+ d->deleteSupport = false;
+ d->uploadSupport = false;
+ d->mkDirSupport = false;
+ d->delDirSupport = false;
+}
+
+GPCamera::~GPCamera()
+{
+ if (d->camera)
+ {
+ gp_camera_unref(d->camera);
+ d->camera = 0;
+ }
+
+ delete d;
+}
+
+TQString GPCamera::model() const
+{
+ return d->model;
+}
+
+TQString GPCamera::port() const
+{
+ return d->port;
+}
+
+TQString GPCamera::path() const
+{
+ return d->globalPath;
+}
+
+bool GPCamera::thumbnailSupport()
+{
+ return d->thumbnailSupport;
+}
+
+bool GPCamera::deleteSupport()
+{
+ return d->deleteSupport;
+}
+
+bool GPCamera::uploadSupport()
+{
+ return d->uploadSupport;
+}
+
+bool GPCamera::mkDirSupport()
+{
+ return d->mkDirSupport;
+}
+
+bool GPCamera::delDirSupport()
+{
+ return d->delDirSupport;
+}
+
+bool GPCamera::doConnect()
+{
+ int errorCode;
+ // -- first step - setup the camera --------------------
+
+ if (d->camera)
+ {
+ gp_camera_unref(d->camera);
+ d->camera = 0;
+ }
+
+ CameraAbilitiesList *abilList;
+ GPPortInfoList *infoList;
+ GPPortInfo info;
+
+ gp_camera_new(&d->camera);
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus();
+
+ gp_abilities_list_new(&abilList);
+ gp_abilities_list_load(abilList, m_status->context);
+ gp_port_info_list_new(&infoList);
+ gp_port_info_list_load(infoList);
+
+ delete m_status;
+ m_status = 0;
+
+ int modelNum = -1, portNum = -1;
+ modelNum = gp_abilities_list_lookup_model(abilList, d->model.latin1());
+ portNum = gp_port_info_list_lookup_path (infoList, d->port.latin1());
+
+ gp_abilities_list_get_abilities(abilList, modelNum, &d->cameraAbilities);
+
+ errorCode = gp_camera_set_abilities(d->camera, d->cameraAbilities);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to set camera Abilities!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_camera_unref(d->camera);
+ d->camera = 0;
+ gp_abilities_list_free(abilList);
+ gp_port_info_list_free(infoList);
+ return false;
+ }
+
+ if (d->model != "Directory Browse")
+ {
+ gp_port_info_list_get_info(infoList, portNum, &info);
+ errorCode = gp_camera_set_port_info(d->camera, info);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to set camera port!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_camera_unref(d->camera);
+ d->camera = 0;
+ gp_abilities_list_free (abilList);
+ gp_port_info_list_free (infoList);
+ return false;
+ }
+ }
+
+ gp_abilities_list_free (abilList);
+ gp_port_info_list_free (infoList);
+
+ if (d->cameraAbilities.file_operations &
+ GP_FILE_OPERATION_PREVIEW)
+ d->thumbnailSupport = true;
+
+ if (d->cameraAbilities.file_operations &
+ GP_FILE_OPERATION_DELETE)
+ d->deleteSupport = true;
+
+ if (d->cameraAbilities.folder_operations &
+ GP_FOLDER_OPERATION_PUT_FILE)
+ d->uploadSupport = true;
+
+ if (d->cameraAbilities.folder_operations &
+ GP_FOLDER_OPERATION_MAKE_DIR)
+ d->mkDirSupport = true;
+
+ if (d->cameraAbilities.folder_operations &
+ GP_FOLDER_OPERATION_REMOVE_DIR)
+ d->delDirSupport = true;
+
+ // -- Now try to initialize the camera -----------------
+
+ m_status = new GPStatus();
+
+ // Try and initialize the camera to see if its connected
+ errorCode = gp_camera_init(d->camera, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to initialize camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_camera_unref(d->camera);
+ d->camera = 0;
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ d->cameraInitialized = true;
+ return true;
+}
+
+void GPCamera::cancel()
+{
+ if (!m_status)
+ return;
+ m_status->cancel = true;
+}
+
+void GPCamera::getAllFolders(const TQString& rootFolder,
+ TQStringList& folderList)
+{
+ TQStringList subfolders;
+ getSubFolders(rootFolder, subfolders);
+
+ for (TQStringList::iterator it = subfolders.begin();
+ it != subfolders.end(); ++it)
+ {
+ *it = rootFolder + TQString(rootFolder.endsWith("/") ? "" : "/") + (*it);
+ folderList.append(*it);
+ }
+
+ for (TQStringList::iterator it = subfolders.begin();
+ it != subfolders.end(); ++it)
+ {
+ getAllFolders(*it, folderList);
+ }
+}
+
+bool GPCamera::getSubFolders(const TQString& folder, TQStringList& subFolderList)
+{
+ int errorCode;
+ CameraList *clist;
+ gp_list_new(&clist);
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+ m_status = new GPStatus();
+
+ errorCode = gp_camera_folder_list_folders(d->camera, TQFile::encodeName(folder), clist, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get folders list from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_list_unref(clist);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ int count = gp_list_count(clist);
+ for (int i = 0 ; i < count ; i++)
+ {
+ const char* subFolder;
+ errorCode = gp_list_get_name(clist, i, &subFolder);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get folder name from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_list_unref(clist);
+ return false;
+ }
+
+ subFolderList.append(TQFile::decodeName(subFolder));
+ }
+
+ gp_list_unref(clist);
+ return true;
+}
+
+bool GPCamera::getItemsList(const TQString& folder, TQStringList& itemsList)
+{
+ int errorCode;
+ CameraList *clist;
+ const char *cname;
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+ m_status = new GPStatus;
+
+ gp_list_new(&clist);
+
+ errorCode = gp_camera_folder_list_files(d->camera, TQFile::encodeName(folder), clist, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get folder files list from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_list_unref(clist);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ int count = gp_list_count(clist);
+ for (int i = 0 ; i < count ; i++)
+ {
+ errorCode = gp_list_get_name(clist, i, &cname);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get file name from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_list_unref(clist);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ itemsList.append(TQFile::decodeName(cname));
+ }
+
+ gp_list_unref(clist);
+
+ delete m_status;
+ m_status = 0;
+
+ return true;
+}
+
+bool GPCamera::getItemsInfoList(const TQString& folder, GPItemInfoList& items, bool /*getImageDimensions*/)
+{
+ int errorCode;
+ CameraList *clist;
+ const char *cname;
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+ m_status = new GPStatus;
+
+ gp_list_new(&clist);
+
+ errorCode = gp_camera_folder_list_files(d->camera, TQFile::encodeName(folder), clist, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get folder files list from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_list_unref(clist);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ int count = gp_list_count(clist);
+ for (int i = 0 ; i < count ; i++)
+ {
+ errorCode = gp_list_get_name(clist, i, &cname);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get file name from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_list_unref(clist);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ GPItemInfo itemInfo;
+
+ itemInfo.name = TQFile::decodeName(cname);
+ itemInfo.folder = folder;
+
+ CameraFileInfo info;
+ gp_camera_file_get_info(d->camera, TQFile::encodeName(folder),
+ cname, &info, m_status->context);
+
+ itemInfo.mtime = -1;
+ itemInfo.mime = "";
+ itemInfo.size = -1;
+ itemInfo.width = -1;
+ itemInfo.height = -1;
+ itemInfo.downloaded = GPItemInfo::DownloadUnknow;
+ itemInfo.readPermissions = -1;
+ itemInfo.writePermissions = -1;
+
+ /* The mime type returned by Gphoto2 is dummy with all RAW files.
+ if (info.file.fields & GP_FILE_INFO_TYPE)
+ itemInfo.mime = info.file.type;*/
+
+ itemInfo.mime = mimeType(TQString(itemInfo.name.section('.', -1)).lower());
+
+ if (info.file.fields & GP_FILE_INFO_MTIME)
+ itemInfo.mtime = info.file.mtime;
+
+ if (info.file.fields & GP_FILE_INFO_SIZE)
+ itemInfo.size = info.file.size;
+
+ if (info.file.fields & GP_FILE_INFO_WIDTH)
+ itemInfo.width = info.file.width;
+
+ if (info.file.fields & GP_FILE_INFO_HEIGHT)
+ itemInfo.height = info.file.height;
+
+ if (info.file.fields & GP_FILE_INFO_STATUS)
+ {
+ if (info.file.status == GP_FILE_STATUS_DOWNLOADED)
+ itemInfo.downloaded = GPItemInfo::DownloadedYes;
+ }
+
+ if (info.file.fields & GP_FILE_INFO_PERMISSIONS)
+ {
+ if (info.file.permissions & GP_FILE_PERM_READ)
+ itemInfo.readPermissions = 1;
+ else
+ itemInfo.readPermissions = 0;
+ if (info.file.permissions & GP_FILE_PERM_DELETE)
+ itemInfo.writePermissions = 1;
+ else
+ itemInfo.writePermissions = 0;
+ }
+
+ items.append(itemInfo);
+ }
+
+ gp_list_unref(clist);
+
+ delete m_status;
+ m_status = 0;
+
+ return true;
+}
+
+bool GPCamera::getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail)
+{
+ int errorCode;
+ CameraFile *cfile;
+ const char *data;
+ unsigned long int size;
+
+ gp_file_new(&cfile);
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_file_get(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName),
+ GP_FILE_TYPE_PREVIEW,
+ cfile, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ errorCode = gp_file_get_data_and_size(cfile, &data, &size);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get thumbnail from camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ return false;
+ }
+
+ thumbnail.loadFromData((const uchar*) data, (uint) size);
+
+ gp_file_unref(cfile);
+ return true;
+}
+
+bool GPCamera::getExif(const TQString& folder, const TQString& itemName,
+ char **edata, int& esize)
+{
+ int errorCode;
+ CameraFile *cfile;
+ const char *data;
+ unsigned long int size;
+
+ gp_file_new(&cfile);
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_file_get(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName),
+ GP_FILE_TYPE_EXIF,
+ cfile, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ errorCode = gp_file_get_data_and_size(cfile, &data, &size);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get Exif data from camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ return false;
+ }
+
+ *edata = new char[size];
+ esize = size;
+ memcpy(*edata, data, size);
+
+ gp_file_unref(cfile);
+ return true;
+}
+
+bool GPCamera::downloadItem(const TQString& folder, const TQString& itemName,
+ const TQString& saveFile)
+{
+ int errorCode;
+ CameraFile *cfile;
+
+ gp_file_new(&cfile);
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_file_get(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName),
+ GP_FILE_TYPE_NORMAL, cfile,
+ m_status->context);
+ if ( errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ errorCode = gp_file_save(cfile, TQFile::encodeName(saveFile));
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to save camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ return false;
+ }
+
+ gp_file_unref(cfile);
+ return true;
+}
+
+bool GPCamera::setLockItem(const TQString& folder, const TQString& itemName, bool lock)
+{
+ int errorCode;
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ CameraFileInfo info;
+ errorCode = gp_camera_file_get_info(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName), &info, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera item properties!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ if (info.file.fields & GP_FILE_INFO_PERMISSIONS)
+ {
+ if (lock)
+ {
+ // Lock the file to set read only flag
+ info.file.permissions = (CameraFilePermissions)GP_FILE_PERM_READ;
+ }
+ else
+ {
+ // Unlock the file to set read/write flag
+ info.file.permissions = (CameraFilePermissions)(GP_FILE_PERM_READ | GP_FILE_PERM_DELETE);
+ }
+ }
+
+ // Some gphoto2 drivers need to have only the right flag at on to process properties update in camera.
+ info.file.fields = GP_FILE_INFO_PERMISSIONS;
+ info.preview.fields = GP_FILE_INFO_NONE;
+ info.audio.fields = GP_FILE_INFO_NONE;
+
+ errorCode = gp_camera_file_set_info(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName), info, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to set camera item lock properties!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+bool GPCamera::deleteItem(const TQString& folder, const TQString& itemName)
+{
+ int errorCode;
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_file_delete(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName),
+ m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to delete camera item!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ return true;
+}
+
+// recursively delete all items
+bool GPCamera::deleteAllItems(const TQString& folder)
+{
+ int errorCode;
+ TQStringList folderList;
+
+ // Get all subfolders in this folder
+ getSubFolders(folder, folderList);
+
+ if (folderList.count() > 0)
+ {
+ for (unsigned int i = 0 ; i < folderList.count() ; i++)
+ {
+ TQString subFolder(folder);
+
+ if (!subFolder.endsWith("/"))
+ subFolder += '/';
+
+ subFolder += folderList[i];
+ deleteAllItems(subFolder);
+ }
+ }
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_folder_delete_all(d->camera, TQFile::encodeName(folder),
+ m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to delete camera folder!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ delete m_status;
+ m_status = 0;
+
+ return true;
+}
+
+bool GPCamera::uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile,
+ GPItemInfo& itemInfo, bool /*getImageDimensions*/)
+{
+ int errorCode;
+ CameraFile *cfile;
+
+ errorCode = gp_file_new(&cfile);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to init new camera file instance!" << endl;
+ printGphotoErrorDescription(errorCode);
+ return false;
+ }
+
+ errorCode = gp_file_open(cfile, TQFile::encodeName(localFile));
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to open file!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ return false;
+ }
+
+ errorCode = gp_file_set_name(cfile, TQFile::encodeName(itemName));
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to rename item from camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ return false;
+ }
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+#ifdef HAVE_GPHOTO25
+ errorCode = gp_camera_folder_put_file(d->camera,
+ TQFile::encodeName(folder),
+ TQFile::encodeName(itemName),
+ GP_FILE_TYPE_NORMAL,
+ cfile,
+ m_status->context);
+#else
+ errorCode = gp_camera_folder_put_file(d->camera,
+ TQFile::encodeName(folder),
+ cfile,
+ m_status->context);
+#endif
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to upload item to camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ // Get new camera item information.
+
+ itemInfo.name = itemName;
+ itemInfo.folder = folder;
+
+ CameraFileInfo info;
+ errorCode = gp_camera_file_get_info(d->camera, TQFile::encodeName(folder),
+ TQFile::encodeName(itemName), &info, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera item information!" << endl;
+ printGphotoErrorDescription(errorCode);
+ gp_file_unref(cfile);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ itemInfo.mtime = -1;
+ itemInfo.mime = "";
+ itemInfo.size = -1;
+ itemInfo.width = -1;
+ itemInfo.height = -1;
+ itemInfo.downloaded = GPItemInfo::DownloadUnknow;
+ itemInfo.readPermissions = -1;
+ itemInfo.writePermissions = -1;
+
+ /* The mime type returned by Gphoto2 is dummy with all RAW files.
+ if (info.file.fields & GP_FILE_INFO_TYPE)
+ itemInfo.mime = info.file.type;*/
+
+ itemInfo.mime = mimeType(TQString(itemInfo.name.section('.', -1)).lower());
+
+ if (info.file.fields & GP_FILE_INFO_MTIME)
+ itemInfo.mtime = info.file.mtime;
+
+ if (info.file.fields & GP_FILE_INFO_SIZE)
+ itemInfo.size = info.file.size;
+
+ if (info.file.fields & GP_FILE_INFO_WIDTH)
+ itemInfo.width = info.file.width;
+
+ if (info.file.fields & GP_FILE_INFO_HEIGHT)
+ itemInfo.height = info.file.height;
+
+ if (info.file.fields & GP_FILE_INFO_STATUS)
+ {
+ if (info.file.status == GP_FILE_STATUS_DOWNLOADED)
+ itemInfo.downloaded = GPItemInfo::DownloadedYes;
+ else
+ itemInfo.downloaded = GPItemInfo::DownloadedNo;
+ }
+
+ if (info.file.fields & GP_FILE_INFO_PERMISSIONS)
+ {
+ if (info.file.permissions & GP_FILE_PERM_READ)
+ itemInfo.readPermissions = 1;
+ else
+ itemInfo.readPermissions = 0;
+ if (info.file.permissions & GP_FILE_PERM_DELETE)
+ itemInfo.writePermissions = 1;
+ else
+ itemInfo.writePermissions = 0;
+ }
+
+ gp_file_unref(cfile);
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+bool GPCamera::cameraSummary(TQString& summary)
+{
+ int errorCode;
+ CameraText sum;
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_get_summary(d->camera, &sum, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera summary!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ summary = i18n("Title: %1\n"
+ "Model: %2\n"
+ "Port: %3\n"
+ "Path: %4\n\n"
+ "Thumbnails: %5\n"
+ "Delete items: %6\n"
+ "Upload items: %7\n"
+ "Create directories: %8\n"
+ "Delete directories: %9\n\n")
+ .arg(title())
+ .arg(model())
+ .arg(port())
+ .arg(path())
+ .arg(thumbnailSupport() ? i18n("yes") : i18n("no"))
+ .arg(deleteSupport() ? i18n("yes") : i18n("no"))
+ .arg(uploadSupport() ? i18n("yes") : i18n("no"))
+ .arg(mkDirSupport() ? i18n("yes") : i18n("no"))
+ .arg(delDirSupport() ? i18n("yes") : i18n("no"));
+
+ summary.append(TQString(sum.text));
+
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+bool GPCamera::cameraManual(TQString& manual)
+{
+ int errorCode;
+ CameraText man;
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_get_manual(d->camera, &man, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get camera manual!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ manual = TQString(man.text);
+
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+bool GPCamera::cameraAbout(TQString& about)
+{
+ int errorCode;
+ CameraText abt;
+
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_get_about(d->camera, &abt, m_status->context);
+ if (errorCode != GP_OK)
+ {
+ DDebug() << "Failed to get information about camera!" << endl;
+ printGphotoErrorDescription(errorCode);
+ delete m_status;
+ m_status = 0;
+ return false;
+ }
+
+ about = TQString(abt.text);
+ about.append(i18n("\n\nTo report problems about this driver, please contact "
+ "the gphoto2 team at:\n\nhttp://gphoto.org/bugs"));
+
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+// -- Static methods ---------------------------------------------------------------------
+
+void GPCamera::printGphotoErrorDescription(int errorCode)
+{
+ DDebug() << "Libgphoto2 error: " << gp_result_as_string(errorCode)
+ << " (" << errorCode << ")" << endl;
+}
+
+void GPCamera::getSupportedCameras(int& count, TQStringList& clist)
+{
+ clist.clear();
+ count = 0;
+
+ CameraAbilitiesList *abilList;
+ CameraAbilities abil;
+ GPContext *context;
+
+ context = gp_context_new();
+
+ gp_abilities_list_new( &abilList );
+ gp_abilities_list_load( abilList, context );
+
+ count = gp_abilities_list_count( abilList );
+ if ( count < 0 )
+ {
+ DDebug() << "Failed to get list of cameras!" << endl;
+ printGphotoErrorDescription(count);
+ gp_context_unref( context );
+ return;
+ }
+ else
+ {
+ for (int i = 0 ; i < count ; i++)
+ {
+ gp_abilities_list_get_abilities( abilList, i, &abil );
+ const char *cname = abil.model;
+ clist.append( TQString( cname ) );
+ }
+ }
+
+ gp_abilities_list_free( abilList );
+ gp_context_unref( context );
+}
+
+void GPCamera::getSupportedPorts(TQStringList& plist)
+{
+ GPPortInfoList *list;
+ GPPortInfo info;
+
+ plist.clear();
+
+ gp_port_info_list_new( &list );
+ gp_port_info_list_load( list );
+
+ int numPorts = gp_port_info_list_count( list );
+ if ( numPorts < 0)
+ {
+ DDebug() << "Failed to get list of port!" << endl;
+ printGphotoErrorDescription(numPorts);
+ gp_port_info_list_free( list );
+ return;
+ }
+ else
+ {
+ for (int i = 0 ; i < numPorts ; i++)
+ {
+ gp_port_info_list_get_info( list, i, &info );
+#ifdef HAVE_GPHOTO25
+ char *xpath;
+ gp_port_info_get_name( info, &xpath );
+ plist.append( xpath );
+#else
+ plist.append( info.path );
+#endif
+ }
+ }
+
+ gp_port_info_list_free( list );
+}
+
+void GPCamera::getCameraSupportedPorts(const TQString& model, TQStringList& plist)
+{
+ int i = 0;
+ plist.clear();
+
+ CameraAbilities abilities;
+ CameraAbilitiesList *abilList;
+ GPContext *context;
+
+ context = gp_context_new();
+
+ gp_abilities_list_new (&abilList);
+ gp_abilities_list_load (abilList, context);
+ i = gp_abilities_list_lookup_model (abilList, model.local8Bit().data());
+ gp_abilities_list_get_abilities (abilList, i, &abilities);
+ gp_abilities_list_free (abilList);
+
+ if (abilities.port & GP_PORT_SERIAL)
+ plist.append("serial");
+
+ if (abilities.port & GP_PORT_USB)
+ plist.append("usb");
+
+ gp_context_unref( context );
+}
+
+int GPCamera::autoDetect(TQString& model, TQString& port)
+{
+ CameraList *camList;
+ CameraAbilitiesList *abilList;
+ GPPortInfoList *infoList;
+ const char *camModel_, *camPort_;
+ GPContext *context;
+
+ context = gp_context_new();
+ gp_list_new(&camList);
+
+ gp_abilities_list_new(&abilList);
+ gp_abilities_list_load(abilList, context);
+ gp_port_info_list_new(&infoList);
+ gp_port_info_list_load(infoList);
+ gp_abilities_list_detect(abilList, infoList, camList, context);
+ gp_abilities_list_free(abilList);
+ gp_port_info_list_free(infoList);
+
+ gp_context_unref(context);
+
+ int count = gp_list_count(camList);
+
+ if (count <= 0)
+ {
+ DDebug() << "Failed to autodetect camera!" << endl;
+ printGphotoErrorDescription(count);
+ gp_list_free(camList);
+ return -1;
+ }
+
+ camModel_ = 0;
+ camPort_ = 0;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (gp_list_get_name(camList, i, &camModel_) != GP_OK)
+ {
+ DDebug() << "Failed to autodetect camera!" << endl;
+ gp_list_free(camList);
+ return -1;
+ }
+
+ if (gp_list_get_value(camList, i, &camPort_) != GP_OK)
+ {
+ DDebug() << "Failed to autodetect camera!" << endl;
+ gp_list_free(camList);
+ return -1;
+ }
+
+ if (camModel_ && camPort_)
+ {
+ model = TQString::fromLatin1(camModel_);
+ port = TQString::fromLatin1(camPort_);
+ gp_list_free(camList);
+ return 0;
+ }
+ }
+
+ DDebug() << "Failed to autodetect camera!" << endl;
+ gp_list_free(camList);
+ return -1;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/gpcamera.h b/src/utilities/cameragui/gpcamera.h
new file mode 100644
index 00000000..7071e972
--- /dev/null
+++ b/src/utilities/cameragui/gpcamera.h
@@ -0,0 +1,107 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-01-21
+ * Description : Gphoto2 camera interface
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 GPCAMERA_H
+#define GPCAMERA_H
+
+// Local includes.
+
+#include "dkcamera.h"
+
+class TQImage;
+
+namespace Digikam
+{
+
+class GPCameraPrivate;
+class GPStatus;
+
+// Gphoto2 camera Implementation of abstract type DKCamera
+
+class GPCamera : public DKCamera
+{
+
+public:
+
+ GPCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path);
+ ~GPCamera();
+
+ bool thumbnailSupport();
+ bool deleteSupport();
+ bool uploadSupport();
+ bool mkDirSupport();
+ bool delDirSupport();
+
+ bool doConnect();
+
+ void cancel();
+
+ void getAllFolders(const TQString& folder, TQStringList& subFolderList);
+ bool getSubFolders(const TQString& folder, TQStringList& subFolderList);
+ bool getItemsList(const TQString& folder, TQStringList& itemsList);
+ bool getItemsInfoList(const TQString& folder, GPItemInfoList& items, bool getImageDimensions = true);
+ bool getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail);
+ bool getExif(const TQString& folder, const TQString& itemName, char **edata, int& esize);
+
+ bool setLockItem(const TQString& folder, const TQString& itemName, bool lock);
+
+ bool downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile);
+ bool deleteItem(const TQString& folder, const TQString& itemName);
+
+ // recursively delete all items
+ bool deleteAllItems(const TQString& folder);
+
+ bool uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile,
+ GPItemInfo& itemInfo, bool getImageDimensions=true);
+
+ bool cameraSummary(TQString& summary);
+ bool cameraManual(TQString& manual);
+ bool cameraAbout(TQString& about);
+
+ TQString model() const;
+ TQString port() const;
+ TQString path() const;
+
+ // Public static methods shared with Camera Setup
+
+ static int autoDetect(TQString& model, TQString& port);
+ static void getSupportedCameras(int& count, TQStringList& clist);
+ static void getSupportedPorts(TQStringList& plist);
+ static void getCameraSupportedPorts(const TQString& model, TQStringList& plist);
+
+private:
+
+ int setup();
+ static void printGphotoErrorDescription(int errorCode);
+
+private:
+
+ GPCameraPrivate *d;
+ GPStatus *m_status;
+};
+
+} // namespace Digikam
+
+#endif /* GPCAMERA_H */
diff --git a/src/utilities/cameragui/gpiteminfo.cpp b/src/utilities/cameragui/gpiteminfo.cpp
new file mode 100644
index 00000000..3a1d53e1
--- /dev/null
+++ b/src/utilities/cameragui/gpiteminfo.cpp
@@ -0,0 +1,68 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-19
+ * Description : camera item info container
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 <tqdatastream.h>
+
+// Local includes.
+
+#include "gpiteminfo.h"
+
+namespace Digikam
+{
+
+TQDataStream& operator<<( TQDataStream& ds, const GPItemInfo& info)
+{
+ ds << info.name;
+ ds << info.folder;
+ ds << info.mtime;
+ ds << info.mime;
+ ds << info.size;
+ ds << info.width;
+ ds << info.height;
+ ds << info.downloaded;
+ ds << info.readPermissions;
+ ds << info.writePermissions;
+
+ return ds;
+}
+
+TQDataStream& operator>>(TQDataStream& ds, GPItemInfo& info)
+{
+ ds >> info.name;
+ ds >> info.folder;
+ ds >> info.mtime;
+ ds >> info.mime;
+ ds >> info.size;
+ ds >> info.width;
+ ds >> info.height;
+ ds >> info.downloaded;
+ ds >> info.readPermissions;
+ ds >> info.writePermissions;
+
+ return ds;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/gpiteminfo.h b/src/utilities/cameragui/gpiteminfo.h
new file mode 100644
index 00000000..02b28693
--- /dev/null
+++ b/src/utilities/cameragui/gpiteminfo.h
@@ -0,0 +1,80 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-18
+ * Description : camera item info container
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 GPITEMINFO_H
+#define GPITEMINFO_H
+
+// C++ includes.
+
+#include <ctime>
+
+// TQt includes.
+
+#include <tqvaluelist.h>
+#include <tqcstring.h>
+
+class TQDataStream;
+
+namespace Digikam
+{
+
+class GPItemInfo
+{
+
+public:
+
+ enum DownloadStatus
+ {
+ DownloadUnknow = -1,
+ DownloadedNo = 0,
+ DownloadedYes = 1,
+ DownloadFailed = 2,
+ DownloadStarted = 3,
+ NewPicture = 4
+ };
+
+public:
+
+ long size;
+ int width;
+ int height;
+ int downloaded; // See DownloadStatus enum.
+ int readPermissions;
+ int writePermissions;
+
+ TQString name;
+ TQString folder;
+ TQString mime;
+
+ time_t mtime;
+};
+
+TQDataStream& operator<<( TQDataStream &, const GPItemInfo & );
+TQDataStream& operator>>( TQDataStream &, GPItemInfo & );
+
+typedef TQValueList<GPItemInfo> GPItemInfoList;
+
+} // namespace Digikam
+
+#endif /* GPITEMINFO_H */
diff --git a/src/utilities/cameragui/mtqueue.h b/src/utilities/cameragui/mtqueue.h
new file mode 100644
index 00000000..0fb80e5c
--- /dev/null
+++ b/src/utilities/cameragui/mtqueue.h
@@ -0,0 +1,116 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-30
+ * Description : camera download multi-threading handler.
+ *
+ * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+
+ * 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 COMMAND_QUEUE_H
+#define COMMAND_QUEUE_H
+
+// TQt includes.
+
+#include <tqptrqueue.h>
+#include <tqmutex.h>
+
+namespace Digikam
+{
+
+template<class Type> class MTQueue
+{
+
+public:
+
+ MTQueue()
+ {
+ queue_.setAutoDelete(true);
+ }
+
+ ~MTQueue()
+ {
+ flush();
+ }
+
+ bool isEmpty()
+ {
+ mutex_.lock();
+ bool empty = queue_.isEmpty();
+ mutex_.unlock();
+ return empty;
+ }
+
+ void flush()
+ {
+ mutex_.lock();
+ queue_.clear();
+ mutex_.unlock();
+ }
+
+ void enqueue(Type * t)
+ {
+ mutex_.lock();
+ queue_.enqueue(t);
+ mutex_.unlock();
+ }
+
+ Type * dequeue()
+ {
+ mutex_.lock();
+ Type * i = queue_.dequeue();
+ mutex_.unlock();
+ return i;
+ }
+
+ Type * head(bool lock=true)
+ {
+ if (lock)
+ mutex_.lock();
+ Type * i = queue_.head();
+ if (lock)
+ mutex_.unlock();
+ return i;
+ }
+
+ int count()
+ {
+ mutex_.lock();
+ int c = queue_.count();
+ mutex_.unlock();
+ return c;
+ }
+
+ void lock()
+ {
+ mutex_.lock();
+ }
+
+ void unlock()
+ {
+ mutex_.unlock();
+ }
+
+private:
+
+ TQPtrQueue<Type> queue_;
+ TQMutex mutex_;
+};
+
+} // namespace Digikam
+
+#endif // COMMAND_QUEUE_H
diff --git a/src/utilities/cameragui/renamecustomizer.cpp b/src/utilities/cameragui/renamecustomizer.cpp
new file mode 100644
index 00000000..a906ccb1
--- /dev/null
+++ b/src/utilities/cameragui/renamecustomizer.cpp
@@ -0,0 +1,532 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-19
+ * Description : a options group to set renaming files
+ * operations during camera downloading
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 <tqdatetime.h>
+#include <tqlayout.h>
+#include <tqradiobutton.h>
+#include <tqcheckbox.h>
+#include <tqcombobox.h>
+#include <tqhbox.h>
+#include <tqlabel.h>
+#include <tqpushbutton.h>
+#include <tqtimer.h>
+#include <tqwhatsthis.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include <kdialogbase.h>
+#if KDE_IS_VERSION(3,2,0)
+#include <kinputdialog.h>
+#else
+#include <klineeditdlg.h>
+#endif
+
+// Local includes.
+
+#include "renamecustomizer.h"
+#include "renamecustomizer.moc"
+
+namespace Digikam
+{
+
+class RenameCustomizerPriv
+{
+public:
+
+ enum DateFormatOptions
+ {
+ DigikamStandard = 0,
+ IsoDateFormat,
+ TextDateFormat,
+ LocalDateFormat,
+ Advanced
+ };
+
+ RenameCustomizerPriv()
+ {
+ renameDefault = 0;
+ renameCustom = 0;
+ renameDefaultBox = 0;
+ renameCustomBox = 0;
+ renameDefaultCase = 0;
+ renameDefaultCaseType = 0;
+ addDateTimeBox = 0;
+ addCameraNameBox = 0;
+ addSeqNumberBox = 0;
+ changedTimer = 0;
+ renameCustomPrefix = 0;
+ renameCustomSuffix = 0;
+ startIndexLabel = 0;
+ startIndexInput = 0;
+ focusedWidget = 0;
+ dateTimeButton = 0;
+ dateTimeLabel = 0;
+ dateTimeFormat = 0;
+}
+
+ TQWidget *focusedWidget;
+
+ TQString cameraTitle;
+
+ TQRadioButton *renameDefault;
+ TQRadioButton *renameCustom;
+
+ TQGroupBox *renameDefaultBox;
+ TQGroupBox *renameCustomBox;
+
+ TQLabel *renameDefaultCase;
+ TQLabel *startIndexLabel;
+ TQLabel *dateTimeLabel;
+
+ TQComboBox *renameDefaultCaseType;
+ TQComboBox *dateTimeFormat;
+
+ TQCheckBox *addDateTimeBox;
+ TQCheckBox *addCameraNameBox;
+ TQCheckBox *addSeqNumberBox;
+
+ TQPushButton *dateTimeButton;
+ TQString dateTimeFormatString;
+
+ TQTimer *changedTimer;
+
+ KLineEdit *renameCustomPrefix;
+ KLineEdit *renameCustomSuffix;
+
+ KIntNumInput *startIndexInput;
+};
+
+RenameCustomizer::RenameCustomizer(TQWidget* parent, const TQString& cameraTitle)
+ : TQButtonGroup(parent)
+{
+ d = new RenameCustomizerPriv;
+ d->changedTimer = new TQTimer(this);
+ d->cameraTitle = cameraTitle;
+
+ setFrameStyle( TQFrame::NoFrame );
+ setRadioButtonExclusive(true);
+ setColumnLayout(0, TQt::Vertical);
+ TQGridLayout* mainLayout = new TQGridLayout(layout(), 4, 1);
+
+ // ----------------------------------------------------------------
+
+ d->renameDefault = new TQRadioButton(i18n("Camera filenames"), this);
+ TQWhatsThis::add( d->renameDefault, i18n("<p>Turn on this option to use camera "
+ "provided image filenames without modifications."));
+ mainLayout->addMultiCellWidget(d->renameDefault, 0, 0, 0, 1);
+
+ d->renameDefaultBox = new TQGroupBox( this );
+ d->renameDefaultBox->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain);
+ d->renameDefaultBox->setInsideMargin(0);
+ d->renameDefaultBox->setColumnLayout(0, TQt::Vertical);
+
+ d->renameDefaultCase = new TQLabel( i18n("Change case to:"), d->renameDefaultBox );
+ d->renameDefaultCase->setSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Preferred );
+
+ d->renameDefaultCaseType = new TQComboBox( d->renameDefaultBox );
+ d->renameDefaultCaseType->insertItem(i18n("Leave as Is"), 0);
+ d->renameDefaultCaseType->insertItem(i18n("Upper"), 1);
+ d->renameDefaultCaseType->insertItem(i18n("Lower"), 2);
+ d->renameDefaultCaseType->setSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Preferred);
+ TQWhatsThis::add( d->renameDefaultCaseType, i18n("<p>Set the method to use to change the case "
+ "of image filenames."));
+
+ TQHBoxLayout* boxLayout1 = new TQHBoxLayout( d->renameDefaultBox->layout() );
+ boxLayout1->addSpacing( 10 );
+ boxLayout1->addWidget( d->renameDefaultCase );
+ boxLayout1->addWidget( d->renameDefaultCaseType );
+
+ mainLayout->addMultiCellWidget(d->renameDefaultBox, 1, 1, 0, 1);
+
+ // -------------------------------------------------------------
+
+ d->renameCustom = new TQRadioButton(i18n("Customize"), this);
+ mainLayout->addMultiCellWidget(d->renameCustom, 2, 2, 0, 1);
+ TQWhatsThis::add( d->renameCustom, i18n("<p>Turn on this option to customize image filenames "
+ "during download."));
+
+ d->renameCustomBox = new TQGroupBox(this);
+ d->renameCustomBox->setFrameStyle(TQFrame::NoFrame|TQFrame::Plain);
+ d->renameCustomBox->setInsideMargin(0);
+ d->renameCustomBox->setColumnLayout(0, TQt::Vertical);
+
+ TQGridLayout* renameCustomBoxLayout = new TQGridLayout(d->renameCustomBox->layout(),
+ 6, 2, KDialogBase::spacingHint());
+ renameCustomBoxLayout->setColSpacing( 0, 10 );
+
+ TQLabel* prefixLabel = new TQLabel(i18n("Prefix:"), d->renameCustomBox);
+ renameCustomBoxLayout->addMultiCellWidget(prefixLabel, 0, 0, 1, 1);
+ d->renameCustomPrefix = new KLineEdit(d->renameCustomBox);
+ d->focusedWidget = d->renameCustomPrefix;
+ renameCustomBoxLayout->addMultiCellWidget(d->renameCustomPrefix, 0, 0, 2, 2);
+ TQWhatsThis::add( d->renameCustomPrefix, i18n("<p>Set the prefix which will be added to "
+ "image filenames."));
+
+ TQLabel* suffixLabel = new TQLabel(i18n("Suffix:"), d->renameCustomBox);
+ renameCustomBoxLayout->addMultiCellWidget(suffixLabel, 1, 1, 1, 1);
+ d->renameCustomSuffix = new KLineEdit(d->renameCustomBox);
+ renameCustomBoxLayout->addMultiCellWidget(d->renameCustomSuffix, 1, 1, 2, 2);
+ TQWhatsThis::add( d->renameCustomSuffix, i18n("<p>Set the suffix which will be added to "
+ "image filenames."));
+
+ d->addDateTimeBox = new TQCheckBox( i18n("Add Date && Time"), d->renameCustomBox );
+ renameCustomBoxLayout->addMultiCellWidget(d->addDateTimeBox, 2, 2, 1, 2);
+ TQWhatsThis::add( d->addDateTimeBox, i18n("<p>Set this option to add the camera provided date and time."));
+
+ TQWidget *dateTimeWidget = new TQWidget(d->renameCustomBox);
+ d->dateTimeLabel = new TQLabel(i18n("Date format:"), dateTimeWidget);
+ d->dateTimeFormat = new TQComboBox(dateTimeWidget);
+ d->dateTimeFormat->insertItem(i18n("Standard"), RenameCustomizerPriv::DigikamStandard);
+ d->dateTimeFormat->insertItem(i18n("ISO"), RenameCustomizerPriv::IsoDateFormat);
+ d->dateTimeFormat->insertItem(i18n("Full Text"), RenameCustomizerPriv::TextDateFormat);
+ d->dateTimeFormat->insertItem(i18n("Local Settings"), RenameCustomizerPriv::LocalDateFormat);
+ d->dateTimeFormat->insertItem(i18n("Advanced..."), RenameCustomizerPriv::Advanced);
+ TQWhatsThis::add( d->dateTimeFormat, i18n("<p>Select your preferred date format for "
+ "creating new albums. The options available are:</p>"
+ "<p><b>Standard</b>: the date format that has been used as a standard by digiKam. "
+ "E.g.: <i>20060824T142618</i></p>"
+ "<p/><b>ISO</b>: the date format according to ISO 8601 "
+ "(YYYY-MM-DD). E.g.: <i>2006-08-24T14:26:18</i></p>"
+ "<p><b>Full Text</b>: the date format is a user-readable string. "
+ "E.g.: <i>Thu Aug 24 14:26:18 2006</i></p>"
+ "<p><b>Local Settings</b>: the date format depending on TDE control panel settings.</p>"
+ "<p><b>Advanced:</b> allows the user to specify a custom date format.</p>"));
+ d->dateTimeButton = new TQPushButton(SmallIcon("configure"), TQString(), dateTimeWidget);
+ TQSizePolicy policy = d->dateTimeButton->sizePolicy();
+ policy.setHorData(TQSizePolicy::Maximum);
+ d->dateTimeButton->setSizePolicy(policy);
+ TQHBoxLayout *boxLayout2 = new TQHBoxLayout(dateTimeWidget);
+ boxLayout2->addWidget(d->dateTimeLabel);
+ boxLayout2->addWidget(d->dateTimeFormat);
+ boxLayout2->addWidget(d->dateTimeButton);
+ renameCustomBoxLayout->addMultiCellWidget(dateTimeWidget, 3, 3, 1, 2);
+
+ d->addCameraNameBox = new TQCheckBox( i18n("Add Camera Name"), d->renameCustomBox );
+ renameCustomBoxLayout->addMultiCellWidget(d->addCameraNameBox, 4, 4, 1, 2);
+ TQWhatsThis::add( d->addCameraNameBox, i18n("<p>Set this option to add the camera name."));
+
+ d->addSeqNumberBox = new TQCheckBox( i18n("Add Sequence Number"), d->renameCustomBox );
+ renameCustomBoxLayout->addMultiCellWidget(d->addSeqNumberBox, 5, 5, 1, 2);
+ TQWhatsThis::add( d->addSeqNumberBox, i18n("<p>Set this option to add a sequence number "
+ "starting with the index set below."));
+
+ d->startIndexLabel = new TQLabel( i18n("Start Index:"), d->renameCustomBox );
+ d->startIndexInput = new KIntNumInput(1, d->renameCustomBox);
+ d->startIndexInput->setRange(1, 900000, 1, false);
+ TQWhatsThis::add( d->startIndexInput, i18n("<p>Set the starting index value used to rename "
+ "files with a sequence number."));
+
+ renameCustomBoxLayout->addMultiCellWidget(d->startIndexLabel, 6, 6, 1, 1);
+ renameCustomBoxLayout->addMultiCellWidget(d->startIndexInput, 6, 6, 2, 2);
+
+ mainLayout->addMultiCellWidget(d->renameCustomBox, 3, 3, 0, 1);
+ mainLayout->setRowStretch(4, 10);
+
+ // -- setup connections -------------------------------------------------
+
+ connect(this, TQ_SIGNAL(clicked(int)),
+ this, TQ_SLOT(slotRadioButtonClicked(int)));
+
+ connect(d->renameCustomPrefix, TQ_SIGNAL(textChanged(const TQString&)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->renameCustomSuffix, TQ_SIGNAL(textChanged(const TQString&)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->addDateTimeBox, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->addCameraNameBox, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->addSeqNumberBox, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->renameDefaultCaseType, TQ_SIGNAL(activated(const TQString&)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->startIndexInput, TQ_SIGNAL(valueChanged (int)),
+ this, TQ_SLOT(slotRenameOptionsChanged()));
+
+ connect(d->changedTimer, TQ_SIGNAL(timeout()),
+ this, TQ_SIGNAL(signalChanged()));
+
+ connect(d->dateTimeButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotDateTimeButtonClicked()));
+
+ connect(d->dateTimeFormat, TQ_SIGNAL(activated(int)),
+ this, TQ_SLOT(slotDateTimeFormatChanged(int)));
+
+ connect(d->addDateTimeBox, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotDateTimeBoxToggled(bool)));
+
+ // -- initial values ---------------------------------------------------
+
+ readSettings();
+
+ // signal to this not yet connected when readSettings is called? Don't know
+ slotDateTimeBoxToggled(d->addDateTimeBox->isChecked());
+}
+
+RenameCustomizer::~RenameCustomizer()
+{
+ delete d->changedTimer;
+ saveSettings();
+ delete d;
+}
+
+bool RenameCustomizer::useDefault() const
+{
+ return d->renameDefault->isChecked();
+}
+
+int RenameCustomizer::startIndex() const
+{
+ return d->startIndexInput->value();
+}
+
+TQString RenameCustomizer::newName(const TQDateTime &dateTime, int index, const TQString &extension) const
+{
+ if (d->renameDefault->isChecked())
+ return TQString();
+ else
+ {
+ TQString name(d->renameCustomPrefix->text());
+
+ // use the "T" as a delimiter between date and time
+ TQString date;
+ switch (d->dateTimeFormat->currentItem())
+ {
+ case RenameCustomizerPriv::DigikamStandard:
+ date = dateTime.toString("yyyyMMddThhmmss");
+ break;
+ case RenameCustomizerPriv::TextDateFormat:
+ date = dateTime.toString(TQt::TextDate);
+ break;
+ case RenameCustomizerPriv::LocalDateFormat:
+ date = dateTime.toString(TQt::LocalDate);
+ break;
+ case RenameCustomizerPriv::IsoDateFormat:
+ date = dateTime.toString(TQt::ISODate);
+ break;
+ case RenameCustomizerPriv::Advanced:
+ date = dateTime.toString(d->dateTimeFormatString);
+ break;
+ }
+
+ // it seems that TQString::number does not support padding with zeros
+ TQString seq;
+ seq.sprintf("-%06d", index);
+
+ if (d->addDateTimeBox->isChecked())
+ name += date;
+
+ if (d->addSeqNumberBox->isChecked())
+ name += seq;
+
+ if (d->addCameraNameBox->isChecked())
+ name += TQString("-%1").arg(d->cameraTitle.simplifyWhiteSpace().replace(" ", ""));
+
+ name += d->renameCustomSuffix->text();
+ name += extension;
+
+ return name;
+ }
+}
+
+RenameCustomizer::Case RenameCustomizer::changeCase() const
+{
+ RenameCustomizer::Case type = NONE;
+
+ if (d->renameDefaultCaseType->currentItem() == 1)
+ type=UPPER;
+ if (d->renameDefaultCaseType->currentItem() == 2)
+ type=LOWER;
+
+ return type;
+}
+
+void RenameCustomizer::slotRadioButtonClicked(int)
+{
+ TQRadioButton* btn = dynamic_cast<TQRadioButton*>(selected());
+ if (!btn)
+ return;
+
+ d->renameCustomBox->setEnabled( btn != d->renameDefault );
+ d->renameDefaultBox->setEnabled( btn == d->renameDefault );
+ slotRenameOptionsChanged();
+}
+
+void RenameCustomizer::slotRenameOptionsChanged()
+{
+ d->focusedWidget = focusWidget();
+
+ if (d->addSeqNumberBox->isChecked())
+ {
+ d->startIndexInput->setEnabled(true);
+ d->startIndexLabel->setEnabled(true);
+ }
+ else
+ {
+ d->startIndexInput->setEnabled(false);
+ d->startIndexLabel->setEnabled(false);
+ }
+
+ d->changedTimer->start(500, true);
+}
+
+void RenameCustomizer::slotDateTimeBoxToggled(bool on)
+{
+ d->dateTimeLabel->setEnabled(on);
+ d->dateTimeFormat->setEnabled(on);
+ d->dateTimeButton->setEnabled(on
+ && d->dateTimeFormat->currentItem() == RenameCustomizerPriv::Advanced);
+ slotRenameOptionsChanged();
+}
+
+void RenameCustomizer::slotDateTimeFormatChanged(int index)
+{
+ if (index == RenameCustomizerPriv::Advanced)
+ {
+ d->dateTimeButton->setEnabled(true);
+ //d->dateTimeButton->show();
+ //slotDateTimeButtonClicked();
+ }
+ else
+ {
+ d->dateTimeButton->setEnabled(false);
+ //d->dateTimeButton->hide();
+ }
+ slotRenameOptionsChanged();
+}
+
+void RenameCustomizer::slotDateTimeButtonClicked()
+{
+ bool ok;
+ TQString message = i18n("<qt><p>Enter the format for date and time.</p>"
+ "<p>Use <i>dd</i> for the day, "
+ "<i>MM</i> for the month, "
+ "<i>yyyy</i> for the year, "
+ "<i>hh</i> for the hour, "
+ "<i>mm</i> for the minute, "
+ "<i>ss</i> for the second.</p>"
+ "<p>Examples: <i>yyyyMMddThhmmss</i> "
+ "for 20060824T142418,<br>"
+ "<i>yyyy-MM-dd hh:mm:ss</i> "
+ "for 2006-08-24 14:24:18.</p></qt>");
+
+#if KDE_IS_VERSION(3,2,0)
+ TQString newFormat = KInputDialog::getText(i18n("Change Date and Time Format"),
+ message,
+ d->dateTimeFormatString, &ok, this);
+#else
+ TQString newFormat = KLineEditDlg::getText(i18n("Change Date and Time Format"),
+ message,
+ d->dateTimeFormatString, &ok, this);
+#endif
+
+ if (!ok)
+ return;
+
+ d->dateTimeFormatString = newFormat;
+ slotRenameOptionsChanged();
+}
+
+void RenameCustomizer::readSettings()
+{
+ TDEConfig* config = kapp->config();
+
+ config->setGroup("Camera Settings");
+ bool def = config->readBoolEntry("Rename Use Default", true);
+ bool addSeqNumb = config->readBoolEntry("Add Sequence Number", true);
+ bool adddateTime = config->readBoolEntry("Add Date Time", false);
+ bool addCamName = config->readBoolEntry("Add Camera Name", false);
+ int chcaseT = config->readNumEntry("Case Type", NONE);
+ TQString prefix = config->readEntry("Rename Prefix", i18n("photo"));
+ TQString suffix = config->readEntry("Rename Postfix", TQString());
+ int startIndex = config->readNumEntry("Rename Start Index", 1);
+ int dateTime = config->readNumEntry("Date Time Format", RenameCustomizerPriv::IsoDateFormat);
+ TQString format = config->readEntry("Date Time Format String", "yyyyMMddThhmmss");
+
+ if (def)
+ {
+ d->renameDefault->setChecked(true);
+ d->renameCustom->setChecked(false);
+ d->renameCustomBox->setEnabled(false);
+ d->renameDefaultBox->setEnabled(true);
+ }
+ else
+ {
+ d->renameDefault->setChecked(false);
+ d->renameCustom->setChecked(true);
+ d->renameCustomBox->setEnabled(true);
+ d->renameDefaultBox->setEnabled(false);
+ }
+
+ d->addDateTimeBox->setChecked(adddateTime);
+ d->addCameraNameBox->setChecked(addCamName);
+ d->addSeqNumberBox->setChecked(addSeqNumb);
+ d->renameDefaultCaseType->setCurrentItem(chcaseT);
+ d->renameCustomPrefix->setText(prefix);
+ d->renameCustomSuffix->setText(suffix);
+ d->startIndexInput->setValue(startIndex);
+ d->dateTimeFormat->setCurrentItem(dateTime);
+ d->dateTimeFormatString = format;
+ slotRenameOptionsChanged();
+}
+
+void RenameCustomizer::saveSettings()
+{
+ TDEConfig* config = kapp->config();
+
+ config->setGroup("Camera Settings");
+ config->writeEntry("Rename Use Default", d->renameDefault->isChecked());
+ config->writeEntry("Add Camera Name", d->addCameraNameBox->isChecked());
+ config->writeEntry("Add Date Time", d->addDateTimeBox->isChecked());
+ config->writeEntry("Add Sequence Number", d->addSeqNumberBox->isChecked());
+ config->writeEntry("Case Type", d->renameDefaultCaseType->currentItem());
+ config->writeEntry("Rename Prefix", d->renameCustomPrefix->text());
+ config->writeEntry("Rename Suffix", d->renameCustomSuffix->text());
+ config->writeEntry("Rename Start Index", d->startIndexInput->value());
+ config->writeEntry("Date Time Format", d->dateTimeFormat->currentItem());
+ config->writeEntry("Date Time Format String", d->dateTimeFormatString);
+ config->sync();
+}
+
+void RenameCustomizer::restoreFocus()
+{
+ d->focusedWidget->setFocus();
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/cameragui/renamecustomizer.h b/src/utilities/cameragui/renamecustomizer.h
new file mode 100644
index 00000000..47ad925b
--- /dev/null
+++ b/src/utilities/cameragui/renamecustomizer.h
@@ -0,0 +1,91 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-19
+ * Description : a options group to set renaming files
+ * operations during camera downloading
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 RENAMECUSTOMIZER_H
+#define RENAMECUSTOMIZER_H
+
+// TQt includes.
+
+#include <tqbuttongroup.h>
+
+class TQDateTime;
+
+namespace Digikam
+{
+
+class RenameCustomizerPriv;
+
+class RenameCustomizer : public TQButtonGroup
+{
+ TQ_OBJECT
+
+
+public:
+
+ enum Case
+ {
+ NONE = 0,
+ UPPER,
+ LOWER
+ };
+
+ RenameCustomizer(TQWidget* parent, const TQString& cameraTitle);
+ ~RenameCustomizer();
+
+ void setUseDefault(bool val);
+ bool useDefault() const;
+ TQString newName(const TQDateTime &date, int index, const TQString &extension) const;
+ Case changeCase() const;
+ int startIndex() const;
+
+signals:
+
+ void signalChanged();
+
+public slots:
+
+ void restoreFocus();
+
+private:
+
+ void readSettings();
+ void saveSettings();
+
+private slots:
+
+ void slotRadioButtonClicked(int);
+ void slotRenameOptionsChanged();
+ void slotDateTimeBoxToggled(bool);
+ void slotDateTimeFormatChanged(int);
+ void slotDateTimeButtonClicked();
+
+private:
+
+ RenameCustomizerPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* RENAMECUSTOMIZER_H */
diff --git a/src/utilities/cameragui/umscamera.cpp b/src/utilities/cameragui/umscamera.cpp
new file mode 100644
index 00000000..537c29ba
--- /dev/null
+++ b/src/utilities/cameragui/umscamera.cpp
@@ -0,0 +1,519 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-12-21
+ * Description : USB Mass Storage camera interface
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// C Ansi includes.
+
+extern "C"
+{
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <utime.h>
+}
+
+// TQt includes.
+
+#include <tqdir.h>
+#include <tqfileinfo.h>
+#include <tqfile.h>
+#include <tqstringlist.h>
+#include <tqdeepcopy.h>
+#include <tqwmatrix.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <tdefilemetainfo.h>
+
+// LibKDcraw includes.
+
+#include <libkdcraw/kdcraw.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dimg.h"
+#include "dmetadata.h"
+#include "umscamera.h"
+
+namespace Digikam
+{
+
+UMSCamera::UMSCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path)
+ : DKCamera(title, model, port, path)
+{
+ m_cancel = false;
+}
+
+UMSCamera::~UMSCamera()
+{
+}
+
+bool UMSCamera::doConnect()
+{
+ return true;
+}
+
+void UMSCamera::cancel()
+{
+ // set the cancel flag
+ m_cancel = true;
+}
+
+void UMSCamera::getAllFolders(const TQString& folder, TQStringList& subFolderList)
+{
+ m_cancel = false;
+ subFolderList.clear();
+ subFolderList.append(folder);
+ listFolders(folder, subFolderList);
+}
+
+bool UMSCamera::getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions)
+{
+ m_cancel = false;
+ infoList.clear();
+
+ TQDir dir(folder);
+ dir.setFilter(TQDir::Files);
+
+ const TQFileInfoList *list = dir.entryInfoList();
+ if (!list)
+ return false;
+
+ TQFileInfoListIterator it(*list);
+ TQFileInfo *fi;
+ TQFileInfo thmlo, thmup;
+ DMetadata meta;
+
+ while ((fi = it.current()) != 0 && !m_cancel)
+ {
+ ++it;
+
+ TQString mime = mimeType(fi->extension(false).lower());
+
+ if (!mime.isEmpty())
+ {
+ TQSize dims;
+ TQDateTime dt;
+ GPItemInfo info;
+ thmlo.setFile(folder + TQString("/") + fi->baseName() + TQString(".thm"));
+ thmup.setFile(folder + TQString("/") + fi->baseName() + TQString(".THM"));
+
+ if (thmlo.exists())
+ {
+ // Try thumbnail sidecar files with lowercase extension.
+ meta.load(thmlo.filePath());
+ dt = meta.getImageDateTime();
+ dims = meta.getImageDimensions();
+ }
+ else if (thmup.exists())
+ {
+ // Try thumbnail sidecar files with uppercase extension.
+ meta.load(thmup.filePath());
+ dt = meta.getImageDateTime();
+ dims = meta.getImageDimensions();
+ }
+ else if (mime == TQString("image/x-raw"))
+ {
+ // If no thumbnail sidecar file available , try to load image metadata with Raw files.
+ meta.load(fi->filePath());
+ dt = meta.getImageDateTime();
+ dims = meta.getImageDimensions();
+ }
+ else
+ {
+ meta.load(fi->filePath());
+ dt = meta.getImageDateTime();
+ dims = meta.getImageDimensions();
+
+ if (dims.isNull())
+ {
+ // In all others case, try KFileMetaInfo.
+ KFileMetaInfo kmeta(fi->filePath());
+ if (kmeta.isValid())
+ {
+ if (kmeta.containsGroup("Jpeg EXIF Data"))
+ dims = kmeta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
+ else if (kmeta.containsGroup("General"))
+ dims = kmeta.group("General").item("Dimensions").value().toSize();
+ else if (kmeta.containsGroup("Technical"))
+ dims = kmeta.group("Technical").item("Dimensions").value().toSize();
+ }
+ }
+ }
+
+ if (dt.isNull())
+ {
+ // If date is not found in metadata, use file time stamp
+ dt = fi->created();
+ }
+
+ info.name = fi->fileName();
+ info.folder = !folder.endsWith("/") ? folder + TQString("/") : folder;
+ info.mime = mime;
+ info.mtime = dt.toTime_t();
+ info.size = fi->size();
+ info.width = getImageDimensions ? dims.width() : -1;
+ info.height = getImageDimensions ? dims.height() : -1;
+ info.downloaded = GPItemInfo::DownloadUnknow;
+ info.readPermissions = fi->isReadable();
+ info.writePermissions = fi->isWritable();
+
+ infoList.append(info);
+ }
+ }
+
+ return true;
+}
+
+bool UMSCamera::getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail)
+{
+ m_cancel = false;
+
+ // JPEG files: try to get thumbnail from Exif data.
+
+ DMetadata metadata(TQFile::encodeName(folder + TQString("/") + itemName));
+ thumbnail = metadata.getExifThumbnail(true);
+ if (!thumbnail.isNull())
+ return true;
+
+ // RAW files : try to extract embedded thumbnail using dcraw
+
+ KDcrawIface::KDcraw::loadDcrawPreview(thumbnail, TQString(folder + TQString("/") + itemName));
+ if (!thumbnail.isNull())
+ return true;
+
+ // THM files: try to get thumbnail from '.thm' files if we didn't manage to get
+ // thumbnail from Exif. Any cameras provides *.thm files like JPEG files with RAW/video files.
+ // Using this way speed up thumbnailization and limit data transfered between camera and computer.
+ // NOTE: the thumbnail extracted with this method can provide a poor quality preview.
+
+ TQFileInfo fi(folder + TQString("/") + itemName);
+
+ if (thumbnail.load(folder + TQString("/") + fi.baseName() + TQString(".thm"))) // Lowercase
+ {
+ if (!thumbnail.isNull())
+ return true;
+ }
+ else if (thumbnail.load(folder + TQString("/") + fi.baseName() + TQString(".THM"))) // Uppercase
+ {
+ if (!thumbnail.isNull())
+ return true;
+ }
+
+ // Finaly, we trying to get thumbnail using DImg API (slow).
+
+ DImg dimgThumb(TQCString(TQFile::encodeName(folder + TQString("/") + itemName)));
+
+ if (!dimgThumb.isNull())
+ {
+ thumbnail = dimgThumb.copyTQImage();
+ return true;
+ }
+
+ return false;
+}
+
+bool UMSCamera::getExif(const TQString&, const TQString&, char **, int&)
+{
+ // not necessary to implement this. read it directly from the file
+ // (done in camera controller)
+ DWarning() << "exif implemented yet in camera controller" << endl;
+ return false;
+}
+
+bool UMSCamera::downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile)
+{
+ m_cancel = false;
+ TQString src = folder + TQString("/") + itemName;
+ TQString dest = saveFile;
+
+ TQFile sFile(src);
+ TQFile dFile(dest);
+
+ if ( !sFile.open(IO_ReadOnly) )
+ {
+ DWarning() << "Failed to open source file for reading: "
+ << src << endl;
+ return false;
+ }
+
+ if ( !dFile.open(IO_WriteOnly) )
+ {
+ sFile.close();
+ DWarning() << "Failed to open dest file for writing: "
+ << dest << endl;
+ return false;
+ }
+
+ const int MAX_IPC_SIZE = (1024*32);
+ char buffer[MAX_IPC_SIZE];
+
+ TQ_LONG len;
+ while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
+ {
+ if (len == -1 || dFile.writeBlock(buffer, (TQ_ULONG)len) != len)
+ {
+ sFile.close();
+ dFile.close();
+ return false;
+ }
+ }
+
+ sFile.close();
+ dFile.close();
+
+ // set the file modification time of the downloaded file to that
+ // of the original file
+ struct stat st;
+ ::stat(TQFile::encodeName(src), &st);
+
+ struct utimbuf ut;
+ ut.modtime = st.st_mtime;
+ ut.actime = st.st_atime;
+
+ ::utime(TQFile::encodeName(dest), &ut);
+
+ return true;
+}
+
+bool UMSCamera::setLockItem(const TQString& folder, const TQString& itemName, bool lock)
+{
+ TQString src = folder + TQString("/") + itemName;
+
+ if (lock)
+ {
+ // Lock the file to set read only flag
+ if (::chmod(TQFile::encodeName(src), S_IREAD) == -1)
+ return false;
+ }
+ else
+ {
+ // Unlock the file to set read/write flag
+ if (::chmod(TQFile::encodeName(src), S_IREAD | S_IWRITE) == -1)
+ return false;
+ }
+
+ return true;
+}
+
+bool UMSCamera::deleteItem(const TQString& folder, const TQString& itemName)
+{
+ m_cancel = false;
+
+ // Any camera provide THM (thumbnail) file with real image. We need to remove it also.
+
+ TQFileInfo fi(folder + TQString("/") + itemName);
+
+ TQFileInfo thmLo(folder + TQString("/") + fi.baseName() + ".thm"); // Lowercase
+
+ if (thmLo.exists())
+ ::unlink(TQFile::encodeName(thmLo.filePath()));
+
+ TQFileInfo thmUp(folder + TQString("/") + fi.baseName() + ".THM"); // Uppercase
+
+ if (thmUp.exists())
+ ::unlink(TQFile::encodeName(thmUp.filePath()));
+
+ // Remove the real image.
+ return (::unlink(TQFile::encodeName(folder + TQString("/") + itemName)) == 0);
+}
+
+bool UMSCamera::uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile,
+ GPItemInfo& info, bool getImageDimensions)
+{
+ m_cancel = false;
+ TQString dest = folder + TQString("/") + itemName;
+ TQString src = localFile;
+
+ TQFile sFile(src);
+ TQFile dFile(dest);
+
+ if ( !sFile.open(IO_ReadOnly) )
+ {
+ DWarning() << "Failed to open source file for reading: "
+ << src << endl;
+ return false;
+ }
+
+ if ( !dFile.open(IO_WriteOnly) )
+ {
+ sFile.close();
+ DWarning() << "Failed to open dest file for writing: "
+ << dest << endl;
+ return false;
+ }
+
+ const int MAX_IPC_SIZE = (1024*32);
+ char buffer[MAX_IPC_SIZE];
+
+ TQ_LONG len;
+ while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
+ {
+ if (len == -1 || dFile.writeBlock(buffer, (TQ_ULONG)len) == -1)
+ {
+ sFile.close();
+ dFile.close();
+ return false;
+ }
+ }
+
+ sFile.close();
+ dFile.close();
+
+ // set the file modification time of the uploaded file to that
+ // of the original file
+ struct stat st;
+ ::stat(TQFile::encodeName(src), &st);
+
+ struct utimbuf ut;
+ ut.modtime = st.st_mtime;
+ ut.actime = st.st_atime;
+
+ ::utime(TQFile::encodeName(dest), &ut);
+
+ // Get new camera item information.
+
+ DMetadata meta;
+ TQFileInfo fi(dest);
+ TQString mime = mimeType(fi.extension(false).lower());
+
+ if (!mime.isEmpty())
+ {
+ TQSize dims;
+ TQDateTime dt;
+
+ if (mime == TQString("image/x-raw"))
+ {
+ // Try to load image metadata with Raw files.
+ meta.load(fi.filePath());
+ dt = meta.getImageDateTime();
+ dims = meta.getImageDimensions();
+ }
+ else
+ {
+ meta.load(fi.filePath());
+ dt = meta.getImageDateTime();
+ dims = meta.getImageDimensions();
+
+ if (dims.isNull())
+ {
+ // In all others case, try KFileMetaInfo.
+ KFileMetaInfo kmeta(fi.filePath());
+ if (kmeta.isValid())
+ {
+ if (kmeta.containsGroup("Jpeg EXIF Data"))
+ dims = kmeta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
+ else if (kmeta.containsGroup("General"))
+ dims = kmeta.group("General").item("Dimensions").value().toSize();
+ else if (kmeta.containsGroup("Technical"))
+ dims = kmeta.group("Technical").item("Dimensions").value().toSize();
+ }
+ }
+ }
+
+ if (dt.isNull())
+ {
+ // If date is not found in metadata, use file time stamp
+ dt = fi.created();
+ }
+
+ info.name = fi.fileName();
+ info.folder = !folder.endsWith("/") ? folder + TQString("/") : folder;
+ info.mime = mime;
+ info.mtime = dt.toTime_t();
+ info.size = fi.size();
+ info.width = getImageDimensions ? dims.width() : -1;
+ info.height = getImageDimensions ? dims.height() : -1;
+ info.downloaded = GPItemInfo::DownloadUnknow;
+ info.readPermissions = fi.isReadable();
+ info.writePermissions = fi.isWritable();
+ }
+
+ return true;
+}
+
+void UMSCamera::listFolders(const TQString& folder, TQStringList& subFolderList)
+{
+ if (m_cancel)
+ return;
+
+ TQDir dir(folder);
+ dir.setFilter(TQDir::Dirs|TQDir::Executable);
+
+ const TQFileInfoList *list = dir.entryInfoList();
+ if (!list)
+ return;
+
+ TQFileInfoListIterator it( *list );
+ TQFileInfo *fi;
+
+ while ((fi = it.current()) != 0 && !m_cancel)
+ {
+ ++it;
+
+ if (fi->fileName() == "." || fi->fileName() == "..")
+ continue;
+
+ TQString subfolder = folder + TQString(folder.endsWith("/") ? "" : "/") + fi->fileName();
+ subFolderList.append(subfolder);
+ listFolders(subfolder, subFolderList);
+ }
+}
+
+bool UMSCamera::cameraSummary(TQString& summary)
+{
+ summary = TQString(i18n("<b>Mounted Camera</b> driver for USB/IEEE1394 mass storage cameras and "
+ "Flash disk card readers.<br><br>"));
+
+ summary.append(i18n("Title: %1<br>"
+ "Model: %2<br>"
+ "Port: %3<br>"
+ "Path: %4<br>")
+ .arg(title())
+ .arg(model())
+ .arg(port())
+ .arg(path()));
+ return true;
+}
+
+bool UMSCamera::cameraManual(TQString& manual)
+{
+ manual = TQString(i18n("For more information about the <b>Mounted Camera</b> driver, "
+ "please read <b>Supported Digital Still "
+ "Cameras</b> section in the digiKam manual."));
+ return true;
+}
+
+bool UMSCamera::cameraAbout(TQString& about)
+{
+ about = TQString(i18n("The <b>Mounted Camera</b> driver is a simple interface to a camera disk "
+ "mounted locally on your system.<br><br>"
+ "It doesn't use libgphoto2 drivers.<br><br>"
+ "To report any problems with this driver, please contact the digiKam team at:<br><br>"
+ "http://www.digikam.org/?q=contact"));
+ return true;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/cameragui/umscamera.h b/src/utilities/cameragui/umscamera.h
new file mode 100644
index 00000000..697ef615
--- /dev/null
+++ b/src/utilities/cameragui/umscamera.h
@@ -0,0 +1,78 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-12-21
+ * Description : USB Mass Storage camera interface
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 UMSCAMERA_H
+#define UMSCAMERA_H
+
+// TQt includes.
+
+#include <tqstringlist.h>
+
+// Local includes.
+
+#include "dkcamera.h"
+
+namespace Digikam
+{
+
+class UMSCameraPriv;
+
+class UMSCamera : public DKCamera
+{
+public:
+
+ UMSCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path);
+ ~UMSCamera();
+
+ bool doConnect();
+ void cancel();
+
+ void getAllFolders(const TQString& folder, TQStringList& subFolderList);
+ bool getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions=true);
+ bool getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail);
+ bool getExif(const TQString& folder, const TQString& itemName, char **edata, int& esize);
+
+ bool setLockItem(const TQString& folder, const TQString& itemName, bool lock);
+
+ bool downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile);
+ bool deleteItem(const TQString& folder, const TQString& itemName);
+ bool uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile,
+ GPItemInfo& info, bool getImageDimensions=true);
+
+ bool cameraSummary(TQString& summary);
+ bool cameraManual(TQString& manual);
+ bool cameraAbout(TQString& about);
+
+private:
+
+ void listFolders(const TQString& folder, TQStringList& subFolderList);
+
+private:
+
+ bool m_cancel;
+};
+
+} // namespace Digikam
+
+#endif /* UMSCAMERA_H */
diff --git a/src/utilities/hotplug/Makefile.am b/src/utilities/hotplug/Makefile.am
new file mode 100644
index 00000000..b0b9e23a
--- /dev/null
+++ b/src/utilities/hotplug/Makefile.am
@@ -0,0 +1,7 @@
+konqservicemenudir = $(kde_datadir)/konqueror/servicemenus
+konqservicemenu_DATA = digikam-download.desktop digikam-gphoto2-camera.desktop digikam-mount-and-download.desktop
+
+helperdir = $(digikamhelper_dir)
+helper_SCRIPTS = digikam-camera
+
+#EXTRA_DIST = $(servicemenu_DATA) $(helper_SCRIPTS)
diff --git a/src/utilities/hotplug/configure.in.in b/src/utilities/hotplug/configure.in.in
new file mode 100644
index 00000000..b36be1e8
--- /dev/null
+++ b/src/utilities/hotplug/configure.in.in
@@ -0,0 +1,7 @@
+KDE_EXPAND_MAKEVAR(digikamhelper_dir, kde_datadir/digikam/utils)
+AC_SUBST(digikamhelper_dir)
+
+AC_OUTPUT(src/utilities/hotplug/digikam-download.desktop)
+AC_OUTPUT(src/utilities/hotplug/digikam-gphoto2-camera.desktop)
+AC_OUTPUT(src/utilities/hotplug/digikam-mount-and-download.desktop)
+
diff --git a/src/utilities/hotplug/digikam-camera b/src/utilities/hotplug/digikam-camera
new file mode 100755
index 00000000..10b2fe3f
--- /dev/null
+++ b/src/utilities/hotplug/digikam-camera
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+action="$1"; shift;
+
+case "$action" in
+detect)
+ cmdoption=--detect-camera
+ dcopcall=detectCamera
+ ;;
+storage)
+ cmdoption=--download-from
+ dcopcall=downloadFrom
+ args="$@"
+ ;;
+*)
+ echo "${0##*/}: wrong action. Usage"
+ echo " ${0##*/} detect # for gphoto2 supported cameras"
+ echo " ${0##*/} storage <url> # for usbdisk or directries with images"
+ exit 1
+ ;;
+esac
+
+for app in `dcop`; do
+ case "$app" in
+ digikam-*)
+ echo "recycling running $app: $dcopcall $@"
+ if test -z "$args"; then
+ exec dcop "$app" camera "$dcopcall"
+ else
+ exec dcop "$app" camera "$dcopcall" "$args"
+ fi
+ ;;
+ esac
+done;
+echo "starting digikam with $cmdoption $args"
+if test -z "$args"; then
+ exec digikam "$cmdoption"
+else
+ exec digikam "$cmdoption" "$args"
+fi
diff --git a/src/utilities/hotplug/digikam-download.desktop.in b/src/utilities/hotplug/digikam-download.desktop.in
new file mode 100644
index 00000000..55a29fdb
--- /dev/null
+++ b/src/utilities/hotplug/digikam-download.desktop.in
@@ -0,0 +1,27 @@
+[Desktop Action digiKam Download]
+Exec=@digikamhelper_dir@/digikam-camera storage %u
+Icon=digikam
+Name=Download Photos with digiKam
+Name[ca]=Descàrrega de fotos amb el digiKam
+Name[de]=Fotos mit digiKam herunterladen
+Name[es]=Descargar fotos con digiKam
+Name[et]=Fotode allalaadimine digiKamiga
+Name[fi]=Lataa valokuvat digiKamilla
+Name[fr]=Télécharger les photos avec digiKam
+Name[is]=Hala niður myndum með digiKam
+Name[it]=Scarica foto con digiKam
+Name[ja]=digiKam で写真をダウンロード
+Name[nds]=Fotos mit digiKam daalladen
+Name[nl]=Foto's downloaden met digiKam
+Name[pl]=Pobierz zdjęcia programem digiKam
+Name[pt]=Obter Fotografias com o digiKam
+Name[pt_BR]=Obter Fotografias com o digiKam
+Name[sk]=Stiahnuť fotky pomocou digiKam
+Name[sr]=Преузми слике помоћу digiKam-а
+Name[sr@Latn]=Преузми слике помоћу digiKam-а
+Name[sv]=Ladda ner foton med Digikam
+Name[xx]=xxDownload Photos with digiKamxx
+
+[Desktop Entry]
+Actions=digiKam Download
+X-TDE-ServiceTypes=media/removable_mounted,media/camera_mounted
diff --git a/src/utilities/hotplug/digikam-gphoto2-camera.desktop.in b/src/utilities/hotplug/digikam-gphoto2-camera.desktop.in
new file mode 100644
index 00000000..f2c4a42a
--- /dev/null
+++ b/src/utilities/hotplug/digikam-gphoto2-camera.desktop.in
@@ -0,0 +1,27 @@
+[Desktop Action digiKam Detect and Download]
+Exec=@digikamhelper_dir@/digikam-camera detect %u
+Icon=digikam
+Name=digiKam Detect and Download
+Name[ca]=Detecta i descarrega amb el digiKam
+Name[de]=Finden und Herunterladen mit digiKam
+Name[es]=Detectar y descargar con digiKam
+Name[et]=*Fotode tuvastamine ja allalaadimine digiKamiga
+Name[fi]=Tunnista kamera ja lataa kuvat digiKamilla
+Name[fr]=Détecter et télécharger avec digiKam
+Name[is]=digiKam Finna og Niðurhala
+Name[it]=Rileva e scarica con digiKam
+Name[ja]=digiKam 検出とダウンロード
+Name[nds]=digiKam - Opdecken un daalladen
+Name[nl]=digiKam-detectie en download
+Name[pl]=Wykrycie i pobieranie digiKamem
+Name[pt]=Detectar e Transferir com o digiKam
+Name[pt_BR]=Detectar e Transferir com o digiKam
+Name[sk]=digiKam Nájsť a stiahnuť
+Name[sr]=digiKam-ово Препознај и преузми
+Name[sr@Latn]=digiKam-ово Препознај и преузми
+Name[sv]=Digikam detektering och nerladdning
+Name[xx]=xxdigiKam Detect and Downloadxx
+
+[Desktop Entry]
+Actions=digiKam Detect and Download
+X-TDE-ServiceTypes=media/gphoto2camera
diff --git a/src/utilities/hotplug/digikam-mount-and-download.desktop.in b/src/utilities/hotplug/digikam-mount-and-download.desktop.in
new file mode 100644
index 00000000..2b773a15
--- /dev/null
+++ b/src/utilities/hotplug/digikam-mount-and-download.desktop.in
@@ -0,0 +1,27 @@
+[Desktop Action digiKam Mount and Download]
+Exec=@digikamhelper_dir@/digikam-camera storage %u
+Icon=digikam
+Name=Download Photos with digiKam
+Name[ca]=Descàrrega de fotos amb el digiKam
+Name[de]=Fotos mit digiKam herunterladen
+Name[es]=Descargar fotos con digiKam
+Name[et]=Fotode allalaadimine digiKamiga
+Name[fi]=Lataa valokuvat digiKamilla
+Name[fr]=Télécharger les photos avec digiKam
+Name[is]=Hala niður myndum með digiKam
+Name[it]=Scarica foto con digiKam
+Name[ja]=digiKam で写真をダウンロード
+Name[nds]=Fotos mit digiKam daalladen
+Name[nl]=Foto's downloaden met digiKam
+Name[pl]=Pobierz zdjęcia programem digiKam
+Name[pt]=Obter Fotografias com o digiKam
+Name[pt_BR]=Obter Fotografias com o digiKam
+Name[sk]=Stiahnuť fotky pomocou digiKam
+Name[sr]=Преузми слике помоћу digiKam-а
+Name[sr@Latn]=Преузми слике помоћу digiKam-а
+Name[sv]=Ladda ner foton med Digikam
+Name[xx]=xxDownload Photos with digiKamxx
+
+[Desktop Entry]
+Actions=digiKam Mount and Download
+X-TDE-ServiceTypes=media/removable_unmounted,media/camera_unmounted
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>&amp;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>&amp;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>&amp;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>&amp;Color</text>
+ </Menu>
+
+ <Menu name="Enhance" ><text>Enh&amp;ance</text>
+ </Menu>
+
+ <Menu name="Transform" ><text>Tra&amp;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>&amp;Decorate</text>
+ </Menu>
+
+ <Menu name="Filters" ><text>F&amp;ilters</text>
+ </Menu>
+
+ <Menu name="help" ><text>&amp;Help</text>
+ <Action name="editorwindow_rawcameralist"/>
+ <Action name="editorwindow_donatemoney" />
+ <Action name="editorwindow_contribute" />
+ </Menu>
+
+ <Merge/>
+
+ <Menu name="settings" noMerge="1"><Text>&amp;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 */
diff --git a/src/utilities/lighttable/Makefile.am b/src/utilities/lighttable/Makefile.am
new file mode 100644
index 00000000..df38b5f9
--- /dev/null
+++ b/src/utilities/lighttable/Makefile.am
@@ -0,0 +1,28 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/src/digikam \
+ -I$(top_srcdir)/src/libs/widgets/common \
+ -I$(top_srcdir)/src/libs/dialogs \
+ -I$(top_srcdir)/src/libs/thumbbar \
+ -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/editor \
+ -I$(top_builddir)/src/libs/dialogs \
+ $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes)
+
+noinst_LTLIBRARIES = liblighttable.la
+
+liblighttable_la_SOURCES = lighttablebar.cpp lighttablewindow.cpp lighttablepreview.cpp \
+ lighttableview.cpp
+
+liblighttable_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
+rcdir = $(kde_datadir)/digikam
+rc_DATA = lighttablewindowui.rc
diff --git a/src/utilities/lighttable/lighttablebar.cpp b/src/utilities/lighttable/lighttablebar.cpp
new file mode 100644
index 00000000..cfb935ab
--- /dev/null
+++ b/src/utilities/lighttable/lighttablebar.cpp
@@ -0,0 +1,881 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-04-11
+ * Description : light table thumbs bar
+ *
+ * Copyright (C) 2007-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 <tqpixmap.h>
+#include <tqpainter.h>
+#include <tqimage.h>
+#include <tqcursor.h>
+
+// KDE includes.
+
+#include <tdeglobal.h>
+#include <kiconloader.h>
+#include <tdelocale.h>
+#include <tdepopupmenu.h>
+#include <kstandarddirs.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "album.h"
+#include "albumdb.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "dragobjects.h"
+#include "imageattributeswatch.h"
+#include "metadatahub.h"
+#include "ratingpopupmenu.h"
+#include "themeengine.h"
+#include "lighttablebar.h"
+#include "lighttablebar.moc"
+
+namespace Digikam
+{
+
+class LightTableBarPriv
+{
+
+public:
+
+ LightTableBarPriv()
+ {
+ navigateByPair = false;
+ toolTip = 0;
+ }
+
+ bool navigateByPair;
+
+ TQPixmap ratingPixmap;
+
+ LightTableBarToolTip *toolTip;
+};
+
+class LightTableBarItemPriv
+{
+
+public:
+
+ LightTableBarItemPriv()
+ {
+ onLeftPanel = false;
+ onRightPanel = false;
+ info = 0;
+ }
+
+ bool onLeftPanel;
+ bool onRightPanel;
+
+ ImageInfo *info;
+};
+
+LightTableBar::LightTableBar(TQWidget* parent, int orientation, bool exifRotate)
+ : ThumbBarView(parent, orientation, exifRotate)
+{
+ d = new LightTableBarPriv;
+ setMouseTracking(true);
+ readToolTipSettings();
+ d->toolTip = new LightTableBarToolTip(this);
+
+ // -- Load rating Pixmap ------------------------------------------
+
+ TDEGlobal::dirs()->addResourceType("digikam_rating", TDEGlobal::dirs()->kde_default("data")
+ + "digikam/data");
+ TQString ratingPixPath = TDEGlobal::dirs()->findResourceDir("digikam_rating", "rating.png");
+ ratingPixPath += "/rating.png";
+ d->ratingPixmap = TQPixmap(ratingPixPath);
+
+ TQPainter painter(&d->ratingPixmap);
+ painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(),
+ ThemeEngine::instance()->textSpecialRegColor());
+ painter.end();
+
+ if (orientation ==TQt::Vertical)
+ setMinimumWidth(d->ratingPixmap.width()*5 + 6 + 2*getMargin());
+ else
+ setMinimumHeight(d->ratingPixmap.width()*5 + 6 + 2*getMargin());
+
+ // ----------------------------------------------------------------
+
+ ImageAttributesWatch *watch = ImageAttributesWatch::instance();
+
+ connect(watch, TQ_SIGNAL(signalImageRatingChanged(TQ_LLONG)),
+ this, TQ_SLOT(slotImageRatingChanged(TQ_LLONG)));
+
+ connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()),
+ this, TQ_SLOT(slotThemeChanged()));
+
+ connect(this, TQ_SIGNAL(signalItemSelected(ThumbBarItem*)),
+ this, TQ_SLOT(slotItemSelected(ThumbBarItem*)));
+}
+
+LightTableBar::~LightTableBar()
+{
+ delete d->toolTip;
+ delete d;
+}
+
+void LightTableBar::setNavigateByPair(bool b)
+{
+ d->navigateByPair = b;
+}
+
+void LightTableBar::slotImageRatingChanged(TQ_LLONG imageId)
+{
+ for (ThumbBarItem *item = firstItem(); item; item = item->next())
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ if (ltItem->info()->id() == imageId)
+ {
+ triggerUpdate();
+ return;
+ }
+ }
+}
+
+void LightTableBar::contentsMouseReleaseEvent(TQMouseEvent *e)
+{
+ if (!e) return;
+
+ ThumbBarView::contentsMouseReleaseEvent(e);
+
+ TQPoint pos = TQCursor::pos();
+ LightTableBarItem *item = findItemByPos(e->pos());
+
+ RatingPopupMenu *ratingMenu = 0;
+
+ if (e->button() == TQt::RightButton)
+ {
+ TDEPopupMenu popmenu(this);
+
+ if (item)
+ {
+ popmenu.insertItem(SmallIcon("go-previous"), i18n("Show on left panel"), 10);
+ popmenu.insertItem(SmallIcon("go-next"), i18n("Show on right panel"), 11);
+ popmenu.insertItem(SmallIcon("editimage"), i18n("Edit"), 12);
+
+ if (d->navigateByPair)
+ {
+ popmenu.setItemEnabled(10, false);
+ popmenu.setItemEnabled(11, false);
+ }
+
+ popmenu.insertSeparator();
+ popmenu.insertItem(SmallIcon("window-close"), i18n("Remove item"), 13);
+ }
+
+ int totalItems = itemsURLs().count();
+ popmenu.insertItem(SmallIcon("editshred"), i18n("Clear all"), 14);
+ popmenu.setItemEnabled(14, totalItems ? true : false);
+
+ if (item)
+ {
+ popmenu.insertSeparator();
+
+ // Assign Star Rating -------------------------------------------
+
+ ratingMenu = new RatingPopupMenu();
+
+ connect(ratingMenu, TQ_SIGNAL(activated(int)),
+ this, TQ_SLOT(slotAssignRating(int)));
+
+ popmenu.insertItem(i18n("Assign Rating"), ratingMenu);
+ }
+
+ switch(popmenu.exec(pos))
+ {
+ case 10: // Left panel
+ {
+ emit signalSetItemOnLeftPanel(item->info());
+ break;
+ }
+ case 11: // Right panel
+ {
+ emit signalSetItemOnRightPanel(item->info());
+ break;
+ }
+ case 12: // Edit
+ {
+ emit signalEditItem(item->info());
+ break;
+ }
+ case 13: // Remove
+ {
+ emit signalRemoveItem(item->info());
+ break;
+ }
+ case 14: // Clear All
+ {
+ emit signalClearAll();
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ delete ratingMenu;
+}
+
+void LightTableBar::slotAssignRating(int rating)
+{
+ rating = TQMIN(5, TQMAX(0, rating));
+ ImageInfo *info = currentItemImageInfo();
+ if (info)
+ {
+ MetadataHub hub;
+ hub.load(info);
+ hub.setRating(rating);
+ hub.write(info, MetadataHub::PartialWrite);
+ hub.write(info->filePath(), MetadataHub::FullWriteIfChanged);
+ }
+}
+
+void LightTableBar::slotAssignRatingNoStar()
+{
+ slotAssignRating(0);
+}
+
+void LightTableBar::slotAssignRatingOneStar()
+{
+ slotAssignRating(1);
+}
+
+void LightTableBar::slotAssignRatingTwoStar()
+{
+ slotAssignRating(2);
+}
+
+void LightTableBar::slotAssignRatingThreeStar()
+{
+ slotAssignRating(3);
+}
+
+void LightTableBar::slotAssignRatingFourStar()
+{
+ slotAssignRating(4);
+}
+
+void LightTableBar::slotAssignRatingFiveStar()
+{
+ slotAssignRating(5);
+}
+
+void LightTableBar::setOnLeftPanel(const ImageInfo* info)
+{
+ for (ThumbBarItem *item = firstItem(); item; item = item->next())
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ if (ltItem)
+ {
+ if (info)
+ {
+ if (ltItem->info()->id() == info->id())
+ {
+ ltItem->setOnLeftPanel(true);
+ repaintItem(item);
+ }
+ else if (ltItem->isOnLeftPanel() == true)
+ {
+ ltItem->setOnLeftPanel(false);
+ repaintItem(item);
+ }
+ }
+ else if (ltItem->isOnLeftPanel() == true)
+ {
+ ltItem->setOnLeftPanel(false);
+ repaintItem(item);
+ }
+ }
+ }
+}
+
+void LightTableBar::setOnRightPanel(const ImageInfo* info)
+{
+ for (ThumbBarItem *item = firstItem(); item; item = item->next())
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ if (ltItem)
+ {
+ if (info)
+ {
+ if (ltItem->info()->id() == info->id())
+ {
+ ltItem->setOnRightPanel(true);
+ repaintItem(item);
+ }
+ else if (ltItem->isOnRightPanel() == true)
+ {
+ ltItem->setOnRightPanel(false);
+ repaintItem(item);
+ }
+ }
+ else if (ltItem->isOnRightPanel() == true)
+ {
+ ltItem->setOnRightPanel(false);
+ repaintItem(item);
+ }
+ }
+ }
+}
+
+void LightTableBar::slotItemSelected(ThumbBarItem* item)
+{
+ if (item)
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ if (ltItem)
+ {
+ emit signalLightTableBarItemSelected(ltItem->info());
+ return;
+ }
+ }
+
+ emit signalLightTableBarItemSelected(0);
+}
+
+ImageInfo* LightTableBar::currentItemImageInfo() const
+{
+ if (currentItem())
+ {
+ LightTableBarItem *item = dynamic_cast<LightTableBarItem*>(currentItem());
+ return item->info();
+ }
+
+ return 0;
+}
+
+ImageInfoList LightTableBar::itemsImageInfoList()
+{
+ ImageInfoList list;
+
+ for (ThumbBarItem *item = firstItem(); item; item = item->next())
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ if (ltItem)
+ {
+ ImageInfo *info = new ImageInfo(*(ltItem->info()));
+ list.append(info);
+ }
+ }
+
+ return list;
+}
+
+void LightTableBar::setSelectedItem(LightTableBarItem* ltItem)
+{
+ ThumbBarItem *item = static_cast<ThumbBarItem*>(ltItem);
+ if (item) ThumbBarView::setSelected(item);
+}
+
+void LightTableBar::removeItem(const ImageInfo* info)
+{
+ if (!info) return;
+
+ LightTableBarItem* ltItem = findItemByInfo(info);
+ ThumbBarItem *item = static_cast<ThumbBarItem*>(ltItem);
+ if (item) ThumbBarView::removeItem(item);
+}
+
+LightTableBarItem* LightTableBar::findItemByInfo(const ImageInfo* info) const
+{
+ if (info)
+ {
+ for (ThumbBarItem *item = firstItem(); item; item = item->next())
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ if (ltItem)
+ {
+ if (ltItem->info()->id() == info->id())
+ return ltItem;
+ }
+ }
+ }
+ return 0;
+}
+
+LightTableBarItem* LightTableBar::findItemByPos(const TQPoint& pos) const
+{
+ ThumbBarItem *item = findItem(pos);
+ if (item)
+ {
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+ return ltItem;
+ }
+
+ return 0;
+}
+
+void LightTableBar::readToolTipSettings()
+{
+ AlbumSettings* albumSettings = AlbumSettings::instance();
+ if (!albumSettings) return;
+
+ Digikam::ThumbBarToolTipSettings settings;
+ settings.showToolTips = albumSettings->getShowToolTips();
+ settings.showFileName = albumSettings->getToolTipsShowFileName();
+ settings.showFileDate = albumSettings->getToolTipsShowFileDate();
+ settings.showFileSize = albumSettings->getToolTipsShowFileSize();
+ settings.showImageType = albumSettings->getToolTipsShowImageType();
+ settings.showImageDim = albumSettings->getToolTipsShowImageDim();
+ settings.showPhotoMake = albumSettings->getToolTipsShowPhotoMake();
+ settings.showPhotoDate = albumSettings->getToolTipsShowPhotoDate();
+ settings.showPhotoFocal = albumSettings->getToolTipsShowPhotoFocal();
+ settings.showPhotoExpo = albumSettings->getToolTipsShowPhotoExpo();
+ settings.showPhotoMode = albumSettings->getToolTipsShowPhotoMode();
+ settings.showPhotoFlash = albumSettings->getToolTipsShowPhotoFlash();
+ settings.showPhotoWB = albumSettings->getToolTipsShowPhotoWB();
+ setToolTipSettings(settings);
+}
+
+void LightTableBar::viewportPaintEvent(TQPaintEvent* e)
+{
+ ThemeEngine* te = ThemeEngine::instance();
+ TQRect er(e->rect());
+ TQPixmap bgPix;
+
+ if (countItems() > 0)
+ {
+ int cy, cx, ts, y1, y2, x1, x2;
+ TQPixmap tile;
+
+ if (getOrientation() ==TQt::Vertical)
+ {
+ cy = viewportToContents(er.topLeft()).y();
+
+ bgPix.resize(contentsRect().width(), er.height());
+
+ ts = getTileSize() + 2*getMargin();
+ tile.resize(visibleWidth(), ts);
+
+ y1 = (cy/ts)*ts;
+ y2 = ((y1 + er.height())/ts +1)*ts;
+ }
+ else
+ {
+ cx = viewportToContents(er.topLeft()).x();
+
+ bgPix.resize(er.width(), contentsRect().height());
+
+ ts = getTileSize() + 2*getMargin();
+ tile.resize(ts, visibleHeight());
+
+ x1 = (cx/ts)*ts;
+ x2 = ((x1 + er.width())/ts +1)*ts;
+ }
+
+ bgPix.fill(te->baseColor());
+
+ for (ThumbBarItem *item = firstItem(); item; item = item->next())
+ {
+ if (getOrientation() ==TQt::Vertical)
+ {
+ if (y1 <= item->position() && item->position() <= y2)
+ {
+ if (item == currentItem())
+ tile = te->thumbSelPixmap(tile.width(), tile.height());
+ else
+ tile = te->thumbRegPixmap(tile.width(), tile.height());
+
+ TQPainter p(&tile);
+ if (item == currentItem())
+ {
+ p.setPen(TQPen(te->textSelColor(), 3));
+ p.drawRect(2, 2, tile.width()-2, tile.height()-2);
+ }
+ else
+ {
+ p.setPen(TQPen(te->textRegColor(), 1));
+ p.drawRect(0, 0, tile.width(), tile.height());
+ }
+ p.end();
+
+ if (item->pixmap())
+ {
+ TQPixmap pix;
+ pix.convertFromImage(TQImage(item->pixmap()->convertToImage()).
+ smoothScale(getTileSize(), getTileSize(), TQImage::ScaleMin));
+ int x = (tile.width() - pix.width())/2;
+ int y = (tile.height() - pix.height())/2;
+ bitBlt(&tile, x, y, &pix);
+
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+
+ if (ltItem->isOnLeftPanel())
+ {
+ TQPixmap lPix = SmallIcon("go-previous");
+ bitBlt(&tile, getMargin(), getMargin(), &lPix);
+ }
+ if (ltItem->isOnRightPanel())
+ {
+ TQPixmap rPix = SmallIcon("go-next");
+ bitBlt(&tile, tile.width() - getMargin() - rPix.width(), getMargin(), &rPix);
+ }
+
+ TQRect r(0, tile.height()-getMargin()-d->ratingPixmap.height(),
+ tile.width(), d->ratingPixmap.height());
+ int rating = ltItem->info()->rating();
+ int xr = (r.width() - rating * d->ratingPixmap.width())/2;
+ int wr = rating * d->ratingPixmap.width();
+ TQPainter p(&tile);
+ p.drawTiledPixmap(xr, r.y(), wr, r.height(), d->ratingPixmap);
+ }
+
+ bitBlt(&bgPix, 0, item->position() - cy, &tile);
+ }
+ }
+ else
+ {
+ if (x1 <= item->position() && item->position() <= x2)
+ {
+ if (item == currentItem())
+ tile = te->thumbSelPixmap(tile.width(), tile.height());
+ else
+ tile = te->thumbRegPixmap(tile.width(), tile.height());
+
+ TQPainter p(&tile);
+ if (item == currentItem())
+ {
+ p.setPen(TQPen(te->textSelColor(), 2));
+ p.drawRect(1, 1, tile.width()-1, tile.height()-1);
+ }
+ else
+ {
+ p.setPen(TQPen(te->textRegColor(), 1));
+ p.drawRect(0, 0, tile.width(), tile.height());
+ }
+ p.end();
+
+ if (item->pixmap())
+ {
+ TQPixmap pix;
+ pix.convertFromImage(TQImage(item->pixmap()->convertToImage()).
+ smoothScale(getTileSize(), getTileSize(), TQImage::ScaleMin));
+ int x = (tile.width() - pix.width())/2;
+ int y = (tile.height()- pix.height())/2;
+ bitBlt(&tile, x, y, &pix);
+
+ LightTableBarItem *ltItem = dynamic_cast<LightTableBarItem*>(item);
+
+ if (ltItem->isOnLeftPanel())
+ {
+ TQPixmap lPix = SmallIcon("go-previous");
+ bitBlt(&tile, getMargin(), getMargin(), &lPix);
+ }
+ if (ltItem->isOnRightPanel())
+ {
+ TQPixmap rPix = SmallIcon("go-next");
+ bitBlt(&tile, tile.width() - getMargin() - rPix.width(), getMargin(), &rPix);
+ }
+
+ TQRect r(0, tile.height()-getMargin()-d->ratingPixmap.height(),
+ tile.width(), d->ratingPixmap.height());
+ int rating = ltItem->info()->rating();
+ int xr = (r.width() - rating * d->ratingPixmap.width())/2;
+ int wr = rating * d->ratingPixmap.width();
+ TQPainter p(&tile);
+ p.drawTiledPixmap(xr, r.y(), wr, r.height(), d->ratingPixmap);
+ }
+
+ bitBlt(&bgPix, item->position() - cx, 0, &tile);
+ }
+ }
+ }
+
+ if (getOrientation() ==TQt::Vertical)
+ bitBlt(viewport(), 0, er.y(), &bgPix);
+ else
+ bitBlt(viewport(), er.x(), 0, &bgPix);
+ }
+ else
+ {
+ bgPix.resize(contentsRect().width(), contentsRect().height());
+ bgPix.fill(te->baseColor());
+ TQPainter p(&bgPix);
+ p.setPen(TQPen(te->textRegColor()));
+ p.drawText(0, 0, bgPix.width(), bgPix.height(),
+ TQt::AlignCenter|TQt::WordBreak,
+ i18n("Drag and drop images here"));
+ p.end();
+ bitBlt(viewport(), 0, 0, &bgPix);
+ }
+}
+
+void LightTableBar::startDrag()
+{
+ if (!currentItem()) return;
+
+ KURL::List urls;
+ KURL::List kioURLs;
+ TQValueList<int> albumIDs;
+ TQValueList<int> imageIDs;
+
+ LightTableBarItem *item = dynamic_cast<LightTableBarItem*>(currentItem());
+
+ urls.append(item->info()->kurl());
+ kioURLs.append(item->info()->kurlForKIO());
+ imageIDs.append(item->info()->id());
+ albumIDs.append(item->info()->albumID());
+
+ TQPixmap icon(DesktopIcon("image-x-generic", 48));
+ int w = icon.width();
+ int h = icon.height();
+
+ TQPixmap pix(w+4,h+4);
+ TQPainter p(&pix);
+ p.fillRect(0, 0, w+4, h+4, TQColor(TQt::white));
+ p.setPen(TQPen(TQt::black, 1));
+ p.drawRect(0, 0, w+4, h+4);
+ p.drawPixmap(2, 2, icon);
+ p.end();
+
+ TQDragObject* drag = 0;
+
+ drag = new ItemDrag(urls, kioURLs, albumIDs, imageIDs, this);
+ if (drag)
+ {
+ drag->setPixmap(pix);
+ drag->drag();
+ }
+}
+
+void LightTableBar::contentsDragMoveEvent(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 LightTableBar::contentsDropEvent(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);
+ if (!findItemByInfo(info))
+ {
+ imageInfoList.append(info);
+ }
+ else
+ {
+ delete info;
+ }
+ }
+
+ emit signalDroppedItems(imageInfoList);
+ e->accept();
+ }
+ else if (AlbumDrag::decode(e, urls, albumID))
+ {
+ TQValueList<TQ_LLONG> itemIDs = AlbumManager::instance()->albumDB()->getItemIDsInAlbum(albumID);
+ ImageInfoList imageInfoList;
+
+ for (TQValueList<TQ_LLONG>::const_iterator it = itemIDs.begin();
+ it != itemIDs.end(); ++it)
+ {
+ ImageInfo *info = new ImageInfo(*it);
+ if (!findItemByInfo(info))
+ {
+ imageInfoList.append(info);
+ }
+ else
+ {
+ delete info;
+ }
+ }
+
+ emit signalDroppedItems(imageInfoList);
+ 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);
+ if (!findItemByInfo(info))
+ {
+ imageInfoList.append(info);
+ }
+ else
+ {
+ delete info;
+ }
+ }
+
+ emit signalDroppedItems(imageInfoList);
+ e->accept();
+ }
+ else
+ {
+ e->ignore();
+ }
+}
+
+void LightTableBar::slotThemeChanged()
+{
+ TDEGlobal::dirs()->addResourceType("digikam_rating", TDEGlobal::dirs()->kde_default("data")
+ + "digikam/data");
+ TQString ratingPixPath = TDEGlobal::dirs()->findResourceDir("digikam_rating", "rating.png");
+ ratingPixPath += "/rating.png";
+ d->ratingPixmap = TQPixmap(ratingPixPath);
+
+ TQPainter painter(&d->ratingPixmap);
+ painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(),
+ ThemeEngine::instance()->textSpecialRegColor());
+ painter.end();
+
+ slotUpdate();
+}
+
+// -------------------------------------------------------------------------
+
+LightTableBarItem::LightTableBarItem(LightTableBar *view, ImageInfo *info)
+ : ThumbBarItem(view, info->kurl())
+{
+ d = new LightTableBarItemPriv;
+ d->info = info;
+}
+
+LightTableBarItem::~LightTableBarItem()
+{
+ delete d;
+}
+
+ImageInfo* LightTableBarItem::info() const
+{
+ return d->info;
+}
+
+void LightTableBarItem::setOnLeftPanel(bool on)
+{
+ d->onLeftPanel = on;
+}
+
+void LightTableBarItem::setOnRightPanel(bool on)
+{
+ d->onRightPanel = on;
+}
+
+bool LightTableBarItem::isOnLeftPanel() const
+{
+ return d->onLeftPanel;
+}
+
+bool LightTableBarItem::isOnRightPanel() const
+{
+ return d->onRightPanel;
+}
+
+// -------------------------------------------------------------------------
+
+LightTableBarToolTip::LightTableBarToolTip(ThumbBarView *parent)
+ : ThumbBarToolTip(parent)
+{
+}
+
+TQString LightTableBarToolTip::tipContentExtraData(ThumbBarItem *item)
+{
+ TQString tip, str;
+ AlbumSettings* settings = AlbumSettings::instance();
+ ImageInfo* info = static_cast<LightTableBarItem *>(item)->info();
+
+ if (settings)
+ {
+ if (settings->getToolTipsShowAlbumName() ||
+ settings->getToolTipsShowComments() ||
+ settings->getToolTipsShowTags() ||
+ settings->getToolTipsShowRating())
+ {
+ tip += m_headBeg + i18n("digiKam Properties") + m_headEnd;
+
+ if (settings->getToolTipsShowAlbumName())
+ {
+ PAlbum* album = info->album();
+ if (album)
+ tip += m_cellSpecBeg + i18n("Album:") + m_cellSpecMid +
+ album->url().remove(0, 1) + m_cellSpecEnd;
+ }
+
+ if (settings->getToolTipsShowComments())
+ {
+ str = info->caption();
+ if (str.isEmpty()) str = TQString("---");
+ tip += m_cellSpecBeg + i18n("Caption:") + m_cellSpecMid + breakString(str) + m_cellSpecEnd;
+ }
+
+ if (settings->getToolTipsShowTags())
+ {
+ TQStringList tagPaths = info->tagPaths(false);
+
+ str = tagPaths.join(", ");
+ if (str.isEmpty()) str = TQString("---");
+ if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
+ tip += m_cellSpecBeg + i18n("Tags:") + m_cellSpecMid + str + m_cellSpecEnd;
+ }
+
+ if (settings->getToolTipsShowRating())
+ {
+ str.fill( '*', info->rating() );
+ if (str.isEmpty()) str = TQString("---");
+ tip += m_cellSpecBeg + i18n("Rating:") + m_cellSpecMid + str + m_cellSpecEnd;
+ }
+ }
+ }
+
+ return tip;
+}
+
+} // NameSpace Digikam
diff --git a/src/utilities/lighttable/lighttablebar.h b/src/utilities/lighttable/lighttablebar.h
new file mode 100644
index 00000000..b64e93a6
--- /dev/null
+++ b/src/utilities/lighttable/lighttablebar.h
@@ -0,0 +1,153 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-04-11
+ * Description : light table thumbs bar
+ *
+ * Copyright (C) 2007-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 LIGHTTABLEBAR_H
+#define LIGHTTABLEBAR_H
+
+// Local includes.
+
+#include "thumbbar.h"
+#include "imageinfo.h"
+#include "digikam_export.h"
+
+class TQDragMoveEvent;
+class TQDropEvent;
+class TQMouseEvent;
+class TQPaintEvent;
+
+class KURL;
+
+namespace Digikam
+{
+
+class LightTableBarItem;
+class LightTableBarItemPriv;
+class LightTableBarPriv;
+
+class DIGIKAM_EXPORT LightTableBar : public ThumbBarView
+{
+ TQ_OBJECT
+
+
+public:
+
+ LightTableBar(TQWidget* parent, int orientation=Vertical, bool exifRotate=true);
+ ~LightTableBar();
+
+ ImageInfo* currentItemImageInfo() const;
+ ImageInfoList itemsImageInfoList();
+
+ void setSelectedItem(LightTableBarItem* ltItem);
+
+ LightTableBarItem* findItemByInfo(const ImageInfo* info) const;
+ LightTableBarItem* findItemByPos(const TQPoint& pos) const;
+
+ /** Read tool tip settings from Album Settings instance */
+ void readToolTipSettings();
+
+ void setOnLeftPanel(const ImageInfo* info);
+ void setOnRightPanel(const ImageInfo* info);
+
+ void removeItem(const ImageInfo* info);
+
+ void setNavigateByPair(bool b);
+
+signals:
+
+ void signalLightTableBarItemSelected(ImageInfo*);
+ void signalSetItemOnLeftPanel(ImageInfo*);
+ void signalSetItemOnRightPanel(ImageInfo*);
+ void signalEditItem(ImageInfo*);
+ void signalRemoveItem(ImageInfo*);
+ void signalClearAll();
+ void signalDroppedItems(const ImageInfoList&);
+
+private:
+
+ void viewportPaintEvent(TQPaintEvent*);
+ void contentsMouseReleaseEvent(TQMouseEvent*);
+ void startDrag();
+ void contentsDragMoveEvent(TQDragMoveEvent*);
+ void contentsDropEvent(TQDropEvent*);
+
+private slots:
+
+ void slotImageRatingChanged(TQ_LLONG);
+ void slotItemSelected(ThumbBarItem*);
+
+ void slotAssignRatingNoStar();
+ void slotAssignRatingOneStar();
+ void slotAssignRatingTwoStar();
+ void slotAssignRatingThreeStar();
+ void slotAssignRatingFourStar();
+ void slotAssignRatingFiveStar();
+ void slotAssignRating(int);
+
+ void slotThemeChanged();
+
+private:
+
+ LightTableBarPriv *d;
+
+ friend class LightTableBarItem;
+};
+
+// -------------------------------------------------------------------------
+
+class DIGIKAM_EXPORT LightTableBarItem : public ThumbBarItem
+{
+public:
+
+ LightTableBarItem(LightTableBar *view, ImageInfo *info);
+ ~LightTableBarItem();
+
+ ImageInfo* info() const;
+
+ void setOnLeftPanel(bool on);
+ void setOnRightPanel(bool on);
+ bool isOnLeftPanel() const;
+ bool isOnRightPanel() const;
+
+private:
+
+ LightTableBarItemPriv *d;
+
+ friend class LightTableBar;
+};
+
+// -------------------------------------------------------------------------
+
+class DIGIKAM_EXPORT LightTableBarToolTip : public ThumbBarToolTip
+{
+public:
+
+ LightTableBarToolTip(ThumbBarView *parent);
+
+private:
+
+ TQString tipContentExtraData(ThumbBarItem *item);
+};
+
+} // NameSpace Digikam
+
+#endif /* LIGHTTABLEBAR_H */
diff --git a/src/utilities/lighttable/lighttablepreview.cpp b/src/utilities/lighttable/lighttablepreview.cpp
new file mode 100644
index 00000000..100427ec
--- /dev/null
+++ b/src/utilities/lighttable/lighttablepreview.cpp
@@ -0,0 +1,777 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-21-12
+ * Description : digiKam light table preview item.
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqpainter.h>
+#include <tqcursor.h>
+#include <tqstring.h>
+#include <tqvaluevector.h>
+#include <tqfileinfo.h>
+#include <tqtoolbutton.h>
+#include <tqtooltip.h>
+#include <tqpixmap.h>
+#include <tqdrawutil.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+#include <tdelocale.h>
+#include <kservice.h>
+#include <krun.h>
+#include <ktrader.h>
+#include <kmimetype.h>
+#include <kcursor.h>
+#include <kdatetbl.h>
+#include <kiconloader.h>
+#include <kprocess.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "dimg.h"
+#include "ddebug.h"
+#include "albumdb.h"
+#include "constants.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "dragobjects.h"
+#include "dmetadata.h"
+#include "dpopupmenu.h"
+#include "metadatahub.h"
+#include "paniconwidget.h"
+#include "previewloadthread.h"
+#include "loadingdescription.h"
+#include "tagspopupmenu.h"
+#include "ratingpopupmenu.h"
+#include "themeengine.h"
+#include "lighttablepreview.h"
+#include "lighttablepreview.moc"
+
+namespace Digikam
+{
+
+class LightTablePreviewPriv
+{
+public:
+
+ LightTablePreviewPriv()
+ {
+ panIconPopup = 0;
+ panIconWidget = 0;
+ cornerButton = 0;
+ previewThread = 0;
+ previewPreloadThread = 0;
+ imageInfo = 0;
+ hasPrev = false;
+ hasNext = false;
+ selected = false;
+ dragAndDropEnabled = true;
+ loadFullImageSize = false;
+ currentFitWindowZoom = 0;
+ previewSize = 1024;
+ }
+
+ bool hasPrev;
+ bool hasNext;
+ bool selected;
+ bool dragAndDropEnabled;
+ bool loadFullImageSize;
+
+ int previewSize;
+
+ double currentFitWindowZoom;
+
+ TQString path;
+ TQString nextPath;
+ TQString previousPath;
+
+ TQToolButton *cornerButton;
+
+ TDEPopupFrame *panIconPopup;
+
+ PanIconWidget *panIconWidget;
+
+ DImg preview;
+
+ ImageInfo *imageInfo;
+
+ PreviewLoadThread *previewThread;
+ PreviewLoadThread *previewPreloadThread;
+};
+
+LightTablePreview::LightTablePreview(TQWidget *parent)
+ : PreviewWidget(parent)
+{
+ d = new LightTablePreviewPriv;
+
+ // get preview size from screen size, but limit from VGA to WTQXGA
+ d->previewSize = TQMAX(TDEApplication::desktop()->height(),
+ TDEApplication::desktop()->width());
+ if (d->previewSize < 640)
+ d->previewSize = 640;
+ if (d->previewSize > 2560)
+ d->previewSize = 2560;
+
+ viewport()->setAcceptDrops(true);
+ setAcceptDrops(true);
+
+ slotThemeChanged();
+ 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"));
+ setCornerWidget(d->cornerButton);
+
+ setLineWidth(5);
+ setSelected(false);
+
+ // ------------------------------------------------------------
+
+ connect(d->cornerButton, TQ_SIGNAL(pressed()),
+ this, TQ_SLOT(slotCornerButtonPressed()));
+
+ connect(this, TQ_SIGNAL(signalRightButtonClicked()),
+ this, TQ_SLOT(slotContextMenu()));
+
+ connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()),
+ this, TQ_SLOT(slotThemeChanged()));
+
+ // ------------------------------------------------------------
+
+ slotReset();
+}
+
+LightTablePreview::~LightTablePreview()
+{
+ delete d->previewThread;
+ delete d->previewPreloadThread;
+ delete d;
+}
+
+void LightTablePreview::setLoadFullImageSize(bool b)
+{
+ d->loadFullImageSize = b;
+ reload();
+}
+
+void LightTablePreview::setDragAndDropEnabled(bool b)
+{
+ d->dragAndDropEnabled = b;
+}
+
+void LightTablePreview::setDragAndDropMessage()
+{
+ if (d->dragAndDropEnabled)
+ {
+ 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("Drag and drop an image here"));
+ p.end();
+ setImage(pix.convertToImage());
+ }
+}
+
+void LightTablePreview::setImage(const DImg& image)
+{
+ d->preview = image;
+
+ updateZoomAndSize(true);
+
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+}
+
+DImg& LightTablePreview::getImage() const
+{
+ return d->preview;
+}
+
+TQSize LightTablePreview::getImageSize()
+{
+ return d->preview.size();
+}
+
+void LightTablePreview::reload()
+{
+ // cache is cleaned from AlbumIconView::refreshItems
+ setImagePath(d->path);
+}
+
+void LightTablePreview::setPreviousNextPaths(const TQString& previous, const TQString &next)
+{
+ d->nextPath = next;
+ d->previousPath = previous;
+}
+
+void LightTablePreview::setImagePath(const TQString& path)
+{
+ setCursor( KCursor::waitCursor() );
+
+ d->path = path;
+ d->nextPath = TQString();
+ d->previousPath = TQString();
+
+ if (d->path.isEmpty())
+ {
+ slotReset();
+ unsetCursor();
+ return;
+ }
+
+ if (!d->previewThread)
+ {
+ d->previewThread = new PreviewLoadThread();
+ connect(d->previewThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
+ this, TQ_SLOT(slotGotImagePreview(const LoadingDescription &, const DImg&)));
+ }
+ if (!d->previewPreloadThread)
+ {
+ d->previewPreloadThread = new PreviewLoadThread();
+ connect(d->previewPreloadThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
+ this, TQ_SLOT(slotNextPreload()));
+ }
+
+ if (d->loadFullImageSize)
+ d->previewThread->loadHighQuality(LoadingDescription(path, 0, AlbumSettings::instance()->getExifRotate()));
+ else
+ d->previewThread->load(LoadingDescription(path, d->previewSize, AlbumSettings::instance()->getExifRotate()));
+}
+
+void LightTablePreview::slotGotImagePreview(const LoadingDescription &description, const DImg& preview)
+{
+ if (description.filePath != d->path)
+ return;
+
+ if (preview.isNull())
+ {
+ TQPixmap pix(visibleWidth(), visibleHeight());
+ pix.fill(ThemeEngine::instance()->baseColor());
+ TQPainter p(&pix);
+ TQFileInfo info(d->path);
+ p.setPen(TQPen(ThemeEngine::instance()->textRegColor()));
+ p.drawText(0, 0, pix.width(), pix.height(),
+ TQt::AlignCenter|TQt::WordBreak,
+ i18n("Unable to display preview for\n\"%1\"")
+ .arg(info.fileName()));
+ p.end();
+ setImage(DImg(pix.convertToImage()));
+
+ emit signalPreviewLoaded(false);
+ }
+ else
+ {
+ DImg img(preview);
+ if (AlbumSettings::instance()->getExifRotate())
+ d->previewThread->exifRotate(img, description.filePath);
+ setImage(img);
+ emit signalPreviewLoaded(true);
+ }
+
+ unsetCursor();
+ slotNextPreload();
+}
+
+void LightTablePreview::slotNextPreload()
+{
+ TQString loadPath;
+ if (!d->nextPath.isNull())
+ {
+ loadPath = d->nextPath;
+ d->nextPath = TQString();
+ }
+ else if (!d->previousPath.isNull())
+ {
+ loadPath = d->previousPath;
+ d->previousPath = TQString();
+ }
+ else
+ return;
+
+ d->previewPreloadThread->load(LoadingDescription(loadPath, d->previewSize,
+ AlbumSettings::instance()->getExifRotate()));
+}
+
+void LightTablePreview::setImageInfo(ImageInfo* info, ImageInfo *previous, ImageInfo *next)
+{
+ d->imageInfo = info;
+ d->hasPrev = previous;
+ d->hasNext = next;
+
+ if (d->imageInfo)
+ setImagePath(info->filePath());
+ else
+ {
+ setImagePath();
+ setSelected(false);
+ }
+
+ setPreviousNextPaths(previous ? previous->filePath() : TQString(),
+ next ? next->filePath() : TQString());
+}
+
+ImageInfo* LightTablePreview::getImageInfo() const
+{
+ return d->imageInfo;
+}
+
+void LightTablePreview::slotContextMenu()
+{
+ RatingPopupMenu *ratingMenu = 0;
+ TagsPopupMenu *assignTagsMenu = 0;
+ TagsPopupMenu *removeTagsMenu = 0;
+
+ if (!d->imageInfo)
+ return;
+
+ //-- Open With Actions ------------------------------------
+
+ KURL url(d->imageInfo->kurl().path());
+ KMimeType::Ptr mimePtr = KMimeType::findByURL(url, 0, true, true);
+
+ TQValueVector<KService::Ptr> serviceVector;
+ TDETrader::OfferList offers = TDETrader::self()->query(mimePtr->name(), "Type == 'Application'");
+
+ TQPopupMenu openWithMenu;
+
+ TDETrader::OfferList::Iterator iter;
+ KService::Ptr ptr;
+ int index = 100;
+
+ for( iter = offers.begin(); iter != offers.end(); ++iter )
+ {
+ ptr = *iter;
+ openWithMenu.insertItem( ptr->pixmap(TDEIcon::Small), ptr->name(), index++);
+ serviceVector.push_back(ptr);
+ }
+
+ DPopupMenu popmenu(this);
+
+ //-- Zoom actions -----------------------------------------------
+
+ popmenu.insertItem(SmallIcon("viewmag"), i18n("Zoom in"), 17);
+ popmenu.insertItem(SmallIcon("zoom-out"), i18n("Zoom out"), 18);
+ popmenu.insertItem(SmallIcon("view_fit_window"), i18n("Fit to &Window"), 19);
+
+ //-- Edit actions -----------------------------------------------
+
+ popmenu.insertSeparator();
+ popmenu.insertItem(SmallIcon("slideshow"), i18n("SlideShow"), 16);
+ popmenu.insertItem(SmallIcon("editimage"), i18n("Edit..."), 12);
+ popmenu.insertItem(i18n("Open With"), &openWithMenu, 13);
+
+ //-- Trash action -------------------------------------------
+
+ popmenu.insertSeparator();
+ popmenu.insertItem(SmallIcon("edittrash"), i18n("Move to Trash"), 14);
+
+ // Bulk assignment/removal of tags --------------------------
+
+ TQ_LLONG id = d->imageInfo->id();
+ TQValueList<TQ_LLONG> idList;
+ idList.append(id);
+
+ assignTagsMenu = new TagsPopupMenu(idList, 1000, TagsPopupMenu::ASSIGN);
+ removeTagsMenu = new TagsPopupMenu(idList, 2000, TagsPopupMenu::REMOVE);
+
+ popmenu.insertSeparator();
+
+ popmenu.insertItem(i18n("Assign Tag"), assignTagsMenu);
+ int i = popmenu.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 ))
+ popmenu.setItemEnabled(i, false);
+
+ popmenu.insertSeparator();
+
+ // Assign Star Rating -------------------------------------------
+
+ ratingMenu = new RatingPopupMenu();
+
+ connect(ratingMenu, TQ_SIGNAL(activated(int)),
+ this, TQ_SLOT(slotAssignRating(int)));
+
+ popmenu.insertItem(i18n("Assign Rating"), ratingMenu);
+
+ // --------------------------------------------------------
+
+ int idm = popmenu.exec(TQCursor::pos());
+
+ switch(idm)
+ {
+ case 12: // Edit...
+ {
+ emit signalEditItem(d->imageInfo);
+ break;
+ }
+
+ case 14: // Move to trash
+ {
+ emit signalDeleteItem(d->imageInfo);
+ break;
+ }
+
+ case 16: // SlideShow
+ {
+ emit signalSlideShow();
+ break;
+ }
+
+ case 17: // Zoom in
+ {
+ slotIncreaseZoom();
+ break;
+ }
+
+ case 18: // Zoom out
+ {
+ slotDecreaseZoom();
+ break;
+ }
+
+ case 19: // Fit to window
+ {
+ fitToWindow();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Open With...
+ if (idm >= 100 && idm < 1000)
+ {
+ KService::Ptr imageServicePtr = serviceVector[idm-100];
+ KRun::run(*imageServicePtr, url);
+ }
+
+ serviceVector.clear();
+ delete assignTagsMenu;
+ delete removeTagsMenu;
+ delete ratingMenu;
+}
+
+void LightTablePreview::slotAssignTag(int tagID)
+{
+ if (d->imageInfo)
+ {
+ MetadataHub hub;
+ hub.load(d->imageInfo);
+ hub.setTag(tagID, true);
+ hub.write(d->imageInfo, MetadataHub::PartialWrite);
+ hub.write(d->imageInfo->filePath(), MetadataHub::FullWriteIfChanged);
+ }
+}
+
+void LightTablePreview::slotRemoveTag(int tagID)
+{
+ if (d->imageInfo)
+ {
+ MetadataHub hub;
+ hub.load(d->imageInfo);
+ hub.setTag(tagID, false);
+ hub.write(d->imageInfo, MetadataHub::PartialWrite);
+ hub.write(d->imageInfo->filePath(), MetadataHub::FullWriteIfChanged);
+ }
+}
+
+void LightTablePreview::slotAssignRating(int rating)
+{
+ rating = TQMIN(RatingMax, TQMAX(RatingMin, rating));
+ if (d->imageInfo)
+ {
+ MetadataHub hub;
+ hub.load(d->imageInfo);
+ hub.setRating(rating);
+ hub.write(d->imageInfo, MetadataHub::PartialWrite);
+ hub.write(d->imageInfo->filePath(), MetadataHub::FullWriteIfChanged);
+ }
+}
+
+void LightTablePreview::slotThemeChanged()
+{
+ setBackgroundColor(ThemeEngine::instance()->baseColor());
+ frameChanged();
+}
+
+void LightTablePreview::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, getImage());
+ 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 LightTablePreview::slotPanIconHiden()
+{
+ d->cornerButton->blockSignals(true);
+ d->cornerButton->animateClick();
+ d->cornerButton->blockSignals(false);
+}
+
+void LightTablePreview::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 LightTablePreview::zoomFactorChanged(double zoom)
+{
+ updateScrollBars();
+
+ if (horizontalScrollBar()->isVisible() || verticalScrollBar()->isVisible())
+ d->cornerButton->show();
+ else
+ d->cornerButton->hide();
+
+ PreviewWidget::zoomFactorChanged(zoom);
+}
+
+void LightTablePreview::resizeEvent(TQResizeEvent* e)
+{
+ if (!e) return;
+
+ TQScrollView::resizeEvent(e);
+
+ if (!d->imageInfo)
+ {
+ d->cornerButton->hide();
+ setDragAndDropMessage();
+ }
+
+ updateZoomAndSize(false);
+}
+
+void LightTablePreview::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 LightTablePreview::previewWidth()
+{
+ return d->preview.width();
+}
+
+int LightTablePreview::previewHeight()
+{
+ return d->preview.height();
+}
+
+bool LightTablePreview::previewIsNull()
+{
+ return d->preview.isNull();
+}
+
+void LightTablePreview::resetPreview()
+{
+ d->preview = DImg();
+ d->path = TQString();
+ d->imageInfo = 0;
+
+ setDragAndDropMessage();
+ updateZoomAndSize(true);
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+ emit signalPreviewLoaded(false);
+}
+
+void LightTablePreview::paintPreview(TQPixmap *pix, int sx, int sy, int sw, int sh)
+{
+ DImg img = d->preview.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize());
+ TQPixmap pix2 = img.convertToPixmap();
+ bitBlt(pix, 0, 0, &pix2, 0, 0);
+}
+
+void LightTablePreview::contentsDragMoveEvent(TQDragMoveEvent *e)
+{
+ if (d->dragAndDropEnabled)
+ {
+ 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 LightTablePreview::contentsDropEvent(TQDropEvent *e)
+{
+ if (d->dragAndDropEnabled)
+ {
+ int albumID;
+ TQValueList<int> albumIDs;
+ TQValueList<int> imageIDs;
+ KURL::List urls;
+ KURL::List kioURLs;
+ ImageInfoList list;
+
+ if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs))
+ {
+ for (TQValueList<int>::const_iterator it = imageIDs.begin();
+ it != imageIDs.end(); ++it)
+ {
+ list.append(new ImageInfo(*it));
+ }
+
+ emit signalDroppedItems(list);
+ e->accept();
+ return;
+ }
+ else if (AlbumDrag::decode(e, urls, albumID))
+ {
+ TQValueList<TQ_LLONG> itemIDs = AlbumManager::instance()->albumDB()->getItemIDsInAlbum(albumID);
+
+ for (TQValueList<TQ_LLONG>::const_iterator it = itemIDs.begin();
+ it != itemIDs.end(); ++it)
+ {
+ list.append(new ImageInfo(*it));
+ }
+
+ emit signalDroppedItems(list);
+ e->accept();
+ return;
+ }
+ 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)
+ {
+ list.append(new ImageInfo(*it));
+ }
+
+ emit signalDroppedItems(list);
+ e->accept();
+ return;
+ }
+ }
+
+ e->ignore();
+}
+
+void LightTablePreview::setSelected(bool sel)
+{
+ if (d->selected != sel)
+ {
+ d->selected = sel;
+ frameChanged();
+ }
+}
+
+bool LightTablePreview::isSelected()
+{
+ return d->selected;
+}
+
+void LightTablePreview::drawFrame(TQPainter *p)
+{
+ if (d->selected)
+ {
+ qDrawPlainRect(p, frameRect(), ThemeEngine::instance()->thumbSelColor(), lineWidth());
+ qDrawPlainRect(p, frameRect(), ThemeEngine::instance()->textSelColor(), 2);
+ }
+ else
+ qDrawPlainRect(p, frameRect(), ThemeEngine::instance()->baseColor(), lineWidth());
+}
+
+} // NameSpace Digikam
diff --git a/src/utilities/lighttable/lighttablepreview.h b/src/utilities/lighttable/lighttablepreview.h
new file mode 100644
index 00000000..3549fa1c
--- /dev/null
+++ b/src/utilities/lighttable/lighttablepreview.h
@@ -0,0 +1,125 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-21-12
+ * Description : digiKam light table preview item.
+ *
+ * Copyright (C) 2006-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 LIGHTTABLEPREVIEW_H
+#define LIGHTTABLEPREVIEW_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqimage.h>
+#include <tqsize.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+#include "previewwidget.h"
+#include "digikam_export.h"
+
+class TQPixmap;
+
+namespace Digikam
+{
+
+class DImg;
+class LoadingDescription;
+class LightTablePreviewPriv;
+
+class DIGIKAM_EXPORT LightTablePreview : public PreviewWidget
+{
+
+TQ_OBJECT
+
+
+public:
+
+ LightTablePreview(TQWidget *parent=0);
+ ~LightTablePreview();
+
+ void setLoadFullImageSize(bool b);
+
+ void setImage(const DImg& image);
+ DImg& getImage() const;
+
+ TQSize getImageSize();
+
+ void setImageInfo(ImageInfo* info=0, ImageInfo *previous=0, ImageInfo *next=0);
+ ImageInfo* getImageInfo() const;
+
+ void reload();
+ void setImagePath(const TQString& path=TQString());
+ void setPreviousNextPaths(const TQString& previous, const TQString &next);
+
+ void setSelected(bool sel);
+ bool isSelected();
+
+ void setDragAndDropEnabled(bool b);
+ void setDragAndDropMessage();
+
+signals:
+
+ void signalDroppedItems(const ImageInfoList&);
+ void signalDeleteItem(ImageInfo*);
+ void signalEditItem(ImageInfo*);
+ void signalPreviewLoaded(bool success);
+ void signalSlideShow();
+
+protected:
+
+ void resizeEvent(TQResizeEvent* e);
+ void drawFrame(TQPainter *p);
+
+private slots:
+
+ void slotGotImagePreview(const LoadingDescription &loadingDescription, const DImg &image);
+ void slotNextPreload();
+ void slotContextMenu();
+ void slotAssignTag(int tagID);
+ void slotRemoveTag(int tagID);
+ void slotAssignRating(int rating);
+ void slotThemeChanged();
+ void slotCornerButtonPressed();
+ void slotPanIconSelectionMoved(const TQRect&, bool);
+ void slotPanIconHiden();
+
+private:
+
+ 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);
+
+ void contentsDragMoveEvent(TQDragMoveEvent*);
+ void contentsDropEvent(TQDropEvent*);
+
+private:
+
+ LightTablePreviewPriv* d;
+};
+
+} // NameSpace Digikam
+
+#endif /* LIGHTTABLEPREVIEW_H */
diff --git a/src/utilities/lighttable/lighttableview.cpp b/src/utilities/lighttable/lighttableview.cpp
new file mode 100644
index 00000000..51f45ab5
--- /dev/null
+++ b/src/utilities/lighttable/lighttableview.cpp
@@ -0,0 +1,446 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-03-05
+ * Description : a widget to display 2 preview image on
+ * lightable to compare pictures.
+ *
+ * Copyright (C) 2007-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 <tqlayout.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "thumbnailsize.h"
+#include "lighttablepreview.h"
+#include "lighttableview.h"
+#include "lighttableview.moc"
+
+namespace Digikam
+{
+
+class LightTableViewPriv
+{
+public:
+
+ LightTableViewPriv()
+ {
+ syncPreview = false;
+ leftLoading = false;
+ rightLoading = false;
+ leftPreview = 0;
+ rightPreview = 0;
+ grid = 0;
+ }
+
+ bool syncPreview;
+ bool leftLoading; // To not sync right panel during left loading.
+ bool rightLoading; // To not sync left panel during right loading.
+
+ TQGridLayout *grid;
+
+ LightTablePreview *leftPreview;
+ LightTablePreview *rightPreview;
+};
+
+LightTableView::LightTableView(TQWidget *parent)
+ : TQFrame(parent, 0, TQt::WDestructiveClose)
+{
+ d = new LightTableViewPriv;
+
+ setFrameStyle(TQFrame::NoFrame);
+ setMargin(0);
+ setLineWidth(0);
+
+ d->grid = new TQGridLayout(this, 1, 1, 0, 1);
+ d->leftPreview = new LightTablePreview(this);
+ d->rightPreview = new LightTablePreview(this);
+
+ d->grid->addMultiCellWidget(d->leftPreview, 0, 0, 0, 0);
+ d->grid->addMultiCellWidget(d->rightPreview, 0, 0, 1, 1);
+
+ d->grid->setColStretch(0, 10),
+ d->grid->setColStretch(1, 10),
+ d->grid->setRowStretch(0, 10),
+
+ // Left panel connections ------------------------------------------------
+
+ connect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
+ this, TQ_SIGNAL(signalLeftZoomFactorChanged(double)));
+
+ connect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)),
+ this, TQ_SLOT(slotLeftContentsMoved(int, int)));
+
+ connect(d->leftPreview, TQ_SIGNAL(signalSlideShow()),
+ this, TQ_SIGNAL(signalSlideShow()));
+
+ connect(d->leftPreview, TQ_SIGNAL(signalDeleteItem(ImageInfo*)),
+ this, TQ_SIGNAL(signalDeleteItem(ImageInfo*)));
+
+ connect(d->leftPreview, TQ_SIGNAL(signalEditItem(ImageInfo*)),
+ this, TQ_SIGNAL(signalEditItem(ImageInfo*)));
+
+ connect(d->leftPreview, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)),
+ this, TQ_SIGNAL(signalLeftDroppedItems(const ImageInfoList&)));
+
+ connect(d->leftPreview, TQ_SIGNAL(signalPreviewLoaded(bool)),
+ this, TQ_SLOT(slotLeftPreviewLoaded(bool)));
+
+ connect(d->leftPreview, TQ_SIGNAL(signalLeftButtonClicked()),
+ this, TQ_SIGNAL(signalLeftPanelLeftButtonClicked()));
+
+ // Right panel connections ------------------------------------------------
+
+ connect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
+ this, TQ_SIGNAL(signalRightZoomFactorChanged(double)));
+
+ connect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)),
+ this, TQ_SLOT(slotRightContentsMoved(int, int)));
+
+ connect(d->rightPreview, TQ_SIGNAL(signalDeleteItem(ImageInfo*)),
+ this, TQ_SIGNAL(signalDeleteItem(ImageInfo*)));
+
+ connect(d->rightPreview, TQ_SIGNAL(signalEditItem(ImageInfo*)),
+ this, TQ_SIGNAL(signalEditItem(ImageInfo*)));
+
+ connect(d->rightPreview, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)),
+ this, TQ_SIGNAL(signalRightDroppedItems(const ImageInfoList&)));
+
+ connect(d->rightPreview, TQ_SIGNAL(signalSlideShow()),
+ this, TQ_SIGNAL(signalSlideShow()));
+
+ connect(d->rightPreview, TQ_SIGNAL(signalPreviewLoaded(bool)),
+ this, TQ_SLOT(slotRightPreviewLoaded(bool)));
+
+ connect(d->rightPreview, TQ_SIGNAL(signalLeftButtonClicked()),
+ this, TQ_SIGNAL(signalRightPanelLeftButtonClicked()));
+}
+
+LightTableView::~LightTableView()
+{
+ delete d;
+}
+
+void LightTableView::setLoadFullImageSize(bool b)
+{
+ d->leftPreview->setLoadFullImageSize(b);
+ d->rightPreview->setLoadFullImageSize(b);
+}
+
+void LightTableView::setSyncPreview(bool sync)
+{
+ d->syncPreview = sync;
+
+ // Left panel like a reference to resync preview.
+ if (d->syncPreview)
+ slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY());
+}
+
+void LightTableView::setNavigateByPair(bool b)
+{
+ d->leftPreview->setDragAndDropEnabled(!b);
+ d->rightPreview->setDragAndDropEnabled(!b);
+}
+
+void LightTableView::slotDecreaseZoom()
+{
+ if (d->syncPreview)
+ {
+ slotDecreaseLeftZoom();
+ return;
+ }
+
+ if (d->leftPreview->isSelected())
+ slotDecreaseLeftZoom();
+ else if (d->rightPreview->isSelected())
+ slotDecreaseRightZoom();
+}
+
+void LightTableView::slotIncreaseZoom()
+{
+ if (d->syncPreview)
+ {
+ slotIncreaseLeftZoom();
+ return;
+ }
+
+ if (d->leftPreview->isSelected())
+ slotIncreaseLeftZoom();
+ else if (d->rightPreview->isSelected())
+ slotIncreaseRightZoom();
+}
+
+void LightTableView::slotDecreaseLeftZoom()
+{
+ d->leftPreview->slotDecreaseZoom();
+}
+
+void LightTableView::slotIncreaseLeftZoom()
+{
+ d->leftPreview->slotIncreaseZoom();
+}
+
+void LightTableView::slotDecreaseRightZoom()
+{
+ d->rightPreview->slotDecreaseZoom();
+}
+
+void LightTableView::slotIncreaseRightZoom()
+{
+ d->rightPreview->slotIncreaseZoom();
+}
+
+void LightTableView::setLeftZoomFactor(double z)
+{
+ d->leftPreview->setZoomFactor(z);
+}
+
+void LightTableView::setRightZoomFactor(double z)
+{
+ d->rightPreview->setZoomFactor(z);
+}
+
+void LightTableView::fitToWindow()
+{
+ d->leftPreview->fitToWindow();
+ d->rightPreview->fitToWindow();
+}
+
+void LightTableView::toggleFitToWindowOr100()
+{
+ // If we are currently precisely at 100%, then fit to window,
+ // otherwise zoom to a centered 100% view.
+ if ((d->leftPreview->zoomFactor()==1.0) &&
+ (d->rightPreview->zoomFactor()==1.0))
+ {
+ fitToWindow();
+ }
+ else
+ {
+ d->leftPreview->setZoomFactor(1.0, true);
+ d->rightPreview->setZoomFactor(1.0, true);
+ }
+}
+
+double LightTableView::leftZoomMax()
+{
+ return d->leftPreview->zoomMax();
+}
+
+double LightTableView::leftZoomMin()
+{
+ return d->leftPreview->zoomMin();
+}
+
+bool LightTableView::leftMaxZoom()
+{
+ return d->leftPreview->maxZoom();
+}
+
+bool LightTableView::leftMinZoom()
+{
+ return d->leftPreview->minZoom();
+}
+
+double LightTableView::rightZoomMax()
+{
+ return d->rightPreview->zoomMax();
+}
+
+double LightTableView::rightZoomMin()
+{
+ return d->rightPreview->zoomMin();
+}
+
+bool LightTableView::rightMaxZoom()
+{
+ return d->rightPreview->maxZoom();
+}
+
+bool LightTableView::rightMinZoom()
+{
+ return d->rightPreview->minZoom();
+}
+
+void LightTableView::slotLeftZoomSliderChanged(int size)
+{
+ double h = (double)ThumbnailSize::Huge;
+ double s = (double)ThumbnailSize::Small;
+ double zmin = d->leftPreview->zoomMin();
+ double zmax = d->leftPreview->zoomMax();
+ double b = (zmin-(zmax*s/h))/(1-s/h);
+ double a = (zmax-b)/h;
+ double z = a*size+b;
+
+ d->leftPreview->setZoomFactorSnapped(z);
+}
+
+void LightTableView::slotRightZoomSliderChanged(int size)
+{
+ double h = (double)ThumbnailSize::Huge;
+ double s = (double)ThumbnailSize::Small;
+ double zmin = d->rightPreview->zoomMin();
+ double zmax = d->rightPreview->zoomMax();
+ double b = (zmin-(zmax*s/h))/(1-s/h);
+ double a = (zmax-b)/h;
+ double z = a*size+b;
+
+ d->rightPreview->setZoomFactorSnapped(z);
+}
+
+void LightTableView::leftReload()
+{
+ d->leftPreview->reload();
+}
+
+void LightTableView::rightReload()
+{
+ d->rightPreview->reload();
+}
+
+void LightTableView::slotLeftContentsMoved(int x, int y)
+{
+ if (d->syncPreview && !d->leftLoading)
+ {
+ disconnect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
+ this, TQ_SIGNAL(signalRightZoomFactorChanged(double)));
+
+ disconnect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)),
+ this, TQ_SLOT(slotRightContentsMoved(int, int)));
+
+ setRightZoomFactor(d->leftPreview->zoomFactor());
+ emit signalRightZoomFactorChanged(d->leftPreview->zoomFactor());
+ d->rightPreview->setContentsPos(x, y);
+
+ connect(d->rightPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
+ this, TQ_SIGNAL(signalRightZoomFactorChanged(double)));
+
+ connect(d->rightPreview, TQ_SIGNAL(contentsMoving(int, int)),
+ this, TQ_SLOT(slotRightContentsMoved(int, int)));
+ }
+}
+
+void LightTableView::slotRightContentsMoved(int x, int y)
+{
+ if (d->syncPreview && !d->rightLoading)
+ {
+ disconnect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
+ this, TQ_SIGNAL(signalLeftZoomFactorChanged(double)));
+
+ disconnect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)),
+ this, TQ_SLOT(slotLeftContentsMoved(int, int)));
+
+
+ setLeftZoomFactor(d->rightPreview->zoomFactor());
+ emit signalLeftZoomFactorChanged(d->rightPreview->zoomFactor());
+ d->leftPreview->setContentsPos(x, y);
+
+ connect(d->leftPreview, TQ_SIGNAL(signalZoomFactorChanged(double)),
+ this, TQ_SIGNAL(signalLeftZoomFactorChanged(double)));
+
+ connect(d->leftPreview, TQ_SIGNAL(contentsMoving(int, int)),
+ this, TQ_SLOT(slotLeftContentsMoved(int, int)));
+ }
+}
+
+ImageInfo* LightTableView::leftImageInfo() const
+{
+ return d->leftPreview->getImageInfo();
+}
+
+ImageInfo* LightTableView::rightImageInfo() const
+{
+ return d->rightPreview->getImageInfo();
+}
+
+void LightTableView::setLeftImageInfo(ImageInfo* info)
+{
+ d->leftLoading = true;
+ d->leftPreview->setImageInfo(info);
+}
+
+void LightTableView::setRightImageInfo(ImageInfo* info)
+{
+ d->rightLoading = true;
+ d->rightPreview->setImageInfo(info);
+}
+
+void LightTableView::slotLeftPreviewLoaded(bool success)
+{
+ checkForSyncPreview();
+ d->leftLoading = false;
+ slotRightContentsMoved(d->rightPreview->contentsX(),
+ d->rightPreview->contentsY());
+
+ emit signalLeftPreviewLoaded(success);
+}
+
+void LightTableView::slotRightPreviewLoaded(bool success)
+{
+ checkForSyncPreview();
+ d->rightLoading = false;
+ slotLeftContentsMoved(d->leftPreview->contentsX(),
+ d->leftPreview->contentsY());
+
+ emit signalRightPreviewLoaded(success);
+}
+
+void LightTableView::checkForSyncPreview()
+{
+ if (d->leftPreview->getImageInfo() && d->rightPreview->getImageInfo() &&
+ d->leftPreview->getImageSize() == d->rightPreview->getImageSize())
+ {
+ d->syncPreview = true;
+ }
+ else
+ {
+ d->syncPreview = false;
+ }
+
+ emit signalToggleOnSyncPreview(d->syncPreview);
+}
+
+void LightTableView::checkForSelection(ImageInfo* info)
+{
+ if (!info)
+ {
+ d->leftPreview->setSelected(false);
+ d->rightPreview->setSelected(false);
+ return;
+ }
+
+ if (d->leftPreview->getImageInfo())
+ {
+ d->leftPreview->setSelected(d->leftPreview->getImageInfo()->id() == info->id());
+ }
+
+ if (d->rightPreview->getImageInfo())
+ {
+ d->rightPreview->setSelected(d->rightPreview->getImageInfo()->id() == info->id());
+ }
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/lighttable/lighttableview.h b/src/utilities/lighttable/lighttableview.h
new file mode 100644
index 00000000..273b7072
--- /dev/null
+++ b/src/utilities/lighttable/lighttableview.h
@@ -0,0 +1,137 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-03-05
+ * Description : a widget to display 2 preview image on
+ * lightable to compare pictures.
+ *
+ * Copyright (C) 2007-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 LIGHTTABLEVIEW_H
+#define LIGHTTABLEVIEW_H
+
+// TQt includes.
+
+#include <tqframe.h>
+#include <tqstring.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class LightTableViewPriv;
+
+class DIGIKAM_EXPORT LightTableView : public TQFrame
+{
+
+TQ_OBJECT
+
+
+public:
+
+ LightTableView(TQWidget *parent=0);
+ ~LightTableView();
+
+ void setSyncPreview(bool sync);
+ void setNavigateByPair(bool b);
+
+ void setLeftImageInfo(ImageInfo* info=0);
+ void setRightImageInfo(ImageInfo* info=0);
+
+ ImageInfo* leftImageInfo() const;
+ ImageInfo* rightImageInfo() const;
+
+ void setLoadFullImageSize(bool b);
+
+ void setLeftZoomFactor(double z);
+ void setRightZoomFactor(double z);
+
+ void checkForSelection(ImageInfo* info);
+
+ double leftZoomMax();
+ double leftZoomMin();
+
+ double rightZoomMax();
+ double rightZoomMin();
+
+ bool leftMaxZoom();
+ bool leftMinZoom();
+
+ bool rightMaxZoom();
+ bool rightMinZoom();
+
+ void leftReload();
+ void rightReload();
+
+ void fitToWindow();
+ void toggleFitToWindowOr100();
+
+signals:
+
+ void signalLeftPreviewLoaded(bool);
+ void signalRightPreviewLoaded(bool);
+
+ void signalLeftZoomFactorChanged(double);
+ void signalRightZoomFactorChanged(double);
+
+ void signalLeftDroppedItems(const ImageInfoList&);
+ void signalRightDroppedItems(const ImageInfoList&);
+
+ void signalLeftPanelLeftButtonClicked();
+ void signalRightPanelLeftButtonClicked();
+
+ void signalSlideShow();
+ void signalDeleteItem(ImageInfo*);
+ void signalEditItem(ImageInfo*);
+ void signalToggleOnSyncPreview(bool);
+
+public slots:
+
+ void slotDecreaseZoom();
+ void slotIncreaseZoom();
+ void slotDecreaseLeftZoom();
+ void slotIncreaseLeftZoom();
+ void slotLeftZoomSliderChanged(int);
+
+ void slotDecreaseRightZoom();
+ void slotIncreaseRightZoom();
+ void slotRightZoomSliderChanged(int);
+
+private slots:
+
+ void slotLeftContentsMoved(int, int);
+ void slotRightContentsMoved(int, int);
+ void slotLeftPreviewLoaded(bool);
+ void slotRightPreviewLoaded(bool);
+
+private :
+
+ void checkForSyncPreview();
+
+private :
+
+ LightTableViewPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* LIGHTTABLEVIEW_H */
diff --git a/src/utilities/lighttable/lighttablewindow.cpp b/src/utilities/lighttable/lighttablewindow.cpp
new file mode 100644
index 00000000..58409aef
--- /dev/null
+++ b/src/utilities/lighttable/lighttablewindow.cpp
@@ -0,0 +1,1676 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-03-05
+ * Description : digiKam light table GUI
+ *
+ * Copyright (C) 2007-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 <tqdockarea.h>
+
+// KDE includes.
+
+#include <kkeydialog.h>
+#include <kedittoolbar.h>
+#include <tdeversion.h>
+#include <tdelocale.h>
+#include <twin.h>
+#include <tdemessagebox.h>
+#include <tdeapplication.h>
+#include <tdeconfig.h>
+#include <kstatusbar.h>
+#include <tdemenubar.h>
+
+// LibKDcraw includes.
+
+#include <libkdcraw/version.h>
+#include <libkdcraw/kdcraw.h>
+
+#if KDCRAW_VERSION < 0x000106
+#include <libkdcraw/dcrawbinary.h>
+#endif
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dlogoaction.h"
+#include "themeengine.h"
+#include "dimg.h"
+#include "dmetadata.h"
+#include "albumsettings.h"
+#include "albummanager.h"
+#include "deletedialog.h"
+#include "imagewindow.h"
+#include "slideshow.h"
+#include "setup.h"
+#include "syncjob.h"
+#include "thumbnailsize.h"
+#include "rawcameradlg.h"
+#include "lighttablepreview.h"
+#include "lighttablewindowprivate.h"
+#include "lighttablewindow.h"
+#include "lighttablewindow.moc"
+
+namespace Digikam
+{
+
+LightTableWindow* LightTableWindow::m_instance = 0;
+
+LightTableWindow* LightTableWindow::lightTableWindow()
+{
+ if (!m_instance)
+ new LightTableWindow();
+
+ return m_instance;
+}
+
+bool LightTableWindow::lightTableWindowCreated()
+{
+ return m_instance;
+}
+
+LightTableWindow::LightTableWindow()
+ : TDEMainWindow(0, "lighttable", WType_TopLevel)
+{
+ d = new LightTableWindowPriv;
+ m_instance = this;
+
+ setCaption(i18n("Light Table"));
+
+ // -- Build the GUI -------------------------------
+
+ setupUserArea();
+ setupStatusBar();
+ setupActions();
+ setupAccelerators();
+
+ // Make signals/slots connections
+
+ setupConnections();
+
+ //-------------------------------------------------------------
+
+ d->leftSidebar->loadViewState();
+ d->rightSidebar->loadViewState();
+ d->leftSidebar->populateTags();
+ d->rightSidebar->populateTags();
+
+ readSettings();
+ applySettings();
+ setAutoSaveSettings("LightTable Settings");
+}
+
+LightTableWindow::~LightTableWindow()
+{
+ m_instance = 0;
+
+ delete d->barView;
+ delete d->rightSidebar;
+ delete d->leftSidebar;
+ delete d;
+}
+
+void LightTableWindow::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("LightTable Settings");
+
+ if(config->hasKey("Vertical Splitter Sizes"))
+ d->vSplitter->setSizes(config->readIntListEntry("Vertical Splitter Sizes"));
+
+ if(config->hasKey("Horizontal Splitter Sizes"))
+ d->hSplitter->setSizes(config->readIntListEntry("Horizontal Splitter Sizes"));
+
+ d->navigateByPairAction->setChecked(config->readBoolEntry("Navigate By Pair", false));
+ slotToggleNavigateByPair();
+}
+
+void LightTableWindow::writeSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("LightTable Settings");
+ config->writeEntry("Vertical Splitter Sizes", d->vSplitter->sizes());
+ config->writeEntry("Horizontal Splitter Sizes", d->hSplitter->sizes());
+ config->writeEntry("Navigate By Pair", d->navigateByPairAction->isChecked());
+ config->sync();
+}
+
+void LightTableWindow::applySettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("LightTable Settings");
+
+ d->autoLoadOnRightPanel = config->readBoolEntry("Auto Load Right Panel", true);
+ d->autoSyncPreview = config->readBoolEntry("Auto Sync Preview", true);
+ d->fullScreenHideToolBar = config->readBoolEntry("FullScreen Hide ToolBar", false);
+ d->previewView->setLoadFullImageSize(config->readBoolEntry("Load Full Image size", false));
+ refreshView();
+}
+
+void LightTableWindow::refreshView()
+{
+ d->leftSidebar->refreshTagsView();
+ d->rightSidebar->refreshTagsView();
+}
+
+void LightTableWindow::closeEvent(TQCloseEvent* e)
+{
+ if (!e) return;
+
+ writeSettings();
+
+ e->accept();
+}
+
+void LightTableWindow::setupUserArea()
+{
+ TQWidget* mainW = new TQWidget(this);
+ d->hSplitter = new TQSplitter(TQt::Horizontal, mainW);
+ TQHBoxLayout *hlay = new TQHBoxLayout(mainW);
+ d->leftSidebar = new ImagePropertiesSideBarDB(mainW,
+ "LightTable Left Sidebar", d->hSplitter,
+ Sidebar::Left, true);
+
+ TQWidget* centralW = new TQWidget(d->hSplitter);
+ TQVBoxLayout *vlay = new TQVBoxLayout(centralW);
+ d->vSplitter = new TQSplitter(TQt::Vertical, centralW);
+ d->barView = new LightTableBar(d->vSplitter, ThumbBarView::Horizontal,
+ AlbumSettings::instance()->getExifRotate());
+ d->previewView = new LightTableView(d->vSplitter);
+ vlay->addWidget(d->vSplitter);
+
+ d->rightSidebar = new ImagePropertiesSideBarDB(mainW,
+ "LightTable Right Sidebar", d->hSplitter,
+ Sidebar::Right, true);
+
+ hlay->addWidget(d->leftSidebar);
+ hlay->addWidget(d->hSplitter);
+ hlay->addWidget(d->rightSidebar);
+
+ d->hSplitter->setFrameStyle( TQFrame::NoFrame );
+ d->hSplitter->setFrameShadow( TQFrame::Plain );
+ d->hSplitter->setFrameShape( TQFrame::NoFrame );
+ d->hSplitter->setOpaqueResize(false);
+ d->vSplitter->setFrameStyle( TQFrame::NoFrame );
+ d->vSplitter->setFrameShadow( TQFrame::Plain );
+ d->vSplitter->setFrameShape( TQFrame::NoFrame );
+ d->vSplitter->setOpaqueResize(false);
+
+ setCentralWidget(mainW);
+}
+
+void LightTableWindow::setupStatusBar()
+{
+ d->leftZoomBar = new StatusZoomBar(statusBar());
+ d->leftZoomBar->setMaximumHeight(fontMetrics().height()+2);
+ statusBar()->addWidget(d->leftZoomBar, 1);
+ d->leftZoomBar->setEnabled(false);
+
+ d->statusProgressBar = new StatusProgressBar(statusBar());
+ d->statusProgressBar->setAlignment(TQt::AlignCenter);
+ d->statusProgressBar->setMaximumHeight(fontMetrics().height()+2);
+ statusBar()->addWidget(d->statusProgressBar, 100);
+
+ d->rightZoomBar = new StatusZoomBar(statusBar());
+ d->rightZoomBar->setMaximumHeight(fontMetrics().height()+2);
+ statusBar()->addWidget(d->rightZoomBar, 1);
+ d->rightZoomBar->setEnabled(false);
+}
+
+void LightTableWindow::setupConnections()
+{
+ connect(d->statusProgressBar, TQ_SIGNAL(signalCancelButtonPressed()),
+ this, TQ_SLOT(slotProgressBarCancelButtonPressed()));
+
+ connect(ThemeEngine::instance(), TQ_SIGNAL(signalThemeChanged()),
+ this, TQ_SLOT(slotThemeChanged()));
+
+ // Thumbs bar connections ---------------------------------------
+
+ connect(d->barView, TQ_SIGNAL(signalSetItemOnLeftPanel(ImageInfo*)),
+ this, TQ_SLOT(slotSetItemOnLeftPanel(ImageInfo*)));
+
+ connect(d->barView, TQ_SIGNAL(signalSetItemOnRightPanel(ImageInfo*)),
+ this, TQ_SLOT(slotSetItemOnRightPanel(ImageInfo*)));
+
+ connect(d->barView, TQ_SIGNAL(signalRemoveItem(ImageInfo*)),
+ this, TQ_SLOT(slotRemoveItem(ImageInfo*)));
+
+ connect(d->barView, TQ_SIGNAL(signalEditItem(ImageInfo*)),
+ this, TQ_SLOT(slotEditItem(ImageInfo*)));
+
+ connect(d->barView, TQ_SIGNAL(signalClearAll()),
+ this, TQ_SLOT(slotClearItemsList()));
+
+ connect(d->barView, TQ_SIGNAL(signalLightTableBarItemSelected(ImageInfo*)),
+ this, TQ_SLOT(slotItemSelected(ImageInfo*)));
+
+ connect(d->barView, TQ_SIGNAL(signalDroppedItems(const ImageInfoList&)),
+ this, TQ_SLOT(slotThumbbarDroppedItems(const ImageInfoList&)));
+
+ // Zoom bars connections -----------------------------------------
+
+ connect(d->leftZoomBar, TQ_SIGNAL(signalZoomMinusClicked()),
+ d->previewView, TQ_SLOT(slotDecreaseLeftZoom()));
+
+ connect(d->leftZoomBar, TQ_SIGNAL(signalZoomPlusClicked()),
+ d->previewView, TQ_SLOT(slotIncreaseLeftZoom()));
+
+ connect(d->leftZoomBar, TQ_SIGNAL(signalZoomSliderChanged(int)),
+ d->previewView, TQ_SLOT(slotLeftZoomSliderChanged(int)));
+
+ connect(d->rightZoomBar, TQ_SIGNAL(signalZoomMinusClicked()),
+ d->previewView, TQ_SLOT(slotDecreaseRightZoom()));
+
+ connect(d->rightZoomBar, TQ_SIGNAL(signalZoomPlusClicked()),
+ d->previewView, TQ_SLOT(slotIncreaseRightZoom()));
+
+ connect(d->rightZoomBar, TQ_SIGNAL(signalZoomSliderChanged(int)),
+ d->previewView, TQ_SLOT(slotRightZoomSliderChanged(int)));
+
+ // View connections ---------------------------------------------
+
+ connect(d->previewView, TQ_SIGNAL(signalLeftZoomFactorChanged(double)),
+ this, TQ_SLOT(slotLeftZoomFactorChanged(double)));
+
+ connect(d->previewView, TQ_SIGNAL(signalRightZoomFactorChanged(double)),
+ this, TQ_SLOT(slotRightZoomFactorChanged(double)));
+
+ connect(d->previewView, TQ_SIGNAL(signalEditItem(ImageInfo*)),
+ this, TQ_SLOT(slotEditItem(ImageInfo*)));
+
+ connect(d->previewView, TQ_SIGNAL(signalDeleteItem(ImageInfo*)),
+ this, TQ_SLOT(slotDeleteItem(ImageInfo*)));
+
+ connect(d->previewView, TQ_SIGNAL(signalSlideShow()),
+ this, TQ_SLOT(slotToggleSlideShow()));
+
+ connect(d->previewView, TQ_SIGNAL(signalLeftDroppedItems(const ImageInfoList&)),
+ this, TQ_SLOT(slotLeftDroppedItems(const ImageInfoList&)));
+
+ connect(d->previewView, TQ_SIGNAL(signalRightDroppedItems(const ImageInfoList&)),
+ this, TQ_SLOT(slotRightDroppedItems(const ImageInfoList&)));
+
+ connect(d->previewView, TQ_SIGNAL(signalToggleOnSyncPreview(bool)),
+ this, TQ_SLOT(slotToggleOnSyncPreview(bool)));
+
+ connect(d->previewView, TQ_SIGNAL(signalLeftPreviewLoaded(bool)),
+ this, TQ_SLOT(slotLeftPreviewLoaded(bool)));
+
+ connect(d->previewView, TQ_SIGNAL(signalRightPreviewLoaded(bool)),
+ this, TQ_SLOT(slotRightPreviewLoaded(bool)));
+
+ connect(d->previewView, TQ_SIGNAL(signalLeftPanelLeftButtonClicked()),
+ this, TQ_SLOT(slotLeftPanelLeftButtonClicked()));
+
+ connect(d->previewView, TQ_SIGNAL(signalRightPanelLeftButtonClicked()),
+ this, TQ_SLOT(slotRightPanelLeftButtonClicked()));
+}
+
+void LightTableWindow::setupActions()
+{
+ // -- Standard 'File' menu actions ---------------------------------------------
+
+ d->backwardAction = KStdAction::back(this, TQ_SLOT(slotBackward()),
+ actionCollection(), "lighttable_backward");
+ d->backwardAction->setEnabled(false);
+
+ d->forwardAction = KStdAction::forward(this, TQ_SLOT(slotForward()),
+ actionCollection(), "lighttable_forward");
+ d->forwardAction->setEnabled(false);
+
+ d->firstAction = new TDEAction(i18n("&First"), "go-first",
+ TDEStdAccel::shortcut( TDEStdAccel::Home),
+ this, TQ_SLOT(slotFirst()),
+ actionCollection(), "lighttable_first");
+ d->firstAction->setEnabled(false);
+
+ d->lastAction = new TDEAction(i18n("&Last"), "go-last",
+ TDEStdAccel::shortcut( TDEStdAccel::End),
+ this, TQ_SLOT(slotLast()),
+ actionCollection(), "lighttable_last");
+ d->lastAction->setEnabled(false);
+
+ d->setItemLeftAction = new TDEAction(i18n("On Left"), "go-previous",
+ CTRL+Key_L, this, TQ_SLOT(slotSetItemLeft()),
+ actionCollection(), "lighttable_setitemleft");
+ d->setItemLeftAction->setEnabled(false);
+ d->setItemLeftAction->setWhatsThis(i18n("Show item on left panel"));
+
+ d->setItemRightAction = new TDEAction(i18n("On Right"), "go-next",
+ CTRL+Key_R, this, TQ_SLOT(slotSetItemRight()),
+ actionCollection(), "lighttable_setitemright");
+ d->setItemRightAction->setEnabled(false);
+ d->setItemRightAction->setWhatsThis(i18n("Show item on right panel"));
+
+ d->editItemAction = new TDEAction(i18n("Edit"), "editimage",
+ Key_F4, this, TQ_SLOT(slotEditItem()),
+ actionCollection(), "lighttable_edititem");
+ d->editItemAction->setEnabled(false);
+
+ d->removeItemAction = new TDEAction(i18n("Remove item from LightTable"), "window-close",
+ CTRL+Key_K, this, TQ_SLOT(slotRemoveItem()),
+ actionCollection(), "lighttable_removeitem");
+ d->removeItemAction->setEnabled(false);
+
+ d->clearListAction = new TDEAction(i18n("Remove all items from LightTable"), "editshred",
+ CTRL+SHIFT+Key_K, this, TQ_SLOT(slotClearItemsList()),
+ actionCollection(), "lighttable_clearlist");
+ d->clearListAction->setEnabled(false);
+
+ d->fileDeleteAction = new TDEAction(i18n("Move to Trash"), "edittrash",
+ Key_Delete,
+ this, TQ_SLOT(slotDeleteItem()),
+ actionCollection(), "lighttable_filedelete");
+ d->fileDeleteAction->setEnabled(false);
+
+ KStdAction::close(this, TQ_SLOT(close()), actionCollection(), "lighttable_close");
+
+ // -- Standard 'View' menu actions ---------------------------------------------
+
+ d->syncPreviewAction = new TDEToggleAction(i18n("Synchronize"), "goto",
+ CTRL+SHIFT+Key_Y, this,
+ TQ_SLOT(slotToggleSyncPreview()),
+ actionCollection(), "lighttable_syncpreview");
+ d->syncPreviewAction->setEnabled(false);
+ d->syncPreviewAction->setWhatsThis(i18n("Synchronize preview from left and right panels"));
+
+ d->navigateByPairAction = new TDEToggleAction(i18n("By Pair"), "preferences-system",
+ CTRL+SHIFT+Key_P, this,
+ TQ_SLOT(slotToggleNavigateByPair()),
+ actionCollection(), "lighttable_navigatebypair");
+ d->navigateByPairAction->setEnabled(false);
+ d->navigateByPairAction->setWhatsThis(i18n("Navigate by pair with all items"));
+
+ d->zoomPlusAction = KStdAction::zoomIn(d->previewView, TQ_SLOT(slotIncreaseZoom()),
+ actionCollection(), "lighttable_zoomplus");
+ d->zoomPlusAction->setEnabled(false);
+
+ d->zoomMinusAction = KStdAction::zoomOut(d->previewView, TQ_SLOT(slotDecreaseZoom()),
+ actionCollection(), "lighttable_zoomminus");
+ d->zoomMinusAction->setEnabled(false);
+
+ 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(), "lighttable_zoomto100percents");
+
+ d->zoomFitToWindowAction = new TDEAction(i18n("Fit to &Window"), "view_fit_window",
+ CTRL+SHIFT+Key_E, this, TQ_SLOT(slotFitToWindow()),
+ actionCollection(), "lighttable_zoomfit2window");
+
+ // Do not use std KDE action for full screen because action text is too large for app. toolbar.
+ d->fullScreenAction = new TDEToggleAction(i18n("Full Screen"), "view-fullscreen",
+ CTRL+SHIFT+Key_F, this,
+ TQ_SLOT(slotToggleFullScreen()),
+ actionCollection(), "lighttable_fullscreen");
+ d->fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode"));
+
+ d->slideShowAction = new TDEAction(i18n("Slideshow"), "slideshow", Key_F9,
+ this, TQ_SLOT(slotToggleSlideShow()),
+ actionCollection(),"lighttable_slideshow");
+
+ // -- 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());
+
+ // -----------------------------------------------------------------------------------------
+
+ d->themeMenuAction = new TDESelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu");
+ connect(d->themeMenuAction, TQ_SIGNAL(activated(const TQString&)),
+ this, TQ_SLOT(slotChangeTheme(const TQString&)));
+
+ d->themeMenuAction->setItems(ThemeEngine::instance()->themeNames());
+ slotThemeChanged();
+
+ // -- Standard 'Help' menu actions ---------------------------------------------
+
+
+ d->donateMoneyAction = new TDEAction(i18n("Donate..."),
+ 0, 0,
+ this, TQ_SLOT(slotDonateMoney()),
+ actionCollection(),
+ "lighttable_donatemoney");
+
+ d->contributeAction = new TDEAction(i18n("Contribute..."),
+ 0, 0,
+ this, TQ_SLOT(slotContribute()),
+ actionCollection(),
+ "lighttable_contribute");
+
+ d->rawCameraListAction = new TDEAction(i18n("Supported RAW Cameras"),
+ "kdcraw",
+ 0,
+ this,
+ TQ_SLOT(slotRawCameraList()),
+ actionCollection(),
+ "lighttable_rawcameralist");
+
+
+ // 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,
+ d->barView, TQ_SLOT(slotAssignRatingNoStar()),
+ actionCollection(), "lighttable_ratenostar");
+ d->star1 = new TDEAction(i18n("Assign Rating \"One Star\""), CTRL+Key_1,
+ d->barView, TQ_SLOT(slotAssignRatingOneStar()),
+ actionCollection(), "lighttable_rateonestar");
+ d->star2 = new TDEAction(i18n("Assign Rating \"Two Stars\""), CTRL+Key_2,
+ d->barView, TQ_SLOT(slotAssignRatingTwoStar()),
+ actionCollection(), "lighttable_ratetwostar");
+ d->star3 = new TDEAction(i18n("Assign Rating \"Three Stars\""), CTRL+Key_3,
+ d->barView, TQ_SLOT(slotAssignRatingThreeStar()),
+ actionCollection(), "lighttable_ratethreestar");
+ d->star4 = new TDEAction(i18n("Assign Rating \"Four Stars\""), CTRL+Key_4,
+ d->barView, TQ_SLOT(slotAssignRatingFourStar()),
+ actionCollection(), "lighttable_ratefourstar");
+ d->star5 = new TDEAction(i18n("Assign Rating \"Five Stars\""), CTRL+Key_5,
+ d->barView, TQ_SLOT(slotAssignRatingFiveStar()),
+ actionCollection(), "lighttable_ratefivestar");
+
+ // ---------------------------------------------------------------------------------
+
+ new DLogoAction(actionCollection(), "logo_action");
+
+ createGUI("lighttablewindowui.rc", false);
+}
+
+void LightTableWindow::setupAccelerators()
+{
+ d->accelerators = new TDEAccel(this);
+
+ d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"),
+ i18n("Exit fullscreen viewing 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, d->previewView, TQ_SLOT(slotIncreaseZoom()),
+ false, true);
+
+ d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom out"),
+ i18n("Zoom out from image"),
+ Key_Minus, d->previewView, TQ_SLOT(slotDecreaseZoom()),
+ false, true);
+}
+
+// Deal with items dropped onto the thumbbar (e.g. from the Album view)
+void LightTableWindow::slotThumbbarDroppedItems(const ImageInfoList& list)
+{
+ // Setting the third parameter of loadImageInfos to true
+ // means that the images are added to the presently available images.
+ loadImageInfos(list, 0, true);
+}
+
+// We get here either
+// - via CTRL+L (from the albumview)
+// a) digikamapp.cpp: CTRL+key_L leads to slotImageLightTable())
+// b) digikamview.cpp: void DigikamView::slotImageLightTable()
+// calls d->iconView->insertToLightTable(list, info);
+// c) albumiconview.cpp: AlbumIconView::insertToLightTable
+// calls ltview->loadImageInfos(list, current);
+// - via drag&drop, i.e. calls issued by the ...Dropped... routines
+void LightTableWindow::loadImageInfos(const ImageInfoList &list,
+ ImageInfo *imageInfoCurrent,
+ bool addTo)
+{
+ // Clear all items before adding new images to the light table.
+ if (!addTo)
+ slotClearItemsList();
+
+ ImageInfoList l = list;
+
+ if (!imageInfoCurrent)
+ imageInfoCurrent = l.first();
+
+ AlbumSettings *settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ TQString imagefilter = settings->getImageFileFilter().lower() +
+ settings->getImageFileFilter().upper();
+
+#if KDCRAW_VERSION < 0x000106
+ if (KDcrawIface::DcrawBinary::instance()->versionIsRight())
+ {
+ // add raw files only if dcraw is available
+ imagefilter += settings->getRawFileFilter().lower() +
+ settings->getRawFileFilter().upper();
+ }
+#else
+ imagefilter += settings->getRawFileFilter().lower() +
+ settings->getRawFileFilter().upper();
+#endif
+
+ d->barView->blockSignals(true);
+ for (TQPtrList<ImageInfo>::const_iterator it = l.begin(); it != l.end(); ++it)
+ {
+ TQString fileExtension = (*it)->kurl().fileName().section( '.', -1 );
+
+ if ( imagefilter.find(fileExtension) != -1 &&
+ !d->barView->findItemByInfo(*it) )
+ {
+ new LightTableBarItem(d->barView, *it);
+ }
+ }
+ d->barView->blockSignals(false);
+
+ // if window is iconified, show it
+ if (isMinimized())
+ {
+ KWin::deIconifyWindow(winId());
+ }
+
+ refreshStatusBar();
+}
+
+void LightTableWindow::refreshStatusBar()
+{
+ switch (d->barView->countItems())
+ {
+ case 0:
+ d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode,
+ i18n("No item on Light Table"));
+ break;
+ case 1:
+ d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode,
+ i18n("1 item on Light Table"));
+ break;
+ default:
+ d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode,
+ i18n("%1 items on Light Table")
+ .arg(d->barView->countItems()));
+ break;
+ }
+}
+
+void LightTableWindow::slotItemsUpdated(const KURL::List& urls)
+{
+ d->barView->refreshThumbs(urls);
+
+ for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it)
+ {
+ if (d->previewView->leftImageInfo())
+ {
+ if (d->previewView->leftImageInfo()->kurl() == *it)
+ {
+ d->previewView->leftReload();
+ d->leftSidebar->itemChanged(d->previewView->leftImageInfo());
+ }
+ }
+
+ if (d->previewView->rightImageInfo())
+ {
+ if (d->previewView->rightImageInfo()->kurl() == *it)
+ {
+ d->previewView->rightReload();
+ d->rightSidebar->itemChanged(d->previewView->rightImageInfo());
+ }
+ }
+ }
+}
+
+void LightTableWindow::slotLeftPanelLeftButtonClicked()
+{
+ if (d->navigateByPairAction->isChecked()) return;
+
+ d->barView->setSelectedItem(d->barView->findItemByInfo(d->previewView->leftImageInfo()));
+}
+
+void LightTableWindow::slotRightPanelLeftButtonClicked()
+{
+ // With navigate by pair option, only the left panel can be selected.
+ if (d->navigateByPairAction->isChecked()) return;
+
+ d->barView->setSelectedItem(d->barView->findItemByInfo(d->previewView->rightImageInfo()));
+}
+
+void LightTableWindow::slotLeftPreviewLoaded(bool b)
+{
+ d->leftZoomBar->setEnabled(b);
+
+ if (b)
+ {
+ d->previewView->checkForSelection(d->barView->currentItemImageInfo());
+ d->barView->setOnLeftPanel(d->previewView->leftImageInfo());
+
+ LightTableBarItem *item = d->barView->findItemByInfo(d->previewView->leftImageInfo());
+ if (item) item->setOnLeftPanel(true);
+
+ if (d->navigateByPairAction->isChecked() && item)
+ {
+ LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(item->next());
+ if (next)
+ {
+ d->barView->setOnRightPanel(next->info());
+ slotSetItemOnRightPanel(next->info());
+ }
+ else
+ {
+ LightTableBarItem* first = dynamic_cast<LightTableBarItem*>(d->barView->firstItem());
+ slotSetItemOnRightPanel(first ? first->info() : 0);
+ }
+ }
+ }
+}
+
+void LightTableWindow::slotRightPreviewLoaded(bool b)
+{
+ d->rightZoomBar->setEnabled(b);
+ if (b)
+ {
+ d->previewView->checkForSelection(d->barView->currentItemImageInfo());
+ d->barView->setOnRightPanel(d->previewView->rightImageInfo());
+
+ LightTableBarItem *item = d->barView->findItemByInfo(d->previewView->rightImageInfo());
+ if (item) item->setOnRightPanel(true);
+ }
+}
+
+void LightTableWindow::slotItemSelected(ImageInfo* info)
+{
+ if (info)
+ {
+ d->setItemLeftAction->setEnabled(true);
+ d->setItemRightAction->setEnabled(true);
+ d->editItemAction->setEnabled(true);
+ d->removeItemAction->setEnabled(true);
+ d->clearListAction->setEnabled(true);
+ d->fileDeleteAction->setEnabled(true);
+ d->backwardAction->setEnabled(true);
+ d->forwardAction->setEnabled(true);
+ d->firstAction->setEnabled(true);
+ d->lastAction->setEnabled(true);
+ d->syncPreviewAction->setEnabled(true);
+ d->zoomPlusAction->setEnabled(true);
+ d->zoomMinusAction->setEnabled(true);
+ d->navigateByPairAction->setEnabled(true);
+ d->slideShowAction->setEnabled(true);
+
+ LightTableBarItem* curr = d->barView->findItemByInfo(info);
+ if (curr)
+ {
+ if (!curr->prev())
+ {
+// d->backwardAction->setEnabled(false);
+ d->firstAction->setEnabled(false);
+ }
+
+ if (!curr->next())
+ {
+// d->forwardAction->setEnabled(false);
+ d->lastAction->setEnabled(false);
+ }
+
+ if (d->navigateByPairAction->isChecked())
+ {
+ d->setItemLeftAction->setEnabled(false);
+ d->setItemRightAction->setEnabled(false);
+
+ d->barView->setOnLeftPanel(info);
+ slotSetItemOnLeftPanel(info);
+ }
+ else if (d->autoLoadOnRightPanel && !curr->isOnLeftPanel())
+ {
+ d->barView->setOnRightPanel(info);
+ slotSetItemOnRightPanel(info);
+ }
+ }
+ }
+ else
+ {
+ d->setItemLeftAction->setEnabled(false);
+ d->setItemRightAction->setEnabled(false);
+ d->editItemAction->setEnabled(false);
+ d->removeItemAction->setEnabled(false);
+ d->clearListAction->setEnabled(false);
+ d->fileDeleteAction->setEnabled(false);
+ d->backwardAction->setEnabled(false);
+ d->forwardAction->setEnabled(false);
+ d->firstAction->setEnabled(false);
+ d->lastAction->setEnabled(false);
+ d->zoomPlusAction->setEnabled(false);
+ d->zoomMinusAction->setEnabled(false);
+ d->syncPreviewAction->setEnabled(false);
+ d->navigateByPairAction->setEnabled(false);
+ d->slideShowAction->setEnabled(false);
+ }
+
+ d->previewView->checkForSelection(info);
+}
+
+// Deal with one (or more) items dropped onto the left panel
+void LightTableWindow::slotLeftDroppedItems(const ImageInfoList& list)
+{
+ ImageInfo *info = *(list.begin());
+ // add the image to the existing images
+ loadImageInfos(list, info, true);
+
+ // We will check if first item from list is already stored in thumbbar
+ // Note that the thumbbar stores all ImageInfo reference
+ // in memory for preview object.
+ LightTableBarItem *item = d->barView->findItemByInfo(info);
+ if (item)
+ {
+ slotSetItemOnLeftPanel(item->info());
+ // One approach is to make this item the current one, via
+ // d->barView->setSelectedItem(item);
+ // However, this is not good, because this also sets
+ // the right thumb to the same image.
+ // Therefore we use setLeftRightItems if there is more than
+ // one item in the list of dropped images.
+ }
+}
+
+// Deal with one (or more) items dropped onto the right panel
+void LightTableWindow::slotRightDroppedItems(const ImageInfoList& list)
+{
+ ImageInfo *info = *(list.begin());
+ // add the image to the existing images
+ loadImageInfos(list, info, true);
+
+ // We will check if first item from list is already stored in thumbbar
+ // Note that the thumbbar stores all ImageInfo reference
+ // in memory for preview object.
+ LightTableBarItem *item = d->barView->findItemByInfo(info);
+ if (item)
+ {
+ slotSetItemOnRightPanel(item->info());
+ // Make this item the current one.
+ d->barView->setSelectedItem(item);
+ }
+}
+
+// Set the images for the left and right panel.
+void LightTableWindow::setLeftRightItems(const ImageInfoList &list, bool addTo)
+{
+ ImageInfoList l = list;
+
+ if (l.count() == 0)
+ return;
+
+ ImageInfo *info = l.first();
+ LightTableBarItem *ltItem = d->barView->findItemByInfo(info);
+
+ if (l.count() == 1 && !addTo)
+ {
+ // Just one item; this is used for the left panel.
+ d->barView->setOnLeftPanel(info);
+ slotSetItemOnLeftPanel(info);
+ d->barView->setSelectedItem(ltItem);
+ d->barView->ensureItemVisible(ltItem);
+ return;
+ }
+
+ if (ltItem)
+ {
+ // The first item is used for the left panel.
+ if (!addTo)
+ {
+ d->barView->setOnLeftPanel(info);
+ slotSetItemOnLeftPanel(info);
+ }
+
+ // The subsequent item is used for the right panel.
+ LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(ltItem->next());
+ if (next && !addTo)
+ {
+ d->barView->setOnRightPanel(next->info());
+ slotSetItemOnRightPanel(next->info());
+ if (!d->navigateByPairAction->isChecked())
+ {
+ d->barView->setSelectedItem(next);
+ // ensure that the selected item is visible
+ // FIXME: this does not work:
+ d->barView->ensureItemVisible(next);
+ }
+ }
+
+ // If navigate by pairs is active, the left panel item is selected.
+ // (Fixes parts of bug #150296)
+ if (d->navigateByPairAction->isChecked())
+ {
+ d->barView->setSelectedItem(ltItem);
+ d->barView->ensureItemVisible(ltItem);
+ }
+ }
+}
+
+void LightTableWindow::slotSetItemLeft()
+{
+ if (d->barView->currentItemImageInfo())
+ {
+ slotSetItemOnLeftPanel(d->barView->currentItemImageInfo());
+ }
+}
+
+void LightTableWindow::slotSetItemRight()
+{
+ if (d->barView->currentItemImageInfo())
+ {
+ slotSetItemOnRightPanel(d->barView->currentItemImageInfo());
+ }
+}
+
+void LightTableWindow::slotSetItemOnLeftPanel(ImageInfo* info)
+{
+ d->previewView->setLeftImageInfo(info);
+ if (info)
+ d->leftSidebar->itemChanged(info);
+ else
+ d->leftSidebar->slotNoCurrentItem();
+}
+
+void LightTableWindow::slotSetItemOnRightPanel(ImageInfo* info)
+{
+ d->previewView->setRightImageInfo(info);
+ if (info)
+ d->rightSidebar->itemChanged(info);
+ else
+ d->rightSidebar->slotNoCurrentItem();
+}
+
+void LightTableWindow::slotClearItemsList()
+{
+ if (d->previewView->leftImageInfo())
+ {
+ d->previewView->setLeftImageInfo();
+ d->leftSidebar->slotNoCurrentItem();
+ }
+
+ if (d->previewView->rightImageInfo())
+ {
+ d->previewView->setRightImageInfo();
+ d->rightSidebar->slotNoCurrentItem();
+ }
+
+ d->barView->clear();
+ refreshStatusBar();
+}
+
+void LightTableWindow::slotDeleteItem()
+{
+ if (d->barView->currentItemImageInfo())
+ slotDeleteItem(d->barView->currentItemImageInfo());
+}
+
+void LightTableWindow::slotDeleteItem(ImageInfo* info)
+{
+ bool ask = true;
+ bool permanently = false;
+
+ KURL u = info->kurl();
+ PAlbum *palbum = AlbumManager::instance()->findPAlbum(u.directory());
+ if (!palbum)
+ return;
+
+ // Provide a digikamalbums:// URL to TDEIO
+ KURL kioURL = info->kurlForKIO();
+ KURL fileURL = u;
+
+ bool useTrash;
+
+ if (ask)
+ {
+ bool preselectDeletePermanently = permanently;
+
+ DeleteDialog dialog(this);
+
+ KURL::List urlList;
+ urlList.append(u);
+ if (!dialog.confirmDeleteList(urlList,
+ DeleteDialogMode::Files,
+ preselectDeletePermanently ?
+ DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash))
+ return;
+
+ useTrash = !dialog.shouldDelete();
+ }
+ else
+ {
+ useTrash = !permanently;
+ }
+
+ // 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(u);
+
+ slotRemoveItem(info);
+}
+
+void LightTableWindow::slotRemoveItem()
+{
+ if (d->barView->currentItemImageInfo())
+ slotRemoveItem(d->barView->currentItemImageInfo());
+}
+
+void LightTableWindow::slotRemoveItem(ImageInfo* info)
+{
+ // When either the image from the left or right panel is removed,
+ // there are various situations to account for.
+ // To describe them, 4 images A B C D are used
+ // and the subscript _L and _ R mark the currently
+ // active item on the left and right panel
+
+ bool leftPanelActive = false;
+ ImageInfo *curr_linfo = d->previewView->leftImageInfo();
+ ImageInfo *curr_rinfo = d->previewView->rightImageInfo();
+ ImageInfo *new_linfo = 0;
+ ImageInfo *new_rinfo = 0;
+
+ TQ_LLONG infoId = info->id();
+
+ // First determine the next images to the current left and right image:
+ ImageInfo *next_linfo = 0;
+ ImageInfo *next_rinfo = 0;
+
+ if (curr_linfo)
+ {
+ LightTableBarItem *ltItem = d->barView->findItemByInfo(curr_linfo);
+ if (ltItem)
+ {
+ LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(ltItem->next());
+ if (next)
+ {
+ next_linfo = next->info();
+ }
+ }
+ }
+
+ if (curr_rinfo)
+ {
+ LightTableBarItem *ltItem = d->barView->findItemByInfo(curr_rinfo);
+ if (ltItem)
+ {
+ LightTableBarItem* next = dynamic_cast<LightTableBarItem*>(ltItem->next());
+ if (next)
+ {
+ next_rinfo = next->info();
+ }
+ }
+ }
+
+ d->barView->removeItem(info);
+
+ // Make sure that next_linfo and next_rinfo are still available:
+ if (!d->barView->findItemByInfo(next_linfo))
+ {
+ next_linfo = 0;
+ }
+ if (!d->barView->findItemByInfo(next_rinfo))
+ {
+ next_rinfo = 0;
+ }
+
+ // removal of the left panel item?
+ if (curr_linfo)
+ {
+ if ( curr_linfo->id() == infoId )
+ {
+ leftPanelActive = true;
+ // Delete the item A_L of the left panel:
+ // 1) A_L B_R C D -> B_L C_R D
+ // 2) A_L B C_R D -> B C_L D_R
+ // 3) A_L B C D_R -> B_R C D_L
+ // 4) A_L B_R -> A_L
+ // some more corner cases:
+ // 5) A B_L C_R D -> A C_L D_R
+ // 6) A B_L C_R -> A_R C_L
+ // 7) A_LR B C D -> B_L C_R D (does not yet work)
+ // I.e. in 3) we wrap around circularly.
+
+ // When removing the left panel image,
+ // put the right panel image into the left panel.
+ // Check if this one is not the same (i.e. also removed).
+ if (curr_rinfo)
+ {
+ if (curr_rinfo->id() != infoId)
+ {
+ new_linfo = curr_rinfo;
+ // Set the right panel to the next image:
+ new_rinfo = next_rinfo;
+ // set the right panel active
+ leftPanelActive = false;
+ }
+ }
+ }
+ }
+
+ // removal of the right panel item?
+ if (curr_rinfo)
+ {
+ if (curr_rinfo->id() == infoId)
+ {
+ // Leave the left panel as the current one
+ new_linfo = curr_linfo;
+ // Set the right panel to the next image
+ new_rinfo = next_rinfo;
+ }
+ }
+
+ // Now we deal with the corner cases, where no left or right item exists.
+ // If the right panel would be set, but not the left-one, then swap
+ if (!new_linfo && new_rinfo)
+ {
+ new_linfo = new_rinfo;
+ new_rinfo = 0;
+ leftPanelActive = true;
+ }
+
+ if (!new_linfo)
+ {
+ if (d->barView->countItems() > 0)
+ {
+ LightTableBarItem* first = dynamic_cast<LightTableBarItem*>(d->barView->firstItem());
+ new_linfo = first->info();
+ }
+ }
+
+
+ // Make sure that new_linfo and new_rinfo exist.
+ // This addresses a crash occuring if the last image is removed
+ // in the navigate by pairs mode.
+ if (!d->barView->findItemByInfo(new_linfo))
+ {
+ new_linfo = 0;
+ }
+ if (!d->barView->findItemByInfo(new_rinfo))
+ {
+ new_rinfo = 0;
+ }
+
+ // no right item defined?
+ if (!new_rinfo)
+ {
+ // If there are at least two items, we can find reasonable right image.
+ if (d->barView->countItems() > 1)
+ {
+ // See if there is an item next to the left one:
+ LightTableBarItem *ltItem = d->barView->findItemByInfo(new_linfo);
+ LightTableBarItem* next = 0;
+ // re-check if ltItem is really set
+ if (ltItem)
+ {
+ next = dynamic_cast<LightTableBarItem*>(ltItem->next());
+ }
+ if (next)
+ {
+ new_rinfo = next->info();
+ }
+ else
+ {
+ // If there is no item to the right of new_linfo
+ // then we can choose the first item for new_rinfo
+ // (as we made sure that there are at least two items)
+ LightTableBarItem* first = dynamic_cast<LightTableBarItem*>(d->barView->firstItem());
+ new_rinfo = first->info();
+ }
+ }
+ }
+
+ // Check if left and right are set to the same
+ if (new_linfo && new_rinfo)
+ {
+ if (new_linfo->id() == new_rinfo->id())
+ {
+ // Only keep the left one
+ new_rinfo = 0;
+ }
+ }
+
+ // If the right panel would be set, but not the left-one, then swap
+ // (note that this has to be done here again!)
+ if (!new_linfo && new_rinfo)
+ {
+ new_linfo = new_rinfo;
+ new_rinfo = 0;
+ leftPanelActive = true;
+ }
+
+ // set the image for the left panel
+ if (new_linfo)
+ {
+ d->barView->setOnLeftPanel(new_linfo);
+ slotSetItemOnLeftPanel(new_linfo);
+
+ // make this the selected item if the left was active before
+ if ( leftPanelActive)
+ {
+ LightTableBarItem *ltItem = d->barView->findItemByInfo(new_linfo);
+ d->barView->setSelectedItem(ltItem);
+ }
+ }
+ else
+ {
+ d->previewView->setLeftImageInfo();
+ d->leftSidebar->slotNoCurrentItem();
+ }
+
+ // set the image for the right panel
+ if (new_rinfo)
+ {
+ d->barView->setOnRightPanel(new_rinfo);
+ slotSetItemOnRightPanel(new_rinfo);
+ // make this the selected item if the left was active before
+ if (!leftPanelActive)
+ {
+ LightTableBarItem *ltItem = d->barView->findItemByInfo(new_rinfo);
+ d->barView->setSelectedItem(ltItem);
+ }
+ }
+ else
+ {
+ d->previewView->setRightImageInfo();
+ d->rightSidebar->slotNoCurrentItem();
+ }
+
+ refreshStatusBar();
+}
+
+void LightTableWindow::slotEditItem()
+{
+ if (d->barView->currentItemImageInfo())
+ slotEditItem(d->barView->currentItemImageInfo());
+}
+
+void LightTableWindow::slotEditItem(ImageInfo* info)
+{
+ ImageWindow *im = ImageWindow::imagewindow();
+ ImageInfoList list = d->barView->itemsImageInfoList();
+
+ im->loadImageInfos(list, info, i18n("Light Table"), true);
+
+ if (im->isHidden())
+ im->show();
+ else
+ im->raise();
+
+ im->setFocus();
+}
+
+void LightTableWindow::slotZoomTo100Percents()
+{
+ d->previewView->toggleFitToWindowOr100();
+}
+
+void LightTableWindow::slotFitToWindow()
+{
+ d->previewView->fitToWindow();
+}
+
+void LightTableWindow::slotToggleSlideShow()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ bool startWithCurrent = config->readBoolEntry("SlideShowStartCurrent", false);
+
+ SlideShowSettings settings;
+ settings.exifRotate = AlbumSettings::instance()->getExifRotate();
+ 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 LightTableWindow::slideShow(bool startWithCurrent, SlideShowSettings& settings)
+{
+ if (!d->barView->countItems()) return;
+
+ DMetadata meta;
+ int i = 0;
+ d->cancelSlideShow = false;
+
+ d->statusProgressBar->progressBarMode(StatusProgressBar::CancelProgressBarMode,
+ i18n("Preparing slideshow. Please wait..."));
+
+ ImageInfoList list = d->barView->itemsImageInfoList();
+
+ for (ImageInfo *info = list.first() ; !d->cancelSlideShow && info ; info = list.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);
+ settings.fileList.append(info->kurl());
+
+ d->statusProgressBar->setProgressValue((int)((i++/(float)list.count())*100.0));
+ kapp->processEvents();
+ }
+
+ d->statusProgressBar->progressBarMode(StatusProgressBar::TextMode, TQString());
+ refreshStatusBar();
+
+ if (!d->cancelSlideShow)
+ {
+ settings.exifRotate = AlbumSettings::instance()->getExifRotate();
+
+ SlideShow *slide = new SlideShow(settings);
+ if (startWithCurrent)
+ slide->setCurrent(d->barView->currentItemImageInfo()->kurl());
+
+ slide->show();
+ }
+}
+
+void LightTableWindow::slotProgressBarCancelButtonPressed()
+{
+ d->cancelSlideShow = true;
+}
+
+void LightTableWindow::slotToggleFullScreen()
+{
+ if (d->fullScreen) // out of fullscreen
+ {
+
+ 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 (d->fullScreenAction->isPlugged(toolBar) && d->removeFullScreenButton)
+ d->fullScreenAction->unplug(toolBar);
+
+ if (toolBar->isHidden())
+ showToolBars();
+ }
+
+ // -- remove the gui action accels ----
+
+ unplugActionAccel(d->zoomFitToWindowAction);
+
+ if (d->fullScreen)
+ {
+ d->leftSidebar->restore();
+ d->rightSidebar->restore();
+ }
+ else
+ {
+ d->leftSidebar->backup();
+ d->rightSidebar->backup();
+ }
+
+ d->fullScreen = false;
+ }
+ else // go to fullscreen
+ {
+ // 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 ( !d->fullScreenAction->isPlugged(toolBar) )
+ {
+ d->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(d->zoomFitToWindowAction);
+
+ if (d->fullScreen)
+ {
+ d->leftSidebar->restore();
+ d->rightSidebar->restore();
+ }
+ else
+ {
+ d->leftSidebar->backup();
+ d->rightSidebar->backup();
+ }
+
+ showFullScreen();
+ d->fullScreen = true;
+ }
+}
+
+void LightTableWindow::slotEscapePressed()
+{
+ if (d->fullScreen)
+ d->fullScreenAction->activate();
+}
+
+void LightTableWindow::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 LightTableWindow::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 LightTableWindow::plugActionAccel(TDEAction* action)
+{
+ if (!action)
+ return;
+
+ d->accelerators->insert(action->text(),
+ action->text(),
+ action->whatsThis(),
+ action->shortcut(),
+ action,
+ TQ_SLOT(activate()));
+}
+
+void LightTableWindow::unplugActionAccel(TDEAction* action)
+{
+ d->accelerators->remove(action->text());
+}
+
+void LightTableWindow::slotDonateMoney()
+{
+ TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation");
+}
+
+void LightTableWindow::slotContribute()
+{
+ TDEApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=contrib");
+}
+
+void LightTableWindow::slotEditKeys()
+{
+ KKeyDialog dialog(true, this);
+ dialog.insert( actionCollection(), i18n( "General" ) );
+ dialog.configure();
+}
+
+void LightTableWindow::slotConfToolbars()
+{
+ saveMainWindowSettings(TDEGlobal::config(), "LightTable Settings");
+ KEditToolbar dlg(factory(), this);
+
+ connect(&dlg, TQ_SIGNAL(newToolbarConfig()),
+ this, TQ_SLOT(slotNewToolbarConfig()));
+
+ dlg.exec();
+}
+
+void LightTableWindow::slotNewToolbarConfig()
+{
+ applyMainWindowSettings(TDEGlobal::config(), "LightTable Settings");
+}
+
+void LightTableWindow::slotSetup()
+{
+ Setup setup(this, 0);
+
+ if (setup.exec() != TQDialog::Accepted)
+ return;
+
+ kapp->config()->sync();
+
+ applySettings();
+}
+
+void LightTableWindow::slotLeftZoomFactorChanged(double zoom)
+{
+ double h = (double)ThumbnailSize::Huge;
+ double s = (double)ThumbnailSize::Small;
+ double zmin = d->previewView->leftZoomMin();
+ double zmax = d->previewView->leftZoomMax();
+ double b = (zmin-(zmax*s/h))/(1-s/h);
+ double a = (zmax-b)/h;
+ int size = (int)((zoom - b) /a);
+
+ d->leftZoomBar->setZoomSliderValue(size);
+ d->leftZoomBar->setZoomTrackerText(i18n("zoom: %1%").arg((int)(zoom*100.0)));
+
+ d->leftZoomBar->setEnableZoomPlus(true);
+ d->leftZoomBar->setEnableZoomMinus(true);
+
+ if (d->previewView->leftMaxZoom())
+ d->leftZoomBar->setEnableZoomPlus(false);
+
+ if (d->previewView->leftMinZoom())
+ d->leftZoomBar->setEnableZoomMinus(false);
+}
+
+void LightTableWindow::slotRightZoomFactorChanged(double zoom)
+{
+ double h = (double)ThumbnailSize::Huge;
+ double s = (double)ThumbnailSize::Small;
+ double zmin = d->previewView->rightZoomMin();
+ double zmax = d->previewView->rightZoomMax();
+ double b = (zmin-(zmax*s/h))/(1-s/h);
+ double a = (zmax-b)/h;
+ int size = (int)((zoom - b) /a);
+
+ d->rightZoomBar->setZoomSliderValue(size);
+ d->rightZoomBar->setZoomTrackerText(i18n("zoom: %1%").arg((int)(zoom*100.0)));
+
+ d->rightZoomBar->setEnableZoomPlus(true);
+ d->rightZoomBar->setEnableZoomMinus(true);
+
+ if (d->previewView->rightMaxZoom())
+ d->rightZoomBar->setEnableZoomPlus(false);
+
+ if (d->previewView->rightMinZoom())
+ d->rightZoomBar->setEnableZoomMinus(false);
+}
+
+void LightTableWindow::slotToggleSyncPreview()
+{
+ d->previewView->setSyncPreview(d->syncPreviewAction->isChecked());
+}
+
+void LightTableWindow::slotToggleOnSyncPreview(bool t)
+{
+ d->syncPreviewAction->setEnabled(t);
+
+ if (!t)
+ {
+ d->syncPreviewAction->setChecked(false);
+ }
+ else
+ {
+ if (d->autoSyncPreview)
+ d->syncPreviewAction->setChecked(true);
+ }
+}
+
+void LightTableWindow::slotBackward()
+{
+ ThumbBarItem* curr = d->barView->currentItem();
+ ThumbBarItem* last = d->barView->lastItem();
+ if (curr)
+ {
+ if (curr->prev())
+ d->barView->setSelected(curr->prev());
+ else
+ d->barView->setSelected(last);
+ }
+}
+
+void LightTableWindow::slotForward()
+{
+ ThumbBarItem* curr = d->barView->currentItem();
+ ThumbBarItem* first = d->barView->firstItem();
+ if (curr)
+ {
+ if (curr->next())
+ d->barView->setSelected(curr->next());
+ else
+ d->barView->setSelected(first);
+ }
+}
+
+void LightTableWindow::slotFirst()
+{
+ d->barView->setSelected( d->barView->firstItem() );
+}
+
+void LightTableWindow::slotLast()
+{
+ d->barView->setSelected( d->barView->lastItem() );
+}
+
+void LightTableWindow::slotToggleNavigateByPair()
+{
+ d->barView->setNavigateByPair(d->navigateByPairAction->isChecked());
+ d->previewView->setNavigateByPair(d->navigateByPairAction->isChecked());
+ slotItemSelected(d->barView->currentItemImageInfo());
+}
+
+void LightTableWindow::slotRawCameraList()
+{
+ RawCameraDlg dlg(this);
+ dlg.exec();
+}
+
+void LightTableWindow::slotThemeChanged()
+{
+ TQStringList themes(ThemeEngine::instance()->themeNames());
+ int index = themes.findIndex(AlbumSettings::instance()->getCurrentTheme());
+ if (index == -1)
+ index = themes.findIndex(i18n("Default"));
+
+ d->themeMenuAction->setCurrentItem(index);
+}
+
+void LightTableWindow::slotChangeTheme(const TQString& theme)
+{
+ AlbumSettings::instance()->setCurrentTheme(theme);
+ ThemeEngine::instance()->slotChangeTheme(theme);
+}
+
+void LightTableWindow::slotShowMenuBar()
+{
+ if (menuBar()->isVisible())
+ menuBar()->hide();
+ else
+ menuBar()->show();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/lighttable/lighttablewindow.h b/src/utilities/lighttable/lighttablewindow.h
new file mode 100644
index 00000000..f080e2d1
--- /dev/null
+++ b/src/utilities/lighttable/lighttablewindow.h
@@ -0,0 +1,162 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-03-05
+ * Description : digiKam light table GUI
+ *
+ * Copyright (C) 2007-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 LIGHTTABLEWINDOW_H
+#define LIGHTTABLEWINDOW_H
+
+// TQt includes.
+
+#include <tqstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <tdemainwindow.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+
+class TDEAction;
+
+namespace Digikam
+{
+
+class SlideShowSettings;
+class ThumbBarItem;
+class LightTableWindowPriv;
+
+class LightTableWindow : public TDEMainWindow
+{
+ TQ_OBJECT
+
+
+public:
+
+ ~LightTableWindow();
+
+ static LightTableWindow *lightTableWindow();
+ static bool lightTableWindowCreated();
+
+ void loadImageInfos(const ImageInfoList &list, ImageInfo *imageInfoCurrent, bool addTo);
+ void setLeftRightItems(const ImageInfoList &list, bool addTo);
+ void applySettings();
+ void refreshView();
+
+signals:
+
+ void signalFileDeleted(const KURL&);
+
+public slots:
+
+ void slotItemsUpdated(const KURL::List&);
+
+private:
+
+ void closeEvent(TQCloseEvent* e);
+ void setupActions();
+ void setupConnections();
+ void setupUserArea();
+ void setupStatusBar();
+ void setupAccelerators();
+ void slideShow(bool startWithCurrent, SlideShowSettings& settings);
+ void showToolBars();
+ void hideToolBars();
+ void plugActionAccel(TDEAction* action);
+ void unplugActionAccel(TDEAction* action);
+ void readSettings();
+ void writeSettings();
+ void refreshStatusBar();
+
+ LightTableWindow();
+
+private slots:
+
+ void slotBackward();
+ void slotForward();
+ void slotFirst();
+ void slotLast();
+
+ void slotSetItemLeft();
+ void slotSetItemRight();
+ void slotSetItemOnLeftPanel(ImageInfo*);
+ void slotSetItemOnRightPanel(ImageInfo*);
+ void slotLeftDroppedItems(const ImageInfoList&);
+ void slotRightDroppedItems(const ImageInfoList&);
+
+ void slotLeftPanelLeftButtonClicked();
+ void slotRightPanelLeftButtonClicked();
+
+ void slotLeftPreviewLoaded(bool);
+ void slotRightPreviewLoaded(bool);
+
+ void slotLeftZoomFactorChanged(double);
+ void slotRightZoomFactorChanged(double);
+
+ void slotToggleOnSyncPreview(bool);
+ void slotToggleSyncPreview();
+ void slotToggleNavigateByPair();
+
+ void slotEditItem();
+ void slotEditItem(ImageInfo*);
+
+ void slotDeleteItem();
+ void slotDeleteItem(ImageInfo*);
+
+ void slotRemoveItem();
+ void slotRemoveItem(ImageInfo*);
+
+ void slotItemSelected(ImageInfo*);
+ void slotClearItemsList();
+
+ void slotThumbbarDroppedItems(const ImageInfoList&);
+
+ void slotZoomTo100Percents();
+ void slotFitToWindow();
+
+ void slotProgressBarCancelButtonPressed();
+ void slotToggleSlideShow();
+ void slotToggleFullScreen();
+ void slotEscapePressed();
+ void slotDonateMoney();
+ void slotContribute();
+ void slotRawCameraList();
+ void slotEditKeys();
+ void slotConfToolbars();
+ void slotShowMenuBar();
+ void slotNewToolbarConfig();
+ void slotSetup();
+
+ void slotThemeChanged();
+ void slotChangeTheme(const TQString& theme);
+
+private:
+
+ LightTableWindowPriv *d;
+
+ static LightTableWindow *m_instance;
+};
+
+} // namespace Digikam
+
+#endif /* LIGHTTABLEWINDOW_H */
diff --git a/src/utilities/lighttable/lighttablewindowprivate.h b/src/utilities/lighttable/lighttablewindowprivate.h
new file mode 100644
index 00000000..a96e0b08
--- /dev/null
+++ b/src/utilities/lighttable/lighttablewindowprivate.h
@@ -0,0 +1,158 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-03-05
+ * Description : digiKam light table GUI
+ *
+ * Copyright (C) 2007-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 <tqsplitter.h>
+
+// KDE includes.
+
+#include <tdeaction.h>
+#include <tdeaccel.h>
+
+// Local includes.
+
+#include "imagepropertiessidebardb.h"
+#include "statusprogressbar.h"
+#include "statuszoombar.h"
+#include "lighttableview.h"
+#include "lighttablebar.h"
+
+namespace Digikam
+{
+
+class LightTableWindowPriv
+{
+
+public:
+
+ LightTableWindowPriv()
+ {
+ autoLoadOnRightPanel = true;
+ autoSyncPreview = true;
+ fullScreenHideToolBar = false;
+ fullScreen = false;
+ removeFullScreenButton = false;
+ cancelSlideShow = false;
+ star0 = 0;
+ star1 = 0;
+ star2 = 0;
+ star3 = 0;
+ star4 = 0;
+ star5 = 0;
+ accelerators = 0;
+ leftSidebar = 0;
+ rightSidebar = 0;
+ previewView = 0;
+ barView = 0;
+ hSplitter = 0;
+ vSplitter = 0;
+ syncPreviewAction = 0;
+ clearListAction = 0;
+ setItemLeftAction = 0;
+ setItemRightAction = 0;
+ editItemAction = 0;
+ removeItemAction = 0;
+ fileDeleteAction = 0;
+ slideShowAction = 0;
+ fullScreenAction = 0;
+ donateMoneyAction = 0;
+ zoomFitToWindowAction = 0;
+ zoomTo100percents = 0;
+ zoomPlusAction = 0;
+ zoomMinusAction = 0;
+ statusProgressBar = 0;
+ leftZoomBar = 0;
+ rightZoomBar = 0;
+ forwardAction = 0;
+ backwardAction = 0;
+ firstAction = 0;
+ lastAction = 0;
+ navigateByPairAction = 0;
+ rawCameraListAction = 0;
+ themeMenuAction = 0;
+ contributeAction = 0;
+ showMenuBarAction = 0;
+ }
+
+ bool autoLoadOnRightPanel;
+ bool autoSyncPreview;
+ bool fullScreenHideToolBar;
+ bool fullScreen;
+ bool removeFullScreenButton;
+ bool cancelSlideShow;
+
+ TQSplitter *hSplitter;
+ TQSplitter *vSplitter;
+
+ // Rating actions.
+ TDEAction *star0;
+ TDEAction *star1;
+ TDEAction *star2;
+ TDEAction *star3;
+ TDEAction *star4;
+ TDEAction *star5;
+
+ TDEAction *forwardAction;
+ TDEAction *backwardAction;
+ TDEAction *firstAction;
+ TDEAction *lastAction;
+
+ TDEAction *setItemLeftAction;
+ TDEAction *setItemRightAction;
+ TDEAction *clearListAction;
+ TDEAction *editItemAction;
+ TDEAction *removeItemAction;
+ TDEAction *fileDeleteAction;
+ TDEAction *slideShowAction;
+ TDEAction *donateMoneyAction;
+ TDEAction *contributeAction;
+ TDEAction *zoomPlusAction;
+ TDEAction *zoomMinusAction;
+ TDEAction *zoomTo100percents;
+ TDEAction *zoomFitToWindowAction;
+ TDEAction *rawCameraListAction;
+
+ TDESelectAction *themeMenuAction;
+
+ TDEToggleAction *fullScreenAction;
+ TDEToggleAction *syncPreviewAction;
+ TDEToggleAction *navigateByPairAction;
+ TDEToggleAction *showMenuBarAction;
+
+ TDEAccel *accelerators;
+
+ LightTableBar *barView;
+
+ LightTableView *previewView;
+
+ StatusZoomBar *leftZoomBar;
+ StatusZoomBar *rightZoomBar;
+
+ StatusProgressBar *statusProgressBar;
+
+ ImagePropertiesSideBarDB *leftSidebar;
+ ImagePropertiesSideBarDB *rightSidebar;
+};
+
+} // namespace Digikam
diff --git a/src/utilities/lighttable/lighttablewindowui.rc b/src/utilities/lighttable/lighttablewindowui.rc
new file mode 100644
index 00000000..ae7ce721
--- /dev/null
+++ b/src/utilities/lighttable/lighttablewindowui.rc
@@ -0,0 +1,83 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<gui version="24" name="lighttablewindow" >
+
+<MenuBar>
+
+ <Menu name="File" ><text>&amp;File</text>
+ <Action name="lighttable_first" />
+ <Action name="lighttable_backward" />
+ <Action name="lighttable_forward" />
+ <Action name="lighttable_last" />
+ <Separator/>
+ <Action name="lighttable_setitemleft" />
+ <Action name="lighttable_setitemright" />
+ <Action name="lighttable_edititem" />
+ <Separator/>
+ <Action name="lighttable_removeitem" />
+ <Action name="lighttable_clearlist" />
+ <Separator/>
+ <Action name="lighttable_filedelete" />
+ <Separator/>
+ <Action name="lighttable_close" />
+ </Menu>
+
+ <Menu name="View" ><text>&amp;View</text>
+ <Action name="lighttable_fullscreen" />
+ <Action name="lighttable_slideshow" />
+ <Separator/>
+ <Action name="lighttable_syncpreview" />
+ <Action name="lighttable_navigatebypair" />
+ <Separator/>
+ <Action name="lighttable_zoomplus" />
+ <Action name="lighttable_zoomminus" />
+ <Action name="lighttable_zoomto100percents" />
+ <Action name="lighttable_zoomfit2window" />
+ </Menu>
+
+ <Menu name="help" ><text>&amp;Help</text>
+ <Action name="lighttable_rawcameralist"/>
+ <Action name="lighttable_donatemoney" />
+ <Action name="lighttable_contribute" />
+ </Menu>
+
+ <Merge/>
+
+ <Menu name="settings" noMerge="1"><Text>&amp;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="lighttable_first" />
+ <Action name="lighttable_backward" />
+ <Action name="lighttable_forward" />
+ <Action name="lighttable_last" />
+ <Separator/>
+ <Action name="lighttable_zoomplus" />
+ <Action name="lighttable_zoomminus" />
+ <Action name="lighttable_zoomfit2window" />
+ <Separator/>
+ <Action name="lighttable_setitemleft" />
+ <Action name="lighttable_setitemright" />
+ <Action name="lighttable_syncpreview" />
+ <Action name="lighttable_navigatebypair" />
+ <Separator/>
+ <Action name="lighttable_fullscreen" />
+ <Action name="lighttable_slideshow" />
+ <Merge />
+ <WeakSeparator/>
+ <Action name="logo_action" />
+</ToolBar>
+
+<ActionProperties/>
+
+</gui>
diff --git a/src/utilities/scripts/Makefile.am b/src/utilities/scripts/Makefile.am
new file mode 100644
index 00000000..198f6c0d
--- /dev/null
+++ b/src/utilities/scripts/Makefile.am
@@ -0,0 +1,4 @@
+####### This script name should probably be more 'namespaced'. Think about distros putting everything in /usr/bin...
+bin_SCRIPTS = digitaglinktree
+man_MANS = digitaglinktree.1
+
diff --git a/src/utilities/scripts/digitaglinktree b/src/utilities/scripts/digitaglinktree
new file mode 100644
index 00000000..8d0d12c9
--- /dev/null
+++ b/src/utilities/scripts/digitaglinktree
@@ -0,0 +1,568 @@
+#!/usr/bin/perl
+
+$version="1.6.3";
+# Author: Rainer Krienke, krienke@uni-koblenz.de
+#
+# Description:
+#
+# This script will create a linktree for all photos in a digikam
+# database that have tags set on them. Tags are used in digikam to
+# create virtual folders containing images that all have one or more tags.
+# Since other programs do not know about these virtual folders this script
+# maps these virtual folders into the filesystem by creating a directory
+# for each tag name and then linking from the tag dir to the tagged image in the
+# digikam photo directory.
+#
+# Call this script like:
+# digitaglinktree -r /home/user/photos -l /home/user/photos/tags \
+# -d /home/user/photos/digikam.db
+
+
+# Changes
+#
+# 1.1->1.2:
+# Support for hierarchical tags was added. The script can either create
+# a hierarchical directory structure for these tags (default) or treat them
+# as tags beeing on the same level resulting in a flat dir structure (-f)
+#
+# 1.2->1.3
+# Added support for multiple tags assigned to one photo. Up to now only
+# one tag (the last one found) was used.
+#
+# 1.3->1.4
+# Bug fix, links with same name in one tag directory were no resolved
+# which led to "file exists" errors when trying to create the symbolic link.
+#
+# 1.4-> 1.6, 2006/08/03
+# Added an option (-A) to archive photos and tag structure in an extra directory
+# 1.6-> 1.6.1 2006/08/15
+# Added an option (-C) for archive mode (-A). Added more information to
+# the manual page.
+# 1.6.1-> 1.6.2 2008/11/24 (Peter Muehlenpfordt, muehlenp@gmx.de)
+# Bug fix, subtags with the same name in different branches were merged
+# into one directory.
+# 1.6.2 -> 1.6.3 2008/11/25 Rainer Krienke, krienke@uni-koblenz.de
+# Fixed a bug that shows in some later perl interpreter versions when
+# accessing array references with $# operator. If $r is a ref to an array
+# then $#{@r} was ok in the past but now $#{r] is correct, perhaps it was
+# always correct and the fact that $#{@r} worked was just good luck ....
+#
+
+
+# ---------------------------------------------------------------------------
+# LICENSE:
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# ---------------------------------------------------------------------------
+
+
+use Getopt::Std;
+use File::Spec;
+use File::Path;
+
+# Please adapt the sqlite version to your digikam version.
+# Do not forget to also install the correct sqlite version:
+# Digikam 0.7x needs sqlite2
+# Digikam 0.8x needs sqlite3
+
+#$SQLITE="/usr/bin/sqlite";
+$SQLITE="/usr/bin/sqlite3";
+$archiveDirPhotos="Photos";
+$archiveDirLinks="Tags";
+
+#
+$scriptAuthor="krienke@uni-koblenz.de";
+
+#
+# check if sqlite can open the database
+#
+sub checkVersion{
+ my($database)=shift;
+ my(@data, $res);
+
+ if( ! -r $SQLITE ){
+ warn "Cannot start sqlite executable \"$SQLITE\". \n",
+ "Please check if the executable searched is really installed.\n",
+ "You should also check if the installed version is correct. The name\n",
+ "of the executable to search for can be set in the head of this script.\n\n";
+ exit(1);
+ }
+
+ @data=`$SQLITE $database .tables 2>&1`; # Try to get the tables information
+
+ if( $? != 0 || grep(/Error:\s*file is encrypted/i, @data) != 0 ){
+ warn "Cannot open database \"$database\". Have you installed a current\n",
+ "version of sqlite? Depending on you digikam version you have to \n",
+ "install and use sqlite2 (for digikam 0.7x) or sqlite3 (for digikam >= 0.8 )\n",
+ "Please install the correct version and set the SQLITE variable in the\n",
+ "script head accordingly \n\n";
+ exit(1);
+ }
+
+ $res=grep(/TagsTree/, @data);
+ if( $res==0 ){
+ return("7") # digikam version 0.7
+ }else{
+ return("8"); # digikam version 0.8
+ }
+}
+
+
+#
+# Get all images that have tags from digikam database
+# refPathNames will contain all photos including path having tags
+# The key in refPathNames is the path, value is photos name
+#
+sub getTaggedImages{
+ my($refImg, $database, $rootDir, $refPaths, $refPathNames)=@_;
+ my($i, $image, $path, $tag, $status, $id, $pid, $tmp);
+ my($sqliteCmd, @data, $vers, @tags, %tagPath, $tagCount, $refTag);
+
+ $vers=checkVersion($database); # Find out version of digikam
+
+ # Get tag information from database
+ $sqliteCmd="\"select id,pid,name from tags;\"";
+
+ @data=`$SQLITE $database $sqliteCmd`;
+ $status=$?;
+ if( $status == 0 ){
+ foreach $i ( @data ){
+ chomp($i);
+ ($id, $pid, $tag)=split(/\|/, $i);
+ # map tag id data into array
+ $tags[$id]->{"tag"}="$tag";
+ $tags[$id]->{"pid"}="$pid";
+ }
+
+ # Now build up the path for tags having parents
+ # Eg: a tag people might have a subtag friends: people
+ # |->friends
+ # We want to find out the complete path for the subtag. For friends this
+ # would be the path "people/friends". Images with tag friends would then be
+ # linked in the directory <tagsroot>/people/friends/
+ for($i=0; $i<=$#tags; $i++){
+ $pid=$tags[$i]->{"pid"}; # Get parent tag id of current tag
+ $tag=$tags[$i]->{"tag"}; # Start constructing tag path
+ if( $pid == 0 ){
+ $tagPath{$i}=$tag;
+ next;
+ }
+
+ while( $pid != 0){
+ $tag=$tags[$pid]->{"tag"} . "/$tag"; # add parents tag name to path
+ $pid=$tags[$pid]->{"pid"}; # look if parent has another parent
+ }
+ # Store path constructed
+ $tagPath{$i}=$tag;
+ #warn "+ $tag \n";
+ }
+ }else{
+ print "Error running SQL-Command \"$sqliteCmd\" on database \"$database\"\n";
+ }
+
+
+ if( $vers==7 ){
+ # SQL to get all tagged images from digikam DB with names of tags
+ $sqliteCmd="\"select ImageTags.name,Albums.Url,ImageTags.tagid from " .
+ " ImageTags, Albums,Tags " .
+ " where Albums.id = ImageTags.dirid; \"";
+
+ }elsif( $vers == 8 ){
+ # SQL to get all tagged images from digikam DB with names of tags
+ $sqliteCmd="\"select Images.name,Albums.url,ImageTags.tagid from" .
+ " Images,Albums,ImageTags where " .
+ " Images.dirid=Albums.id AND Images.id=ImageTags.imageid; \"";
+ }else{
+ warn "Unsupported digikam database version. Contact $scriptAuthor \n\n";
+ exit(1);
+ }
+
+ @data=`$SQLITE $database $sqliteCmd`;
+ $status=$?;
+ if( $status == 0 ){
+ foreach $i ( @data ){
+ chomp($i);
+ ($image, $path, $tag)=split(/\|/, $i);
+ $refPaths->{"$rootDir$path"}=1;
+ $refPathNames->{"$rootDir$path/$image"}=1;
+
+ $tmp=$path;
+ #warn "- $rootDir, $path, $image \n";
+ # Enter all subpaths in $path as defined too
+ do{
+ $tmp=~s/\/[^\/]+$//;
+ $refPaths->{"$rootDir$tmp"}=1;
+ } while (length($tmp));
+
+
+ $refImg->{"$path/$image"}->{"path"}=$path;
+ $refImg->{"$path/$image"}->{"image"}=$image;
+ $refTag=$refImg->{"$path/$image"}->{"tag"};
+ #
+ # One image can have several tags assigned. So we manage
+ # a list of tags for each image
+ $tagCount=$#{$refTag}+1;
+ # The tags name
+ $refImg->{"$path/$image"}->{"tag"}->[$tagCount]=$tag;
+ # tags path for sub(sub+)tags
+ $refImg->{"$path/$image"}->{"tagpath"}->[$tagCount]=$tagPath{$tag};
+ }
+ }else{
+ print "Error running SQL-Command \"$sqliteCmd\" on database \"$database\"\n";
+ }
+
+ return($status);
+}
+
+
+#
+# Create a directory with tag-subdirectories containing links to photos having
+# tags set. Links can be absolute or relative as well as hard or soft.
+#
+sub createLinkTree{
+ my($refImages)=shift;
+ my($photoRootDir, $linktreeRootDir, $opt_flat, $opt_absolute, $linkMode)=@_;
+ my( $i, $j, $cmd, $path, $image, $tag, $qpath, $qtag, $qimage, $linkName,
+ $tmp, $ret, $sourceDir, $destDir);
+ my($qtagPath, $relPath);
+
+ if( -d "$linktreeRootDir" ){
+ # Remove old backuplinktree
+ system("rm -rf ${linktreeRootDir}.bak");
+ if( $? ){
+ die "Cannot run \"rm -rf ${linktreeRootDir}.bak\"\n";
+ }
+
+ # rename current tree to .bak
+ $ret=rename("$linktreeRootDir", "${linktreeRootDir}.bak" );
+ if( !$ret ){
+ die "Cannot rename \"$linktreeRootDir\" to \"${linktreeRootDir}.bak\"\n";
+ }
+ }
+
+ # Create new to level directory to hold linktree
+ $ret=mkdir("$linktreeRootDir");
+ if( !$ret ){
+ die "Cannot mkdir \"$linktreeRootDir\"\n";
+ }
+ # Iterate over all tagged images and create links
+ foreach $i (keys(%$refImages)){
+ # Check that the images in the linktrees themselves are
+ # ignored in the process of link creation. If we do not do this
+ # we might get into trouble when the linktree root is inside the
+ # digikam root dir and so the image links inside the liktree directory
+ # are indexed by digikam.
+ next if( -l "${photoRootDir}$i" );
+
+ $path=$refImages->{$i}->{"path"};
+ $image=$refImages->{$i}->{"image"};
+ #$qimage=quotemeta($image);
+ #$qpath=quotemeta($path);
+
+ # Handle all of the tags for the current photo
+ for( $j=0; $j<=$#{$refImages->{$i}->{"tag"}}; $j++){
+ $tag=$refImages->{$i}->{"tagpath"}->[$j];
+ #$qtagPath=quotemeta($tagPath);
+
+ # For tags that have subtags there is a path defined in qtagPath
+ # describing the parentrelationship as directory path like "friends/family/brothers"
+ # If it is defined we want to use this path instead of the flat tag name like "brothers"
+ # Doing so results in a directory hirachy that maps the tags parent relationships
+ # into the filesystem.
+ if( $opt_flat ){
+ # For flat option just use the last subdirectory
+ $tag=~s/^.+\///;
+ }
+ # Create subdirectories needed
+ if( ! -d "${linktreeRootDir}/$tag" ){
+ $ret=mkpath("${linktreeRootDir}/$tag", 0, 0755);
+
+ if( !$ret ){
+ die "Cannot mkdir \"${linktreeRootDir}/$tag\"\n";
+ }
+ }
+ # Avoid conflicts for images with the same name in one tag directory
+ $linkName=$image;
+ $tmp=$image;
+ while( -r "${linktreeRootDir}/$tag/$tmp" ){
+ $linkName="_" . $linkName;
+ $tmp="_" . $tmp;
+ }
+
+ if(length($opt_absolute)){
+ # Create link
+ $sourceDir="${photoRootDir}$path/$image";
+ $destDir="${linktreeRootDir}/$tag/$linkName";
+ }else{
+ # Get relative path from absolute one
+ # $rel=File::Spec->abs2rel( $path, $base ) ;
+ $relPath="";
+ $relPath=File::Spec->abs2rel("${photoRootDir}$path", "${linktreeRootDir}/$tag" ) ;
+ if( !length($relPath)){
+ die "Cannot create relative path from \"${linktreeRootDir}/$tag\" to \"${photoRootDir}$path\" . Abort.\n";
+ }
+ # Create link
+ #print "-> $relPath\n";
+ $sourceDir="$relPath/$image";
+ $destDir="${linktreeRootDir}/$tag/$linkName";
+ }
+
+ if( $linkMode eq "symbolic" ){
+ $ret=symlink($sourceDir, $destDir);
+ if( !$ret ){
+ $ret="$!";
+ warn "Warning: Failed symbolic linking \"$sourceDir\" to \"$destDir\": ",
+ "\"$ret\"\n";
+ }
+ }elsif( $linkMode eq "hard" ){
+ $ret=link($sourceDir, $destDir);
+ if( !$ret ){
+ $ret="$!";
+ warn "Warning: Failed hard linking \"$sourceDir\" to \"$destDir\": ",
+ "\"$ret\"\n";
+ }
+ }else{
+ die "$0: Illegal linkMode: \"$linkMode\". Abort.\n";
+ }
+
+ }# for
+ }
+}
+
+
+
+#
+# Clone a directory into another directory.
+# source and destination have to exist
+# Files in $srcDir will symbolically or hard linked
+# to the $cloneDir according to $cloneMode which can
+# be symbolic for symbolic links or hard for hardlinks
+# refPathNames contains path for all photos having tags set
+#
+sub cloneDir{
+ local($srcDir, $cloneDir, $linkMode, $cloneMode, $refPaths, $refPathNames)=@_;
+ local(@entries, $ki, $path, $name, $ret);
+
+ # Read directory entries
+ opendir( DIR, $srcDir ) || warn "Cannot read directory $srcDir \n";
+ local(@entries)=readdir(DIR);
+ closedir(DIR);
+
+ foreach $k (@entries){
+ next if( $k eq '.' );
+ next if( $k eq '..');
+ next if( $k =~ /digikam.*\.db/o );
+
+ #warn "-> $srcDir, $k, $cloneDir\n";
+ # Recurse into directories
+ if( -d "$srcDir/$k" ){
+ # if cloneMode is "minimal" then only clone directories and files
+ # with photos that have tags set.
+ if( $cloneMode ne "minimal" ||
+ defined($refPaths->{"$srcDir/$k"}) ){
+ #warn "* $srcDir/$k defined \n";
+ mkdir("$cloneDir/$k", 0755);
+ if( $? ){
+ die "Cannot run \"mkdir $cloneDir/$k\"\n";
+ }
+ cloneDir("$srcDir/$k", "$cloneDir/$k", $linkMode,
+ $cloneMode, $refPaths, $refPathNames );
+ }
+ }else{
+ # if cloneMode is "minimal" then only clone directories and files
+ # with photos that have tags set.
+ if( $cloneMode ne "minimal" ||
+ defined($refPathNames->{"$srcDir/$k"}) ){
+ # link files
+ if( $linkMode eq "symbolic" ){
+ $ret=symlink( "$srcDir/$k", "$cloneDir/$k");
+ if( !$ret ){
+ $ret="$!";
+ warn "Warning: In cloning failed symbolic linking \"$srcDir/$k\" to \"$cloneDir/$k\": ",
+ "\"$ret\"\n";
+ }
+ }elsif( $linkMode eq "hard" ){
+ $ret=link( "$srcDir/$k", "$cloneDir/$k");
+ if( !$ret ){
+ $ret="$!";
+ warn "Warning: In cloning failed hard linking \"$srcDir/$k\" to \"$cloneDir/$k\": ",
+ "\"$ret\"\n";
+ }
+ }else{
+ die "$0: Illegal cloneLinkMode: $linkMode set. Aborting.\n";
+ }
+ }
+ }
+ }
+}
+
+
+#
+# Manage cloning of a complete directory. If the clone directory exists
+# a .bak will be created
+# Files will be linked (hard/symbolic) according to cloneLinkMode which
+# should be "symbolic" or "hard"
+# cloneMode can "minimal" or anything else. minimal means only to clone
+# those files and directories that have tags set. Anything else means
+# to clone the whole photo tree with all files
+#
+sub runClone{
+ my($rootDir, $cloneDir, $photoDir, $cloneMode, $cloneLinkMode,
+ $refPaths, $refPathNames)=@_;
+ my($ret);
+ my($dev_r,$dev_A, $ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks);
+
+ if( -d "$cloneDir" ){
+ # Remove old backuplinktree
+ system("rm -rf ${cloneDir}.bak");
+ if( $? ){
+ die "Cannot run \"rm -rf ${cloneDir}.bak\"\n";
+ }
+
+ # rename current tree to .bak
+ $ret=rename("$cloneDir", "${cloneDir}.bak" );
+ if( !$ret ){
+ die "Cannot rename \"$cloneDir\" to \"${cloneDir}.bak\"\n";
+ }
+ }
+ $ret=mkdir("$cloneDir", 0755);
+ if( !$ret ){
+ die "Cannot run \"mkdir $cloneDir\"\n";
+ }
+ $ret=mkdir("$cloneDir/$photoDir", 0755);
+ if( !$ret ){
+ die "Cannot run \"mkdir $cloneDir/$photoDir\"\n";
+ }
+
+ # Check if root and archive dir are on same filesystem
+ ($dev_r,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = stat($rootDir);
+ ($dev_A,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = stat($cloneDir);
+ #
+ if( $dev_r != $dev_A ){
+ warn "Error: \"$rootDir\" and \"$cloneDir\" are not on the same filesystem. Please select ",
+ "an archive directory on the same filesystem like digikams root directory! Abort.\n";
+ exit 1;
+ }
+
+ # Create clone of all entries in $rootDir into $clonedir
+ cloneDir($rootDir, "$cloneDir/$photoDir", $cloneLinkMode,
+ $cloneMode, $refPaths, $refPathNames);
+}
+
+
+#
+# print out usage
+#
+sub usage{
+ print "$0 -r <photoroot> \n",
+ " -l <taglinkdir> | -A <archivedir> \n",
+ " -d <digikamdatabasefile> \n",
+ " [-H|-f|-a|-v|-C] \n",
+ " -r <rootdir> path to digikams root directory containing all photos\n",
+ " -l <tagdir> path to directory where the tag directory structure with \n",
+ " links to the original images should be created \n",
+ " -d <dbfile> full path to the digikam database file \n",
+ " -A <ardir> Create selfcontained archive of photos and tags in directory\n",
+ " ardir. rootdir and arDir have to be on the *same* filesystem!\n",
+ " -C If -A <archdir> was given this option will put hardlinks of all\n",
+ " photos in the \"$archiveDirPhotos\" directory not only of those with tags.\n",
+ " -a Create absolute symbolic links instead of relative ones \n",
+ " -H Use hard links instead of symbolic links in linktree. \n",
+ " -f If there are hierarchical tags (tags that have subtags) \n",
+ " create a flat tag directory hierarchy. So directories for\n",
+ " subtags are at the same directory level like their parent tags\n",
+ " -h Print this help \n",
+ " -v Print scripts version number \n";
+
+ print "Exit.\n\n";
+ exit 1;
+}
+
+
+# ------------------------------------------------------------------
+# main
+# ------------------------------------------------------------------
+$ret=getopts('HhCar:l:d:A:fv');
+
+if( defined($opt_h) ){
+ usage(0);
+}
+
+if( defined($opt_v) ){
+ print "Version: $version\n";
+ exit 0;
+}
+
+usage if( !length($opt_r) || (!length($opt_l) && ! length($opt_A))
+ || !length($opt_d) );
+
+$opt_f=0 if( ! length($opt_f) );
+
+if( ! -d $opt_r ){
+ print "Invalid digikam photoroot directory \"$opt_r\". Exit.\n";
+ exit 1;
+}
+if( ! -f $opt_d ){
+ print "Digikam database \"$opt_d\" not found. Exit.\n";
+ exit 1;
+}
+
+# Remove trailing /
+$opt_r=~s/\/$//;
+$opt_l=~s/\/$//;
+#
+$rootDir=$opt_r;
+$linkDir=$opt_l;
+
+if( length($opt_C) ){
+ $cloneMode="full"; # Clone all files/dirs
+}else{
+ $cloneMode="minimal"; # Only clone dirs and files haviong tags not all files
+}
+
+if( length($opt_H) ){
+ $linkMode="hard"; # type of link from linktree to phototree
+}else{
+ $linkMode="symbolic"; # type of link from linktree to phototree
+}
+
+# Extract data needed from database
+$ret=getTaggedImages(\%images, $opt_d, $opt_r, \%paths, \%pathNames);
+
+# Handle Archiving photos and tag structure
+# digikams photo dir will be clone as a whole by using
+# either soft or hard links ($cloneMode)
+if( length($opt_A) ){
+ #
+ runClone($opt_r, $opt_A, $archiveDirPhotos, $cloneMode, "hard", \%paths, \%pathNames);
+ $rootDir="$opt_A/$archiveDirPhotos";
+ $linkDir="$opt_A/$archiveDirLinks";
+}
+
+if( !$ret && ( length($opt_l) || length($opt_A)) ){
+ # When doing hard links we always use absolute linking
+ if( $linkMode eq "hard" ){
+ warn "Will use absolute hard links for linktree in archive mode...\n" if( !length($opt_a) );
+ $opt_a="1";
+ }
+
+ # Create the link trees for all tagged images
+ createLinkTree(\%images, $rootDir, $linkDir, $opt_f, $opt_a, $linkMode);
+}
diff --git a/src/utilities/scripts/digitaglinktree.1 b/src/utilities/scripts/digitaglinktree.1
new file mode 100644
index 00000000..fdfe9e09
--- /dev/null
+++ b/src/utilities/scripts/digitaglinktree.1
@@ -0,0 +1,182 @@
+.\" -*-Nroff-*-
+.\"
+.TH digitaglinktree 1 "16 Aug 2006 " " " "Linux User's Manual"
+.SH NAME
+digitaglinktree \- Export tag structure of photos in digikam to the filesystem.
+.SH SYNOPSIS
+.B digitaglinktree
+.B -r\fI rootdir\fR
+
+.B -l\fI taglinkdir\fR
+|
+.B -A\fI archivedir\fR
+
+.B -d\fI database\fR
+
+.B [-H|-f|-a|-v|-C]
+
+.SH DESCRIPTION
+.B "digitaglinktree "
+will create a linktree for all photos in a digikam database that have tags set
+on them. Tags (like eg. "family", "events", ...) are used in digikam to create
+virtual folders containing images that all have one or more tags assigned.
+Please note: Photos that have no tags at all assigned are silently ignored by
+this script. The program will not modify or even touch your original photos
+managed by digikam.
+
+
+The script can be used in two ways: If you call it using
+Option -l \fItaglinkdir\fR the script will create the user specified
+directory \fItaglinkdir\fR and inside this directory it will create sub
+directories for digikam tags set on the photos. Inside these subdirectories it
+will finally place symbolic or hard links (see -H) to photos having the tags
+in question. As a result you will see the tags of your photos as folders and in
+these folders you will find links to your original photos.
+
+
+In this way you can access the collection of all images that share a certain tag
+by changing directory to the folder with the tags name created by this script.
+This allows you e.g. to run JAlbum a photo album software that needs to find the
+pictures to be put into a web album in the filesystem because JAlbum cannot
+access digikams virtual folders directly.
+
+
+The second way of calling this script is the so called archive-mode by setting
+option -A \fIarchiveDir\fR.
+
+Archive mode is thought for people who want to archive tagged photos
+independently of digikams root directories and the photos therein. This way you
+can put your photos and their tag structure in eg. a tar archive and send it to
+a friend, who can look at the photos via their tag structure. In this mode the
+script creates the directory given as parameter to -A and in this directory two
+more subdirectories. One named Photos and a second named Tags. The Photos
+directory contains hard links to your original photos, and the Tags directory
+contains a subdirectory for each Tag used by any of your photos. Inside this
+subdirectory there are links (either symbolic or hard links) to the files in the
+Photos directory. This way the archive directory needs nearly no additional
+space on your harddisk and you have an archive that allows you or a friend to
+easily look at the photos tag structure.
+
+Another benefit from using this script is that you have kind of a backup of your
+tag settings for all of your photos. The backup is simply the directory
+structure containing links to the original images that wear the tags.
+This could become important if
+for whatever reason the digikam.db file gets corrupted or even lost.
+
+.PP
+.SH "COMMAND\-LINE OPTIONS"
+.TP
+\fB \-r \fIrootdir\fR
+\fIrootdir\fR denotes the digikam base directory containing all your photos.
+
+.TP
+\fB \-l\fI taglinkdir\fR
+Parameter \fI taglinkdir\fR denotes a directory in which the tag structure of
+all your photos stored in
+rootdir will be exported to by creating subdirectories for each tag and placing
+symbolic links in these subdirectories that point to the original photo wearing
+the tags. If calling the script with option -l\fI taglinkDir\fR you also have
+to specify options -r \fIrootdir\fR as well as -d \fIdatabase\fR.
+
+.TP
+\fB \-A \fIarchivedirectory\fR
+\fIarchivedirectory\fR denotes a directory into which the script will export the photos and their tag
+structure. -A has to be used together with option -r \fIrootdir\fR as well as
+-d\fI database\fR else the script will terminate. Inside the archive directory
+the script will create a Photos and a Tags directory. It will put hard links in
+the Photos directory that point to your original photos. By using hard links
+you are independent of changes in your digikam root directory but on the other
+hand you are limited to one filesystem. So the directory given by
+-r \fIrootdir\fR and the directory specified for -A \fIarchivedir\fR have to be one
+the same filesystem. The Tags subdirectory will contain links to the files in
+the Photos directory. This way you have one archive directory that is completely
+self contained. You can tar it, send it to a friend or just put it somewhere
+for archivel or backup purposes. Usually only those photos will be archived that
+have a digikam tag set on them. By using option -C however you can perform a
+complete archive. See -C for more infos.
+
+.TP
+\fB \-d \fIdatabase\fR
+\fIdatabase\fR is the complete path including the filename to digikams photo database which
+usually can be found in digikams root directory. The files name is usually
+digikam.db .
+
+.TP
+\fB \-C\fR
+When the script is called with option -A \fIarchivedir\fR only those photos
+will be archived (by placing links) in the Photos subdirectory of
+\fIarchivedir\fR that have at least one digikam tag set. By setting option -C all
+photos will be archived to \fIarchivedir\fR no matter if they have a tag set
+or not. Note: This only changes the contents of the Photos subdirectory not of
+the Tags subdirectory in the \fIarchivedir\fR directory.
+
+.TP
+\fB \-a \fR
+By default the script will try to create relative symbolic links from the
+directory \fItaglinkdir\fR set by option -l to the photo files under
+\fIrootdir\fR given by option -r. Using this option will result in absolute symbolic
+links beeing created instead of relative ones.
+
+.TP
+\fB \-H \fR
+By default the script will create soft (symbolic) links from the Tag-Tree to the
+photos. By setting option -H the script will use hard links instead. Please note
+that hard links can only be created inside one filesystem. So your photos and the Tag tree
+have to be one the same filesystem. If not you will see a warning about this problem and the script
+will not run.
+
+.TP
+\fB \-f \fR
+In digikam photos can have hierachical tags (tags that have subtags). In this case
+digitaglinktree would by default add a directory for the tag and a subdirectory for
+each of the subtags of this tag. By setting \fB \-f \fR a subtag is treated like a
+regular tag just as its parent tag so digitaglinktree will create all subdirectories
+for tags and subtags at the same level independent of the tag - subtag hierarchy.
+
+.TP
+\fB \-v \fR
+Prints the scripts version number and exits.
+
+
+.SH CONFIGURATION
+
+The script has to know which version of database is beeing used by digikam.
+The script needs this information to find the correct sqlite binary to
+start queries to the database.
+.sp
+You have to configure the script by setting the path to the sqlite binary that
+is used by the script to query the digikam database digikam.db. Since older
+digikam version use sqlite in version 2, but later digikam 0.80 versions
+needs sqlite version 3 you have to take care to install the correct version of
+sqlite for the installed digikam version and to set the path to the correct
+sqlite executable in the scripts head:
+.sp
+Choose
+
+$SQLITE="/usr/bin/sqlite3";
+
+for digikam version 0.8x and 0.9x and
+
+$SQLITE="/usr/bin/sqlite";
+
+for digikam version 0.7x.
+
+.SH EXAMPLE
+
+A call to digitaglinktree is shown below:
+
+digiTagLinktree -r /home/user/photos -l /home/user/photos/tags \
+ -d /home/user/photos/digikam.db
+
+In this example digikams photo root denoted by -r is /home/user/photos where all of the photos
+can be found that are managed by digikam. The option -l /home/user/photos/tags
+tells the script that all the subdirectories and symbolic links will be placed in
+the directory /home/user/photos/tags. Because the link directory is
+below digikams root directory in this example, you will see a new album in digikam
+after running the script that contains the exported tag structure with all the photos inside.
+Since only links are used here this tag structure does hardly need any additional space on your
+harddisk.
+
+.SH AUTHORS
+.B digitaglinktree
+was written by Rainer Krienke <krienke at uni-koblenz.de>
diff --git a/src/utilities/setup/Makefile.am b/src/utilities/setup/Makefile.am
new file mode 100644
index 00000000..bd6fd66e
--- /dev/null
+++ b/src/utilities/setup/Makefile.am
@@ -0,0 +1,29 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/src/digikam \
+ -I$(top_srcdir)/src/utilities/cameragui \
+ -I$(top_srcdir)/src/utilities/batch \
+ -I$(top_srcdir)/src/utilities/imageeditor/canvas \
+ -I$(top_srcdir)/src/libs/dialogs \
+ -I$(top_srcdir)/src/libs/dimg \
+ -I$(top_srcdir)/src/libs/dimg/loaders \
+ -I$(top_srcdir)/src/libs/widgets/common \
+ $(LIBKIPI_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes)
+
+noinst_LTLIBRARIES = libsetup.la libshowfotosetup.la
+
+libsetup_la_SOURCES = cameraselection.cpp setupcamera.cpp \
+ setupmime.cpp setupplugins.cpp setupidentity.cpp \
+ setupgeneral.cpp setup.cpp \
+ setupcollections.cpp setupmetadata.cpp \
+ setupeditor.cpp setupmisc.cpp setupicc.cpp \
+ setupiofiles.cpp setupdcraw.cpp setupslideshow.cpp \
+ setuptooltip.cpp setuplighttable.cpp
+
+libsetup_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_GPHOTO)
+
+libshowfotosetup_la_SOURCES = setupiofiles.cpp setupdcraw.cpp \
+ setupicc.cpp setupslideshow.cpp
+
+libshowfotosetup_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
diff --git a/src/utilities/setup/cameraselection.cpp b/src/utilities/setup/cameraselection.cpp
new file mode 100644
index 00000000..2cf2635c
--- /dev/null
+++ b/src/utilities/setup/cameraselection.cpp
@@ -0,0 +1,494 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-10
+ * Description : Camera type selection dialog
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqcombobox.h>
+#include <tqvgroupbox.h>
+#include <tqlabel.h>
+#include <tqpushbutton.h>
+#include <tqradiobutton.h>
+#include <tqlistview.h>
+#include <tqvbuttongroup.h>
+#include <tqlayout.h>
+#include <tqwhatsthis.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+#include <tdeglobalsettings.h>
+#include <kactivelabel.h>
+#include <kurlrequester.h>
+#include <tdelocale.h>
+#include <klineedit.h>
+#include <kcursor.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "searchtextbar.h"
+#include "gpcamera.h"
+#include "cameraselection.h"
+#include "cameraselection.moc"
+
+namespace Digikam
+{
+
+class CameraSelectionPriv
+{
+public:
+
+ CameraSelectionPriv()
+ {
+ listView = 0;
+ titleEdit = 0;
+ portButtonGroup = 0;
+ usbButton = 0;
+ serialButton = 0;
+ portPathLabel = 0;
+ portPathComboBox = 0;
+ umsMountURL = 0;
+ searchBar = 0;
+ }
+
+ TQVButtonGroup *portButtonGroup;
+
+ TQRadioButton *usbButton;
+ TQRadioButton *serialButton;
+
+ TQLabel *portPathLabel;
+
+ TQComboBox *portPathComboBox;
+
+ TQString UMSCameraNameActual;
+ TQString UMSCameraNameShown;
+ TQString PTPCameraNameShown;
+
+ TQStringList serialPortList;
+
+ TQListView *listView;
+
+ KLineEdit *titleEdit;
+
+ KURLRequester *umsMountURL;
+
+ SearchTextBar *searchBar;
+};
+
+CameraSelection::CameraSelection( TQWidget* parent )
+ : KDialogBase(Plain, i18n("Camera Configuration"),
+ Help|Ok|Cancel, Ok, parent, 0, true, true)
+{
+ d = new CameraSelectionPriv;
+
+ kapp->setOverrideCursor(KCursor::waitCursor());
+ setHelp("cameraselection.anchor", "digikam");
+ d->UMSCameraNameActual = TQString("Directory Browse"); // Don't be i18n!
+ d->UMSCameraNameShown = i18n("Mounted Camera");
+ d->PTPCameraNameShown = TQString("USB PTP Class Camera");
+
+ TQGridLayout* mainBoxLayout = new TQGridLayout(plainPage(), 6, 1, 0, KDialog::spacingHint());
+ mainBoxLayout->setColStretch(0, 10);
+ mainBoxLayout->setRowStretch(6, 10);
+
+ // --------------------------------------------------------------
+
+ d->listView = new TQListView(plainPage());
+ d->listView->addColumn(i18n("Camera List"));
+ d->listView->setAllColumnsShowFocus(true);
+ d->listView->setResizeMode(TQListView::LastColumn);
+ d->listView->setMinimumWidth(350);
+ TQWhatsThis::add(d->listView, i18n("<p>Select the camera name that you want to use. All "
+ "default settings on the right panel "
+ "will be set automatically.</p><p>This list has been generated "
+ "using the gphoto2 library installed on your computer.</p>"));
+
+ d->searchBar = new SearchTextBar(plainPage(), "CameraSelectionSearchBar");
+
+ // --------------------------------------------------------------
+
+ TQVGroupBox* titleBox = new TQVGroupBox( i18n("Camera Title"), plainPage() );
+ d->titleEdit = new KLineEdit( titleBox );
+ TQWhatsThis::add(d->titleEdit, i18n("<p>Set here the name used in digiKam interface to "
+ "identify this camera.</p>"));
+
+ // --------------------------------------------------------------
+
+ d->portButtonGroup = new TQVButtonGroup( i18n("Camera Port Type"), plainPage() );
+ d->portButtonGroup->setRadioButtonExclusive( true );
+
+ d->usbButton = new TQRadioButton( d->portButtonGroup );
+ d->usbButton->setText( i18n( "USB" ) );
+ TQWhatsThis::add(d->usbButton, i18n("<p>Select this option if your camera is connected to your "
+ "computer using an USB cable.</p>"));
+
+ d->serialButton = new TQRadioButton( d->portButtonGroup );
+ d->serialButton->setText( i18n( "Serial" ) );
+ TQWhatsThis::add(d->serialButton, i18n("<p>Select this option if your camera is connected to your "
+ "computer using a serial cable.</p>"));
+
+ // --------------------------------------------------------------
+
+ TQVGroupBox* portPathBox = new TQVGroupBox( i18n( "Camera Port Path" ), plainPage() );
+ d->portPathLabel = new TQLabel( portPathBox);
+ d->portPathLabel->setText( i18n( "Note: only for serial port camera" ) );
+
+ d->portPathComboBox = new TQComboBox( false, portPathBox );
+ d->portPathComboBox->setDuplicatesEnabled( false );
+ TQWhatsThis::add(d->portPathComboBox, i18n("<p>Select the serial port to use on your computer. "
+ "This option is only required if you use a serial camera.</p>"));
+
+ // --------------------------------------------------------------
+
+ TQVGroupBox* umsMountBox = new TQVGroupBox(i18n("Camera Mount Path"), plainPage());
+
+ TQLabel* umsMountLabel = new TQLabel( umsMountBox );
+ umsMountLabel->setText(i18n("Note: only for USB/IEEE mass storage camera"));
+
+ d->umsMountURL = new KURLRequester( TQString("/mnt/camera"), umsMountBox);
+ d->umsMountURL->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly);
+ TQWhatsThis::add(d->umsMountURL, i18n("<p>Set here the mount path to use on your computer. This "
+ "option is only required if you use a <b>USB Mass Storage</b> "
+ "camera.</p>"));
+
+ // --------------------------------------------------------------
+
+ TQGroupBox* box2 = new TQGroupBox( 0, TQt::Vertical, plainPage() );
+ box2->setFrameStyle( TQFrame::NoFrame );
+ TQGridLayout* box2Layout = new TQGridLayout( box2->layout(), 1, 5 );
+
+ TQLabel* logo = new TQLabel( box2 );
+
+ TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", TDEIcon::NoGroup, 64,
+ TDEIcon::DefaultState, 0, true));
+
+ KActiveLabel* link = new KActiveLabel(box2);
+ link->setText(i18n("<p>To set a <b>USB Mass Storage</b> camera<br>"
+ "(which looks like a removable drive when mounted on your desktop), please<br>"
+ "use <a href=\"umscamera\">%1</a> from camera list.</p>")
+ .arg(d->UMSCameraNameShown));
+
+ KActiveLabel* link2 = new KActiveLabel(box2);
+ link2->setText(i18n("<p>To set a <b>Generic PTP USB Device</b><br>"
+ "(which uses the Picture Transfer Protocol), please<br>"
+ "use <a href=\"ptpcamera\">%1</a> from the camera list.</p>")
+ .arg(d->PTPCameraNameShown));
+
+ KActiveLabel* explanation = new KActiveLabel(box2);
+ explanation->setText(i18n("<p>A complete list of camera settings to use is<br>"
+ "available at <a href='http://www.teaser.fr/~hfiguiere/linux/digicam.html'>"
+ "this url</a>.</p>"));
+
+ box2Layout->addMultiCellWidget(logo, 0, 0, 0, 0);
+ box2Layout->addMultiCellWidget(link, 0, 1, 1, 1);
+ box2Layout->addMultiCellWidget(link2, 2, 3, 1, 1);
+ box2Layout->addMultiCellWidget(explanation, 4, 5, 1, 1);
+
+ // --------------------------------------------------------------
+
+ mainBoxLayout->addMultiCellWidget(d->listView, 0, 5, 0, 0);
+ mainBoxLayout->addMultiCellWidget(d->searchBar, 6, 6, 0, 0);
+ mainBoxLayout->addMultiCellWidget(titleBox, 0, 0, 1, 1);
+ mainBoxLayout->addMultiCellWidget(d->portButtonGroup, 1, 1, 1, 1);
+ mainBoxLayout->addMultiCellWidget(portPathBox, 2, 2, 1, 1);
+ mainBoxLayout->addMultiCellWidget(umsMountBox, 3, 3, 1, 1);
+ mainBoxLayout->addMultiCellWidget(box2, 4, 5, 1, 1);
+
+ // Connections --------------------------------------------------
+
+ disconnect(link, TQ_SIGNAL(linkClicked(const TQString &)),
+ link, TQ_SLOT(openLink(const TQString &)));
+
+ connect(link, TQ_SIGNAL(linkClicked(const TQString &)),
+ this, TQ_SLOT(slotUMSCameraLinkUsed()));
+
+ disconnect(link2, TQ_SIGNAL(linkClicked(const TQString &)),
+ link2, TQ_SLOT(openLink(const TQString &)));
+
+ connect(link2, TQ_SIGNAL(linkClicked(const TQString &)),
+ this, TQ_SLOT(slotPTPCameraLinkUsed()));
+
+ connect(d->listView, TQ_SIGNAL(selectionChanged(TQListViewItem *)),
+ this, TQ_SLOT(slotSelectionChanged(TQListViewItem *)));
+
+ connect(d->portButtonGroup, TQ_SIGNAL(clicked(int)),
+ this, TQ_SLOT(slotPortChanged()));
+
+ connect(this, TQ_SIGNAL(okClicked()),
+ this, TQ_SLOT(slotOkClicked()));
+
+ connect(d->searchBar, TQ_SIGNAL(signalTextChanged(const TQString&)),
+ this, TQ_SLOT(slotSearchTextChanged(const TQString&)));
+
+ // Initialize --------------------------------------------------
+
+ getCameraList();
+ getSerialPortList();
+ kapp->restoreOverrideCursor();
+}
+
+CameraSelection::~CameraSelection()
+{
+ delete d;
+}
+
+void CameraSelection::slotUMSCameraLinkUsed()
+{
+ TQListViewItem *item = d->listView->findItem(d->UMSCameraNameShown, 0);
+ if (item)
+ {
+ d->listView->setCurrentItem(item);
+ d->listView->ensureItemVisible(item);
+ }
+}
+
+void CameraSelection::slotPTPCameraLinkUsed()
+{
+ TQListViewItem *item = d->listView->findItem(d->PTPCameraNameShown, 0);
+ if (item)
+ {
+ d->listView->setCurrentItem(item);
+ d->listView->ensureItemVisible(item);
+ }
+}
+
+void CameraSelection::setCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path)
+{
+ TQString camModel(model);
+
+ if (camModel == d->UMSCameraNameActual)
+ camModel = d->UMSCameraNameShown;
+
+ TQListViewItem* item = d->listView->findItem(camModel, 0);
+ if (!item) return;
+
+ d->listView->setSelected(item, true);
+ d->listView->ensureItemVisible(item);
+
+ d->titleEdit->setText(title);
+
+ if (port.contains("usb"))
+ {
+ d->usbButton->setChecked(true);
+ slotPortChanged();
+ }
+ else if (port.contains("serial"))
+ {
+ d->serialButton->setChecked(true);
+
+ for (int i=0; i<d->portPathComboBox->count(); i++)
+ {
+ if (port == d->portPathComboBox->text(i))
+ {
+ d->portPathComboBox->setCurrentItem(i);
+ break;
+ }
+ }
+ slotPortChanged();
+ }
+
+ d->umsMountURL->setURL(path);
+}
+
+void CameraSelection::getCameraList()
+{
+ int count = 0;
+ TQStringList clist;
+ TQString cname;
+
+ GPCamera::getSupportedCameras(count, clist);
+
+ for (int i = 0 ; i < count ; i++)
+ {
+ cname = clist[i];
+ if (cname == d->UMSCameraNameActual)
+ new TQListViewItem(d->listView, d->UMSCameraNameShown);
+ else
+ new TQListViewItem(d->listView, cname);
+ }
+}
+
+void CameraSelection::getSerialPortList()
+{
+ TQStringList plist;
+
+ GPCamera::getSupportedPorts(plist);
+
+ d->serialPortList.clear();
+
+ for (unsigned int i=0; i<plist.count(); i++)
+ {
+ if ((plist[i]).startsWith("serial:"))
+ d->serialPortList.append(plist[i]);
+ }
+}
+
+void CameraSelection::slotSelectionChanged(TQListViewItem *item)
+{
+ if (!item) return;
+
+ TQString model(item->text(0));
+
+ if (model == d->UMSCameraNameShown)
+ {
+ model = d->UMSCameraNameActual;
+
+ d->titleEdit->setText(model);
+
+ d->serialButton->setEnabled(true);
+ d->serialButton->setChecked(false);
+ d->serialButton->setEnabled(false);
+ d->usbButton->setEnabled(true);
+ d->usbButton->setChecked(false);
+ d->usbButton->setEnabled(false);
+ d->portPathComboBox->setEnabled(true);
+ d->portPathComboBox->insertItem(TQString("NONE"), 0);
+ d->portPathComboBox->setEnabled(false);
+
+ d->umsMountURL->setEnabled(true);
+ d->umsMountURL->clear();
+ d->umsMountURL->setURL(TQString("/mnt/camera"));
+ return;
+ }
+ else
+ {
+ d->umsMountURL->setEnabled(true);
+ d->umsMountURL->clear();
+ d->umsMountURL->setURL(TQString("/"));
+ d->umsMountURL->setEnabled(false);
+ }
+
+ d->titleEdit->setText(model);
+
+ TQStringList plist;
+ GPCamera::getCameraSupportedPorts(model, plist);
+
+ if (plist.contains("serial"))
+ {
+ d->serialButton->setEnabled(true);
+ d->serialButton->setChecked(true);
+ }
+ else
+ {
+ d->serialButton->setEnabled(true);
+ d->serialButton->setChecked(false);
+ d->serialButton->setEnabled(false);
+ }
+
+ if (plist.contains("usb"))
+ {
+ d->usbButton->setEnabled(true);
+ d->usbButton->setChecked(true);
+ }
+ else
+ {
+ d->usbButton->setEnabled(true);
+ d->usbButton->setChecked(false);
+ d->usbButton->setEnabled(false);
+ }
+
+ slotPortChanged();
+}
+
+void CameraSelection::slotPortChanged()
+{
+ if (d->usbButton->isChecked())
+ {
+ d->portPathComboBox->setEnabled(true);
+ d->portPathComboBox->clear();
+ d->portPathComboBox->insertItem( TQString("usb:"), 0 );
+ d->portPathComboBox->setEnabled(false);
+ return;
+ }
+
+ if (d->serialButton->isChecked())
+ {
+ d->portPathComboBox->setEnabled(true);
+ d->portPathComboBox->clear();
+ d->portPathComboBox->insertStringList(d->serialPortList);
+ }
+}
+
+TQString CameraSelection::currentTitle()
+{
+ return d->titleEdit->text();
+}
+
+TQString CameraSelection::currentModel()
+{
+ TQListViewItem* item = d->listView->currentItem();
+ if (!item)
+ return TQString();
+
+ TQString model(item->text(0));
+ if (model == d->UMSCameraNameShown)
+ model = d->UMSCameraNameActual;
+
+ return model;
+}
+
+TQString CameraSelection::currentPortPath()
+{
+ return d->portPathComboBox->currentText();
+}
+
+TQString CameraSelection::currentCameraPath()
+{
+ return d->umsMountURL->url();
+}
+
+void CameraSelection::slotOkClicked()
+{
+ emit signalOkClicked(currentTitle(), currentModel(),
+ currentPortPath(), currentCameraPath());
+}
+
+void CameraSelection::slotSearchTextChanged(const TQString& filter)
+{
+ bool query = false;
+ TQString search = filter.lower();
+
+ TQListViewItemIterator it(d->listView);
+
+ for ( ; it.current(); ++it )
+ {
+ TQListViewItem *item = it.current();
+
+ if (item->text(0).lower().contains(search))
+ {
+ query = true;
+ item->setVisible(true);
+ }
+ else
+ {
+ item->setVisible(false);
+ }
+ }
+
+ d->searchBar->slotSearchResult(query);
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/cameraselection.h b/src/utilities/setup/cameraselection.h
new file mode 100644
index 00000000..0458f13b
--- /dev/null
+++ b/src/utilities/setup/cameraselection.h
@@ -0,0 +1,88 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-10
+ * Description : Camera type selection dialog
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 CAMERASELECTION_H
+#define CAMERASELECTION_H
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqstringlist.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+class TQListViewItem;
+
+namespace Digikam
+{
+
+class CameraSelectionPriv;
+
+class CameraSelection : public KDialogBase
+{
+ TQ_OBJECT
+
+
+public:
+
+ CameraSelection(TQWidget *parent=0);
+ ~CameraSelection();
+
+ void setCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path);
+
+ TQString currentTitle();
+ TQString currentModel();
+ TQString currentPortPath();
+ TQString currentCameraPath();
+
+signals:
+
+ void signalOkClicked(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path);
+
+private:
+
+ void getCameraList();
+ void getSerialPortList();
+
+private slots:
+
+ void slotPTPCameraLinkUsed();
+ void slotUMSCameraLinkUsed();
+ void slotSelectionChanged(TQListViewItem *item);
+ void slotPortChanged();
+ void slotOkClicked();
+ void slotSearchTextChanged(const TQString&);
+
+private:
+
+ CameraSelectionPriv *d;
+};
+
+} // namespace Digikam
+
+#endif // CAMERASELECTION_H
diff --git a/src/utilities/setup/setup.cpp b/src/utilities/setup/setup.cpp
new file mode 100644
index 00000000..bd47796f
--- /dev/null
+++ b/src/utilities/setup/setup.cpp
@@ -0,0 +1,266 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-03
+ * Description : digiKam setup dialog.
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi at pooh.tam.uiuc.edu>
+ * Copyright (C) 2003-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 <tqtabwidget.h>
+#include <tqapplication.h>
+#include <tqframe.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <tdemessagebox.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "batchthumbsgenerator.h"
+#include "setupgeneral.h"
+#include "setuptooltip.h"
+#include "setupmetadata.h"
+#include "setupidentity.h"
+#include "setupcollections.h"
+#include "setupmime.h"
+#include "setuplighttable.h"
+#include "setupeditor.h"
+#include "setupdcraw.h"
+#include "setupiofiles.h"
+#include "setupslideshow.h"
+#include "setupicc.h"
+#include "setupplugins.h"
+#include "setupcamera.h"
+#include "setupmisc.h"
+#include "setup.h"
+#include "setup.moc"
+
+namespace Digikam
+{
+
+class SetupPrivate
+{
+public:
+
+ SetupPrivate()
+ {
+ page_general = 0;
+ page_tooltip = 0;
+ page_metadata = 0;
+ page_identity = 0;
+ page_collections = 0;
+ page_mime = 0;
+ page_lighttable = 0;
+ page_editor = 0;
+ page_dcraw = 0;
+ page_iofiles = 0;
+ page_slideshow = 0;
+ page_icc = 0;
+ page_plugins = 0;
+ page_camera = 0;
+ page_misc = 0;
+
+ generalPage = 0;
+ tooltipPage = 0;
+ metadataPage = 0;
+ identityPage = 0;
+ collectionsPage = 0;
+ mimePage = 0;
+ lighttablePage = 0;
+ editorPage = 0;
+ dcrawPage = 0;
+ iofilesPage = 0;
+ slideshowPage = 0;
+ iccPage = 0;
+ cameraPage = 0;
+ miscPage = 0;
+ pluginsPage = 0;
+ }
+
+ TQFrame *page_general;
+ TQFrame *page_tooltip;
+ TQFrame *page_metadata;
+ TQFrame *page_identity;
+ TQFrame *page_collections;
+ TQFrame *page_mime;
+ TQFrame *page_lighttable;
+ TQFrame *page_editor;
+ TQFrame *page_dcraw;
+ TQFrame *page_iofiles;
+ TQFrame *page_slideshow;
+ TQFrame *page_icc;
+ TQFrame *page_plugins;
+ TQFrame *page_camera;
+ TQFrame *page_misc;
+
+ SetupGeneral *generalPage;
+ SetupToolTip *tooltipPage;
+ SetupMetadata *metadataPage;
+ SetupIdentity *identityPage;
+ SetupCollections *collectionsPage;
+ SetupMime *mimePage;
+ SetupLightTable *lighttablePage;
+ SetupEditor *editorPage;
+ SetupDcraw *dcrawPage;
+ SetupIOFiles *iofilesPage;
+ SetupSlideShow *slideshowPage;
+ SetupICC *iccPage;
+ SetupCamera *cameraPage;
+ SetupMisc *miscPage;
+ SetupPlugins *pluginsPage;
+};
+
+Setup::Setup(TQWidget* parent, const char* name, Setup::Page page)
+ : KDialogBase(IconList, i18n("Configure"), Help|Ok|Cancel, Ok, parent,
+ name, true, true )
+{
+ d = new SetupPrivate;
+ setHelp("setupdialog.anchor", "digikam");
+
+ d->page_general = addPage(i18n("Albums"), i18n("Album Settings"),
+ BarIcon("folder_image", TDEIcon::SizeMedium));
+ d->generalPage = new SetupGeneral(d->page_general, this);
+
+ d->page_collections = addPage(i18n("Collections"), i18n("Album Collections"),
+ BarIcon("document-open", TDEIcon::SizeMedium));
+ d->collectionsPage = new SetupCollections(d->page_collections);
+
+ d->page_identity = addPage(i18n("Identity"), i18n("Default IPTC identity information"),
+ BarIcon("identity", TDEIcon::SizeMedium));
+ d->identityPage = new SetupIdentity(d->page_identity);
+
+ d->page_metadata = addPage(i18n("Metadata"), i18n("Embedded Image Information Management"),
+ BarIcon("exifinfo", TDEIcon::SizeMedium));
+ d->metadataPage = new SetupMetadata(d->page_metadata);
+
+ d->page_tooltip = addPage(i18n("Tool Tip"), i18n("Album Items Tool Tip Settings"),
+ BarIcon("filetypes", TDEIcon::SizeMedium));
+ d->tooltipPage = new SetupToolTip(d->page_tooltip);
+
+ d->page_mime = addPage(i18n("Mime Types"), i18n("File (MIME) Types Settings"),
+ BarIcon("preferences-system", TDEIcon::SizeMedium));
+ d->mimePage = new SetupMime(d->page_mime);
+
+ d->page_lighttable = addPage(i18n("Light Table"), i18n("Light Table Settings"),
+ BarIcon("lighttable", TDEIcon::SizeMedium));
+ d->lighttablePage = new SetupLightTable(d->page_lighttable);
+
+ d->page_editor = addPage(i18n("Image Editor"), i18n("Image Editor General Settings"),
+ BarIcon("image-x-generic", TDEIcon::SizeMedium));
+ d->editorPage = new SetupEditor(d->page_editor);
+
+ d->page_iofiles = addPage(i18n("Save Images"), i18n("Image Editor: Settings for Saving Images Files"),
+ BarIcon("document-save", TDEIcon::SizeMedium));
+ d->iofilesPage = new SetupIOFiles(d->page_iofiles);
+
+ d->page_dcraw = addPage(i18n("RAW decoding"), i18n("RAW Files Decoding Settings"),
+ BarIcon("kdcraw", TDEIcon::SizeMedium));
+ d->dcrawPage = new SetupDcraw(d->page_dcraw);
+
+ d->page_icc = addPage(i18n("Color Management"), i18n("Image Editor Color Management Settings"),
+ BarIcon("colorize", TDEIcon::SizeMedium));
+ d->iccPage = new SetupICC(d->page_icc, this);
+
+ d->page_plugins = addPage(i18n("Kipi Plugins"), i18n("Main Interface Plug-in Settings"),
+ BarIcon("kipi", TDEIcon::SizeMedium));
+ d->pluginsPage = new SetupPlugins(d->page_plugins);
+
+ d->page_slideshow = addPage(i18n("Slide Show"), i18n("Slide Show Settings"),
+ BarIcon("slideshow", TDEIcon::SizeMedium));
+ d->slideshowPage = new SetupSlideShow(d->page_slideshow);
+
+ d->page_camera = addPage(i18n("Cameras"), i18n("Camera Settings"),
+ BarIcon("digitalcam", TDEIcon::SizeMedium));
+ d->cameraPage = new SetupCamera(d->page_camera);
+
+ d->page_misc = addPage(i18n("Miscellaneous"), i18n("Miscellaneous Settings"),
+ BarIcon("misc", TDEIcon::SizeMedium));
+ d->miscPage = new SetupMisc(d->page_misc);
+
+ connect(this, TQ_SIGNAL(okClicked()),
+ this, TQ_SLOT(slotOkClicked()) );
+
+ if (page != LastPageUsed)
+ showPage((int) page);
+ else
+ {
+ TDEConfig* config = kapp->config();
+ config->setGroup("General Settings");
+ showPage(config->readNumEntry("Setup Page", General));
+ }
+
+ show();
+}
+
+Setup::~Setup()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("General Settings");
+ config->writeEntry("Setup Page", activePageIndex());
+ config->sync();
+ delete d;
+}
+
+void Setup::slotOkClicked()
+{
+ d->generalPage->applySettings();
+ d->tooltipPage->applySettings();
+ d->metadataPage->applySettings();
+ d->identityPage->applySettings();
+ d->collectionsPage->applySettings();
+ d->mimePage->applySettings();
+ d->cameraPage->applySettings();
+ d->lighttablePage->applySettings();
+ d->editorPage->applySettings();
+ d->dcrawPage->applySettings();
+ d->iofilesPage->applySettings();
+ d->slideshowPage->applySettings();
+ d->iccPage->applySettings();
+ d->miscPage->applySettings();
+
+ if (d->metadataPage->exifAutoRotateAsChanged())
+ {
+ TQString msg = i18n("The Exif auto-rotate thumbnails option has been changed.\n"
+ "Do you want to rebuild all albums' items' thumbnails now?\n\n"
+ "Note: thumbnail processing can take a while! You can start "
+ "this job later from the \"Tools\" menu.");
+ int result = KMessageBox::warningYesNo(this, msg);
+ if (result != KMessageBox::Yes)
+ return;
+
+ BatchThumbsGenerator *thumbsGenerator = new BatchThumbsGenerator(this);
+ thumbsGenerator->exec();
+ }
+
+ close();
+}
+
+SetupPlugins* Setup::kipiPluginsPage()
+{
+ return d->pluginsPage;
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setup.h b/src/utilities/setup/setup.h
new file mode 100644
index 00000000..ce5e57b1
--- /dev/null
+++ b/src/utilities/setup/setup.h
@@ -0,0 +1,81 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-03
+ * Description : digiKam setup dialog.
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi at pooh.tam.uiuc.edu>
+ * Copyright (C) 2003-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 SETUP_H
+#define SETUP_H
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class SetupPlugins;
+class SetupPrivate;
+
+class Setup : public KDialogBase
+{
+ TQ_OBJECT
+
+
+public:
+
+ enum Page
+ {
+ LastPageUsed = -1,
+ General = 0,
+ ToolTip,
+ Metadata,
+ Identify,
+ Collections,
+ Mime,
+ LightTable,
+ Editor,
+ Dcraw,
+ IOFiles,
+ Slideshow,
+ IccProfiles,
+ KipiPlugins,
+ Camera,
+ Miscellaneous
+ };
+
+ Setup(TQWidget* parent=0, const char* name=0, Page page=LastPageUsed);
+ ~Setup();
+
+ SetupPlugins *kipiPluginsPage();
+
+private slots:
+
+ void slotOkClicked();
+
+private:
+
+ SetupPrivate* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUP_H
diff --git a/src/utilities/setup/setupcamera.cpp b/src/utilities/setup/setupcamera.cpp
new file mode 100644
index 00000000..1b8d0bb8
--- /dev/null
+++ b/src/utilities/setup/setupcamera.cpp
@@ -0,0 +1,315 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-10
+ * Description : camera setup tab.
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 <tqgroupbox.h>
+#include <tqpushbutton.h>
+#include <tqlayout.h>
+#include <tqwhatsthis.h>
+#include <tqtooltip.h>
+#include <tqdatetime.h>
+#include <tqlistview.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <tdemessagebox.h>
+#include <kurllabel.h>
+#include <kiconloader.h>
+#include <tdeglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kcursor.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "cameraselection.h"
+#include "cameralist.h"
+#include "cameratype.h"
+#include "gpcamera.h"
+#include "setupcamera.h"
+#include "setupcamera.moc"
+
+namespace Digikam
+{
+class SetupCameraPriv
+{
+public:
+
+ SetupCameraPriv()
+ {
+ listView = 0;
+ addButton = 0;
+ removeButton = 0;
+ editButton = 0;
+ autoDetectButton = 0;
+ }
+
+ TQPushButton *addButton;
+ TQPushButton *removeButton;
+ TQPushButton *editButton;
+ TQPushButton *autoDetectButton;
+
+ TQListView *listView;
+};
+
+SetupCamera::SetupCamera( TQWidget* parent )
+ : TQWidget( parent )
+{
+ d = new SetupCameraPriv;
+
+ TQVBoxLayout *mainLayout = new TQVBoxLayout(parent);
+ TQGridLayout* groupBoxLayout = new TQGridLayout( this, 2, 5, 0, KDialog::spacingHint() );
+
+ d->listView = new TQListView( this );
+ d->listView->addColumn( i18n("Title") );
+ d->listView->addColumn( i18n("Model") );
+ d->listView->addColumn( i18n("Port") );
+ d->listView->addColumn( i18n("Path") );
+ d->listView->addColumn( "Last Access Date", 0 ); // No i18n here. Hidden column with the last access date.
+ d->listView->setAllColumnsShowFocus(true);
+ TQWhatsThis::add( d->listView, i18n("<p>Here you can see the digital camera list used by digiKam "
+ "via the Gphoto interface."));
+
+ // -------------------------------------------------------------
+
+ d->addButton = new TQPushButton( this );
+ d->removeButton = new TQPushButton( this );
+ d->editButton = new TQPushButton( this );
+ d->autoDetectButton = new TQPushButton( this );
+
+ d->addButton->setText( i18n( "&Add..." ) );
+ d->addButton->setIconSet(SmallIcon("add"));
+ d->removeButton->setText( i18n( "&Remove" ) );
+ d->removeButton->setIconSet(SmallIcon("remove"));
+ d->editButton->setText( i18n( "&Edit..." ) );
+ d->editButton->setIconSet(SmallIcon("configure"));
+ d->autoDetectButton->setText( i18n( "Auto-&Detect" ) );
+ d->autoDetectButton->setIconSet(SmallIcon("edit-find"));
+ d->removeButton->setEnabled(false);
+ d->editButton->setEnabled(false);
+
+ TQSpacerItem* spacer = new TQSpacerItem( 20, 20, TQSizePolicy::Minimum, TQSizePolicy::Expanding );
+
+ KURLLabel *gphotoLogoLabel = new KURLLabel(this);
+ gphotoLogoLabel->setText(TQString());
+ gphotoLogoLabel->setURL("http://www.gphoto.org");
+ TDEGlobal::dirs()->addResourceType("logo-gphoto", TDEGlobal::dirs()->kde_default("data") + "digikam/data");
+ TQString directory = TDEGlobal::dirs()->findResourceDir("logo-gphoto", "logo-gphoto.png");
+ gphotoLogoLabel->setPixmap( TQPixmap( directory + "logo-gphoto.png" ) );
+ TQToolTip::add(gphotoLogoLabel, i18n("Visit Gphoto project website"));
+
+ groupBoxLayout->setAlignment( TQt::AlignTop );
+ groupBoxLayout->addMultiCellWidget( d->listView, 0, 5, 0, 0 );
+ groupBoxLayout->addWidget( d->addButton, 0, 1 );
+ groupBoxLayout->addWidget( d->removeButton, 1, 1 );
+ groupBoxLayout->addWidget( d->editButton, 2, 1 );
+ groupBoxLayout->addWidget( d->autoDetectButton, 3, 1 );
+ groupBoxLayout->addItem( spacer, 4, 1 );
+ groupBoxLayout->addWidget( gphotoLogoLabel, 5, 1 );
+
+ adjustSize();
+ mainLayout->addWidget(this);
+
+ // -------------------------------------------------------------
+
+ connect(gphotoLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)),
+ this, TQ_SLOT(processGphotoURL(const TQString&)));
+
+ connect(d->listView, TQ_SIGNAL(selectionChanged()),
+ this, TQ_SLOT(slotSelectionChanged()));
+
+ connect(d->addButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotAddCamera()));
+
+ connect(d->removeButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotRemoveCamera()));
+
+ connect(d->editButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotEditCamera()));
+
+ connect(d->autoDetectButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotAutoDetectCamera()));
+
+ // Add cameras --------------------------------------
+
+ CameraList* clist = CameraList::instance();
+
+ if (clist)
+ {
+ TQPtrList<CameraType>* cl = clist->cameraList();
+
+ for (CameraType *ctype = cl->first(); ctype;
+ ctype = cl->next())
+ {
+ new TQListViewItem(d->listView, ctype->title(), ctype->model(),
+ ctype->port(), ctype->path(),
+ ctype->lastAccess().toString(TQt::ISODate));
+ }
+ }
+}
+
+SetupCamera::~SetupCamera()
+{
+ delete d;
+}
+
+void SetupCamera::processGphotoURL(const TQString& url)
+{
+ TDEApplication::kApplication()->invokeBrowser(url);
+}
+
+void SetupCamera::slotSelectionChanged()
+{
+ TQListViewItem *item = d->listView->selectedItem();
+
+ if (!item)
+ {
+ d->removeButton->setEnabled(false);
+ d->editButton->setEnabled(false);
+ return;
+ }
+
+ d->removeButton->setEnabled(true);
+ d->editButton->setEnabled(true);
+}
+
+void SetupCamera::slotAddCamera()
+{
+ CameraSelection *select = new CameraSelection;
+
+ connect(select, TQ_SIGNAL(signalOkClicked(const TQString&, const TQString&,
+ const TQString&, const TQString&)),
+ this, TQ_SLOT(slotAddedCamera(const TQString&, const TQString&,
+ const TQString&, const TQString&)));
+
+ select->show();
+}
+
+void SetupCamera::slotRemoveCamera()
+{
+ TQListViewItem *item = d->listView->currentItem();
+ if (!item) return;
+
+ delete item;
+}
+
+void SetupCamera::slotEditCamera()
+{
+ TQListViewItem *item = d->listView->currentItem();
+ if (!item) return;
+
+ CameraSelection *select = new CameraSelection;
+ select->setCamera(item->text(0), item->text(1), item->text(2), item->text(3));
+
+ connect(select, TQ_SIGNAL(signalOkClicked(const TQString&, const TQString&,
+ const TQString&, const TQString&)),
+ this, TQ_SLOT(slotEditedCamera(const TQString&, const TQString&,
+ const TQString&, const TQString&)));
+
+ select->show();
+}
+
+void SetupCamera::slotAutoDetectCamera()
+{
+ TQString model, port;
+
+ kapp->setOverrideCursor( KCursor::waitCursor() );
+ int ret = GPCamera::autoDetect(model, port);
+ kapp->restoreOverrideCursor();
+
+ if (ret != 0)
+ {
+ KMessageBox::error(this,i18n("Failed to auto-detect camera.\n"
+ "Please check if your camera is turned on "
+ "and retry or try setting it manually."));
+ return;
+ }
+
+ // NOTE: See note in digikam/digikam/cameralist.cpp
+ if (port.startsWith("usb:"))
+ port = "usb:";
+
+ if (d->listView->findItem(model, 1))
+ {
+ KMessageBox::information(this, i18n("Camera '%1' (%2) is already in list.").arg(model).arg(port));
+ }
+ else
+ {
+ KMessageBox::information(this, i18n("Found camera '%1' (%2) and added it to the list.")
+ .arg(model).arg(port));
+ new TQListViewItem(d->listView, model, model, port, "/",
+ TQDateTime::currentDateTime().toString(TQt::ISODate));
+ }
+}
+
+void SetupCamera::slotAddedCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path)
+{
+ new TQListViewItem(d->listView, title, model, port, path,
+ TQDateTime::currentDateTime().toString(TQt::ISODate));
+}
+
+void SetupCamera::slotEditedCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path)
+{
+ TQListViewItem *item = d->listView->currentItem();
+ if (!item) return;
+
+ item->setText(0, title);
+ item->setText(1, model);
+ item->setText(2, port);
+ item->setText(3, path);
+}
+
+void SetupCamera::applySettings()
+{
+ CameraList* clist = CameraList::instance();
+
+ if (clist)
+ {
+ clist->clear();
+
+ TQListViewItemIterator it(d->listView);
+
+ for ( ; it.current(); ++it )
+ {
+ TQListViewItem *item = it.current();
+ TQDateTime lastAccess = TQDateTime::currentDateTime();
+
+ if (!item->text(4).isEmpty())
+ lastAccess = TQDateTime::fromString(item->text(4), TQt::ISODate);
+
+ CameraType *ctype = new CameraType(item->text(0), item->text(1), item->text(2),
+ item->text(3), lastAccess);
+ clist->insert(ctype);
+ }
+
+ clist->save();
+ }
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setupcamera.h b/src/utilities/setup/setupcamera.h
new file mode 100644
index 00000000..f0df8a71
--- /dev/null
+++ b/src/utilities/setup/setupcamera.h
@@ -0,0 +1,73 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-10
+ * Description : camera setup tab.
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2003-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 SETUPCAMERA_H
+#define SETUPCAMERA_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupCameraPriv;
+
+class SetupCamera : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupCamera( TQWidget* parent = 0 );
+ ~SetupCamera();
+
+ void applySettings();
+
+private slots:
+
+ void processGphotoURL(const TQString& url);
+
+ void slotSelectionChanged();
+
+ void slotAddCamera();
+ void slotRemoveCamera();
+ void slotEditCamera();
+ void slotAutoDetectCamera();
+
+ void slotAddedCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path);
+ void slotEditedCamera(const TQString& title, const TQString& model,
+ const TQString& port, const TQString& path);
+
+private:
+
+ SetupCameraPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif // SETUPCAMERA_H
diff --git a/src/utilities/setup/setupcollections.cpp b/src/utilities/setup/setupcollections.cpp
new file mode 100644
index 00000000..10a25c31
--- /dev/null
+++ b/src/utilities/setup/setupcollections.cpp
@@ -0,0 +1,218 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-01-02
+ * Description : collection setup tab.
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqlayout.h>
+#include <tqvbuttongroup.h>
+#include <tqvgroupbox.h>
+#include <tqhgroupbox.h>
+#include <tqgroupbox.h>
+#include <tqradiobutton.h>
+#include <tqcheckbox.h>
+#include <tqlabel.h>
+#include <tqlineedit.h>
+#include <tqpushbutton.h>
+#include <tqdir.h>
+#include <tqwhatsthis.h>
+
+// KDE includes.
+
+#include <tdelistbox.h>
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <tdefiledialog.h>
+#include <kurl.h>
+#include <tdemessagebox.h>
+#include <kiconloader.h>
+#include <tdeversion.h>
+
+#if KDE_IS_VERSION(3,2,0)
+#include <kinputdialog.h>
+#else
+#include <klineeditdlg.h>
+#endif
+
+// Local includes.
+
+#include "thumbnailsize.h"
+#include "albumsettings.h"
+#include "setupcollections.h"
+#include "setupcollections.moc"
+
+namespace Digikam
+{
+
+class SetupCollectionsPriv
+{
+public:
+
+ SetupCollectionsPriv()
+ {
+ albumCollectionBox = 0;
+ addCollectionButton = 0;
+ delCollectionButton = 0;
+ }
+
+ TQListBox *albumCollectionBox;
+
+ TQPushButton *addCollectionButton;
+ TQPushButton *delCollectionButton;
+};
+
+SetupCollections::SetupCollections(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupCollectionsPriv;
+
+ TQVBoxLayout *mainLayout = new TQVBoxLayout(parent);
+ TQGridLayout *collectionGroupLayout = new TQGridLayout( this, 2, 5, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ d->albumCollectionBox = new TDEListBox(this);
+ TQWhatsThis::add( d->albumCollectionBox, i18n("<p>You can add or remove Album "
+ "collection types here to improve how "
+ "your Albums are sorted in digiKam."));
+
+ d->albumCollectionBox->setVScrollBarMode(TQScrollView::AlwaysOn);
+
+ d->addCollectionButton = new TQPushButton( i18n("&Add..."), this);
+ d->delCollectionButton = new TQPushButton( i18n("&Delete"), this);
+
+ d->addCollectionButton->setIconSet(SmallIcon("add"));
+ d->delCollectionButton->setIconSet(SmallIcon("remove"));
+ d->delCollectionButton->setEnabled(false);
+
+ TQSpacerItem* spacer = new TQSpacerItem( 20, 20, TQSizePolicy::Minimum, TQSizePolicy::Expanding );
+
+ collectionGroupLayout->setAlignment( TQt::AlignTop );
+ collectionGroupLayout->addMultiCellWidget( d->albumCollectionBox, 0, 4, 0, 0 );
+ collectionGroupLayout->addWidget( d->addCollectionButton, 0, 1);
+ collectionGroupLayout->addWidget( d->delCollectionButton, 1, 1);
+ collectionGroupLayout->addItem( spacer, 4, 1 );
+
+ // --------------------------------------------------------
+
+ connect(d->albumCollectionBox, TQ_SIGNAL(selectionChanged()),
+ this, TQ_SLOT(slotCollectionSelectionChanged()));
+
+ connect(d->addCollectionButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotAddCollection()));
+
+ connect(d->delCollectionButton, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotDelCollection()));
+
+ // --------------------------------------------------------
+
+ readSettings();
+ adjustSize();
+ mainLayout->addWidget(this);
+}
+
+SetupCollections::~SetupCollections()
+{
+ delete d;
+}
+
+void SetupCollections::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ TQStringList collectionList;
+
+ for (TQListBoxItem *item = d->albumCollectionBox->firstItem();
+ item; item = item->next())
+ {
+ collectionList.append(item->text());
+ }
+
+ settings->setAlbumCollectionNames(collectionList);
+
+ settings->saveSettings();
+}
+
+void SetupCollections::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ d->albumCollectionBox->insertStringList(settings->getAlbumCollectionNames());
+}
+
+void SetupCollections::slotCollectionSelectionChanged()
+{
+ if (d->albumCollectionBox->currentItem() != -1)
+ d->delCollectionButton->setEnabled(true);
+ else
+ d->delCollectionButton->setEnabled(false);
+}
+
+void SetupCollections::slotAddCollection()
+{
+ bool ok;
+
+#if KDE_IS_VERSION(3,2,0)
+ TQString newCollection =
+ KInputDialog::getText(i18n("New Collection Name"),
+ i18n("Enter new collection name:"),
+ TQString(), &ok, this);
+#else
+ TQString newCollection =
+ KLineEditDlg::getText(i18n("New Collection Name"),
+ i18n("Enter new collection name:"),
+ TQString(), &ok, this);
+#endif
+
+ if (!ok) return;
+
+ bool found = false;
+ for (TQListBoxItem *item = d->albumCollectionBox->firstItem();
+ item; item = item->next())
+ {
+ if (newCollection == item->text())
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ d->albumCollectionBox->insertItem(newCollection);
+}
+
+void SetupCollections::slotDelCollection()
+{
+ int index = d->albumCollectionBox->currentItem();
+ if (index == -1)
+ return;
+
+ TQListBoxItem* item = d->albumCollectionBox->item(index);
+ if (!item) return;
+ delete item;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupcollections.h b/src/utilities/setup/setupcollections.h
new file mode 100644
index 00000000..c65b93e1
--- /dev/null
+++ b/src/utilities/setup/setupcollections.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-01-02
+ * Description : collection setup tab.
+ *
+ * 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 SETUPCOLLECTIONS_H
+#define SETUPCOLLECTIONS_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupCollectionsPriv;
+
+class SetupCollections : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupCollections(TQWidget* parent = 0);
+ ~SetupCollections();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void slotCollectionSelectionChanged();
+ void slotAddCollection();
+ void slotDelCollection();
+
+private:
+
+ SetupCollectionsPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif // SETUPCOLLECTIONS_H
diff --git a/src/utilities/setup/setupdcraw.cpp b/src/utilities/setup/setupdcraw.cpp
new file mode 100644
index 00000000..57f9cb2d
--- /dev/null
+++ b/src/utilities/setup/setupdcraw.cpp
@@ -0,0 +1,150 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-02-06
+ * Description : setup RAW decoding settings.
+ *
+ * Copyright (C) 2007-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 <tqlayout.h>
+#include <tqlabel.h>
+#include <tqcolor.h>
+#include <tqhbox.h>
+#include <tqvgroupbox.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqcheckbox.h>
+#include <tqcombobox.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kiconloader.h>
+#include <kdialog.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+
+// LibKDcraw includes.
+
+#include <libkdcraw/version.h>
+#include <libkdcraw/dcrawsettingswidget.h>
+
+// Local includes.
+
+#include "drawdecoding.h"
+#include "setupdcraw.h"
+#include "setupdcraw.moc"
+
+using namespace KDcrawIface;
+
+namespace Digikam
+{
+
+class SetupDcrawPriv
+{
+public:
+
+
+ SetupDcrawPriv()
+ {
+ dcrawSettings = 0;
+ }
+
+ KDcrawIface::DcrawSettingsWidget *dcrawSettings;
+};
+
+SetupDcraw::SetupDcraw(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupDcrawPriv;
+ TQVBoxLayout *layout = new TQVBoxLayout(parent, 0, KDialog::spacingHint());
+ d->dcrawSettings = new DcrawSettingsWidget(parent, DcrawSettingsWidget::SIXTEENBITS);
+ d->dcrawSettings->setItemIconSet(0, SmallIconSet("kdcraw"));
+ d->dcrawSettings->setItemIconSet(1, SmallIconSet("whitebalance"));
+ d->dcrawSettings->setItemIconSet(2, SmallIconSet("lensdistortion"));
+ layout->addWidget(d->dcrawSettings);
+ layout->addStretch();
+
+ connect(d->dcrawSettings, TQ_SIGNAL(signalSixteenBitsImageToggled(bool)),
+ this, TQ_SLOT(slotSixteenBitsImageToggled(bool)));
+
+ readSettings();
+}
+
+SetupDcraw::~SetupDcraw()
+{
+ delete d;
+}
+
+void SetupDcraw::slotSixteenBitsImageToggled(bool)
+{
+ // Dcraw do not provide a way to set brigness of image in 16 bits color depth.
+ // We always set on this option. We drive brightness adjustment in digiKam Raw image loader.
+ d->dcrawSettings->setEnabledBrightnessSettings(true);
+}
+
+void SetupDcraw::applySettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ config->writeEntry("SixteenBitsImage", d->dcrawSettings->sixteenBits());
+ config->writeEntry("WhiteBalance", d->dcrawSettings->whiteBalance());
+ config->writeEntry("CustomWhiteBalance", d->dcrawSettings->customWhiteBalance());
+ config->writeEntry("CustomWhiteBalanceGreen", d->dcrawSettings->customWhiteBalanceGreen());
+ config->writeEntry("RGBInterpolate4Colors", d->dcrawSettings->useFourColor());
+ config->writeEntry("DontStretchPixels", d->dcrawSettings->useDontStretchPixels());
+ config->writeEntry("EnableNoiseReduction", d->dcrawSettings->useNoiseReduction());
+ config->writeEntry("NRThreshold", d->dcrawSettings->NRThreshold());
+ config->writeEntry("EnableCACorrection", d->dcrawSettings->useCACorrection());
+ config->writeEntry("caRedMultiplier", d->dcrawSettings->caRedMultiplier());
+ config->writeEntry("caBlueMultiplier", d->dcrawSettings->caBlueMultiplier());
+ config->writeEntry("UnclipColors", d->dcrawSettings->unclipColor());
+ config->writeEntry("RAWBrightness", d->dcrawSettings->brightness());
+ config->writeEntry("RAWQuality", d->dcrawSettings->quality());
+ config->writeEntry("MedianFilterPasses", d->dcrawSettings->medianFilterPasses());
+ config->sync();
+}
+
+void SetupDcraw::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ d->dcrawSettings->setSixteenBits(config->readBoolEntry("SixteenBitsImage", false));
+ d->dcrawSettings->setNoiseReduction(config->readBoolEntry("EnableNoiseReduction", false));
+ d->dcrawSettings->setNRThreshold(config->readNumEntry("NRThreshold", 100));
+ d->dcrawSettings->setUseCACorrection(config->readBoolEntry("EnableCACorrection", false));
+ d->dcrawSettings->setcaRedMultiplier(config->readDoubleNumEntry("caRedMultiplier", 1.0));
+ d->dcrawSettings->setcaBlueMultiplier(config->readDoubleNumEntry("caBlueMultiplier", 1.0));
+ d->dcrawSettings->setDontStretchPixels(config->readBoolEntry("DontStretchPixels", false));
+ d->dcrawSettings->setUnclipColor(config->readNumEntry("UnclipColors", 0));
+ d->dcrawSettings->setWhiteBalance((DRawDecoding::WhiteBalance)
+ config->readNumEntry("WhiteBalance",
+ DRawDecoding::CAMERA));
+ d->dcrawSettings->setCustomWhiteBalance(config->readNumEntry("CustomWhiteBalance", 6500));
+ d->dcrawSettings->setCustomWhiteBalanceGreen(config->readDoubleNumEntry("CustomWhiteBalanceGreen", 1.0));
+ d->dcrawSettings->setFourColor(config->readBoolEntry("RGBInterpolate4Colors", false));
+ d->dcrawSettings->setQuality((DRawDecoding::DecodingQuality)
+ config->readNumEntry("RAWQuality",
+ DRawDecoding::BILINEAR));
+ d->dcrawSettings->setBrightness(config->readDoubleNumEntry("RAWBrightness", 1.0));
+ d->dcrawSettings->setMedianFilterPasses(config->readNumEntry("MedianFilterPasses", 0));
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupdcraw.h b/src/utilities/setup/setupdcraw.h
new file mode 100644
index 00000000..835199f4
--- /dev/null
+++ b/src/utilities/setup/setupdcraw.h
@@ -0,0 +1,67 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-02-06
+ * Description : setup RAW decoding settings.
+ *
+ * Copyright (C) 2007-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 SETUPDCRAW_H
+#define SETUPDCRAW_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class SetupDcrawPriv;
+
+class DIGIKAM_EXPORT SetupDcraw : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupDcraw(TQWidget* parent = 0);
+ ~SetupDcraw();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void slotSixteenBitsImageToggled(bool);
+
+private:
+
+ SetupDcrawPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPDCRAW_H
diff --git a/src/utilities/setup/setupeditor.cpp b/src/utilities/setup/setupeditor.cpp
new file mode 100644
index 00000000..337b5655
--- /dev/null
+++ b/src/utilities/setup/setupeditor.cpp
@@ -0,0 +1,176 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-08-03
+ * Description : setup Image Editor tab.
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqlayout.h>
+#include <tqcolor.h>
+#include <tqhbox.h>
+#include <tqvgroupbox.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqcheckbox.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <kcolorbutton.h>
+#include <knuminput.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "setupeditor.h"
+#include "setupeditor.moc"
+
+namespace Digikam
+{
+class SetupEditorPriv
+{
+public:
+
+ SetupEditorPriv()
+ {
+ hideToolBar = 0;
+ themebackgroundColor = 0;
+ backgroundColor = 0;
+ colorBox = 0;
+ overExposureColor = 0;
+ underExposureColor = 0;
+ useRawImportTool = 0;
+ }
+
+ TQHBox *colorBox;
+
+ TQCheckBox *hideToolBar;
+ TQCheckBox *themebackgroundColor;
+ TQCheckBox *useRawImportTool;
+
+ KColorButton *backgroundColor;
+ KColorButton *underExposureColor;
+ KColorButton *overExposureColor;
+};
+
+SetupEditor::SetupEditor(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupEditorPriv;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ TQVGroupBox *interfaceOptionsGroup = new TQVGroupBox(i18n("Interface Options"), parent);
+
+ d->themebackgroundColor = new TQCheckBox(i18n("&Use theme background color"), interfaceOptionsGroup);
+
+ TQWhatsThis::add(d->themebackgroundColor, i18n("<p>Enable this option to use background theme "
+ "color in image editor area"));
+
+ d->colorBox = new TQHBox(interfaceOptionsGroup);
+
+ TQLabel *backgroundColorlabel = new TQLabel(i18n("&Background color:"), d->colorBox);
+
+ d->backgroundColor = new KColorButton(d->colorBox);
+ backgroundColorlabel->setBuddy(d->backgroundColor);
+ TQWhatsThis::add(d->backgroundColor, i18n("<p>Customize background color to use "
+ "in image editor area."));
+
+ d->hideToolBar = new TQCheckBox(i18n("H&ide toolbar in fullscreen mode"), interfaceOptionsGroup);
+
+ d->useRawImportTool = new TQCheckBox(i18n("Use Raw Import Tool to handle Raw image"), interfaceOptionsGroup);
+ TQWhatsThis::add(d->useRawImportTool, i18n("<p>Set on this option to use Raw Import "
+ "tool before to load a Raw image, "
+ "to customize indeep decoding settings."));
+
+ // --------------------------------------------------------
+
+ TQVGroupBox *exposureOptionsGroup = new TQVGroupBox(i18n("Exposure Indicators"), parent);
+
+ TQHBox *underExpoBox = new TQHBox(exposureOptionsGroup);
+ TQLabel *underExpoColorlabel = new TQLabel( i18n("&Under-exposure color:"), underExpoBox);
+ d->underExposureColor = new KColorButton(underExpoBox);
+ underExpoColorlabel->setBuddy(d->underExposureColor);
+ TQWhatsThis::add(d->underExposureColor, i18n("<p>Customize the color used in image editor to identify "
+ "under-exposed pixels."));
+
+ TQHBox *overExpoBox = new TQHBox(exposureOptionsGroup);
+ TQLabel *overExpoColorlabel = new TQLabel( i18n("&Over-exposure color:"), overExpoBox);
+ d->overExposureColor = new KColorButton(overExpoBox);
+ overExpoColorlabel->setBuddy(d->overExposureColor);
+ TQWhatsThis::add(d->overExposureColor, i18n("<p>Customize the color used in image editor to identify "
+ "over-exposed pixels."));
+
+ // --------------------------------------------------------
+
+ layout->addWidget(interfaceOptionsGroup);
+ layout->addWidget(exposureOptionsGroup);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ connect(d->themebackgroundColor, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotThemeBackgroundColor(bool)));
+
+ readSettings();
+}
+
+SetupEditor::~SetupEditor()
+{
+ delete d;
+}
+
+void SetupEditor::slotThemeBackgroundColor(bool e)
+{
+ d->colorBox->setEnabled(!e);
+}
+
+void SetupEditor::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ TQColor Black(TQt::black);
+ TQColor White(TQt::white);
+ config->setGroup("ImageViewer Settings");
+ d->themebackgroundColor->setChecked(config->readBoolEntry("UseThemeBackgroundColor", true));
+ d->backgroundColor->setColor(config->readColorEntry("BackgroundColor", &Black));
+ d->hideToolBar->setChecked(config->readBoolEntry("FullScreen Hide ToolBar", false));
+ d->underExposureColor->setColor(config->readColorEntry("UnderExposureColor", &White));
+ d->overExposureColor->setColor(config->readColorEntry("OverExposureColor", &Black));
+ d->useRawImportTool->setChecked(config->readBoolEntry("UseRawImportTool", false));
+}
+
+void SetupEditor::applySettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ config->writeEntry("UseThemeBackgroundColor", d->themebackgroundColor->isChecked());
+ config->writeEntry("BackgroundColor", d->backgroundColor->color());
+ config->writeEntry("FullScreen Hide ToolBar", d->hideToolBar->isChecked());
+ config->writeEntry("UnderExposureColor", d->underExposureColor->color());
+ config->writeEntry("OverExposureColor", d->overExposureColor->color());
+ config->writeEntry("UseRawImportTool", d->useRawImportTool->isChecked());
+ config->sync();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupeditor.h b/src/utilities/setup/setupeditor.h
new file mode 100644
index 00000000..bc7793ad
--- /dev/null
+++ b/src/utilities/setup/setupeditor.h
@@ -0,0 +1,63 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-08-03
+ * Description : setup Image Editor tab.
+ *
+ * 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 SETUPEDITOR_H
+#define SETUPEDITOR_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupEditorPriv;
+
+class SetupEditor : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupEditor(TQWidget* parent = 0);
+ ~SetupEditor();
+
+ void applySettings();
+
+private slots:
+
+ void slotThemeBackgroundColor(bool);
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupEditorPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPEDITOR_H
diff --git a/src/utilities/setup/setupgeneral.cpp b/src/utilities/setup/setupgeneral.cpp
new file mode 100644
index 00000000..2a8db22c
--- /dev/null
+++ b/src/utilities/setup/setupgeneral.cpp
@@ -0,0 +1,313 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-01
+ * Description : general configuration setup tab
+ *
+ * Copyright (C) 2003-2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005-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 <tqlayout.h>
+#include <tqcombobox.h>
+#include <tqvbuttongroup.h>
+#include <tqvgroupbox.h>
+#include <tqhgroupbox.h>
+#include <tqgroupbox.h>
+#include <tqradiobutton.h>
+#include <tqcheckbox.h>
+#include <tqlabel.h>
+#include <tqdir.h>
+#include <tqlistbox.h>
+#include <tqwhatsthis.h>
+#include <tqtooltip.h>
+#include <tqfileinfo.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialogbase.h>
+#include <tdefiledialog.h>
+#include <kurl.h>
+#include <tdemessagebox.h>
+#include <kurlrequester.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "setupgeneral.h"
+#include "setupgeneral.moc"
+
+namespace Digikam
+{
+
+class SetupGeneralPriv
+{
+public:
+
+ SetupGeneralPriv()
+ {
+ albumPathEdit = 0;
+ iconTreeThumbSize = 0;
+ iconTreeThumbLabel = 0;
+ iconShowNameBox = 0;
+ iconShowSizeBox = 0;
+ iconShowDateBox = 0;
+ iconShowModDateBox = 0;
+ iconShowResolutionBox = 0;
+ iconShowCommentsBox = 0;
+ iconShowTagsBox = 0;
+ iconShowRatingBox = 0;
+ rightClickActionComboBox = 0;
+ previewLoadFullImageSize = 0;
+ showFolderTreeViewItemsCount = 0;
+ }
+
+ TQLabel *iconTreeThumbLabel;
+
+ TQCheckBox *iconShowNameBox;
+ TQCheckBox *iconShowSizeBox;
+ TQCheckBox *iconShowDateBox;
+ TQCheckBox *iconShowModDateBox;
+ TQCheckBox *iconShowResolutionBox;
+ TQCheckBox *iconShowCommentsBox;
+ TQCheckBox *iconShowTagsBox;
+ TQCheckBox *iconShowRatingBox;
+ TQCheckBox *previewLoadFullImageSize;
+ TQCheckBox *showFolderTreeViewItemsCount;
+
+ TQComboBox *iconTreeThumbSize;
+ TQComboBox *rightClickActionComboBox;
+
+ KURLRequester *albumPathEdit;
+
+ KDialogBase *mainDialog;
+};
+
+SetupGeneral::SetupGeneral(TQWidget* parent, KDialogBase* dialog )
+ : TQWidget(parent)
+{
+ d = new SetupGeneralPriv;
+ d->mainDialog = dialog;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ TQHGroupBox *albumPathBox = new TQHGroupBox(parent);
+ albumPathBox->setTitle(i18n("Album &Library Path"));
+
+ d->albumPathEdit = new KURLRequester(albumPathBox);
+ d->albumPathEdit->setMode(KFile::Directory | KFile::LocalOnly | KFile::ExistingOnly);
+ TQToolTip::add( d->albumPathEdit, i18n("<p>Here you can set the main path to the digiKam album "
+ "library in your computer."
+ "<p>Write access is required for this path and do not use a "
+ "remote path here, like an NFS mounted file system."));
+
+ connect(d->albumPathEdit, TQ_SIGNAL(urlSelected(const TQString &)),
+ this, TQ_SLOT(slotChangeAlbumPath(const TQString &)));
+
+ connect(d->albumPathEdit, TQ_SIGNAL(textChanged(const TQString&)),
+ this, TQ_SLOT(slotPathEdited(const TQString&)) );
+
+ layout->addWidget(albumPathBox);
+
+ // --------------------------------------------------------
+
+ TQVGroupBox *iconTextGroup = new TQVGroupBox(i18n("Thumbnail Information"), parent);
+
+ d->iconShowNameBox = new TQCheckBox(i18n("Show file &name"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowNameBox, i18n("<p>Set this option to show the file name below the image thumbnail."));
+
+ d->iconShowSizeBox = new TQCheckBox(i18n("Show file si&ze"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowSizeBox, i18n("<p>Set this option to show the file size below the image thumbnail."));
+
+ d->iconShowDateBox = new TQCheckBox(i18n("Show camera creation &date"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowDateBox, i18n("<p>Set this option to show the camera creation date "
+ "below the image thumbnail."));
+
+ d->iconShowModDateBox = new TQCheckBox(i18n("Show file &modification date"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowModDateBox, i18n("<p>Set this option to show the file modification date "
+ "below the image thumbnail."));
+
+ d->iconShowCommentsBox = new TQCheckBox(i18n("Show digiKam &captions"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowCommentsBox, i18n("<p>Set this option to show the digiKam captions "
+ "below the image thumbnail."));
+
+ d->iconShowTagsBox = new TQCheckBox(i18n("Show digiKam &tags"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowTagsBox, i18n("<p>Set this option to show the digiKam tags "
+ "below the image thumbnail."));
+
+ d->iconShowRatingBox = new TQCheckBox(i18n("Show digiKam &rating"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowRatingBox, i18n("<p>Set this option to show the digiKam rating "
+ "below the image thumbnail."));
+
+ d->iconShowResolutionBox = new TQCheckBox(i18n("Show ima&ge dimensions (warning: slow)"), iconTextGroup);
+ TQWhatsThis::add( d->iconShowResolutionBox, i18n("<p>Set this option to show the image size in pixels "
+ "below the image thumbnail."));
+
+ layout->addWidget(iconTextGroup);
+
+ // --------------------------------------------------------
+
+ TQVGroupBox *interfaceOptionsGroup = new TQVGroupBox(i18n("Interface Options"), parent);
+ interfaceOptionsGroup->setColumnLayout(0, TQt::Vertical );
+ interfaceOptionsGroup->layout()->setMargin(KDialog::marginHint());
+ TQGridLayout* ifaceSettingsLayout = new TQGridLayout(interfaceOptionsGroup->layout(), 3, 4, KDialog::spacingHint());
+
+ d->iconTreeThumbLabel = new TQLabel(i18n("Sidebar thumbnail size:"), interfaceOptionsGroup);
+ d->iconTreeThumbSize = new TQComboBox(false, interfaceOptionsGroup);
+ d->iconTreeThumbSize->insertItem("16");
+ d->iconTreeThumbSize->insertItem("22");
+ d->iconTreeThumbSize->insertItem("32");
+ d->iconTreeThumbSize->insertItem("48");
+ TQToolTip::add( d->iconTreeThumbSize, i18n("<p>Set this option to configure the size "
+ "in pixels of the thumbnails in digiKam's sidebars. "
+ "This option will take effect when you restart "
+ "digiKam."));
+ ifaceSettingsLayout->addMultiCellWidget(d->iconTreeThumbLabel, 0, 0, 0, 0);
+ ifaceSettingsLayout->addMultiCellWidget(d->iconTreeThumbSize, 0, 0, 1, 1);
+
+ d->showFolderTreeViewItemsCount = new TQCheckBox(i18n("Show count of items in all tree-view"), interfaceOptionsGroup);
+ ifaceSettingsLayout->addMultiCellWidget(d->showFolderTreeViewItemsCount, 1, 1, 0, 4);
+
+
+ TQLabel *rightClickLabel = new TQLabel(i18n("Thumbnail click action:"), interfaceOptionsGroup);
+ d->rightClickActionComboBox = new TQComboBox(false, interfaceOptionsGroup);
+ d->rightClickActionComboBox->insertItem(i18n("Show embedded preview"), AlbumSettings::ShowPreview);
+ d->rightClickActionComboBox->insertItem(i18n("Start image editor"), AlbumSettings::StartEditor);
+ TQToolTip::add( d->rightClickActionComboBox, i18n("<p>Here, choose what should happen when you "
+ "click on a thumbnail."));
+ ifaceSettingsLayout->addMultiCellWidget(rightClickLabel, 2 ,2, 0, 0);
+ ifaceSettingsLayout->addMultiCellWidget(d->rightClickActionComboBox, 2, 2, 1, 4);
+
+ d->previewLoadFullImageSize = new TQCheckBox(i18n("Embedded preview loads full image size"), interfaceOptionsGroup);
+ TQWhatsThis::add( d->previewLoadFullImageSize, i18n("<p>Set this option to load the full image size "
+ "with an embedded preview, instead a reduced one. Because this option will take more time "
+ "to load images, use it only if you have a fast computer."));
+ ifaceSettingsLayout->addMultiCellWidget(d->previewLoadFullImageSize, 3, 3, 0, 4);
+
+ layout->addWidget(interfaceOptionsGroup);
+
+ // --------------------------------------------------------
+
+ layout->addStretch();
+
+ readSettings();
+ adjustSize();
+}
+
+SetupGeneral::~SetupGeneral()
+{
+ delete d;
+}
+
+void SetupGeneral::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ settings->setAlbumLibraryPath(d->albumPathEdit->url());
+
+ settings->setDefaultTreeIconSize(d->iconTreeThumbSize->currentText().toInt());
+ settings->setIconShowName(d->iconShowNameBox->isChecked());
+ settings->setIconShowTags(d->iconShowTagsBox->isChecked());
+ settings->setIconShowSize(d->iconShowSizeBox->isChecked());
+ settings->setIconShowDate(d->iconShowDateBox->isChecked());
+ settings->setIconShowModDate(d->iconShowModDateBox->isChecked());
+ settings->setIconShowResolution(d->iconShowResolutionBox->isChecked());
+ settings->setIconShowComments(d->iconShowCommentsBox->isChecked());
+ settings->setIconShowRating(d->iconShowRatingBox->isChecked());
+
+ settings->setItemRightClickAction((AlbumSettings::ItemRightClickAction)
+ d->rightClickActionComboBox->currentItem());
+
+ settings->setPreviewLoadFullImageSize(d->previewLoadFullImageSize->isChecked());
+ settings->setShowFolderTreeViewItemsCount(d->showFolderTreeViewItemsCount->isChecked());
+ settings->saveSettings();
+}
+
+void SetupGeneral::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ d->albumPathEdit->setURL(settings->getAlbumLibraryPath());
+
+ if (settings->getDefaultTreeIconSize() == 16)
+ d->iconTreeThumbSize->setCurrentItem(0);
+ else if (settings->getDefaultTreeIconSize() == 22)
+ d->iconTreeThumbSize->setCurrentItem(1);
+ else if (settings->getDefaultTreeIconSize() == 32)
+ d->iconTreeThumbSize->setCurrentItem(2);
+ else
+ d->iconTreeThumbSize->setCurrentItem(3);
+
+ d->iconShowNameBox->setChecked(settings->getIconShowName());
+ d->iconShowTagsBox->setChecked(settings->getIconShowTags());
+ d->iconShowSizeBox->setChecked(settings->getIconShowSize());
+ d->iconShowDateBox->setChecked(settings->getIconShowDate());
+ d->iconShowModDateBox->setChecked(settings->getIconShowModDate());
+ d->iconShowResolutionBox->setChecked(settings->getIconShowResolution());
+ d->iconShowCommentsBox->setChecked(settings->getIconShowComments());
+ d->iconShowRatingBox->setChecked(settings->getIconShowRating());
+
+ d->rightClickActionComboBox->setCurrentItem((int)settings->getItemRightClickAction());
+
+ d->previewLoadFullImageSize->setChecked(settings->getPreviewLoadFullImageSize());
+ d->showFolderTreeViewItemsCount->setChecked(settings->getShowFolderTreeViewItemsCount());
+}
+
+void SetupGeneral::slotChangeAlbumPath(const TQString &result)
+{
+ if (KURL(result).equals(KURL(TQDir::homeDirPath()), true))
+ {
+ KMessageBox::sorry(0, i18n("Sorry you can't use your home directory as album library."));
+ return;
+ }
+
+ TQFileInfo targetPath(result);
+
+ if (!result.isEmpty() && !targetPath.isWritable())
+ {
+ KMessageBox::information(0, i18n("No write access for this path.\n"
+ "Warning: the caption and tag features will not work."));
+ }
+}
+
+void SetupGeneral::slotPathEdited(const TQString& newPath)
+{
+ if (newPath.isEmpty())
+ {
+ d->mainDialog->enableButtonOK(false);
+ return;
+ }
+
+ if (!newPath.startsWith("/"))
+ {
+ d->albumPathEdit->setURL(TQDir::homeDirPath() + '/' + newPath);
+ }
+
+ TQFileInfo targetPath(newPath);
+ TQDir dir(newPath);
+ d->mainDialog->enableButtonOK(dir.exists() && dir.path() != TQDir::homeDirPath());
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setupgeneral.h b/src/utilities/setup/setupgeneral.h
new file mode 100644
index 00000000..768c4154
--- /dev/null
+++ b/src/utilities/setup/setupgeneral.h
@@ -0,0 +1,67 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-02-01
+ * Description : general configuration setup tab
+ *
+ * Copyright (C) 2003-2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005-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 SETUPGENERAL_H
+#define SETUPGENERAL_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+class KDialogBase;
+
+namespace Digikam
+{
+
+class SetupGeneralPriv;
+
+class SetupGeneral : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupGeneral(TQWidget* parent = 0, KDialogBase* dialog = 0);
+ ~SetupGeneral();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void slotChangeAlbumPath(const TQString &);
+ void slotPathEdited(const TQString&);
+
+private:
+
+ SetupGeneralPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPGENERAL_H
diff --git a/src/utilities/setup/setupicc.cpp b/src/utilities/setup/setupicc.cpp
new file mode 100644
index 00000000..b08750c1
--- /dev/null
+++ b/src/utilities/setup/setupicc.cpp
@@ -0,0 +1,727 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-11-24
+ * Description : Color management setup tab.
+ *
+ * Copyright (C) 2005-2007 by F.J. Cruz <fj.cruz@supercable.es>
+ * 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.
+ *
+ * ============================================================ */
+
+#include <config.h>
+
+// TQt includes.
+
+#include <tqlayout.h>
+#include <tqvbuttongroup.h>
+#include <tqvgroupbox.h>
+#include <tqhgroupbox.h>
+#include <tqgroupbox.h>
+#include <tqcheckbox.h>
+#include <tqradiobutton.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqiconset.h>
+#include <tqpixmap.h>
+#include <tqpushbutton.h>
+#include <tqstringlist.h>
+#include <tqmap.h>
+#include <tqdir.h>
+#include <tqtooltip.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kurlrequester.h>
+#include <klineedit.h>
+#include <tdeconfig.h>
+#include <kcombobox.h>
+#include <tdeapplication.h>
+#include <tdemessagebox.h>
+#include <kurllabel.h>
+#include <kiconloader.h>
+#include <tdeglobalsettings.h>
+#include <kstandarddirs.h>
+
+// lcms includes.
+
+#include LCMS_HEADER
+#if LCMS_VERSION < 114
+#define cmsTakeCopyright(profile) "Unknown"
+#endif // LCMS_VERSION < 114
+
+// Local includes.
+
+#include "ddebug.h"
+#include "squeezedcombobox.h"
+#include "iccprofileinfodlg.h"
+#include "albumsettings.h"
+#include "setupicc.h"
+#include "setupicc.moc"
+
+namespace Digikam
+{
+
+class SetupICCPriv
+{
+public:
+
+ SetupICCPriv()
+ {
+ enableColorManagement = 0;
+ bpcAlgorithm = 0;
+ managedView = 0;
+ defaultApplyICC = 0;
+ defaultAskICC = 0;
+ defaultPathKU = 0;
+ inProfilesKC = 0;
+ workProfilesKC = 0;
+ proofProfilesKC = 0;
+ monitorProfilesKC = 0;
+ renderingIntentKC = 0;
+ infoWorkProfiles = 0;
+ infoMonitorProfiles = 0;
+ infoInProfiles = 0;
+ infoProofProfiles = 0;
+ behaviourGB = 0;
+ defaultPathGB = 0;
+ profilesGB = 0;
+ advancedSettingsGB = 0;
+ monitorIcon = 0;
+ monitorProfiles = 0;
+ }
+
+ TQLabel *monitorIcon;
+ TQLabel *monitorProfiles;
+
+ TQCheckBox *enableColorManagement;
+ TQCheckBox *bpcAlgorithm;
+ TQCheckBox *managedView;
+
+ TQRadioButton *defaultApplyICC;
+ TQRadioButton *defaultAskICC;
+
+ TQPushButton *infoWorkProfiles;
+ TQPushButton *infoMonitorProfiles;
+ TQPushButton *infoInProfiles;
+ TQPushButton *infoProofProfiles;
+
+ TQVGroupBox *behaviourGB;
+ TQHGroupBox *defaultPathGB;
+ TQGroupBox *profilesGB;
+ TQVGroupBox *advancedSettingsGB;
+
+ // Maps to store profile descriptions and profile file path
+ TQMap<TQString, TQString> inICCPath;
+ TQMap<TQString, TQString> workICCPath;
+ TQMap<TQString, TQString> proofICCPath;
+ TQMap<TQString, TQString> monitorICCPath;
+
+ KURLRequester *defaultPathKU;
+
+ KComboBox *renderingIntentKC;
+
+ KDialogBase *mainDialog;
+
+ SqueezedComboBox *inProfilesKC;
+ SqueezedComboBox *workProfilesKC;
+ SqueezedComboBox *proofProfilesKC;
+ SqueezedComboBox *monitorProfilesKC;
+};
+
+SetupICC::SetupICC(TQWidget* parent, KDialogBase* dialog )
+ : TQWidget(parent)
+{
+ d = new SetupICCPriv();
+ d->mainDialog = dialog;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent, 0, KDialog::spacingHint());
+
+ // --------------------------------------------------------
+
+ TQGroupBox *colorPolicy = new TQGroupBox(0, TQt::Horizontal, i18n("Color Management Policy"), parent);
+ TQGridLayout* grid = new TQGridLayout( colorPolicy->layout(), 1, 2, KDialog::spacingHint());
+
+ d->enableColorManagement = new TQCheckBox(colorPolicy);
+ d->enableColorManagement->setText(i18n("Enable Color Management"));
+ TQWhatsThis::add( d->enableColorManagement, i18n("<ul><li>Checked: Color Management is enabled</li>"
+ "<li>Unchecked: Color Management is disabled</li></ul>"));
+
+ KURLLabel *lcmsLogoLabel = new KURLLabel(colorPolicy);
+ lcmsLogoLabel->setText(TQString());
+ lcmsLogoLabel->setURL("http://www.littlecms.com");
+ TDEGlobal::dirs()->addResourceType("logo-lcms", TDEGlobal::dirs()->kde_default("data") + "digikam/data");
+ TQString directory = TDEGlobal::dirs()->findResourceDir("logo-lcms", "logo-lcms.png");
+ lcmsLogoLabel->setPixmap( TQPixmap( directory + "logo-lcms.png" ) );
+ TQToolTip::add(lcmsLogoLabel, i18n("Visit Little CMS project website"));
+
+ d->behaviourGB = new TQVGroupBox(i18n("Behavior"), colorPolicy);
+ TQButtonGroup *behaviourOptions = new TQButtonGroup(2, TQt::Vertical, d->behaviourGB);
+ behaviourOptions->setFrameStyle( TQFrame::NoFrame );
+ behaviourOptions->setInsideMargin(0);
+
+ d->defaultApplyICC = new TQRadioButton(behaviourOptions);
+ d->defaultApplyICC->setText(i18n("Apply when opening an image in the Image Editor"));
+ TQWhatsThis::add( d->defaultApplyICC, i18n("<p>If this option is enabled, digiKam applies the "
+ "Workspace default color profile to an image, without prompting you about missing "
+ "embedded profiles or embedded profiles different from the workspace profile.</p>"));
+
+ d->defaultAskICC = new TQRadioButton(behaviourOptions);
+ d->defaultAskICC->setText(i18n("Ask when opening an image in the Image Editor"));
+ TQWhatsThis::add( d->defaultAskICC, i18n("<p>If this option is enabled, digiKam asks to user "
+ "before it applies the Workspace default color profile to an image which has no "
+ "embedded profile or, if the image has an embedded profile, when it's not the same "
+ "as the workspace profile.</p>"));
+
+ grid->addMultiCellWidget(d->enableColorManagement, 0, 0, 0, 0);
+ grid->addMultiCellWidget(lcmsLogoLabel, 0, 0, 2, 2);
+ grid->addMultiCellWidget(d->behaviourGB, 1, 1, 0, 2);
+ grid->setColStretch(1, 10);
+
+ layout->addWidget(colorPolicy);
+
+ // --------------------------------------------------------
+
+ d->defaultPathGB = new TQHGroupBox(parent);
+ d->defaultPathGB->setTitle(i18n("Color Profiles Directory"));
+
+ d->defaultPathKU = new KURLRequester(d->defaultPathGB);
+ d->defaultPathKU->lineEdit()->setReadOnly(true);
+ d->defaultPathKU->setMode(KFile::Directory | KFile::LocalOnly | KFile::ExistingOnly);
+ TQWhatsThis::add( d->defaultPathKU, i18n("<p>Default path to the color profiles folder. "
+ "You must store all your color profiles in this directory.</p>"));
+
+ layout->addWidget(d->defaultPathGB);
+
+ // --------------------------------------------------------
+
+ d->profilesGB = new TQGroupBox(0, TQt::Horizontal, i18n("ICC Profiles Settings"), parent);
+ TQGridLayout* grid2 = new TQGridLayout( d->profilesGB->layout(), 4, 3, KDialog::spacingHint());
+ grid2->setColStretch(2, 10);
+
+ d->managedView = new TQCheckBox(d->profilesGB);
+ d->managedView->setText(i18n("Use color managed view (warning: slow)"));
+ TQWhatsThis::add( d->managedView, i18n("<p>Turn on this option if "
+ "you want to use your <b>Monitor Color Profile</b> to show your pictures in "
+ "the Image Editor window with a color correction adapted to your monitor. "
+ "Warning: this option can take a while to render "
+ "pictures on the screen, especially with a slow computer.</p>"));
+
+ d->monitorIcon = new TQLabel(d->profilesGB);
+ d->monitorIcon->setPixmap(SmallIcon("tv"));
+ d->monitorProfiles = new TQLabel(i18n("Monitor:"), d->profilesGB);
+ d->monitorProfilesKC = new SqueezedComboBox(d->profilesGB);
+ d->monitorProfiles->setBuddy(d->monitorProfilesKC);
+ TQWhatsThis::add( d->monitorProfilesKC, i18n("<p>Select the color profile for your monitor. "
+ "You need to enable the <b>Use color managed view</b> option to use this profile.</p>"));
+ d->infoMonitorProfiles = new TQPushButton(i18n("Info..."), d->profilesGB);
+ TQWhatsThis::add( d->infoMonitorProfiles, i18n("<p>You can use this button to get more detailed "
+ "information about the selected monitor profile.</p>"));
+
+ grid2->addMultiCellWidget(d->managedView, 0, 0, 0, 3);
+ grid2->addMultiCellWidget(d->monitorIcon, 1, 1, 0, 0);
+ grid2->addMultiCellWidget(d->monitorProfiles, 1, 1, 1, 1);
+ grid2->addMultiCellWidget(d->monitorProfilesKC, 1, 1, 2, 2);
+ grid2->addMultiCellWidget(d->infoMonitorProfiles, 1, 1, 3, 3);
+
+ TQLabel *workIcon = new TQLabel(d->profilesGB);
+ workIcon->setPixmap(SmallIcon("input-tablet"));
+ TQLabel *workProfiles = new TQLabel(i18n("Workspace:"), d->profilesGB);
+ d->workProfilesKC = new SqueezedComboBox(d->profilesGB);
+ workProfiles->setBuddy(d->workProfilesKC);
+ TQWhatsThis::add( d->workProfilesKC, i18n("<p>All the images will be converted to the color "
+ "space of this profile, so you must select a profile appropriate for editing.</p>"
+ "<p>These color profiles are device independent.</p>"));
+ d->infoWorkProfiles = new TQPushButton(i18n("Info..."), d->profilesGB);
+ TQWhatsThis::add( d->infoWorkProfiles, i18n("<p>You can use this button to get more detailed "
+ "information about the selected workspace profile.</p>"));
+
+ grid2->addMultiCellWidget(workIcon, 2, 2, 0, 0);
+ grid2->addMultiCellWidget(workProfiles, 2, 2, 1, 1);
+ grid2->addMultiCellWidget(d->workProfilesKC, 2, 2, 2, 2);
+ grid2->addMultiCellWidget(d->infoWorkProfiles, 2, 2, 3, 3);
+
+ TQLabel *inIcon = new TQLabel(d->profilesGB);
+ inIcon->setPixmap(SmallIcon("camera-photo"));
+ TQLabel *inProfiles = new TQLabel(i18n("Input:"), d->profilesGB);
+ d->inProfilesKC = new SqueezedComboBox(d->profilesGB);
+ inProfiles->setBuddy(d->inProfilesKC);
+ TQWhatsThis::add( d->inProfilesKC, i18n("<p>You must select the profile for your input device "
+ "(usually, your camera, scanner...)</p>"));
+ d->infoInProfiles = new TQPushButton(i18n("Info..."), d->profilesGB);
+ TQWhatsThis::add( d->infoInProfiles, i18n("<p>You can use this button to get more detailed "
+ "information about the selected input profile.</p>"));
+
+ grid2->addMultiCellWidget(inIcon, 3, 3, 0, 0);
+ grid2->addMultiCellWidget(inProfiles, 3, 3, 1, 1);
+ grid2->addMultiCellWidget(d->inProfilesKC, 3, 3, 2, 2);
+ grid2->addMultiCellWidget(d->infoInProfiles, 3, 3, 3, 3);
+
+ TQLabel *proofIcon = new TQLabel(d->profilesGB);
+ proofIcon->setPixmap(SmallIcon("printer"));
+ TQLabel *proofProfiles = new TQLabel(i18n("Soft proof:"), d->profilesGB);
+ d->proofProfilesKC = new SqueezedComboBox(d->profilesGB);
+ proofProfiles->setBuddy(d->proofProfilesKC);
+ TQWhatsThis::add( d->proofProfilesKC, i18n("<p>You must select the profile for your output device "
+ "(usually, your printer). This profile will be used to do a soft proof, so you will "
+ "be able to preview how an image will be rendered via an output device.</p>"));
+ d->infoProofProfiles = new TQPushButton(i18n("Info..."), d->profilesGB);
+ TQWhatsThis::add( d->infoProofProfiles, i18n("<p>You can use this button to get more detailed "
+ "information about the selected soft proof profile.</p>"));
+
+ grid2->addMultiCellWidget(proofIcon, 4, 4, 0, 0);
+ grid2->addMultiCellWidget(proofProfiles, 4, 4, 1, 1);
+ grid2->addMultiCellWidget(d->proofProfilesKC, 4, 4, 2, 2);
+ grid2->addMultiCellWidget(d->infoProofProfiles, 4, 4, 3, 3);
+
+ layout->addWidget(d->profilesGB);
+
+ // --------------------------------------------------------
+
+ d->advancedSettingsGB = new TQVGroupBox(i18n("Advanced Settings"), parent);
+
+ d->bpcAlgorithm = new TQCheckBox(d->advancedSettingsGB);
+ d->bpcAlgorithm->setText(i18n("Use black point compensation"));
+ TQWhatsThis::add( d->bpcAlgorithm, i18n("<p><b>Black Point Compensation</b> is a way to make "
+ "adjustments between the maximum "
+ "black levels of digital files and the black capabilities of various "
+ "digital devices.</p>"));
+
+ TQHBox *hbox2 = new TQHBox(d->advancedSettingsGB);
+ TQLabel *lablel = new TQLabel(hbox2);
+ lablel->setText(i18n("Rendering Intents:"));
+
+ d->renderingIntentKC = new KComboBox(false, hbox2);
+ d->renderingIntentKC->insertItem("Perceptual");
+ d->renderingIntentKC->insertItem("Relative Colorimetric");
+ d->renderingIntentKC->insertItem("Saturation");
+ d->renderingIntentKC->insertItem("Absolute Colorimetric");
+ TQWhatsThis::add( d->renderingIntentKC, i18n("<ul><li><p><b>Perceptual intent</b> causes the full gamut of the image to be "
+ "compressed or expanded to fill the gamut of the destination device, so that gray balance is "
+ "preserved but colorimetric accuracy may not be preserved.</p>"
+ "<p>In other words, if certain colors in an image fall outside of the range of colors that the output "
+ "device can render, the image intent will cause all the colors in the image to be adjusted so that "
+ "the every color in the image falls within the range that can be rendered and so that the relationship "
+ "between colors is preserved as much as possible.</p>"
+ "<p>This intent is most suitable for display of photographs and images, and is the default intent.</p></li>"
+ "<li><p><b>Absolute Colorimetric intent</b> causes any colors that fall outside the range that the output device "
+ "can render are adjusted to the closest color that can be rendered, while all other colors are "
+ "left unchanged.</p>"
+ "<p>This intent preserves the white point and is most suitable for spot colors (Pantone, TruMatch, "
+ "logo colors, ...).</p></li>"
+ "<li><p><b>Relative Colorimetric intent</b> is defined such that any colors that fall outside the range that the "
+ "output device can render are adjusted to the closest color that can be rendered, while all other colors "
+ "are left unchanged. Proof intent does not preserve the white point.</p></li>"
+ "<li><p><b>Saturation intent</b> preserves the saturation of colors in the image at the possible expense of "
+ "hue and lightness.</p>"
+ "<p>Implementation of this intent remains somewhat problematic, and the ICC is still working on methods to "
+ "achieve the desired effects.</p>"
+ "<p>This intent is most suitable for business graphics such as charts, where it is more important that the "
+ "colors be vivid and contrast well with each other rather than a specific color.</p></li></ul>"));
+
+ layout->addWidget(d->advancedSettingsGB);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ connect(d->managedView, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotToggleManagedView(bool)));
+
+ connect(lcmsLogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)),
+ this, TQ_SLOT(processLCMSURL(const TQString&)));
+
+ connect(d->enableColorManagement, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotToggledWidgets(bool)));
+
+ connect(d->infoProofProfiles, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotClickedProof()) );
+
+ connect(d->infoInProfiles, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotClickedIn()) );
+
+ connect(d->infoMonitorProfiles, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotClickedMonitor()) );
+
+ connect(d->infoWorkProfiles, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotClickedWork()));
+
+ connect(d->defaultPathKU, TQ_SIGNAL(urlSelected(const TQString&)),
+ this, TQ_SLOT(slotFillCombos(const TQString&)));
+
+ // --------------------------------------------------------
+
+ adjustSize();
+ readSettings();
+ slotToggledWidgets(d->enableColorManagement->isChecked());
+ slotToggleManagedView(d->managedView->isChecked());
+}
+
+SetupICC::~SetupICC()
+{
+ delete d;
+}
+
+void SetupICC::processLCMSURL(const TQString& url)
+{
+ TDEApplication::kApplication()->invokeBrowser(url);
+}
+
+void SetupICC::applySettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("Color Management");
+
+ config->writeEntry("EnableCM", d->enableColorManagement->isChecked());
+
+ if (!d->enableColorManagement->isChecked())
+ return; // No need to write settings in this case.
+
+ if (d->defaultApplyICC->isChecked())
+ config->writeEntry("BehaviourICC", true);
+ else
+ config->writeEntry("BehaviourICC", false);
+
+ config->writePathEntry("DefaultPath", d->defaultPathKU->url());
+ config->writeEntry("WorkSpaceProfile", d->workProfilesKC->currentItem());
+ config->writeEntry("MonitorProfile", d->monitorProfilesKC->currentItem());
+ config->writeEntry("InProfile", d->inProfilesKC->currentItem());
+ config->writeEntry("ProofProfile", d->proofProfilesKC->currentItem());
+ config->writeEntry("BPCAlgorithm", d->bpcAlgorithm->isChecked());
+ config->writeEntry("RenderingIntent", d->renderingIntentKC->currentItem());
+ config->writeEntry("ManagedView", d->managedView->isChecked());
+
+ config->writePathEntry("InProfileFile",
+ *(d->inICCPath.find(d->inProfilesKC->itemHighlighted())));
+ config->writePathEntry("WorkProfileFile",
+ *(d->workICCPath.find(d->workProfilesKC->itemHighlighted())));
+ config->writePathEntry("MonitorProfileFile",
+ *(d->monitorICCPath.find(d->monitorProfilesKC->itemHighlighted())));
+ config->writePathEntry("ProofProfileFile",
+ *(d->proofICCPath.find(d->proofProfilesKC->itemHighlighted())));
+}
+
+void SetupICC::readSettings(bool restore)
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("Color Management");
+
+ if (!restore)
+ d->enableColorManagement->setChecked(config->readBoolEntry("EnableCM", false));
+
+ d->defaultPathKU->setURL(config->readPathEntry("DefaultPath", TQString()));
+ d->bpcAlgorithm->setChecked(config->readBoolEntry("BPCAlgorithm", false));
+ d->renderingIntentKC->setCurrentItem(config->readNumEntry("RenderingIntent", 0));
+ d->managedView->setChecked(config->readBoolEntry("ManagedView", false));
+
+ if (config->readBoolEntry("BehaviourICC"))
+ d->defaultApplyICC->setChecked(true);
+ else
+ d->defaultAskICC->setChecked(true);
+
+ fillCombos(d->defaultPathKU->url(), false);
+
+ d->workProfilesKC->setCurrentItem(config->readNumEntry("WorkSpaceProfile", 0));
+ d->monitorProfilesKC->setCurrentItem(config->readNumEntry("MonitorProfile", 0));
+ d->inProfilesKC->setCurrentItem(config->readNumEntry("InProfile", 0));
+ d->proofProfilesKC->setCurrentItem(config->readNumEntry("ProofProfile", 0));
+}
+
+void SetupICC::slotFillCombos(const TQString& path)
+{
+ fillCombos(path, true);
+}
+
+void SetupICC::fillCombos(const TQString& path, bool report)
+{
+ if (!d->enableColorManagement->isChecked())
+ return;
+
+ d->inProfilesKC->clear();
+ d->monitorProfilesKC->clear();
+ d->workProfilesKC->clear();
+ d->proofProfilesKC->clear();
+ d->inICCPath.clear();
+ d->workICCPath.clear();
+ d->proofICCPath.clear();
+ d->monitorICCPath.clear();
+ TQDir dir(path);
+
+ if (path.isEmpty() || !dir.exists() || !dir.isReadable())
+ {
+ if (report)
+ KMessageBox::sorry(this, i18n("<p>You must set a correct default "
+ "path for your ICC color profiles files.</p>"));
+
+ d->mainDialog->enableButtonOK(false);
+ return;
+ }
+ d->mainDialog->enableButtonOK(true);
+
+ // Look the ICC profile path repository set by user.
+ TQDir userProfilesDir(path, "*.icc;*.icm", TQDir::Files);
+ const TQFileInfoList* usersFiles = userProfilesDir.entryInfoList();
+ DDebug() << "Scanning ICC profiles from user repository: " << path << endl;
+
+ if ( !parseProfilesfromDir(usersFiles) )
+ {
+ if (report)
+ {
+ TQString message = i18n("<p>Sorry, there are no ICC profiles files in ");
+ message.append(path);
+ message.append(i18n("</p>"));
+ KMessageBox::sorry(this, message);
+ }
+
+ DDebug() << "No ICC profile files found!!!" << endl;
+ d->mainDialog->enableButtonOK(false);
+ return;
+ }
+
+ // Look the ICC color-space profile path include with digiKam dist.
+ TDEGlobal::dirs()->addResourceType("profiles", TDEGlobal::dirs()->kde_default("data") + "digikam/profiles");
+ TQString digiKamProfilesPath = TDEGlobal::dirs()->findResourceDir("profiles", "srgb.icm");
+ TQDir digiKamProfilesDir(digiKamProfilesPath, "*.icc;*.icm", TQDir::Files);
+ const TQFileInfoList* digiKamFiles = digiKamProfilesDir.entryInfoList();
+ DDebug() << "Scanning ICC profiles included with digiKam: " << digiKamProfilesPath << endl;
+ parseProfilesfromDir(digiKamFiles);
+
+ d->monitorProfilesKC->insertSqueezedList(d->monitorICCPath.keys(), 0);
+ if (d->monitorICCPath.keys().isEmpty())
+ {
+ d->managedView->setEnabled(false);
+ d->managedView->setChecked(false);
+ }
+ else
+ {
+ d->managedView->setEnabled(true);
+ }
+
+ d->inProfilesKC->insertSqueezedList(d->inICCPath.keys(), 0);
+ d->proofProfilesKC->insertSqueezedList(d->proofICCPath.keys(), 0);
+
+ d->workProfilesKC->insertSqueezedList(d->workICCPath.keys(), 0);
+ if (d->workICCPath.keys().isEmpty())
+ {
+ // If there is no workspace icc profiles available,
+ // the CM is broken and cannot be used.
+ d->mainDialog->enableButtonOK(false);
+ return;
+ }
+
+ d->mainDialog->enableButtonOK(true);
+}
+
+bool SetupICC::parseProfilesfromDir(const TQFileInfoList* files)
+{
+ cmsHPROFILE tmpProfile=0;
+ bool findIccFiles=false;
+
+ if (files)
+ {
+ TQFileInfoListIterator it(*files);
+ TQFileInfo *fileInfo=0;
+
+ while ((fileInfo = it.current()) != 0)
+ {
+ if (fileInfo->isFile() && fileInfo->isReadable())
+ {
+ TQString fileName = fileInfo->filePath();
+ tmpProfile = cmsOpenProfileFromFile(TQFile::encodeName(fileName), "r");
+
+ if (tmpProfile == NULL)
+ {
+ DDebug() << "Error: Parsed profile is NULL (invalid profile); " << fileName << endl;
+ cmsCloseProfile(tmpProfile);
+ ++it;
+ TQString message = i18n("<p>The following profile is invalid:</p><p><b>");
+ message.append(fileName);
+ message.append("</b></p><p>To avoid this message remove it from color profiles repository</p>");
+ message.append("<p>Do you want digiKam do it for you?</p>");
+ if (KMessageBox::warningYesNo(this, message, i18n("Invalid Profile")) == 3)
+ {
+ if (TQFile::remove(fileName))
+ {
+ KMessageBox::information(this, i18n("Invalid color profile has been removed"));
+ }
+ else
+ {
+ KMessageBox::information(this, i18n("<p>digiKam has failed to remove the invalid color profile</p><p>You have to do it manually</p>"));
+ }
+ }
+
+ continue;
+ }
+
+ TQString profileDescription = TQString((cmsTakeProductDesc(tmpProfile)));
+
+ switch ((int)cmsGetDeviceClass(tmpProfile))
+ {
+ case icSigInputClass:
+ {
+ if (TQString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ d->inICCPath.insert(fileName, fileName);
+ else
+ d->inICCPath.insert(TQString(cmsTakeProductDesc(tmpProfile)), fileName);
+
+ DDebug() << "ICC file: " << fileName << " ==> Input device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ case icSigDisplayClass:
+ {
+ if (TQString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ {
+ d->monitorICCPath.insert(fileName, fileName);
+ d->workICCPath.insert(fileName, fileName);
+ }
+ else
+ {
+ d->monitorICCPath.insert(TQString(cmsTakeProductDesc(tmpProfile)), fileName);
+ d->workICCPath.insert(TQString(cmsTakeProductDesc(tmpProfile)), fileName);
+ }
+
+ DDebug() << "ICC file: " << fileName << " ==> Monitor device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ case icSigOutputClass:
+ {
+ if (TQString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ d->proofICCPath.insert(fileName, fileName);
+ else
+ d->proofICCPath.insert(TQString(cmsTakeProductDesc(tmpProfile)), fileName);
+
+ DDebug() << "ICC file: " << fileName << " ==> Output device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ case icSigColorSpaceClass:
+ {
+ if (TQString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ {
+ d->inICCPath.insert(fileName, fileName);
+ d->workICCPath.insert(fileName, fileName);
+ }
+ else
+ {
+ d->inICCPath.insert(TQString(cmsTakeProductDesc(tmpProfile)), fileName);
+ d->workICCPath.insert(TQString(cmsTakeProductDesc(tmpProfile)), fileName);
+ }
+
+ DDebug() << "ICC file: " << fileName << " ==> WorkingSpace device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ default:
+ {
+ DDebug() << "ICC file: " << fileName << " ==> UNKNOW device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ break;
+ }
+ }
+
+ cmsCloseProfile(tmpProfile);
+ }
+ ++it;
+ }
+ }
+
+ return findIccFiles;
+}
+
+void SetupICC::slotToggledWidgets(bool t)
+{
+ d->behaviourGB->setEnabled(t);
+ d->defaultPathGB->setEnabled(t);
+ d->profilesGB->setEnabled(t);
+ d->advancedSettingsGB->setEnabled(t);
+
+ if (t)
+ {
+ readSettings(true);
+ slotToggleManagedView(d->managedView->isChecked());
+ }
+ else
+ d->mainDialog->enableButtonOK(true);
+}
+
+void SetupICC::slotClickedWork()
+{
+ profileInfo(*(d->workICCPath.find(d->workProfilesKC->itemHighlighted())));
+}
+
+void SetupICC::slotClickedIn()
+{
+ profileInfo(*(d->inICCPath.find(d->inProfilesKC->itemHighlighted())));
+}
+
+void SetupICC::slotClickedMonitor()
+{
+ profileInfo(*(d->monitorICCPath.find(d->monitorProfilesKC->itemHighlighted())));
+}
+
+void SetupICC::slotClickedProof()
+{
+ profileInfo(*(d->proofICCPath.find(d->proofProfilesKC->itemHighlighted())));
+}
+
+void SetupICC::profileInfo(const TQString& profile)
+{
+ if (profile.isEmpty())
+ {
+ KMessageBox::error(this, i18n("Sorry, there is not any selected profile"), i18n("Profile Error"));
+ return;
+ }
+
+ ICCProfileInfoDlg infoDlg(this, profile);
+ infoDlg.exec();
+}
+
+void SetupICC::slotToggleManagedView(bool b)
+{
+ d->monitorIcon->setEnabled(b);
+ d->monitorProfiles->setEnabled(b);
+ d->monitorProfilesKC->setEnabled(b);
+ d->infoMonitorProfiles->setEnabled(b);
+}
+
+bool SetupICC::iccRepositoryIsValid()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("Color Management");
+
+ // If color management is disable, no need to check anymore.
+ if (!config->readBoolEntry("EnableCM", false))
+ return true;
+
+ // To be valid, the ICC profiles repository must exist and be readable.
+
+ TQDir tmpPath(config->readPathEntry("DefaultPath", TQString()));
+ DDebug() << "ICC profiles repository is: " << tmpPath.dirName() << endl;
+
+ if ( tmpPath.exists() && tmpPath.isReadable() )
+ return true;
+
+ return false;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupicc.h b/src/utilities/setup/setupicc.h
new file mode 100644
index 00000000..8eaaece1
--- /dev/null
+++ b/src/utilities/setup/setupicc.h
@@ -0,0 +1,86 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-11-24
+ * Description : Color management setup tab.
+ *
+ * Copyright (C) 2005-2007 by F.J. Cruz <fj.cruz@supercable.es>
+ * 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 SETUPICC_H
+#define SETUPICC_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+#include <tqmap.h>
+#include <tqdir.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class KDialogBase;
+
+namespace Digikam
+{
+
+class SetupICCPriv;
+
+class DIGIKAM_EXPORT SetupICC : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupICC(TQWidget* parent = 0, KDialogBase* dialog = 0);
+ ~SetupICC();
+
+ void applySettings();
+
+ static bool iccRepositoryIsValid();
+
+private:
+
+ void readSettings(bool restore=false);
+ void fillCombos(const TQString& path, bool report);
+ void enableWidgets();
+ void disableWidgets();
+ void profileInfo(const TQString&);
+ bool parseProfilesfromDir(const TQFileInfoList* files);
+
+private slots:
+
+ void processLCMSURL(const TQString&);
+ void slotToggledWidgets(bool);
+ void slotToggleManagedView(bool);
+ void slotFillCombos(const TQString&);
+ void slotClickedIn();
+ void slotClickedWork();
+ void slotClickedMonitor();
+ void slotClickedProof();
+
+private:
+
+ SetupICCPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPICC_H
diff --git a/src/utilities/setup/setupidentity.cpp b/src/utilities/setup/setupidentity.cpp
new file mode 100644
index 00000000..ecbfdfbf
--- /dev/null
+++ b/src/utilities/setup/setupidentity.cpp
@@ -0,0 +1,217 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-07-04
+ * Description : default IPTC identity setup tab.
+ *
+ * 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 <tqlayout.h>
+#include <tqhgroupbox.h>
+#include <tqgroupbox.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqvalidator.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <klineedit.h>
+#include <kactivelabel.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "setupidentity.h"
+#include "setupidentity.moc"
+
+namespace Digikam
+{
+
+class SetupIdentityPriv
+{
+public:
+
+ SetupIdentityPriv()
+ {
+ authorEdit = 0;
+ authorTitleEdit = 0;
+ creditEdit = 0;
+ sourceEdit = 0;
+ copyrightEdit = 0;
+ }
+
+ KLineEdit *authorEdit;
+ KLineEdit *authorTitleEdit;
+ KLineEdit *creditEdit;
+ KLineEdit *sourceEdit;
+ KLineEdit *copyrightEdit;
+};
+
+SetupIdentity::SetupIdentity(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupIdentityPriv;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ // IPTC only accept printable Ascii char.
+ TQRegExp asciiRx("[\x20-\x7F]+$");
+ TQValidator *asciiValidator = new TQRegExpValidator(asciiRx, this);
+
+ TQGroupBox *photographerIdGroup = new TQGroupBox(0, TQt::Horizontal, i18n("Photographer and Copyright Information"), parent);
+ TQGridLayout* grid = new TQGridLayout( photographerIdGroup->layout(), 1, 1, KDialog::spacingHint());
+
+ TQLabel *label1 = new TQLabel(i18n("Author:"), photographerIdGroup);
+ d->authorEdit = new KLineEdit(photographerIdGroup);
+ d->authorEdit->setValidator(asciiValidator);
+ d->authorEdit->setMaxLength(32);
+ label1->setBuddy(d->authorEdit);
+ grid->addMultiCellWidget(label1, 0, 0, 0, 0);
+ grid->addMultiCellWidget(d->authorEdit, 0, 0, 1, 1);
+ TQWhatsThis::add( d->authorEdit, i18n("<p>This field should contain your name, or the name of the person who created the photograph. "
+ "If it is not appropriate to add the name of the photographer (for example, if the identify of "
+ "the photographer needs to be protected) the name of a company or organization can also be used. "
+ "Once saved, this field should not be changed by anyone. This field does not support the use of "
+ "commas or semi-colons as separator. \nThis field is limited to 32 ASCII characters.</p>"));
+
+ TQLabel *label2 = new TQLabel(i18n("Author Title:"), photographerIdGroup);
+ d->authorTitleEdit = new KLineEdit(photographerIdGroup);
+ d->authorTitleEdit->setValidator(asciiValidator);
+ d->authorTitleEdit->setMaxLength(32);
+ label2->setBuddy(d->authorTitleEdit);
+ grid->addMultiCellWidget(label2, 1, 1, 0, 0);
+ grid->addMultiCellWidget(d->authorTitleEdit, 1, 1, 1, 1);
+ TQWhatsThis::add( d->authorTitleEdit, i18n("<p>This field should contain the job title of the photographer. Examples might include "
+ "titles such as: Staff Photographer, Freelance Photographer, or Independent Commercial "
+ "Photographer. Since this is a qualifier for the Author field, the Author field must also "
+ "be filled out. \nThis field is limited to 32 ASCII characters.</p>"));
+
+ // --------------------------------------------------------
+
+ TQGroupBox *creditsGroup = new TQGroupBox(0, TQt::Horizontal, i18n("Credit and Copyright"), parent);
+ TQGridLayout* grid2 = new TQGridLayout( creditsGroup->layout(), 2, 1, KDialog::spacingHint());
+
+ TQLabel *label3 = new TQLabel(i18n("Credit:"), creditsGroup);
+ d->creditEdit = new KLineEdit(creditsGroup);
+ d->creditEdit->setValidator(asciiValidator);
+ d->creditEdit->setMaxLength(32);
+ label3->setBuddy(d->creditEdit);
+ grid2->addMultiCellWidget(label3, 0, 0, 0, 0);
+ grid2->addMultiCellWidget(d->creditEdit, 0, 0, 1, 1);
+ TQWhatsThis::add( d->creditEdit, i18n("<p>(synonymous to Provider): Use the Provider field to identify who is providing the photograph. "
+ "This does not necessarily have to be the author. If a photographer is working for a news agency "
+ "such as Reuters or the Associated Press, these organizations could be listed here as they are "
+ "\"providing\" the image for use by others. If the image is a stock photograph, then the group "
+ "(agency) involved in supplying the image should be listed here. "
+ "\nThis field is limited to 32 ASCII characters.</p>"));
+
+ TQLabel *label4 = new TQLabel(i18n("Source:"), creditsGroup);
+ d->sourceEdit = new KLineEdit(creditsGroup);
+ d->sourceEdit->setValidator(asciiValidator);
+ d->sourceEdit->setMaxLength(32);
+ label4->setBuddy(d->sourceEdit);
+ grid2->addMultiCellWidget(label4, 1, 1, 0, 0);
+ grid2->addMultiCellWidget(d->sourceEdit, 1, 1, 1, 1);
+ TQWhatsThis::add( d->sourceEdit, i18n("<p>The Source field should be used to identify the original owner or copyright holder of the "
+ "photograph. The value of this field should never be changed after the information is entered "
+ "following the image's creation. While not yet enforced by the custom panels, you should consider "
+ "this to be a \"write-once\" field. The source could be an individual, an agency, or a "
+ "member of an agency. To aid in later searches, it is suggested to separate any slashes "
+ "\"/\" with a blank space. Use the form \"photographer / agency\" rather than "
+ "\"photographer/agency.\" Source may also be different from Creator and from the names "
+ "listed in the Copyright Notice.\nThis field is limited to 32 ASCII characters.</p>"));
+
+ TQLabel *label5 = new TQLabel(i18n("Copyright:"), creditsGroup);
+ d->copyrightEdit = new KLineEdit(creditsGroup);
+ d->copyrightEdit->setValidator(asciiValidator);
+ d->copyrightEdit->setMaxLength(128);
+ label5->setBuddy(d->copyrightEdit);
+ grid2->addMultiCellWidget(label5, 2, 2, 0, 0);
+ grid2->addMultiCellWidget(d->copyrightEdit, 2, 2, 1, 1);
+ TQWhatsThis::add( d->copyrightEdit, i18n("<p>The Copyright Notice should contain any necessary copyright notice for claiming the intellectual "
+ "property, and should identify the current owner(s) of the copyright for the photograph. Usually, "
+ "this would be the photographer, but if the image was done by an employee or as work-for-hire, "
+ "then the agency or company should be listed. Use the form appropriate to your country. USA: "
+ "&copy; {date of first publication} name of copyright owner, as in \"&copy;2005 John Doe.\" "
+ "Note, the word \"copyright\" or the abbreviation \"copr\" may be used in place of the &copy; symbol. "
+ "In some foreign countries only the copyright symbol is recognized and the abbreviation does not work. "
+ "Furthermore the copyright symbol must be a full circle with a \"c\" inside; using something like (c) "
+ "where the parentheses form a partial circle is not sufficient. For additional protection worldwide, "
+ "use of the phrase, \"all rights reserved\" following the notice above is encouraged. \nIn Europe "
+ "you would use: Copyright {Year} {Copyright owner}, all rights reserved. \nIn Japan, for maximum "
+ "protection, the following three items should appear in the copyright field of the IPTC Core: "
+ "(a) the word, Copyright; (b) year of the first publication; and (c) name of the author. "
+ "You may also wish to include the phrase \"all rights reserved.\"\n"
+ "This field is limited to 128 ASCII characters.</p>"));
+
+ // --------------------------------------------------------
+
+ KActiveLabel *note = new KActiveLabel(i18n("<b>Note: These informations are used to set "
+ "<b><a href='http://en.wikipedia.org/wiki/IPTC'>IPTC</a></b> tags contents. "
+ "IPTC text tags only support the printable "
+ "<b><a href='http://en.wikipedia.org/wiki/Ascii'>ASCII</a></b> "
+ "characters set and limit strings size. "
+ "Use contextual help for details.</b>"), parent);
+
+ // --------------------------------------------------------
+
+ layout->addWidget(photographerIdGroup);
+ layout->addWidget(creditsGroup);
+ layout->addWidget(note);
+ layout->addStretch();
+
+ readSettings();
+}
+
+SetupIdentity::~SetupIdentity()
+{
+ delete d;
+}
+
+void SetupIdentity::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ settings->setIptcAuthor(d->authorEdit->text());
+ settings->setIptcAuthorTitle(d->authorTitleEdit->text());
+ settings->setIptcCredit(d->creditEdit->text());
+ settings->setIptcSource(d->sourceEdit->text());
+ settings->setIptcCopyright(d->copyrightEdit->text());
+ settings->saveSettings();
+}
+
+void SetupIdentity::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ d->authorEdit->setText(settings->getIptcAuthor());
+ d->authorTitleEdit->setText(settings->getIptcAuthorTitle());
+ d->creditEdit->setText(settings->getIptcCredit());
+ d->sourceEdit->setText(settings->getIptcSource());
+ d->copyrightEdit->setText(settings->getIptcCopyright());
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setupidentity.h b/src/utilities/setup/setupidentity.h
new file mode 100644
index 00000000..ae26dc77
--- /dev/null
+++ b/src/utilities/setup/setupidentity.h
@@ -0,0 +1,60 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-07-04
+ * Description : default IPTC identity setup tab.
+ *
+ * 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 SETUP_IDENTITY_H
+#define SETUP_IDENTITY_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupIdentityPriv;
+
+class SetupIdentity : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupIdentity(TQWidget* parent = 0);
+ ~SetupIdentity();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupIdentityPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif // SETUP_IDENTITY_H
diff --git a/src/utilities/setup/setupiofiles.cpp b/src/utilities/setup/setupiofiles.cpp
new file mode 100644
index 00000000..6cdf23de
--- /dev/null
+++ b/src/utilities/setup/setupiofiles.cpp
@@ -0,0 +1,137 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-01-23
+ * Description : setup image editor output files settings.
+ *
+ * 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 <tqlayout.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+#include <kseparator.h>
+
+// Local includes.
+
+#include "jpegsettings.h"
+#include "pngsettings.h"
+#include "tiffsettings.h"
+#include "jp2ksettings.h"
+#include "setupiofiles.h"
+#include "setupiofiles.moc"
+
+namespace Digikam
+{
+
+class SetupIOFilesPriv
+{
+public:
+
+
+ SetupIOFilesPriv()
+ {
+ JPEGOptions = 0;
+ PNGOptions = 0;
+ TIFFOptions = 0;
+ JPEG2000Options = 0;
+ }
+
+ JPEGSettings *JPEGOptions;
+
+ PNGSettings *PNGOptions;
+
+ TIFFSettings *TIFFOptions;
+
+ JP2KSettings *JPEG2000Options;
+};
+
+SetupIOFiles::SetupIOFiles(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupIOFilesPriv;
+
+ TQVBoxLayout* vbox = new TQVBoxLayout(parent);
+
+ //-- JPEG Settings ------------------------------------------------------
+
+ d->JPEGOptions = new JPEGSettings(parent);
+ KSeparator *line1 = new KSeparator(TQt::Horizontal, parent);
+ vbox->addWidget(d->JPEGOptions);
+ vbox->addWidget(line1);
+
+ //-- PNG Settings -------------------------------------------------------
+
+ d->PNGOptions = new PNGSettings(parent);
+ KSeparator *line2 = new KSeparator(TQt::Horizontal, parent);
+ vbox->addWidget(d->PNGOptions);
+ vbox->addWidget(line2);
+
+ //-- TIFF Settings ------------------------------------------------------
+
+ d->TIFFOptions = new TIFFSettings(parent);
+ KSeparator *line3 = new KSeparator(TQt::Horizontal, parent);
+ vbox->addWidget(d->TIFFOptions);
+ vbox->addWidget(line3);
+
+ //-- JPEG 2000 Settings -------------------------------------------------
+
+ d->JPEG2000Options = new JP2KSettings(parent);
+ vbox->addWidget(d->JPEG2000Options);
+
+ vbox->addStretch(10);
+ readSettings();
+}
+
+SetupIOFiles::~SetupIOFiles()
+{
+ delete d;
+}
+
+void SetupIOFiles::applySettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ config->writeEntry("JPEGCompression", d->JPEGOptions->getCompressionValue());
+ config->writeEntry("JPEGSubSampling", d->JPEGOptions->getSubSamplingValue());
+ config->writeEntry("PNGCompression", d->PNGOptions->getCompressionValue());
+ config->writeEntry("TIFFCompression", d->TIFFOptions->getCompression());
+ config->writeEntry("JPEG2000Compression", d->JPEG2000Options->getCompressionValue());
+ config->writeEntry("JPEG2000LossLess", d->JPEG2000Options->getLossLessCompression());
+ config->sync();
+}
+
+void SetupIOFiles::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ d->JPEGOptions->setCompressionValue( config->readNumEntry("JPEGCompression", 75) );
+ d->JPEGOptions->setSubSamplingValue( config->readNumEntry("JPEGSubSampling", 1) ); // Medium subsampling
+ d->PNGOptions->setCompressionValue( config->readNumEntry("PNGCompression", 9) );
+ d->TIFFOptions->setCompression(config->readBoolEntry("TIFFCompression", false));
+ d->JPEG2000Options->setCompressionValue( config->readNumEntry("JPEG2000Compression", 75) );
+ d->JPEG2000Options->setLossLessCompression( config->readBoolEntry("JPEG2000LossLess", true) );
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupiofiles.h b/src/utilities/setup/setupiofiles.h
new file mode 100644
index 00000000..060dbba1
--- /dev/null
+++ b/src/utilities/setup/setupiofiles.h
@@ -0,0 +1,63 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-01-23
+ * Description : setup image editor output files settings.
+ *
+ * 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 SETUPIOFILES_H
+#define SETUPIOFILES_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class SetupIOFilesPriv;
+
+class DIGIKAM_EXPORT SetupIOFiles : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupIOFiles(TQWidget* parent = 0);
+ ~SetupIOFiles();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupIOFilesPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPIOFILES_H
diff --git a/src/utilities/setup/setuplighttable.cpp b/src/utilities/setup/setuplighttable.cpp
new file mode 100644
index 00000000..0ed01eab
--- /dev/null
+++ b/src/utilities/setup/setuplighttable.cpp
@@ -0,0 +1,133 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-05-11
+ * Description : setup Light Table tab.
+ *
+ * Copyright (C) 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 <tqlayout.h>
+#include <tqcolor.h>
+#include <tqhbox.h>
+#include <tqvgroupbox.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqcheckbox.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "setuplighttable.h"
+#include "setuplighttable.moc"
+
+namespace Digikam
+{
+class SetupLightTablePriv
+{
+public:
+
+ SetupLightTablePriv()
+ {
+ hideToolBar = 0;
+ autoSyncPreview = 0;
+ autoLoadOnRightPanel = 0;
+ loadFullImageSize = 0;
+ }
+
+ TQCheckBox *hideToolBar;
+ TQCheckBox *autoSyncPreview;
+ TQCheckBox *autoLoadOnRightPanel;
+ TQCheckBox *loadFullImageSize;
+};
+
+SetupLightTable::SetupLightTable(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupLightTablePriv;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ TQVGroupBox *interfaceOptionsGroup = new TQVGroupBox(i18n("Interface Options"), parent);
+
+
+ d->autoSyncPreview = new TQCheckBox(i18n("Synchronize panels automatically"), interfaceOptionsGroup);
+ TQWhatsThis::add( d->autoSyncPreview, i18n("<p>Set this option to automatically synchronize "
+ "zooming and panning between left and right panels if the images have "
+ "the same size."));
+
+ d->autoLoadOnRightPanel = new TQCheckBox(i18n("Selecting a thumbbar item loads image to the right panel"),
+ interfaceOptionsGroup);
+ TQWhatsThis::add( d->autoLoadOnRightPanel, i18n("<p>Set this option to automatically load an image "
+ "into the right panel when the corresponding item is selected on the thumbbar."));
+
+ d->loadFullImageSize = new TQCheckBox(i18n("Load full image size"), interfaceOptionsGroup);
+ TQWhatsThis::add( d->loadFullImageSize, i18n("<p>Set this option to load full image size "
+ "into the preview panel instead of a reduced size. Because this option will take more time "
+ "to load images, use it only if you have a fast computer."));
+
+ d->hideToolBar = new TQCheckBox(i18n("H&ide toolbar in fullscreen mode"), interfaceOptionsGroup);
+
+ // --------------------------------------------------------
+
+ layout->addWidget(interfaceOptionsGroup);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ readSettings();
+}
+
+SetupLightTable::~SetupLightTable()
+{
+ delete d;
+}
+
+void SetupLightTable::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ TQColor Black(TQt::black);
+ TQColor White(TQt::white);
+ config->setGroup("LightTable Settings");
+ d->hideToolBar->setChecked(config->readBoolEntry("FullScreen Hide ToolBar", false));
+ d->autoSyncPreview->setChecked(config->readBoolEntry("Auto Sync Preview", true));
+ d->autoLoadOnRightPanel->setChecked(config->readBoolEntry("Auto Load Right Panel", true));
+ d->loadFullImageSize->setChecked(config->readBoolEntry("Load Full Image size", false));
+}
+
+void SetupLightTable::applySettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("LightTable Settings");
+ config->writeEntry("FullScreen Hide ToolBar", d->hideToolBar->isChecked());
+ config->writeEntry("Auto Sync Preview", d->autoSyncPreview->isChecked());
+ config->writeEntry("Auto Load Right Panel", d->autoLoadOnRightPanel->isChecked());
+ config->writeEntry("Load Full Image size", d->loadFullImageSize->isChecked());
+ config->sync();
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setuplighttable.h b/src/utilities/setup/setuplighttable.h
new file mode 100644
index 00000000..20af9a64
--- /dev/null
+++ b/src/utilities/setup/setuplighttable.h
@@ -0,0 +1,59 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-05-11
+ * Description : setup Light Table tab.
+ *
+ * Copyright (C) 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 SETUPLIGHTTABLE_H
+#define SETUPLIGHTTABLE_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupLightTablePriv;
+
+class SetupLightTable : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupLightTable(TQWidget* parent = 0);
+ ~SetupLightTable();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupLightTablePriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPLIGHTTABLE_H
diff --git a/src/utilities/setup/setupmetadata.cpp b/src/utilities/setup/setupmetadata.cpp
new file mode 100644
index 00000000..e4f74ede
--- /dev/null
+++ b/src/utilities/setup/setupmetadata.cpp
@@ -0,0 +1,238 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-08-03
+ * Description : setup Metadata tab.
+ *
+ * Copyright (C) 2003-2004 by Ralf Holzer <ralf at well.com>
+ * Copyright (C) 2003-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 <tqlayout.h>
+#include <tqvbuttongroup.h>
+#include <tqvgroupbox.h>
+#include <tqhgroupbox.h>
+#include <tqgroupbox.h>
+#include <tqcheckbox.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqtooltip.h>
+#include <tqhbox.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kactivelabel.h>
+#include <kdialog.h>
+#include <kurllabel.h>
+#include <kiconloader.h>
+#include <tdeglobalsettings.h>
+#include <kstandarddirs.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "setupmetadata.h"
+#include "setupmetadata.moc"
+
+namespace Digikam
+{
+
+class SetupMetadataPriv
+{
+public:
+
+ SetupMetadataPriv()
+ {
+ ExifAutoRotateAsChanged = false;
+ saveCommentsBox = 0;
+ ExifRotateBox = 0;
+ ExifSetOrientationBox = 0;
+ saveRatingBox = 0;
+ saveTagsIptcBox = 0;
+ saveDateTimeBox = 0;
+ savePhotographerIdIptcBox = 0;
+ saveCreditsIptcBox = 0;
+ }
+
+ bool ExifAutoRotateAsChanged;
+ bool ExifAutoRotateOrg;
+
+ TQCheckBox *saveCommentsBox;
+ TQCheckBox *ExifRotateBox;
+ TQCheckBox *ExifSetOrientationBox;
+ TQCheckBox *saveRatingBox;
+ TQCheckBox *saveTagsIptcBox;
+ TQCheckBox *saveDateTimeBox;
+ TQCheckBox *savePhotographerIdIptcBox;
+ TQCheckBox *saveCreditsIptcBox;
+};
+
+SetupMetadata::SetupMetadata(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupMetadataPriv;
+ TQVBoxLayout *mainLayout = new TQVBoxLayout(parent, 0, KDialog::spacingHint());
+
+ // --------------------------------------------------------
+
+ TQGroupBox *ExifGroup = new TQGroupBox(1, TQt::Horizontal, i18n("EXIF Actions"), parent);
+
+ d->ExifRotateBox = new TQCheckBox(ExifGroup);
+ d->ExifRotateBox->setText(i18n("Show images/thumbs &rotated according to orientation tag"));
+
+ d->ExifSetOrientationBox = new TQCheckBox(ExifGroup);
+ d->ExifSetOrientationBox->setText(i18n("Set orientation tag to normal after rotate/flip"));
+
+ // --------------------------------------------------------
+
+ TQGroupBox *IptcGroup = new TQGroupBox(1, TQt::Horizontal, i18n("IPTC Actions"), parent);
+
+ d->saveTagsIptcBox = new TQCheckBox(IptcGroup);
+ d->saveTagsIptcBox->setText(i18n("&Save image tags as \"Keywords\" tag"));
+ TQWhatsThis::add( d->saveTagsIptcBox, i18n("<p>Turn this option on to store the image tags "
+ "in the IPTC <i>Keywords</i> tag."));
+
+ d->savePhotographerIdIptcBox = new TQCheckBox(IptcGroup);
+ d->savePhotographerIdIptcBox->setText(i18n("&Save default photographer identity as tags"));
+ TQWhatsThis::add( d->savePhotographerIdIptcBox, i18n("<p>Turn this option on to store the default "
+ "photographer identity in the IPTC tags. You can set this "
+ "value in the Identity setup page."));
+
+ d->saveCreditsIptcBox = new TQCheckBox(IptcGroup);
+ d->saveCreditsIptcBox->setText(i18n("&Save default credit and copyright identity as tags"));
+ TQWhatsThis::add( d->saveCreditsIptcBox, i18n("<p>Turn this option on to store the default "
+ "credit and copyright identity in the IPTC tags. "
+ "You can set this value in the Identity setup page."));
+
+ // --------------------------------------------------------
+
+ TQGroupBox *commonGroup = new TQGroupBox(1, TQt::Horizontal, i18n("Common Metadata Actions"), parent);
+
+ d->saveCommentsBox = new TQCheckBox(commonGroup);
+ d->saveCommentsBox->setText(i18n("&Save image captions as embedded text"));
+ TQWhatsThis::add( d->saveCommentsBox, i18n("<p>Turn this option on to store image captions "
+ "in the JFIF section, EXIF tag, and IPTC tag."));
+
+ d->saveDateTimeBox = new TQCheckBox(commonGroup);
+ d->saveDateTimeBox->setText(i18n("&Save image timestamps as tags"));
+ TQWhatsThis::add( d->saveDateTimeBox, i18n("<p>Turn this option on to store the image date and time "
+ "in the EXIF and IPTC tags."));
+
+ d->saveRatingBox = new TQCheckBox(commonGroup);
+ d->saveRatingBox->setText(i18n("&Save image rating as tags"));
+ TQWhatsThis::add( d->saveRatingBox, i18n("<p>Turn this option on to store the image rating "
+ "in the EXIF tag and IPTC <i>Urgency</i> tag."));
+
+ // --------------------------------------------------------
+
+ TQHBox *hbox = new TQHBox(parent);
+
+ KURLLabel *exiv2LogoLabel = new KURLLabel(hbox);
+ exiv2LogoLabel->setText(TQString());
+ exiv2LogoLabel->setURL("http://www.exiv2.org");
+ TDEGlobal::dirs()->addResourceType("logo-exiv2", TDEGlobal::dirs()->kde_default("data") + "digikam/data");
+ TQString directory = TDEGlobal::dirs()->findResourceDir("logo-exiv2", "logo-exiv2.png");
+ exiv2LogoLabel->setPixmap( TQPixmap( directory + "logo-exiv2.png" ) );
+ TQToolTip::add(exiv2LogoLabel, i18n("Visit Exiv2 project website"));
+
+ KActiveLabel* explanation = new KActiveLabel(hbox);
+ explanation->setText(i18n("<p><b><a href='http://en.wikipedia.org/wiki/Exif'>EXIF</a></b> is "
+ "a standard used by most digital cameras today to store technical "
+ "informations about photograph.</p>"
+ "<p><b><a href='http://en.wikipedia.org/wiki/IPTC'>IPTC</a></b> is "
+ "an standard used in digital photography to store "
+ "photographer informations in pictures.</p>"));
+
+ mainLayout->addWidget(ExifGroup);
+ mainLayout->addWidget(IptcGroup);
+ mainLayout->addWidget(commonGroup);
+ mainLayout->addSpacing(KDialog::spacingHint());
+ mainLayout->addWidget(hbox);
+ mainLayout->addStretch();
+
+ readSettings();
+
+ // --------------------------------------------------------
+
+ connect(exiv2LogoLabel, TQ_SIGNAL(leftClickedURL(const TQString&)),
+ this, TQ_SLOT(processExiv2URL(const TQString&)));
+
+ connect(d->ExifRotateBox, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotExifAutoRotateToggled(bool)));
+}
+
+SetupMetadata::~SetupMetadata()
+{
+ delete d;
+}
+
+void SetupMetadata::processExiv2URL(const TQString& url)
+{
+ TDEApplication::kApplication()->invokeBrowser(url);
+}
+
+void SetupMetadata::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ settings->setExifRotate(d->ExifRotateBox->isChecked());
+ settings->setExifSetOrientation(d->ExifSetOrientationBox->isChecked());
+ settings->setSaveComments(d->saveCommentsBox->isChecked());
+ settings->setSaveDateTime(d->saveDateTimeBox->isChecked());
+ settings->setSaveRating(d->saveRatingBox->isChecked());
+ settings->setSaveIptcTags(d->saveTagsIptcBox->isChecked());
+ settings->setSaveIptcPhotographerId(d->savePhotographerIdIptcBox->isChecked());
+ settings->setSaveIptcCredits(d->saveCreditsIptcBox->isChecked());
+
+ settings->saveSettings();
+}
+
+void SetupMetadata::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ d->ExifAutoRotateOrg = settings->getExifRotate();
+ d->ExifRotateBox->setChecked(d->ExifAutoRotateOrg);
+ d->ExifSetOrientationBox->setChecked(settings->getExifSetOrientation());
+ d->saveCommentsBox->setChecked(settings->getSaveComments());
+ d->saveDateTimeBox->setChecked(settings->getSaveDateTime());
+ d->saveRatingBox->setChecked(settings->getSaveRating());
+ d->saveTagsIptcBox->setChecked(settings->getSaveIptcTags());
+ d->savePhotographerIdIptcBox->setChecked(settings->getSaveIptcPhotographerId());
+ d->saveCreditsIptcBox->setChecked(settings->getSaveIptcCredits());
+}
+
+bool SetupMetadata::exifAutoRotateAsChanged()
+{
+ return d->ExifAutoRotateAsChanged;
+}
+
+void SetupMetadata::slotExifAutoRotateToggled(bool b)
+{
+ if ( b != d->ExifAutoRotateOrg)
+ d->ExifAutoRotateAsChanged = true;
+ else
+ d->ExifAutoRotateAsChanged = false;
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupmetadata.h b/src/utilities/setup/setupmetadata.h
new file mode 100644
index 00000000..45511065
--- /dev/null
+++ b/src/utilities/setup/setupmetadata.h
@@ -0,0 +1,67 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-08-03
+ * Description : setup Metadata tab.
+ *
+ * Copyright (C) 2003-2004 by Ralf Holzer <ralf at well.com>
+ * Copyright (C) 2003-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 SETUPMETADATA_H
+#define SETUPMETADATA_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupMetadataPriv;
+
+class SetupMetadata : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupMetadata(TQWidget* parent = 0);
+ ~SetupMetadata();
+
+ void applySettings();
+
+ bool exifAutoRotateAsChanged();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void processExiv2URL(const TQString&);
+ void slotExifAutoRotateToggled(bool);
+
+private:
+
+ SetupMetadataPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPMETADATA_H
diff --git a/src/utilities/setup/setupmime.cpp b/src/utilities/setup/setupmime.cpp
new file mode 100644
index 00000000..6ac069e3
--- /dev/null
+++ b/src/utilities/setup/setupmime.cpp
@@ -0,0 +1,280 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-05-03
+ * Description : mime types setup tab
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// TQt includes.
+
+#include <tqlayout.h>
+#include <tqhbox.h>
+#include <tqhgroupbox.h>
+#include <tqgroupbox.h>
+#include <tqlabel.h>
+#include <tqlineedit.h>
+#include <tqwhatsthis.h>
+#include <tqtoolbutton.h>
+#include <tqtooltip.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <klineeditdlg.h>
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "setupmime.h"
+#include "setupmime.moc"
+
+namespace Digikam
+{
+
+class SetupMimePriv
+{
+public:
+
+ SetupMimePriv()
+ {
+ imageFileFilterEdit = 0;
+ movieFileFilterEdit = 0;
+ audioFileFilterEdit = 0;
+ rawFileFilterEdit = 0;
+ revertImageFileFilterBtn = 0;
+ revertMovieFileFilterBtn = 0;
+ revertAudioFileFilterBtn = 0;
+ revertRawFileFilterBtn = 0;
+ }
+
+ TQToolButton *revertImageFileFilterBtn;
+ TQToolButton *revertMovieFileFilterBtn;
+ TQToolButton *revertAudioFileFilterBtn;
+ TQToolButton *revertRawFileFilterBtn;
+
+ TQLineEdit *imageFileFilterEdit;
+ TQLineEdit *movieFileFilterEdit;
+ TQLineEdit *audioFileFilterEdit;
+ TQLineEdit *rawFileFilterEdit;
+};
+
+SetupMime::SetupMime(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupMimePriv;
+ TQVBoxLayout *layout = new TQVBoxLayout(parent, 0, KDialog::spacingHint());
+
+ // --------------------------------------------------------
+
+ TQGroupBox *imageFileFilterBox = new TQGroupBox(0, TQt::Horizontal, i18n("Image Files"), parent);
+ TQGridLayout* grid1 = new TQGridLayout(imageFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ TQLabel *logoLabel1 = new TQLabel(imageFileFilterBox);
+ logoLabel1->setPixmap(DesktopIcon("image-x-generic"));
+
+ TQLabel *imageFileFilterLabel = new TQLabel(imageFileFilterBox);
+ imageFileFilterLabel->setText(i18n("Show only &image files with extensions:"));
+
+ TQHBox *hbox1 = new TQHBox(imageFileFilterBox);
+ d->imageFileFilterEdit = new TQLineEdit(hbox1);
+ TQWhatsThis::add( d->imageFileFilterEdit, i18n("<p>Here you can set the extensions of image files "
+ "to be displayed in Albums (such as JPEG or TIFF); "
+ "clicking on these files will "
+ "open them in the digiKam Image Editor."));
+ imageFileFilterLabel->setBuddy(d->imageFileFilterEdit);
+ hbox1->setStretchFactor(d->imageFileFilterEdit, 10);
+
+ d->revertImageFileFilterBtn = new TQToolButton(hbox1);
+ d->revertImageFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ TQToolTip::add(d->revertImageFileFilterBtn, i18n("Revert to default settings"));
+
+ grid1->addMultiCellWidget(logoLabel1, 0, 1, 0, 0);
+ grid1->addMultiCellWidget(imageFileFilterLabel, 0, 0, 1, 1);
+ grid1->addMultiCellWidget(hbox1, 1, 1, 1, 1);
+ grid1->setColStretch(1, 10);
+
+ layout->addWidget(imageFileFilterBox);
+
+ // --------------------------------------------------------
+
+ TQGroupBox *movieFileFilterBox = new TQGroupBox(0, TQt::Horizontal, i18n("Movie Files"), parent);
+ TQGridLayout* grid2 = new TQGridLayout(movieFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ TQLabel *logoLabel2 = new TQLabel(movieFileFilterBox);
+ logoLabel2->setPixmap(DesktopIcon("video-x-generic"));
+
+ TQLabel *movieFileFilterLabel = new TQLabel(movieFileFilterBox);
+ movieFileFilterLabel->setText(i18n("Show only &movie files with extensions:"));
+
+ TQHBox *hbox2 = new TQHBox(movieFileFilterBox);
+ d->movieFileFilterEdit = new TQLineEdit(hbox2);
+ TQWhatsThis::add( d->movieFileFilterEdit, i18n("<p>Here you can set the extensions of movie files "
+ "to be displayed in Albums (such as MPEG or AVI); "
+ "clicking on these files will "
+ "open them with the default TDE movie player."));
+ movieFileFilterLabel->setBuddy(d->movieFileFilterEdit);
+ hbox2->setStretchFactor(d->movieFileFilterEdit, 10);
+
+ d->revertMovieFileFilterBtn = new TQToolButton(hbox2);
+ d->revertMovieFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ TQToolTip::add(d->revertMovieFileFilterBtn, i18n("Revert to default settings"));
+
+ grid2->addMultiCellWidget(logoLabel2, 0, 1, 0, 0);
+ grid2->addMultiCellWidget(movieFileFilterLabel, 0, 0, 1, 1);
+ grid2->addMultiCellWidget(hbox2, 1, 1, 1, 1);
+ grid2->setColStretch(1, 10);
+
+ layout->addWidget(movieFileFilterBox);
+
+ // --------------------------------------------------------
+
+ TQGroupBox *audioFileFilterBox = new TQGroupBox(0, TQt::Horizontal, i18n("Audio Files"), parent);
+ TQGridLayout* grid3 = new TQGridLayout(audioFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ TQLabel *logoLabel3 = new TQLabel(audioFileFilterBox);
+ logoLabel3->setPixmap(DesktopIcon("audio-x-generic"));
+
+ TQLabel *audioFileFilterLabel = new TQLabel(audioFileFilterBox);
+ audioFileFilterLabel->setText(i18n("Show only &audio files with extensions:"));
+
+ TQHBox *hbox3 = new TQHBox(audioFileFilterBox);
+ d->audioFileFilterEdit = new TQLineEdit(hbox3);
+ TQWhatsThis::add( d->audioFileFilterEdit, i18n("<p>Here you can set the extensions of audio files "
+ "to be displayed in Albums (such as MP3 or OGG); "
+ "clicking on these files will "
+ "open them with the default TDE audio player."));
+ audioFileFilterLabel->setBuddy(d->audioFileFilterEdit);
+ hbox3->setStretchFactor(d->audioFileFilterEdit, 10);
+
+ d->revertAudioFileFilterBtn = new TQToolButton(hbox3);
+ d->revertAudioFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ TQToolTip::add(d->revertAudioFileFilterBtn, i18n("Revert to default settings"));
+
+ grid3->addMultiCellWidget(logoLabel3, 0, 1, 0, 0);
+ grid3->addMultiCellWidget(audioFileFilterLabel, 0, 0, 1, 1);
+ grid3->addMultiCellWidget(hbox3, 1, 1, 1, 1);
+ grid3->setColStretch(1, 10);
+
+ layout->addWidget(audioFileFilterBox);
+
+ // --------------------------------------------------------
+
+ TQGroupBox *rawFileFilterBox = new TQGroupBox(0, TQt::Horizontal, i18n("RAW Files"), parent);
+ TQGridLayout* grid4 = new TQGridLayout(rawFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ TQLabel *logoLabel4 = new TQLabel(rawFileFilterBox);
+ logoLabel4->setPixmap(DesktopIcon("kdcraw"));
+
+ TQLabel *rawFileFilterLabel = new TQLabel(rawFileFilterBox);
+ rawFileFilterLabel->setText(i18n("Show only &RAW files with extensions:"));
+
+ TQHBox *hbox4 = new TQHBox(rawFileFilterBox);
+ d->rawFileFilterEdit = new TQLineEdit(hbox4);
+ TQWhatsThis::add( d->rawFileFilterEdit, i18n("<p>Here you can set the extensions of RAW image files "
+ "to be displayed in Albums (such as CRW, for Canon cameras, "
+ "or NEF, for Nikon cameras)."));
+ rawFileFilterLabel->setBuddy(d->rawFileFilterEdit);
+ hbox4->setStretchFactor(d->rawFileFilterEdit, 10);
+
+ d->revertRawFileFilterBtn = new TQToolButton(hbox4);
+ d->revertRawFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ TQToolTip::add(d->revertRawFileFilterBtn, i18n("Revert to default settings"));
+
+ grid4->addMultiCellWidget(logoLabel4, 0, 1, 0, 0);
+ grid4->addMultiCellWidget(rawFileFilterLabel, 0, 0, 1, 1);
+ grid4->addMultiCellWidget(hbox4, 1, 1, 1, 1);
+ grid4->setColStretch(1, 10);
+
+ layout->addWidget(rawFileFilterBox);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ connect(d->revertImageFileFilterBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotRevertImageFileFilter()));
+
+ connect(d->revertMovieFileFilterBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotRevertMovieFileFilter()));
+
+ connect(d->revertAudioFileFilterBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotRevertAudioFileFilter()));
+
+ connect(d->revertRawFileFilterBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotRevertRawFileFilter()));
+
+ // --------------------------------------------------------
+
+ readSettings();
+}
+
+SetupMime::~SetupMime()
+{
+ delete d;
+}
+
+void SetupMime::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ settings->setImageFileFilter(d->imageFileFilterEdit->text());
+ settings->setMovieFileFilter(d->movieFileFilterEdit->text());
+ settings->setAudioFileFilter(d->audioFileFilterEdit->text());
+ settings->setRawFileFilter(d->rawFileFilterEdit->text());
+
+ settings->saveSettings();
+}
+
+void SetupMime::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ d->imageFileFilterEdit->setText(settings->getImageFileFilter());
+ d->movieFileFilterEdit->setText(settings->getMovieFileFilter());
+ d->audioFileFilterEdit->setText(settings->getAudioFileFilter());
+ d->rawFileFilterEdit->setText(settings->getRawFileFilter());
+}
+
+void SetupMime::slotRevertImageFileFilter()
+{
+ d->imageFileFilterEdit->setText(AlbumSettings::instance()->getDefaultImageFileFilter());
+}
+
+void SetupMime::slotRevertMovieFileFilter()
+{
+ d->movieFileFilterEdit->setText(AlbumSettings::instance()->getDefaultMovieFileFilter());
+}
+
+void SetupMime::slotRevertAudioFileFilter()
+{
+ d->audioFileFilterEdit->setText(AlbumSettings::instance()->getDefaultAudioFileFilter());
+}
+
+void SetupMime::slotRevertRawFileFilter()
+{
+ d->rawFileFilterEdit->setText(AlbumSettings::instance()->getDefaultRawFileFilter());
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setupmime.h b/src/utilities/setup/setupmime.h
new file mode 100644
index 00000000..3bff1525
--- /dev/null
+++ b/src/utilities/setup/setupmime.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-05-03
+ * Description : mime types setup tab.
+ *
+ * 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 SETUPMIME_H
+#define SETUPMIME_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupMimePriv;
+
+class SetupMime : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupMime(TQWidget* parent = 0);
+ ~SetupMime();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void slotRevertImageFileFilter();
+ void slotRevertMovieFileFilter();
+ void slotRevertAudioFileFilter();
+ void slotRevertRawFileFilter();
+
+private:
+
+ SetupMimePriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPMIME_H
diff --git a/src/utilities/setup/setupmisc.cpp b/src/utilities/setup/setupmisc.cpp
new file mode 100644
index 00000000..8dc16e96
--- /dev/null
+++ b/src/utilities/setup/setupmisc.cpp
@@ -0,0 +1,124 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-08-23
+ * Description : mics configuration setup tab
+ *
+ * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005-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 <tqlayout.h>
+#include <tqvgroupbox.h>
+#include <tqcheckbox.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "setupmisc.h"
+
+namespace Digikam
+{
+
+class SetupMiscPriv
+{
+public:
+
+ SetupMiscPriv()
+ {
+ showSplashCheck = 0;
+ showTrashDeleteDialogCheck = 0;
+ sidebarApplyDirectlyCheck = 0;
+ scanAtStart = 0;
+ }
+
+ TQCheckBox* showSplashCheck;
+ TQCheckBox* showTrashDeleteDialogCheck;
+ TQCheckBox* sidebarApplyDirectlyCheck;
+ TQCheckBox* scanAtStart;
+};
+
+SetupMisc::SetupMisc(TQWidget* parent)
+ : TQWidget( parent )
+{
+ d = new SetupMiscPriv;
+
+ TQVBoxLayout *mainLayout = new TQVBoxLayout(parent);
+ TQVBoxLayout *layout = new TQVBoxLayout( this, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ d->showTrashDeleteDialogCheck = new TQCheckBox(i18n("Show confirmation dialog when moving items to the &trash"), this);
+ layout->addWidget(d->showTrashDeleteDialogCheck);
+
+ // --------------------------------------------------------
+
+ d->sidebarApplyDirectlyCheck = new TQCheckBox(i18n("Apply changes in the &right sidebar without confirmation"), this);
+ layout->addWidget(d->sidebarApplyDirectlyCheck);
+
+ // --------------------------------------------------------
+
+ d->showSplashCheck = new TQCheckBox(i18n("&Show splash screen at startup"), this);
+ layout->addWidget(d->showSplashCheck);
+
+ // --------------------------------------------------------
+
+ d->scanAtStart = new TQCheckBox(i18n("&Scan for new items on startup (slows down startup)"), this);
+ layout->addWidget(d->scanAtStart);
+
+ // --------------------------------------------------------
+
+ layout->addStretch();
+ readSettings();
+ adjustSize();
+ mainLayout->addWidget(this);
+}
+
+SetupMisc::~SetupMisc()
+{
+ delete d;
+}
+
+void SetupMisc::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ settings->setShowSplashScreen(d->showSplashCheck->isChecked());
+ settings->setShowTrashDeleteDialog(d->showTrashDeleteDialogCheck->isChecked());
+ settings->setApplySidebarChangesDirectly(d->sidebarApplyDirectlyCheck->isChecked());
+ settings->setScanAtStart(d->scanAtStart->isChecked());
+ settings->saveSettings();
+}
+
+void SetupMisc::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ d->showSplashCheck->setChecked(settings->getShowSplashScreen());
+ d->showTrashDeleteDialogCheck->setChecked(settings->getShowTrashDeleteDialog());
+ d->sidebarApplyDirectlyCheck->setChecked(settings->getApplySidebarChangesDirectly());
+ d->scanAtStart->setChecked(settings->getScanAtStart());
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupmisc.h b/src/utilities/setup/setupmisc.h
new file mode 100644
index 00000000..92918ba4
--- /dev/null
+++ b/src/utilities/setup/setupmisc.h
@@ -0,0 +1,58 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-08-23
+ * Description : mics configuration setup tab
+ *
+ * Copyright (C) 2004 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2005-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 SETUPMISC_H
+#define SETUPMISC_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupMiscPriv;
+
+class SetupMisc : public TQWidget
+{
+public:
+
+ SetupMisc(TQWidget* parent);
+ ~SetupMisc();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupMiscPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif /* SETUPMISC_H */
diff --git a/src/utilities/setup/setupplugins.cpp b/src/utilities/setup/setupplugins.cpp
new file mode 100644
index 00000000..e0d9c494
--- /dev/null
+++ b/src/utilities/setup/setupplugins.cpp
@@ -0,0 +1,104 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-01-02
+ * Description : setup Kipi plugins tab.
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// TQt includes.
+
+#include <tqlayout.h>
+#include <tqstring.h>
+#include <tqgroupbox.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+
+// libkipi includes.
+
+#include <libkipi/pluginloader.h>
+#include <libkipi/version.h>
+
+// Local includes.
+
+#include "setupplugins.h"
+#include "setupplugins.moc"
+
+namespace Digikam
+{
+
+class SetupPluginsPriv
+{
+public:
+
+ SetupPluginsPriv()
+ {
+ pluginsNumber = 0;
+ kipiConfig = 0;
+ }
+
+ TQLabel* pluginsNumber;
+
+ KIPI::ConfigWidget* kipiConfig;
+};
+
+SetupPlugins::SetupPlugins(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupPluginsPriv;
+ TQVBoxLayout *layout = new TQVBoxLayout(parent);
+ d->pluginsNumber = new TQLabel(parent);
+ d->pluginsNumber->setAlignment(TQt::AlignLeft | TQt::AlignVCenter);
+
+ d->kipiConfig = KIPI::PluginLoader::instance()->configWidget( parent );
+ TQString pluginsListHelp = i18n("<p>A list of available Kipi plugins appears below.");
+ TQWhatsThis::add(d->kipiConfig, pluginsListHelp);
+
+ layout->addWidget(d->pluginsNumber);
+ layout->addWidget(d->kipiConfig);
+ layout->setMargin(0);
+ layout->setSpacing(KDialog::spacingHint());
+}
+
+SetupPlugins::~SetupPlugins()
+{
+ delete d;
+}
+
+void SetupPlugins::initPlugins(int kipiPluginsNumber)
+{
+ d->pluginsNumber->setText(i18n("1 Kipi plugin found",
+ "%n Kipi plugins found",
+ kipiPluginsNumber));
+}
+
+void SetupPlugins::applyPlugins()
+{
+ d->kipiConfig->apply();
+}
+
+} // namespace Digikam
diff --git a/src/utilities/setup/setupplugins.h b/src/utilities/setup/setupplugins.h
new file mode 100644
index 00000000..31b71121
--- /dev/null
+++ b/src/utilities/setup/setupplugins.h
@@ -0,0 +1,56 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-01-02
+ * Description : setup Kipi plugins tab.
+ *
+ * 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 SETUPPLUGINS_H
+#define SETUPPLUGINS_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupPluginsPriv;
+
+class SetupPlugins : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupPlugins(TQWidget* parent = 0);
+ ~SetupPlugins();
+
+ void initPlugins(int kipiPluginsNumber);
+ void applyPlugins();
+
+private:
+
+ SetupPluginsPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPPLUGINS_H
diff --git a/src/utilities/setup/setupslideshow.cpp b/src/utilities/setup/setupslideshow.cpp
new file mode 100644
index 00000000..970d9c67
--- /dev/null
+++ b/src/utilities/setup/setupslideshow.cpp
@@ -0,0 +1,165 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-05-21
+ * Description : setup tab for slideshow options.
+ *
+ * Copyright (C) 2005-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 <tqlayout.h>
+#include <tqlabel.h>
+#include <tqwhatsthis.h>
+#include <tqcheckbox.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialog.h>
+#include <knuminput.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+
+// Local includes.
+
+#include "setupslideshow.h"
+#include "setupslideshow.moc"
+
+namespace Digikam
+{
+
+class SetupSlideShowPriv
+{
+public:
+
+ SetupSlideShowPriv()
+ {
+ delayInput = 0;
+ startWithCurrent = 0;
+ loopMode = 0;
+ printName = 0;
+ printDate = 0;
+ printApertureFocal = 0;
+ printExpoSensitivity = 0;
+ printMakeModel = 0;
+ printComment = 0;
+ }
+
+ TQCheckBox *startWithCurrent;
+ TQCheckBox *loopMode;
+ TQCheckBox *printName;
+ TQCheckBox *printDate;
+ TQCheckBox *printApertureFocal;
+ TQCheckBox *printExpoSensitivity;
+ TQCheckBox *printMakeModel;
+ TQCheckBox *printComment;
+
+ KIntNumInput *delayInput;
+};
+
+SetupSlideShow::SetupSlideShow(TQWidget* parent )
+ : TQWidget(parent)
+{
+ d = new SetupSlideShowPriv;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent );
+
+ d->delayInput = new KIntNumInput(5, parent);
+ d->delayInput->setRange(1, 3600, 1, true );
+ d->delayInput->setLabel( i18n("&Delay between images:"), AlignLeft|AlignTop );
+ TQWhatsThis::add( d->delayInput, i18n("<p>The delay, in seconds, between images."));
+
+ d->startWithCurrent = new TQCheckBox(i18n("Start with current image"), parent);
+ TQWhatsThis::add( d->startWithCurrent, i18n("<p>If this option is enabled, slideshow will be started "
+ "with currently selected image."));
+
+ d->loopMode = new TQCheckBox(i18n("Display in a loop"), parent);
+ TQWhatsThis::add( d->loopMode, i18n("<p>Run the slideshow in endless repetition."));
+
+ d->printName = new TQCheckBox(i18n("Print image file name"), parent);
+ TQWhatsThis::add( d->printName, i18n("<p>Print the image file name at the bottom of the screen."));
+
+ d->printDate = new TQCheckBox(i18n("Print image creation date"), parent);
+ TQWhatsThis::add( d->printDate, i18n("<p>Print the image creation time/date at the bottom of the screen."));
+
+ d->printApertureFocal = new TQCheckBox(i18n("Print camera aperture and focal length"), parent);
+ TQWhatsThis::add( d->printApertureFocal, i18n("<p>Print the camera aperture and focal length at the bottom of the screen."));
+
+ d->printExpoSensitivity = new TQCheckBox(i18n("Print camera exposure and sensitivity"), parent);
+ TQWhatsThis::add( d->printExpoSensitivity, i18n("<p>Print the camera exposure and sensitivity at the bottom of the screen."));
+
+ d->printMakeModel = new TQCheckBox(i18n("Print camera make and model"), parent);
+ TQWhatsThis::add( d->printMakeModel, i18n("<p>Print the camera make and model at the bottom of the screen."));
+
+ d->printComment = new TQCheckBox(i18n("Print image caption"), parent);
+ TQWhatsThis::add( d->printComment, i18n("<p>Print the image caption at the bottom of the screen."));
+
+ layout->addWidget(d->delayInput);
+ layout->addWidget(d->startWithCurrent);
+ layout->addWidget(d->loopMode);
+ layout->addWidget(d->printName);
+ layout->addWidget(d->printDate);
+ layout->addWidget(d->printApertureFocal);
+ layout->addWidget(d->printExpoSensitivity);
+ layout->addWidget(d->printMakeModel);
+ layout->addWidget(d->printComment);
+ layout->addStretch();
+
+ readSettings();
+}
+
+SetupSlideShow::~SetupSlideShow()
+{
+ delete d;
+}
+
+void SetupSlideShow::applySettings()
+{
+ TDEConfig* config = kapp->config();
+
+ config->setGroup("ImageViewer Settings");
+ config->writeEntry("SlideShowDelay", d->delayInput->value());
+ config->writeEntry("SlideShowStartCurrent", d->startWithCurrent->isChecked());
+ config->writeEntry("SlideShowLoop", d->loopMode->isChecked());
+ config->writeEntry("SlideShowPrintName", d->printName->isChecked());
+ config->writeEntry("SlideShowPrintDate", d->printDate->isChecked());
+ config->writeEntry("SlideShowPrintApertureFocal", d->printApertureFocal->isChecked());
+ config->writeEntry("SlideShowPrintExpoSensitivity", d->printExpoSensitivity->isChecked());
+ config->writeEntry("SlideShowPrintMakeModel", d->printMakeModel->isChecked());
+ config->writeEntry("SlideShowPrintComment", d->printComment->isChecked());
+ config->sync();
+}
+
+void SetupSlideShow::readSettings()
+{
+ TDEConfig* config = kapp->config();
+
+ config->setGroup("ImageViewer Settings");
+ d->delayInput->setValue(config->readNumEntry("SlideShowDelay", 5));
+ d->startWithCurrent->setChecked(config->readBoolEntry("SlideShowStartCurrent", false));
+ d->loopMode->setChecked(config->readBoolEntry("SlideShowLoop", false));
+ d->printName->setChecked(config->readBoolEntry("SlideShowPrintName", true));
+ d->printDate->setChecked(config->readBoolEntry("SlideShowPrintDate", false));
+ d->printApertureFocal->setChecked(config->readBoolEntry("SlideShowPrintApertureFocal", false));
+ d->printExpoSensitivity->setChecked(config->readBoolEntry("SlideShowPrintExpoSensitivity", false));
+ d->printMakeModel->setChecked(config->readBoolEntry("SlideShowPrintMakeModel", false));
+ d->printComment->setChecked(config->readBoolEntry("SlideShowPrintComment", false));
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setupslideshow.h b/src/utilities/setup/setupslideshow.h
new file mode 100644
index 00000000..9ba68035
--- /dev/null
+++ b/src/utilities/setup/setupslideshow.h
@@ -0,0 +1,64 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-05-21
+ * Description : setup tab for slideshow options.
+ *
+ * Copyright (C) 2005-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 SETUPSLIDESHOW_H
+#define SETUPSLIDESHOW_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class SetupSlideShowPriv;
+
+class DIGIKAM_EXPORT SetupSlideShow : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupSlideShow(TQWidget* parent = 0);
+ ~SetupSlideShow();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupSlideShowPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif /* SETUPSLIDESHOW_H */
diff --git a/src/utilities/setup/setuptooltip.cpp b/src/utilities/setup/setuptooltip.cpp
new file mode 100644
index 00000000..2a5c62c8
--- /dev/null
+++ b/src/utilities/setup/setuptooltip.cpp
@@ -0,0 +1,272 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-07-09
+ * Description : album item tool tip configuration setup tab
+ *
+ * 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 <tqlayout.h>
+#include <tqvgroupbox.h>
+#include <tqcheckbox.h>
+#include <tqwhatsthis.h>
+
+// KDE includes.
+
+#include <tdelocale.h>
+#include <kdialogbase.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "setuptooltip.h"
+#include "setuptooltip.moc"
+
+namespace Digikam
+{
+
+class SetupToolTipPriv
+{
+public:
+
+ SetupToolTipPriv()
+ {
+ showToolTipsBox = 0;
+
+ showFileNameBox = 0;
+ showFileDateBox = 0;
+ showFileSizeBox = 0;
+ showImageTypeBox = 0;
+ showImageDimBox = 0;
+
+ showPhotoMakeBox = 0;
+ showPhotoDateBox = 0;
+ showPhotoFocalBox = 0;
+ showPhotoExpoBox = 0;
+ showPhotoModeBox = 0;
+ showPhotoFlashBox = 0;
+ showPhotoWbBox = 0;
+
+ showAlbumNameBox = 0;
+ showCommentsBox = 0;
+ showTagsBox = 0;
+ showRatingBox = 0;
+
+ fileSettingBox = 0;
+ photoSettingBox = 0;
+ digikamSettingBox = 0;
+ }
+
+ TQCheckBox *showToolTipsBox;
+
+ TQCheckBox *showFileNameBox;
+ TQCheckBox *showFileDateBox;
+ TQCheckBox *showFileSizeBox;
+ TQCheckBox *showImageTypeBox;
+ TQCheckBox *showImageDimBox;
+
+ TQCheckBox *showPhotoMakeBox;
+ TQCheckBox *showPhotoDateBox;
+ TQCheckBox *showPhotoFocalBox;
+ TQCheckBox *showPhotoExpoBox;
+ TQCheckBox *showPhotoModeBox;
+ TQCheckBox *showPhotoFlashBox;
+ TQCheckBox *showPhotoWbBox;
+
+ TQCheckBox *showAlbumNameBox;
+ TQCheckBox *showCommentsBox;
+ TQCheckBox *showTagsBox;
+ TQCheckBox *showRatingBox;
+
+ TQVGroupBox *fileSettingBox;
+ TQVGroupBox *photoSettingBox;
+ TQVGroupBox *digikamSettingBox;
+};
+
+SetupToolTip::SetupToolTip(TQWidget* parent)
+ : TQWidget(parent)
+{
+ d = new SetupToolTipPriv;
+ TQVBoxLayout *layout = new TQVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ d->showToolTipsBox = new TQCheckBox(i18n("Show album items toolti&ps"), parent);
+ TQWhatsThis::add( d->showToolTipsBox, i18n("<p>Set this option to display image information when "
+ "the mouse hovers over an album item."));
+
+ layout->addWidget(d->showToolTipsBox);
+
+ // --------------------------------------------------------
+
+ d->fileSettingBox = new TQVGroupBox(i18n("File/Image Information"), parent);
+
+ d->showFileNameBox = new TQCheckBox(i18n("Show file name"), d->fileSettingBox);
+ TQWhatsThis::add( d->showFileNameBox, i18n("<p>Set this option to display the image file name."));
+
+ d->showFileDateBox = new TQCheckBox(i18n("Show file date"), d->fileSettingBox);
+ TQWhatsThis::add( d->showFileDateBox, i18n("<p>Set this option to display the image file date."));
+
+ d->showFileSizeBox = new TQCheckBox(i18n("Show file size"), d->fileSettingBox);
+ TQWhatsThis::add( d->showFileSizeBox, i18n("<p>Set this option to display the image file size."));
+
+ d->showImageTypeBox = new TQCheckBox(i18n("Show image type"), d->fileSettingBox);
+ TQWhatsThis::add( d->showImageTypeBox, i18n("<p>Set this option to display the image type."));
+
+ d->showImageDimBox = new TQCheckBox(i18n("Show image dimensions"), d->fileSettingBox);
+ TQWhatsThis::add( d->showImageDimBox, i18n("<p>Set this option to display the image dimensions in pixels."));
+
+ layout->addWidget(d->fileSettingBox);
+
+ // --------------------------------------------------------
+
+ d->photoSettingBox = new TQVGroupBox(i18n("Photograph Information"), parent);
+
+ d->showPhotoMakeBox = new TQCheckBox(i18n("Show camera make and model"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoMakeBox, i18n("<p>Set this option to display the make and model of the "
+ "camera with which the image has been taken."));
+
+ d->showPhotoDateBox = new TQCheckBox(i18n("Show camera date"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoDateBox, i18n("<p>Set this option to display the date when the image was taken."));
+
+ d->showPhotoFocalBox = new TQCheckBox(i18n("Show camera aperture and focal"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoFocalBox, i18n("<p>Set this option to display the camera aperture and focal settings "
+ "used to take the image."));
+
+ d->showPhotoExpoBox = new TQCheckBox(i18n("Show camera exposure and sensitivity"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoExpoBox, i18n("<p>Set this option to display the camera exposure and sensitivity "
+ "used to take the image."));
+
+ d->showPhotoModeBox = new TQCheckBox(i18n("Show camera mode and program"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoModeBox, i18n("<p>Set this option to display the camera mode and program "
+ "used to take the image."));
+
+ d->showPhotoFlashBox = new TQCheckBox(i18n("Show camera flash settings"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoFlashBox, i18n("<p>Set this option to display the camera flash settings "
+ "used to take the image."));
+
+ d->showPhotoWbBox = new TQCheckBox(i18n("Show camera white balance settings"), d->photoSettingBox);
+ TQWhatsThis::add( d->showPhotoWbBox, i18n("<p>Set this option to display the camera white balance settings "
+ "used to take the image."));
+
+ layout->addWidget(d->photoSettingBox);
+
+ // --------------------------------------------------------
+
+ d->digikamSettingBox = new TQVGroupBox(i18n("digiKam Information"), parent);
+
+ d->showAlbumNameBox = new TQCheckBox(i18n("Show album name"), d->digikamSettingBox);
+ TQWhatsThis::add( d->showAlbumNameBox, i18n("<p>Set this option to display the album name."));
+
+ d->showCommentsBox = new TQCheckBox(i18n("Show image caption"), d->digikamSettingBox);
+ TQWhatsThis::add( d->showCommentsBox, i18n("<p>Set this option to display the image captions."));
+
+ d->showTagsBox = new TQCheckBox(i18n("Show image tags"), d->digikamSettingBox);
+ TQWhatsThis::add( d->showTagsBox, i18n("<p>Set this option to display the image tags."));
+
+ d->showRatingBox = new TQCheckBox(i18n("Show image rating"), d->digikamSettingBox);
+ TQWhatsThis::add( d->showRatingBox, i18n("<p>Set this option to display the image rating."));
+
+ layout->addWidget(d->digikamSettingBox);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ connect(d->showToolTipsBox, TQ_SIGNAL(toggled(bool)),
+ d->fileSettingBox, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->showToolTipsBox, TQ_SIGNAL(toggled(bool)),
+ d->photoSettingBox, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->showToolTipsBox, TQ_SIGNAL(toggled(bool)),
+ d->digikamSettingBox, TQ_SLOT(setEnabled(bool)));
+
+ // --------------------------------------------------------
+
+ readSettings();
+ adjustSize();
+}
+
+SetupToolTip::~SetupToolTip()
+{
+ delete d;
+}
+
+void SetupToolTip::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings) return;
+
+ settings->setShowToolTips(d->showToolTipsBox->isChecked());
+
+ settings->setToolTipsShowFileName(d->showFileNameBox->isChecked());
+ settings->setToolTipsShowFileDate(d->showFileDateBox->isChecked());
+ settings->setToolTipsShowFileSize(d->showFileSizeBox->isChecked());
+ settings->setToolTipsShowImageType(d->showImageTypeBox->isChecked());
+ settings->setToolTipsShowImageDim(d->showImageDimBox->isChecked());
+
+ settings->setToolTipsShowPhotoMake(d->showPhotoMakeBox->isChecked());
+ settings->setToolTipsShowPhotoDate(d->showPhotoDateBox->isChecked());
+ settings->setToolTipsShowPhotoFocal(d->showPhotoFocalBox->isChecked());
+ settings->setToolTipsShowPhotoExpo(d->showPhotoExpoBox->isChecked());
+ settings->setToolTipsShowPhotoMode(d->showPhotoModeBox->isChecked());
+ settings->setToolTipsShowPhotoFlash(d->showPhotoFlashBox->isChecked());
+ settings->setToolTipsShowPhotoWB(d->showPhotoWbBox->isChecked());
+
+ settings->setToolTipsShowAlbumName(d->showAlbumNameBox->isChecked());
+ settings->setToolTipsShowComments(d->showCommentsBox->isChecked());
+ settings->setToolTipsShowTags(d->showTagsBox->isChecked());
+ settings->setToolTipsShowRating(d->showRatingBox->isChecked());
+
+ settings->saveSettings();
+}
+
+void SetupToolTip::readSettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ d->showToolTipsBox->setChecked(settings->getShowToolTips());
+
+ d->showFileNameBox->setChecked(settings->getToolTipsShowFileName());
+ d->showFileDateBox->setChecked(settings->getToolTipsShowFileDate());
+ d->showFileSizeBox->setChecked(settings->getToolTipsShowFileSize());
+ d->showImageTypeBox->setChecked(settings->getToolTipsShowImageType());
+ d->showImageDimBox->setChecked(settings->getToolTipsShowImageDim());
+
+ d->showPhotoMakeBox->setChecked(settings->getToolTipsShowPhotoMake());
+ d->showPhotoDateBox->setChecked(settings->getToolTipsShowPhotoDate());
+ d->showPhotoFocalBox->setChecked(settings->getToolTipsShowPhotoFocal());
+ d->showPhotoExpoBox->setChecked(settings->getToolTipsShowPhotoExpo());
+ d->showPhotoModeBox->setChecked(settings->getToolTipsShowPhotoMode());
+ d->showPhotoFlashBox->setChecked(settings->getToolTipsShowPhotoFlash());
+ d->showPhotoWbBox->setChecked(settings->getToolTipsShowPhotoWB());
+
+ d->showAlbumNameBox->setChecked(settings->getToolTipsShowAlbumName());
+ d->showCommentsBox->setChecked(settings->getToolTipsShowComments());
+ d->showTagsBox->setChecked(settings->getToolTipsShowTags());
+ d->showRatingBox->setChecked(settings->getToolTipsShowRating());
+
+ d->fileSettingBox->setEnabled(d->showToolTipsBox->isChecked());
+ d->photoSettingBox->setEnabled(d->showToolTipsBox->isChecked());
+ d->digikamSettingBox->setEnabled(d->showToolTipsBox->isChecked());
+}
+
+} // namespace Digikam
+
diff --git a/src/utilities/setup/setuptooltip.h b/src/utilities/setup/setuptooltip.h
new file mode 100644
index 00000000..8474de78
--- /dev/null
+++ b/src/utilities/setup/setuptooltip.h
@@ -0,0 +1,59 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-07-09
+ * Description : album item tool tip configuration setup tab
+ *
+ * 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 SETUPTOOLTIP_H
+#define SETUPTOOLTIP_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+namespace Digikam
+{
+
+class SetupToolTipPriv;
+
+class SetupToolTip : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SetupToolTip(TQWidget* parent = 0);
+ ~SetupToolTip();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupToolTipPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPTOOLTIP_H
diff --git a/src/utilities/slideshow/Makefile.am b/src/utilities/slideshow/Makefile.am
new file mode 100644
index 00000000..5340e80c
--- /dev/null
+++ b/src/utilities/slideshow/Makefile.am
@@ -0,0 +1,17 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/src/digikam \
+ -I$(top_srcdir)/src/libs/dimg \
+ -I$(top_srcdir)/src/libs/dmetadata \
+ -I$(top_srcdir)/src/libs/themeengine \
+ -I$(top_srcdir)/src/libs/threadimageio \
+ $(LIBKDCRAW_CFLAGS) \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libslideshow.la
+
+libslideshow_la_SOURCES = toolbar.cpp slideshow.cpp
+
+libslideshow_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIB_TQT) -lDCOP $(LIB_TDECORE) $(LIB_TDEUI) -ltdefx $(LIB_TDEIO) -ltdetexteditor
+
+
diff --git a/src/utilities/slideshow/slideshow.cpp b/src/utilities/slideshow/slideshow.cpp
new file mode 100644
index 00000000..33cf9edc
--- /dev/null
+++ b/src/utilities/slideshow/slideshow.cpp
@@ -0,0 +1,679 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-04-21
+ * Description : slide show tool using preview of pictures.
+ *
+ * Copyright (C) 2005-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.
+ *
+ * ============================================================ */
+
+#define MAXSTRINGLEN 80
+
+// TQt includes.
+
+#include <tqtimer.h>
+#include <tqpixmap.h>
+#include <tqdesktopwidget.h>
+#include <tqevent.h>
+#include <tqcursor.h>
+#include <tqpainter.h>
+#include <tqfont.h>
+
+// KDE includes.
+
+#include <tdeapplication.h>
+#include <kiconloader.h>
+#include <tdelocale.h>
+#include <tdeversion.h>
+#include <tdeglobalsettings.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "dimg.h"
+#include "toolbar.h"
+#include "previewloadthread.h"
+#include "slideshow.h"
+#include "slideshow.moc"
+
+namespace Digikam
+{
+
+class SlideShowPriv
+{
+public:
+
+ SlideShowPriv()
+ {
+ previewThread = 0;
+ mouseMoveTimer = 0;
+ timer = 0;
+ toolBar = 0;
+ fileIndex = -1;
+ endOfShow = false;
+ pause = false;
+ }
+
+ bool endOfShow;
+ bool pause;
+
+ int deskX;
+ int deskY;
+ int deskWidth;
+ int deskHeight;
+ int fileIndex;
+
+ TQTimer *mouseMoveTimer; // To hide cursor when not moved.
+ TQTimer *timer;
+
+ TQPixmap pixmap;
+
+ DImg preview;
+
+ KURL currentImage;
+
+ PreviewLoadThread *previewThread;
+ PreviewLoadThread *previewPreloadThread;
+
+ ToolBar *toolBar;
+
+ SlideShowSettings settings;
+};
+
+SlideShow::SlideShow(const SlideShowSettings& settings)
+ : TQWidget(0, 0, WStyle_StaysOnTop | WType_Popup |
+ WX11BypassWM | WDestructiveClose)
+{
+ d = new SlideShowPriv;
+ d->settings = settings;
+
+ // ---------------------------------------------------------------
+
+#if KDE_IS_VERSION(3,2,0)
+ TQRect deskRect = TDEGlobalSettings::desktopGeometry(this);
+ d->deskX = deskRect.x();
+ d->deskY = deskRect.y();
+ d->deskWidth = deskRect.width();
+ d->deskHeight = deskRect.height();
+#else
+ TQRect deskRect = TQApplication::desktop()->screenGeometry(this);
+ d->deskX = deskRect.x();
+ d->deskY = deskRect.y();
+ d->deskWidth = deskRect.width();
+ d->deskHeight = deskRect.height();
+#endif
+
+ move(d->deskX, d->deskY);
+ resize(d->deskWidth, d->deskHeight);
+ setPaletteBackgroundColor(TQt::black);
+
+ // ---------------------------------------------------------------
+
+ d->toolBar = new ToolBar(this);
+ d->toolBar->hide();
+ if (!d->settings.loop)
+ d->toolBar->setEnabledPrev(false);
+
+ connect(d->toolBar, TQ_SIGNAL(signalPause()),
+ this, TQ_SLOT(slotPause()));
+
+ connect(d->toolBar, TQ_SIGNAL(signalPlay()),
+ this, TQ_SLOT(slotPlay()));
+
+ connect(d->toolBar, TQ_SIGNAL(signalNext()),
+ this, TQ_SLOT(slotNext()));
+
+ connect(d->toolBar, TQ_SIGNAL(signalPrev()),
+ this, TQ_SLOT(slotPrev()));
+
+ connect(d->toolBar, TQ_SIGNAL(signalClose()),
+ this, TQ_SLOT(slotClose()));
+
+ // ---------------------------------------------------------------
+
+ d->previewThread = new PreviewLoadThread();
+ d->previewPreloadThread = new PreviewLoadThread();
+ d->timer = new TQTimer(this);
+ d->mouseMoveTimer = new TQTimer(this);
+
+ connect(d->previewThread, TQ_SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
+ this, TQ_SLOT(slotGotImagePreview(const LoadingDescription &, const DImg&)));
+
+ connect(d->mouseMoveTimer, TQ_SIGNAL(timeout()),
+ this, TQ_SLOT(slotMouseMoveTimeOut()));
+
+ connect(d->timer, TQ_SIGNAL(timeout()),
+ this, TQ_SLOT(slotTimeOut()));
+
+ d->timer->start(10, true);
+
+ // ---------------------------------------------------------------
+
+ setMouseTracking(true);
+ slotMouseMoveTimeOut();
+}
+
+SlideShow::~SlideShow()
+{
+ d->timer->stop();
+ d->mouseMoveTimer->stop();
+
+ delete d->timer;
+ delete d->mouseMoveTimer;
+ delete d->previewThread;
+ delete d->previewPreloadThread;
+ delete d;
+}
+
+void SlideShow::setCurrent(const KURL& url)
+{
+ int index = d->settings.fileList.findIndex(url);
+ if (index != -1)
+ {
+ d->currentImage = url;
+ d->fileIndex = index-1;
+ }
+}
+
+void SlideShow::slotTimeOut()
+{
+ loadNextImage();
+}
+
+void SlideShow::loadNextImage()
+{
+ d->fileIndex++;
+ int num = d->settings.fileList.count();
+
+ if (d->fileIndex >= num)
+ {
+ if (d->settings.loop)
+ {
+ d->fileIndex = 0;
+ }
+ }
+
+ if (!d->settings.loop)
+ {
+ d->toolBar->setEnabledPrev(d->fileIndex > 0);
+ d->toolBar->setEnabledNext(d->fileIndex < num-1);
+ }
+
+ if (d->fileIndex < num)
+ {
+ d->currentImage = d->settings.fileList[d->fileIndex];
+ d->previewThread->load(LoadingDescription(d->currentImage.path(),
+ TQMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
+ }
+ else
+ {
+ d->currentImage = KURL();
+ d->preview = DImg();
+ updatePixmap();
+ update();
+ }
+
+}
+
+void SlideShow::loadPrevImage()
+{
+ d->fileIndex--;
+ int num = d->settings.fileList.count();
+
+ if (d->fileIndex < 0)
+ {
+ if (d->settings.loop)
+ {
+ d->fileIndex = num-1;
+ }
+ }
+
+ if (!d->settings.loop)
+ {
+ d->toolBar->setEnabledPrev(d->fileIndex > 0);
+ d->toolBar->setEnabledNext(d->fileIndex < num-1);
+ }
+
+ if (d->fileIndex >= 0)
+ {
+ d->currentImage = d->settings.fileList[d->fileIndex];
+ d->previewThread->load(LoadingDescription(d->currentImage.path(),
+ TQMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
+ }
+ else
+ {
+ d->currentImage = KURL();
+ d->preview = DImg();
+ updatePixmap();
+ update();
+ }
+
+}
+
+void SlideShow::slotGotImagePreview(const LoadingDescription&, const DImg& preview)
+{
+ d->preview = preview;
+
+ updatePixmap();
+ update();
+
+ if (!d->endOfShow)
+ {
+ if (!d->pause)
+ d->timer->start(d->settings.delay, true);
+ preloadNextImage();
+ }
+}
+
+void SlideShow::preloadNextImage()
+{
+ int index = d->fileIndex + 1;
+ int num = d->settings.fileList.count();
+
+ if (index >= num)
+ {
+ if (d->settings.loop)
+ {
+ index = 0;
+ }
+ }
+
+ if (index < num)
+ {
+ d->previewPreloadThread->load(LoadingDescription(d->settings.fileList[index].path(),
+ TQMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
+ }
+}
+
+void SlideShow::updatePixmap()
+{
+ d->pixmap = TQPixmap(size());
+ d->pixmap.fill(TQt::black);
+ TQPainter p(&(d->pixmap));
+
+ if (!d->currentImage.path().isEmpty())
+ {
+ if (!d->preview.isNull())
+ {
+ // Preview extraction is complete... Draw the image.
+
+ TQPixmap pix(d->preview.smoothScale(width(), height(), TQSize::ScaleMin).convertToPixmap());
+ p.drawPixmap((width()-pix.width())/2,
+ (height()-pix.height())/2, pix,
+ 0, 0, pix.width(), pix.height());
+
+ TQString str;
+ PhotoInfoContainer photoInfo = d->settings.pictInfoMap[d->currentImage].photoInfo;
+ int offset = 0;
+
+ // Display the Comments.
+
+ if (d->settings.printComment)
+ {
+ str = d->settings.pictInfoMap[d->currentImage].comment;
+ printComments(p, offset, str);
+ }
+
+ // Display the Make and Model.
+
+ if (d->settings.printMakeModel)
+ {
+ str = TQString();
+
+ if (!photoInfo.make.isEmpty())
+ str = photoInfo.make;
+
+ if (!photoInfo.model.isEmpty())
+ {
+ if (!photoInfo.make.isEmpty())
+ str += TQString(" / ");
+
+ str += photoInfo.model;
+ }
+
+ printInfoText(p, offset, str);
+ }
+
+ // Display the Exposure and Sensitivity.
+
+ if (d->settings.printExpoSensitivity)
+ {
+ str = TQString();
+
+ if (!photoInfo.exposureTime.isEmpty())
+ str = photoInfo.exposureTime;
+
+ if (!photoInfo.sensitivity.isEmpty())
+ {
+ if (!photoInfo.exposureTime.isEmpty())
+ str += TQString(" / ");
+
+ str += i18n("%1 ISO").arg(photoInfo.sensitivity);
+ }
+
+ printInfoText(p, offset, str);
+ }
+
+ // Display the Aperture and Focal.
+
+ if (d->settings.printApertureFocal)
+ {
+ str = TQString();
+
+ if (!photoInfo.aperture.isEmpty())
+ str = photoInfo.aperture;
+
+ if (photoInfo.focalLength35mm.isEmpty())
+ {
+ if (!photoInfo.focalLength.isEmpty())
+ {
+ if (!photoInfo.aperture.isEmpty())
+ str += TQString(" / ");
+
+ str += photoInfo.focalLength;
+ }
+ }
+ else
+ {
+ if (!photoInfo.aperture.isEmpty())
+ str += TQString(" / ");
+
+ if (!photoInfo.focalLength.isEmpty())
+ str += TQString("%1 (35mm: %2)").arg(photoInfo.focalLength).arg(photoInfo.focalLength35mm);
+ else
+ str += TQString("35mm: %1)").arg(photoInfo.focalLength35mm);
+ }
+
+ printInfoText(p, offset, str);
+ }
+
+ // Display the Creation Date.
+
+ if (d->settings.printDate)
+ {
+ if (photoInfo.dateTime.isValid())
+ {
+ str = TDEGlobal::locale()->formatDateTime(photoInfo.dateTime, true, true);
+ printInfoText(p, offset, str);
+ }
+ }
+
+ // Display the image File Name.
+
+ if (d->settings.printName)
+ {
+ str = TQString("%1 (%2/%3)").arg(d->currentImage.filename())
+ .arg(TQString::number(d->fileIndex + 1))
+ .arg(TQString::number(d->settings.fileList.count()));
+
+ printInfoText(p, offset, str);
+ }
+ }
+ else
+ {
+ // ...or preview extraction is failed.
+
+ p.setPen(TQt::white);
+ p.drawText(0, 0, d->pixmap.width(), d->pixmap.height(),
+ TQt::AlignCenter|TQt::WordBreak,
+ i18n("Cannot display image\n\"%1\"")
+ .arg(d->currentImage.fileName()));
+ }
+ }
+ else
+ {
+ // End of Slide Show.
+
+ TQPixmap logo = kapp->iconLoader()->loadIcon("digikam", TDEIcon::NoGroup, 128,
+ TDEIcon::DefaultState, 0, true);
+
+ TQFont fn(font());
+ fn.setPointSize(fn.pointSize()+10);
+ fn.setBold(true);
+
+ p.setFont(fn);
+ p.setPen(TQt::white);
+ p.drawPixmap(50, 100, logo);
+ p.drawText(60 + logo.width(), 100 + logo.height()/3, i18n("SlideShow Completed."));
+ p.drawText(60 + logo.width(), 100 + 2*logo.height()/3, i18n("Click To Exit..."));
+
+ d->endOfShow = true;
+ d->toolBar->setEnabledPlay(false);
+ d->toolBar->setEnabledNext(false);
+ d->toolBar->setEnabledPrev(false);
+ }
+}
+
+void SlideShow::printInfoText(TQPainter &p, int &offset, const TQString& str)
+{
+ if (!str.isEmpty())
+ {
+ offset += 20;
+ p.setPen(TQt::black);
+ for (int x=9; x<=11; x++)
+ for (int y=offset+1; y>=offset-1; y--)
+ p.drawText(x, height()-y, str);
+
+ p.setPen(TQt::white);
+ p.drawText(10, height()-offset, str);
+ }
+}
+
+void SlideShow::printComments(TQPainter &p, int &offset, const TQString& comments)
+{
+ TQStringList commentsByLines;
+
+ uint commentsIndex = 0; // Comments TQString index
+
+ while (commentsIndex < comments.length())
+ {
+ TQString newLine;
+ bool breakLine = false; // End Of Line found
+ uint currIndex; // Comments TQString current index
+
+ // Check miminal lines dimension
+
+ uint commentsLinesLengthLocal = MAXSTRINGLEN;
+
+ for (currIndex = commentsIndex; currIndex < comments.length() && !breakLine; currIndex++ )
+ {
+ if( comments[currIndex] == TQChar('\n') || comments[currIndex].isSpace() )
+ breakLine = true;
+ }
+
+ if (commentsLinesLengthLocal <= (currIndex - commentsIndex))
+ commentsLinesLengthLocal = (currIndex - commentsIndex);
+
+ breakLine = false;
+
+ for (currIndex = commentsIndex ; currIndex <= commentsIndex + commentsLinesLengthLocal &&
+ currIndex < comments.length() && !breakLine ;
+ currIndex++ )
+ {
+ breakLine = (comments[currIndex] == TQChar('\n')) ? true : false;
+
+ if (breakLine)
+ newLine.append(TQString(" "));
+ else
+ newLine.append(comments[currIndex]);
+ }
+
+ commentsIndex = currIndex; // The line is ended
+
+ if (commentsIndex != comments.length())
+ {
+ while (!newLine.endsWith(" "))
+ {
+ newLine.truncate(newLine.length() - 1);
+ commentsIndex--;
+ }
+ }
+
+ commentsByLines.prepend(newLine.stripWhiteSpace());
+ }
+
+ for (int i = 0 ; i < (int)commentsByLines.count() ; i++ )
+ {
+ printInfoText(p, offset, commentsByLines[i]);
+ }
+}
+
+void SlideShow::paintEvent(TQPaintEvent *)
+{
+ bitBlt(this, 0, 0, static_cast<TQPaintDevice*>(&d->pixmap),
+ 0, 0, d->pixmap.width(),
+ d->pixmap.height(), TQt::CopyROP, true);
+}
+
+void SlideShow::slotPause()
+{
+ d->timer->stop();
+ d->pause = true;
+
+ if (d->toolBar->isHidden())
+ {
+ int w = d->toolBar->width();
+ d->toolBar->move(d->deskWidth-w-1,0);
+ d->toolBar->show();
+ }
+}
+
+void SlideShow::slotPlay()
+{
+ d->toolBar->hide();
+ d->pause = false;
+ slotTimeOut();
+}
+
+void SlideShow::slotPrev()
+{
+ loadPrevImage();
+}
+
+void SlideShow::slotNext()
+{
+ loadNextImage();
+}
+
+void SlideShow::slotClose()
+{
+ close();
+}
+
+void SlideShow::wheelEvent(TQWheelEvent * e)
+{
+ if (e->delta() < 0)
+ {
+ d->timer->stop();
+ d->pause = true;
+ d->toolBar->setPaused(true);
+ slotNext();
+ }
+
+ if (e->delta() > 0 && d->fileIndex-1 >= 0)
+ {
+ d->timer->stop();
+ d->pause = true;
+ d->toolBar->setPaused(true);
+ slotPrev();
+ }
+}
+
+void SlideShow::mousePressEvent(TQMouseEvent *e)
+{
+ if (d->endOfShow)
+ close();
+
+ if (e->button() == TQt::LeftButton)
+ {
+ d->timer->stop();
+ d->pause = true;
+ d->toolBar->setPaused(true);
+ slotNext();
+ }
+ else if (e->button() == TQt::RightButton && d->fileIndex-1 >= 0)
+ {
+ d->timer->stop();
+ d->pause = true;
+ d->toolBar->setPaused(true);
+ slotPrev();
+ }
+}
+
+void SlideShow::keyPressEvent(TQKeyEvent *event)
+{
+ if (!event)
+ return;
+
+ d->toolBar->keyPressEvent(event);
+}
+
+void SlideShow::mouseMoveEvent(TQMouseEvent *e)
+{
+ setCursor(TQCursor(TQt::ArrowCursor));
+ d->mouseMoveTimer->start(1000, true);
+
+ if (!d->toolBar->canHide())
+ return;
+
+ TQPoint pos(e->pos());
+
+ if ((pos.y() > (d->deskY+20)) &&
+ (pos.y() < (d->deskY+d->deskHeight-20-1)))
+ {
+ if (d->toolBar->isHidden())
+ return;
+ else
+ d->toolBar->hide();
+ return;
+ }
+
+ int w = d->toolBar->width();
+ int h = d->toolBar->height();
+
+ if (pos.y() < (d->deskY+20))
+ {
+ if (pos.x() <= (d->deskX+d->deskWidth/2))
+ // position top left
+ d->toolBar->move(d->deskX, d->deskY);
+ else
+ // position top right
+ d->toolBar->move(d->deskX+d->deskWidth-w-1, d->deskY);
+ }
+ else
+ {
+ if (pos.x() <= (d->deskX+d->deskWidth/2))
+ // position bot left
+ d->toolBar->move(d->deskX, d->deskY+d->deskHeight-h-1);
+ else
+ // position bot right
+ d->toolBar->move(d->deskX+d->deskWidth-w-1, d->deskY+d->deskHeight-h-1);
+ }
+ d->toolBar->show();
+}
+
+void SlideShow::slotMouseMoveTimeOut()
+{
+ TQPoint pos(TQCursor::pos());
+ if ((pos.y() < (d->deskY+20)) ||
+ (pos.y() > (d->deskY+d->deskHeight-20-1)))
+ return;
+
+ setCursor(TQCursor(TQt::BlankCursor));
+}
+
+} // NameSpace Digikam
diff --git a/src/utilities/slideshow/slideshow.h b/src/utilities/slideshow/slideshow.h
new file mode 100644
index 00000000..dc15ce1c
--- /dev/null
+++ b/src/utilities/slideshow/slideshow.h
@@ -0,0 +1,91 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-04-21
+ * Description : slide show tool using preview of pictures.
+ *
+ * Copyright (C) 2005-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 SLIDE_SHOW_H
+#define SLIDE_SHOW_H
+
+// TQt includes.
+
+#include <tqwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "loadingdescription.h"
+#include "slideshowsettings.h"
+
+namespace Digikam
+{
+
+class DImg;
+class SlideShowPriv;
+
+class DIGIKAM_EXPORT SlideShow : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ SlideShow(const SlideShowSettings& settings);
+ ~SlideShow();
+
+ void setCurrent(const KURL& url);
+
+protected:
+
+ void paintEvent(TQPaintEvent *);
+ void mousePressEvent(TQMouseEvent *);
+ void mouseMoveEvent(TQMouseEvent *);
+ void keyPressEvent(TQKeyEvent *);
+ void wheelEvent(TQWheelEvent *);
+
+private slots:
+
+ void slotTimeOut();
+ void slotMouseMoveTimeOut();
+ void slotGotImagePreview(const LoadingDescription &, const DImg &);
+
+ void slotPause();
+ void slotPlay();
+ void slotPrev();
+ void slotNext();
+ void slotClose();
+
+private:
+
+ void loadNextImage();
+ void loadPrevImage();
+ void preloadNextImage();
+ void updatePixmap();
+ void printInfoText(TQPainter &p, int &offset, const TQString& str);
+ void printComments(TQPainter &p, int &offset, const TQString& comments);
+
+private:
+
+ SlideShowPriv *d;
+};
+
+} // NameSpace Digikam
+
+#endif /* SLIDE_SHOW_H */
diff --git a/src/utilities/slideshow/slideshowsettings.h b/src/utilities/slideshow/slideshowsettings.h
new file mode 100644
index 00000000..85057f27
--- /dev/null
+++ b/src/utilities/slideshow/slideshowsettings.h
@@ -0,0 +1,125 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2007-02-13
+ * Description : slide show settings container.
+ *
+ * Copyright (C) 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 SLIDESHOWSETTINGSCONTAINER_H
+#define SLIDESHOWSETTINGSCONTAINER_H
+
+// TQt includes.
+
+#include <tqmap.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "photoinfocontainer.h"
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+/** This class contain the information of one picture to slide */
+class DIGIKAM_EXPORT SlidePictureInfo
+{
+
+public:
+
+ SlidePictureInfo(){};
+
+ ~SlidePictureInfo(){};
+
+public:
+
+ /** Image Comment */
+ TQString comment;
+
+ /** Exif photo info of picture */
+ PhotoInfoContainer photoInfo;
+};
+
+// --------------------------------------------------------------------------------
+
+/** This class contain all settings to perform a slide show of a group of pictures */
+class DIGIKAM_EXPORT SlideShowSettings
+{
+
+public:
+
+ SlideShowSettings()
+ {
+ exifRotate = true;
+ printName = true;
+ printDate = false;
+ printComment = false;
+ printApertureFocal = false;
+ printMakeModel = false;
+ printExpoSensitivity = false;
+ loop = false;
+ delay = 5;
+ };
+
+ ~SlideShowSettings(){};
+
+public:
+
+ // Global Slide Show Settings
+
+ /** Auto-rotate image accordinly with Exif Rotation tag */
+ bool exifRotate;
+
+ /** Print picture file name during slide */
+ bool printName;
+
+ /** Print picture creation date during slide */
+ bool printDate;
+
+ /** Print camera Aperture and Focal during slide */
+ bool printApertureFocal;
+
+ /** Print camera Make and Model during slide */
+ bool printMakeModel;
+
+ /** Print camera Exposure and Sensitivity during slide */
+ bool printExpoSensitivity;
+
+ /** Print picture comment during slide */
+ bool printComment;
+
+ /** Slide pictures in loop */
+ bool loop;
+
+ /** Delay in seconds */
+ int delay;
+
+ /** List of pictures URL to slide */
+ KURL::List fileList;
+
+ /** Map of pictures information to slide */
+ TQMap<KURL, SlidePictureInfo> pictInfoMap;
+};
+
+} // namespace Digikam
+
+#endif // SLIDESHOWSETTINGSCONTAINER_H
diff --git a/src/utilities/slideshow/toolbar.cpp b/src/utilities/slideshow/toolbar.cpp
new file mode 100644
index 00000000..dbecd4ad
--- /dev/null
+++ b/src/utilities/slideshow/toolbar.cpp
@@ -0,0 +1,217 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-10-05
+ * Description : a tool bar for slideshow
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 <tqtoolbutton.h>
+#include <tqlayout.h>
+#include <tqpixmap.h>
+
+// KDE includes.
+
+#include <tdeapplication.h>
+#include <kiconloader.h>
+#include <tdelocale.h>
+
+// Local includes.
+
+#include "toolbar.h"
+#include "toolbar.moc"
+
+namespace Digikam
+{
+
+class ToolBarPriv
+{
+public:
+
+ ToolBarPriv()
+ {
+ playBtn = 0;
+ stopBtn = 0;
+ nextBtn = 0;
+ prevBtn = 0;
+ canHide = true;
+ }
+
+ bool canHide;
+
+ TQToolButton *playBtn;
+ TQToolButton *stopBtn;
+ TQToolButton *nextBtn;
+ TQToolButton *prevBtn;
+};
+
+ToolBar::ToolBar(TQWidget* parent)
+ : TQWidget(parent)
+{
+ d = new ToolBarPriv;
+
+ TQHBoxLayout* lay = new TQHBoxLayout(this);
+ d->playBtn = new TQToolButton(this);
+ d->prevBtn = new TQToolButton(this);
+ d->nextBtn = new TQToolButton(this);
+ d->stopBtn = new TQToolButton(this);
+ d->playBtn->setToggleButton(true);
+
+ TDEIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("media-playback-pause", TDEIcon::NoGroup, 22));
+ d->prevBtn->setIconSet(loader->loadIcon("back", TDEIcon::NoGroup, 22));
+ d->nextBtn->setIconSet(loader->loadIcon("forward", TDEIcon::NoGroup, 22));
+ d->stopBtn->setIconSet(loader->loadIcon("process-stop", TDEIcon::NoGroup, 22));
+
+ lay->addWidget(d->playBtn);
+ lay->addWidget(d->prevBtn);
+ lay->addWidget(d->nextBtn);
+ lay->addWidget(d->stopBtn);
+
+ setBackgroundMode(TQt::NoBackground);
+ adjustSize();
+ setSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Fixed);
+
+ connect(d->playBtn, TQ_SIGNAL(toggled(bool)),
+ this, TQ_SLOT(slotPlayBtnToggled()));
+
+ connect(d->nextBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotNexPrevClicked()));
+
+ connect(d->prevBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotNexPrevClicked()));
+
+ connect(d->nextBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SIGNAL(signalNext()));
+
+ connect(d->prevBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SIGNAL(signalPrev()));
+
+ connect(d->stopBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SIGNAL(signalClose()));
+}
+
+ToolBar::~ToolBar()
+{
+ delete d;
+}
+
+bool ToolBar::canHide() const
+{
+ return d->canHide;
+}
+
+bool ToolBar::isPaused() const
+{
+ return d->playBtn->isOn();
+}
+
+void ToolBar::setPaused(bool val)
+{
+ if (val == isPaused())
+ return;
+
+ d->playBtn->setOn(val);
+ slotPlayBtnToggled();
+}
+
+void ToolBar::setEnabledPlay(bool val)
+{
+ d->playBtn->setEnabled(val);
+}
+
+void ToolBar::setEnabledNext(bool val)
+{
+ d->nextBtn->setEnabled(val);
+}
+
+void ToolBar::setEnabledPrev(bool val)
+{
+ d->prevBtn->setEnabled(val);
+}
+
+void ToolBar::slotPlayBtnToggled()
+{
+ if (d->playBtn->isOn())
+ {
+ d->canHide = false;
+ TDEIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("media-playback-start", TDEIcon::NoGroup, 22));
+ emit signalPause();
+ }
+ else
+ {
+ d->canHide = true;
+ TDEIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("media-playback-pause", TDEIcon::NoGroup, 22));
+ emit signalPlay();
+ }
+}
+
+void ToolBar::slotNexPrevClicked()
+{
+ if (!d->playBtn->isOn())
+ {
+ d->playBtn->setOn(true);
+ d->canHide = false;
+ TDEIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("media-playback-start", TDEIcon::NoGroup, 22));
+ emit signalPause();
+ }
+}
+
+void ToolBar::keyPressEvent(TQKeyEvent *event)
+{
+ switch(event->key())
+ {
+ case(TQt::Key_Space):
+ {
+ if (d->playBtn->isEnabled())
+ d->playBtn->animateClick();
+ break;
+ }
+ case(TQt::Key_Prior):
+ {
+ if (d->prevBtn->isEnabled())
+ d->prevBtn->animateClick();
+ break;
+ }
+ case(TQt::Key_Next):
+ {
+ if (d->nextBtn->isEnabled())
+ d->nextBtn->animateClick();
+ break;
+ }
+ case(TQt::Key_Escape):
+ {
+ if (d->stopBtn->isEnabled())
+ d->stopBtn->animateClick();
+ break;
+ }
+ default:
+ break;
+ }
+
+ event->accept();
+}
+
+} // Namespace Digikam
+
diff --git a/src/utilities/slideshow/toolbar.h b/src/utilities/slideshow/toolbar.h
new file mode 100644
index 00000000..97262c12
--- /dev/null
+++ b/src/utilities/slideshow/toolbar.h
@@ -0,0 +1,85 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-10-05
+ * Description : a tool bar for slideshow
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * 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 TOOL_BAR_H
+#define TOOL_BAR_H
+
+#include <tqwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class TQToolButton;
+
+namespace Digikam
+{
+
+class ToolBarPriv;
+
+class DIGIKAM_EXPORT ToolBar : public TQWidget
+{
+ TQ_OBJECT
+
+
+public:
+
+ ToolBar(TQWidget* parent);
+ ~ToolBar();
+
+ bool canHide() const;
+ bool isPaused() const;
+ void setPaused(bool val);
+
+ void setEnabledPlay(bool val);
+ void setEnabledNext(bool val);
+ void setEnabledPrev(bool val);
+
+protected:
+
+ void keyPressEvent(TQKeyEvent *event);
+
+signals:
+
+ void signalNext();
+ void signalPrev();
+ void signalClose();
+ void signalPlay();
+ void signalPause();
+
+private slots:
+
+ void slotPlayBtnToggled();
+ void slotNexPrevClicked();
+
+private:
+
+ ToolBarPriv *d;
+
+ friend class SlideShow;
+};
+
+} // Namespace Digikam
+
+#endif /* TOOL_BAR_H */