summaryrefslogtreecommitdiffstats
path: root/digikam/utilities
diff options
context:
space:
mode:
Diffstat (limited to 'digikam/utilities')
-rw-r--r--digikam/utilities/Makefile.am1
-rw-r--r--digikam/utilities/batch/Makefile.am20
-rw-r--r--digikam/utilities/batch/batchalbumssyncmetadata.cpp183
-rw-r--r--digikam/utilities/batch/batchalbumssyncmetadata.h81
-rw-r--r--digikam/utilities/batch/batchsyncmetadata.cpp166
-rw-r--r--digikam/utilities/batch/batchsyncmetadata.h88
-rw-r--r--digikam/utilities/batch/batchthumbsgenerator.cpp233
-rw-r--r--digikam/utilities/batch/batchthumbsgenerator.h82
-rw-r--r--digikam/utilities/batch/imageinfoalbumsjob.cpp125
-rw-r--r--digikam/utilities/batch/imageinfoalbumsjob.h79
-rw-r--r--digikam/utilities/batch/imageinfojob.cpp163
-rw-r--r--digikam/utilities/batch/imageinfojob.h77
-rw-r--r--digikam/utilities/cameragui/Makefile.am30
-rw-r--r--digikam/utilities/cameragui/albumselectdialog.cpp417
-rw-r--r--digikam/utilities/cameragui/albumselectdialog.h79
-rw-r--r--digikam/utilities/cameragui/animwidget.cpp131
-rw-r--r--digikam/utilities/cameragui/animwidget.h65
-rw-r--r--digikam/utilities/cameragui/cameracontroller.cpp1227
-rw-r--r--digikam/utilities/cameragui/cameracontroller.h110
-rw-r--r--digikam/utilities/cameragui/camerafolderdialog.cpp138
-rw-r--r--digikam/utilities/cameragui/camerafolderdialog.h67
-rw-r--r--digikam/utilities/cameragui/camerafolderitem.cpp108
-rw-r--r--digikam/utilities/cameragui/camerafolderitem.h69
-rw-r--r--digikam/utilities/cameragui/camerafolderview.cpp169
-rw-r--r--digikam/utilities/cameragui/camerafolderview.h82
-rw-r--r--digikam/utilities/cameragui/cameraiconitem.cpp302
-rw-r--r--digikam/utilities/cameragui/cameraiconitem.h81
-rw-r--r--digikam/utilities/cameragui/cameraiconview.cpp900
-rw-r--r--digikam/utilities/cameragui/cameraiconview.h140
-rw-r--r--digikam/utilities/cameragui/camerainfodialog.cpp85
-rw-r--r--digikam/utilities/cameragui/camerainfodialog.h50
-rw-r--r--digikam/utilities/cameragui/cameraui.cpp1734
-rw-r--r--digikam/utilities/cameragui/cameraui.h154
-rw-r--r--digikam/utilities/cameragui/dkcamera.cpp113
-rw-r--r--digikam/utilities/cameragui/dkcamera.h97
-rw-r--r--digikam/utilities/cameragui/downloadsettingscontainer.h79
-rw-r--r--digikam/utilities/cameragui/freespacewidget.cpp252
-rw-r--r--digikam/utilities/cameragui/freespacewidget.h74
-rw-r--r--digikam/utilities/cameragui/gpcamera.cpp1208
-rw-r--r--digikam/utilities/cameragui/gpcamera.h107
-rw-r--r--digikam/utilities/cameragui/gpiteminfo.cpp68
-rw-r--r--digikam/utilities/cameragui/gpiteminfo.h80
-rw-r--r--digikam/utilities/cameragui/mtqueue.h116
-rw-r--r--digikam/utilities/cameragui/renamecustomizer.cpp532
-rw-r--r--digikam/utilities/cameragui/renamecustomizer.h90
-rw-r--r--digikam/utilities/cameragui/umscamera.cpp519
-rw-r--r--digikam/utilities/cameragui/umscamera.h78
-rw-r--r--digikam/utilities/hotplug/Makefile.am7
-rw-r--r--digikam/utilities/hotplug/configure.in.in7
-rwxr-xr-xdigikam/utilities/hotplug/digikam-camera40
-rw-r--r--digikam/utilities/hotplug/digikam-download.desktop.in27
-rw-r--r--digikam/utilities/hotplug/digikam-gphoto2-camera.desktop.in27
-rw-r--r--digikam/utilities/hotplug/digikam-mount-and-download.desktop.in27
-rw-r--r--digikam/utilities/imageeditor/Makefile.am1
-rw-r--r--digikam/utilities/imageeditor/canvas/Makefile.am28
-rw-r--r--digikam/utilities/imageeditor/canvas/canvas.cpp1421
-rw-r--r--digikam/utilities/imageeditor/canvas/canvas.h208
-rw-r--r--digikam/utilities/imageeditor/canvas/colorcorrectiondlg.cpp186
-rw-r--r--digikam/utilities/imageeditor/canvas/colorcorrectiondlg.h71
-rw-r--r--digikam/utilities/imageeditor/canvas/dimginterface.cpp1270
-rw-r--r--digikam/utilities/imageeditor/canvas/dimginterface.h199
-rw-r--r--digikam/utilities/imageeditor/canvas/iccsettingscontainer.h82
-rw-r--r--digikam/utilities/imageeditor/canvas/imageplugin.cpp68
-rw-r--r--digikam/utilities/imageeditor/canvas/imageplugin.h69
-rw-r--r--digikam/utilities/imageeditor/canvas/imagepluginloader.cpp278
-rw-r--r--digikam/utilities/imageeditor/canvas/imagepluginloader.h79
-rw-r--r--digikam/utilities/imageeditor/canvas/iofilesettingscontainer.h84
-rw-r--r--digikam/utilities/imageeditor/canvas/undoaction.cpp185
-rw-r--r--digikam/utilities/imageeditor/canvas/undoaction.h144
-rw-r--r--digikam/utilities/imageeditor/canvas/undocache.cpp178
-rw-r--r--digikam/utilities/imageeditor/canvas/undocache.h62
-rw-r--r--digikam/utilities/imageeditor/canvas/undomanager.cpp253
-rw-r--r--digikam/utilities/imageeditor/canvas/undomanager.h76
-rw-r--r--digikam/utilities/imageeditor/editor/Makefile.am51
-rw-r--r--digikam/utilities/imageeditor/editor/digikamimageplugin.desktop39
-rw-r--r--digikam/utilities/imageeditor/editor/digikamimagewindowui.rc125
-rw-r--r--digikam/utilities/imageeditor/editor/editorstackview.cpp233
-rw-r--r--digikam/utilities/imageeditor/editor/editorstackview.h96
-rw-r--r--digikam/utilities/imageeditor/editor/editortool.cpp436
-rw-r--r--digikam/utilities/imageeditor/editor/editortool.h162
-rw-r--r--digikam/utilities/imageeditor/editor/editortooliface.cpp147
-rw-r--r--digikam/utilities/imageeditor/editor/editortooliface.h75
-rw-r--r--digikam/utilities/imageeditor/editor/editortoolsettings.cpp331
-rw-r--r--digikam/utilities/imageeditor/editor/editortoolsettings.h109
-rw-r--r--digikam/utilities/imageeditor/editor/editorwindow.cpp1936
-rw-r--r--digikam/utilities/imageeditor/editor/editorwindow.h262
-rw-r--r--digikam/utilities/imageeditor/editor/editorwindowprivate.h143
-rw-r--r--digikam/utilities/imageeditor/editor/imageiface.cpp444
-rw-r--r--digikam/utilities/imageeditor/editor/imageiface.h198
-rw-r--r--digikam/utilities/imageeditor/editor/imagewindow.cpp1263
-rw-r--r--digikam/utilities/imageeditor/editor/imagewindow.h154
-rw-r--r--digikam/utilities/imageeditor/editor/savingcontextcontainer.h89
-rw-r--r--digikam/utilities/imageeditor/rawimport/Makefile.am27
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawimport.cpp223
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawimport.h87
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawpostprocessing.cpp137
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawpostprocessing.h63
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawpreview.cpp336
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawpreview.h107
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawsettingsbox.cpp741
-rw-r--r--digikam/utilities/imageeditor/rawimport/rawsettingsbox.h90
-rw-r--r--digikam/utilities/imageeditor/tools/Makefile.am19
-rw-r--r--digikam/utilities/imageeditor/tools/imageprint.cpp814
-rw-r--r--digikam/utilities/imageeditor/tools/imageprint.h121
-rw-r--r--digikam/utilities/imageeditor/tools/imageresize.cpp650
-rw-r--r--digikam/utilities/imageeditor/tools/imageresize.h81
-rw-r--r--digikam/utilities/lighttable/Makefile.am28
-rw-r--r--digikam/utilities/lighttable/lighttablebar.cpp881
-rw-r--r--digikam/utilities/lighttable/lighttablebar.h152
-rw-r--r--digikam/utilities/lighttable/lighttablepreview.cpp777
-rw-r--r--digikam/utilities/lighttable/lighttablepreview.h124
-rw-r--r--digikam/utilities/lighttable/lighttableview.cpp446
-rw-r--r--digikam/utilities/lighttable/lighttableview.h136
-rw-r--r--digikam/utilities/lighttable/lighttablewindow.cpp1680
-rw-r--r--digikam/utilities/lighttable/lighttablewindow.h161
-rw-r--r--digikam/utilities/lighttable/lighttablewindowprivate.h158
-rw-r--r--digikam/utilities/lighttable/lighttablewindowui.rc83
-rw-r--r--digikam/utilities/scripts/Makefile.am4
-rw-r--r--digikam/utilities/scripts/digitaglinktree568
-rw-r--r--digikam/utilities/scripts/digitaglinktree.1182
-rw-r--r--digikam/utilities/setup/Makefile.am29
-rw-r--r--digikam/utilities/setup/cameraselection.cpp494
-rw-r--r--digikam/utilities/setup/cameraselection.h87
-rw-r--r--digikam/utilities/setup/setup.cpp266
-rw-r--r--digikam/utilities/setup/setup.h80
-rw-r--r--digikam/utilities/setup/setupcamera.cpp315
-rw-r--r--digikam/utilities/setup/setupcamera.h72
-rw-r--r--digikam/utilities/setup/setupcollections.cpp218
-rw-r--r--digikam/utilities/setup/setupcollections.h65
-rw-r--r--digikam/utilities/setup/setupdcraw.cpp150
-rw-r--r--digikam/utilities/setup/setupdcraw.h66
-rw-r--r--digikam/utilities/setup/setupeditor.cpp176
-rw-r--r--digikam/utilities/setup/setupeditor.h62
-rw-r--r--digikam/utilities/setup/setupgeneral.cpp313
-rw-r--r--digikam/utilities/setup/setupgeneral.h66
-rw-r--r--digikam/utilities/setup/setupicc.cpp727
-rw-r--r--digikam/utilities/setup/setupicc.h85
-rw-r--r--digikam/utilities/setup/setupidentity.cpp217
-rw-r--r--digikam/utilities/setup/setupidentity.h59
-rw-r--r--digikam/utilities/setup/setupiofiles.cpp137
-rw-r--r--digikam/utilities/setup/setupiofiles.h62
-rw-r--r--digikam/utilities/setup/setuplighttable.cpp133
-rw-r--r--digikam/utilities/setup/setuplighttable.h58
-rw-r--r--digikam/utilities/setup/setupmetadata.cpp238
-rw-r--r--digikam/utilities/setup/setupmetadata.h66
-rw-r--r--digikam/utilities/setup/setupmime.cpp280
-rw-r--r--digikam/utilities/setup/setupmime.h65
-rw-r--r--digikam/utilities/setup/setupmisc.cpp124
-rw-r--r--digikam/utilities/setup/setupmisc.h58
-rw-r--r--digikam/utilities/setup/setupplugins.cpp104
-rw-r--r--digikam/utilities/setup/setupplugins.h55
-rw-r--r--digikam/utilities/setup/setupslideshow.cpp165
-rw-r--r--digikam/utilities/setup/setupslideshow.h63
-rw-r--r--digikam/utilities/setup/setuptooltip.cpp272
-rw-r--r--digikam/utilities/setup/setuptooltip.h58
-rw-r--r--digikam/utilities/slideshow/Makefile.am17
-rw-r--r--digikam/utilities/slideshow/slideshow.cpp679
-rw-r--r--digikam/utilities/slideshow/slideshow.h90
-rw-r--r--digikam/utilities/slideshow/slideshowsettings.h125
-rw-r--r--digikam/utilities/slideshow/toolbar.cpp217
-rw-r--r--digikam/utilities/slideshow/toolbar.h84
161 files changed, 37792 insertions, 0 deletions
diff --git a/digikam/utilities/Makefile.am b/digikam/utilities/Makefile.am
new file mode 100644
index 0000000..fe4c153
--- /dev/null
+++ b/digikam/utilities/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = imageeditor setup cameragui hotplug scripts batch slideshow lighttable
diff --git a/digikam/utilities/batch/Makefile.am b/digikam/utilities/batch/Makefile.am
new file mode 100644
index 0000000..72cb18d
--- /dev/null
+++ b/digikam/utilities/batch/Makefile.am
@@ -0,0 +1,20 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/libs/dialogs \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/thumbbar \
+ -I$(top_srcdir)/digikam/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)
+
+
diff --git a/digikam/utilities/batch/batchalbumssyncmetadata.cpp b/digikam/utilities/batch/batchalbumssyncmetadata.cpp
new file mode 100644
index 0000000..a889e21
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kapplication.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;
+
+ QTime duration;
+
+ ImageInfoJob *imageInfoJob;
+
+ AlbumList palbumList;
+ AlbumList::Iterator albumsIt;
+};
+
+BatchAlbumsSyncMetadata::BatchAlbumsSyncMetadata(QWidget* 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);
+ QTimer::singleShot(500, this, SLOT(slotStart()));
+}
+
+BatchAlbumsSyncMetadata::~BatchAlbumsSyncMetadata()
+{
+ delete d;
+}
+
+void BatchAlbumsSyncMetadata::slotStart()
+{
+ setTitle(i18n("Parsing all albums"));
+ setTotalSteps(d->palbumList.count());
+
+ connect(d->imageInfoJob, SIGNAL(signalItemsInfo(const ImageInfoList&)),
+ this, SLOT(slotAlbumParsed(const ImageInfoList&)));
+
+ connect(d->imageInfoJob, SIGNAL(signalCompleted()),
+ this, SLOT(slotComplete()));
+
+ d->albumsIt = d->palbumList.begin();
+ parseAlbum();
+}
+
+void BatchAlbumsSyncMetadata::parseAlbum()
+{
+ if (d->albumsIt == d->palbumList.end()) // All is done.
+ {
+ QTime 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)
+{
+ QPixmap pix = KApplication::kApplication()->iconLoader()->loadIcon(
+ "folder_image", KIcon::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(QCloseEvent *e)
+{
+ abort();
+ e->accept();
+}
+
+void BatchAlbumsSyncMetadata::abort()
+{
+ d->cancel = true;
+ d->imageInfoJob->stop();
+ emit signalComplete();
+}
+
+} // namespace Digikam
+
+
diff --git a/digikam/utilities/batch/batchalbumssyncmetadata.h b/digikam/utilities/batch/batchalbumssyncmetadata.h
new file mode 100644
index 0000000..8aa1971
--- /dev/null
+++ b/digikam/utilities/batch/batchalbumssyncmetadata.h
@@ -0,0 +1,81 @@
+/* ============================================================
+ *
+ * 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 QWidget;
+
+class KURL;
+
+namespace Digikam
+{
+
+class BatchAlbumsSyncMetadataPriv;
+
+class BatchAlbumsSyncMetadata : public DProgressDlg
+{
+ Q_OBJECT
+
+public:
+
+ BatchAlbumsSyncMetadata(QWidget* parent);
+ ~BatchAlbumsSyncMetadata();
+
+signals:
+
+ void signalComplete();
+
+private:
+
+ void abort();
+ void parseAlbum();
+
+protected:
+
+ void closeEvent(QCloseEvent *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/digikam/utilities/batch/batchsyncmetadata.cpp b/digikam/utilities/batch/batchsyncmetadata.cpp
new file mode 100644
index 0000000..4caedb2
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kapplication.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(QObject* parent, Album *album)
+ : QObject(parent)
+{
+ d = new BatchSyncMetadataPriv;
+ d->album = album;
+}
+
+BatchSyncMetadata::BatchSyncMetadata(QObject* parent, const ImageInfoList& list)
+ : QObject(parent)
+{
+ d = new BatchSyncMetadataPriv;
+ d->imageInfoList = list;
+}
+
+BatchSyncMetadata::~BatchSyncMetadata()
+{
+ delete d;
+}
+
+void BatchSyncMetadata::parseAlbum()
+{
+ d->imageInfoJob->allItemsFromAlbum(d->album);
+
+ connect(d->imageInfoJob, SIGNAL(signalItemsInfo(const ImageInfoList&)),
+ this, SLOT(slotAlbumParsed(const ImageInfoList&)));
+
+ connect(d->imageInfoJob, SIGNAL(signalCompleted()),
+ this, 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, QString());
+ emit signalComplete();
+}
+
+} // namespace Digikam
+
+
diff --git a/digikam/utilities/batch/batchsyncmetadata.h b/digikam/utilities/batch/batchsyncmetadata.h
new file mode 100644
index 0000000..f1d1592
--- /dev/null
+++ b/digikam/utilities/batch/batchsyncmetadata.h
@@ -0,0 +1,88 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+
+class KURL;
+
+namespace Digikam
+{
+
+class Album;
+class BatchSyncMetadataPriv;
+
+class BatchSyncMetadata : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /** Constructor witch sync all metatada pictures from an Album */
+ BatchSyncMetadata(QObject* parent, Album *album);
+
+ /** Constructor witch sync all metatada from an images list */
+ BatchSyncMetadata(QObject* parent, const ImageInfoList& list);
+
+ ~BatchSyncMetadata();
+
+ void parseList();
+ void parseAlbum();
+
+signals:
+
+ void signalComplete();
+ void signalProgressValue(int);
+ void signalProgressBarMode(int, const QString&);
+
+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/digikam/utilities/batch/batchthumbsgenerator.cpp b/digikam/utilities/batch/batchthumbsgenerator.cpp
new file mode 100644
index 0000000..3d6e7ec
--- /dev/null
+++ b/digikam/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>
+}
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qtimer.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qdatetime.h>
+
+// KDE includes.
+
+#include <kmdcodec.h>
+#include <klocale.h>
+#include <kapplication.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;
+
+ QTime duration;
+
+ QGuardedPtr<ThumbnailJob> thumbJob;
+};
+
+BatchThumbsGenerator::BatchThumbsGenerator(QWidget* parent)
+ : DProgressDlg(parent)
+{
+ d = new BatchThumbsGeneratorPriv;
+ setValue(0);
+ setCaption(i18n("Thumbnails processing"));
+ setLabel(i18n("<b>Updating thumbnails database. Please wait...</b>"));
+ setButtonText(i18n("&Abort"));
+ QTimer::singleShot(500, this, 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, SIGNAL(signalRebuildThumbsDone()),
+ this, SLOT(slotRebuildThumbs256()));
+}
+
+void BatchThumbsGenerator::slotRebuildThumbs256()
+{
+ setTitle(i18n("Processing large thumbs"));
+ rebuildAllThumbs(256);
+
+ disconnect(this, SIGNAL(signalRebuildThumbsDone()),
+ this, SLOT(slotRebuildThumbs256()));
+
+ connect(this, SIGNAL(signalRebuildThumbsDone()),
+ this, SLOT(slotRebuildAllThumbComplete()));
+}
+
+void BatchThumbsGenerator::slotRebuildAllThumbComplete()
+{
+ QTime 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)
+{
+ QStringList allPicturesPath;
+ QString thumbCacheDir = QDir::homeDirPath() + "/.thumbnails/";
+ QString 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();
+ QStringList albumItemsPath = db->getItemURLsInAlbum((*it)->id());
+ db->commitTransaction();
+
+ QStringList pathSorted;
+ for (QStringList::iterator it2 = albumItemsPath.begin();
+ !d->cancel && (it2 != albumItemsPath.end()); ++it2)
+ {
+ QFileInfo 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 (QStringList::iterator it = allPicturesPath.begin();
+ !d->cancel && (it != allPicturesPath.end()); ++it)
+ {
+ QString uri = "file://" + QDir::cleanDirPath(*it);
+ KMD5 md5(QFile::encodeName(uri));
+ uri = md5.hexDigest();
+
+ QString smallThumbPath = thumbCacheDir + "normal/" + uri + ".png";
+ QString bigThumbPath = thumbCacheDir + "large/" + uri + ".png";
+
+ if (size <= 128)
+ ::unlink(QFile::encodeName(smallThumbPath));
+ else
+ ::unlink(QFile::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, SIGNAL(signalThumbnail(const KURL&, const QPixmap&)),
+ this, SLOT(slotRebuildThumbDone(const KURL&, const QPixmap&)));
+
+ connect(d->thumbJob, SIGNAL(signalFailed(const KURL&)),
+ this, SLOT(slotRebuildThumbDone(const KURL&)));
+
+ connect(d->thumbJob, SIGNAL(signalCompleted()),
+ this, SIGNAL(signalRebuildThumbsDone()));
+}
+
+void BatchThumbsGenerator::slotRebuildThumbDone(const KURL& url, const QPixmap& pix)
+{
+ addedAction(pix, url.path());
+ advance(1);
+}
+
+void BatchThumbsGenerator::slotCancel()
+{
+ abort();
+ done(Cancel);
+}
+
+void BatchThumbsGenerator::closeEvent(QCloseEvent *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/digikam/utilities/batch/batchthumbsgenerator.h b/digikam/utilities/batch/batchthumbsgenerator.h
new file mode 100644
index 0000000..774da11
--- /dev/null
+++ b/digikam/utilities/batch/batchthumbsgenerator.h
@@ -0,0 +1,82 @@
+/* ============================================================
+ *
+ * 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 QWidget;
+class QPixmap;
+
+class KURL;
+
+namespace Digikam
+{
+
+class BatchThumbsGeneratorPriv;
+
+class BatchThumbsGenerator : public DProgressDlg
+{
+ Q_OBJECT
+
+public:
+
+ BatchThumbsGenerator(QWidget* parent);
+ ~BatchThumbsGenerator();
+
+signals:
+
+ void signalRebuildThumbsDone();
+ void signalRebuildAllThumbsDone();
+
+private:
+
+ void rebuildAllThumbs(int size);
+ void abort();
+
+protected:
+
+ void closeEvent(QCloseEvent *e);
+
+protected slots:
+
+ void slotCancel();
+
+private slots:
+
+ void slotRebuildThumbs128();
+ void slotRebuildThumbs256();
+ void slotRebuildThumbDone(const KURL& url, const QPixmap& pix=QPixmap());
+ void slotRebuildAllThumbComplete();
+
+private:
+
+ BatchThumbsGeneratorPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* BATCHTHUMBSGENERATOR_H */
diff --git a/digikam/utilities/batch/imageinfoalbumsjob.cpp b/digikam/utilities/batch/imageinfoalbumsjob.cpp
new file mode 100644
index 0000000..5fbc914
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.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, SIGNAL(signalItemsInfo(const ImageInfoList&)),
+ this, SLOT(slotItemsInfo(const ImageInfoList&)));
+
+ connect(&d->imageInfoJob, SIGNAL(signalCompleted()),
+ this, 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/digikam/utilities/batch/imageinfoalbumsjob.h b/digikam/utilities/batch/imageinfoalbumsjob.h
new file mode 100644
index 0000000..a1d22d5
--- /dev/null
+++ b/digikam/utilities/batch/imageinfoalbumsjob.h
@@ -0,0 +1,79 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qcstring.h>
+
+// Local includes.
+
+#include "albummanager.h"
+#include "imageinfo.h"
+
+namespace KIO
+{
+class Job;
+}
+
+namespace Digikam
+{
+
+class ImageInfoAlbumsJobPriv;
+
+class ImageInfoAlbumsJob : public QObject
+{
+ Q_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/digikam/utilities/batch/imageinfojob.cpp b/digikam/utilities/batch/imageinfojob.cpp
new file mode 100644
index 0000000..d7570d1
--- /dev/null
+++ b/digikam/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 KIO 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qdatastream.h>
+
+// KDE includes.
+
+#include <kio/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();
+ }
+
+ QString imagefilter;
+
+ KIO::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;
+
+ QByteArray ba;
+ QDataStream 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 -> kio_digikamalbums
+ d->job = new KIO::TransferJob(album->kurl(), KIO::CMD_SPECIAL,
+ ba, QByteArray(), false);
+
+ connect(d->job, SIGNAL(result(KIO::Job*)),
+ this, SLOT(slotResult(KIO::Job*)));
+
+ connect(d->job, SIGNAL(data(KIO::Job*, const QByteArray&)),
+ this, SLOT(slotData(KIO::Job*, const QByteArray&)));
+}
+
+void ImageInfoJob::stop()
+{
+ if (d->job)
+ {
+ d->job->kill();
+ d->job = 0;
+ }
+}
+
+void ImageInfoJob::slotResult(KIO::Job* job)
+{
+ d->job = 0;
+
+ if (job->error())
+ {
+ DWarning() << "Failed to list url: " << job->errorString() << endl;
+ return;
+ }
+
+ emit signalCompleted();
+}
+
+void ImageInfoJob::slotData(KIO::Job*, const QByteArray& data)
+{
+ if (data.isEmpty())
+ return;
+
+ Q_LLONG imageID;
+ int albumID;
+ QString name;
+ QString date;
+ size_t size;
+ QSize dims;
+ ImageInfoList itemsList;
+ QDataStream 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,
+ QDateTime::fromString(date, Qt::ISODate),
+ size, dims);
+
+ itemsList.append(info);
+ }
+
+ emit signalItemsInfo(itemsList);
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/batch/imageinfojob.h b/digikam/utilities/batch/imageinfojob.h
new file mode 100644
index 0000000..80fb112
--- /dev/null
+++ b/digikam/utilities/batch/imageinfojob.h
@@ -0,0 +1,77 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2006-22-01
+ * Description : digikamalbum KIO 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
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qcstring.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+
+namespace KIO
+{
+class Job;
+}
+
+namespace Digikam
+{
+
+class Album;
+class ImageInfoJobPriv;
+
+class ImageInfoJob : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ ImageInfoJob();
+ ~ImageInfoJob();
+
+ void allItemsFromAlbum(Album *album);
+ void stop();
+
+signals:
+
+ void signalItemsInfo(const ImageInfoList& items);
+ void signalCompleted();
+
+private slots:
+
+ void slotResult(KIO::Job* job);
+ void slotData(KIO::Job* job, const QByteArray& data);
+
+private:
+
+ ImageInfoJobPriv *d;
+};
+
+} // namespace Digikam
+
+#endif /* IMAGEINFOJOB_H */
diff --git a/digikam/utilities/cameragui/Makefile.am b/digikam/utilities/cameragui/Makefile.am
new file mode 100644
index 0000000..cb99f9b
--- /dev/null
+++ b/digikam/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)
+
+libcameragui_la_LIBADD = $(top_builddir)/digikam/libs/imageproperties/libimagepropertiescamgui.la \
+ $(LIB_GPHOTO) $(LIBJPEG)
+
+INCLUDES = -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/editor \
+ -I$(top_srcdir)/digikam/libs/jpegutils \
+ -I$(top_srcdir)/digikam/libs/themeengine \
+ -I$(top_srcdir)/digikam/libs/imageproperties \
+ -I$(top_srcdir)/digikam/libs/widgets/common \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ $(LIBKEXIV2_CFLAGS) \
+ $(GPHOTO_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes)
diff --git a/digikam/utilities/cameragui/albumselectdialog.cpp b/digikam/utilities/cameragui/albumselectdialog.cpp
new file mode 100644
index 0000000..a94f4df
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlabel.h>
+#include <qframe.h>
+#include <qlayout.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qdatetime.h>
+#include <qmap.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kinputdialog.h>
+#include <kmessagebox.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;
+
+ QString newAlbumString;
+
+ QMap<FolderItem*, PAlbum*> albumMap;
+
+ FolderView *folderView;
+
+ SearchTextBar *searchBar;
+};
+
+AlbumSelectDialog::AlbumSelectDialog(QWidget* parent, PAlbum* albumToSelect,
+ const QString& header,
+ const QString& 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;
+
+ // -------------------------------------------------------------
+
+ QGridLayout* grid = new QGridLayout(plainPage(), 2, 1, 0, spacingHint());
+
+ QLabel *logo = new QLabel(plainPage());
+ KIconLoader* iconLoader = KApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", KIcon::NoGroup, 128, KIcon::DefaultState, 0, true));
+
+ QLabel *message = new QLabel(plainPage());
+ if (!header.isEmpty())
+ message->setText(header);
+
+ d->folderView = new FolderView(plainPage());
+ d->folderView->addColumn(i18n("My Albums"));
+ d->folderView->setColumnWidthMode( 0, QListView::Maximum );
+ d->folderView->setResizeMode( QListView::AllColumns );
+ d->folderView->setRootIsDecorated(true);
+
+ d->searchBar = new SearchTextBar(plainPage(), "AlbumSelectDialogSearchBar");
+
+ // -------------------------------------------------------------
+
+ QPixmap icon = iconLoader->loadIcon("folder", KIcon::NoGroup,
+ AlbumSettings::instance()->getDefaultTreeIconSize(), KIcon::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(), SIGNAL(signalAlbumAdded(Album*)),
+ this, SLOT(slotAlbumAdded(Album*)));
+
+ connect(AlbumManager::instance(), SIGNAL(signalAlbumDeleted(Album*)),
+ this, SLOT(slotAlbumDeleted(Album*)));
+
+ connect(AlbumManager::instance(), SIGNAL(signalAlbumsCleared()),
+ this, SLOT(slotAlbumsCleared()));
+
+ connect(d->folderView, SIGNAL(selectionChanged()),
+ this, SLOT(slotSelectionChanged()));
+
+ connect(d->folderView, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotContextMenu(QListViewItem*, const QPoint&, int)));
+
+ connect(d->searchBar, SIGNAL(signalTextChanged(const QString&)),
+ this, SLOT(slotSearchTextChanged(const QString&)));
+
+ // -------------------------------------------------------------
+
+ 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;
+ }
+
+ KIconLoader *iconLoader = KApplication::kApplication()->iconLoader();
+ QPixmap icon = iconLoader->loadIcon("folder", KIcon::NoGroup,
+ AlbumSettings::instance()->getDefaultTreeIconSize(),
+ KIcon::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()
+{
+ QListViewItem* selItem = 0;
+ QListViewItemIterator 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(QListViewItem *, const QPoint &, int)
+{
+ QPopupMenu popmenu(d->folderView);
+ KAction *action = new KAction(i18n( "Create New Album" ),
+ "albumfolder-new", 0, this,
+ SLOT( slotUser1() ),
+ &popmenu);
+ action->plug(&popmenu);
+ popmenu.exec(QCursor::pos());
+}
+
+void AlbumSelectDialog::slotUser1()
+{
+ QListViewItem* item = d->folderView->currentItem();
+ if (!item)
+ item = d->folderView->firstChild();
+
+ if (!item)
+ return;
+
+ PAlbum* album = d->albumMap[(FolderItem*)item];
+ if (!album)
+ return;
+
+ bool ok;
+ QString 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;
+
+ QString errMsg;
+ PAlbum* newAlbum = AlbumManager::instance()->createPAlbum(album, newAlbumName,
+ QString(), QDate::currentDate(),
+ QString(), 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(QWidget* parent,
+ PAlbum* albumToSelect,
+ const QString& header,
+ const QString& 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 QString& filter)
+{
+ QString 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/digikam/utilities/cameragui/albumselectdialog.h b/digikam/utilities/cameragui/albumselectdialog.h
new file mode 100644
index 0000000..20dc756
--- /dev/null
+++ b/digikam/utilities/cameragui/albumselectdialog.h
@@ -0,0 +1,79 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class PAlbum;
+class AlbumSelectDialogPrivate;
+
+class AlbumSelectDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ AlbumSelectDialog(QWidget* parent, PAlbum* albumToSelect,
+ const QString& header=QString(),
+ const QString& newAlbumString=QString(),
+ bool allowRootSelection=false);
+ ~AlbumSelectDialog();
+
+
+ static PAlbum* selectAlbum(QWidget* parent,
+ PAlbum* albumToSelect,
+ const QString& header=QString(),
+ const QString& newAlbumString=QString(),
+ bool allowRootSelection=false);
+
+private slots:
+
+ void slotAlbumAdded(Album*);
+ void slotAlbumDeleted(Album*);
+ void slotAlbumsCleared();
+ void slotSelectionChanged();
+ void slotContextMenu(QListViewItem *item, const QPoint&, int);
+ void slotUser1();
+ void slotSearchTextChanged(const QString&);
+
+private:
+
+ AlbumSelectDialogPrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* ALBUMSELECTDIALOG_H */
diff --git a/digikam/utilities/cameragui/animwidget.cpp b/digikam/utilities/cameragui/animwidget.cpp
new file mode 100644
index 0000000..a1112ab
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpalette.h>
+#include <qcolor.h>
+#include <qtimer.h>
+
+// Local includes.
+
+#include "animwidget.h"
+#include "animwidget.moc"
+
+namespace Digikam
+{
+
+class AnimWidgetPriv
+{
+public:
+
+ AnimWidgetPriv()
+ {
+ timer = 0;
+ pos = 0;
+ }
+
+ int pos;
+ int size;
+
+ QTimer *timer;
+
+ QPixmap pix;
+};
+
+AnimWidget::AnimWidget(QWidget* parent, int size)
+ : QWidget(parent, 0, WResizeNoErase|WRepaintNoErase)
+{
+ d = new AnimWidgetPriv;
+ setBackgroundMode(Qt::NoBackground);
+
+ d->size = size;
+ d->pix = QPixmap(d->size, d->size);
+ setFixedSize(d->size, d->size);
+
+ d->timer = new QTimer(this);
+
+ connect(d->timer, SIGNAL(timeout()),
+ this, 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(QPaintEvent*)
+{
+ d->pix.fill(colorGroup().background());
+ QPainter p(&d->pix);
+
+ p.translate(d->size/2, d->size/2);
+
+ if (d->timer->isActive())
+ {
+ p.setPen(QPen(colorGroup().text()));
+ p.rotate( d->pos );
+ }
+ else
+ {
+ p.setPen(QPen(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/digikam/utilities/cameragui/animwidget.h b/digikam/utilities/cameragui/animwidget.h
new file mode 100644
index 0000000..533ef37
--- /dev/null
+++ b/digikam/utilities/cameragui/animwidget.h
@@ -0,0 +1,65 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class AnimWidgetPriv;
+
+class AnimWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ AnimWidget(QWidget* parent, int size=28);
+ ~AnimWidget();
+
+ void start();
+ void stop();
+ bool running() const;
+
+protected:
+
+ void paintEvent(QPaintEvent*);
+
+private slots:
+
+ void slotTimeout();
+
+private:
+
+ AnimWidgetPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* ANIMWIDGET_H */
diff --git a/digikam/utilities/cameragui/cameracontroller.cpp b/digikam/utilities/cameragui/cameracontroller.cpp
new file mode 100644
index 0000000..10e134c
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qevent.h>
+#include <qapplication.h>
+#include <qdeepcopy.h>
+#include <qvariant.h>
+#include <qimage.h>
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qtimer.h>
+#include <qregexp.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <kio/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;
+ QMap<QString,QVariant> map;
+};
+
+class CameraEvent : public QCustomEvent
+{
+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) :
+ QCustomEvent(QEvent::User+state)
+ {}
+
+ bool result;
+ QString msg;
+ QMap<QString,QVariant> 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;
+
+ QWidget *parent;
+
+ QTimer *timer;
+
+ CameraThread *thread;
+
+ DKCamera *camera;
+
+ MTQueue<CameraCommand> cmdQueue;
+};
+
+class CameraThread : public QThread
+{
+public:
+
+ CameraThread(CameraController* controller);
+ ~CameraThread();
+
+ void sendBusy(bool busy);
+ void sendError(const QString& msg);
+ void sendInfo(const QString& msg);
+
+protected:
+
+ void run();
+
+private:
+
+ CameraControllerPriv *d;
+
+ QObject *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;
+ QApplication::postEvent(parent, event);
+
+ if (result)
+ sendInfo(i18n("Connection established"));
+ else
+ sendInfo(i18n("Connection failed"));
+
+ break;
+ }
+ case(CameraCommand::gp_cameraInformations):
+ {
+ sendInfo(i18n("Getting camera information..."));
+
+ QString 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", QVariant(summary));
+ event->map.insert("manual", QVariant(manual));
+ event->map.insert("about", QVariant(about));
+ QApplication::postEvent(parent, event);
+ break;
+ }
+ case(CameraCommand::gp_listfolders):
+ {
+ sendInfo(i18n("Listing folders..."));
+
+ QStringList folderList;
+ folderList.append(d->camera->path());
+ d->camera->getAllFolders(d->camera->path(), folderList);
+
+ /* TODO: ugly hack since qt <= 3.1.2 does not define
+ QStringList with QDeepCopy as a friend. */
+ QValueList<QString> flist(folderList);
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_listedfolders);
+ event->map.insert("folders", QVariant(flist));
+ QApplication::postEvent(parent, event);
+
+ sendInfo(i18n("The folders have been listed."));
+
+ break;
+ }
+ case(CameraCommand::gp_listfiles):
+ {
+ QString 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", QVariant(folder));
+
+ QByteArray ba;
+ QDataStream ds(ba, IO_WriteOnly);
+ ds << itemsList;
+
+ event->map.insert("files", QVariant(ba));
+ QApplication::postEvent(parent, event);
+ }
+
+ sendInfo(i18n("Listing files in %1 is complete").arg(folder));
+
+ break;
+ }
+ case(CameraCommand::gp_thumbnail):
+ {
+ QString folder = cmd->map["folder"].asString();
+ QString file = cmd->map["file"].asString();
+
+ sendInfo(i18n("Getting thumbnails..."));
+
+ QImage thumbnail;
+ d->camera->getThumbnail(folder, file, thumbnail);
+
+ if (!thumbnail.isNull())
+ {
+ thumbnail = thumbnail.smoothScale(ThumbnailSize::Huge, ThumbnailSize::Huge, QImage::ScaleMin);
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_thumbnailed);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("thumbnail", QVariant(thumbnail));
+ QApplication::postEvent(parent, event);
+ }
+
+ break;
+ }
+ case(CameraCommand::gp_exif):
+ {
+ QString folder = cmd->map["folder"].asString();
+ QString 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)
+ {
+ QByteArray ba;
+ QDataStream ds(ba, IO_WriteOnly);
+ ds.writeRawBytes(edata, esize);
+ delete [] edata;
+
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_exif);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("exifSize", QVariant(esize));
+ event->map.insert("exifData", QVariant(ba));
+ QApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_download):
+ {
+ QString folder = cmd->map["folder"].asString();
+ QString file = cmd->map["file"].asString();
+ QString dest = cmd->map["dest"].asString();
+ bool autoRotate = cmd->map["autoRotate"].asBool();
+ bool fixDateTime = cmd->map["fixDateTime"].asBool();
+ QDateTime newDateTime = cmd->map["newDateTime"].asDateTime();
+ bool setPhotographerId = cmd->map["setPhotographerId"].asBool();
+ QString author = cmd->map["author"].asString();
+ QString authorTitle = cmd->map["authorTitle"].asString();
+ bool setCredits = cmd->map["setCredits"].asBool();
+ QString credit = cmd->map["credit"].asString();
+ QString source = cmd->map["source"].asString();
+ QString copyright = cmd->map["copyright"].asString();
+ bool convertJpeg = cmd->map["convertJpeg"].asBool();
+ QString 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", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("dest", QVariant(dest));
+ QApplication::postEvent(parent, event);
+
+ KURL tempURL(dest);
+ tempURL = tempURL.upURL();
+ tempURL.addPath( QString(".digikam-camera-tmp1-%1").arg(getpid()).append(file));
+ DDebug() << "Downloading: " << file << " using (" << tempURL.path() << ")" << endl;
+ QString 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( QString(".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(QFile::encodeName(tempURL.path()));
+ unlink(QFile::encodeName(tempURL2.path()));
+ result = false;
+ }
+ else
+ {
+ // Else remove only the first temp file.
+ unlink(QFile::encodeName(tempURL.path()));
+ }
+ }
+ }
+
+ if (result)
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_downloaded);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("dest", QVariant(dest));
+ event->map.insert("temp", QVariant(temp));
+ QApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_downloadFailed);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("dest", QVariant(dest));
+ QApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_open):
+ {
+ QString folder = cmd->map["folder"].asString();
+ QString file = cmd->map["file"].asString();
+ QString 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", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("dest", QVariant(dest));
+ QApplication::postEvent(parent, event);
+ }
+ else
+ {
+ sendError(i18n("Failed to retrieve file %1 from camera").arg(file));
+ }
+ break;
+ }
+ case(CameraCommand::gp_upload):
+ {
+ QString folder = cmd->map["destFolder"].asString();
+
+ // We will using the same source file name to create the dest file
+ // name in camera.
+ QString file = cmd->map["destFile"].asString();
+
+ // The source file path to download in camera.
+ QString 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);
+ QByteArray ba;
+ QDataStream ds(ba, IO_WriteOnly);
+ ds << itemsInfo;
+ event->map.insert("info", QVariant(ba));
+
+ QApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_uploadFailed);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ event->map.insert("src", QVariant(src));
+ QApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_delete):
+ {
+ QString folder = cmd->map["folder"].asString();
+ QString 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", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ QApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_deleteFailed);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ QApplication::postEvent(parent, event);
+ }
+ break;
+ }
+ case(CameraCommand::gp_lock):
+ {
+ QString folder = cmd->map["folder"].asString();
+ QString 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", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ QApplication::postEvent(parent, event);
+ }
+ else
+ {
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_lockFailed);
+ event->map.insert("folder", QVariant(folder));
+ event->map.insert("file", QVariant(file));
+ QApplication::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;
+ QApplication::postEvent(parent, event);
+}
+
+void CameraThread::sendError(const QString& msg)
+{
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_errormsg);
+ event->msg = msg;
+ QApplication::postEvent(parent, event);
+}
+
+void CameraThread::sendInfo(const QString& msg)
+{
+ CameraEvent* event = new CameraEvent(CameraEvent::gp_infomsg);
+ event->msg = msg;
+ QApplication::postEvent(parent, event);
+}
+
+
+//-- Camera Controller ------------------------------------------------------
+
+
+CameraController::CameraController(QWidget* parent, const QString& title, const QString& model,
+ const QString& port, const QString& path)
+ : QObject(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;
+ QString xport = url.host();
+ if (xport.startsWith("usb:"))
+ {
+ DDebug() << "xport " << xport << endl;
+ QRegExp x = QRegExp("(usb:[0-9,]*)");
+
+ if (x.search(xport) != -1)
+ {
+ QString 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 QTimer(this);
+
+ connect(d->timer, SIGNAL(timeout()),
+ this, 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;
+}
+
+QString CameraController::getCameraPath()
+{
+ if (!d->camera) return QString();
+ return d->camera->path();
+}
+
+QString CameraController::getCameraTitle()
+{
+ if (!d->camera) return QString();
+ 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 QString& folder)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_listfiles;
+ cmd->map.insert("folder", QVariant(folder));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::getThumbnail(const QString& folder, const QString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_thumbnail;
+ cmd->map.insert("folder", QVariant(folder));
+ cmd->map.insert("file", QVariant(file));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::getExif(const QString& folder, const QString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_exif;
+ cmd->map.insert("folder", QVariant(folder));
+ cmd->map.insert("file", QVariant(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 QFileInfo& srcFileInfo, const QString& destFile, const QString& destFolder)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_upload;
+ cmd->map.insert("srcFilePath", QVariant(srcFileInfo.filePath()));
+ cmd->map.insert("destFile", QVariant(destFile));
+ cmd->map.insert("destFolder", QVariant(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", QVariant(downloadSettings.folder));
+ cmd->map.insert("file", QVariant(downloadSettings.file));
+ cmd->map.insert("dest", QVariant(downloadSettings.dest));
+ cmd->map.insert("autoRotate", QVariant(downloadSettings.autoRotate, 0));
+ cmd->map.insert("fixDateTime", QVariant(downloadSettings.fixDateTime, 0));
+ cmd->map.insert("newDateTime", QVariant(downloadSettings.newDateTime));
+ cmd->map.insert("setPhotographerId", QVariant(downloadSettings.setPhotographerId, 0));
+ cmd->map.insert("author", QVariant(downloadSettings.author));
+ cmd->map.insert("authorTitle", QVariant(downloadSettings.authorTitle));
+ cmd->map.insert("setCredits", QVariant(downloadSettings.setCredits, 0));
+ cmd->map.insert("credit", QVariant(downloadSettings.credit));
+ cmd->map.insert("source", QVariant(downloadSettings.source));
+ cmd->map.insert("copyright", QVariant(downloadSettings.copyright));
+ cmd->map.insert("convertJpeg", QVariant(downloadSettings.convertJpeg, 0));
+ cmd->map.insert("losslessFormat", QVariant(downloadSettings.losslessFormat));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::deleteFile(const QString& folder, const QString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_delete;
+ cmd->map.insert("folder", QVariant(folder));
+ cmd->map.insert("file", QVariant(file));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::lockFile(const QString& folder, const QString& file, bool lock)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_lock;
+ cmd->map.insert("folder", QVariant(folder));
+ cmd->map.insert("file", QVariant(file));
+ cmd->map.insert("lock", QVariant(lock, 0));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::openFile(const QString& folder, const QString& file)
+{
+ d->canceled = false;
+ CameraCommand *cmd = new CameraCommand;
+ cmd->action = CameraCommand::gp_open;
+ cmd->map.insert("folder", QVariant(folder));
+ cmd->map.insert("file", QVariant(file));
+ cmd->map.insert("dest", QVariant(locateLocal("tmp", file)));
+ d->cmdQueue.enqueue(cmd);
+}
+
+void CameraController::slotCancel()
+{
+ d->canceled = true;
+ d->cmdQueue.flush();
+ d->camera->cancel();
+}
+
+void CameraController::customEvent(QCustomEvent* e)
+{
+ CameraEvent* event = dynamic_cast<CameraEvent*>(e);
+ if (!event)
+ {
+ return;
+ }
+
+ switch(event->type()-QEvent::User)
+ {
+ case (CameraEvent::gp_connected) :
+ {
+ emit signalConnected(event->result);
+ break;
+ }
+ case (CameraEvent::gp_cameraInformations) :
+ {
+ QString summary = QDeepCopy<QString>(event->map["summary"].asString());
+ QString manual = QDeepCopy<QString>(event->map["manual"].asString());
+ QString about = QDeepCopy<QString>(event->map["about"].asString());
+ emit signalCameraInformations(summary, manual, about);
+ break;
+ }
+ case (CameraEvent::gp_errormsg) :
+ {
+ emit signalErrorMsg(QDeepCopy<QString>(event->msg));
+ break;
+ }
+ case (CameraEvent::gp_busy) :
+ {
+ if (event->result)
+ emit signalBusy(true);
+ break;
+ }
+ case (CameraEvent::gp_infomsg) :
+ {
+ if (!d->canceled)
+ emit signalInfoMsg(QDeepCopy<QString>(event->msg));
+ break;
+ }
+ case (CameraEvent::gp_listedfolders) :
+ {
+ /* TODO: ugly hack since qt <= 3.1.2 does not define
+ QStringList with QDeepCopy as a friend. */
+ QValueList<QVariant> flist = QDeepCopy< QValueList<QVariant> >(event->map["folders"].toList());
+
+ QStringList folderList;
+ QValueList<QVariant>::Iterator it;
+ for (it = flist.begin(); it != flist.end(); ++it )
+ {
+ folderList.append(QDeepCopy<QString>((*it).asString()));
+ }
+
+ emit signalFolderList(folderList);
+ break;
+ }
+ case (CameraEvent::gp_listedfiles) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QByteArray ba = QDeepCopy<QByteArray>(event->map["files"].asByteArray());
+ QDataStream ds(ba, IO_ReadOnly);
+ GPItemInfoList items;
+ ds >> items;
+ emit signalFileList(items);
+ break;
+ }
+ case (CameraEvent::gp_thumbnailed) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ QImage thumb = QDeepCopy<QImage>(event->map["thumbnail"].asImage());
+ emit signalThumbnail(folder, file, thumb);
+ break;
+ }
+ case (CameraEvent::gp_exif) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ QByteArray ba = QDeepCopy<QByteArray>(event->map["exifData"].asByteArray());
+ emit signalExifData(ba);
+ break;
+ }
+ case (CameraEvent::gp_downloadstarted) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ emit signalDownloaded(folder, file, GPItemInfo::DownloadStarted);
+ break;
+ }
+ case (CameraEvent::gp_downloaded) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ QString dest = QDeepCopy<QString>(event->map["dest"].asString());
+ QString temp = QDeepCopy<QString>(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)
+ {
+ QFileInfo info(dest);
+
+ while (info.exists())
+ {
+ if (d->skipAll)
+ {
+ skip = true;
+ break;
+ }
+
+ KIO::RenameDlg dlg(d->parent, i18n("Rename File"),
+ folder + QString("/") + file, dest,
+ KIO::RenameDlg_Mode(KIO::M_MULTI | KIO::M_OVERWRITE | KIO::M_SKIP));
+
+ int result = dlg.exec();
+ dest = dlg.newDestURL().path();
+ info = QFileInfo(dest);
+
+ switch (result)
+ {
+ case KIO::R_CANCEL:
+ {
+ cancel = true;
+ break;
+ }
+ case KIO::R_SKIP:
+ {
+ skip = true;
+ break;
+ }
+ case KIO::R_AUTO_SKIP:
+ {
+ d->skipAll = true;
+ skip = true;
+ break;
+ }
+ case KIO::R_OVERWRITE:
+ {
+ overwrite = true;
+ break;
+ }
+ case KIO::R_OVERWRITE_ALL:
+ {
+ d->overwriteAll = true;
+ overwrite = true;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (cancel || skip || overwrite)
+ break;
+ }
+ }
+
+ if (cancel)
+ {
+ unlink(QFile::encodeName(temp));
+ slotCancel();
+ d->timer->start(50);
+ emit signalSkipped(folder, file);
+ return;
+ }
+ else if (skip)
+ {
+ unlink(QFile::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(QFile::encodeName(temp), QFile::encodeName(dest)) != 0)
+ {
+ // rename failed. delete the temp file
+ unlink(QFile::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) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+
+ d->timer->stop();
+
+ QString 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) :
+ {
+ QByteArray ba = QDeepCopy<QByteArray>(event->map["info"].asByteArray());
+ QDataStream ds(ba, IO_ReadOnly);
+ GPItemInfo itemInfo;
+ ds >> itemInfo;
+
+ emit signalUploaded(itemInfo);
+ break;
+ }
+ case (CameraEvent::gp_uploadFailed) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ QString src = QDeepCopy<QString>(event->map["src"].asString());
+
+ d->timer->stop();
+
+ QString 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) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ emit signalDeleted(folder, file, true);
+ break;
+ }
+ case (CameraEvent::gp_deleteFailed) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+
+ d->timer->stop();
+ emit signalDeleted(folder, file, false);
+
+ QString 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) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ emit signalLocked(folder, file, true);
+ break;
+ }
+ case (CameraEvent::gp_lockFailed) :
+ {
+ QString folder = QDeepCopy<QString>(event->map["folder"].asString());
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+
+ d->timer->stop();
+ emit signalLocked(folder, file, false);
+
+ QString 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) :
+ {
+ QString file = QDeepCopy<QString>(event->map["file"].asString());
+ QString dest = QDeepCopy<QString>(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();
+
+ QString folder;
+ QString file;
+ QString dest;
+
+ if ((cmd->action == CameraCommand::gp_exif) &&
+ (typeid(*(d->camera)) == typeid(UMSCamera)))
+ {
+ folder = QDeepCopy<QString>(cmd->map["folder"].asString());
+ file = QDeepCopy<QString>(cmd->map["file"].asString());
+
+ emit signalExifFromFile(folder, file);
+
+ d->cmdQueue.dequeue();
+ d->timer->start(50, false);
+ return;
+ }
+
+ if (cmd->action == CameraCommand::gp_download)
+ {
+ folder = QDeepCopy<QString>(cmd->map["folder"].asString());
+ file = QDeepCopy<QString>(cmd->map["file"].asString());
+ dest = QDeepCopy<QString>(cmd->map["dest"].asString());
+ cmd->map["dest"] = QVariant(QDeepCopy<QString>(dest));
+ }
+
+ d->thread->start();
+ d->timer->start(50, false);
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/cameragui/cameracontroller.h b/digikam/utilities/cameragui/cameracontroller.h
new file mode 100644
index 0000000..577ded7
--- /dev/null
+++ b/digikam/utilities/cameragui/cameracontroller.h
@@ -0,0 +1,110 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qfileinfo.h>
+
+// Local includes.
+
+#include "downloadsettingscontainer.h"
+#include "gpiteminfo.h"
+
+namespace Digikam
+{
+
+class CameraControllerPriv;
+
+class CameraController : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ CameraController(QWidget* parent, const QString& title, const QString& model,
+ const QString& port, const QString& path);
+ ~CameraController();
+
+ void listFolders();
+ void listFiles(const QString& folder);
+ void getThumbnail(const QString& folder, const QString& file);
+ void getExif(const QString& folder, const QString& file);
+ void getCameraInformations();
+ QString getCameraPath();
+ QString getCameraTitle();
+
+ void downloadPrep();
+ void download(DownloadSettingsContainer downloadSettings);
+ void upload(const QFileInfo& srcFileInfo, const QString& destFile, const QString& destFolder);
+ void deleteFile(const QString& folder, const QString& file);
+ void lockFile(const QString& folder, const QString& file, bool lock);
+ void openFile(const QString& folder, const QString& file);
+
+signals:
+
+ void signalBusy(bool val);
+ void signalInfoMsg(const QString& msg);
+ void signalErrorMsg(const QString& msg);
+ void signalCameraInformations(const QString& summary, const QString& manual, const QString& about);
+
+ void signalConnected(bool val);
+ void signalFolderList(const QStringList& folderList);
+ void signalFileList(const GPItemInfoList& infoList);
+ void signalUploaded(const GPItemInfo& itemInfo);
+ void signalDownloaded(const QString& folder, const QString& file, int status);
+ void signalSkipped(const QString& folder, const QString& file);
+ void signalDeleted(const QString& folder, const QString& file, bool status);
+ void signalLocked(const QString& folder, const QString& file, bool status);
+ void signalThumbnail(const QString& folder, const QString& file, const QImage& thumb);
+ void signalExifFromFile(const QString& folder, const QString& file);
+ void signalExifData(const QByteArray& exifData);
+
+protected:
+
+ void customEvent(QCustomEvent* 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/digikam/utilities/cameragui/camerafolderdialog.cpp b/digikam/utilities/cameragui/camerafolderdialog.cpp
new file mode 100644
index 0000000..c5d72f5
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qframe.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.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(QWidget *parent, CameraIconView *cameraView,
+ const QStringList& cameraFolderList,
+ const QString& cameraName, const QString& 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;
+
+ QFrame *page = makeMainWidget();
+ QGridLayout* grid = new QGridLayout(page, 2, 1, 0, spacingHint());
+
+ m_folderView = new CameraFolderView(page);
+ QLabel *logo = new QLabel(page);
+ QLabel *message = new QLabel(page);
+
+ KIconLoader* iconLoader = KApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", KIcon::NoGroup, 128, KIcon::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 (QStringList::const_iterator it = cameraFolderList.begin();
+ it != cameraFolderList.end(); ++it)
+ {
+ QString folder(*it);
+ if (folder.startsWith(rootPath) && rootPath != QString("/"))
+ folder.remove(0, rootPath.length());
+
+ if (folder != QString("/") && !folder.isEmpty())
+ {
+ QString root = folder.section( '/', 0, -2 );
+ if (root.isEmpty()) root = QString("/");
+
+ QString sub = folder.section( '/', -1 );
+ m_folderView->addFolder(root, sub, cameraView->countItemsByFolder(*it));
+ DDebug() << "Camera folder: '" << folder << "' (root='" << root << "', sub='" <<sub <<"')" << endl;
+ }
+ }
+
+ connect(m_folderView, SIGNAL(signalFolderChanged(CameraFolderItem*)),
+ this, SLOT(slotFolderPathSelectionChanged(CameraFolderItem*)));
+
+ resize(500, 500);
+}
+
+CameraFolderDialog::~CameraFolderDialog()
+{
+}
+
+QString CameraFolderDialog::selectedFolderPath()
+{
+ QListViewItem *item = m_folderView->currentItem();
+ if (!item) return QString();
+
+ CameraFolderItem *folderItem = static_cast<CameraFolderItem *>(item);
+ if (folderItem->isVirtualFolder())
+ return QString(m_rootPath);
+
+ // Case of Gphoto2 cameras. No need to duplicate root '/'.
+ if (m_rootPath == QString("/"))
+ 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/digikam/utilities/cameragui/camerafolderdialog.h b/digikam/utilities/cameragui/camerafolderdialog.h
new file mode 100644
index 0000000..788d36e
--- /dev/null
+++ b/digikam/utilities/cameragui/camerafolderdialog.h
@@ -0,0 +1,67 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class CameraIconView;
+class CameraFolderView;
+class CameraFolderItem;
+
+class CameraFolderDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ CameraFolderDialog(QWidget *parent, CameraIconView *cameraView, const QStringList& cameraFolderList,
+ const QString& cameraName, const QString& rootPath);
+ ~CameraFolderDialog();
+
+ QString selectedFolderPath();
+
+private slots:
+
+ void slotFolderPathSelectionChanged(CameraFolderItem* item);
+
+private:
+
+ QString m_rootPath;
+
+ CameraFolderView *m_folderView;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAFOLDERDIALOG_H */
diff --git a/digikam/utilities/cameragui/camerafolderitem.cpp b/digikam/utilities/cameragui/camerafolderitem.cpp
new file mode 100644
index 0000000..506c3f8
--- /dev/null
+++ b/digikam/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;
+
+ QString folderName;
+ QString folderPath;
+ QString name;
+};
+
+CameraFolderItem::CameraFolderItem(QListView* parent, const QString& name, const QPixmap& pixmap)
+ : QListViewItem(parent, name)
+{
+ d = new CameraFolderItemPriv;
+ d->virtualFolder = true;
+ d->name = name;
+ setPixmap(0, pixmap);
+}
+
+CameraFolderItem::CameraFolderItem(QListViewItem* parent, const QString& folderName,
+ const QString& folderPath, const QPixmap& pixmap)
+ : QListViewItem(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;
+}
+
+QString CameraFolderItem::folderName()
+{
+ return d->folderName;
+}
+
+QString CameraFolderItem::folderPath()
+{
+ return d->folderPath;
+}
+
+void CameraFolderItem::changeCount(int val)
+{
+ d->count += val;
+ setText(0, QString("%1 (%2)").arg(d->name).arg(QString::number(d->count)));
+}
+
+void CameraFolderItem::setCount(int val)
+{
+ d->count = val;
+ setText(0, QString("%1 (%2)").arg(d->name).arg(QString::number(d->count)));
+}
+
+int CameraFolderItem::count()
+{
+ return d->count;
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/cameragui/camerafolderitem.h b/digikam/utilities/cameragui/camerafolderitem.h
new file mode 100644
index 0000000..5aa33ac
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qlistview.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+
+namespace Digikam
+{
+
+class CameraFolderItemPriv;
+
+class CameraFolderItem : public QListViewItem
+{
+
+public:
+
+ CameraFolderItem(QListView* parent, const QString& name,
+ const QPixmap& pixmap=SmallIcon("folder"));
+
+ CameraFolderItem(QListViewItem* parent, const QString& folderName, const QString& folderPath,
+ const QPixmap& pixmap=SmallIcon("folder"));
+
+ ~CameraFolderItem();
+
+ QString folderName();
+ QString folderPath();
+ bool isVirtualFolder();
+ void changeCount(int val);
+ void setCount(int val);
+ int count();
+
+private:
+
+ CameraFolderItemPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAFOLDERITEM_H */
diff --git a/digikam/utilities/cameragui/camerafolderview.cpp b/digikam/utilities/cameragui/camerafolderview.cpp
new file mode 100644
index 0000000..7dbf612
--- /dev/null
+++ b/digikam/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 <klocale.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 = QString("Camera");
+ }
+
+ QString cameraName;
+
+ CameraFolderItem *virtualFolder;
+ CameraFolderItem *rootFolder;
+};
+
+CameraFolderView::CameraFolderView(QWidget* parent)
+ : QListView(parent)
+{
+ d = new CameraFolderViewPriv;
+
+ addColumn(i18n("Camera Folders"));
+ setColumnWidthMode( 0, QListView::Maximum );
+ setResizeMode( QListView::AllColumns );
+ setSelectionMode(QListView::Single);
+
+ connect(this, SIGNAL(currentChanged(QListViewItem*)),
+ this, SLOT(slotCurrentChanged(QListViewItem*)));
+
+ connect(this, SIGNAL(clicked(QListViewItem*)),
+ this, SLOT(slotCurrentChanged(QListViewItem*)));
+}
+
+CameraFolderView::~CameraFolderView()
+{
+ delete d;
+}
+
+void CameraFolderView::addVirtualFolder(const QString& name, const QPixmap& 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 QString& folder, int nbItems, const QPixmap& pixmap)
+{
+ d->rootFolder = new CameraFolderItem(d->virtualFolder, folder, folder, pixmap);
+ d->rootFolder->setOpen(true);
+ d->rootFolder->setCount(nbItems);
+}
+
+CameraFolderItem* CameraFolderView::addFolder(const QString& folder, const QString& subFolder,
+ int nbItems, const QPixmap& pixmap)
+{
+ CameraFolderItem *parentItem = findFolder(folder);
+
+ DDebug() << "CameraFolderView: Adding Subfolder " << subFolder
+ << " of folder " << folder << endl;
+
+ if (parentItem)
+ {
+ QString 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 QString& folderPath)
+{
+
+ QListViewItemIterator it(this);
+ for ( ; it.current(); ++it)
+ {
+ CameraFolderItem* item = static_cast<CameraFolderItem*>(it.current());
+
+ if (item->folderPath() == folderPath)
+ return item;
+ }
+
+ return 0;
+}
+
+void CameraFolderView::slotCurrentChanged(QListViewItem* 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()
+{
+ QListView::clear();
+ d->virtualFolder = 0;
+ d->rootFolder = 0;
+ emit signalCleared();
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/cameragui/camerafolderview.h b/digikam/utilities/cameragui/camerafolderview.h
new file mode 100644
index 0000000..8687e99
--- /dev/null
+++ b/digikam/utilities/cameragui/camerafolderview.h
@@ -0,0 +1,82 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qlistview.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+
+namespace Digikam
+{
+
+class CameraFolderItem;
+class CameraFolderViewPriv;
+
+class CameraFolderView : public QListView
+{
+ Q_OBJECT
+
+public:
+
+ CameraFolderView(QWidget* parent);
+ ~CameraFolderView();
+
+ void addVirtualFolder(const QString& name, const QPixmap& pixmap=SmallIcon("camera"));
+ void addRootFolder(const QString& folder, int nbItems, const QPixmap& pixmap=SmallIcon("folder"));
+
+ CameraFolderItem* addFolder(const QString& folder, const QString& subFolder, int nbItems,
+ const QPixmap& pixmap=SmallIcon("folder"));
+
+ CameraFolderItem* findFolder(const QString& folderPath);
+
+ CameraFolderItem* virtualFolder();
+ CameraFolderItem* rootFolder();
+
+ virtual void clear();
+
+signals:
+
+ void signalFolderChanged(CameraFolderItem*);
+ void signalCleared();
+
+private slots:
+
+ void slotCurrentChanged(QListViewItem*);
+
+private:
+
+ CameraFolderViewPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAFOLDERVIEW_H */
diff --git a/digikam/utilities/cameragui/cameraiconitem.cpp b/digikam/utilities/cameragui/cameraiconitem.cpp
new file mode 100644
index 0000000..c7cd180
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qpainter.h>
+#include <qpixmap.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;
+ }
+
+ QString downloadName;
+
+ QPixmap pixmap;
+ QPixmap thumbnail;
+
+ QRect pixRect;
+ QRect textRect;
+ QRect extraRect;
+
+ GPItemInfo *itemInfo;
+};
+
+CameraIconViewItem::CameraIconViewItem(IconGroupItem* parent, const GPItemInfo& itemInfo,
+ const QImage& thumbnail, const QString& 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 QImage& thumbnail)
+{
+ d->thumbnail = QPixmap(thumbnail);
+}
+
+GPItemInfo* CameraIconViewItem::itemInfo() const
+{
+ return d->itemInfo;
+}
+
+void CameraIconViewItem::paintItem()
+{
+ CameraIconView* view = (CameraIconView*)iconView();
+ QFont fn(view->font());
+
+ QPixmap pix;
+ QRect r(rect());
+
+ if (isSelected())
+ pix = *(view->itemBaseSelPixmap());
+ else
+ pix = *(view->itemBaseRegPixmap());
+
+ ThemeEngine* te = ThemeEngine::instance();
+
+ QPainter p(&pix);
+
+ QString itemName = AlbumIconItem::squeezedText(&p, r.width()-5, d->itemInfo->name);
+ QString 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, Qt::AlignHCenter|Qt::AlignTop, itemName);
+
+ if (!d->downloadName.isEmpty())
+ {
+ if (fn.pointSize() > 0)
+ fn.setPointSize(QMAX(fn.pointSize()-2, 6));
+
+ p.setFont(fn);
+ p.setPen(isSelected() ? te->textSpecialSelColor() : te->textSpecialRegColor());
+ p.drawText(d->extraRect, Qt::AlignHCenter|Qt::AlignTop, downloadName);
+ }
+
+ if (this == iconView()->currentItem())
+ {
+ p.setPen(QPen(isSelected() ? Qt::white : Qt::black, 1, Qt::DotLine));
+ p.drawRect(0, 0, r.width(), r.height());
+ }
+
+ // Draw download status icon.
+ QPixmap downloaded;
+
+ switch (d->itemInfo->downloaded)
+ {
+ case GPItemInfo::NewPicture:
+ {
+ downloaded = QPixmap(view->newPicturePixmap());
+ break;
+ }
+ case GPItemInfo::DownloadedYes:
+ {
+ downloaded = SmallIcon( "button_ok" );
+ break;
+ }
+ case GPItemInfo::DownloadStarted:
+ {
+ downloaded = SmallIcon( "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 = QRect(view->contentsToViewport(QPoint(r.x(), r.y())),
+ QSize(r.width(), r.height()));
+
+ bitBlt(view->viewport(), r.x(), r.y(), &pix);
+}
+
+void CameraIconViewItem::setDownloadName(const QString& downloadName)
+{
+ d->downloadName = downloadName;
+ repaint();
+}
+
+QString 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 QString& itemName, const QString& downloadName)
+{
+ CameraIconView* view = (CameraIconView*)iconView();
+ int thumbSize = view->thumbnailSize().size();
+ d->pixmap = QPixmap(d->thumbnail.convertToImage().smoothScale(thumbSize, thumbSize, QImage::ScaleMin));
+ d->pixRect = QRect(0,0,0,0);
+ d->textRect = QRect(0,0,0,0);
+ d->extraRect = QRect(0,0,0,0);
+ QRect itemRect = rect();
+ itemRect.moveTopLeft(QPoint(0, 0));
+
+ d->pixRect.setWidth(thumbSize);
+ d->pixRect.setHeight(thumbSize);
+
+ QFontMetrics fm(iconView()->font());
+ QRect r = QRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ Qt::AlignHCenter | Qt::AlignTop,
+ itemName));
+ d->textRect.setWidth(r.width());
+ d->textRect.setHeight(r.height());
+
+ if (!d->downloadName.isEmpty())
+ {
+ QFont fn(iconView()->font());
+ if (fn.pointSize() > 0)
+ {
+ fn.setPointSize(QMAX(fn.pointSize()-2, 6));
+ }
+
+ fm = QFontMetrics(fn);
+ r = QRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ Qt::AlignHCenter | Qt::WordBreak,
+ downloadName));
+ d->extraRect.setWidth(r.width());
+ d->extraRect.setHeight(r.height());
+
+ d->textRect.setWidth(QMAX(d->textRect.width(), d->extraRect.width()));
+ d->textRect.setHeight(d->textRect.height() + d->extraRect.height());
+ }
+
+ int w = QMAX(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 = QRect(2, 2, d->pixRect.width(), d->pixRect.height());
+ d->textRect = QRect((itemRect.width() - d->textRect.width())/2,
+ itemRect.height() - d->textRect.height(),
+ d->textRect.width(), d->textRect.height());
+
+ if (!d->extraRect.isEmpty())
+ {
+ d->extraRect = QRect((itemRect.width() - d->extraRect.width())/2,
+ itemRect.height() - d->extraRect.height(),
+ d->extraRect.width(), d->extraRect.height());
+ }
+}
+
+QRect CameraIconViewItem::clickToOpenRect()
+{
+ QRect r(rect());
+
+ if (d->pixmap.isNull())
+ {
+ QRect pixRect(d->pixRect);
+ pixRect.moveBy(r.x(), r.y());
+ return pixRect;
+ }
+
+ QRect 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/digikam/utilities/cameragui/cameraiconitem.h b/digikam/utilities/cameragui/cameraiconitem.h
new file mode 100644
index 0000000..7d03d86
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qimage.h>
+
+// Local includes.
+
+#include "iconitem.h"
+
+namespace Digikam
+{
+
+class GPItemInfo;
+class CameraIconViewItemPriv;
+
+class CameraIconViewItem : public IconItem
+{
+
+public:
+
+ CameraIconViewItem(IconGroupItem* parent, const GPItemInfo& itemInfo,
+ const QImage& thumbnail, const QString& downloadName=QString());
+ ~CameraIconViewItem();
+
+ void setThumbnail(const QImage& thumbnail);
+
+ void setDownloadName(const QString& downloadName);
+ QString getDownloadName() const;
+ void setDownloaded(int status);
+ bool isDownloaded() const;
+
+ void toggleLock();
+
+ GPItemInfo* itemInfo() const;
+
+ // reimplemented from IconItem
+ virtual QRect clickToOpenRect();
+
+protected:
+
+ virtual void paintItem();
+
+private:
+
+ void calcRect(const QString& itemName, const QString& downloadName);
+
+private:
+
+ CameraIconViewItemPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAICONITEM_H */
diff --git a/digikam/utilities/cameragui/cameraiconview.cpp b/digikam/utilities/cameragui/cameraiconview.cpp
new file mode 100644
index 0000000..b1e8e6c
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qtimer.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qcursor.h>
+#include <qfontmetrics.h>
+#include <qfont.h>
+#include <qdragobject.h>
+#include <qclipboard.h>
+
+// KDE includes.
+
+#include <kurldrag.h>
+#include <kmimetype.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kaction.h>
+#include <kapplication.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 = QPixmap(newPicture_xpm);
+ pixmapUnknowPicture = QPixmap(unknowPicture_xpm);
+ }
+
+ static const char *newPicture_xpm[];
+ static const char *unknowPicture_xpm[];
+
+ QDict<CameraIconViewItem> itemDict;
+
+ QRect itemRect;
+
+ QPixmap itemRegPixmap;
+ QPixmap itemSelPixmap;
+ QPixmap pixmapNewPicture;
+ QPixmap 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, QWidget* parent)
+ : IconView(parent)
+{
+ d = new CameraIconViewPriv;
+ d->cameraUI = ui;
+ d->groupItem = new IconGroupItem(this);
+
+ setHScrollBarMode(QScrollView::AlwaysOff);
+ setMinimumSize(400, 300);
+
+ setAcceptDrops(true);
+ viewport()->setAcceptDrops(true);
+
+ // ----------------------------------------------------------------
+
+ connect(this, SIGNAL(signalSelectionChanged()),
+ this, SLOT(slotSelectionChanged()));
+
+ connect(this, SIGNAL(signalNewSelection(bool)),
+ this, SLOT(slotUpdateDownloadNames(bool)));
+
+ connect(this, SIGNAL(signalRightButtonClicked(IconItem*, const QPoint&)),
+ this, SLOT(slotContextMenu(IconItem*, const QPoint&)));
+
+ connect(this, SIGNAL(signalRightButtonClicked(const QPoint &)),
+ this, SLOT(slotRightButtonClicked(const QPoint &)));
+
+ connect(this, SIGNAL(signalDoubleClicked(IconItem*)),
+ this, SLOT(slotDoubleClicked(IconItem*)));
+
+ connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
+ this, SLOT(slotThemeChanged()));
+
+ // ----------------------------------------------------------------
+
+ updateItemRectsPixmap();
+ slotThemeChanged();
+}
+
+CameraIconView::~CameraIconView()
+{
+ clear();
+ delete d;
+}
+
+QPixmap* CameraIconView::itemBaseRegPixmap() const
+{
+ return &d->itemRegPixmap;
+}
+
+QPixmap* CameraIconView::itemBaseSelPixmap() const
+{
+ return &d->itemSelPixmap;
+}
+
+QPixmap CameraIconView::newPicturePixmap() const
+{
+ return d->pixmapNewPicture;
+}
+
+QPixmap CameraIconView::unknowPicturePixmap() const
+{
+ return d->pixmapUnknowPicture;
+}
+
+void CameraIconView::setRenameCustomizer(RenameCustomizer* renamer)
+{
+ d->renamer = renamer;
+
+ connect(d->renamer, SIGNAL(signalChanged()),
+ this, SLOT(slotDownloadNameChanged()));
+}
+
+void CameraIconView::addItem(const GPItemInfo& info)
+{
+ QImage thumb;
+ // Just to have a generic image thumb from desktop with KDE < 3.5.0
+ KMimeType::Ptr mime = KMimeType::mimeType(info.mime == QString("image/x-raw") ?
+ QString("image/tiff") : info.mime);
+
+ if (mime)
+ {
+ thumb = QImage(mime->pixmap(KIcon::Desktop, ThumbnailSize::Huge, KIcon::DefaultState)
+ .convertToImage());
+ }
+ else
+ {
+ KIconLoader *iconLoader = KApplication::kApplication()->iconLoader();
+ thumb = iconLoader->loadIcon("empty", KIcon::Desktop,
+ ThumbnailSize::Huge, KIcon::DefaultState, 0, true)
+ .convertToImage();
+ }
+
+ QString 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 QString& folder, const QString& 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 QString& folder, const QString& file)
+{
+ return d->itemDict.find(folder+file);
+}
+
+int CameraIconView::countItemsByFolder(QString 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);
+ QString itemFolder = iconItem->itemInfo()->folder;
+ if (itemFolder.endsWith("/")) itemFolder.truncate(itemFolder.length()-1);
+
+ if (folder == itemFolder)
+ count++;
+ }
+
+ return count;
+}
+
+void CameraIconView::setThumbnail(const QString& folder, const QString& filename, const QImage& 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 QString& folder, const QString& 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();
+ QString 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())
+ {
+ QString 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())
+ {
+ QFileInfo fi(downloadName);
+ QString ext = fi.extension(false).upper();
+ if (ext == QString("JPEG") || ext == QString("JPG") || ext == QString("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())
+ {
+ QString downloadName;
+ CameraIconViewItem* viewItem = static_cast<CameraIconViewItem*>(item);
+
+ if (!useDefault)
+ downloadName = getTemplatedName( viewItem->itemInfo(), startIndex );
+ else
+ downloadName = getCasedName( d->renamer->changeCase(), viewItem->itemInfo() );
+
+ if (convertLossLessJpeg)
+ {
+ QFileInfo fi(downloadName);
+ QString ext = fi.extension(false).upper();
+ if (ext == QString("JPEG") || ext == QString("JPG") || ext == QString("JPE"))
+ {
+ downloadName.truncate(downloadName.length() - ext.length());
+ downloadName.append(losslessFormat.lower());
+ }
+ }
+
+ viewItem->setDownloadName( downloadName );
+ startIndex++;
+ }
+ }
+
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+}
+
+QString CameraIconView::defaultDownloadName(CameraIconViewItem *viewItem)
+{
+ RenameCustomizer::Case renamecase = RenameCustomizer::NONE;
+ if (d->renamer)
+ renamecase = d->renamer->changeCase();
+
+ return getCasedName( renamecase, viewItem->itemInfo() );
+}
+
+QString CameraIconView::getTemplatedName(const GPItemInfo* itemInfo, int position)
+{
+ QString ext = itemInfo->name;
+ int pos = ext.findRev('.');
+ if (pos < 0)
+ ext = "";
+ else
+ ext = ext.right( ext.length() - pos );
+
+ QDateTime mtime;
+ mtime.setTime_t(itemInfo->mtime);
+
+ return d->renamer->newName(mtime, position+1, ext);
+}
+
+QString CameraIconView::getCasedName(const RenameCustomizer::Case ccase,
+ const GPItemInfo* itemInfo)
+{
+ QString 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 QPoint&)
+{
+ 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("down"),i18n("Download"), 1);
+ menu.insertItem(SmallIcon("down"),i18n("Download && Delete"), 4);
+ menu.insertItem(SmallIcon("encrypted"), i18n("Toggle lock"), 3);
+ menu.insertSeparator(-1);
+ menu.insertItem(SmallIcon("editdelete"), i18n("Delete"), 2);
+
+ int result = menu.exec(QCursor::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()
+{
+ QStringList lst;
+
+ for (IconItem* item = firstItem(); item; item = item->nextItem())
+ {
+ if (!item->isSelected())
+ continue;
+
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ QString itemPath = iconItem->itemInfo()->folder + iconItem->itemInfo()->name;
+ lst.append(itemPath);
+ }
+
+ QDragObject * drag = new CameraItemListDrag(lst, d->cameraUI);
+ if (drag)
+ {
+ QPixmap icon(DesktopIcon("image", 48));
+ int w = icon.width();
+ int h = icon.height();
+
+ QPixmap pix(w+4,h+4);
+ QString text(QString::number(lst.count()));
+
+ QPainter p(&pix);
+ p.fillRect(0, 0, w+4, h+4, QColor(Qt::white));
+ p.setPen(QPen(Qt::black, 1));
+ p.drawRect(0, 0, w+4, h+4);
+ p.drawPixmap(2, 2, icon);
+ QRect r = p.boundingRect(2,2,w,h,Qt::AlignLeft|Qt::AlignTop,text);
+ r.setWidth(QMAX(r.width(),r.height()));
+ r.setHeight(QMAX(r.width(),r.height()));
+ p.fillRect(r, QColor(0,80,0));
+ p.setPen(Qt::white);
+ QFont f(font());
+ f.setBold(true);
+ p.setFont(f);
+ p.drawText(r, Qt::AlignCenter, text);
+ p.end();
+
+ drag->setPixmap(pix);
+ drag->drag();
+ }
+}
+
+void CameraIconView::contentsDropEvent(QDropEvent *event)
+{
+ // don't popup context menu if the camera is busy
+ if (d->cameraUI->isBusy())
+ return;
+
+ if ( (!QUriDrag::canDecode(event) && !CameraDragObject::canDecode(event) )
+ || event->source() == this)
+ {
+ event->ignore();
+ return;
+ }
+
+ KURL::List srcURLs;
+ KURLDrag::decode(event, srcURLs);
+ uploadItemPopupMenu(srcURLs);
+}
+
+void CameraIconView::slotRightButtonClicked(const QPoint&)
+{
+ // don't popup context menu if the camera is busy
+ if (d->cameraUI->isBusy())
+ return;
+
+ QMimeSource *data = kapp->clipboard()->data(QClipboard::Clipboard);
+ if(!data || !QUriDrag::canDecode(data))
+ return;
+
+ KURL::List srcURLs;
+ KURLDrag::decode(data, srcURLs);
+ uploadItemPopupMenu(srcURLs);
+}
+
+void CameraIconView::uploadItemPopupMenu(const KURL::List& srcURLs)
+{
+ KPopupMenu 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(QCursor::pos());
+ switch(id)
+ {
+ case 10:
+ {
+ emit signalUpload(srcURLs);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+QRect 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();
+
+ QRect pixRect;
+ QRect textRect;
+ QRect extraRect;
+
+ pixRect.setWidth(thumbSize);
+ pixRect.setHeight(thumbSize);
+
+ QFontMetrics fm(font());
+ QRect r = QRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ Qt::AlignHCenter | Qt::AlignTop,
+ "XXXXXXXXX"));
+ textRect.setWidth(r.width());
+ textRect.setHeight(r.height());
+
+ QFont fn(font());
+ if (fn.pointSize() > 0)
+ {
+ fn.setPointSize(QMAX(fn.pointSize()-2, 6));
+ }
+
+ fm = QFontMetrics(fn);
+ r = QRect(fm.boundingRect(0, 0, thumbSize, 0xFFFFFFFF,
+ Qt::AlignHCenter | Qt::AlignTop,
+ "XXXXXXXXX"));
+ extraRect.setWidth(r.width());
+ extraRect.setHeight(r.height());
+
+ r = QRect();
+ r.setWidth(QMAX(QMAX(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 == QString("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/digikam/utilities/cameragui/cameraiconview.h b/digikam/utilities/cameragui/cameraiconview.h
new file mode 100644
index 0000000..733023e
--- /dev/null
+++ b/digikam/utilities/cameragui/cameraiconview.h
@@ -0,0 +1,140 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qdict.h>
+#include <qrect.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "iconview.h"
+#include "renamecustomizer.h"
+
+class QPixmap;
+
+namespace Digikam
+{
+
+class ThumbnailSize;
+class GPItemInfo;
+class RenameCustomizer;
+class CameraUI;
+class CameraIconViewItem;
+class CameraIconViewPriv;
+
+class CameraIconView : public IconView
+{
+ Q_OBJECT
+
+public:
+
+ CameraIconView(CameraUI* ui, QWidget* parent);
+ ~CameraIconView();
+
+ void setRenameCustomizer(RenameCustomizer* renamer);
+
+ void addItem(const GPItemInfo& itemInfo);
+ void removeItem(const QString& folder, const QString& file);
+ void setThumbnail(const QString& folder, const QString& filename, const QImage& image);
+
+ void ensureItemVisible(CameraIconViewItem *item);
+ void ensureItemVisible(const GPItemInfo& itemInfo);
+ void ensureItemVisible(const QString& folder, const QString& file);
+
+ void setThumbnailSize(const ThumbnailSize& thumbSize);
+ ThumbnailSize thumbnailSize() const;
+
+ CameraIconViewItem* findItem(const QString& folder, const QString& file);
+
+ int countItemsByFolder(QString folder);
+ int itemsDownloaded();
+
+ QPixmap* itemBaseRegPixmap() const;
+ QPixmap* itemBaseSelPixmap() const;
+ QPixmap newPicturePixmap() const;
+ QPixmap unknowPicturePixmap() const;
+
+ virtual QRect itemRect() const;
+
+ QString 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 QPoint& pos);
+ void slotContextMenu(IconItem* item, const QPoint& pos);
+ void slotDoubleClicked(IconItem* item);
+ void slotThemeChanged();
+ void slotUpdateDownloadNames(bool hasSelection);
+
+protected:
+
+ void startDrag();
+ void contentsDropEvent(QDropEvent *event);
+ void updateItemRectsPixmap();
+
+private:
+
+ QString getTemplatedName(const GPItemInfo* itemInfo, int position);
+ QString 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/digikam/utilities/cameragui/camerainfodialog.cpp b/digikam/utilities/cameragui/camerainfodialog.cpp
new file mode 100644
index 0000000..f7453e9
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qframe.h>
+#include <qtextedit.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+
+// Local includes.
+
+#include "camerainfodialog.h"
+
+namespace Digikam
+{
+
+CameraInfoDialog::CameraInfoDialog(QWidget *parent, const QString& summary, const QString& manual,
+ const QString& about)
+ : KDialogBase(IconList, i18n("Camera Information"), Help|Ok, Ok, parent, 0, true, true)
+{
+ setHelp("digitalstillcamera.anchor", "digikam");
+ resize(500, 400);
+
+ // ----------------------------------------------------------
+
+ QFrame *p1 = addPage( i18n("Summary"), i18n("Camera Summary"), BarIcon("contents2", KIcon::SizeMedium) );
+ QVBoxLayout *p1layout = new QVBoxLayout( p1, 0, 6 );
+
+ QTextEdit *summaryView = new QTextEdit(summary, QString(), p1);
+ summaryView->setWordWrap(QTextEdit::WidgetWidth);
+ summaryView->setReadOnly(true);
+ p1layout->addWidget(summaryView);
+
+ // ----------------------------------------------------------
+
+ QFrame *p2 = addPage( i18n("Manual"), i18n("Camera Manual"), BarIcon("contents", KIcon::SizeMedium) );
+ QVBoxLayout *p2layout = new QVBoxLayout( p2, 0, 6 );
+
+ QTextEdit *manualView = new QTextEdit(manual, QString(), p2);
+ manualView->setWordWrap(QTextEdit::WidgetWidth);
+ manualView->setReadOnly(true);
+ p2layout->addWidget(manualView);
+
+ // ----------------------------------------------------------
+
+ QFrame *p3 = addPage( i18n("About"), i18n("About Driver"), BarIcon("camera", KIcon::SizeMedium) );
+ QVBoxLayout *p3layout = new QVBoxLayout( p3, 0, 6 );
+
+ QTextEdit *aboutView = new QTextEdit(about, QString(), p3);
+ aboutView->setWordWrap(QTextEdit::WidgetWidth);
+ aboutView->setReadOnly(true);
+ p3layout->addWidget(aboutView);
+}
+
+CameraInfoDialog::~CameraInfoDialog()
+{
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/cameragui/camerainfodialog.h b/digikam/utilities/cameragui/camerainfodialog.h
new file mode 100644
index 0000000..889d880
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+namespace Digikam
+{
+
+class CameraInfoDialog : public KDialogBase
+{
+public:
+
+ CameraInfoDialog(QWidget *parent, const QString& summary, const QString& manual,
+ const QString& about);
+ ~CameraInfoDialog();
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAINFODIALOG_H */
diff --git a/digikam/utilities/cameragui/cameraui.cpp b/digikam/utilities/cameragui/cameraui.cpp
new file mode 100644
index 0000000..8b41f1f
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qvgroupbox.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qtoolbutton.h>
+#include <qiconview.h>
+#include <qvbox.h>
+#include <qhbox.h>
+#include <qpopupmenu.h>
+#include <qsplitter.h>
+#include <qpixmap.h>
+#include <qcombobox.h>
+#include <qtoolbox.h>
+#include <qframe.h>
+#include <qvbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qtooltip.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <kfiledialog.h>
+#include <kimageio.h>
+#include <kaboutdata.h>
+#include <kmessagebox.h>
+#include <kprogress.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kpopupmenu.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;
+
+ QString cameraTitle;
+
+ QStringList currentlyDeleting;
+ QStringList foldersToScan;
+ QStringList cameraFolderList;
+
+ QPopupMenu *downloadMenu;
+ QPopupMenu *deleteMenu;
+ QPopupMenu *imageMenu;
+
+ QToolButton *cancelBtn;
+
+ QToolBox *advBox;
+
+ QCheckBox *autoRotateCheck;
+ QCheckBox *autoAlbumDateCheck;
+ QCheckBox *autoAlbumExtCheck;
+ QCheckBox *fixDateTimeCheck;
+ QCheckBox *setPhotographerId;
+ QCheckBox *setCredits;
+ QCheckBox *convertJpegCheck;
+
+ QLabel *formatLabel;
+ QLabel *folderDateLabel;
+
+ QComboBox *losslessFormat;
+ QComboBox *folderDateFormat;
+
+ QSplitter *splitter;
+
+ QDateTime 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(QWidget* /*parent*/, const QString& cameraTitle,
+ const QString& model, const QString& port,
+ const QString& path, const QDateTime 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");
+
+ // -------------------------------------------------------------------------
+
+ QGridLayout* viewBoxLayout = new QGridLayout(plainPage(), 2, 7);
+
+ QHBox* widget = new QHBox(plainPage());
+ d->splitter = new QSplitter(widget);
+ d->view = new CameraIconView(this, d->splitter);
+
+ QSizePolicy rightSzPolicy(QSizePolicy::Preferred, QSizePolicy::Expanding, 2, 1);
+ d->view->setSizePolicy(rightSzPolicy);
+
+ d->rightSidebar = new ImagePropertiesSideBarCamGui(widget, "CameraGui Sidebar Right", d->splitter,
+ Sidebar::Right, true);
+ d->splitter->setFrameStyle( QFrame::NoFrame );
+ d->splitter->setFrameShadow( QFrame::Plain );
+ d->splitter->setFrameShape( QFrame::NoFrame );
+ d->splitter->setOpaqueResize(false);
+
+ // -------------------------------------------------------------------------
+
+ d->advBox = new QToolBox(d->rightSidebar);
+ d->renameCustomizer = new RenameCustomizer(d->advBox, d->cameraTitle);
+ d->view->setRenameCustomizer(d->renameCustomizer);
+
+ QWhatsThis::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 -----------------------------------------
+
+ QWidget* albumBox = new QWidget(d->advBox);
+ QVBoxLayout* albumVlay = new QVBoxLayout(albumBox, marginHint(), spacingHint());
+ d->autoAlbumExtCheck = new QCheckBox(i18n("Extension-based sub-albums"), albumBox);
+ d->autoAlbumDateCheck = new QCheckBox(i18n("Date-based sub-albums"), albumBox);
+ QHBox *hbox1 = new QHBox(albumBox);
+ d->folderDateLabel = new QLabel(i18n("Date format:"), hbox1);
+ d->folderDateFormat = new QComboBox(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();
+
+ QWhatsThis::add( albumBox, i18n("<p>Set how digiKam creates albums automatically when downloading."));
+ QWhatsThis::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."));
+ QWhatsThis::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."));
+ QWhatsThis::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 KDE control panel settings.<p>"));
+
+ d->advBox->insertItem(CameraUIPriv::AUTOALBUMPAGE, albumBox, SmallIconSet("folder_new"),
+ i18n("Auto-creation of Albums"));
+
+ // -- On the Fly options ---------------------------------------------------
+
+ QWidget* onFlyBox = new QWidget(d->advBox);
+ QVBoxLayout* onFlyVlay = new QVBoxLayout(onFlyBox, marginHint(), spacingHint());
+ d->setPhotographerId = new QCheckBox(i18n("Set default photographer identity"), onFlyBox);
+ d->setCredits = new QCheckBox(i18n("Set default credit and copyright"), onFlyBox);
+ d->fixDateTimeCheck = new QCheckBox(i18n("Fix internal date && time"), onFlyBox);
+ d->dateTimeEdit = new KDateTimeEdit(onFlyBox, "datepicker");
+ d->autoRotateCheck = new QCheckBox(i18n("Auto-rotate/flip image"), onFlyBox);
+ d->convertJpegCheck = new QCheckBox(i18n("Convert to lossless file format"), onFlyBox);
+ QHBox *hbox2 = new QHBox(onFlyBox);
+ d->formatLabel = new QLabel(i18n("New image format:"), hbox2);
+ d->losslessFormat = new QComboBox(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();
+
+ QWhatsThis::add( onFlyBox, i18n("<p>Set here all options to fix/transform JPEG files automatically "
+ "as they are downloaded."));
+ QWhatsThis::add( d->autoRotateCheck, i18n("<p>Enable this option if you want images automatically "
+ "rotated or flipped using EXIF information provided by the camera."));
+ QWhatsThis::add( d->setPhotographerId, i18n("<p>Enable this option to store the default "
+ "photographer identity in the IPTC tags using digiKam's metadata settings."));
+ QWhatsThis::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."));
+ QWhatsThis::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."));
+ QWhatsThis::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."));
+ QWhatsThis::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("run"),
+ i18n("On the Fly Operations (JPEG only)"));
+
+ d->rightSidebar->appendTab(d->advBox, SmallIcon("configure"), i18n("Settings"));
+ d->rightSidebar->loadViewState();
+
+ // -------------------------------------------------------------------------
+
+ d->cancelBtn = new QToolButton(plainPage());
+ d->cancelBtn->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::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();
+
+ QWidget *frame = new QWidget(plainPage());
+ QHBoxLayout* layout = new QHBoxLayout(frame);
+ frame->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
+
+ KURLLabel *pixmapLogo = new KURLLabel( Digikam::webProjectUrl(), QString(), frame );
+ pixmapLogo->setMargin(0);
+ pixmapLogo->setScaledContents( false );
+ pixmapLogo->setSizePolicy(QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum));
+ QToolTip::add(pixmapLogo, i18n("Visit digiKam project website"));
+ KGlobal::dirs()->addResourceType("logo-digikam", KGlobal::dirs()->kde_default("data") + "digikam/data");
+ QString directory = KGlobal::dirs()->findResourceDir("logo-digikam", "logo-digikam.png");
+ pixmapLogo->setPixmap( QPixmap( directory + "logo-digikam.png" ) );
+ pixmapLogo->setFocusPolicy(QWidget::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 QPopupMenu(this);
+ d->imageMenu->insertItem(i18n("Select &All"), d->view, SLOT(slotSelectAll()), CTRL+Key_A, 0);
+ d->imageMenu->insertItem(i18n("Select N&one"), d->view, SLOT(slotSelectNone()), CTRL+Key_U, 1);
+ d->imageMenu->insertItem(i18n("&Invert Selection"), d->view, SLOT(slotSelectInvert()), CTRL+Key_Asterisk, 2);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Select &New Items"), d->view, SLOT(slotSelectNew()), 0, 3);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Increase Thumbnail Size"), this, SLOT(slotIncreaseThumbSize()), CTRL+Key_Plus, 4);
+ d->imageMenu->insertItem(i18n("Decrease Thumbnail Size"), this, SLOT(slotDecreaseThumbSize()), CTRL+Key_Minus, 5);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Toggle Lock"), this, SLOT(slotToggleLock()), 0, 6);
+ actionButton(User3)->setPopup(d->imageMenu);
+
+ // -------------------------------------------------------------------------
+
+ d->downloadMenu = new QPopupMenu(this);
+ d->downloadMenu->insertItem(i18n("Download Selected"),
+ this, SLOT(slotDownloadSelected()), 0, 0);
+ d->downloadMenu->insertItem(i18n("Download All"),
+ this, SLOT(slotDownloadAll()), 0, 1);
+ d->downloadMenu->insertSeparator();
+ d->downloadMenu->insertItem(i18n("Download/Delete Selected"),
+ this, SLOT(slotDownloadAndDeleteSelected()), 0, 2);
+ d->downloadMenu->insertItem(i18n("Download/Delete All"),
+ this, SLOT(slotDownloadAndDeleteAll()), 0, 3);
+ d->downloadMenu->insertSeparator();
+ d->downloadMenu->insertItem(i18n("Upload..."),
+ this, SLOT(slotUpload()), 0, 4);
+ d->downloadMenu->setItemEnabled(0, false);
+ d->downloadMenu->setItemEnabled(2, false);
+ actionButton(User2)->setPopup(d->downloadMenu);
+
+ // -------------------------------------------------------------------------
+
+ d->deleteMenu = new QPopupMenu(this);
+ d->deleteMenu->insertItem(i18n("Delete Selected"), this, SLOT(slotDeleteSelected()), 0, 0);
+ d->deleteMenu->insertItem(i18n("Delete All"), this, SLOT(slotDeleteAll()), 0, 1);
+ d->deleteMenu->setItemEnabled(0, false);
+ actionButton(User1)->setPopup(d->deleteMenu);
+
+ // -------------------------------------------------------------------------
+
+ QPushButton *helpButton = actionButton( Help );
+ d->helpMenu = new KHelpMenu(this, kapp->aboutData(), false);
+ d->helpMenu->menu()->insertItem(SmallIcon("camera"), i18n("Camera Information"),
+ this, SLOT(slotInformations()), 0, CAMERA_INFO_MENU_ID, 0);
+ helpButton->setPopup( d->helpMenu->menu() );
+
+ // -------------------------------------------------------------------------
+
+ connect(d->autoAlbumDateCheck, SIGNAL(toggled(bool)),
+ d->folderDateFormat, SLOT(setEnabled(bool)));
+
+ connect(d->autoAlbumDateCheck, SIGNAL(toggled(bool)),
+ d->folderDateLabel, SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, SIGNAL(toggled(bool)),
+ d->losslessFormat, SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, SIGNAL(toggled(bool)),
+ d->formatLabel, SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, SIGNAL(toggled(bool)),
+ d->view, SLOT(slotDownloadNameChanged()));
+
+ connect(d->fixDateTimeCheck, SIGNAL(toggled(bool)),
+ d->dateTimeEdit, SLOT(setEnabled(bool)));
+
+ connect(pixmapLogo, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(slotProcessURL(const QString&)));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->view, SIGNAL(signalSelected(CameraIconViewItem*, bool)),
+ this, SLOT(slotItemsSelected(CameraIconViewItem*, bool)));
+
+ connect(d->view, SIGNAL(signalFileView(CameraIconViewItem*)),
+ this, SLOT(slotFileView(CameraIconViewItem*)));
+
+ connect(d->view, SIGNAL(signalUpload(const KURL::List&)),
+ this, SLOT(slotUploadItems(const KURL::List&)));
+
+ connect(d->view, SIGNAL(signalDownload()),
+ this, SLOT(slotDownloadSelected()));
+
+ connect(d->view, SIGNAL(signalDownloadAndDelete()),
+ this, SLOT(slotDownloadAndDeleteSelected()));
+
+ connect(d->view, SIGNAL(signalDelete()),
+ this, SLOT(slotDeleteSelected()));
+
+ connect(d->view, SIGNAL(signalToggleLock()),
+ this, SLOT(slotToggleLock()));
+
+ connect(d->view, SIGNAL(signalNewSelection(bool)),
+ this, SLOT(slotNewSelection(bool)));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->rightSidebar, SIGNAL(signalFirstItem()),
+ this, SLOT(slotFirstItem()));
+
+ connect(d->rightSidebar, SIGNAL(signalNextItem()),
+ this, SLOT(slotNextItem()));
+
+ connect(d->rightSidebar, SIGNAL(signalPrevItem()),
+ this, SLOT(slotPrevItem()));
+
+ connect(d->rightSidebar, SIGNAL(signalLastItem()),
+ this, SLOT(slotLastItem()));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->cancelBtn, SIGNAL(clicked()),
+ this, 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, SIGNAL(signalConnected(bool)),
+ this, SLOT(slotConnected(bool)));
+
+ connect(d->controller, SIGNAL(signalInfoMsg(const QString&)),
+ d->status, SLOT(setText(const QString&)));
+
+ connect(d->controller, SIGNAL(signalErrorMsg(const QString&)),
+ this, SLOT(slotErrorMsg(const QString&)));
+
+ connect(d->controller, SIGNAL(signalCameraInformations(const QString&, const QString&, const QString&)),
+ this, SLOT(slotCameraInformations(const QString&, const QString&, const QString&)));
+
+ connect(d->controller, SIGNAL(signalBusy(bool)),
+ this, SLOT(slotBusy(bool)));
+
+ connect(d->controller, SIGNAL(signalFolderList(const QStringList&)),
+ this, SLOT(slotFolderList(const QStringList&)));
+
+ connect(d->controller, SIGNAL(signalFileList(const GPItemInfoList&)),
+ this, SLOT(slotFileList(const GPItemInfoList&)));
+
+ connect(d->controller, SIGNAL(signalThumbnail(const QString&, const QString&, const QImage&)),
+ this, SLOT(slotThumbnail(const QString&, const QString&, const QImage&)));
+
+ connect(d->controller, SIGNAL(signalDownloaded(const QString&, const QString&, int)),
+ this, SLOT(slotDownloaded(const QString&, const QString&, int)));
+
+ connect(d->controller, SIGNAL(signalSkipped(const QString&, const QString&)),
+ this, SLOT(slotSkipped(const QString&, const QString&)));
+
+ connect(d->controller, SIGNAL(signalDeleted(const QString&, const QString&, bool)),
+ this, SLOT(slotDeleted(const QString&, const QString&, bool)));
+
+ connect(d->controller, SIGNAL(signalLocked(const QString&, const QString&, bool)),
+ this, SLOT(slotLocked(const QString&, const QString&, bool)));
+
+ connect(d->controller, SIGNAL(signalExifFromFile(const QString&, const QString&)),
+ this, SLOT(slotExifFromFile(const QString&, const QString&)));
+
+ connect(d->controller, SIGNAL(signalExifData(const QByteArray&)),
+ this, SLOT(slotExifFromData(const QByteArray&)));
+
+ connect(d->controller, SIGNAL(signalUploaded(const GPItemInfo&)),
+ this, SLOT(slotUploaded(const GPItemInfo&)));
+
+ // -------------------------------------------------------------------------
+
+ d->view->setFocus();
+ QTimer::singleShot(0, d->controller, SLOT(slotConnect()));
+}
+
+CameraUI::~CameraUI()
+{
+ delete d->rightSidebar;
+ delete d->controller;
+ delete d;
+}
+
+void CameraUI::readSettings()
+{
+ KConfig* 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");
+
+ KConfig* 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 QString& url)
+{
+ KApplication::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();
+}
+
+QString CameraUI::losslessFormat()
+{
+ return d->losslessFormat->currentText();
+}
+
+QString CameraUI::cameraTitle() const
+{
+ return d->cameraTitle;
+}
+
+void CameraUI::slotCancelButton()
+{
+ d->status->setText(i18n("Cancelling current operation, please wait..."));
+ d->progress->hide();
+ QTimer::singleShot(0, d->controller, SLOT(slotCancel()));
+ d->currentlyDeleting.clear();
+}
+
+void CameraUI::closeEvent(QCloseEvent* 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, QDateTime::QDateTime::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 (QStringList::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)
+ QTimer::singleShot(0, d->controller, SLOT(slotConnect()));
+ else
+ close();
+ }
+ else
+ {
+ d->controller->listFolders();
+ }
+}
+
+void CameraUI::slotFolderList(const QStringList& folderList)
+{
+ if (d->closed)
+ return;
+
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(0);
+ d->progress->show();
+
+ d->cameraFolderList = folderList;
+ for (QStringList::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.
+ QStringList fileNames, fileExts;
+ QFileInfo 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 QString& folder, const QString& file,
+ const QImage& 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 QString& summary, const QString& manual, const QString& about)
+{
+ CameraInfoDialog *infoDlg = new CameraInfoDialog(this, summary, manual, about);
+ infoDlg->show();
+}
+
+void CameraUI::slotErrorMsg(const QString& msg)
+{
+ KMessageBox::error(this, msg);
+}
+
+void CameraUI::slotUpload()
+{
+ if (d->busy)
+ return;
+
+ QString fileformats;
+
+ QStringList patternList = QStringList::split('\n', KImageIO::pattern(KImageIO::Reading));
+
+ // All Images from list must been always the first entry given by KDE API
+ QString allPictures = patternList[0];
+
+ // Add RAW file format to All Images" type mime and remplace current.
+#if KDCRAW_VERSION < 0x000106
+ allPictures.insert(allPictures.find("|"), QString(KDcrawIface::DcrawBinary::instance()->rawFiles()));
+#else
+ allPictures.insert(allPictures.find("|"), QString(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(QString("\n%1|Camera RAW files").arg(QString(KDcrawIface::DcrawBinary::instance()->rawFiles())));
+#else
+ patternList.append(QString("\n%1|Camera RAW files").arg(QString(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() != QDialog::Accepted)
+ return;
+
+ QString cameraFolder = dlg.selectedFolderPath();
+
+ for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it)
+ {
+ QFileInfo fi((*it).path());
+ if (!fi.exists()) continue;
+ if (fi.isDir()) continue;
+
+ QString ext = QString(".") + fi.extension();
+ QString name = fi.fileName();
+ name.truncate(fi.fileName().length() - ext.length());
+
+ bool ok;
+
+ while (d->view->findItem(cameraFolder, name + ext))
+ {
+ QString 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(KIO::convertSizeFromKB(dSize))
+ .arg(KIO::convertSizeFromKB(d->freeSpaceWidget->kBAvail())));
+ return;
+ }
+
+ QString newDirName;
+ IconItem* firstItem = d->view->firstItem();
+ if (firstItem)
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(firstItem);
+
+ QDateTime dateTime;
+ dateTime.setTime_t(iconItem->itemInfo()->mtime);
+
+ switch(d->folderDateFormat->currentItem())
+ {
+ case CameraUIPriv::TextDateFormat:
+ newDirName = dateTime.date().toString(Qt::TextDate);
+ break;
+ case CameraUIPriv::LocalDateFormat:
+ newDirName = dateTime.date().toString(Qt::LocalDate);
+ break;
+ default: // IsoDateFormat
+ newDirName = dateTime.date().toString(Qt::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;
+
+ QString 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;
+ QString 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);
+ QString errMsg;
+ QDateTime dateTime;
+ dateTime.setTime_t(mtime);
+
+ // Auto sub-albums creation based on file date.
+
+ if (d->autoAlbumDateCheck->isChecked())
+ {
+ QString dirName;
+
+ switch(d->folderDateFormat->currentItem())
+ {
+ case CameraUIPriv::TextDateFormat:
+ dirName = dateTime.date().toString(Qt::TextDate);
+ break;
+ case CameraUIPriv::LocalDateFormat:
+ dirName = dateTime.date().toString(Qt::LocalDate);
+ break;
+ default: // IsoDateFormat
+ dirName = dateTime.date().toString(Qt::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.
+ QFileInfo fi(downloadName);
+
+ QString subAlbum = fi.extension(false).upper();
+ if (fi.extension(false).upper() == QString("JPEG") ||
+ fi.extension(false).upper() == QString("JPE"))
+ subAlbum = QString("JPG");
+ if (fi.extension(false).upper() == QString("TIFF"))
+ subAlbum = QString("TIF");
+ if (fi.extension(false).upper() == QString("MPEG") ||
+ fi.extension(false).upper() == QString("MPE") ||
+ fi.extension(false).upper() == QString("MPO"))
+ subAlbum = QString("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(QFileInfo(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 QString& folder, const QString& 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 QString& folder, const QString& 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())
+ {
+ QString folder = iconItem->itemInfo()->folder;
+ QString 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 QString& folder, const QString& 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, QStringList& folders, QStringList& files,
+ QStringList& deleteList, QStringList& lockedList)
+{
+ if (iconItem->itemInfo()->writePermissions != 0) // Item not locked ?
+ {
+ QString folder = iconItem->itemInfo()->folder;
+ QString file = iconItem->itemInfo()->name;
+ folders.append(folder);
+ files.append(file);
+ deleteList.append(folder + QString("/") + file);
+ }
+ else
+ {
+ lockedList.append(iconItem->itemInfo()->name);
+ }
+}
+
+void CameraUI::deleteItems(bool onlySelected, bool onlyDownloaded)
+{
+ QStringList folders;
+ QStringList files;
+ QStringList deleteList;
+ QStringList 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())
+ {
+ QString 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;
+
+ QString 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)
+ {
+ QStringList::iterator itFolder = folders.begin();
+ QStringList::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 QString& folder, const QString& 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 QString& folder, const QString& file)
+{
+ CameraIconViewItem* item = d->view->findItem(folder, file);
+ if (!item)
+ return;
+
+ d->rightSidebar->itemChanged(item->itemInfo(), folder + QString("/") + file,
+ QByteArray(), d->view, item);
+}
+
+void CameraUI::slotExifFromData(const QByteArray& 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);
+ QByteArray 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, QByteArray(), 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 QString& sub,
+ const QDate& date, QString& errMsg)
+{
+ KURL u(parentURL);
+ u.addPath(sub);
+
+ // first stat to see if the album exists
+ QFileInfo 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, QString(""), date, QString(""), errMsg);
+}
+
+void CameraUI::addFileExtension(const QString& 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() + QString(" *.") + 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(QKeyEvent *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/digikam/utilities/cameragui/cameraui.h b/digikam/utilities/cameragui/cameraui.h
new file mode 100644
index 0000000..8038b1c
--- /dev/null
+++ b/digikam/utilities/cameragui/cameraui.h
@@ -0,0 +1,154 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qimage.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
+{
+ Q_OBJECT
+
+public:
+
+ CameraUI(QWidget* parent, const QString& cameraTitle,
+ const QString& model, const QString& port,
+ const QString& path, const QDateTime 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;
+ QString losslessFormat();
+
+ QString cameraTitle() const;
+
+signals:
+
+ void signalLastDestination(const KURL&);
+ void signalAlbumSettingsChanged();
+
+public slots:
+
+ void slotDownload(bool onlySelected, bool deleteAfter, Album *album=0);
+
+protected:
+
+ void closeEvent(QCloseEvent* e);
+ void keyPressEvent(QKeyEvent *e);
+
+private:
+
+ void readSettings();
+ void saveSettings();
+ bool dialogClosed();
+ bool createAutoAlbum(const KURL& parentURL, const QString& sub,
+ const QDate& date, QString& errMsg);
+ void addFileExtension(const QString& ext);
+ void finishDialog();
+ void deleteItems(bool onlySelected, bool onlyDownloaded);
+ void checkItem4Deletion(CameraIconViewItem* iconItem, QStringList& folders, QStringList& files,
+ QStringList& deleteList, QStringList& lockedList);
+
+private slots:
+
+ void slotClose();
+ void slotCancelButton();
+ void slotProcessURL(const QString& url);
+
+ void slotConnected(bool val);
+ void slotBusy(bool val);
+ void slotErrorMsg(const QString& msg);
+ void slotInformations();
+ void slotCameraInformations(const QString&, const QString&, const QString&);
+
+ void slotFolderList(const QStringList& folderList);
+ void slotFileList(const GPItemInfoList& fileList);
+ void slotThumbnail(const QString&, const QString&, const QImage&);
+
+ 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 QString&, const QString&, int);
+ void slotSkipped(const QString&, const QString&);
+ void slotDeleted(const QString&, const QString&, bool);
+ void slotLocked(const QString&, const QString&, bool);
+
+ void slotNewSelection(bool);
+ void slotItemsSelected(CameraIconViewItem* item, bool selected);
+
+ void slotExifFromFile(const QString& folder, const QString& file);
+ void slotExifFromData(const QByteArray& exifData);
+
+ void slotFirstItem(void);
+ void slotPrevItem(void);
+ void slotNextItem(void);
+ void slotLastItem(void);
+
+private:
+
+ CameraUIPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* CAMERAUI_H */
diff --git a/digikam/utilities/cameragui/dkcamera.cpp b/digikam/utilities/cameragui/dkcamera.cpp
new file mode 100644
index 0000000..a0adaff
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qdeepcopy.h>
+
+// Local includes.
+
+#include "albumsettings.h"
+#include "dkcamera.h"
+
+namespace Digikam
+{
+
+DKCamera::DKCamera(const QString& title, const QString& model, const QString& port, const QString& path)
+{
+ m_title = title;
+ m_model = model;
+ m_port = port;
+ m_path = path;
+
+ AlbumSettings* settings = AlbumSettings::instance();
+ m_imageFilter = QDeepCopy<QString>(settings->getImageFileFilter());
+ m_movieFilter = QDeepCopy<QString>(settings->getMovieFileFilter());
+ m_audioFilter = QDeepCopy<QString>(settings->getAudioFileFilter());
+ m_rawFilter = QDeepCopy<QString>(settings->getRawFileFilter());
+
+ m_imageFilter = m_imageFilter.lower();
+ m_movieFilter = m_movieFilter.lower();
+ m_audioFilter = m_audioFilter.lower();
+ m_rawFilter = m_rawFilter.lower();
+}
+
+DKCamera::~DKCamera()
+{
+}
+
+QString DKCamera::title() const
+{
+ return m_title;
+}
+
+QString DKCamera::model() const
+{
+ return m_model;
+}
+
+QString DKCamera::port() const
+{
+ return m_port;
+}
+
+QString DKCamera::path() const
+{
+ return m_path;
+}
+
+QString DKCamera::mimeType(const QString& fileext) const
+{
+ if (fileext.isEmpty()) return QString();
+
+ QString ext = fileext;
+ QString 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 = QString("image/x-raw");
+ }
+ else if (m_imageFilter.contains(ext))
+ {
+ mime = QString("image/") + ext;
+ }
+ else if (m_movieFilter.contains(ext))
+ {
+ mime = QString("video/") + ext;
+ }
+ else if (m_audioFilter.contains(ext))
+ {
+ mime = QString("audio/") + ext;
+ }
+
+ return mime;
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/cameragui/dkcamera.h b/digikam/utilities/cameragui/dkcamera.h
new file mode 100644
index 0000000..0180986
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// Local includes.
+
+#include "gpiteminfo.h"
+
+class QStringList;
+class QImage;
+
+namespace Digikam
+{
+
+class DKCamera
+{
+public:
+
+ DKCamera(const QString& title, const QString& model, const QString& port, const QString& path);
+ virtual ~DKCamera();
+
+ virtual bool doConnect() = 0;
+ virtual void cancel() = 0;
+
+ virtual void getAllFolders(const QString& folder, QStringList& 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 QString& folder, GPItemInfoList& infoList, bool getImageDimensions = true) = 0;
+
+ virtual bool getThumbnail(const QString& folder, const QString& itemName, QImage& thumbnail) = 0;
+ virtual bool getExif(const QString& folder, const QString& itemName, char **edata, int& esize) = 0;
+
+ virtual bool downloadItem(const QString& folder, const QString& itemName, const QString& saveFile) = 0;
+ virtual bool deleteItem(const QString& folder, const QString& itemName) = 0;
+ virtual bool uploadItem(const QString& folder, const QString& itemName, const QString& localFile,
+ GPItemInfo& itemInfo, bool getImageDimensions=true) = 0;
+ virtual bool cameraSummary(QString& summary) = 0;
+ virtual bool cameraManual(QString& manual) = 0;
+ virtual bool cameraAbout(QString& about) = 0;
+
+ virtual bool setLockItem(const QString& folder, const QString& itemName, bool lock) = 0;
+
+ QString title() const;
+ QString model() const;
+ QString port() const;
+ QString path() const;
+
+protected:
+
+ QString mimeType(const QString& fileext) const;
+
+protected:
+
+ QString m_imageFilter;
+ QString m_movieFilter;
+ QString m_audioFilter;
+ QString m_rawFilter;
+
+private:
+
+ QString m_title;
+ QString m_model;
+ QString m_port;
+ QString m_path;
+};
+
+} // namespace Digikam
+
+#endif /* DKCAMERA_H */
diff --git a/digikam/utilities/cameragui/downloadsettingscontainer.h b/digikam/utilities/cameragui/downloadsettingscontainer.h
new file mode 100644
index 0000000..7004326
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qdatetime.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;
+
+ QDateTime newDateTime;
+
+ // File path to download.
+ QString folder;
+ QString file;
+ QString dest;
+
+ // New format to convert Jpeg files.
+ QString losslessFormat;
+
+ // IPTC settings
+ QString author;
+ QString authorTitle;
+ QString credit;
+ QString source;
+ QString copyright;
+};
+
+} // namespace Digikam
+
+#endif // DOWNLOADSETTINGSCONTAINER_H
diff --git a/digikam/utilities/cameragui/freespacewidget.cpp b/digikam/utilities/cameragui/freespacewidget.cpp
new file mode 100644
index 0000000..2794110
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpalette.h>
+#include <qcolor.h>
+#include <qtimer.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <klocale.h>
+#include <kdiskfreesp.h>
+#include <kio/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;
+
+ QString mountPoint;
+
+ QTimer *timer;
+
+ QPixmap pix;
+};
+
+FreeSpaceWidget::FreeSpaceWidget(QWidget* parent, int width)
+ : QWidget(parent, 0, WResizeNoErase|WRepaintNoErase)
+{
+ d = new FreeSpaceWidgetPriv;
+ setBackgroundMode(Qt::NoBackground);
+ setFixedWidth(width);
+ setMaximumHeight(fontMetrics().height()+4);
+ slotTimeout();
+
+ d->timer = new QTimer(this);
+
+ connect(d->timer, SIGNAL(timeout()),
+ this, 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;
+}
+
+QString FreeSpaceWidget::mountPoint()
+{
+ return d->mountPoint;
+}
+
+void FreeSpaceWidget::updatePixmap()
+{
+ QPixmap fimgPix = SmallIcon("folder_image");
+ d->pix = QPixmap(size());
+ d->pix.fill(colorGroup().background());
+
+ QPainter 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 ? Qt::red : Qt::darkGreen);
+ p.setPen(Qt::white);
+ QRect 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);
+
+ QRect tRect(fimgPix.height()+2, 1, d->pix.width()-2-fimgPix.width()-2, d->pix.height()-2);
+ QString text = QString("%1%").arg(peUsed);
+ p.setPen(colorGroup().text());
+ QFontMetrics fontMt = p.fontMetrics();
+ QRect fontRect = fontMt.boundingRect(tRect.x(), tRect.y(),
+ tRect.width(), tRect.height(), 0, text);
+ p.drawText(tRect, Qt::AlignCenter, text);
+
+ QString tipText, value;
+ QString header = i18n("Album Library");
+ QString headBeg("<tr bgcolor=\"orange\"><td colspan=\"2\">"
+ "<nobr><font size=\"-1\" color=\"black\"><b>");
+ QString headEnd("</b></font></nobr></td></tr>");
+ QString cellBeg("<tr><td><nobr><font size=-1>");
+ QString cellMid("</font></nobr></td><td><nobr><font size=-1>");
+ QString 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 += KIO::convertSizeFromKB(d->kBSize) + cellEnd;
+
+ tipText += cellBeg + i18n("Available:") + cellMid;
+ tipText += KIO::convertSizeFromKB(d->kBAvail) + cellEnd;
+
+ tipText += cellBeg + i18n("Require:") + cellMid;
+ tipText += KIO::convertSizeFromKB(d->dSizeKb) + cellEnd;
+ }
+ else
+ {
+ tipText += cellBeg + i18n("Capacity:") + cellMid;
+ tipText += KIO::convertSizeFromKB(d->kBSize) + cellEnd;
+
+ tipText += cellBeg + i18n("Available:") + cellMid;
+ tipText += KIO::convertSizeFromKB(d->kBAvail) + cellEnd;
+ }
+
+ tipText += "</table>";
+
+ QWhatsThis::add(this, tipText);
+ QToolTip::add(this, tipText);
+ }
+
+ p.end();
+}
+
+void FreeSpaceWidget::paintEvent(QPaintEvent*)
+{
+ bitBlt(this, 0, 0, &d->pix);
+}
+
+void FreeSpaceWidget::slotTimeout()
+{
+ QString mountPoint = KIO::findPathMountPoint(AlbumSettings::instance()->getAlbumLibraryPath());
+ KDiskFreeSp *job = new KDiskFreeSp;
+ connect(job, SIGNAL(foundMountPoint(const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString&)),
+ this, SLOT(slotAvailableFreeSpace(const unsigned long&, const unsigned long&,
+ const unsigned long&, const QString&)));
+ job->readDF(mountPoint);
+}
+
+void FreeSpaceWidget::slotAvailableFreeSpace(const unsigned long& kBSize, const unsigned long& kBUsed,
+ const unsigned long& kBAvail, const QString& 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/digikam/utilities/cameragui/freespacewidget.h b/digikam/utilities/cameragui/freespacewidget.h
new file mode 100644
index 0000000..e58f382
--- /dev/null
+++ b/digikam/utilities/cameragui/freespacewidget.h
@@ -0,0 +1,74 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class FreeSpaceWidgetPriv;
+
+class FreeSpaceWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ FreeSpaceWidget(QWidget* 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();
+ QString mountPoint();
+
+protected:
+
+ void paintEvent(QPaintEvent*);
+ void updatePixmap();
+
+private slots:
+
+ void slotTimeout();
+ void slotAvailableFreeSpace(const unsigned long& kBSize, const unsigned long& kBUsed,
+ const unsigned long& kBAvail, const QString& mountPoint);
+
+private:
+
+ FreeSpaceWidgetPriv* d;
+};
+
+} // namespace Digikam
+
+#endif /* FREESPACEWIDGET_H */
diff --git a/digikam/utilities/cameragui/gpcamera.cpp b/digikam/utilities/cameragui/gpcamera.cpp
new file mode 100644
index 0000000..2e5b372
--- /dev/null
+++ b/digikam/utilities/cameragui/gpcamera.cpp
@@ -0,0 +1,1208 @@
+/* ============================================================
+ *
+ * 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>
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qdom.h>
+#include <qfile.h>
+
+// KDE includes.
+
+#include <klocale.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;
+
+ QString model;
+ QString port;
+ QString 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 QString& title, const QString& model, const QString& port, const QString& 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;
+}
+
+QString GPCamera::model() const
+{
+ return d->model;
+}
+
+QString GPCamera::port() const
+{
+ return d->port;
+}
+
+QString 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 QString& rootFolder,
+ QStringList& folderList)
+{
+ QStringList subfolders;
+ getSubFolders(rootFolder, subfolders);
+
+ for (QStringList::iterator it = subfolders.begin();
+ it != subfolders.end(); ++it)
+ {
+ *it = rootFolder + QString(rootFolder.endsWith("/") ? "" : "/") + (*it);
+ folderList.append(*it);
+ }
+
+ for (QStringList::iterator it = subfolders.begin();
+ it != subfolders.end(); ++it)
+ {
+ getAllFolders(*it, folderList);
+ }
+}
+
+bool GPCamera::getSubFolders(const QString& folder, QStringList& 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, QFile::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(QFile::decodeName(subFolder));
+ }
+
+ gp_list_unref(clist);
+ return true;
+}
+
+bool GPCamera::getItemsList(const QString& folder, QStringList& 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, QFile::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(QFile::decodeName(cname));
+ }
+
+ gp_list_unref(clist);
+
+ delete m_status;
+ m_status = 0;
+
+ return true;
+}
+
+bool GPCamera::getItemsInfoList(const QString& 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, QFile::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 = QFile::decodeName(cname);
+ itemInfo.folder = folder;
+
+ CameraFileInfo info;
+ gp_camera_file_get_info(d->camera, QFile::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(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 QString& folder, const QString& itemName, QImage& 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, QFile::encodeName(folder),
+ QFile::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 QString& folder, const QString& 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, QFile::encodeName(folder),
+ QFile::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 QString& folder, const QString& itemName,
+ const QString& 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, QFile::encodeName(folder),
+ QFile::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, QFile::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 QString& folder, const QString& 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, QFile::encodeName(folder),
+ QFile::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, QFile::encodeName(folder),
+ QFile::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 QString& folder, const QString& itemName)
+{
+ int errorCode;
+ if (m_status)
+ {
+ delete m_status;
+ m_status = 0;
+ }
+
+ m_status = new GPStatus;
+
+ errorCode = gp_camera_file_delete(d->camera, QFile::encodeName(folder),
+ QFile::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 QString& folder)
+{
+ int errorCode;
+ QStringList folderList;
+
+ // Get all subfolders in this folder
+ getSubFolders(folder, folderList);
+
+ if (folderList.count() > 0)
+ {
+ for (unsigned int i = 0 ; i < folderList.count() ; i++)
+ {
+ QString 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, QFile::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 QString& folder, const QString& itemName, const QString& 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, QFile::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, QFile::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;
+
+ errorCode = gp_camera_folder_put_file(d->camera,
+ QFile::encodeName(folder),
+ cfile,
+ m_status->context);
+ 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, QFile::encodeName(folder),
+ QFile::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(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(QString& 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(QString(sum.text));
+
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+bool GPCamera::cameraManual(QString& 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 = QString(man.text);
+
+ delete m_status;
+ m_status = 0;
+ return true;
+}
+
+bool GPCamera::cameraAbout(QString& 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 = QString(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, QStringList& 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( QString( cname ) );
+ }
+ }
+
+ gp_abilities_list_free( abilList );
+ gp_context_unref( context );
+}
+
+void GPCamera::getSupportedPorts(QStringList& 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 );
+ plist.append( info.path );
+ }
+ }
+
+ gp_port_info_list_free( list );
+}
+
+void GPCamera::getCameraSupportedPorts(const QString& model, QStringList& 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(QString& model, QString& 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 = QString::fromLatin1(camModel_);
+ port = QString::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/digikam/utilities/cameragui/gpcamera.h b/digikam/utilities/cameragui/gpcamera.h
new file mode 100644
index 0000000..b487e2b
--- /dev/null
+++ b/digikam/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 QImage;
+
+namespace Digikam
+{
+
+class GPCameraPrivate;
+class GPStatus;
+
+// Gphoto2 camera Implementation of abstract type DKCamera
+
+class GPCamera : public DKCamera
+{
+
+public:
+
+ GPCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path);
+ ~GPCamera();
+
+ bool thumbnailSupport();
+ bool deleteSupport();
+ bool uploadSupport();
+ bool mkDirSupport();
+ bool delDirSupport();
+
+ bool doConnect();
+
+ void cancel();
+
+ void getAllFolders(const QString& folder, QStringList& subFolderList);
+ bool getSubFolders(const QString& folder, QStringList& subFolderList);
+ bool getItemsList(const QString& folder, QStringList& itemsList);
+ bool getItemsInfoList(const QString& folder, GPItemInfoList& items, bool getImageDimensions = true);
+ bool getThumbnail(const QString& folder, const QString& itemName, QImage& thumbnail);
+ bool getExif(const QString& folder, const QString& itemName, char **edata, int& esize);
+
+ bool setLockItem(const QString& folder, const QString& itemName, bool lock);
+
+ bool downloadItem(const QString& folder, const QString& itemName, const QString& saveFile);
+ bool deleteItem(const QString& folder, const QString& itemName);
+
+ // recursively delete all items
+ bool deleteAllItems(const QString& folder);
+
+ bool uploadItem(const QString& folder, const QString& itemName, const QString& localFile,
+ GPItemInfo& itemInfo, bool getImageDimensions=true);
+
+ bool cameraSummary(QString& summary);
+ bool cameraManual(QString& manual);
+ bool cameraAbout(QString& about);
+
+ QString model() const;
+ QString port() const;
+ QString path() const;
+
+ // Public static methods shared with Camera Setup
+
+ static int autoDetect(QString& model, QString& port);
+ static void getSupportedCameras(int& count, QStringList& clist);
+ static void getSupportedPorts(QStringList& plist);
+ static void getCameraSupportedPorts(const QString& model, QStringList& plist);
+
+private:
+
+ int setup();
+ static void printGphotoErrorDescription(int errorCode);
+
+private:
+
+ GPCameraPrivate *d;
+ GPStatus *m_status;
+};
+
+} // namespace Digikam
+
+#endif /* GPCAMERA_H */
diff --git a/digikam/utilities/cameragui/gpiteminfo.cpp b/digikam/utilities/cameragui/gpiteminfo.cpp
new file mode 100644
index 0000000..e32e470
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qdatastream.h>
+
+// Local includes.
+
+#include "gpiteminfo.h"
+
+namespace Digikam
+{
+
+QDataStream& operator<<( QDataStream& 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;
+}
+
+QDataStream& operator>>(QDataStream& 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/digikam/utilities/cameragui/gpiteminfo.h b/digikam/utilities/cameragui/gpiteminfo.h
new file mode 100644
index 0000000..768685d
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qvaluelist.h>
+#include <qcstring.h>
+
+class QDataStream;
+
+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;
+
+ QString name;
+ QString folder;
+ QString mime;
+
+ time_t mtime;
+};
+
+QDataStream& operator<<( QDataStream &, const GPItemInfo & );
+QDataStream& operator>>( QDataStream &, GPItemInfo & );
+
+typedef QValueList<GPItemInfo> GPItemInfoList;
+
+} // namespace Digikam
+
+#endif /* GPITEMINFO_H */
diff --git a/digikam/utilities/cameragui/mtqueue.h b/digikam/utilities/cameragui/mtqueue.h
new file mode 100644
index 0000000..1933c35
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qptrqueue.h>
+#include <qmutex.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:
+
+ QPtrQueue<Type> queue_;
+ QMutex mutex_;
+};
+
+} // namespace Digikam
+
+#endif // COMMAND_QUEUE_H
diff --git a/digikam/utilities/cameragui/renamecustomizer.cpp b/digikam/utilities/cameragui/renamecustomizer.cpp
new file mode 100644
index 0000000..fc90ce2
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qdatetime.h>
+#include <qlayout.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.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;
+}
+
+ QWidget *focusedWidget;
+
+ QString cameraTitle;
+
+ QRadioButton *renameDefault;
+ QRadioButton *renameCustom;
+
+ QGroupBox *renameDefaultBox;
+ QGroupBox *renameCustomBox;
+
+ QLabel *renameDefaultCase;
+ QLabel *startIndexLabel;
+ QLabel *dateTimeLabel;
+
+ QComboBox *renameDefaultCaseType;
+ QComboBox *dateTimeFormat;
+
+ QCheckBox *addDateTimeBox;
+ QCheckBox *addCameraNameBox;
+ QCheckBox *addSeqNumberBox;
+
+ QPushButton *dateTimeButton;
+ QString dateTimeFormatString;
+
+ QTimer *changedTimer;
+
+ KLineEdit *renameCustomPrefix;
+ KLineEdit *renameCustomSuffix;
+
+ KIntNumInput *startIndexInput;
+};
+
+RenameCustomizer::RenameCustomizer(QWidget* parent, const QString& cameraTitle)
+ : QButtonGroup(parent)
+{
+ d = new RenameCustomizerPriv;
+ d->changedTimer = new QTimer(this);
+ d->cameraTitle = cameraTitle;
+
+ setFrameStyle( QFrame::NoFrame );
+ setRadioButtonExclusive(true);
+ setColumnLayout(0, Qt::Vertical);
+ QGridLayout* mainLayout = new QGridLayout(layout(), 4, 1);
+
+ // ----------------------------------------------------------------
+
+ d->renameDefault = new QRadioButton(i18n("Camera filenames"), this);
+ QWhatsThis::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 QGroupBox( this );
+ d->renameDefaultBox->setFrameStyle(QFrame::NoFrame|QFrame::Plain);
+ d->renameDefaultBox->setInsideMargin(0);
+ d->renameDefaultBox->setColumnLayout(0, Qt::Vertical);
+
+ d->renameDefaultCase = new QLabel( i18n("Change case to:"), d->renameDefaultBox );
+ d->renameDefaultCase->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
+
+ d->renameDefaultCaseType = new QComboBox( 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(QSizePolicy::Minimum, QSizePolicy::Preferred);
+ QWhatsThis::add( d->renameDefaultCaseType, i18n("<p>Set the method to use to change the case "
+ "of image filenames."));
+
+ QHBoxLayout* boxLayout1 = new QHBoxLayout( 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 QRadioButton(i18n("Customize"), this);
+ mainLayout->addMultiCellWidget(d->renameCustom, 2, 2, 0, 1);
+ QWhatsThis::add( d->renameCustom, i18n("<p>Turn on this option to customize image filenames "
+ "during download."));
+
+ d->renameCustomBox = new QGroupBox(this);
+ d->renameCustomBox->setFrameStyle(QFrame::NoFrame|QFrame::Plain);
+ d->renameCustomBox->setInsideMargin(0);
+ d->renameCustomBox->setColumnLayout(0, Qt::Vertical);
+
+ QGridLayout* renameCustomBoxLayout = new QGridLayout(d->renameCustomBox->layout(),
+ 6, 2, KDialogBase::spacingHint());
+ renameCustomBoxLayout->setColSpacing( 0, 10 );
+
+ QLabel* prefixLabel = new QLabel(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);
+ QWhatsThis::add( d->renameCustomPrefix, i18n("<p>Set the prefix which will be added to "
+ "image filenames."));
+
+ QLabel* suffixLabel = new QLabel(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);
+ QWhatsThis::add( d->renameCustomSuffix, i18n("<p>Set the suffix which will be added to "
+ "image filenames."));
+
+ d->addDateTimeBox = new QCheckBox( i18n("Add Date && Time"), d->renameCustomBox );
+ renameCustomBoxLayout->addMultiCellWidget(d->addDateTimeBox, 2, 2, 1, 2);
+ QWhatsThis::add( d->addDateTimeBox, i18n("<p>Set this option to add the camera provided date and time."));
+
+ QWidget *dateTimeWidget = new QWidget(d->renameCustomBox);
+ d->dateTimeLabel = new QLabel(i18n("Date format:"), dateTimeWidget);
+ d->dateTimeFormat = new QComboBox(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);
+ QWhatsThis::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 KDE control panel settings.</p>"
+ "<p><b>Advanced:</b> allows the user to specify a custom date format.</p>"));
+ d->dateTimeButton = new QPushButton(SmallIcon("configure"), QString(), dateTimeWidget);
+ QSizePolicy policy = d->dateTimeButton->sizePolicy();
+ policy.setHorData(QSizePolicy::Maximum);
+ d->dateTimeButton->setSizePolicy(policy);
+ QHBoxLayout *boxLayout2 = new QHBoxLayout(dateTimeWidget);
+ boxLayout2->addWidget(d->dateTimeLabel);
+ boxLayout2->addWidget(d->dateTimeFormat);
+ boxLayout2->addWidget(d->dateTimeButton);
+ renameCustomBoxLayout->addMultiCellWidget(dateTimeWidget, 3, 3, 1, 2);
+
+ d->addCameraNameBox = new QCheckBox( i18n("Add Camera Name"), d->renameCustomBox );
+ renameCustomBoxLayout->addMultiCellWidget(d->addCameraNameBox, 4, 4, 1, 2);
+ QWhatsThis::add( d->addCameraNameBox, i18n("<p>Set this option to add the camera name."));
+
+ d->addSeqNumberBox = new QCheckBox( i18n("Add Sequence Number"), d->renameCustomBox );
+ renameCustomBoxLayout->addMultiCellWidget(d->addSeqNumberBox, 5, 5, 1, 2);
+ QWhatsThis::add( d->addSeqNumberBox, i18n("<p>Set this option to add a sequence number "
+ "starting with the index set below."));
+
+ d->startIndexLabel = new QLabel( i18n("Start Index:"), d->renameCustomBox );
+ d->startIndexInput = new KIntNumInput(1, d->renameCustomBox);
+ d->startIndexInput->setRange(1, 900000, 1, false);
+ QWhatsThis::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, SIGNAL(clicked(int)),
+ this, SLOT(slotRadioButtonClicked(int)));
+
+ connect(d->renameCustomPrefix, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->renameCustomSuffix, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->addDateTimeBox, SIGNAL(toggled(bool)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->addCameraNameBox, SIGNAL(toggled(bool)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->addSeqNumberBox, SIGNAL(toggled(bool)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->renameDefaultCaseType, SIGNAL(activated(const QString&)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->startIndexInput, SIGNAL(valueChanged (int)),
+ this, SLOT(slotRenameOptionsChanged()));
+
+ connect(d->changedTimer, SIGNAL(timeout()),
+ this, SIGNAL(signalChanged()));
+
+ connect(d->dateTimeButton, SIGNAL(clicked()),
+ this, SLOT(slotDateTimeButtonClicked()));
+
+ connect(d->dateTimeFormat, SIGNAL(activated(int)),
+ this, SLOT(slotDateTimeFormatChanged(int)));
+
+ connect(d->addDateTimeBox, SIGNAL(toggled(bool)),
+ this, 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();
+}
+
+QString RenameCustomizer::newName(const QDateTime &dateTime, int index, const QString &extension) const
+{
+ if (d->renameDefault->isChecked())
+ return QString();
+ else
+ {
+ QString name(d->renameCustomPrefix->text());
+
+ // use the "T" as a delimiter between date and time
+ QString date;
+ switch (d->dateTimeFormat->currentItem())
+ {
+ case RenameCustomizerPriv::DigikamStandard:
+ date = dateTime.toString("yyyyMMddThhmmss");
+ break;
+ case RenameCustomizerPriv::TextDateFormat:
+ date = dateTime.toString(Qt::TextDate);
+ break;
+ case RenameCustomizerPriv::LocalDateFormat:
+ date = dateTime.toString(Qt::LocalDate);
+ break;
+ case RenameCustomizerPriv::IsoDateFormat:
+ date = dateTime.toString(Qt::ISODate);
+ break;
+ case RenameCustomizerPriv::Advanced:
+ date = dateTime.toString(d->dateTimeFormatString);
+ break;
+ }
+
+ // it seems that QString::number does not support padding with zeros
+ QString seq;
+ seq.sprintf("-%06d", index);
+
+ if (d->addDateTimeBox->isChecked())
+ name += date;
+
+ if (d->addSeqNumberBox->isChecked())
+ name += seq;
+
+ if (d->addCameraNameBox->isChecked())
+ name += QString("-%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)
+{
+ QRadioButton* btn = dynamic_cast<QRadioButton*>(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;
+ QString 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)
+ QString newFormat = KInputDialog::getText(i18n("Change Date and Time Format"),
+ message,
+ d->dateTimeFormatString, &ok, this);
+#else
+ QString 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()
+{
+ KConfig* 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);
+ QString prefix = config->readEntry("Rename Prefix", i18n("photo"));
+ QString suffix = config->readEntry("Rename Postfix", QString());
+ int startIndex = config->readNumEntry("Rename Start Index", 1);
+ int dateTime = config->readNumEntry("Date Time Format", RenameCustomizerPriv::IsoDateFormat);
+ QString 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()
+{
+ KConfig* 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/digikam/utilities/cameragui/renamecustomizer.h b/digikam/utilities/cameragui/renamecustomizer.h
new file mode 100644
index 0000000..7e03858
--- /dev/null
+++ b/digikam/utilities/cameragui/renamecustomizer.h
@@ -0,0 +1,90 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qbuttongroup.h>
+
+class QDateTime;
+
+namespace Digikam
+{
+
+class RenameCustomizerPriv;
+
+class RenameCustomizer : public QButtonGroup
+{
+ Q_OBJECT
+
+public:
+
+ enum Case
+ {
+ NONE = 0,
+ UPPER,
+ LOWER
+ };
+
+ RenameCustomizer(QWidget* parent, const QString& cameraTitle);
+ ~RenameCustomizer();
+
+ void setUseDefault(bool val);
+ bool useDefault() const;
+ QString newName(const QDateTime &date, int index, const QString &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/digikam/utilities/cameragui/umscamera.cpp b/digikam/utilities/cameragui/umscamera.cpp
new file mode 100644
index 0000000..a06d02c
--- /dev/null
+++ b/digikam/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>
+}
+
+// Qt includes.
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qfile.h>
+#include <qstringlist.h>
+#include <qdeepcopy.h>
+#include <qwmatrix.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kfilemetainfo.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 QString& title, const QString& model, const QString& port, const QString& 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 QString& folder, QStringList& subFolderList)
+{
+ m_cancel = false;
+ subFolderList.clear();
+ subFolderList.append(folder);
+ listFolders(folder, subFolderList);
+}
+
+bool UMSCamera::getItemsInfoList(const QString& folder, GPItemInfoList& infoList, bool getImageDimensions)
+{
+ m_cancel = false;
+ infoList.clear();
+
+ QDir dir(folder);
+ dir.setFilter(QDir::Files);
+
+ const QFileInfoList *list = dir.entryInfoList();
+ if (!list)
+ return false;
+
+ QFileInfoListIterator it(*list);
+ QFileInfo *fi;
+ QFileInfo thmlo, thmup;
+ DMetadata meta;
+
+ while ((fi = it.current()) != 0 && !m_cancel)
+ {
+ ++it;
+
+ QString mime = mimeType(fi->extension(false).lower());
+
+ if (!mime.isEmpty())
+ {
+ QSize dims;
+ QDateTime dt;
+ GPItemInfo info;
+ thmlo.setFile(folder + QString("/") + fi->baseName() + QString(".thm"));
+ thmup.setFile(folder + QString("/") + fi->baseName() + QString(".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 == QString("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 + QString("/") : 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 QString& folder, const QString& itemName, QImage& thumbnail)
+{
+ m_cancel = false;
+
+ // JPEG files: try to get thumbnail from Exif data.
+
+ DMetadata metadata(QFile::encodeName(folder + QString("/") + itemName));
+ thumbnail = metadata.getExifThumbnail(true);
+ if (!thumbnail.isNull())
+ return true;
+
+ // RAW files : try to extract embedded thumbnail using dcraw
+
+ KDcrawIface::KDcraw::loadDcrawPreview(thumbnail, QString(folder + QString("/") + 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.
+
+ QFileInfo fi(folder + QString("/") + itemName);
+
+ if (thumbnail.load(folder + QString("/") + fi.baseName() + QString(".thm"))) // Lowercase
+ {
+ if (!thumbnail.isNull())
+ return true;
+ }
+ else if (thumbnail.load(folder + QString("/") + fi.baseName() + QString(".THM"))) // Uppercase
+ {
+ if (!thumbnail.isNull())
+ return true;
+ }
+
+ // Finaly, we trying to get thumbnail using DImg API (slow).
+
+ DImg dimgThumb(QFile::encodeName(folder + QString("/") + itemName));
+
+ if (!dimgThumb.isNull())
+ {
+ thumbnail = dimgThumb.copyQImage();
+ return true;
+ }
+
+ return false;
+}
+
+bool UMSCamera::getExif(const QString&, const QString&, 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 QString& folder, const QString& itemName, const QString& saveFile)
+{
+ m_cancel = false;
+ QString src = folder + QString("/") + itemName;
+ QString dest = saveFile;
+
+ QFile sFile(src);
+ QFile 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];
+
+ Q_LONG len;
+ while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
+ {
+ if (len == -1 || dFile.writeBlock(buffer, (Q_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(QFile::encodeName(src), &st);
+
+ struct utimbuf ut;
+ ut.modtime = st.st_mtime;
+ ut.actime = st.st_atime;
+
+ ::utime(QFile::encodeName(dest), &ut);
+
+ return true;
+}
+
+bool UMSCamera::setLockItem(const QString& folder, const QString& itemName, bool lock)
+{
+ QString src = folder + QString("/") + itemName;
+
+ if (lock)
+ {
+ // Lock the file to set read only flag
+ if (::chmod(QFile::encodeName(src), S_IREAD) == -1)
+ return false;
+ }
+ else
+ {
+ // Unlock the file to set read/write flag
+ if (::chmod(QFile::encodeName(src), S_IREAD | S_IWRITE) == -1)
+ return false;
+ }
+
+ return true;
+}
+
+bool UMSCamera::deleteItem(const QString& folder, const QString& itemName)
+{
+ m_cancel = false;
+
+ // Any camera provide THM (thumbnail) file with real image. We need to remove it also.
+
+ QFileInfo fi(folder + QString("/") + itemName);
+
+ QFileInfo thmLo(folder + QString("/") + fi.baseName() + ".thm"); // Lowercase
+
+ if (thmLo.exists())
+ ::unlink(QFile::encodeName(thmLo.filePath()));
+
+ QFileInfo thmUp(folder + QString("/") + fi.baseName() + ".THM"); // Uppercase
+
+ if (thmUp.exists())
+ ::unlink(QFile::encodeName(thmUp.filePath()));
+
+ // Remove the real image.
+ return (::unlink(QFile::encodeName(folder + QString("/") + itemName)) == 0);
+}
+
+bool UMSCamera::uploadItem(const QString& folder, const QString& itemName, const QString& localFile,
+ GPItemInfo& info, bool getImageDimensions)
+{
+ m_cancel = false;
+ QString dest = folder + QString("/") + itemName;
+ QString src = localFile;
+
+ QFile sFile(src);
+ QFile 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];
+
+ Q_LONG len;
+ while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
+ {
+ if (len == -1 || dFile.writeBlock(buffer, (Q_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(QFile::encodeName(src), &st);
+
+ struct utimbuf ut;
+ ut.modtime = st.st_mtime;
+ ut.actime = st.st_atime;
+
+ ::utime(QFile::encodeName(dest), &ut);
+
+ // Get new camera item information.
+
+ DMetadata meta;
+ QFileInfo fi(dest);
+ QString mime = mimeType(fi.extension(false).lower());
+
+ if (!mime.isEmpty())
+ {
+ QSize dims;
+ QDateTime dt;
+
+ if (mime == QString("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 + QString("/") : 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 QString& folder, QStringList& subFolderList)
+{
+ if (m_cancel)
+ return;
+
+ QDir dir(folder);
+ dir.setFilter(QDir::Dirs|QDir::Executable);
+
+ const QFileInfoList *list = dir.entryInfoList();
+ if (!list)
+ return;
+
+ QFileInfoListIterator it( *list );
+ QFileInfo *fi;
+
+ while ((fi = it.current()) != 0 && !m_cancel)
+ {
+ ++it;
+
+ if (fi->fileName() == "." || fi->fileName() == "..")
+ continue;
+
+ QString subfolder = folder + QString(folder.endsWith("/") ? "" : "/") + fi->fileName();
+ subFolderList.append(subfolder);
+ listFolders(subfolder, subFolderList);
+ }
+}
+
+bool UMSCamera::cameraSummary(QString& summary)
+{
+ summary = QString(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(QString& manual)
+{
+ manual = QString(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(QString& about)
+{
+ about = QString(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/digikam/utilities/cameragui/umscamera.h b/digikam/utilities/cameragui/umscamera.h
new file mode 100644
index 0000000..9654a27
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstringlist.h>
+
+// Local includes.
+
+#include "dkcamera.h"
+
+namespace Digikam
+{
+
+class UMSCameraPriv;
+
+class UMSCamera : public DKCamera
+{
+public:
+
+ UMSCamera(const QString& title, const QString& model, const QString& port, const QString& path);
+ ~UMSCamera();
+
+ bool doConnect();
+ void cancel();
+
+ void getAllFolders(const QString& folder, QStringList& subFolderList);
+ bool getItemsInfoList(const QString& folder, GPItemInfoList& infoList, bool getImageDimensions=true);
+ bool getThumbnail(const QString& folder, const QString& itemName, QImage& thumbnail);
+ bool getExif(const QString& folder, const QString& itemName, char **edata, int& esize);
+
+ bool setLockItem(const QString& folder, const QString& itemName, bool lock);
+
+ bool downloadItem(const QString& folder, const QString& itemName, const QString& saveFile);
+ bool deleteItem(const QString& folder, const QString& itemName);
+ bool uploadItem(const QString& folder, const QString& itemName, const QString& localFile,
+ GPItemInfo& info, bool getImageDimensions=true);
+
+ bool cameraSummary(QString& summary);
+ bool cameraManual(QString& manual);
+ bool cameraAbout(QString& about);
+
+private:
+
+ void listFolders(const QString& folder, QStringList& subFolderList);
+
+private:
+
+ bool m_cancel;
+};
+
+} // namespace Digikam
+
+#endif /* UMSCAMERA_H */
diff --git a/digikam/utilities/hotplug/Makefile.am b/digikam/utilities/hotplug/Makefile.am
new file mode 100644
index 0000000..b0b9e23
--- /dev/null
+++ b/digikam/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/digikam/utilities/hotplug/configure.in.in b/digikam/utilities/hotplug/configure.in.in
new file mode 100644
index 0000000..94133f7
--- /dev/null
+++ b/digikam/utilities/hotplug/configure.in.in
@@ -0,0 +1,7 @@
+KDE_EXPAND_MAKEVAR(digikamhelper_dir, kde_datadir/digikam/utils)
+AC_SUBST(digikamhelper_dir)
+
+AC_OUTPUT(digikam/utilities/hotplug/digikam-download.desktop)
+AC_OUTPUT(digikam/utilities/hotplug/digikam-gphoto2-camera.desktop)
+AC_OUTPUT(digikam/utilities/hotplug/digikam-mount-and-download.desktop)
+
diff --git a/digikam/utilities/hotplug/digikam-camera b/digikam/utilities/hotplug/digikam-camera
new file mode 100755
index 0000000..10b2fe3
--- /dev/null
+++ b/digikam/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/digikam/utilities/hotplug/digikam-download.desktop.in b/digikam/utilities/hotplug/digikam-download.desktop.in
new file mode 100644
index 0000000..81cb873
--- /dev/null
+++ b/digikam/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
+ServiceTypes=media/removable_mounted,media/camera_mounted
diff --git a/digikam/utilities/hotplug/digikam-gphoto2-camera.desktop.in b/digikam/utilities/hotplug/digikam-gphoto2-camera.desktop.in
new file mode 100644
index 0000000..d3ea1db
--- /dev/null
+++ b/digikam/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
+ServiceTypes=media/gphoto2camera
diff --git a/digikam/utilities/hotplug/digikam-mount-and-download.desktop.in b/digikam/utilities/hotplug/digikam-mount-and-download.desktop.in
new file mode 100644
index 0000000..5f354bf
--- /dev/null
+++ b/digikam/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
+ServiceTypes=media/removable_unmounted,media/camera_unmounted
diff --git a/digikam/utilities/imageeditor/Makefile.am b/digikam/utilities/imageeditor/Makefile.am
new file mode 100644
index 0000000..c324c68
--- /dev/null
+++ b/digikam/utilities/imageeditor/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = canvas tools rawimport editor
diff --git a/digikam/utilities/imageeditor/canvas/Makefile.am b/digikam/utilities/imageeditor/canvas/Makefile.am
new file mode 100644
index 0000000..6ebf238
--- /dev/null
+++ b/digikam/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)/digikam/digikam \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dimg/filters \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/dialogs \
+ -I$(top_srcdir)/digikam/libs/histogram \
+ -I$(top_srcdir)/digikam/libs/threadimageio \
+ -I$(top_srcdir)/digikam/utilities/splashscreen \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/editor \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/rawimport \
+ -I$(top_srcdir)/digikam/libs/widgets/imageplugins \
+ -I$(top_srcdir)/digikam/libs/widgets/common \
+ $(LIBKEXIV2_CFLAGS) $(LIBKDCRAW_CFLAGS) $(all_includes)
+
+digikaminclude_HEADERS = imageplugin.h
+
+digikamincludedir = $(includedir)/digikam
diff --git a/digikam/utilities/imageeditor/canvas/canvas.cpp b/digikam/utilities/imageeditor/canvas/canvas.cpp
new file mode 100644
index 0000000..9c6734f
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qtooltip.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <qevent.h>
+#include <qpoint.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qimage.h>
+#include <qregion.h>
+#include <qtimer.h>
+#include <qcache.h>
+#include <qcolor.h>
+#include <qdragobject.h>
+#include <qclipboard.h>
+#include <qtoolbutton.h>
+
+// KDE includes.
+
+#include <kcursor.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdatetbl.h>
+#include <kglobalsettings.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 QPixmap(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;
+
+ QToolButton *cornerButton;
+
+ QRect *rubber;
+ QRect pixmapRect;
+
+ QCache<QPixmap> tileCache;
+
+ QPixmap* tileTmpPix;
+ QPixmap qcheck;
+
+ QColor bgColor;
+
+ QWidget *parent;
+
+ KPopupFrame *panIconPopup;
+
+ DImgInterface *im;
+
+ ImagePanIconWidget *panIconWidget;
+};
+
+Canvas::Canvas(QWidget *parent)
+ : QScrollView(parent)
+{
+ d = new CanvasPrivate;
+ d->im = new DImgInterface();
+ d->parent = parent;
+ d->bgColor.setRgb(0, 0, 0);
+
+ d->qcheck.resize(16, 16);
+ QPainter p(&d->qcheck);
+ p.fillRect(0, 0, 8, 8, QColor(144, 144, 144));
+ p.fillRect(8, 8, 8, 8, QColor(144, 144, 144));
+ p.fillRect(0, 8, 8, 8, QColor(100, 100, 100));
+ p.fillRect(8, 0, 8, 8, QColor(100, 100, 100));
+ p.end();
+
+ d->cornerButton = new QToolButton(this);
+ d->cornerButton->setIconSet(SmallIcon("move"));
+ d->cornerButton->hide();
+ QToolTip::add(d->cornerButton, i18n("Pan the image to a region"));
+ setCornerWidget(d->cornerButton);
+
+ viewport()->setBackgroundMode(Qt::NoBackground);
+ viewport()->setMouseTracking(false);
+ setFrameStyle( QFrame::NoFrame );
+
+ // ------------------------------------------------------------
+
+ connect(this, SIGNAL(signalZoomChanged(double)),
+ this, SLOT(slotZoomChanged(double)));
+
+ connect(d->cornerButton, SIGNAL(pressed()),
+ this, SLOT(slotCornerButtonPressed()));
+
+ connect(d->im, SIGNAL(signalModified()),
+ this, SLOT(slotModified()));
+
+ connect(d->im, SIGNAL(signalUndoStateChanged(bool, bool, bool)),
+ this, SIGNAL(signalUndoStateChanged(bool, bool, bool)));
+
+ connect(d->im, SIGNAL(signalLoadingStarted(const QString&)),
+ this, SIGNAL(signalLoadingStarted(const QString&)));
+
+ connect(d->im, SIGNAL(signalImageLoaded(const QString&, bool)),
+ this, SLOT(slotImageLoaded(const QString&, bool)));
+
+ connect(d->im, SIGNAL(signalImageSaved(const QString&, bool)),
+ this, SLOT(slotImageSaved(const QString&, bool)));
+
+ connect(d->im, SIGNAL(signalLoadingProgress(const QString&, float)),
+ this, SIGNAL(signalLoadingProgress(const QString&, float)));
+
+ connect(d->im, SIGNAL(signalSavingProgress(const QString&, float)),
+ this, SIGNAL(signalSavingProgress(const QString&, float)));
+
+ connect(this, SIGNAL(signalSelected(bool)),
+ this, 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 QString& filename, IOFileSettingsContainer *IOFileSettings)
+{
+ reset();
+
+ viewport()->setUpdatesEnabled(false);
+
+ d->im->load( filename, IOFileSettings, d->parent );
+
+ emit signalPrepareToLoad();
+}
+
+void Canvas::slotImageLoaded(const QString& 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 QString& /*filename*/)
+{
+// d->im->preload(filename);
+}
+
+/*
+These code part are unused and untested
+void Canvas::save(const QString& filename, IOFileSettingsContainer *IOFileSettings)
+{
+ d->im->save(filename, IOFileSettings);
+ emit signalSavingStarted(filename);
+}
+
+void Canvas::saveAs(const QString& filename,IOFileSettingsContainer *IOFileSettings,
+ const QString& mimeType)
+{
+ d->im->saveAs(filename, IOFileSettings, mimeType);
+ emit signalSavingStarted(filename);
+}
+*/
+
+void Canvas::saveAs(const QString& filename, IOFileSettingsContainer *IOFileSettings,
+ bool setExifOrientationTag, const QString& mimeType)
+{
+ d->im->saveAs(filename, IOFileSettings, setExifOrientationTag, mimeType);
+ emit signalSavingStarted(filename);
+}
+
+void Canvas::slotImageSaved(const QString& filePath, bool success)
+{
+ emit signalSavingFinished(filePath, success);
+}
+
+void Canvas::switchToLastSaved(const QString& newFilename)
+{
+ d->im->switchToLastSaved(newFilename);
+}
+
+void Canvas::abortSaving()
+{
+ d->im->abortSaving();
+}
+
+void Canvas::setModified()
+{
+ d->im->setModified();
+}
+
+void Canvas::readMetadataFromFile(const QString &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());
+}
+
+QString Canvas::currentImageFileFormat()
+{
+ return d->im->getImageFormat();
+}
+
+QString 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();
+}
+
+QRect Canvas::getSelectedArea()
+{
+ int x, y, w, h;
+ d->im->getSelectedArea(x, y, w, h);
+ return ( QRect(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 QMIN(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 = QMAX(xoffset, 0);
+ yoffset = QMAX(yoffset, 0);
+
+ d->pixmapRect = QRect(xoffset, yoffset, wZ, hZ);
+ }
+ else
+ {
+ d->pixmapRect = QRect(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(QResizeEvent* e)
+{
+ if (!e)
+ return;
+
+ QScrollView::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(QPaintEvent *e)
+{
+ QRect er(e->rect());
+ er = QRect(QMAX(er.x() - 1, 0),
+ QMAX(er.y() - 1, 0),
+ QMIN(er.width() + 2, contentsRect().width()),
+ QMIN(er.height() + 2, contentsRect().height()));
+
+ paintViewport(er, (d->zoom <= 1.0) ? true : false);
+}
+
+void Canvas::paintViewport(const QRect& er, bool antialias)
+{
+ QRect o_cr(viewportToContents(er.topLeft()), viewportToContents(er.bottomRight()));
+ QRect cr = o_cr;
+
+ QRegion clipRegion(er);
+ cr = d->pixmapRect.intersect(cr);
+
+ if (!cr.isEmpty() && d->im->imageValid())
+ {
+ clipRegion -= QRect(contentsToViewport(cr.topLeft()), cr.size());
+
+ QRect pr = QRect(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;
+
+ QPixmap 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)
+ {
+ QString key = QString("%1,%2").arg(i).arg(j);
+ QPixmap *pix = d->tileCache.find(key);
+
+ if (!pix)
+ {
+ if (antialias)
+ {
+ pix = new QPixmap(d->tileSize, d->tileSize);
+ d->tileCache.insert(key, pix);
+ }
+ else
+ {
+ pix = d->tileTmpPix;
+ }
+
+ if (d->im->hasAlpha())
+ {
+ QPainter 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)
+ {
+ QRect rr(d->rubber->normalize());
+ QRect 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());
+
+ QPainter p(pix);
+ p.setPen(QPen(QColor(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);
+ }
+ }
+
+ QRect r(i, j, d->tileSize, d->tileSize);
+ QRect ir = pr.intersect(r);
+ QPoint pt(contentsToViewport(QPoint(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();
+ }
+ }
+
+ QPainter painter(viewport());
+ painter.setClipRegion(clipRegion);
+ painter.fillRect(er, d->bgColor);
+ painter.end();
+}
+
+void Canvas::drawRubber()
+{
+ if (!d->rubber || !d->im->imageValid())
+ return;
+
+ QPainter p(viewport());
+ p.setRasterOp(Qt::NotROP );
+ p.setPen(QPen(Qt::color0, 1));
+ p.setBrush(NoBrush);
+
+ QRect r(d->rubber->normalize());
+ r = QRect(contentsToViewport(QPoint(r.x(), r.y())), r.size());
+
+ QPoint pnt(r.x(), r.y());
+
+ style().drawPrimitive(QStyle::PE_FocusRect, &p,
+ QRect(pnt.x(), pnt.y(), r.width(), r.height()),
+ colorGroup(), QStyle::Style_Default,
+ QStyleOption(colorGroup().base()));
+ p.end();
+}
+
+void Canvas::contentsMousePressEvent(QMouseEvent *e)
+{
+ if (!e || e->button() == Qt::RightButton)
+ return;
+
+ d->midButtonPressed = false;
+
+ if (e->button() == Qt::LeftButton)
+ {
+ if (d->ltActive || d->rtActive ||
+ d->lbActive || d->rbActive)
+ {
+ Q_ASSERT( d->rubber );
+ if (!d->rubber)
+ return;
+
+ // Set diagonally opposite corner as anchor
+
+ QRect 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() == Qt::MidButton)
+ {
+ if (visibleWidth() < d->im->width() ||
+ visibleHeight() < d->im->height())
+ {
+ viewport()->setCursor(Qt::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 QRect(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(QMouseEvent *e)
+{
+ if (!e)
+ return;
+
+ if (e->state() & Qt::MidButton)
+ {
+ if (d->midButtonPressed)
+ {
+ scrollBy(d->midButtonX - e->x(),
+ d->midButtonY - e->y());
+ }
+ }
+ else if (!viewport()->hasMouseTracking())
+ {
+ if (!d->rubber)
+ return;
+
+ if (e->state() != Qt::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;
+
+ QRect r(d->rubber->normalize());
+
+ QRect lt(r.x()-5, r.y()-5, 10, 10);
+ QRect rt(r.x()+r.width()-5, r.y()-5, 10, 10);
+ QRect lb(r.x()-5, r.y()+r.height()-5, 10, 10);
+ QRect 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(Qt::SizeFDiagCursor);
+ d->ltActive = true;
+ }
+ else if (rb.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(Qt::SizeFDiagCursor);
+ d->rbActive = true;
+ }
+ else if (lb.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(Qt::SizeBDiagCursor);
+ d->lbActive = true;
+ }
+ else if (rt.contains(e->x(), e->y()))
+ {
+ viewport()->setCursor(Qt::SizeBDiagCursor);
+ d->rtActive = true;
+ }
+ else
+ viewport()->unsetCursor();
+ }
+}
+
+void Canvas::contentsMouseReleaseEvent(QMouseEvent *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
+ QRect 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() != Qt::LeftButton)
+ {
+ viewport()->unsetCursor();
+ }
+
+ if (e->button() == Qt::RightButton)
+ {
+ emit signalRightButtonClicked();
+ }
+}
+
+void Canvas::contentsWheelEvent(QWheelEvent *e)
+{
+ e->accept();
+
+ if (e->state() & Qt::ShiftButton)
+ {
+ if (e->delta() < 0)
+ emit signalShowNextImage();
+ else if (e->delta() > 0)
+ emit signalShowPrevImage();
+ return;
+ }
+ else if (e->state() & Qt::ControlButton)
+ {
+ if (e->delta() < 0)
+ slotDecreaseZoom();
+ else if (e->delta() > 0)
+ slotIncreaseZoom();
+ return;
+ }
+
+ QScrollView::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();
+ QValueList<double> snapValues;
+ snapValues.append(0.5);
+ snapValues.append(1.0);
+ snapValues.append(fit);
+
+ qHeapSort(snapValues);
+ QValueList<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, qCopyBackward 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 = QMIN(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 QColor& 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(QStringList &titles)
+{
+ d->im->getUndoHistory(titles);
+}
+
+void Canvas::getRedoHistory(QStringList &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;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+ uchar* data = d->im->getImageSelection();
+ DImg selDImg = DImg(w, h, d->im->sixteenBit(), d->im->hasAlpha(), data);
+ delete [] data;
+
+ QImage selImg = selDImg.copyQImage();
+ QApplication::clipboard()->setData(new QImageDrag(selImg), QClipboard::Clipboard);
+ QApplication::restoreOverrideCursor ();
+}
+
+void Canvas::slotSelected()
+{
+ int x=0, y=0, w=0, h=0;
+
+ if (d->rubber && d->pressedMoved)
+ {
+ QRect sel = calcSeletedArea();
+ x = sel.x();
+ y = sel.y();
+ w = sel.width();
+ h = sel.height();
+ }
+
+ d->im->setSelectedArea(x, y, w, h);
+}
+
+QRect Canvas::calcSeletedArea()
+{
+ int x=0, y=0, w=0, h=0;
+ QRect 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 = QMIN(imageWidth(), QMAX(x, 0));
+ y = QMIN(imageHeight(), QMAX(y, 0));
+ w = QMIN(imageWidth(), QMAX(w, 0));
+ h = QMIN(imageHeight(), QMAX(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 QRect(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 KPopupFrame(this);
+ ImagePanIconWidget *pan = new ImagePanIconWidget(180, 120, d->panIconPopup);
+ d->panIconPopup->setMainWidget(pan);
+
+ QRect r((int)(contentsX() / d->zoom), (int)(contentsY() / d->zoom),
+ (int)(visibleWidth() / d->zoom), (int)(visibleHeight() / d->zoom));
+ pan->setRegionSelection(r);
+ pan->setMouseFocus();
+
+ connect(pan, SIGNAL(signalSelectionMoved(const QRect&, bool)),
+ this, SLOT(slotPanIconSelectionMoved(const QRect&, bool)));
+
+ connect(pan, SIGNAL(signalHiden()),
+ this, SLOT(slotPanIconHiden()));
+
+ QPoint g = mapToGlobal(viewport()->pos());
+ g.setX(g.x()+ viewport()->size().width());
+ g.setY(g.y()+ viewport()->size().height());
+ d->panIconPopup->popup(QPoint(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 QRect& 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 QRect(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/digikam/utilities/imageeditor/canvas/canvas.h b/digikam/utilities/imageeditor/canvas/canvas.h
new file mode 100644
index 0000000..b10ae61
--- /dev/null
+++ b/digikam/utilities/imageeditor/canvas/canvas.h
@@ -0,0 +1,208 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qscrollview.h>
+#include <qrect.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "dimg.h"
+
+class QString;
+class QStringList;
+class QPixmap;
+class QPaintEvent;
+class QResizeEvent;
+class QWheelEvent;
+class QKeyEvent;
+class QColor;
+
+namespace Digikam
+{
+
+class CanvasPrivate;
+class DImgInterface;
+class ExposureSettingsContainer;
+class ICCSettingsContainer;
+class IOFileSettingsContainer;
+
+class DIGIKAM_EXPORT Canvas : public QScrollView
+{
+ Q_OBJECT
+
+public:
+
+ Canvas(QWidget *parent=0);
+ ~Canvas();
+
+ void load(const QString& filename, IOFileSettingsContainer *IOFileSettings);
+ void preload(const QString& filename);
+
+ void saveAs(const QString& filename, IOFileSettingsContainer *IOFileSettings,
+ bool setExifOrientationTag, const QString& mimeType=QString());
+ void resetImage();
+ void switchToLastSaved(const QString& newFilename);
+ void abortSaving();
+ void setModified();
+ void readMetadataFromFile(const QString &file);
+ void clearUndoHistory();
+ void setUndoHistoryOrigin();
+ void updateUndoState();
+ DImg currentImage();
+ QString currentImageFileFormat();
+ QString 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();
+ QRect 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 QColor& 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(QStringList &titles);
+ void getRedoHistory(QStringList &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 QString &filename);
+ void signalLoadingFinished(const QString &filename, bool success);
+ void signalLoadingProgress(const QString& filePath, float progress);
+ void signalSavingStarted(const QString &filename);
+ void signalSavingFinished(const QString &filename, bool success);
+ void signalSavingProgress(const QString& filePath, float progress);
+ void signalSelectionChanged(const QRect&);
+ 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(QResizeEvent* e);
+ void viewportPaintEvent(QPaintEvent *e);
+ void contentsMousePressEvent(QMouseEvent *e);
+ void contentsMouseMoveEvent(QMouseEvent *e);
+ void contentsMouseReleaseEvent(QMouseEvent *e);
+ void contentsWheelEvent(QWheelEvent *e);
+
+private:
+
+ QRect calcSeletedArea();
+ double calcAutoZoomFactor();
+ void updateAutoZoom();
+ void updateContentsSize(bool deleteRubber);
+
+ void drawRubber();
+ void paintViewport(const QRect& er, bool antialias);
+
+ void reset();
+
+private slots:
+
+ void slotSelected();
+ void slotModified();
+ void slotImageLoaded(const QString& filePath, bool success);
+ void slotImageSaved(const QString& filePath, bool success);
+ void slotCornerButtonPressed();
+ void slotZoomChanged(double);
+ void slotPanIconSelectionMoved(const QRect&, bool);
+ void slotPanIconHiden();
+
+private:
+
+ CanvasPrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* CANVAS_H */
+
diff --git a/digikam/utilities/imageeditor/canvas/colorcorrectiondlg.cpp b/digikam/utilities/imageeditor/canvas/colorcorrectiondlg.cpp
new file mode 100644
index 0000000..098a7d7
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qlayout.h>
+#include <qframe.h>
+#include <qstring.h>
+#include <qfileinfo.h>
+#include <qpushbutton.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.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(QWidget* parent, DImg *preview,
+ IccTransform *iccTrans, const QString& file)
+ : KDialogBase(parent, "", true, QString(),
+ 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"));
+
+ QFileInfo fi(file);
+ setCaption(fi.fileName());
+
+ QWidget *page = new QWidget(this);
+ QGridLayout* grid = new QGridLayout(page, 3, 2, 0, KDialog::spacingHint());
+
+ QLabel *originalTitle = new QLabel(i18n("Original Image:"), page);
+ QLabel *previewOriginal = new QLabel(page);
+ QLabel *targetTitle = new QLabel(i18n("Corrected Image:"), page);
+ QLabel *previewTarget = new QLabel(page);
+ QLabel *logo = new QLabel(page);
+ QLabel *message = new QLabel(page);
+ QLabel *currentProfileTitle = new QLabel(i18n("Current workspace color profile:"), page);
+ QLabel *currentProfileDesc = new QLabel(QString("<b>%1</b>").arg(m_iccTrans->getOutpoutProfileDescriptor()), page);
+ QPushButton *currentProfInfo = new QPushButton(i18n("Info..."), page);
+ QLabel *embeddedProfileTitle = new QLabel(i18n("Embedded color profile:"), page);
+ QLabel *embeddedProfileDesc = new QLabel(QString("<b>%1</b>").arg(m_iccTrans->getEmbeddedProfileDescriptor()), page);
+ QPushButton *embeddedProfInfo = new QPushButton(i18n("Info..."), page);
+ KSeparator *line = new KSeparator (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));
+ KIconLoader* iconLoader = KApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", KIcon::NoGroup, 128, KIcon::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);
+
+ QVBoxLayout *vlay = new QVBoxLayout( KDialog::spacingHint() );
+ vlay->addWidget(logo);
+ vlay->addWidget(message);
+
+ vlay->addWidget(new KSeparator (Horizontal, page));
+ vlay->addWidget(currentProfileTitle);
+ vlay->addWidget(currentProfileDesc);
+
+ QHBoxLayout *hlay1 = new QHBoxLayout( KDialog::spacingHint() );
+ hlay1->addWidget(currentProfInfo);
+ hlay1->addStretch();
+ vlay->addLayout(hlay1);
+
+ vlay->addWidget(line);
+ vlay->addWidget(embeddedProfileTitle);
+ vlay->addWidget(embeddedProfileDesc);
+
+ QHBoxLayout *hlay2 = new QHBoxLayout( KDialog::spacingHint() );
+ hlay2->addWidget(embeddedProfInfo);
+ hlay2->addStretch();
+ vlay->addLayout(hlay2);
+ vlay->addStretch();
+
+ grid->addMultiCell(new QSpacerItem(KDialog::spacingHint(), KDialog::spacingHint(),
+ QSizePolicy::Minimum, QSizePolicy::Expanding), 0, 3, 1, 1);
+ grid->addMultiCellLayout(vlay, 0, 3, 2, 2);
+
+ setMainWidget(page);
+
+ // --------------------------------------------------------------------
+
+ connect(currentProfInfo, SIGNAL(clicked()),
+ this, SLOT(slotCurrentProfInfo()) );
+
+ connect(embeddedProfInfo, SIGNAL(clicked()),
+ this, SLOT(slotEmbeddedProfInfo()) );
+
+ connect(this, SIGNAL(applyClicked()),
+ this, SLOT(slotApplyClicked()));
+}
+
+ColorCorrectionDlg::~ColorCorrectionDlg()
+{
+}
+
+void ColorCorrectionDlg::slotCurrentProfInfo()
+{
+ if (m_iccTrans->outputProfile().isEmpty())
+ return;
+
+ ICCProfileInfoDlg infoDlg(m_parent, QString(), m_iccTrans->outputProfile());
+ infoDlg.exec();
+}
+
+void ColorCorrectionDlg::slotEmbeddedProfInfo()
+{
+ if (m_iccTrans->embeddedProfile().isEmpty())
+ return;
+
+ ICCProfileInfoDlg infoDlg(m_parent, QString(), m_iccTrans->embeddedProfile());
+ infoDlg.exec();
+}
+
+void ColorCorrectionDlg::slotApplyClicked()
+{
+ DDebug() << "colorcorrectiondlg: Apply pressed" << endl;
+ done(-1);
+}
+
+} // NameSpace Digikam
+
diff --git a/digikam/utilities/imageeditor/canvas/colorcorrectiondlg.h b/digikam/utilities/imageeditor/canvas/colorcorrectiondlg.h
new file mode 100644
index 0000000..1be5134
--- /dev/null
+++ b/digikam/utilities/imageeditor/canvas/colorcorrectiondlg.h
@@ -0,0 +1,71 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class IccTransform;
+class DImg;
+
+class DIGIKAM_EXPORT ColorCorrectionDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ ColorCorrectionDlg(QWidget *parent, DImg *preview,
+ IccTransform *iccTrans, const QString& file);
+ ~ColorCorrectionDlg();
+
+private slots:
+
+ void slotCurrentProfInfo();
+ void slotEmbeddedProfInfo();
+ void slotApplyClicked();
+
+private:
+
+ QWidget *m_parent;
+
+ IccTransform *m_iccTrans;
+};
+
+} // Namespace Digikam
+
+#endif /* COLORCORRECTIONDLG_H */
diff --git a/digikam/utilities/imageeditor/canvas/dimginterface.cpp b/digikam/utilities/imageeditor/canvas/dimginterface.cpp
new file mode 100644
index 0000000..a713662
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qwidget.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qcolor.h>
+#include <qfile.h>
+#include <qvariant.h>
+
+// KDE includes.
+
+#include <kcursor.h>
+#include <kmessagebox.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.
+ QWidget *parent;
+
+ QString filename;
+ QString 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()
+ : QObject()
+{
+ d = new DImgInterfacePrivate;
+
+ d->undoMan = new UndoManager(this);
+ d->thread = new SharedLoadSaveThread;
+
+ connect( d->thread, SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg&)),
+ this, SLOT(slotImageLoaded(const LoadingDescription &, const DImg&)) );
+
+ connect( d->thread, SIGNAL(signalImageSaved(const QString&, bool)),
+ this, SLOT(slotImageSaved(const QString&, bool)) );
+
+ connect( d->thread, SIGNAL(signalLoadingProgress(const LoadingDescription &, float)),
+ this, SLOT(slotLoadingProgress(const LoadingDescription &, float)) );
+
+ connect( d->thread, SIGNAL(signalSavingProgress(const QString&, float)),
+ this, SLOT(slotSavingProgress(const QString&, float)) );
+}
+
+DImgInterface::~DImgInterface()
+{
+ delete d->undoMan;
+ delete d->thread;
+ delete d;
+ if (m_defaultInterface == this)
+ m_defaultInterface = 0;
+}
+
+void DImgInterface::load(const QString& filename, IOFileSettingsContainer *iofileSettings,
+ QWidget *parent)
+{
+ // store here in case filename == d->fileName, and is then reset by resetValues
+ QString 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, SIGNAL(okClicked()),
+ this, SLOT(slotUseRawImportSettings()));
+
+ connect(rawImport, SIGNAL(cancelClicked()),
+ this, 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 = QString();
+ 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 QString &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() == QString("RAW"))
+ d->rotatedOrFlipped = true;
+
+ if (d->exifOrient &&
+ (d->image.attribute("format").toString() == QString("JPEG") ||
+ d->image.attribute("format").toString() == QString("PNG") ||
+ d->image.attribute("format").toString() == QString("TIFF")))
+ exifRotate(d->filename);
+
+ if (d->cmSettings->enableCMSetting)
+ {
+ if (QFile::exists(d->cmSettings->workspaceSetting))
+ {
+ IccTransform trans;
+ QByteArray 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(QFile::encodeName(d->cmSettings->inputSetting),
+ QFile::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,
+ QFile::exists(d->cmSettings->inputSetting));
+
+ d->image.getICCProfilFromFile(QFile::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, QSize::ScaleMin);
+ trans.setProfiles(QFile::encodeName(d->cmSettings->inputSetting),
+ QFile::encodeName(d->cmSettings->workspaceSetting));
+ ColorCorrectionDlg dlg(d->parent, &preview, &trans, fileName);
+
+ switch (dlg.exec())
+ {
+ case QDialog::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,
+ QFile::exists(d->cmSettings->inputSetting));
+
+ d->image.getICCProfilFromFile(QFile::encodeName(d->cmSettings->workspaceSetting));
+ if (d->parent) d->parent->unsetCursor();
+ break;
+ case -1:
+ if (d->parent) d->parent->setCursor( KCursor::waitCursor() );
+ d->image.getICCProfilFromFile(QFile::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(QFile::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, QSize::ScaleMin);
+ trans.setProfiles(QFile::encodeName(d->cmSettings->workspaceSetting));
+ ColorCorrectionDlg dlg(d->parent, &preview, &trans, fileName);
+
+ switch (dlg.exec())
+ {
+ case QDialog::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(QFile::encodeName(d->cmSettings->workspaceSetting));
+ if (d->parent) d->parent->unsetCursor();
+ break;
+ case -1:
+ if (d->parent) d->parent->setCursor( KCursor::waitCursor() );
+ d->image.getICCProfilFromFile(QFile::encodeName(d->cmSettings->workspaceSetting));
+ if (d->parent) d->parent->unsetCursor();
+ DDebug() << "dimginterface.cpp: Apply pressed" << endl;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ QString 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 QString& 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 QString& 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;
+
+ QString currentMimeType(QImageIO::imageFormat(d->filename));
+
+ d->needClearUndoManager = true;
+
+ saveAction(file, iofileSettings, currentMimeType);
+}
+*/
+
+void DImgInterface::saveAs(const QString& fileName, IOFileSettingsContainer *iofileSettings,
+ bool setExifOrientationTag, const QString& 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.
+ QString mimeType = givenMimeType;
+
+ // This is possibly empty
+ if (mimeType.isEmpty())
+ mimeType = getImageFormat();
+
+ DDebug() << "Saving to :" << QFile::encodeName(fileName).data() << " ("
+ << mimeType << ")" << endl;
+
+ // JPEG file format.
+ if ( mimeType.upper() == QString("JPG") || mimeType.upper() == QString("JPEG") ||
+ mimeType.upper() == QString("JPE"))
+ {
+ d->image.setAttribute("quality", iofileSettings->JPEGCompression);
+ d->image.setAttribute("subsampling", iofileSettings->JPEGSubSampling);
+ }
+
+ // PNG file format.
+ if ( mimeType.upper() == QString("PNG") )
+ d->image.setAttribute("quality", iofileSettings->PNGCompression);
+
+ // TIFF file format.
+ if ( mimeType.upper() == QString("TIFF") || mimeType.upper() == QString("TIF") )
+ d->image.setAttribute("compress", iofileSettings->TIFFCompression);
+
+ // JPEG 2000 file format.
+ if ( mimeType.upper() == QString("JP2") || mimeType.upper() == QString("JPX") ||
+ mimeType.upper() == QString("JPC") || mimeType.upper() == QString("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.
+
+ QImage preview = d->image.smoothScale(1280, 1024, QSize::ScaleMin).copyQImage();
+
+ if ( mimeType.upper() != QString("JPG") && mimeType.upper() != QString("JPEG") &&
+ mimeType.upper() != QString("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.
+ QImage thumb = preview.smoothScale(160, 120, QImage::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 QString& filePath, bool success)
+{
+ if (filePath != d->savingFilename)
+ return;
+
+ if (!success)
+ DWarning() << "error saving image '" << QFile::encodeName(filePath).data() << endl;
+
+ emit signalImageSaved(filePath, success);
+ emit signalUndoStateChanged(d->undoMan->anyMoreUndo(), d->undoMan->anyMoreRedo(), !d->undoMan->isAtOrigin());
+}
+
+void DImgInterface::slotSavingProgress(const QString& 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 QString& 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.
+ QString 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 QString &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(QPaintDevice* 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)
+ {
+ QPixmap pix(img.convertToPixmap(&d->monitorICCtrans));
+ bitBlt(p, dx, dy, &pix, 0, 0);
+ }
+ else
+ {
+ QPixmap pix(img.convertToPixmap());
+ bitBlt(p, dx, dy, &pix, 0, 0);
+ }
+
+ // Show the Over/Under exposure pixels indicators
+
+ if (d->expoSettings->underExposureIndicator || d->expoSettings->overExposureIndicator)
+ {
+ QImage pureColorMask = d->image.copy(sx, sy, sw, sh).pureColorMask(d->expoSettings);
+ QPixmap pixMask(pureColorMask.scale(dw, dh));
+ bitBlt(p, dx, dy, &pixMask, 0, 0);
+ }
+}
+
+void DImgInterface::paintOnDevice(QPaintDevice* 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)
+ {
+ QPixmap pix(img.convertToPixmap(&d->monitorICCtrans));
+ bitBlt(p, dx, dy, &pix, 0, 0);
+ }
+ else
+ {
+ QPixmap pix(img.convertToPixmap());
+ bitBlt(p, dx, dy, &pix, 0, 0);
+ }
+
+ // Show the Over/Under exposure pixels indicators
+
+ if (d->expoSettings->underExposureIndicator || d->expoSettings->overExposureIndicator)
+ {
+ QImage pureColorMask = d->image.copy(sx, sy, sw, sh).pureColorMask(d->expoSettings);
+ QPixmap 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 QString &caller, uchar* data, int w, int h)
+{
+ putImage(caller, data, w, h, d->image.sixteenBit());
+}
+
+void DImgInterface::putImage(const QString &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( QString profilePath)
+{
+ if (d->image.isNull())
+ {
+ DWarning() << k_funcinfo << "d->image is NULL" << endl;
+ return;
+ }
+
+ DDebug() << k_funcinfo << "Embedding profile: " << profilePath << endl;
+ d->image.getICCProfilFromFile( QFile::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 QString &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(QStringList &titles)
+{
+ d->undoMan->getUndoHistory(titles);
+}
+
+void DImgInterface::getRedoHistory(QStringList &titles)
+{
+ d->undoMan->getRedoHistory(titles);
+}
+
+QByteArray DImgInterface::getEmbeddedICC()
+{
+ return d->image.getICCProfil();
+}
+
+QByteArray DImgInterface::getExif()
+{
+ return d->image.getExif();
+}
+
+QByteArray DImgInterface::getIptc()
+{
+ return d->image.getIptc();
+}
+
+QString DImgInterface::getImageFilePath()
+{
+ return d->filename;
+}
+
+QString DImgInterface::getImageFileName()
+{
+ return d->filename.section( '/', -1 );
+}
+
+QString DImgInterface::getImageFormat()
+{
+ if (d->image.isNull())
+ return QString();
+
+ QString 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 = QImageIO::imageFormat(d->filename);
+ }
+ return mimeType;
+}
+
+ICCSettingsContainer* DImgInterface::getICCSettings()
+{
+ return d->cmSettings;
+}
+
+QPixmap DImgInterface::convertToPixmap(DImg& img)
+{
+ if (d->cmSettings->enableCMSetting && d->cmSettings->managedViewSetting)
+ return img.convertToPixmap(&d->monitorICCtrans);
+
+ return img.convertToPixmap();
+}
+
+QColor DImgInterface::underExposureColor()
+{
+ return d->expoSettings->underExposureColor;
+}
+
+QColor DImgInterface::overExposureColor()
+{
+ return d->expoSettings->overExposureColor;
+}
+
+} // namespace Digikam
+
diff --git a/digikam/utilities/imageeditor/canvas/dimginterface.h b/digikam/utilities/imageeditor/canvas/dimginterface.h
new file mode 100644
index 0000000..2de684d
--- /dev/null
+++ b/digikam/utilities/imageeditor/canvas/dimginterface.h
@@ -0,0 +1,199 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qstring.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "dimg.h"
+
+class QWidget;
+class QPixmap;
+
+namespace Digikam
+{
+
+class ICCSettingsContainer;
+class ExposureSettingsContainer;
+class IOFileSettingsContainer;
+class LoadingDescription;
+class DImgInterfacePrivate;
+
+class DIGIKAM_EXPORT DImgInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ static DImgInterface* defaultInterface();
+ static void setDefaultInterface(DImgInterface *defaultInterface);
+
+ DImgInterface();
+ ~DImgInterface();
+
+ void load(const QString& filename, IOFileSettingsContainer *iofileSettings, QWidget *parent=0);
+
+ void setICCSettings(ICCSettingsContainer *cmSettings);
+ void setExposureSettings(ExposureSettingsContainer *expoSettings);
+ void setExifOrient(bool exifOrient);
+
+ void undo();
+ void redo();
+ void restore();
+
+ void saveAs(const QString& file, IOFileSettingsContainer *iofileSettings,
+ bool setExifOrientationTag, const QString& mimeType=QString());
+
+ void switchToLastSaved(const QString& newFilename);
+ void abortSaving();
+ void setModified();
+ void readMetadataFromFile(const QString &file);
+ void clearUndoManager();
+ void setUndoManagerOrigin();
+ void updateUndoState();
+ void resetImage();
+
+ void zoom(double val);
+
+ void paintOnDevice(QPaintDevice* p,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh,
+ int antialias);
+ void paintOnDevice(QPaintDevice* 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(QStringList &titles);
+ void getRedoHistory(QStringList &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 QString &caller, uchar* data, int w, int h);
+ void putImage(const QString &caller, uchar* data, int w, int h, bool sixteenBit);
+
+ uchar* getImageSelection();
+ void putImageSelection(const QString &caller, uchar* data);
+
+ void setEmbeddedICCToOriginalImage( QString profilePath);
+
+ /** Convert a DImg image to a pixmap for screen using color
+ managemed view if necessary */
+ QPixmap convertToPixmap(DImg& img);
+
+ QByteArray getEmbeddedICC();
+ QByteArray getExif();
+ QByteArray getIptc();
+
+ ICCSettingsContainer *getICCSettings();
+
+ QString getImageFileName();
+ QString getImageFilePath();
+ QString getImageFormat();
+
+ QColor underExposureColor();
+ QColor overExposureColor();
+
+protected slots:
+
+ void slotImageLoaded(const LoadingDescription &loadingDescription, const DImg& img);
+ void slotImageSaved(const QString& filePath, bool success);
+ void slotLoadingProgress(const LoadingDescription &loadingDescription, float progress);
+ void slotSavingProgress(const QString& filePath, float progress);
+
+signals:
+
+ void signalModified();
+ void signalUndoStateChanged(bool moreUndo, bool moreRedo, bool canSave);
+ void signalLoadingStarted(const QString& filename);
+ void signalLoadingProgress(const QString& filePath, float progress);
+ void signalImageLoaded(const QString& filePath, bool success);
+ void signalSavingProgress(const QString& filePath, float progress);
+ void signalImageSaved(const QString& filePath, bool success);
+
+private slots:
+
+ void slotUseRawImportSettings();
+ void slotUseDefaultSettings();
+
+private:
+
+ void exifRotate(const QString& filename);
+ void resetValues();
+
+private:
+
+ static DImgInterface *m_defaultInterface;
+
+ DImgInterfacePrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* DIMGINTERFACE_H */
diff --git a/digikam/utilities/imageeditor/canvas/iccsettingscontainer.h b/digikam/utilities/imageeditor/canvas/iccsettingscontainer.h
new file mode 100644
index 0000000..78d98bf
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.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 = QString();
+ monitorSetting = QString();
+ inputSetting = QString();
+ proofSetting = QString();
+ };
+
+ ~ICCSettingsContainer(){};
+
+public:
+
+ bool enableCMSetting;
+
+ // FALSE -> apply
+ // TRUE -> ask
+ bool askOrApplySetting;
+ bool BPCSetting;
+ bool managedViewSetting;
+
+ int renderingSetting;
+
+ QString workspaceSetting;
+ QString monitorSetting;
+ QString inputSetting;
+ QString proofSetting;
+};
+
+} // namespace Digikam
+
+#endif // ICCSETTINGSCONTAINER_H
diff --git a/digikam/utilities/imageeditor/canvas/imageplugin.cpp b/digikam/utilities/imageeditor/canvas/imageplugin.cpp
new file mode 100644
index 0000000..8f44332
--- /dev/null
+++ b/digikam/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(QObject *parent, const char* name)
+ : QObject(parent, name)
+{
+}
+
+ImagePlugin::~ImagePlugin()
+{
+}
+
+void ImagePlugin::setEnabledSelectionActions(bool)
+{
+}
+
+void ImagePlugin::setEnabledActions(bool)
+{
+}
+
+void ImagePlugin::loadTool(EditorTool* tool)
+{
+ EditorToolIface::editorToolIface()->loadTool(tool);
+
+ connect(tool, SIGNAL(okClicked()),
+ this, SLOT(slotToolDone()));
+
+ connect(tool, SIGNAL(cancelClicked()),
+ this, SLOT(slotToolDone()));
+}
+
+void ImagePlugin::slotToolDone()
+{
+ EditorToolIface::editorToolIface()->unLoadTool();
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/imageeditor/canvas/imageplugin.h b/digikam/utilities/imageeditor/canvas/imageplugin.h
new file mode 100644
index 0000000..7982b52
--- /dev/null
+++ b/digikam/utilities/imageeditor/canvas/imageplugin.h
@@ -0,0 +1,69 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+
+// KDE includes.
+
+#include <kxmlguiclient.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class QWidget;
+
+namespace Digikam
+{
+
+class EditorTool;
+
+class DIGIKAM_EXPORT ImagePlugin : public QObject, public KXMLGUIClient
+{
+ Q_OBJECT
+
+public:
+
+ ImagePlugin(QObject *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/digikam/utilities/imageeditor/canvas/imagepluginloader.cpp b/digikam/utilities/imageeditor/canvas/imagepluginloader.cpp
new file mode 100644
index 0000000..fc5f49c
--- /dev/null
+++ b/digikam/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 <kparts/componentfactory.h>
+#include <kapplication.h>
+#include <klocale.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 QPair<QString, ImagePlugin*> PluginType;
+ typedef QValueList< PluginType > PluginList;
+
+public:
+
+ ImagePluginLoaderPrivate()
+ {
+ splash = 0;
+
+ for (int i=0 ; QString(ObsoleteImagePluginsList[i]) != QString("-1") ; i++)
+ obsoleteImagePluginsList << ObsoleteImagePluginsList[i];
+ }
+
+ QStringList obsoleteImagePluginsList;
+
+ SplashScreen *splash;
+
+ PluginList pluginList;
+};
+
+ImagePluginLoader* ImagePluginLoader::m_instance=0;
+
+ImagePluginLoader* ImagePluginLoader::instance()
+{
+ return m_instance;
+}
+
+ImagePluginLoader::ImagePluginLoader(QObject *parent, SplashScreen *splash)
+ : QObject(parent)
+{
+ m_instance = this;
+ d = new ImagePluginLoaderPrivate;
+ d->splash = splash;
+
+ QStringList imagePluginsList2Load;
+
+ KTrader::OfferList offers = KTrader::self()->query("Digikam/ImagePlugin");
+ KTrader::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 QStringList& list)
+{
+ if (d->splash)
+ d->splash->message(i18n("Loading Image Plugins"));
+
+ KTrader::OfferList offers = KTrader::self()->query("Digikam/ImagePlugin");
+ KTrader::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 QString& 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 QString& libraryName)
+{
+ KTrader::OfferList offers = KTrader::self()->query("Digikam/ImagePlugin");
+ KTrader::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 QString& libraryName)
+{
+ KTrader::OfferList offers = KTrader::self()->query("Digikam/ImagePlugin");
+ KTrader::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;
+}
+
+QPtrList<ImagePlugin> ImagePluginLoader::pluginList()
+{
+ QPtrList<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/digikam/utilities/imageeditor/canvas/imagepluginloader.h b/digikam/utilities/imageeditor/canvas/imagepluginloader.h
new file mode 100644
index 0000000..24e035e
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qpair.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "imageplugin.h"
+
+namespace Digikam
+{
+
+class SplashScreen;
+class ImagePluginLoaderPrivate;
+
+class DIGIKAM_EXPORT ImagePluginLoader : public QObject
+{
+
+public:
+
+ ImagePluginLoader(QObject *parent, SplashScreen *splash=0);
+ ~ImagePluginLoader();
+
+ static ImagePluginLoader* instance();
+
+ QPtrList<ImagePlugin> pluginList();
+ void loadPluginsFromList(const QStringList& list);
+
+ // Return true if plugin library is loaded in memory.
+ // 'libraryName' is internal plugin library name not i18n.
+ bool pluginLibraryIsLoaded(const QString& libraryName);
+
+ ImagePlugin* pluginInstance(const QString& libraryName);
+
+private:
+
+ ImagePlugin* pluginIsLoaded(const QString& name);
+
+private:
+
+ static ImagePluginLoader *m_instance;
+
+ ImagePluginLoaderPrivate *d;
+};
+
+} // namespace Digikam
+
+#endif /* IMAGEPLUGINLOADER_H */
diff --git a/digikam/utilities/imageeditor/canvas/iofilesettingscontainer.h b/digikam/utilities/imageeditor/canvas/iofilesettingscontainer.h
new file mode 100644
index 0000000..360299b
--- /dev/null
+++ b/digikam/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/digikam/utilities/imageeditor/canvas/undoaction.cpp b/digikam/utilities/imageeditor/canvas/undoaction.cpp
new file mode 100644
index 0000000..b75d18a
--- /dev/null
+++ b/digikam/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()
+{
+}
+
+QString 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 == Horizontal)
+ m_title = i18n("Flip Horizontal");
+ else if(m_dir == Vertical)
+ m_title = i18n("Flip Vertical");
+}
+
+UndoActionFlip::~UndoActionFlip()
+{
+}
+
+void UndoActionFlip::rollBack()
+{
+ switch(m_dir)
+ {
+ case(Horizontal):
+ m_iface->flipHoriz(false);
+ return;
+ case(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 QString &title)
+ : UndoAction(iface)
+{
+ m_title = title;
+}
+
+UndoActionIrreversible::~UndoActionIrreversible()
+{
+}
+
+void UndoActionIrreversible::rollBack()
+{
+}
+
+void UndoActionIrreversible::execute()
+{
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/imageeditor/canvas/undoaction.h b/digikam/utilities/imageeditor/canvas/undoaction.h
new file mode 100644
index 0000000..f3b6562
--- /dev/null
+++ b/digikam/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 <klocale.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;
+
+ QString getTitle() const;
+
+protected:
+
+ DImgInterface *m_iface;
+ QString 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 QString &caller=i18n("Unknown"));
+ ~UndoActionIrreversible();
+
+ void rollBack();
+ void execute();
+};
+
+} // namespace Digikam
+
+#endif /* UNDOACTION_H */
diff --git a/digikam/utilities/imageeditor/canvas/undocache.cpp b/digikam/utilities/imageeditor/canvas/undocache.cpp
new file mode 100644
index 0000000..972ff34
--- /dev/null
+++ b/digikam/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>
+}
+
+// Qt includes.
+
+#include <qcstring.h>
+#include <qstring.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qstringlist.h>
+
+// KDE includes.
+
+#include <kstandarddirs.h>
+#include <kaboutdata.h>
+#include <kinstance.h>
+#include <kglobal.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "undocache.h"
+
+namespace Digikam
+{
+
+class UndoCachePriv
+{
+public:
+
+ QString cachePrefix;
+ QStringList cacheFilenames;
+};
+
+UndoCache::UndoCache()
+{
+ d = new UndoCachePriv;
+
+ QString cacheDir;
+ cacheDir = locateLocal("cache",
+ KGlobal::instance()->aboutData()->programName() + '/');
+
+ d->cachePrefix = QString("%1undocache-%2")
+ .arg(cacheDir)
+ .arg(getpid());
+}
+
+UndoCache::~UndoCache()
+{
+ clear();
+ delete d;
+}
+
+/**
+ * delete all cache files
+ */
+void UndoCache::clear()
+{
+ for (QStringList::iterator it = d->cacheFilenames.begin();
+ it != d->cacheFilenames.end(); ++it)
+ {
+ ::unlink(QFile::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)
+{
+ QString cacheFile = QString("%1-%2.bin")
+ .arg(d->cachePrefix)
+ .arg(level);
+
+ QFile file(cacheFile);
+
+ if (file.exists() || !file.open(IO_WriteOnly))
+ return false;
+
+ QDataStream ds(&file);
+ ds << w;
+ ds << h;
+ ds << bytesDepth;
+
+ QByteArray 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)
+{
+ QString cacheFile = QString("%1-%2.bin")
+ .arg(d->cachePrefix)
+ .arg(level);
+
+ QFile file(cacheFile);
+ if (!file.open(IO_ReadOnly))
+ return 0;
+
+ QDataStream ds(&file);
+ ds >> w;
+ ds >> h;
+ ds >> bytesDepth;
+
+ uchar *data = new uchar[w*h*bytesDepth];
+ if (!data)
+ return 0;
+
+ QByteArray ba(w*h*bytesDepth);
+ ds >> ba;
+ memcpy (data, ba.data(), w*h*bytesDepth);
+
+ file.close();
+
+ if(del)
+ {
+ ::unlink(QFile::encodeName(cacheFile));
+ d->cacheFilenames.remove(cacheFile);
+ }
+
+ return data;
+}
+
+/**
+ * delete a cache file
+ */
+void UndoCache::erase(int level)
+{
+ QString cacheFile = QString("%1-%2.bin")
+ .arg(d->cachePrefix)
+ .arg(level);
+
+ if(d->cacheFilenames.find(cacheFile) == d->cacheFilenames.end())
+ return;
+
+ ::unlink(QFile::encodeName(cacheFile));
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/imageeditor/canvas/undocache.h b/digikam/utilities/imageeditor/canvas/undocache.h
new file mode 100644
index 0000000..2954c30
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qglobal.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/digikam/utilities/imageeditor/canvas/undomanager.cpp b/digikam/utilities/imageeditor/canvas/undomanager.cpp
new file mode 100644
index 0000000..25525dd
--- /dev/null
+++ b/digikam/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;
+ }
+
+ QValueList<UndoAction*> undoActions;
+ QValueList<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;
+ QValueList<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;
+ QValueList<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(QStringList &titles)
+{
+ QValueList<UndoAction*>::iterator it;
+
+ for(it = d->undoActions.begin(); it != d->undoActions.end(); ++it)
+ {
+ titles.push_front((*it)->getTitle());
+ }
+}
+
+void UndoManager::getRedoHistory(QStringList &titles)
+{
+ QValueList<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/digikam/utilities/imageeditor/canvas/undomanager.h b/digikam/utilities/imageeditor/canvas/undomanager.h
new file mode 100644
index 0000000..4a633d5
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstringlist.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(QStringList &titles);
+ void getRedoHistory(QStringList &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/digikam/utilities/imageeditor/editor/Makefile.am b/digikam/utilities/imageeditor/editor/Makefile.am
new file mode 100644
index 0000000..b9fad07
--- /dev/null
+++ b/digikam/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_KDEPRINT)
+
+libdimgeditor_la_LIBADD = $(top_builddir)/digikam/utilities/imageeditor/tools/libdimgeditortools.la \
+ $(top_builddir)/digikam/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_KDEPRINT)
+
+libshowfoto_la_LIBADD = $(top_builddir)/digikam/libs/dimg/libdimg.la \
+ $(top_builddir)/digikam/libs/dialogs/libdialogshowfoto.la \
+ $(top_builddir)/digikam/libs/widgets/libwidgets.la \
+ $(top_builddir)/digikam/libs/greycstoration/libgreycstoration.la \
+ $(top_builddir)/digikam/utilities/imageeditor/canvas/libdimgcanvas.la \
+ $(top_builddir)/digikam/utilities/imageeditor/tools/libdimgeditortools.la \
+ $(top_builddir)/digikam/utilities/imageeditor/rawimport/librawimport.la
+
+INCLUDES = -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/libs/widgets/common \
+ -I$(top_srcdir)/digikam/libs/widgets/imageplugins \
+ -I$(top_srcdir)/digikam/libs/dialogs \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/themeengine \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/dimg/filters \
+ -I$(top_srcdir)/digikam/libs/imageproperties \
+ -I$(top_srcdir)/digikam/libs/threadimageio \
+ -I$(top_srcdir)/digikam/utilities/setup \
+ -I$(top_srcdir)/digikam/utilities/slideshow \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/canvas \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/tools \
+ -I$(top_builddir)/digikam/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/digikam/utilities/imageeditor/editor/digikamimageplugin.desktop b/digikam/utilities/imageeditor/editor/digikamimageplugin.desktop
new file mode 100644
index 0000000..4b8ffa4
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/digikamimageplugin.desktop
@@ -0,0 +1,39 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=ServiceType
+X-KDE-ServiceType=Digikam/ImagePlugin
+X-KDE-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/digikam/utilities/imageeditor/editor/digikamimagewindowui.rc b/digikam/utilities/imageeditor/editor/digikamimagewindowui.rc
new file mode 100644
index 0000000..2c0314a
--- /dev/null
+++ b/digikam/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/digikam/utilities/imageeditor/editor/editorstackview.cpp b/digikam/utilities/imageeditor/editor/editorstackview.cpp
new file mode 100644
index 0000000..7258afd
--- /dev/null
+++ b/digikam/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;
+ }
+
+ QWidget *toolView;
+ Canvas *canvas;
+};
+
+EditorStackView::EditorStackView(QWidget *parent)
+ : QWidgetStack(parent, 0, Qt::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, SIGNAL(signalZoomChanged(double)),
+ this, SLOT(slotZoomChanged(double)));
+}
+
+Canvas* EditorStackView::canvas() const
+{
+ return d->canvas;
+}
+
+void EditorStackView::setToolView(QWidget* view)
+{
+ if (d->toolView)
+ removeWidget(d->toolView);
+
+ d->toolView = view;
+
+ if (d->toolView)
+ addWidget(d->toolView, ToolViewMode);
+
+ PreviewWidget *preview = previewWidget();
+ if (preview)
+ {
+ connect(preview, SIGNAL(signalZoomFactorChanged(double)),
+ this, SLOT(slotZoomChanged(double)));
+ }
+}
+
+QWidget* 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/digikam/utilities/imageeditor/editor/editorstackview.h b/digikam/utilities/imageeditor/editor/editorstackview.h
new file mode 100644
index 0000000..6f34a89
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/editorstackview.h
@@ -0,0 +1,96 @@
+/* ============================================================
+ *
+ * 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 <qwidgetstack.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class PreviewWidget;
+class Canvas;
+class EditorStackViewPriv;
+
+class DIGIKAM_EXPORT EditorStackView : public QWidgetStack
+{
+Q_OBJECT
+
+public:
+
+ enum StackViewMode
+ {
+ CanvasMode=0,
+ ToolViewMode
+ };
+
+public:
+
+ EditorStackView(QWidget *parent=0);
+ ~EditorStackView();
+
+ void setCanvas(Canvas* canvas);
+ Canvas *canvas() const;
+
+ void setToolView(QWidget* view);
+ QWidget *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/digikam/utilities/imageeditor/editor/editortool.cpp b/digikam/utilities/imageeditor/editor/editortool.cpp
new file mode 100644
index 0000000..2b4761d
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qwidget.h>
+#include <qtimer.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;
+ }
+
+ QString helpAnchor;
+ QString name;
+
+ QWidget *view;
+
+ QPixmap icon;
+
+ QTimer *timer;
+
+ EditorToolSettings *settings;
+};
+
+EditorTool::EditorTool(QObject *parent)
+ : QObject(parent)
+{
+ d = new EditorToolPriv;
+ d->timer = new QTimer(this);
+
+ connect(d->timer, SIGNAL(timeout()),
+ this, SLOT(slotEffect()));
+}
+
+EditorTool::~EditorTool()
+{
+ delete d;
+}
+
+void EditorTool::init()
+{
+ QTimer::singleShot(0, this, SLOT(slotInit()));
+}
+
+QPixmap EditorTool::toolIcon() const
+{
+ return d->icon;
+}
+
+void EditorTool::setToolIcon(const QPixmap& icon)
+{
+ d->icon = icon;
+}
+
+QString EditorTool::toolName() const
+{
+ return d->name;
+}
+
+void EditorTool::setToolName(const QString& name)
+{
+ d->name = name;
+}
+
+QWidget* EditorTool::toolView() const
+{
+ return d->view;
+}
+
+void EditorTool::setToolView(QWidget *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, SIGNAL(signalOkClicked()),
+ this, SLOT(slotOk()));
+
+ connect(d->settings, SIGNAL(signalCancelClicked()),
+ this, SLOT(slotCancel()));
+
+ connect(d->settings, SIGNAL(signalDefaultClicked()),
+ this, SLOT(slotResetSettings()));
+
+ connect(d->settings, SIGNAL(signalSaveAsClicked()),
+ this, SLOT(slotSaveAsSettings()));
+
+ connect(d->settings, SIGNAL(signalLoadClicked()),
+ this, SLOT(slotLoadSettings()));
+
+ connect(d->settings, SIGNAL(signalTryClicked()),
+ this, 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 QString& anchor)
+{
+ d->helpAnchor = anchor;
+ // TODO: use this anchor with editor Help menu
+}
+
+QString EditorTool::toolHelp() const
+{
+ if (d->helpAnchor.isEmpty())
+ return (name() + QString(".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;
+
+ QString progressMess;
+
+ DImgThreadedFilter *threadedFilter;
+};
+
+EditorToolThreaded::EditorToolThreaded(QObject *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 QString& 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();
+ }
+
+ QTimer::singleShot(0, this, 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(QCustomEvent *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(QWidget *view)
+{
+ EditorTool::setToolView(view);
+
+ if (dynamic_cast<ImageWidget*>(view) || dynamic_cast<ImageGuideWidget*>(view) ||
+ dynamic_cast<ImagePanelWidget*>(view))
+ {
+ connect(view, SIGNAL(signalResized()),
+ this, 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/digikam/utilities/imageeditor/editor/editortool.h b/digikam/utilities/imageeditor/editor/editortool.h
new file mode 100644
index 0000000..e54681c
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/editortool.h
@@ -0,0 +1,162 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qpixmap.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class DImgThreadedFilter;
+class EditorToolSettings;
+class EditorToolPriv;
+
+class DIGIKAM_EXPORT EditorTool : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ EditorTool(QObject *parent);
+ virtual ~EditorTool();
+
+ void init();
+
+ QString toolHelp() const;
+ QString toolName() const;
+ QPixmap toolIcon() const;
+ QWidget* toolView() const;
+ EditorToolSettings* toolSettings() const;
+
+signals:
+
+ void okClicked();
+ void cancelClicked();
+
+protected:
+
+ void setToolHelp(const QString& anchor);
+ void setToolName(const QString& name);
+ void setToolIcon(const QPixmap& icon);
+
+ virtual void setToolView(QWidget *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
+{
+ Q_OBJECT
+
+public:
+
+ enum RenderingMode
+ {
+ NoneRendering=0,
+ PreviewRendering,
+ FinalRendering
+ };
+
+public:
+
+ EditorToolThreaded(QObject *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 QString& 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(QCustomEvent *event);
+
+ virtual void setToolView(QWidget *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/digikam/utilities/imageeditor/editor/editortooliface.cpp b/digikam/utilities/imageeditor/editor/editortooliface.cpp
new file mode 100644
index 0000000..20453df
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qwidget.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;
+ }
+
+ QWidget *prevTab;
+
+ EditorTool *tool;
+
+ EditorWindow *editor;
+};
+
+EditorToolIface* EditorToolIface::m_iface = 0;
+
+EditorToolIface* EditorToolIface::editorToolIface()
+{
+ return m_iface;
+}
+
+EditorToolIface::EditorToolIface(EditorWindow *editor)
+ : QObject()
+{
+ 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 QString& 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/digikam/utilities/imageeditor/editor/editortooliface.h b/digikam/utilities/imageeditor/editor/editortooliface.h
new file mode 100644
index 0000000..b00012d
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/editortooliface.h
@@ -0,0 +1,75 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qobject.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class EditorTool;
+class EditorWindow;
+class EditorToolIfacePriv;
+
+class DIGIKAM_EXPORT EditorToolIface : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ static EditorToolIface* editorToolIface();
+
+ EditorToolIface(EditorWindow *editor);
+ ~EditorToolIface();
+
+ EditorTool* currentTool() const;
+
+ void loadTool(EditorTool* tool);
+ void unLoadTool();
+
+ void setToolStartProgress(const QString& 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/digikam/utilities/imageeditor/editor/editortoolsettings.cpp b/digikam/utilities/imageeditor/editor/editortoolsettings.cpp
new file mode 100644
index 0000000..43d4f5d
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qstring.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <kapplication.h>
+#include <kcolorbutton.h>
+#include <kdialog.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.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;
+ }
+
+ QHBox *btnBox1;
+ QHBox *btnBox2;
+ QHBox *btnBox3;
+ QHBox *guideBox;
+
+ QVBox *mainVBox;
+ QWidget *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, QWidget *parent)
+ : QScrollView(parent)
+{
+ d = new EditorToolSettingsPriv;
+
+ viewport()->setBackgroundMode(Qt::PaletteBackground);
+ setResizePolicy(QScrollView::AutoOneFit);
+ setFrameStyle(QFrame::NoFrame);
+
+ d->mainVBox = new QVBox(viewport());
+ addChild(d->mainVBox);
+
+ // ---------------------------------------------------------------
+
+ QFrame *frame = new QFrame(d->mainVBox);
+ frame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ QVBoxLayout* vlay = new QVBoxLayout(frame, 5, 0);
+ d->panIconView = new ImagePanIconWidget(360, 240, frame);
+ QWhatsThis::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, Qt::AlignCenter);
+
+ if (!(toolMask & PanIcon))
+ frame->hide();
+
+ // ---------------------------------------------------------------
+
+ d->plainPage = new QWidget(d->mainVBox);
+ d->guideBox = new QHBox(d->mainVBox);
+ d->btnBox1 = new QHBox(d->mainVBox);
+ d->btnBox2 = new QHBox(d->mainVBox);
+
+ // ---------------------------------------------------------------
+
+ new QLabel(i18n("Guide:"), d->guideBox);
+ QLabel *space4 = new QLabel(d->guideBox);
+ d->guideColorBt = new KColorButton(QColor(Qt::red), d->guideBox);
+ QWhatsThis::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);
+ QWhatsThis::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"));
+ QToolTip::add(d->defaultBtn, i18n("<p>Reset all settings to their default values."));
+ if (!(buttonMask & Default))
+ d->defaultBtn->hide();
+
+ QLabel *space = new QLabel(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..."));
+ QToolTip::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());
+ QToolTip::add(d->saveAsBtn, i18n("<p>Save all parameters to settings text file."));
+ if (!(buttonMask & SaveAs))
+ d->saveAsBtn->hide();
+
+ QLabel *space2 = new QLabel(d->btnBox2);
+
+ d->tryBtn = new KPushButton(d->btnBox2);
+ d->tryBtn->setGuiItem(KStdGuiItem::apply());
+ d->tryBtn->setText(i18n("Try"));
+ QToolTip::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, SIGNAL(clicked()),
+ this, SIGNAL(signalOkClicked()));
+
+ connect(d->cancelBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalCancelClicked()));
+
+ connect(d->tryBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalTryClicked()));
+
+ connect(d->defaultBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalDefaultClicked()));
+
+ connect(d->saveAsBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalSaveAsClicked()));
+
+ connect(d->loadBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalLoadClicked()));
+
+ connect(d->guideColorBt, SIGNAL(changed(const QColor&)),
+ this, SIGNAL(signalColorGuideChanged()));
+
+ connect(d->guideSize, SIGNAL(valueChanged(int)),
+ this, SIGNAL(signalColorGuideChanged()));
+}
+
+EditorToolSettings::~EditorToolSettings()
+{
+ delete d;
+}
+
+QSize 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.
+ QSize hint = QScrollView::minimumSizeHint();
+ QRect desktopRect = KGlobalSettings::desktopGeometry(d->mainVBox);
+ hint.setWidth(QMIN(d->mainVBox->minimumSizeHint().width(), desktopRect.width() * 2 / 5));
+ return hint;
+}
+
+int EditorToolSettings::marginHint()
+{
+ return KDialog::marginHint();
+}
+
+int EditorToolSettings::spacingHint()
+{
+ return KDialog::spacingHint();
+}
+
+QWidget *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);
+}
+
+QColor EditorToolSettings::guideColor() const
+{
+ return d->guideColorBt->color();
+}
+
+void EditorToolSettings::setGuideColor(const QColor& 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/digikam/utilities/imageeditor/editor/editortoolsettings.h b/digikam/utilities/imageeditor/editor/editortoolsettings.h
new file mode 100644
index 0000000..a6a515d
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/editortoolsettings.h
@@ -0,0 +1,109 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qscrollview.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class KPushButton;
+
+namespace Digikam
+{
+
+class ImagePanIconWidget;
+class EditorToolSettingsPriv;
+
+class DIGIKAM_EXPORT EditorToolSettings : public QScrollView
+{
+ Q_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, QWidget *parent=0);
+ ~EditorToolSettings();
+
+ virtual void setBusy(bool){};
+ virtual void writeSettings(){};
+ virtual void readSettings(){};
+ virtual void resetSettings(){};
+
+ int marginHint();
+ int spacingHint();
+
+ QWidget *plainPage() const;
+
+ QColor guideColor() const;
+ void setGuideColor(const QColor& color);
+
+ int guideSize() const;
+ void setGuideSize(int size);
+
+ ImagePanIconWidget* panIconView() const;
+ KPushButton* button(int buttonCode) const;
+ void enableButton(int buttonCode, bool state);
+
+ virtual QSize 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/digikam/utilities/imageeditor/editor/editorwindow.cpp b/digikam/utilities/imageeditor/editor/editorwindow.cpp
new file mode 100644
index 0000000..2c61ea1
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/editorwindow.cpp
@@ -0,0 +1,1936 @@
+/* ============================================================
+ *
+ * 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>
+
+// Qt includes.
+
+#include <qlabel.h>
+#include <qdockarea.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qtoolbutton.h>
+#include <qsplitter.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qfile.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <kprinter.h>
+#include <kkeydialog.h>
+#include <kdeversion.h>
+#include <kaction.h>
+#include <kedittoolbar.h>
+#include <kaboutdata.h>
+#include <kcursor.h>
+#include <kstdaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <kimageio.h>
+#include <kaccel.h>
+#include <kmessagebox.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <kio/job.h>
+#include <kprotocolinfo.h>
+#include <kglobalsettings.h>
+#include <ktoolbar.h>
+#include <kstatusbar.h>
+#include <kprogress.h>
+#include <kwin.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 qt_enter_modal( QWidget *widget );
+void qt_leave_modal( QWidget *widget );
+
+namespace Digikam
+{
+
+EditorWindow::EditorWindow(const char *name)
+ : KMainWindow(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);
+ KActionCollection *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, SIGNAL(signalToggleOffFitToWindow()),
+ this, SLOT(slotToggleOffFitToWindow()));
+
+ connect(m_canvas, SIGNAL(signalShowNextImage()),
+ this, SLOT(slotForward()));
+
+ connect(m_canvas, SIGNAL(signalShowPrevImage()),
+ this, SLOT(slotBackward()));
+
+ connect(m_canvas, SIGNAL(signalRightButtonClicked()),
+ this, SLOT(slotContextMenu()));
+
+ connect(m_stackView, SIGNAL(signalZoomChanged(bool, bool, double)),
+ this, SLOT(slotZoomChanged(bool, bool, double)));
+
+ connect(m_canvas, SIGNAL(signalChanged()),
+ this, SLOT(slotChanged()));
+
+ connect(m_canvas, SIGNAL(signalUndoStateChanged(bool, bool, bool)),
+ this, SLOT(slotUndoStateChanged(bool, bool, bool)));
+
+ connect(m_canvas, SIGNAL(signalSelected(bool)),
+ this, SLOT(slotSelected(bool)));
+
+ connect(m_canvas, SIGNAL(signalPrepareToLoad()),
+ this, SLOT(slotPrepareToLoad()));
+
+ connect(m_canvas, SIGNAL(signalLoadingStarted(const QString &)),
+ this, SLOT(slotLoadingStarted(const QString &)));
+
+ connect(m_canvas, SIGNAL(signalLoadingFinished(const QString &, bool)),
+ this, SLOT(slotLoadingFinished(const QString &, bool)));
+
+ connect(m_canvas, SIGNAL(signalLoadingProgress(const QString &, float)),
+ this, SLOT(slotLoadingProgress(const QString &, float)));
+
+ connect(m_canvas, SIGNAL(signalSavingStarted(const QString&)),
+ this, SLOT(slotSavingStarted(const QString&)));
+
+ connect(m_canvas, SIGNAL(signalSavingFinished(const QString&, bool)),
+ this, SLOT(slotSavingFinished(const QString&, bool)));
+
+ connect(m_canvas, SIGNAL(signalSavingProgress(const QString&, float)),
+ this, SLOT(slotSavingProgress(const QString&, float)));
+
+ connect(m_canvas, SIGNAL(signalSelectionChanged(const QRect&)),
+ this, SLOT(slotSelectionChanged(const QRect&)));
+
+ // -- if rotating/flipping set the rotatedflipped flag to true -----------
+
+ connect(d->rotateLeftAction, SIGNAL(activated()),
+ this, SLOT(slotRotatedOrFlipped()));
+
+ connect(d->rotateRightAction, SIGNAL(activated()),
+ this, SLOT(slotRotatedOrFlipped()));
+
+ connect(d->flipHorizAction, SIGNAL(activated()),
+ this, SLOT(slotRotatedOrFlipped()));
+
+ connect(d->flipVertAction, SIGNAL(activated()),
+ this, SLOT(slotRotatedOrFlipped()));
+
+ // -- status bar connections --------------------------------------
+
+ connect(m_nameLabel, SIGNAL(signalCancelButtonPressed()),
+ this, SLOT(slotNameLabelCancelButtonPressed()));
+
+ connect(m_nameLabel, SIGNAL(signalCancelButtonPressed()),
+ d->toolIface, SLOT(slotToolAborted()));
+}
+
+void EditorWindow::setupStandardActions()
+{
+ // -- Standard 'File' menu actions ---------------------------------------------
+
+ m_backwardAction = KStdAction::back(this, SLOT(slotBackward()),
+ actionCollection(), "editorwindow_backward");
+
+ m_forwardAction = KStdAction::forward(this, SLOT(slotForward()),
+ actionCollection(), "editorwindow_forward");
+
+ m_firstAction = new KAction(i18n("&First"), "start",
+ KStdAccel::shortcut( KStdAccel::Home),
+ this, SLOT(slotFirst()),
+ actionCollection(), "editorwindow_first");
+
+ m_lastAction = new KAction(i18n("&Last"), "finish",
+ KStdAccel::shortcut( KStdAccel::End),
+ this, SLOT(slotLast()),
+ actionCollection(), "editorwindow_last");
+
+ m_saveAction = KStdAction::save(this, SLOT(slotSave()),
+ actionCollection(), "editorwindow_save");
+
+ m_saveAsAction = KStdAction::saveAs(this, SLOT(slotSaveAs()),
+ actionCollection(), "editorwindow_saveas");
+
+ m_revertAction = KStdAction::revert(this, SLOT(slotRevert()),
+ actionCollection(), "editorwindow_revert");
+
+ m_saveAction->setEnabled(false);
+ m_saveAsAction->setEnabled(false);
+ m_revertAction->setEnabled(false);
+
+ d->filePrintAction = new KAction(i18n("Print Image..."), "fileprint",
+ CTRL+Key_P,
+ this, SLOT(slotFilePrint()),
+ actionCollection(), "editorwindow_print");
+
+ m_fileDeleteAction = new KAction(i18n("Move to Trash"), "edittrash",
+ Key_Delete,
+ this, SLOT(slotDeleteCurrentItem()),
+ actionCollection(), "editorwindow_delete");
+
+ KStdAction::close(this, SLOT(close()), actionCollection(), "editorwindow_close");
+
+ // -- Standard 'Edit' menu actions ---------------------------------------------
+
+ d->copyAction = KStdAction::copy(m_canvas, SLOT(slotCopy()),
+ actionCollection(), "editorwindow_copy");
+
+ d->copyAction->setEnabled(false);
+
+ m_undoAction = new KToolBarPopupAction(i18n("Undo"), "undo",
+ KStdAccel::shortcut(KStdAccel::Undo),
+ m_canvas, SLOT(slotUndo()),
+ actionCollection(), "editorwindow_undo");
+
+ connect(m_undoAction->popupMenu(), SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowUndoMenu()));
+
+ connect(m_undoAction->popupMenu(), SIGNAL(activated(int)),
+ m_canvas, SLOT(slotUndo(int)));
+
+ m_undoAction->setEnabled(false);
+
+ m_redoAction = new KToolBarPopupAction(i18n("Redo"), "redo",
+ KStdAccel::shortcut(KStdAccel::Redo),
+ m_canvas, SLOT(slotRedo()),
+ actionCollection(), "editorwindow_redo");
+
+ connect(m_redoAction->popupMenu(), SIGNAL(aboutToShow()),
+ this, SLOT(slotAboutToShowRedoMenu()));
+
+ connect(m_redoAction->popupMenu(), SIGNAL(activated(int)),
+ m_canvas, SLOT(slotRedo(int)));
+
+ m_redoAction->setEnabled(false);
+
+ d->selectAllAction = new KAction(i18n("Select All"),
+ 0,
+ CTRL+Key_A,
+ m_canvas,
+ SLOT(slotSelectAll()),
+ actionCollection(),
+ "editorwindow_selectAll");
+
+ d->selectNoneAction = new KAction(i18n("Select None"),
+ 0,
+ CTRL+SHIFT+Key_A,
+ m_canvas,
+ SLOT(slotSelectNone()),
+ actionCollection(),
+ "editorwindow_selectNone");
+
+ // -- Standard 'View' menu actions ---------------------------------------------
+
+ d->zoomPlusAction = KStdAction::zoomIn(this, SLOT(slotIncreaseZoom()),
+ actionCollection(), "editorwindow_zoomplus");
+
+ d->zoomMinusAction = KStdAction::zoomOut(this, SLOT(slotDecreaseZoom()),
+ actionCollection(), "editorwindow_zoomminus");
+
+ d->zoomTo100percents = new KAction(i18n("Zoom to 100%"), "viewmag1",
+ ALT+CTRL+Key_0, // NOTE: Photoshop 7 use ALT+CTRL+0.
+ this, SLOT(slotZoomTo100Percents()),
+ actionCollection(), "editorwindow_zoomto100percents");
+
+
+ d->zoomFitToWindowAction = new KToggleAction(i18n("Fit to &Window"), "view_fit_window",
+ CTRL+SHIFT+Key_E, // NOTE: Gimp 2 use CTRL+SHIFT+E.
+ this, SLOT(slotToggleFitToWindow()),
+ actionCollection(), "editorwindow_zoomfit2window");
+
+ d->zoomFitToSelectAction = new KAction(i18n("Fit to &Selection"), "viewmagfit",
+ ALT+CTRL+Key_S, this, 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(ClickFocus);
+ d->zoomCombo->setInsertionPolicy(QComboBox::NoInsertion);
+ d->zoomComboAction = new KWidgetAction(d->zoomCombo, i18n("Zoom"), 0, 0, 0,
+ actionCollection(), "editorwindow_zoomto");
+
+ d->zoomCombo->insertItem(QString("10%"));
+ d->zoomCombo->insertItem(QString("25%"));
+ d->zoomCombo->insertItem(QString("50%"));
+ d->zoomCombo->insertItem(QString("75%"));
+ d->zoomCombo->insertItem(QString("100%"));
+ d->zoomCombo->insertItem(QString("150%"));
+ d->zoomCombo->insertItem(QString("200%"));
+ d->zoomCombo->insertItem(QString("300%"));
+ d->zoomCombo->insertItem(QString("450%"));
+ d->zoomCombo->insertItem(QString("600%"));
+ d->zoomCombo->insertItem(QString("800%"));
+ d->zoomCombo->insertItem(QString("1200%"));
+
+ connect(d->zoomCombo, SIGNAL(activated(int)),
+ this, SLOT(slotZoomSelected()) );
+
+ connect(d->zoomCombo, SIGNAL(returnPressed(const QString&)),
+ this, SLOT(slotZoomTextChanged(const QString &)) );
+
+ // Do not use std KDE action for full screen because action text is too large for app. toolbar.
+ m_fullScreenAction = new KToggleAction(i18n("Full Screen"), "window_fullscreen",
+ CTRL+SHIFT+Key_F, this,
+ SLOT(slotToggleFullScreen()),
+ actionCollection(), "editorwindow_fullscreen");
+ m_fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode"));
+
+ d->slideShowAction = new KAction(i18n("Slideshow"), "slideshow", Key_F9,
+ this, SLOT(slotToggleSlideShow()),
+ actionCollection(),"editorwindow_slideshow");
+
+ d->viewUnderExpoAction = new KToggleAction(i18n("Under-Exposure Indicator"), "underexposure",
+ Key_F10, this,
+ SLOT(slotToggleUnderExposureIndicator()),
+ actionCollection(),"editorwindow_underexposure");
+
+ d->viewOverExpoAction = new KToggleAction(i18n("Over-Exposure Indicator"), "overexposure",
+ Key_F11, this,
+ SLOT(slotToggleOverExposureIndicator()),
+ actionCollection(),"editorwindow_overexposure");
+
+ d->viewCMViewAction = new KToggleAction(i18n("Color Managed View"), "tv",
+ Key_F12, this,
+ SLOT(slotToggleColorManagedView()),
+ actionCollection(),"editorwindow_cmview");
+
+ // -- Standard 'Transform' menu actions ---------------------------------------------
+
+ d->resizeAction = new KAction(i18n("&Resize..."), "resize_image", 0,
+ this, SLOT(slotResize()),
+ actionCollection(), "editorwindow_resize");
+
+ d->cropAction = new KAction(i18n("Crop"), "crop",
+ CTRL+Key_X,
+ m_canvas, 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 KAction(i18n("Flip Horizontally"), "mirror", CTRL+Key_Asterisk,
+ m_canvas, SLOT(slotFlipHoriz()),
+ actionCollection(), "editorwindow_flip_horiz");
+ d->flipHorizAction->setEnabled(false);
+
+ d->flipVertAction = new KAction(i18n("Flip Vertically"), "flip", CTRL+Key_Slash,
+ m_canvas, SLOT(slotFlipVert()),
+ actionCollection(), "editorwindow_flip_vert");
+ d->flipVertAction->setEnabled(false);
+
+ // -- Standard 'Rotate' menu actions ----------------------------------------
+
+ d->rotateLeftAction = new KAction(i18n("Rotate Left"),
+ "rotate_ccw", SHIFT+CTRL+Key_Left,
+ m_canvas, SLOT(slotRotate270()),
+ actionCollection(),
+ "editorwindow_rotate_left");
+ d->rotateLeftAction->setEnabled(false);
+ d->rotateRightAction = new KAction(i18n("Rotate Right"),
+ "rotate_cw", SHIFT+CTRL+Key_Right,
+ m_canvas, SLOT(slotRotate90()),
+ actionCollection(),
+ "editorwindow_rotate_right");
+ d->rotateRightAction->setEnabled(false);
+
+ // -- Standard 'Configure' menu actions ----------------------------------------
+
+ d->showMenuBarAction = KStdAction::showMenubar(this, SLOT(slotShowMenuBar()), actionCollection());
+
+ KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());
+ KStdAction::configureToolbars(this, SLOT(slotConfToolbars()), actionCollection());
+ KStdAction::preferences(this, SLOT(slotSetup()), actionCollection());
+
+ // -----------------------------------------------------------------------------------------
+
+ m_themeMenuAction = new KSelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu");
+ m_themeMenuAction->setItems(ThemeEngine::instance()->themeNames());
+
+ connect(m_themeMenuAction, SIGNAL(activated(const QString&)),
+ this, SLOT(slotChangeTheme(const QString&)));
+
+ connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
+ this, SLOT(slotThemeChanged()));
+
+ // -- Standard 'Help' menu actions ---------------------------------------------
+
+ d->donateMoneyAction = new KAction(i18n("Donate..."),
+ 0, 0,
+ this, SLOT(slotDonateMoney()),
+ actionCollection(),
+ "editorwindow_donatemoney");
+
+ d->contributeAction = new KAction(i18n("Contribute..."),
+ 0, 0,
+ this, SLOT(slotContribute()),
+ actionCollection(),
+ "editorwindow_contribute");
+
+ d->rawCameraListAction = new KAction(i18n("Supported RAW Cameras"),
+ "kdcraw",
+ 0,
+ this,
+ SLOT(slotRawCameraList()),
+ actionCollection(),
+ "editorwindow_rawcameralist");
+}
+
+void EditorWindow::setupStandardAccelerators()
+{
+ d->accelerators = new KAccel(this);
+
+ d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"),
+ i18n("Exit out of the fullscreen mode"),
+ Key_Escape, this, SLOT(slotEscapePressed()),
+ false, true);
+
+ d->accelerators->insert("Next Image Key_Space", i18n("Next Image"),
+ i18n("Load Next Image"),
+ Key_Space, this, SLOT(slotForward()),
+ false, true);
+
+ d->accelerators->insert("Previous Image SHIFT+Key_Space", i18n("Previous Image"),
+ i18n("Load Previous Image"),
+ SHIFT+Key_Space, this, SLOT(slotBackward()),
+ false, true);
+
+ d->accelerators->insert("Previous Image Key_Backspace", i18n("Previous Image"),
+ i18n("Load Previous Image"),
+ Key_Backspace, this, SLOT(slotBackward()),
+ false, true);
+
+ d->accelerators->insert("Next Image Key_Next", i18n("Next Image"),
+ i18n("Load Next Image"),
+ Key_Next, this, SLOT(slotForward()),
+ false, true);
+
+ d->accelerators->insert("Previous Image Key_Prior", i18n("Previous Image"),
+ i18n("Load Previous Image"),
+ Key_Prior, this, SLOT(slotBackward()),
+ false, true);
+
+ d->accelerators->insert("Zoom Plus Key_Plus", i18n("Zoom In"),
+ i18n("Zoom in on Image"),
+ Key_Plus, this, SLOT(slotIncreaseZoom()),
+ false, true);
+
+ d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom Out"),
+ i18n("Zoom out of Image"),
+ Key_Minus, this, SLOT(slotDecreaseZoom()),
+ false, true);
+
+ d->accelerators->insert("Redo CTRL+Key_Y", i18n("Redo"),
+ i18n("Redo Last action"),
+ CTRL+Key_Y, m_canvas, SLOT(slotRedo()),
+ false, true);
+}
+
+void EditorWindow::setupStatusBar()
+{
+ m_nameLabel = new StatusProgressBar(statusBar());
+ m_nameLabel->setAlignment(Qt::AlignCenter);
+ m_nameLabel->setMaximumHeight(fontMetrics().height()+2);
+ statusBar()->addWidget(m_nameLabel, 100);
+
+ d->selectLabel = new QLabel(i18n("No selection"), statusBar());
+ d->selectLabel->setAlignment(Qt::AlignCenter);
+ d->selectLabel->setMaximumHeight(fontMetrics().height()+2);
+ statusBar()->addWidget(d->selectLabel, 100);
+ QToolTip::add(d->selectLabel, i18n("Information about current selection area"));
+
+ m_resLabel = new QLabel(statusBar());
+ m_resLabel->setAlignment(Qt::AlignCenter);
+ m_resLabel->setMaximumHeight(fontMetrics().height()+2);
+ statusBar()->addWidget(m_resLabel, 100);
+ QToolTip::add(m_resLabel, i18n("Information about image size"));
+
+ d->underExposureIndicator = new QToolButton(statusBar());
+ d->underExposureIndicator->setIconSet(SmallIcon("underexposure"));
+ d->underExposureIndicator->setToggleButton(true);
+ statusBar()->addWidget(d->underExposureIndicator, 1);
+
+ d->overExposureIndicator = new QToolButton(statusBar());
+ d->overExposureIndicator->setIconSet(SmallIcon("overexposure"));
+ d->overExposureIndicator->setToggleButton(true);
+ statusBar()->addWidget(d->overExposureIndicator, 1);
+
+ d->cmViewIndicator = new QToolButton(statusBar());
+ d->cmViewIndicator->setIconSet(SmallIcon("tv"));
+ d->cmViewIndicator->setToggleButton(true);
+ statusBar()->addWidget(d->cmViewIndicator, 1);
+
+ connect(d->underExposureIndicator, SIGNAL(toggled(bool)),
+ this, SLOT(slotToggleUnderExposureIndicator()));
+
+ connect(d->overExposureIndicator, SIGNAL(toggled(bool)),
+ this, SLOT(slotToggleOverExposureIndicator()));
+
+ connect(d->cmViewIndicator, SIGNAL(toggled(bool)),
+ this, 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;
+ QString appName = KApplication::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, (appName.append(" page")).ascii() ));
+
+ if ( printer.setup( this, i18n("Print %1").arg(printer.docName().section('/', -1)) ) )
+ {
+ ImagePrint printOperations(image, printer, url.filename());
+ if (!printOperations.printImageWithQt())
+ {
+ KMessageBox::error(this, i18n("Failed to print file: '%1'")
+ .arg(url.filename()));
+ }
+ }
+}
+
+void EditorWindow::slotEditKeys()
+{
+ KKeyDialog dialog(true, this);
+ dialog.insert( actionCollection(), i18n( "General" ) );
+
+ QPtrList<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();
+ QStringList titles;
+ m_canvas->getUndoHistory(titles);
+
+ if(!titles.isEmpty())
+ {
+ int id = 1;
+ QStringList::Iterator iter = titles.begin();
+ for(; iter != titles.end(); ++iter,++id)
+ {
+ m_undoAction->popupMenu()->insertItem(*iter, id);
+ }
+ }
+}
+
+void EditorWindow::slotAboutToShowRedoMenu()
+{
+ m_redoAction->popupMenu()->clear();
+ QStringList titles;
+ m_canvas->getRedoHistory(titles);
+
+ if(!titles.isEmpty())
+ {
+ int id = 1;
+ QStringList::Iterator iter = titles.begin();
+ for(; iter != titles.end(); ++iter,++id)
+ {
+ m_redoAction->popupMenu()->insertItem(*iter, id);
+ }
+ }
+}
+
+void EditorWindow::slotConfToolbars()
+{
+ saveMainWindowSettings(KGlobal::config(), "ImageViewer Settings");
+ KEditToolbar dlg(factory(), this);
+
+ connect(&dlg, SIGNAL(newToolbarConfig()),
+ this, SLOT(slotNewToolbarConfig()));
+
+ dlg.exec();
+}
+
+void EditorWindow::slotNewToolbarConfig()
+{
+ applyMainWindowSettings(KGlobal::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()
+{
+ QString txt = d->zoomCombo->currentText();
+ txt = txt.left(txt.find('%'));
+ slotZoomTextChanged(txt);
+}
+
+void EditorWindow::slotZoomTextChanged(const QString &txt)
+{
+ bool r = false;
+ double zoom = KGlobal::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(QString::number(lround(zoom*100.0)) + QString("%"));
+ 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(KAction* action)
+{
+ if (!action)
+ return;
+
+ d->accelerators->insert(action->text(),
+ action->text(),
+ action->whatsThis(),
+ action->shortcut(),
+ action,
+ SLOT(activate()));
+}
+
+void EditorWindow::unplugActionAccel(KAction* action)
+{
+ d->accelerators->remove(action->text());
+}
+
+void EditorWindow::loadImagePlugins()
+{
+ QPtrList<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()
+{
+ QPtrList<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()
+{
+ KConfig* 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()
+{
+ KConfig* 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", QString());
+ d->ICCSettings->workspaceSetting = config->readPathEntry("WorkProfileFile", QString());
+ d->ICCSettings->monitorSetting = config->readPathEntry("MonitorProfileFile", QString());
+ d->ICCSettings->proofSetting = config->readPathEntry("ProofProfileFile", QString());
+
+ 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 -------------------------------------------------------
+
+ QSizePolicy rightSzPolicy(QSizePolicy::Preferred, QSizePolicy::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 ---------------------------------------
+
+ QColor black(Qt::black);
+ QColor white(Qt::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()
+{
+ KConfig* 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);
+ }
+
+ QPtrList<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);
+
+#if QT_VERSION >= 0x030300
+ setWindowState( windowState() & ~WindowFullScreen );
+#else
+ showNormal();
+#endif
+ menuBar()->show();
+ statusBar()->show();
+ leftDock()->show();
+ rightDock()->show();
+ topDock()->show();
+ bottomDock()->show();
+
+ QObject* obj = child("ToolBar","KToolBar");
+
+ if (obj)
+ {
+ KToolBar* toolBar = static_cast<KToolBar*>(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(QColor(Qt::black));
+
+ // hide the menubar and the statusbar
+ menuBar()->hide();
+ statusBar()->hide();
+ topDock()->hide();
+ leftDock()->hide();
+ rightDock()->hide();
+ bottomDock()->hide();
+
+ QObject* obj = child("ToolBar","KToolBar");
+
+ if (obj)
+ {
+ KToolBar* toolBar = static_cast<KToolBar*>(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 QString&, float progress)
+{
+ m_nameLabel->setProgressValue((int)(progress*100.0));
+}
+
+void EditorWindow::slotSavingProgress(const QString&, float progress)
+{
+ m_nameLabel->setProgressValue((int)(progress*100.0));
+}
+
+bool EditorWindow::promptForOverWrite()
+{
+ QFileInfo fi(m_canvas->currentImageFilePath());
+ QString 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()),
+ QString(),
+ 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()
+{
+ QWidget dummy(0, 0, WType_Dialog | WShowModal);
+ dummy.setFocusPolicy( QWidget::NoFocus );
+ qt_enter_modal(&dummy);
+ qApp->enter_loop();
+ qt_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);
+ }
+ }
+
+ QRect sel = m_canvas->getSelectedArea();
+ // Update histogram into sidebar.
+ emit signalSelectionChanged(sel);
+
+ // Update status bar
+ if (val)
+ d->selectLabel->setText(QString("(%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()
+{
+ QPtrListIterator<KToolBar> it = toolBarIterator();
+ KToolBar* bar;
+
+ for(;it.current()!=0L; ++it)
+ {
+ bar = it.current();
+
+ if (bar->area())
+ bar->area()->hide();
+ else
+ bar->hide();
+ }
+}
+
+void EditorWindow::showToolBars()
+{
+ QPtrListIterator<KToolBar> it = toolBarIterator();
+ KToolBar* 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 QString& /*filename*/)
+{
+ setCursor( KCursor::waitCursor() );
+
+ m_nameLabel->progressBarMode(StatusProgressBar::ProgressBarMode, i18n("Loading: "));
+}
+
+void EditorWindow::slotLoadingFinished(const QString& 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 != QString())
+ {
+ QFileInfo fi(filename);
+ QString 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 QString& /*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 QString& 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 Qt event loop to unlock promptUserSave() method.
+ if (m_savingContext->synchronizingState == SavingContextContainer::SynchronousSaving)
+ qApp->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;
+
+ QString 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() : QDir::homeDirPath(),
+ QString(),
+ this,
+ "imageFileSaveDialog",
+ false,
+ options);
+
+ connect(&imageFileSaveDialog, SIGNAL(filterChanged(const QString &)),
+ options, SLOT(slotImageFileFormatChanged(const QString &)));
+
+ connect(&imageFileSaveDialog, SIGNAL(fileSelected(const QString &)),
+ options, SLOT(slotImageFileSelected(const QString &)));
+
+ 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);
+
+ QFileInfo info(m_savingContext->srcURL.fileName());
+ KConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+ QString ext = config->readEntry("LastSavedImageTypeMime", "png");
+ QString fileName = info.baseName(false) + QString(".") + 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.
+
+ QFileInfo 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 = QImageIO::imageFormat(m_savingContext->srcURL.path());
+ }
+ else
+ {
+ // Else, check if format from file name extension is include on file mime type list.
+
+ QString imgExtPattern;
+ QStringList imgExtList = QStringList::split(" ", mimetypes);
+ for (QStringList::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 ----------------------------------------------------------
+
+ QFileInfo 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.
+
+ QFileInfo 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()
+{
+ QCString dstFileName = QFile::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(QFile::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.
+ KConfig* 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)
+{
+ QToolTip::remove(d->cmViewIndicator);
+ QString 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");
+ }
+ QToolTip::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)
+{
+ QToolTip::remove(d->underExposureIndicator);
+ QToolTip::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)
+{
+ QToolTip::remove(d->overExposureIndicator);
+ QToolTip::add(d->overExposureIndicator,
+ oei ? i18n("Over-Exposure indicator is enabled")
+ : i18n("Over-Exposure indicator is disabled"));
+}
+
+void EditorWindow::slotDonateMoney()
+{
+ KApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation");
+}
+
+void EditorWindow::slotContribute()
+{
+ KApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=contrib");
+}
+
+void EditorWindow::slotToggleSlideShow()
+{
+ KConfig* 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 QRect& sel)
+{
+ d->selectLabel->setText(QString("(%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()
+{
+ QStringList themes(ThemeEngine::instance()->themeNames());
+ int index = themes.findIndex(ThemeEngine::instance()->getCurrentThemeName());
+ if (index == -1)
+ index = themes.findIndex(i18n("Default"));
+
+ m_themeMenuAction->setCurrentItem(index);
+
+ KConfig* config = kapp->config();
+ config->setGroup("ImageViewer Settings");
+
+ if (!config->readBoolEntry("UseThemeBackgroundColor", true))
+ m_bgColor = config->readColorEntry("BackgroundColor", &Qt::black);
+ else
+ m_bgColor = ThemeEngine::instance()->baseColor();
+
+ m_canvas->setBackgroundColor(m_bgColor);
+}
+
+void EditorWindow::slotChangeTheme(const QString& theme)
+{
+ ThemeEngine::instance()->slotChangeTheme(theme);
+}
+
+void EditorWindow::setToolStartProgress(const QString& toolName)
+{
+ m_nameLabel->setProgressValue(0);
+ m_nameLabel->progressBarMode(StatusProgressBar::CancelProgressBarMode, QString("%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/digikam/utilities/imageeditor/editor/editorwindow.h b/digikam/utilities/imageeditor/editor/editorwindow.h
new file mode 100644
index 0000000..6cb20cf
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/editorwindow.h
@@ -0,0 +1,262 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qcolor.h>
+#include <qstring.h>
+#include <qrect.h>
+
+// KDE includes.
+
+#include <kmainwindow.h>
+#include <kurl.h>
+
+// Local includes.
+
+#include "sidebar.h"
+#include "digikam_export.h"
+
+class QSplitter;
+class QPopupMenu;
+class QLabel;
+
+class KToolBarPopupAction;
+class KToggleAction;
+class KAction;
+class KSelectAction;
+
+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 KMainWindow
+{
+ Q_OBJECT
+
+public:
+
+ EditorWindow(const char *name);
+ ~EditorWindow();
+
+ virtual void applySettings(){};
+ virtual bool setup(bool iccSetupPage=false)=0;
+
+signals:
+
+ void signalSelectionChanged( const QRect & );
+ void signalNoCurrentItem();
+
+protected:
+
+ bool m_cancelSlideShow;
+ bool m_fullScreen;
+ bool m_rotatedOrFlipped;
+ bool m_setExifOrientationTag;
+
+ QLabel *m_resLabel;
+
+ QColor m_bgColor;
+
+ QSplitter *m_splitter;
+
+ KAction *m_saveAction;
+ KAction *m_saveAsAction;
+ KAction *m_revertAction;
+ KAction *m_fileDeleteAction;
+ KAction *m_forwardAction;
+ KAction *m_backwardAction;
+ KAction *m_firstAction;
+ KAction *m_lastAction;
+
+ KToggleAction *m_fullScreenAction;
+
+ KSelectAction *m_themeMenuAction;
+
+ KToolBarPopupAction *m_undoAction;
+ KToolBarPopupAction *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(KAction* action);
+ void unplugActionAccel(KAction* 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 QString& filePath, float progress);
+ void slotSavingProgress(const QString& filePath, float progress);
+
+ void slotNameLabelCancelButtonPressed();
+
+ void slotThemeChanged();
+
+ virtual void slotLoadingStarted(const QString& filename);
+ virtual void slotLoadingFinished(const QString &filename, bool success);
+ virtual void slotSavingStarted(const QString &filename);
+
+ virtual void slotSetup(){ setup(); };
+ virtual void slotChangeTheme(const QString& 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 QString &filename, bool success);
+ void slotDonateMoney();
+ void slotContribute();
+ void slotToggleSlideShow();
+ void slotZoomTo100Percents();
+ void slotZoomSelected();
+ void slotZoomTextChanged(const QString &);
+ void slotZoomChanged(bool isMax, bool isMin, double zoom);
+ void slotSelectionChanged(const QRect& 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 QString& toolName);
+ void setToolProgress(int progress);
+ void setToolStopProgress();
+
+private:
+
+ EditorWindowPriv *d;
+
+ friend class EditorToolIface;
+};
+
+} // namespace Digikam
+
+#endif /* EDITORWINDOW_H */
diff --git a/digikam/utilities/imageeditor/editor/editorwindowprivate.h b/digikam/utilities/imageeditor/editor/editorwindowprivate.h
new file mode 100644
index 0000000..e66504e
--- /dev/null
+++ b/digikam/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 QToolButton;
+class QLabel;
+
+class KComboBox;
+class KAction;
+class KToggleAction;
+class KWidgetAction;
+class KSelectAction;
+class KActionMenu;
+class KAccel;
+
+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;
+
+ QLabel *selectLabel;
+
+ QToolButton *cmViewIndicator;
+ QToolButton *underExposureIndicator;
+ QToolButton *overExposureIndicator;
+
+ KAction *rawCameraListAction;
+ KAction *donateMoneyAction;
+ KAction *contributeAction;
+ KAction *filePrintAction;
+ KAction *copyAction;
+ KAction *resizeAction;
+ KAction *cropAction;
+ KAction *zoomPlusAction;
+ KAction *zoomMinusAction;
+ KAction *zoomTo100percents;
+ KAction *zoomFitToSelectAction;
+ KAction *rotateLeftAction;
+ KAction *rotateRightAction;
+ KAction *flipHorizAction;
+ KAction *flipVertAction;
+ KAction *slideShowAction;
+ KAction *selectAllAction;
+ KAction *selectNoneAction;
+
+ KToggleAction *zoomFitToWindowAction;
+ KToggleAction *viewCMViewAction;
+ KToggleAction *viewUnderExpoAction;
+ KToggleAction *viewOverExpoAction;
+ KToggleAction *showMenuBarAction;
+
+ KWidgetAction *zoomComboAction;
+
+ KComboBox *zoomCombo;
+
+ KAccel *accelerators;
+
+ ICCSettingsContainer *ICCSettings;
+
+ ExposureSettingsContainer *exposureSettings;
+
+ EditorToolIface *toolIface;
+};
+
+} // NameSpace Digikam
+
+#endif /* EDITORWINDOWPRIVATE_H */
diff --git a/digikam/utilities/imageeditor/editor/imageiface.cpp b/digikam/utilities/imageeditor/editor/imageiface.cpp
new file mode 100644
index 0000000..600482c
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qwidget.h>
+#include <qsize.h>
+#include <qpixmap.h>
+#include <qbitmap.h>
+#include <qpainter.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;
+
+ QPixmap qcheck;
+ QPixmap qpix;
+ QBitmap 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);
+
+ QPainter p;
+ p.begin(&d->qcheck);
+ p.fillRect(0, 0, 4, 4, QColor(144,144,144));
+ p.fillRect(4, 4, 4, 4, QColor(144,144,144));
+ p.fillRect(0, 4, 4, 4, QColor(100,100,100));
+ p.fillRect(4, 0, 4, 4, QColor(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 QPoint& 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 QPoint& 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 QPoint& 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::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;
+ }
+ }
+
+ QSize sz(im->width(), im->height());
+ sz.scale(d->constrainWidth, d->constrainHeight, QSize::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 QString &caller, uchar* data, int w, int h)
+{
+ if (!data)
+ return;
+
+ DImgInterface::defaultInterface()->putImage(caller, data, w, h);
+}
+
+void ImageIface::setEmbeddedICCToOriginalImage(const QString& profilePath)
+{
+ DImgInterface::defaultInterface()->setEmbeddedICCToOriginalImage( profilePath );
+}
+
+void ImageIface::putImageSelection(const QString &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);
+}
+
+QPixmap ImageIface::convertToPixmap(DImg& img)
+{
+ return DImgInterface::defaultInterface()->convertToPixmap(img);
+}
+
+QByteArray ImageIface::getEmbeddedICCFromOriginalImage()
+{
+ return DImgInterface::defaultInterface()->getEmbeddedICC();
+}
+
+QByteArray ImageIface::getExifFromOriginalImage()
+{
+ return DImgInterface::defaultInterface()->getExif();
+}
+
+QByteArray 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(QPaintDevice* device, int x, int y, int w, int h,
+ bool underExposure, bool overExposure)
+{
+ if ( !d->targetPreviewImage.isNull() )
+ {
+ if (d->targetPreviewImage.hasAlpha())
+ {
+ QPainter p(&d->qpix);
+ p.drawTiledPixmap(0, 0, d->qpix.width(), d->qpix.height(), d->qcheck);
+ p.end();
+ }
+
+ QPixmap 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, &pixImage, 0, 0, w, h, Qt::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();
+
+ QImage pureColorMask = d->targetPreviewImage.pureColorMask(&expoSettings);
+ QPixmap pixMask(pureColorMask);
+ bitBlt(&d->qpix, 0, 0, &pixMask, 0, 0, w, h, Qt::CopyROP, false);
+ }
+ }
+
+ bitBlt(device, x, y, &d->qpix, 0, 0, -1, -1, Qt::CopyROP, false);
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/imageeditor/editor/imageiface.h b/digikam/utilities/imageeditor/editor/imageiface.h
new file mode 100644
index 0000000..61d752b
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qglobal.h>
+#include <qstring.h>
+
+// KDE includes.
+
+#include <klocale.h>
+
+// Local includes.
+
+#include "dimg.h"
+#include "dcolor.h"
+#include "photoinfocontainer.h"
+#include "digikam_export.h"
+
+#define MAX3(a, b, c) (QMAX(QMAX(a,b),b))
+#define MIN3(a, b, c) (QMIN(QMIN(a,b),b))
+#define ROUND(x) ((int) ((x) + 0.5))
+
+class QPaintDevice;
+
+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 QString &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 QString& 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 QString &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 QPoint& point);
+ DColor getColorInfoFromPreviewImage(const QPoint& point);
+ DColor getColorInfoFromTargetPreviewImage(const QPoint& point);
+
+ /** Original image information.*/
+ int originalWidth();
+ int originalHeight();
+ bool originalSixteenBit();
+ bool originalHasAlpha();
+
+ /** Original image metadata.*/
+ QByteArray getEmbeddedICCFromOriginalImage();
+ QByteArray getExifFromOriginalImage();
+ QByteArray 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 */
+ QPixmap 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(QPaintDevice* 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/digikam/utilities/imageeditor/editor/imagewindow.cpp b/digikam/utilities/imageeditor/editor/imagewindow.cpp
new file mode 100644
index 0000000..d17c6c0
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qlabel.h>
+#include <qimage.h>
+#include <qsplitter.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+// KDE includes.
+
+#include <kcursor.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kimageio.h>
+#include <kfiledialog.h>
+#include <kdeversion.h>
+#include <kmenubar.h>
+#include <ktoolbar.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kstdguiitem.h>
+#include <kstatusbar.h>
+#include <kprogress.h>
+#include <kwin.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.
+ KAction *star0;
+ KAction *star1;
+ KAction *star2;
+ KAction *star3;
+ KAction *star4;
+ KAction *star5;
+
+ // Delete actions
+ KAction *fileDeletePermanentlyAction;
+ KAction *fileDeletePermanentlyDirectlyAction;
+ KAction *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(QCloseEvent* 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, SIGNAL(signalNextItem()),
+ this, SLOT(slotForward()));
+
+ connect(d->rightSidebar, SIGNAL(signalPrevItem()),
+ this, SLOT(slotBackward()));
+
+ connect(this, SIGNAL(signalSelectionChanged( const QRect &)),
+ d->rightSidebar, SLOT(slotImageSelectionChanged( const QRect &)));
+
+ connect(this, SIGNAL(signalNoCurrentItem()),
+ d->rightSidebar, SLOT(slotNoCurrentItem()));
+
+ ImageAttributesWatch *watch = ImageAttributesWatch::instance();
+
+ connect(watch, SIGNAL(signalFileMetadataChanged(const KURL &)),
+ this, SLOT(slotFileMetadataChanged(const KURL &)));
+}
+
+void ImageWindow::setupUserArea()
+{
+ QWidget* widget = new QWidget(this);
+ QHBoxLayout *lay = new QHBoxLayout(widget);
+
+ m_splitter = new QSplitter(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();
+
+ QSizePolicy rightSzPolicy(QSizePolicy::Preferred, QSizePolicy::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( QFrame::NoFrame );
+ m_splitter->setFrameShadow( QFrame::Plain );
+ m_splitter->setFrameShape( QFrame::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 KAction(i18n("Assign Rating \"No Stars\""), CTRL+Key_0,
+ this, SLOT(slotAssignRatingNoStar()),
+ actionCollection(), "imageview_ratenostar");
+ d->star1 = new KAction(i18n("Assign Rating \"One Star\""), CTRL+Key_1,
+ this, SLOT(slotAssignRatingOneStar()),
+ actionCollection(), "imageview_rateonestar");
+ d->star2 = new KAction(i18n("Assign Rating \"Two Stars\""), CTRL+Key_2,
+ this, SLOT(slotAssignRatingTwoStar()),
+ actionCollection(), "imageview_ratetwostar");
+ d->star3 = new KAction(i18n("Assign Rating \"Three Stars\""), CTRL+Key_3,
+ this, SLOT(slotAssignRatingThreeStar()),
+ actionCollection(), "imageview_ratethreestar");
+ d->star4 = new KAction(i18n("Assign Rating \"Four Stars\""), CTRL+Key_4,
+ this, SLOT(slotAssignRatingFourStar()),
+ actionCollection(), "imageview_ratefourstar");
+ d->star5 = new KAction(i18n("Assign Rating \"Five Stars\""), CTRL+Key_5,
+ this, SLOT(slotAssignRatingFiveStar()),
+ actionCollection(), "imageview_ratefivestar");
+
+ // -- Special Delete actions ---------------------------------------------------------------
+
+ // Pop up dialog to ask user whether to permanently delete
+ d->fileDeletePermanentlyAction = new KAction(i18n("Delete File Permanently"),
+ "editdelete",
+ SHIFT+Key_Delete,
+ this,
+ 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 KAction(i18n("Delete Permanently without Confirmation"),
+ "editdelete",
+ 0,
+ this,
+ SLOT(slotDeleteCurrentItemPermanentlyDirectly()),
+ actionCollection(),
+ "image_delete_permanently_directly");
+
+ d->fileTrashDirectlyAction = new KAction(i18n("Move to Trash without Confirmation"),
+ "edittrash",
+ 0,
+ this,
+ 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 QString& 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 QString& 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 QString& 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);
+
+ QTimer::singleShot(0, this, 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 --------------------------
+
+ Q_LLONG id = d->imageInfoCurrent->id();
+ QValueList<Q_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, SIGNAL(signalTagActivated(int)),
+ this, SLOT(slotAssignTag(int)));
+
+ connect(removeTagsMenu, SIGNAL(signalTagActivated(int)),
+ this, 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, SIGNAL(activated(int)),
+ this, SLOT(slotAssignRating(int)));
+
+ m_contextMenu->insertItem(i18n("Assign Rating"), ratingMenu);
+ }
+
+ m_contextMenu->exec(QCursor::pos());
+
+ if (separatorID1 != -1)
+ m_contextMenu->removeItem(separatorID1);
+ if (separatorID2 != -1)
+ m_contextMenu->removeItem(separatorID2);
+
+ delete assignTagsMenu;
+ delete removeTagsMenu;
+ delete ratingMenu;
+ }
+}
+
+void ImageWindow::slotChanged()
+{
+ QString mpixels;
+ QSize dims(m_canvas->imageWidth(), m_canvas->imageHeight());
+ mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2);
+ QString 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 = QMIN(RatingMax, QMAX(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;
+
+ QString text = d->urlCurrent.filename() + i18n(" (%2 of %3)")
+ .arg(QString::number(index+1))
+ .arg(QString::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() != QDialog::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(QDir::cleanDirPath(m_savingContext->srcURL.directory()));
+ PAlbum* srcAlbum = AlbumManager::instance()->findPAlbum(srcDirURL);
+
+ KURL dstDirURL(QDir::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 KIO
+ 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))
+ {
+ QString 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, QString());
+
+ 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(QDragMoveEvent *e)
+{
+ int albumID;
+ QValueList<int> albumIDs;
+ QValueList<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(QDropEvent *e)
+{
+ int albumID;
+ QValueList<int> albumIDs;
+ QValueList<int> imageIDs;
+ KURL::List urls;
+ KURL::List kioURLs;
+
+ if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs))
+ {
+ ImageInfoList imageInfoList;
+
+ for (QValueList<int>::const_iterator it = imageIDs.begin();
+ it != imageIDs.end(); ++it)
+ {
+ ImageInfo *info = new ImageInfo(*it);
+ imageInfoList.append(info);
+ }
+
+ if (imageInfoList.isEmpty())
+ {
+ e->ignore();
+ return;
+ }
+
+ QString 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();
+ QValueList<Q_LLONG> itemIDs = man->albumDB()->getItemIDsInAlbum(albumID);
+ ImageInfoList imageInfoList;
+
+ for (QValueList<Q_LLONG>::const_iterator it = itemIDs.begin();
+ it != itemIDs.end(); ++it)
+ {
+ ImageInfo *info = new ImageInfo(*it);
+ imageInfoList.append(info);
+ }
+
+ if (imageInfoList.isEmpty())
+ {
+ e->ignore();
+ return;
+ }
+
+ QString 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))
+ {
+ QByteArray ba = e->encodedData("digikam/tag-id");
+ QDataStream ds(ba, IO_ReadOnly);
+ int tagID;
+ ds >> tagID;
+
+ AlbumManager* man = AlbumManager::instance();
+ QValueList<Q_LLONG> itemIDs = man->albumDB()->getItemIDsInTag(tagID, true);
+ ImageInfoList imageInfoList;
+
+ for (QValueList<Q_LLONG>::const_iterator it = itemIDs.begin();
+ it != itemIDs.end(); ++it)
+ {
+ ImageInfo *info = new ImageInfo(*it);
+ imageInfoList.append(info);
+ }
+
+ if (imageInfoList.isEmpty())
+ {
+ e->ignore();
+ return;
+ }
+
+ QString 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 QString& theme)
+{
+ AlbumSettings::instance()->setCurrentTheme(theme);
+ ThemeEngine::instance()->slotChangeTheme(theme);
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/imageeditor/editor/imagewindow.h b/digikam/utilities/imageeditor/editor/imagewindow.h
new file mode 100644
index 0000000..c9f9e62
--- /dev/null
+++ b/digikam/utilities/imageeditor/editor/imagewindow.h
@@ -0,0 +1,154 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "editorwindow.h"
+#include "imageinfo.h"
+
+class QDragMoveEvent;
+class QDropEvent;
+
+namespace Digikam
+{
+
+class AlbumIconView;
+class ImageWindowPriv;
+class SlideShowSettings;
+
+class ImageWindow : public EditorWindow
+{
+ Q_OBJECT
+
+public:
+
+ ~ImageWindow();
+
+ void loadURL(const KURL::List& urlList, const KURL& urlCurrent,
+ const QString& caption=QString(),
+ bool allowSaving=true);
+
+ void loadImageInfos(const ImageInfoList &imageInfoList,
+ ImageInfo *imageInfoCurrent,
+ const QString& 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 QString& caption, bool allowSaving);
+ void closeEvent(QCloseEvent* e);
+
+ void dragMoveEvent(QDragMoveEvent *e);
+ void dropEvent(QDropEvent *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 QString& theme);
+
+private:
+
+ ImageWindowPriv *d;
+
+ static ImageWindow *m_instance;
+};
+
+} // namespace Digikam
+
+#endif /* IMAGEWINDOW_H */
diff --git a/digikam/utilities/imageeditor/editor/savingcontextcontainer.h b/digikam/utilities/imageeditor/editor/savingcontextcontainer.h
new file mode 100644
index 0000000..2ada4bd
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <ktempfile.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;
+
+ QString originalFormat;
+ QString format;
+
+ KURL srcURL;
+ KURL destinationURL;
+
+ KTempFile *saveTempFile;
+};
+
+} // namespace Digikam
+
+#endif /* SAVINGCONTEXTCONTAINER_H */
diff --git a/digikam/utilities/imageeditor/rawimport/Makefile.am b/digikam/utilities/imageeditor/rawimport/Makefile.am
new file mode 100644
index 0000000..c3b1979
--- /dev/null
+++ b/digikam/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_KDEPRINT)
+
+INCLUDES= -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/editor \
+ -I$(top_srcdir)/digikam/libs/histogram \
+ -I$(top_srcdir)/digikam/libs/curves \
+ -I$(top_srcdir)/digikam/libs/levels \
+ -I$(top_srcdir)/digikam/libs/whitebalance \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/curves \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dimg/filters \
+ -I$(top_srcdir)/digikam/libs/dialogs \
+ -I$(top_srcdir)/digikam/libs/widgets/common \
+ -I$(top_srcdir)/digikam/libs/widgets/iccprofiles \
+ -I$(top_srcdir)/digikam/libs/threadimageio \
+ -I$(top_srcdir)/digikam/libs/themeengine \
+ $(LIBKDCRAW_CFLAGS) \
+ $(all_includes)
+
diff --git a/digikam/utilities/imageeditor/rawimport/rawimport.cpp b/digikam/utilities/imageeditor/rawimport/rawimport.cpp
new file mode 100644
index 0000000..30f0a4e
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <kcursor.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kapplication.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, QObject *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, SIGNAL(signalLoadingStarted()),
+ this, SLOT(slotLoadingStarted()));
+
+ connect(d->previewWidget, SIGNAL(signalDemosaicedImage()),
+ this, SLOT(slotDemosaicedImage()));
+
+ connect(d->previewWidget, SIGNAL(signalLoadingStarted()),
+ this, SLOT(slotLoadingStarted()));
+
+ connect(d->previewWidget, SIGNAL(signalLoadingProgress(float)),
+ this, SLOT(slotLoadingProgress(float)));
+
+ connect(d->previewWidget, SIGNAL(signalLoadingFailed()),
+ this, SLOT(slotLoadingFailed()));
+
+ connect(d->settingsBox, SIGNAL(signalDemosaicingChanged()),
+ this, SLOT(slotDemosaicingChanged()));
+
+ connect(d->settingsBox, SIGNAL(signalPostProcessingChanged()),
+ this, SLOT(slotTimer()));
+
+ connect(d->settingsBox, SIGNAL(signalUpdatePreview()),
+ this, SLOT(slotUpdatePreview()));
+
+ connect(d->settingsBox, SIGNAL(signalAbortPreview()),
+ this, 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/digikam/utilities/imageeditor/rawimport/rawimport.h b/digikam/utilities/imageeditor/rawimport/rawimport.h
new file mode 100644
index 0000000..15da997
--- /dev/null
+++ b/digikam/utilities/imageeditor/rawimport/rawimport.h
@@ -0,0 +1,87 @@
+/* ============================================================
+ *
+ * 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
+{
+ Q_OBJECT
+
+public:
+
+ RawImport(const KURL& url, QObject *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/digikam/utilities/imageeditor/rawimport/rawpostprocessing.cpp b/digikam/utilities/imageeditor/rawimport/rawpostprocessing.cpp
new file mode 100644
index 0000000..de6d6c5
--- /dev/null
+++ b/digikam/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, QObject *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/digikam/utilities/imageeditor/rawimport/rawpostprocessing.h b/digikam/utilities/imageeditor/rawimport/rawpostprocessing.h
new file mode 100644
index 0000000..d9ee96e
--- /dev/null
+++ b/digikam/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, QObject *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/digikam/utilities/imageeditor/rawimport/rawpreview.cpp b/digikam/utilities/imageeditor/rawimport/rawpreview.cpp
new file mode 100644
index 0000000..3cac33f
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qpainter.h>
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+#include <qpixmap.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <klocale.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;
+
+ QToolButton *cornerButton;
+
+ KPopupFrame *panIconPopup;
+
+ KURL url;
+
+ PanIconWidget *panIconWidget;
+
+ DImg demosaicedImg;
+
+ DImg postProcessedImg;
+
+ DRawDecoding settings;
+
+ ManagedLoadSaveThread *thread;
+
+ LoadingDescription loadingDesc;
+};
+
+RawPreview::RawPreview(const KURL& url, QWidget *parent)
+ : PreviewWidget(parent)
+{
+ d = new RawPreviewPriv;
+ d->thread = new ManagedLoadSaveThread;
+ d->url = url;
+
+ setMinimumWidth(500);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ d->cornerButton = new QToolButton(this);
+ d->cornerButton->setIconSet(SmallIcon("move"));
+ d->cornerButton->hide();
+ QToolTip::add(d->cornerButton, i18n("Pan the image to a region"));
+ setCornerWidget(d->cornerButton);
+
+ // ------------------------------------------------------------
+
+ connect(d->thread, SIGNAL(signalImageLoaded(const LoadingDescription&, const DImg&)),
+ this, SLOT(slotImageLoaded(const LoadingDescription&, const DImg&)));
+
+ connect(d->thread, SIGNAL(signalLoadingProgress(const LoadingDescription&, float)),
+ this, SLOT(slotLoadingProgress(const LoadingDescription&, float)));
+
+ connect(d->cornerButton, SIGNAL(pressed()),
+ this, SLOT(slotCornerButtonPressed()));
+
+ connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
+ this, 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())
+ {
+ QPixmap pix(visibleWidth(), visibleHeight());
+ pix.fill(ThemeEngine::instance()->baseColor());
+ QPainter p(&pix);
+ p.setPen(QPen(ThemeEngine::instance()->textRegColor()));
+ p.drawText(0, 0, pix.width(), pix.height(),
+ Qt::AlignCenter|Qt::WordBreak,
+ i18n("Cannot decode RAW image for\n\"%1\"")
+ .arg(QFileInfo(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 KPopupFrame(this);
+ PanIconWidget *pan = new PanIconWidget(d->panIconPopup);
+ pan->setImage(180, 120, postProcessedImage());
+ d->panIconPopup->setMainWidget(pan);
+
+ QRect r((int)(contentsX() / zoomFactor()), (int)(contentsY() / zoomFactor()),
+ (int)(visibleWidth() / zoomFactor()), (int)(visibleHeight() / zoomFactor()));
+ pan->setRegionSelection(r);
+ pan->setMouseFocus();
+
+ connect(pan, SIGNAL(signalSelectionMoved(const QRect&, bool)),
+ this, SLOT(slotPanIconSelectionMoved(const QRect&, bool)));
+
+ connect(pan, SIGNAL(signalHiden()),
+ this, SLOT(slotPanIconHiden()));
+
+ QPoint g = mapToGlobal(viewport()->pos());
+ g.setX(g.x()+ viewport()->size().width());
+ g.setY(g.y()+ viewport()->size().height());
+ d->panIconPopup->popup(QPoint(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 QRect& 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(QResizeEvent* e)
+{
+ if (!e) return;
+
+ QScrollView::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(QPixmap *pix, int sx, int sy, int sw, int sh)
+{
+ DImg img = d->postProcessedImg.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize());
+ QPixmap pix2 = img.convertToPixmap();
+ bitBlt(pix, 0, 0, &pix2, 0, 0);
+}
+
+} // NameSpace Digikam
diff --git a/digikam/utilities/imageeditor/rawimport/rawpreview.h b/digikam/utilities/imageeditor/rawimport/rawpreview.h
new file mode 100644
index 0000000..eabce7d
--- /dev/null
+++ b/digikam/utilities/imageeditor/rawimport/rawpreview.h
@@ -0,0 +1,107 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qimage.h>
+
+// KDE includes.
+
+#include <kurl.h>
+
+// Local includes.
+
+#include "dimg.h"
+#include "previewwidget.h"
+#include "digikam_export.h"
+
+class QPixmap;
+
+namespace Digikam
+{
+
+class LoadingDescription;
+class RawPreviewPriv;
+
+class DIGIKAM_EXPORT RawPreview : public PreviewWidget
+{
+
+Q_OBJECT
+
+public:
+
+ RawPreview(const KURL& url, QWidget *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(QResizeEvent* 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 QRect&, 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(QPixmap *pix, int sx, int sy, int sw, int sh);
+
+private:
+
+ RawPreviewPriv* d;
+};
+
+} // NameSpace Digikam
+
+#endif /* RAWPREVIEW_H */
diff --git a/digikam/utilities/imageeditor/rawimport/rawsettingsbox.cpp b/digikam/utilities/imageeditor/rawimport/rawsettingsbox.cpp
new file mode 100644
index 0000000..0cd63a8
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qhbuttongroup.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qtoolbutton.h>
+#include <qtoolbox.h>
+#include <qpushbutton.h>
+
+// KDE includes.
+
+#include <kapplication.h>
+#include <ktabwidget.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kfiledialog.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;
+ }
+
+ QWidget *advExposureBox;
+ QWidget *curveBox;
+ QWidget *rawdecodingBox;
+
+ QComboBox *channelCB;
+ QComboBox *colorsCB;
+
+ QLabel *brightnessLabel;
+ QLabel *contrastLabel;
+ QLabel *gammaLabel;
+ QLabel *saturationLabel;
+ QLabel *fineExposureLabel;
+
+ QHButtonGroup *scaleBG;
+
+ QPushButton *abortBtn;
+ QPushButton *updateBtn;
+
+ QToolButton *resetCurveBtn;
+
+ QToolBox *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, QWidget *parent)
+ : EditorToolSettings(Default|Ok|Cancel, NoTool, parent)
+{
+ d = new RawSettingsBoxPriv;
+
+ // ---------------------------------------------------------------
+
+ QGridLayout* gridSettings = new QGridLayout(plainPage(), 5, 4);
+
+ QLabel *label1 = new QLabel(i18n("Channel:"), plainPage());
+ label1->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
+ d->channelCB = new QComboBox(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") );
+ QWhatsThis::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 QHButtonGroup(plainPage());
+ d->scaleBG->setExclusive(true);
+ d->scaleBG->setFrameShape(QFrame::NoFrame);
+ d->scaleBG->setInsideMargin( 0 );
+ QWhatsThis::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."));
+
+ QPushButton *linHistoButton = new QPushButton( d->scaleBG );
+ QToolTip::add( linHistoButton, i18n( "<p>Linear" ) );
+ d->scaleBG->insert(linHistoButton, HistogramWidget::LinScaleHistogram);
+ KGlobal::dirs()->addResourceType("histogram-lin", KGlobal::dirs()->kde_default("data") + "digikam/data");
+ QString directory = KGlobal::dirs()->findResourceDir("histogram-lin", "histogram-lin.png");
+ linHistoButton->setPixmap( QPixmap( directory + "histogram-lin.png" ) );
+ linHistoButton->setToggleButton(true);
+
+ QPushButton *logHistoButton = new QPushButton( d->scaleBG );
+ QToolTip::add( logHistoButton, i18n( "<p>Logarithmic" ) );
+ d->scaleBG->insert(logHistoButton, HistogramWidget::LogScaleHistogram);
+ KGlobal::dirs()->addResourceType("histogram-log", KGlobal::dirs()->kde_default("data") + "digikam/data");
+ directory = KGlobal::dirs()->findResourceDir("histogram-log", "histogram-log.png");
+ logHistoButton->setPixmap( QPixmap( directory + "histogram-log.png" ) );
+ logHistoButton->setToggleButton(true);
+
+ QLabel *label10 = new QLabel(i18n("Colors:"), plainPage());
+ label10->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
+ d->colorsCB = new QComboBox(false, plainPage());
+ d->colorsCB->insertItem( i18n("Red") );
+ d->colorsCB->insertItem( i18n("Green") );
+ d->colorsCB->insertItem( i18n("Blue") );
+ d->colorsCB->setEnabled( false );
+ QWhatsThis::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>"));
+
+ // ---------------------------------------------------------------
+
+ QVBox *histoBox = new QVBox(plainPage());
+ d->histogramWidget = new HistogramWidget(256, 140, histoBox, false, true, true);
+ QWhatsThis::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."));
+ QLabel *space = new QLabel(histoBox);
+ space->setFixedHeight(1);
+ d->hGradient = new ColorGradientWidget( ColorGradientWidget::Horizontal, 10, histoBox );
+ d->hGradient->setColors( QColor( "black" ), QColor( "white" ) );
+
+ // ---------------------------------------------------------------
+
+ d->tabView = new KTabWidget(plainPage());
+ d->rawdecodingBox = new QWidget(d->tabView);
+ QGridLayout* rawGrid = new QGridLayout(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 QPushButton(d->rawdecodingBox);
+ d->abortBtn->setText(i18n("Abort"));
+ d->abortBtn->setIconSet(SmallIconSet("stop"));
+ d->abortBtn->setEnabled(false);
+ QToolTip::add(d->abortBtn, i18n("Abort the current Raw image preview."));
+
+ d->updateBtn = new QPushButton(d->rawdecodingBox);
+ d->updateBtn->setText(i18n("Update"));
+ d->updateBtn->setIconSet(SmallIconSet("reload_page"));
+ d->updateBtn->setEnabled(false);
+ QToolTip::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 QToolBox(d->tabView);
+ d->infoBox = new ImageDialogPreview(d->postProcessSettingsBox);
+ d->infoBox->showPreview(url);
+
+ // ---------------------------------------------------------------
+
+ d->advExposureBox = new QWidget(d->postProcessSettingsBox);
+ QGridLayout* advExposureLayout = new QGridLayout(d->advExposureBox, 5, 2);
+
+ d->brightnessLabel = new QLabel(i18n("Brightness:"), d->advExposureBox);
+ d->brightnessInput = new RIntNumInput(d->advExposureBox);
+ d->brightnessInput->setRange(-100, 100, 1);
+ d->brightnessInput->setDefaultValue(0);
+ QWhatsThis::add(d->brightnessInput->input(), i18n("<p>Set here the brightness adjustment of the image."));
+
+ d->contrastLabel = new QLabel(i18n("Contrast:"), d->advExposureBox);
+ d->contrastInput = new RIntNumInput(d->advExposureBox);
+ d->contrastInput->setRange(-100, 100, 1);
+ d->contrastInput->setDefaultValue(0);
+ QWhatsThis::add(d->contrastInput->input(), i18n("<p>Set here the contrast adjustment of the image."));
+
+ d->gammaLabel = new QLabel(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);
+ QWhatsThis::add(d->gammaInput->input(), i18n("Set here the gamma adjustement of the image"));
+
+ d->saturationLabel = new QLabel(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);
+ QWhatsThis::add(d->saturationInput->input(), i18n("<p>Set here the color saturation correction."));
+
+ d->fineExposureLabel = new QLabel(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);
+ QWhatsThis::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 QWidget(d->postProcessSettingsBox);
+ QGridLayout* curveLayout = new QGridLayout(d->curveBox, 3, 2);
+
+ ColorGradientWidget* vGradient = new ColorGradientWidget(ColorGradientWidget::Vertical, 10, d->curveBox);
+ vGradient->setColors( QColor( "white" ), QColor( "black" ) );
+
+ QLabel *spacev = new QLabel(d->curveBox);
+ spacev->setFixedWidth(1);
+
+ d->curveWidget = new CurvesWidget(256, 192, d->curveBox);
+ QWhatsThis::add(d->curveWidget, i18n("<p>This is the curve adjustment of the image luminosity"));
+
+ d->resetCurveBtn = new QToolButton(d->curveBox);
+ d->resetCurveBtn->setFixedSize(11, 11);
+ d->resetCurveBtn->setIconSet(SmallIconSet("reload_page", 8));
+ d->resetCurveBtn->setFocusPolicy(QWidget::NoFocus);
+ d->resetCurveBtn->setAutoRaise(true);
+ QToolTip::add(d->resetCurveBtn, i18n("Reset curve to linear"));
+
+ QLabel *spaceh = new QLabel(d->curveBox);
+ spaceh->setFixedHeight(1);
+
+ ColorGradientWidget *hGradient = new ColorGradientWidget(ColorGradientWidget::Horizontal, 10, d->curveBox);
+ hGradient->setColors( QColor( "black" ), QColor( "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"));
+ QToolTip::add(button(Default), i18n("<p>Reset all settings to default values."));
+
+ button(Ok)->setText(i18n("Import"));
+ button(Ok)->setIconSet(SmallIconSet("ok"));
+ QToolTip::add(button(Ok), i18n("<p>Import image to editor using current settings."));
+
+ button(Cancel)->setText(i18n("Use Default"));
+ button(Cancel)->setIconSet(SmallIconSet("gohome"));
+ QToolTip::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, SIGNAL(activated(int)),
+ this, SLOT(slotChannelChanged(int)));
+
+ connect(d->scaleBG, SIGNAL(released(int)),
+ this, SLOT(slotScaleChanged(int)));
+
+ connect(d->colorsCB, SIGNAL(activated(int)),
+ this, SLOT(slotColorsChanged(int)));
+
+ connect(d->resetCurveBtn, SIGNAL(clicked()),
+ this, SLOT(slotResetCurve()));
+
+ connect(d->updateBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalUpdatePreview()));
+
+ connect(d->abortBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalAbortPreview()));
+
+ connect(d->decodingSettingsBox, SIGNAL(signalSettingsChanged()),
+ this, SIGNAL(signalDemosaicingChanged()));
+
+ connect(d->curveWidget, SIGNAL(signalCurvesChanged()),
+ this, SIGNAL(signalPostProcessingChanged()));
+
+ connect(d->brightnessInput, SIGNAL(valueChanged(int)),
+ this, SIGNAL(signalPostProcessingChanged()));
+
+ connect(d->contrastInput, SIGNAL(valueChanged(int)),
+ this, SIGNAL(signalPostProcessingChanged()));
+
+ connect(d->gammaInput, SIGNAL(valueChanged(double)),
+ this, SIGNAL(signalPostProcessingChanged()));
+
+ connect(d->saturationInput, SIGNAL(valueChanged(double)),
+ this, SIGNAL(signalPostProcessingChanged()));
+
+ connect(d->fineExposureInput, SIGNAL(valueChanged(double)),
+ this, 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()
+{
+ KConfig* 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", QString()));
+ d->decodingSettingsBox->setOutputColorProfile(config->readPathEntry("Output Color Profile", QString()));
+
+ 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++)
+ {
+ QPoint disable(-1, -1);
+ QPoint p = config->readPointEntry(QString("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()
+{
+ KConfig* 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++)
+ {
+ QPoint 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(QString("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( QColor( "black" ), QColor( "white" ) );
+ d->colorsCB->setEnabled(false);
+ break;
+
+ case RawSettingsBoxPriv::RedChannel:
+ d->histogramWidget->m_channelType = HistogramWidget::RedChannelHistogram;
+ d->hGradient->setColors( QColor( "black" ), QColor( "red" ) );
+ d->colorsCB->setEnabled(false);
+ break;
+
+ case RawSettingsBoxPriv::GreenChannel:
+ d->histogramWidget->m_channelType = HistogramWidget::GreenChannelHistogram;
+ d->hGradient->setColors( QColor( "black" ), QColor( "green" ) );
+ d->colorsCB->setEnabled(false);
+ break;
+
+ case RawSettingsBoxPriv::BlueChannel:
+ d->histogramWidget->m_channelType = HistogramWidget::BlueChannelHistogram;
+ d->hGradient->setColors( QColor( "black" ), QColor( "blue" ) );
+ d->colorsCB->setEnabled(false);
+ break;
+
+ case RawSettingsBoxPriv::ColorChannels:
+ d->histogramWidget->m_channelType = HistogramWidget::ColorChannelsHistogram;
+ d->hGradient->setColors( QColor( "black" ), QColor( "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/digikam/utilities/imageeditor/rawimport/rawsettingsbox.h b/digikam/utilities/imageeditor/rawimport/rawsettingsbox.h
new file mode 100644
index 0000000..5aa60bb
--- /dev/null
+++ b/digikam/utilities/imageeditor/rawimport/rawsettingsbox.h
@@ -0,0 +1,90 @@
+/* ============================================================
+ *
+ * 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
+{
+ Q_OBJECT
+
+public:
+
+ RawSettingsBox(const KURL& url, QWidget *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/digikam/utilities/imageeditor/tools/Makefile.am b/digikam/utilities/imageeditor/tools/Makefile.am
new file mode 100644
index 0000000..d49ced0
--- /dev/null
+++ b/digikam/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_KDEPRINT)
+
+INCLUDES= -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dimg/filters \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/widgets/common \
+ -I$(top_srcdir)/digikam/libs/greycstoration \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/canvas \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/editor \
+ $(LIBKDCRAW_CFLAGS) \
+ $(all_includes)
+
diff --git a/digikam/utilities/imageeditor/tools/imageprint.cpp b/digikam/utilities/imageeditor/tools/imageprint.cpp
new file mode 100644
index 0000000..465ea65
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qbuttongroup.h>
+#include <qstring.h>
+#include <qsize.h>
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qhbox.h>
+#include <qcheckbox.h>
+#include <qfont.h>
+#include <qgrid.h>
+#include <qimage.h>
+#include <qpaintdevicemetrics.h>
+#include <qpainter.h>
+#include <qradiobutton.h>
+#include <qvbuttongroup.h>
+#include <qcolor.h>
+#include <qcombobox.h>
+#include <qstyle.h>
+#include <qpushbutton.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kimageio.h>
+#include <kcombobox.h>
+#include <kglobalsettings.h>
+#include <knuminput.h>
+#include <kprinter.h>
+#include <ktempfile.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(){}
+
+ QString filename;
+ QString inProfilePath;
+ QString outputProfilePath;
+
+ DImg image;
+};
+
+ImagePrint::ImagePrint(DImg& image, KPrinter& printer, const QString& filename)
+ : m_printer(printer)
+{
+ d = new ImagePrintPrivate();
+ d->image = image;
+ d->filename = filename;
+}
+
+ImagePrint::~ImagePrint()
+{
+ delete d;
+}
+
+bool ImagePrint::printImageWithQt()
+{
+ if ( d->image.isNull() )
+ {
+ DWarning() << "Supplied Image for printing is null" << endl;
+ return false;
+ }
+
+ QString t = "true";
+ QString 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 );
+ }
+
+ QImage image2Print = d->image.copyQImage();
+
+ // Black & white print ?
+ if ( m_printer.option( "app-imageeditor-blackwhite" ) != f)
+ {
+ image2Print = image2Print.convertDepth( 1, Qt::MonoOnly |
+ Qt::ThresholdDither |
+ Qt::AvoidDither );
+ }
+
+ QPainter p;
+ p.begin( &m_printer );
+
+ QPaintDeviceMetrics metrics( &m_printer );
+ p.setFont( KGlobalSettings::generalFont() );
+ QFontMetrics 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;
+
+ QSize 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, QSize::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(KApplication::kApplication()->mainWidget(),
+ i18n("The image will not fit on the page, what do you want to do?"),
+ QString(),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, QSize::ScaleMin);
+ }
+ }
+ }
+
+ // Align image.
+ int alignment = (m_printer.option("app-imageeditor-alignment").isEmpty() ?
+ Qt::AlignCenter : m_printer.option("app-imageeditor-alignment").toInt());
+
+ int x = 0;
+ int y = 0;
+
+ // x - alignment
+ if ( alignment & Qt::AlignHCenter )
+ x = (w - size.width())/2;
+ else if ( alignment & Qt::AlignLeft )
+ x = 0;
+ else if ( alignment & Qt::AlignRight )
+ x = w - size.width();
+
+ // y - alignment
+ if ( alignment & Qt::AlignVCenter )
+ y = (h - size.height())/2;
+ else if ( alignment & Qt::AlignTop )
+ y = 0;
+ else if ( alignment & Qt::AlignBottom )
+ y = h - size.height();
+
+ // Perform the actual drawing.
+ p.drawImage( QRect( x, y, size.width(), size.height()), image2Print );
+
+ if ( printFilename )
+ {
+ QString 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;
+}
+
+QString ImagePrint::minimizeString( QString text, const QFontMetrics& metrics,
+ int maxWidth )
+{
+ // no sense to cut that tiny little string
+ if ( text.length() <= 5 )
+ return QString();
+
+ 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 QString();
+
+ text.replace( mid - 1, 3, "..." );
+ }
+
+ return text;
+}
+
+void ImagePrint::readSettings()
+{
+ KConfig* 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;
+
+ QRadioButton *scaleToFit;
+ QRadioButton *scale;
+
+ QCheckBox *keepRatio;
+ QCheckBox *addFileName;
+ QCheckBox *blackwhite;
+ QCheckBox *autoRotate;
+ QCheckBox *colorManaged;
+
+ QPushButton *cmPreferences;
+
+ QWidget *parent;
+
+ KDoubleNumInput *width;
+ KDoubleNumInput *height;
+
+ KComboBox *position;
+ KComboBox *units;
+
+ DImg image;
+
+ ImageEditorPrintDialogPage::Unit previousUnit;
+};
+
+ImageEditorPrintDialogPage::ImageEditorPrintDialogPage(DImg& image, QWidget *parent, const char *name )
+ : KPrintDialogPage( parent, name )
+{
+ d = new ImageEditorPrintDialogPagePrivate;
+ d->image = image;
+ d->parent = parent;
+ setTitle( i18n("Image Settings") );
+
+ readSettings();
+
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ layout->setMargin( KDialog::marginHint() );
+ layout->setSpacing( KDialog::spacingHint() );
+
+ // ------------------------------------------------------------------------
+
+ QHBoxLayout *layout2 = new QHBoxLayout( layout );
+ layout2->setSpacing(3);
+
+ QLabel* textLabel = new QLabel( 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 );
+ QSpacerItem *spacer1 = new QSpacerItem( 101, 21, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ layout2->addItem( spacer1 );
+
+ d->addFileName = new QCheckBox( i18n("Print fi&lename below image"), this);
+ d->addFileName->setChecked( false );
+ layout->addWidget( d->addFileName );
+
+ d->blackwhite = new QCheckBox ( i18n("Print image in &black and white"), this);
+ d->blackwhite->setChecked( false );
+ layout->addWidget (d->blackwhite );
+
+ d->autoRotate = new QCheckBox( i18n("&Auto-rotate page"), this );
+ d->autoRotate->setChecked( false );
+ layout->addWidget( d->autoRotate );
+
+ // ------------------------------------------------------------------------
+
+ QHBox *cmbox = new QHBox(this);
+
+ d->colorManaged = new QCheckBox(i18n("Use Color Management for Printing"), cmbox);
+ d->colorManaged->setChecked( false );
+
+ d->cmPreferences = new QPushButton(i18n("Settings..."), cmbox);
+
+ QWidget *space = new QWidget(cmbox);
+ cmbox->setStretchFactor(space, 10);
+ cmbox->setSpacing(KDialog::spacingHint());
+
+ layout->addWidget(cmbox);
+
+ // ------------------------------------------------------------------------
+
+ QVButtonGroup *group = new QVButtonGroup( i18n("Scaling"), this );
+ group->setRadioButtonExclusive( true );
+ layout->addWidget( group );
+
+ d->scaleToFit = new QRadioButton( i18n("Scale image to &fit"), group );
+ d->scaleToFit->setChecked( true );
+
+ d->scale = new QRadioButton( i18n("Print e&xact size: "), group );
+
+ QHBox *hb = new QHBox( group );
+ hb->setSpacing( KDialog::spacingHint() );
+ QWidget *w = new QWidget(hb);
+ w->setFixedWidth(d->scale->style().subRect( QStyle::SR_RadioButtonIndicator, d->scale ).width());
+
+ d->width = new KDoubleNumInput( hb, "exact width" );
+ d->width->setMinValue( 1 );
+
+ new QLabel( "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 QCheckBox( i18n("Keep ratio"), hb);
+
+ w = new QWidget(hb);
+ hb->setStretchFactor( w, 1 );
+ d->previousUnit = DK_MILLIMETERS;
+
+ // ------------------------------------------------------------------------
+
+ connect( d->colorManaged, SIGNAL(toggled(bool)),
+ this, SLOT(slotAlertSettings( bool )) );
+
+ connect( d->cmPreferences, SIGNAL(clicked()),
+ this, SLOT(slotSetupDlg()) );
+
+ connect( d->scale, SIGNAL( toggled( bool )),
+ this, SLOT( toggleScaling( bool )));
+
+ connect(d->width, SIGNAL( valueChanged( double )),
+ this, SLOT( slotWidthChanged( double )));
+
+ connect(d->height, SIGNAL( valueChanged( double )),
+ this, SLOT( slotHeightChanged( double )));
+
+ connect(d->keepRatio, SIGNAL( toggled( bool )),
+ this, SLOT( toggleRatio( bool )));
+
+ connect(d->units, SIGNAL(activated(const QString &)),
+ this, SLOT(slotUnitChanged(const QString& )));
+}
+
+ImageEditorPrintDialogPage::~ImageEditorPrintDialogPage()
+{
+ delete d;
+}
+
+void ImageEditorPrintDialogPage::getOptions( QMap<QString,QString>& opts, bool /*incldef*/ )
+{
+ QString t = "true";
+ QString f = "false";
+
+ opts["app-imageeditor-alignment"] = QString::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"] = QString::number(stringToUnit(d->units->currentText()));
+ opts["app-imageeditor-scale-width"] = QString::number( d->width->value() );
+ opts["app-imageeditor-scale-height"] = QString::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 QMap<QString,QString>& opts )
+{
+ QString t = "true";
+ QString f = "false";
+ QString 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 QString& align)
+{
+ int alignment;
+
+ if (align == i18n("Central-Left"))
+ {
+ alignment = Qt::AlignLeft | Qt::AlignVCenter;
+ }
+ else if (align == i18n("Central-Right"))
+ {
+ alignment = Qt::AlignRight | Qt::AlignVCenter;
+ }
+ else if (align == i18n("Top-Left"))
+ {
+ alignment = Qt::AlignTop | Qt::AlignLeft;
+ }
+ else if (align == i18n("Top-Right"))
+ {
+ alignment = Qt::AlignTop | Qt::AlignRight;
+ }
+ else if (align == i18n("Bottom-Left"))
+ {
+ alignment = Qt::AlignBottom | Qt::AlignLeft;
+ }
+ else if (align == i18n("Bottom-Right"))
+ {
+ alignment = Qt::AlignBottom | Qt::AlignRight;
+ }
+ else if (align == i18n("Top-Central"))
+ {
+ alignment = Qt::AlignTop | Qt::AlignHCenter;
+ }
+ else if (align == i18n("Bottom-Central"))
+ {
+ alignment = Qt::AlignBottom | Qt::AlignHCenter;
+ }
+ else
+ {
+ // Central
+ alignment = Qt::AlignCenter; // Qt::AlignHCenter || Qt::AlignVCenter
+ }
+
+ return alignment;
+}
+
+QString ImageEditorPrintDialogPage::setPosition(int align)
+{
+ QString alignment;
+
+ if (align == (Qt::AlignLeft | Qt::AlignVCenter))
+ {
+ alignment = i18n("Central-Left");
+ }
+ else if (align == (Qt::AlignRight | Qt::AlignVCenter))
+ {
+ alignment = i18n("Central-Right");
+ }
+ else if (align == (Qt::AlignTop | Qt::AlignLeft))
+ {
+ alignment = i18n("Top-Left");
+ }
+ else if (align == (Qt::AlignTop | Qt::AlignRight))
+ {
+ alignment = i18n("Top-Right");
+ }
+ else if (align == (Qt::AlignBottom | Qt::AlignLeft))
+ {
+ alignment = i18n("Bottom-Left");
+ }
+ else if (align == (Qt::AlignBottom | Qt::AlignRight))
+ {
+ alignment = i18n("Bottom-Right");
+ }
+ else if (align == (Qt::AlignTop | Qt::AlignHCenter))
+ {
+ alignment = i18n("Top-Central");
+ }
+ else if (align == (Qt::AlignBottom | Qt::AlignHCenter))
+ {
+ alignment = i18n("Bottom-Central");
+ }
+ else
+ {
+ // Central: Qt::AlignCenter or (Qt::AlignHCenter || Qt::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 QString& 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()
+{
+ KConfig* 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)
+ {
+ QString 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 QString& unit)
+{
+ if (unit == i18n("Millimeters"))
+ {
+ return DK_MILLIMETERS;
+ }
+ else if (unit == i18n("Centimeters"))
+ {
+ return DK_CENTIMETERS;
+ }
+ else
+ {//Inches
+ return DK_INCHES;
+ }
+}
+
+QString 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/digikam/utilities/imageeditor/tools/imageprint.h b/digikam/utilities/imageeditor/tools/imageprint.h
new file mode 100644
index 0000000..905f6b6
--- /dev/null
+++ b/digikam/utilities/imageeditor/tools/imageprint.h
@@ -0,0 +1,121 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <kprinter.h>
+#include <kdeprint/kprintdialogpage.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class ImagePrintPrivate;
+
+class DIGIKAM_EXPORT ImagePrint
+{
+public:
+
+ ImagePrint(DImg& image, KPrinter& printer, const QString& fileName);
+ ~ImagePrint();
+
+ bool printImageWithQt();
+
+private:
+
+ QString minimizeString(QString text, const QFontMetrics& metrics, int maxWidth);
+ void readSettings();
+
+private:
+
+ KPrinter& m_printer;
+
+ ImagePrintPrivate *d;
+};
+
+//-----------------------------------------------------------------------------
+
+class ImageEditorPrintDialogPagePrivate;
+
+class DIGIKAM_EXPORT ImageEditorPrintDialogPage : public KPrintDialogPage
+{
+ Q_OBJECT
+
+public:
+
+ enum Unit
+ {
+ DK_MILLIMETERS = 1,
+ DK_CENTIMETERS,
+ DK_INCHES
+ };
+
+ static inline double unitToMM(Unit unit);
+ static inline Unit stringToUnit(const QString& unit);
+ static inline QString unitToString(Unit unit);
+
+public:
+
+ ImageEditorPrintDialogPage(DImg& image, QWidget *parent=0L, const char *name=0);
+ ~ImageEditorPrintDialogPage();
+
+ virtual void getOptions(QMap<QString,QString>& opts, bool incldef = false);
+ virtual void setOptions(const QMap<QString,QString>& opts);
+
+private slots:
+
+ void toggleScaling( bool enable );
+ void toggleRatio( bool enable );
+ void slotUnitChanged(const QString& string);
+ void slotHeightChanged(double value);
+ void slotWidthChanged(double value);
+ void slotSetupDlg();
+ void slotAlertSettings(bool t);
+
+private:
+
+ void readSettings();
+ int getPosition(const QString& align);
+ QString setPosition(int align);
+
+private:
+
+ ImageEditorPrintDialogPagePrivate *d;
+};
+
+} // namespace Digikam
+
+#endif // IMAGEPRINT_H
diff --git a/digikam/utilities/imageeditor/tools/imageresize.cpp b/digikam/utilities/imageeditor/tools/imageresize.cpp
new file mode 100644
index 0000000..57ccc72
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qvgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qlayout.h>
+#include <qframe.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qtabwidget.h>
+#include <qtimer.h>
+#include <qevent.h>
+#include <qpixmap.h>
+#include <qbrush.h>
+#include <qfile.h>
+#include <qimage.h>
+
+// KDE includes.
+
+#include <kseparator.h>
+#include <kcursor.h>
+#include <kurllabel.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kglobalsettings.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;
+
+ QWidget *parent;
+
+ QLabel *restorationTips;
+
+ QCheckBox *preserveRatioBox;
+ QCheckBox *useGreycstorationBox;
+
+ QTabWidget *mainTab;
+
+ RIntNumInput *wInput;
+ RIntNumInput *hInput;
+
+ RDoubleNumInput *wpInput;
+ RDoubleNumInput *hpInput;
+
+ KProgress *progressBar;
+
+ KURLLabel *cimgLogoLabel;
+
+ GreycstorationIface *greycstorationIface;
+ GreycstorationWidget *settingsWidget;
+};
+
+ImageResize::ImageResize(QWidget* parent)
+ : KDialogBase(Plain, i18n("Resize Image"),
+ Help|Default|User2|User3|Ok|Cancel, Ok,
+ parent, 0, true, false,
+ QString(),
+ i18n("&Save As..."),
+ i18n("&Load..."))
+{
+ d = new ImageResizePriv;
+ d->parent = parent;
+ setHelp("resizetool.anchor", "digikam");
+ QString 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;
+
+ // -------------------------------------------------------------
+
+ QVBoxLayout *vlay = new QVBoxLayout(plainPage(), 0, spacingHint());
+ d->mainTab = new QTabWidget( plainPage() );
+
+ QWidget* firstPage = new QWidget( d->mainTab );
+ QGridLayout* grid = new QGridLayout( firstPage, 8, 2, spacingHint());
+ d->mainTab->addTab( firstPage, i18n("New Size") );
+
+ QLabel *label1 = new QLabel(i18n("Width:"), firstPage);
+ d->wInput = new RIntNumInput(firstPage);
+ d->wInput->setRange(1, QMAX(d->orgWidth * 10, 9999), 1);
+ d->wInput->setName("d->wInput");
+ d->wInput->setDefaultValue(d->orgWidth);
+ QWhatsThis::add( d->wInput, i18n("<p>Set here the new image width in pixels."));
+
+ QLabel *label2 = new QLabel(i18n("Height:"), firstPage);
+ d->hInput = new RIntNumInput(firstPage);
+ d->hInput->setRange(1, QMAX(d->orgHeight * 10, 9999), 1);
+ d->hInput->setName("d->hInput");
+ d->hInput->setDefaultValue(d->orgHeight);
+ QWhatsThis::add( d->hInput, i18n("<p>Set here the new image height in pixels."));
+
+ QLabel *label3 = new QLabel(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);
+ QWhatsThis::add( d->wpInput, i18n("<p>Set here the new image width in percent."));
+
+ QLabel *label4 = new QLabel(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);
+ QWhatsThis::add( d->hpInput, i18n("<p>Set here the new image height in percent."));
+
+ d->preserveRatioBox = new QCheckBox(i18n("Maintain aspect ratio"), firstPage);
+ QWhatsThis::add( d->preserveRatioBox, i18n("<p>Enable this option to maintain aspect "
+ "ratio with new image sizes."));
+
+ d->cimgLogoLabel = new KURLLabel(firstPage);
+ d->cimgLogoLabel->setText(QString());
+ d->cimgLogoLabel->setURL("http://cimg.sourceforge.net");
+ KGlobal::dirs()->addResourceType("logo-cimg", KGlobal::dirs()->kde_default("data") +
+ "digikam/data");
+ QString directory = KGlobal::dirs()->findResourceDir("logo-cimg", "logo-cimg.png");
+ d->cimgLogoLabel->setPixmap( QPixmap( directory + "logo-cimg.png" ) );
+ QToolTip::add(d->cimgLogoLabel, i18n("Visit CImg library website"));
+
+ d->useGreycstorationBox = new QCheckBox(i18n("Restore photograph"), firstPage);
+ QWhatsThis::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 QLabel(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);
+ QWhatsThis::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();
+ QTimer::singleShot(0, this, SLOT(readUserSettings()));
+
+ // -------------------------------------------------------------
+
+ connect(d->cimgLogoLabel, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(processCImgURL(const QString&)));
+
+ connect(d->wInput, SIGNAL(valueChanged(int)),
+ this, SLOT(slotValuesChanged()));
+
+ connect(d->hInput, SIGNAL(valueChanged(int)),
+ this, SLOT(slotValuesChanged()));
+
+ connect(d->wpInput, SIGNAL(valueChanged(double)),
+ this, SLOT(slotValuesChanged()));
+
+ connect(d->hpInput, SIGNAL(valueChanged(double)),
+ this, SLOT(slotValuesChanged()));
+
+ connect(d->useGreycstorationBox, SIGNAL(toggled(bool)),
+ this, 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()
+{
+ KConfig* 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();
+ KConfig* 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);
+
+ QString 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 QString& url)
+{
+ KApplication::kApplication()->invokeBrowser(url);
+}
+
+void ImageResize::closeEvent(QCloseEvent *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(QCustomEvent *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(KGlobalSettings::documentPath(),
+ QString( "*" ), this,
+ QString( i18n("Photograph Resizing Settings File to Load")) );
+ if( loadBlowupFile.isEmpty() )
+ return;
+
+ QFile file(loadBlowupFile.path());
+
+ if ( file.open(IO_ReadOnly) )
+ {
+ if (!d->settingsWidget->loadSettings(file, QString("# 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(KGlobalSettings::documentPath(),
+ QString( "*" ), this,
+ QString( i18n("Photograph Resizing Settings File to Save")) );
+ if( saveBlowupFile.isEmpty() )
+ return;
+
+ QFile file(saveBlowupFile.path());
+
+ if ( file.open(IO_WriteOnly) )
+ d->settingsWidget->saveSettings(file, QString("# 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/digikam/utilities/imageeditor/tools/imageresize.h b/digikam/utilities/imageeditor/tools/imageresize.h
new file mode 100644
index 0000000..4ea9d88
--- /dev/null
+++ b/digikam/utilities/imageeditor/tools/imageresize.h
@@ -0,0 +1,81 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class ImageResizePriv;
+
+class DIGIKAM_EXPORT ImageResize : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ ImageResize(QWidget* parent);
+ ~ImageResize();
+
+protected:
+
+ void closeEvent(QCloseEvent *e);
+
+private:
+
+ void customEvent(QCustomEvent *event);
+ void writeUserSettings();
+
+private slots:
+
+ void slotOk();
+ void slotCancel();
+ void slotDefault();
+ void slotUser2();
+ void slotUser3();
+ void processCImgURL(const QString&);
+ void slotValuesChanged();
+ void readUserSettings();
+ void slotRestorationToggled(bool);
+
+private:
+
+ ImageResizePriv *d;
+};
+
+} // NameSpace Digikam
+
+#endif /* IMAGE_RESIZE_H */
diff --git a/digikam/utilities/lighttable/Makefile.am b/digikam/utilities/lighttable/Makefile.am
new file mode 100644
index 0000000..ca117d1
--- /dev/null
+++ b/digikam/utilities/lighttable/Makefile.am
@@ -0,0 +1,28 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/libs/widgets/common \
+ -I$(top_srcdir)/digikam/libs/dialogs \
+ -I$(top_srcdir)/digikam/libs/thumbbar \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/themeengine \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/dimg/filters \
+ -I$(top_srcdir)/digikam/libs/imageproperties \
+ -I$(top_srcdir)/digikam/libs/threadimageio \
+ -I$(top_srcdir)/digikam/utilities/setup \
+ -I$(top_srcdir)/digikam/utilities/slideshow \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/canvas \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/editor \
+ -I$(top_builddir)/digikam/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)
+
+rcdir = $(kde_datadir)/digikam
+rc_DATA = lighttablewindowui.rc
diff --git a/digikam/utilities/lighttable/lighttablebar.cpp b/digikam/utilities/lighttable/lighttablebar.cpp
new file mode 100644
index 0000000..6dd6e93
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qimage.h>
+#include <qcursor.h>
+
+// KDE includes.
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kpopupmenu.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;
+
+ QPixmap ratingPixmap;
+
+ LightTableBarToolTip *toolTip;
+};
+
+class LightTableBarItemPriv
+{
+
+public:
+
+ LightTableBarItemPriv()
+ {
+ onLeftPanel = false;
+ onRightPanel = false;
+ info = 0;
+ }
+
+ bool onLeftPanel;
+ bool onRightPanel;
+
+ ImageInfo *info;
+};
+
+LightTableBar::LightTableBar(QWidget* parent, int orientation, bool exifRotate)
+ : ThumbBarView(parent, orientation, exifRotate)
+{
+ d = new LightTableBarPriv;
+ setMouseTracking(true);
+ readToolTipSettings();
+ d->toolTip = new LightTableBarToolTip(this);
+
+ // -- Load rating Pixmap ------------------------------------------
+
+ KGlobal::dirs()->addResourceType("digikam_rating", KGlobal::dirs()->kde_default("data")
+ + "digikam/data");
+ QString ratingPixPath = KGlobal::dirs()->findResourceDir("digikam_rating", "rating.png");
+ ratingPixPath += "/rating.png";
+ d->ratingPixmap = QPixmap(ratingPixPath);
+
+ QPainter painter(&d->ratingPixmap);
+ painter.fillRect(0, 0, d->ratingPixmap.width(), d->ratingPixmap.height(),
+ ThemeEngine::instance()->textSpecialRegColor());
+ painter.end();
+
+ if (orientation == Vertical)
+ setMinimumWidth(d->ratingPixmap.width()*5 + 6 + 2*getMargin());
+ else
+ setMinimumHeight(d->ratingPixmap.width()*5 + 6 + 2*getMargin());
+
+ // ----------------------------------------------------------------
+
+ ImageAttributesWatch *watch = ImageAttributesWatch::instance();
+
+ connect(watch, SIGNAL(signalImageRatingChanged(Q_LLONG)),
+ this, SLOT(slotImageRatingChanged(Q_LLONG)));
+
+ connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
+ this, SLOT(slotThemeChanged()));
+
+ connect(this, SIGNAL(signalItemSelected(ThumbBarItem*)),
+ this, SLOT(slotItemSelected(ThumbBarItem*)));
+}
+
+LightTableBar::~LightTableBar()
+{
+ delete d->toolTip;
+ delete d;
+}
+
+void LightTableBar::setNavigateByPair(bool b)
+{
+ d->navigateByPair = b;
+}
+
+void LightTableBar::slotImageRatingChanged(Q_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(QMouseEvent *e)
+{
+ if (!e) return;
+
+ ThumbBarView::contentsMouseReleaseEvent(e);
+
+ QPoint pos = QCursor::pos();
+ LightTableBarItem *item = findItemByPos(e->pos());
+
+ RatingPopupMenu *ratingMenu = 0;
+
+ if (e->button() == Qt::RightButton)
+ {
+ KPopupMenu popmenu(this);
+
+ if (item)
+ {
+ popmenu.insertItem(SmallIcon("previous"), i18n("Show on left panel"), 10);
+ popmenu.insertItem(SmallIcon("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("fileclose"), 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, SIGNAL(activated(int)),
+ this, 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 = QMIN(5, QMAX(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 QPoint& 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(QPaintEvent* e)
+{
+ ThemeEngine* te = ThemeEngine::instance();
+ QRect er(e->rect());
+ QPixmap bgPix;
+
+ if (countItems() > 0)
+ {
+ int cy, cx, ts, y1, y2, x1, x2;
+ QPixmap tile;
+
+ if (getOrientation() == 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() == 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());
+
+ QPainter p(&tile);
+ if (item == currentItem())
+ {
+ p.setPen(QPen(te->textSelColor(), 3));
+ p.drawRect(2, 2, tile.width()-2, tile.height()-2);
+ }
+ else
+ {
+ p.setPen(QPen(te->textRegColor(), 1));
+ p.drawRect(0, 0, tile.width(), tile.height());
+ }
+ p.end();
+
+ if (item->pixmap())
+ {
+ QPixmap pix;
+ pix.convertFromImage(QImage(item->pixmap()->convertToImage()).
+ smoothScale(getTileSize(), getTileSize(), QImage::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())
+ {
+ QPixmap lPix = SmallIcon("previous");
+ bitBlt(&tile, getMargin(), getMargin(), &lPix);
+ }
+ if (ltItem->isOnRightPanel())
+ {
+ QPixmap rPix = SmallIcon("next");
+ bitBlt(&tile, tile.width() - getMargin() - rPix.width(), getMargin(), &rPix);
+ }
+
+ QRect 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();
+ QPainter 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());
+
+ QPainter p(&tile);
+ if (item == currentItem())
+ {
+ p.setPen(QPen(te->textSelColor(), 2));
+ p.drawRect(1, 1, tile.width()-1, tile.height()-1);
+ }
+ else
+ {
+ p.setPen(QPen(te->textRegColor(), 1));
+ p.drawRect(0, 0, tile.width(), tile.height());
+ }
+ p.end();
+
+ if (item->pixmap())
+ {
+ QPixmap pix;
+ pix.convertFromImage(QImage(item->pixmap()->convertToImage()).
+ smoothScale(getTileSize(), getTileSize(), QImage::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())
+ {
+ QPixmap lPix = SmallIcon("previous");
+ bitBlt(&tile, getMargin(), getMargin(), &lPix);
+ }
+ if (ltItem->isOnRightPanel())
+ {
+ QPixmap rPix = SmallIcon("next");
+ bitBlt(&tile, tile.width() - getMargin() - rPix.width(), getMargin(), &rPix);
+ }
+
+ QRect 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();
+ QPainter p(&tile);
+ p.drawTiledPixmap(xr, r.y(), wr, r.height(), d->ratingPixmap);
+ }
+
+ bitBlt(&bgPix, item->position() - cx, 0, &tile);
+ }
+ }
+ }
+
+ if (getOrientation() == 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());
+ QPainter p(&bgPix);
+ p.setPen(QPen(te->textRegColor()));
+ p.drawText(0, 0, bgPix.width(), bgPix.height(),
+ Qt::AlignCenter|Qt::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;
+ QValueList<int> albumIDs;
+ QValueList<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());
+
+ QPixmap icon(DesktopIcon("image", 48));
+ int w = icon.width();
+ int h = icon.height();
+
+ QPixmap pix(w+4,h+4);
+ QPainter p(&pix);
+ p.fillRect(0, 0, w+4, h+4, QColor(Qt::white));
+ p.setPen(QPen(Qt::black, 1));
+ p.drawRect(0, 0, w+4, h+4);
+ p.drawPixmap(2, 2, icon);
+ p.end();
+
+ QDragObject* drag = 0;
+
+ drag = new ItemDrag(urls, kioURLs, albumIDs, imageIDs, this);
+ if (drag)
+ {
+ drag->setPixmap(pix);
+ drag->drag();
+ }
+}
+
+void LightTableBar::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ int albumID;
+ QValueList<int> albumIDs;
+ QValueList<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(QDropEvent *e)
+{
+ int albumID;
+ QValueList<int> albumIDs;
+ QValueList<int> imageIDs;
+ KURL::List urls;
+ KURL::List kioURLs;
+
+ if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs))
+ {
+ ImageInfoList imageInfoList;
+
+ for (QValueList<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))
+ {
+ QValueList<Q_LLONG> itemIDs = AlbumManager::instance()->albumDB()->getItemIDsInAlbum(albumID);
+ ImageInfoList imageInfoList;
+
+ for (QValueList<Q_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))
+ {
+ QByteArray ba = e->encodedData("digikam/tag-id");
+ QDataStream ds(ba, IO_ReadOnly);
+ int tagID;
+ ds >> tagID;
+
+ AlbumManager* man = AlbumManager::instance();
+ QValueList<Q_LLONG> itemIDs = man->albumDB()->getItemIDsInTag(tagID, true);
+ ImageInfoList imageInfoList;
+
+ for (QValueList<Q_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()
+{
+ KGlobal::dirs()->addResourceType("digikam_rating", KGlobal::dirs()->kde_default("data")
+ + "digikam/data");
+ QString ratingPixPath = KGlobal::dirs()->findResourceDir("digikam_rating", "rating.png");
+ ratingPixPath += "/rating.png";
+ d->ratingPixmap = QPixmap(ratingPixPath);
+
+ QPainter 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)
+{
+}
+
+QString LightTableBarToolTip::tipContentExtraData(ThumbBarItem *item)
+{
+ QString 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 = QString("---");
+ tip += m_cellSpecBeg + i18n("Caption:") + m_cellSpecMid + breakString(str) + m_cellSpecEnd;
+ }
+
+ if (settings->getToolTipsShowTags())
+ {
+ QStringList tagPaths = info->tagPaths(false);
+
+ str = tagPaths.join(", ");
+ if (str.isEmpty()) str = QString("---");
+ 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 = QString("---");
+ tip += m_cellSpecBeg + i18n("Rating:") + m_cellSpecMid + str + m_cellSpecEnd;
+ }
+ }
+ }
+
+ return tip;
+}
+
+} // NameSpace Digikam
diff --git a/digikam/utilities/lighttable/lighttablebar.h b/digikam/utilities/lighttable/lighttablebar.h
new file mode 100644
index 0000000..13428a0
--- /dev/null
+++ b/digikam/utilities/lighttable/lighttablebar.h
@@ -0,0 +1,152 @@
+/* ============================================================
+ *
+ * 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 QDragMoveEvent;
+class QDropEvent;
+class QMouseEvent;
+class QPaintEvent;
+
+class KURL;
+
+namespace Digikam
+{
+
+class LightTableBarItem;
+class LightTableBarItemPriv;
+class LightTableBarPriv;
+
+class DIGIKAM_EXPORT LightTableBar : public ThumbBarView
+{
+ Q_OBJECT
+
+public:
+
+ LightTableBar(QWidget* 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 QPoint& 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(QPaintEvent*);
+ void contentsMouseReleaseEvent(QMouseEvent*);
+ void startDrag();
+ void contentsDragMoveEvent(QDragMoveEvent*);
+ void contentsDropEvent(QDropEvent*);
+
+private slots:
+
+ void slotImageRatingChanged(Q_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:
+
+ QString tipContentExtraData(ThumbBarItem *item);
+};
+
+} // NameSpace Digikam
+
+#endif /* LIGHTTABLEBAR_H */
diff --git a/digikam/utilities/lighttable/lighttablepreview.cpp b/digikam/utilities/lighttable/lighttablepreview.cpp
new file mode 100644
index 0000000..f68148f
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qpainter.h>
+#include <qcursor.h>
+#include <qstring.h>
+#include <qvaluevector.h>
+#include <qfileinfo.h>
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+#include <qpixmap.h>
+#include <qdrawutil.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+#include <klocale.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 <kapplication.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;
+
+ QString path;
+ QString nextPath;
+ QString previousPath;
+
+ QToolButton *cornerButton;
+
+ KPopupFrame *panIconPopup;
+
+ PanIconWidget *panIconWidget;
+
+ DImg preview;
+
+ ImageInfo *imageInfo;
+
+ PreviewLoadThread *previewThread;
+ PreviewLoadThread *previewPreloadThread;
+};
+
+LightTablePreview::LightTablePreview(QWidget *parent)
+ : PreviewWidget(parent)
+{
+ d = new LightTablePreviewPriv;
+
+ // get preview size from screen size, but limit from VGA to WQXGA
+ d->previewSize = QMAX(KApplication::desktop()->height(),
+ KApplication::desktop()->width());
+ if (d->previewSize < 640)
+ d->previewSize = 640;
+ if (d->previewSize > 2560)
+ d->previewSize = 2560;
+
+ viewport()->setAcceptDrops(true);
+ setAcceptDrops(true);
+
+ slotThemeChanged();
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ d->cornerButton = new QToolButton(this);
+ d->cornerButton->setIconSet(SmallIcon("move"));
+ d->cornerButton->hide();
+ QToolTip::add(d->cornerButton, i18n("Pan the image"));
+ setCornerWidget(d->cornerButton);
+
+ setLineWidth(5);
+ setSelected(false);
+
+ // ------------------------------------------------------------
+
+ connect(d->cornerButton, SIGNAL(pressed()),
+ this, SLOT(slotCornerButtonPressed()));
+
+ connect(this, SIGNAL(signalRightButtonClicked()),
+ this, SLOT(slotContextMenu()));
+
+ connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
+ this, 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)
+ {
+ QPixmap pix(visibleWidth(), visibleHeight());
+ pix.fill(ThemeEngine::instance()->baseColor());
+ QPainter p(&pix);
+ p.setPen(QPen(ThemeEngine::instance()->textRegColor()));
+ p.drawText(0, 0, pix.width(), pix.height(),
+ Qt::AlignCenter|Qt::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;
+}
+
+QSize LightTablePreview::getImageSize()
+{
+ return d->preview.size();
+}
+
+void LightTablePreview::reload()
+{
+ // cache is cleaned from AlbumIconView::refreshItems
+ setImagePath(d->path);
+}
+
+void LightTablePreview::setPreviousNextPaths(const QString& previous, const QString &next)
+{
+ d->nextPath = next;
+ d->previousPath = previous;
+}
+
+void LightTablePreview::setImagePath(const QString& path)
+{
+ setCursor( KCursor::waitCursor() );
+
+ d->path = path;
+ d->nextPath = QString();
+ d->previousPath = QString();
+
+ if (d->path.isEmpty())
+ {
+ slotReset();
+ unsetCursor();
+ return;
+ }
+
+ if (!d->previewThread)
+ {
+ d->previewThread = new PreviewLoadThread();
+ connect(d->previewThread, SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
+ this, SLOT(slotGotImagePreview(const LoadingDescription &, const DImg&)));
+ }
+ if (!d->previewPreloadThread)
+ {
+ d->previewPreloadThread = new PreviewLoadThread();
+ connect(d->previewPreloadThread, SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
+ this, 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())
+ {
+ QPixmap pix(visibleWidth(), visibleHeight());
+ pix.fill(ThemeEngine::instance()->baseColor());
+ QPainter p(&pix);
+ QFileInfo info(d->path);
+ p.setPen(QPen(ThemeEngine::instance()->textRegColor()));
+ p.drawText(0, 0, pix.width(), pix.height(),
+ Qt::AlignCenter|Qt::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()
+{
+ QString loadPath;
+ if (!d->nextPath.isNull())
+ {
+ loadPath = d->nextPath;
+ d->nextPath = QString();
+ }
+ else if (!d->previousPath.isNull())
+ {
+ loadPath = d->previousPath;
+ d->previousPath = QString();
+ }
+ 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() : QString(),
+ next ? next->filePath() : QString());
+}
+
+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);
+
+ QValueVector<KService::Ptr> serviceVector;
+ KTrader::OfferList offers = KTrader::self()->query(mimePtr->name(), "Type == 'Application'");
+
+ QPopupMenu openWithMenu;
+
+ KTrader::OfferList::Iterator iter;
+ KService::Ptr ptr;
+ int index = 100;
+
+ for( iter = offers.begin(); iter != offers.end(); ++iter )
+ {
+ ptr = *iter;
+ openWithMenu.insertItem( ptr->pixmap(KIcon::Small), ptr->name(), index++);
+ serviceVector.push_back(ptr);
+ }
+
+ DPopupMenu popmenu(this);
+
+ //-- Zoom actions -----------------------------------------------
+
+ popmenu.insertItem(SmallIcon("viewmag"), i18n("Zoom in"), 17);
+ popmenu.insertItem(SmallIcon("viewmag-"), 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 --------------------------
+
+ Q_LLONG id = d->imageInfo->id();
+ QValueList<Q_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, SIGNAL(signalTagActivated(int)),
+ this, SLOT(slotAssignTag(int)));
+
+ connect(removeTagsMenu, SIGNAL(signalTagActivated(int)),
+ this, 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, SIGNAL(activated(int)),
+ this, SLOT(slotAssignRating(int)));
+
+ popmenu.insertItem(i18n("Assign Rating"), ratingMenu);
+
+ // --------------------------------------------------------
+
+ int idm = popmenu.exec(QCursor::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 = QMIN(RatingMax, QMAX(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 KPopupFrame(this);
+ PanIconWidget *pan = new PanIconWidget(d->panIconPopup);
+ pan->setImage(180, 120, getImage());
+ d->panIconPopup->setMainWidget(pan);
+
+ QRect r((int)(contentsX() / zoomFactor()), (int)(contentsY() / zoomFactor()),
+ (int)(visibleWidth() / zoomFactor()), (int)(visibleHeight() / zoomFactor()));
+ pan->setRegionSelection(r);
+ pan->setMouseFocus();
+
+ connect(pan, SIGNAL(signalSelectionMoved(const QRect&, bool)),
+ this, SLOT(slotPanIconSelectionMoved(const QRect&, bool)));
+
+ connect(pan, SIGNAL(signalHiden()),
+ this, SLOT(slotPanIconHiden()));
+
+ QPoint g = mapToGlobal(viewport()->pos());
+ g.setX(g.x()+ viewport()->size().width());
+ g.setY(g.y()+ viewport()->size().height());
+ d->panIconPopup->popup(QPoint(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 QRect& 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(QResizeEvent* e)
+{
+ if (!e) return;
+
+ QScrollView::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 = QString();
+ d->imageInfo = 0;
+
+ setDragAndDropMessage();
+ updateZoomAndSize(true);
+ viewport()->setUpdatesEnabled(true);
+ viewport()->update();
+ emit signalPreviewLoaded(false);
+}
+
+void LightTablePreview::paintPreview(QPixmap *pix, int sx, int sy, int sw, int sh)
+{
+ DImg img = d->preview.smoothScaleSection(sx, sy, sw, sh, tileSize(), tileSize());
+ QPixmap pix2 = img.convertToPixmap();
+ bitBlt(pix, 0, 0, &pix2, 0, 0);
+}
+
+void LightTablePreview::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ if (d->dragAndDropEnabled)
+ {
+ int albumID;
+ QValueList<int> albumIDs;
+ QValueList<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(QDropEvent *e)
+{
+ if (d->dragAndDropEnabled)
+ {
+ int albumID;
+ QValueList<int> albumIDs;
+ QValueList<int> imageIDs;
+ KURL::List urls;
+ KURL::List kioURLs;
+ ImageInfoList list;
+
+ if (ItemDrag::decode(e, urls, kioURLs, albumIDs, imageIDs))
+ {
+ for (QValueList<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))
+ {
+ QValueList<Q_LLONG> itemIDs = AlbumManager::instance()->albumDB()->getItemIDsInAlbum(albumID);
+
+ for (QValueList<Q_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))
+ {
+ QByteArray ba = e->encodedData("digikam/tag-id");
+ QDataStream ds(ba, IO_ReadOnly);
+ int tagID;
+ ds >> tagID;
+
+ AlbumManager* man = AlbumManager::instance();
+ QValueList<Q_LLONG> itemIDs = man->albumDB()->getItemIDsInTag(tagID, true);
+ ImageInfoList imageInfoList;
+
+ for (QValueList<Q_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(QPainter *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/digikam/utilities/lighttable/lighttablepreview.h b/digikam/utilities/lighttable/lighttablepreview.h
new file mode 100644
index 0000000..2612339
--- /dev/null
+++ b/digikam/utilities/lighttable/lighttablepreview.h
@@ -0,0 +1,124 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qimage.h>
+#include <qsize.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+#include "previewwidget.h"
+#include "digikam_export.h"
+
+class QPixmap;
+
+namespace Digikam
+{
+
+class DImg;
+class LoadingDescription;
+class LightTablePreviewPriv;
+
+class DIGIKAM_EXPORT LightTablePreview : public PreviewWidget
+{
+
+Q_OBJECT
+
+public:
+
+ LightTablePreview(QWidget *parent=0);
+ ~LightTablePreview();
+
+ void setLoadFullImageSize(bool b);
+
+ void setImage(const DImg& image);
+ DImg& getImage() const;
+
+ QSize getImageSize();
+
+ void setImageInfo(ImageInfo* info=0, ImageInfo *previous=0, ImageInfo *next=0);
+ ImageInfo* getImageInfo() const;
+
+ void reload();
+ void setImagePath(const QString& path=QString());
+ void setPreviousNextPaths(const QString& previous, const QString &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(QResizeEvent* e);
+ void drawFrame(QPainter *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 QRect&, bool);
+ void slotPanIconHiden();
+
+private:
+
+ int previewWidth();
+ int previewHeight();
+ bool previewIsNull();
+ void resetPreview();
+ void zoomFactorChanged(double zoom);
+ void updateZoomAndSize(bool alwaysFitToWindow);
+ inline void paintPreview(QPixmap *pix, int sx, int sy, int sw, int sh);
+
+ void contentsDragMoveEvent(QDragMoveEvent*);
+ void contentsDropEvent(QDropEvent*);
+
+private:
+
+ LightTablePreviewPriv* d;
+};
+
+} // NameSpace Digikam
+
+#endif /* LIGHTTABLEPREVIEW_H */
diff --git a/digikam/utilities/lighttable/lighttableview.cpp b/digikam/utilities/lighttable/lighttableview.cpp
new file mode 100644
index 0000000..2ee9633
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.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.
+
+ QGridLayout *grid;
+
+ LightTablePreview *leftPreview;
+ LightTablePreview *rightPreview;
+};
+
+LightTableView::LightTableView(QWidget *parent)
+ : QFrame(parent, 0, Qt::WDestructiveClose)
+{
+ d = new LightTableViewPriv;
+
+ setFrameStyle(QFrame::NoFrame);
+ setMargin(0);
+ setLineWidth(0);
+
+ d->grid = new QGridLayout(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, SIGNAL(signalZoomFactorChanged(double)),
+ this, SIGNAL(signalLeftZoomFactorChanged(double)));
+
+ connect(d->leftPreview, SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotLeftContentsMoved(int, int)));
+
+ connect(d->leftPreview, SIGNAL(signalSlideShow()),
+ this, SIGNAL(signalSlideShow()));
+
+ connect(d->leftPreview, SIGNAL(signalDeleteItem(ImageInfo*)),
+ this, SIGNAL(signalDeleteItem(ImageInfo*)));
+
+ connect(d->leftPreview, SIGNAL(signalEditItem(ImageInfo*)),
+ this, SIGNAL(signalEditItem(ImageInfo*)));
+
+ connect(d->leftPreview, SIGNAL(signalDroppedItems(const ImageInfoList&)),
+ this, SIGNAL(signalLeftDroppedItems(const ImageInfoList&)));
+
+ connect(d->leftPreview, SIGNAL(signalPreviewLoaded(bool)),
+ this, SLOT(slotLeftPreviewLoaded(bool)));
+
+ connect(d->leftPreview, SIGNAL(signalLeftButtonClicked()),
+ this, SIGNAL(signalLeftPanelLeftButtonClicked()));
+
+ // Right panel connections ------------------------------------------------
+
+ connect(d->rightPreview, SIGNAL(signalZoomFactorChanged(double)),
+ this, SIGNAL(signalRightZoomFactorChanged(double)));
+
+ connect(d->rightPreview, SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotRightContentsMoved(int, int)));
+
+ connect(d->rightPreview, SIGNAL(signalDeleteItem(ImageInfo*)),
+ this, SIGNAL(signalDeleteItem(ImageInfo*)));
+
+ connect(d->rightPreview, SIGNAL(signalEditItem(ImageInfo*)),
+ this, SIGNAL(signalEditItem(ImageInfo*)));
+
+ connect(d->rightPreview, SIGNAL(signalDroppedItems(const ImageInfoList&)),
+ this, SIGNAL(signalRightDroppedItems(const ImageInfoList&)));
+
+ connect(d->rightPreview, SIGNAL(signalSlideShow()),
+ this, SIGNAL(signalSlideShow()));
+
+ connect(d->rightPreview, SIGNAL(signalPreviewLoaded(bool)),
+ this, SLOT(slotRightPreviewLoaded(bool)));
+
+ connect(d->rightPreview, SIGNAL(signalLeftButtonClicked()),
+ this, 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, SIGNAL(signalZoomFactorChanged(double)),
+ this, SIGNAL(signalRightZoomFactorChanged(double)));
+
+ disconnect(d->rightPreview, SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotRightContentsMoved(int, int)));
+
+ setRightZoomFactor(d->leftPreview->zoomFactor());
+ emit signalRightZoomFactorChanged(d->leftPreview->zoomFactor());
+ d->rightPreview->setContentsPos(x, y);
+
+ connect(d->rightPreview, SIGNAL(signalZoomFactorChanged(double)),
+ this, SIGNAL(signalRightZoomFactorChanged(double)));
+
+ connect(d->rightPreview, SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotRightContentsMoved(int, int)));
+ }
+}
+
+void LightTableView::slotRightContentsMoved(int x, int y)
+{
+ if (d->syncPreview && !d->rightLoading)
+ {
+ disconnect(d->leftPreview, SIGNAL(signalZoomFactorChanged(double)),
+ this, SIGNAL(signalLeftZoomFactorChanged(double)));
+
+ disconnect(d->leftPreview, SIGNAL(contentsMoving(int, int)),
+ this, SLOT(slotLeftContentsMoved(int, int)));
+
+
+ setLeftZoomFactor(d->rightPreview->zoomFactor());
+ emit signalLeftZoomFactorChanged(d->rightPreview->zoomFactor());
+ d->leftPreview->setContentsPos(x, y);
+
+ connect(d->leftPreview, SIGNAL(signalZoomFactorChanged(double)),
+ this, SIGNAL(signalLeftZoomFactorChanged(double)));
+
+ connect(d->leftPreview, SIGNAL(contentsMoving(int, int)),
+ this, 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/digikam/utilities/lighttable/lighttableview.h b/digikam/utilities/lighttable/lighttableview.h
new file mode 100644
index 0000000..92b6055
--- /dev/null
+++ b/digikam/utilities/lighttable/lighttableview.h
@@ -0,0 +1,136 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qframe.h>
+#include <qstring.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class LightTableViewPriv;
+
+class DIGIKAM_EXPORT LightTableView : public QFrame
+{
+
+Q_OBJECT
+
+public:
+
+ LightTableView(QWidget *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/digikam/utilities/lighttable/lighttablewindow.cpp b/digikam/utilities/lighttable/lighttablewindow.cpp
new file mode 100644
index 0000000..d760c40
--- /dev/null
+++ b/digikam/utilities/lighttable/lighttablewindow.cpp
@@ -0,0 +1,1680 @@
+/* ============================================================
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qdockarea.h>
+
+// KDE includes.
+
+#include <kkeydialog.h>
+#include <kedittoolbar.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kwin.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kstatusbar.h>
+#include <kmenubar.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()
+ : KMainWindow(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()
+{
+ KConfig* 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()
+{
+ KConfig* 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()
+{
+ KConfig* 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(QCloseEvent* e)
+{
+ if (!e) return;
+
+ writeSettings();
+
+ e->accept();
+}
+
+void LightTableWindow::setupUserArea()
+{
+ QWidget* mainW = new QWidget(this);
+ d->hSplitter = new QSplitter(Qt::Horizontal, mainW);
+ QHBoxLayout *hlay = new QHBoxLayout(mainW);
+ d->leftSidebar = new ImagePropertiesSideBarDB(mainW,
+ "LightTable Left Sidebar", d->hSplitter,
+ Sidebar::Left, true);
+
+ QWidget* centralW = new QWidget(d->hSplitter);
+ QVBoxLayout *vlay = new QVBoxLayout(centralW);
+ d->vSplitter = new QSplitter(Qt::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( QFrame::NoFrame );
+ d->hSplitter->setFrameShadow( QFrame::Plain );
+ d->hSplitter->setFrameShape( QFrame::NoFrame );
+ d->hSplitter->setOpaqueResize(false);
+ d->vSplitter->setFrameStyle( QFrame::NoFrame );
+ d->vSplitter->setFrameShadow( QFrame::Plain );
+ d->vSplitter->setFrameShape( QFrame::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(Qt::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, SIGNAL(signalCancelButtonPressed()),
+ this, SLOT(slotProgressBarCancelButtonPressed()));
+
+ connect(ThemeEngine::instance(), SIGNAL(signalThemeChanged()),
+ this, SLOT(slotThemeChanged()));
+
+ // Thumbs bar connections ---------------------------------------
+
+ connect(d->barView, SIGNAL(signalSetItemOnLeftPanel(ImageInfo*)),
+ this, SLOT(slotSetItemOnLeftPanel(ImageInfo*)));
+
+ connect(d->barView, SIGNAL(signalSetItemOnRightPanel(ImageInfo*)),
+ this, SLOT(slotSetItemOnRightPanel(ImageInfo*)));
+
+ connect(d->barView, SIGNAL(signalRemoveItem(ImageInfo*)),
+ this, SLOT(slotRemoveItem(ImageInfo*)));
+
+ connect(d->barView, SIGNAL(signalEditItem(ImageInfo*)),
+ this, SLOT(slotEditItem(ImageInfo*)));
+
+ connect(d->barView, SIGNAL(signalClearAll()),
+ this, SLOT(slotClearItemsList()));
+
+ connect(d->barView, SIGNAL(signalLightTableBarItemSelected(ImageInfo*)),
+ this, SLOT(slotItemSelected(ImageInfo*)));
+
+ connect(d->barView, SIGNAL(signalDroppedItems(const ImageInfoList&)),
+ this, SLOT(slotThumbbarDroppedItems(const ImageInfoList&)));
+
+ // Zoom bars connections -----------------------------------------
+
+ connect(d->leftZoomBar, SIGNAL(signalZoomMinusClicked()),
+ d->previewView, SLOT(slotDecreaseLeftZoom()));
+
+ connect(d->leftZoomBar, SIGNAL(signalZoomPlusClicked()),
+ d->previewView, SLOT(slotIncreaseLeftZoom()));
+
+ connect(d->leftZoomBar, SIGNAL(signalZoomSliderChanged(int)),
+ d->previewView, SLOT(slotLeftZoomSliderChanged(int)));
+
+ connect(d->rightZoomBar, SIGNAL(signalZoomMinusClicked()),
+ d->previewView, SLOT(slotDecreaseRightZoom()));
+
+ connect(d->rightZoomBar, SIGNAL(signalZoomPlusClicked()),
+ d->previewView, SLOT(slotIncreaseRightZoom()));
+
+ connect(d->rightZoomBar, SIGNAL(signalZoomSliderChanged(int)),
+ d->previewView, SLOT(slotRightZoomSliderChanged(int)));
+
+ // View connections ---------------------------------------------
+
+ connect(d->previewView, SIGNAL(signalLeftZoomFactorChanged(double)),
+ this, SLOT(slotLeftZoomFactorChanged(double)));
+
+ connect(d->previewView, SIGNAL(signalRightZoomFactorChanged(double)),
+ this, SLOT(slotRightZoomFactorChanged(double)));
+
+ connect(d->previewView, SIGNAL(signalEditItem(ImageInfo*)),
+ this, SLOT(slotEditItem(ImageInfo*)));
+
+ connect(d->previewView, SIGNAL(signalDeleteItem(ImageInfo*)),
+ this, SLOT(slotDeleteItem(ImageInfo*)));
+
+ connect(d->previewView, SIGNAL(signalSlideShow()),
+ this, SLOT(slotToggleSlideShow()));
+
+ connect(d->previewView, SIGNAL(signalLeftDroppedItems(const ImageInfoList&)),
+ this, SLOT(slotLeftDroppedItems(const ImageInfoList&)));
+
+ connect(d->previewView, SIGNAL(signalRightDroppedItems(const ImageInfoList&)),
+ this, SLOT(slotRightDroppedItems(const ImageInfoList&)));
+
+ connect(d->previewView, SIGNAL(signalToggleOnSyncPreview(bool)),
+ this, SLOT(slotToggleOnSyncPreview(bool)));
+
+ connect(d->previewView, SIGNAL(signalLeftPreviewLoaded(bool)),
+ this, SLOT(slotLeftPreviewLoaded(bool)));
+
+ connect(d->previewView, SIGNAL(signalRightPreviewLoaded(bool)),
+ this, SLOT(slotRightPreviewLoaded(bool)));
+
+ connect(d->previewView, SIGNAL(signalLeftPanelLeftButtonClicked()),
+ this, SLOT(slotLeftPanelLeftButtonClicked()));
+
+ connect(d->previewView, SIGNAL(signalRightPanelLeftButtonClicked()),
+ this, SLOT(slotRightPanelLeftButtonClicked()));
+}
+
+void LightTableWindow::setupActions()
+{
+ // -- Standard 'File' menu actions ---------------------------------------------
+
+ d->backwardAction = KStdAction::back(this, SLOT(slotBackward()),
+ actionCollection(), "lighttable_backward");
+ d->backwardAction->setEnabled(false);
+
+ d->forwardAction = KStdAction::forward(this, SLOT(slotForward()),
+ actionCollection(), "lighttable_forward");
+ d->forwardAction->setEnabled(false);
+
+ d->firstAction = new KAction(i18n("&First"), "start",
+ KStdAccel::shortcut( KStdAccel::Home),
+ this, SLOT(slotFirst()),
+ actionCollection(), "lighttable_first");
+ d->firstAction->setEnabled(false);
+
+ d->lastAction = new KAction(i18n("&Last"), "finish",
+ KStdAccel::shortcut( KStdAccel::End),
+ this, SLOT(slotLast()),
+ actionCollection(), "lighttable_last");
+ d->lastAction->setEnabled(false);
+
+ d->setItemLeftAction = new KAction(i18n("On Left"), "previous",
+ CTRL+Key_L, this, SLOT(slotSetItemLeft()),
+ actionCollection(), "lighttable_setitemleft");
+ d->setItemLeftAction->setEnabled(false);
+ d->setItemLeftAction->setWhatsThis(i18n("Show item on left panel"));
+
+ d->setItemRightAction = new KAction(i18n("On Right"), "next",
+ CTRL+Key_R, this, SLOT(slotSetItemRight()),
+ actionCollection(), "lighttable_setitemright");
+ d->setItemRightAction->setEnabled(false);
+ d->setItemRightAction->setWhatsThis(i18n("Show item on right panel"));
+
+ d->editItemAction = new KAction(i18n("Edit"), "editimage",
+ Key_F4, this, SLOT(slotEditItem()),
+ actionCollection(), "lighttable_edititem");
+ d->editItemAction->setEnabled(false);
+
+ d->removeItemAction = new KAction(i18n("Remove item from LightTable"), "fileclose",
+ CTRL+Key_K, this, SLOT(slotRemoveItem()),
+ actionCollection(), "lighttable_removeitem");
+ d->removeItemAction->setEnabled(false);
+
+ d->clearListAction = new KAction(i18n("Remove all items from LightTable"), "editshred",
+ CTRL+SHIFT+Key_K, this, SLOT(slotClearItemsList()),
+ actionCollection(), "lighttable_clearlist");
+ d->clearListAction->setEnabled(false);
+
+ d->fileDeleteAction = new KAction(i18n("Move to Trash"), "edittrash",
+ Key_Delete,
+ this, SLOT(slotDeleteItem()),
+ actionCollection(), "lighttable_filedelete");
+ d->fileDeleteAction->setEnabled(false);
+
+ KStdAction::close(this, SLOT(close()), actionCollection(), "lighttable_close");
+
+ // -- Standard 'View' menu actions ---------------------------------------------
+
+ d->syncPreviewAction = new KToggleAction(i18n("Synchronize"), "goto",
+ CTRL+SHIFT+Key_Y, this,
+ SLOT(slotToggleSyncPreview()),
+ actionCollection(), "lighttable_syncpreview");
+ d->syncPreviewAction->setEnabled(false);
+ d->syncPreviewAction->setWhatsThis(i18n("Synchronize preview from left and right panels"));
+
+ d->navigateByPairAction = new KToggleAction(i18n("By Pair"), "kcmsystem",
+ CTRL+SHIFT+Key_P, this,
+ 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, SLOT(slotIncreaseZoom()),
+ actionCollection(), "lighttable_zoomplus");
+ d->zoomPlusAction->setEnabled(false);
+
+ d->zoomMinusAction = KStdAction::zoomOut(d->previewView, SLOT(slotDecreaseZoom()),
+ actionCollection(), "lighttable_zoomminus");
+ d->zoomMinusAction->setEnabled(false);
+
+ d->zoomTo100percents = new KAction(i18n("Zoom to 100%"), "viewmag1",
+ ALT+CTRL+Key_0, // NOTE: Photoshop 7 use ALT+CTRL+0.
+ this, SLOT(slotZoomTo100Percents()),
+ actionCollection(), "lighttable_zoomto100percents");
+
+ d->zoomFitToWindowAction = new KAction(i18n("Fit to &Window"), "view_fit_window",
+ CTRL+SHIFT+Key_E, this, 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 KToggleAction(i18n("Full Screen"), "window_fullscreen",
+ CTRL+SHIFT+Key_F, this,
+ SLOT(slotToggleFullScreen()),
+ actionCollection(), "lighttable_fullscreen");
+ d->fullScreenAction->setWhatsThis(i18n("Toggle the window to full screen mode"));
+
+ d->slideShowAction = new KAction(i18n("Slideshow"), "slideshow", Key_F9,
+ this, SLOT(slotToggleSlideShow()),
+ actionCollection(),"lighttable_slideshow");
+
+ // -- Standard 'Configure' menu actions ----------------------------------------
+
+ d->showMenuBarAction = KStdAction::showMenubar(this, SLOT(slotShowMenuBar()), actionCollection());
+
+ KStdAction::keyBindings(this, SLOT(slotEditKeys()), actionCollection());
+ KStdAction::configureToolbars(this, SLOT(slotConfToolbars()), actionCollection());
+ KStdAction::preferences(this, SLOT(slotSetup()), actionCollection());
+
+ // -----------------------------------------------------------------------------------------
+
+ d->themeMenuAction = new KSelectAction(i18n("&Themes"), 0, actionCollection(), "theme_menu");
+ connect(d->themeMenuAction, SIGNAL(activated(const QString&)),
+ this, SLOT(slotChangeTheme(const QString&)));
+
+ d->themeMenuAction->setItems(ThemeEngine::instance()->themeNames());
+ slotThemeChanged();
+
+ // -- Standard 'Help' menu actions ---------------------------------------------
+
+
+ d->donateMoneyAction = new KAction(i18n("Donate..."),
+ 0, 0,
+ this, SLOT(slotDonateMoney()),
+ actionCollection(),
+ "lighttable_donatemoney");
+
+ d->contributeAction = new KAction(i18n("Contribute..."),
+ 0, 0,
+ this, SLOT(slotContribute()),
+ actionCollection(),
+ "lighttable_contribute");
+
+ d->rawCameraListAction = new KAction(i18n("Supported RAW Cameras"),
+ "kdcraw",
+ 0,
+ this,
+ 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 KAction(i18n("Assign Rating \"No Stars\""), CTRL+Key_0,
+ d->barView, SLOT(slotAssignRatingNoStar()),
+ actionCollection(), "lighttable_ratenostar");
+ d->star1 = new KAction(i18n("Assign Rating \"One Star\""), CTRL+Key_1,
+ d->barView, SLOT(slotAssignRatingOneStar()),
+ actionCollection(), "lighttable_rateonestar");
+ d->star2 = new KAction(i18n("Assign Rating \"Two Stars\""), CTRL+Key_2,
+ d->barView, SLOT(slotAssignRatingTwoStar()),
+ actionCollection(), "lighttable_ratetwostar");
+ d->star3 = new KAction(i18n("Assign Rating \"Three Stars\""), CTRL+Key_3,
+ d->barView, SLOT(slotAssignRatingThreeStar()),
+ actionCollection(), "lighttable_ratethreestar");
+ d->star4 = new KAction(i18n("Assign Rating \"Four Stars\""), CTRL+Key_4,
+ d->barView, SLOT(slotAssignRatingFourStar()),
+ actionCollection(), "lighttable_ratefourstar");
+ d->star5 = new KAction(i18n("Assign Rating \"Five Stars\""), CTRL+Key_5,
+ d->barView, SLOT(slotAssignRatingFiveStar()),
+ actionCollection(), "lighttable_ratefivestar");
+
+ // ---------------------------------------------------------------------------------
+
+ new DLogoAction(actionCollection(), "logo_action");
+
+ createGUI("lighttablewindowui.rc", false);
+}
+
+void LightTableWindow::setupAccelerators()
+{
+ d->accelerators = new KAccel(this);
+
+ d->accelerators->insert("Exit fullscreen", i18n("Exit Fullscreen mode"),
+ i18n("Exit fullscreen viewing mode"),
+ Key_Escape, this, SLOT(slotEscapePressed()),
+ false, true);
+
+ d->accelerators->insert("Next Image Key_Space", i18n("Next Image"),
+ i18n("Load Next Image"),
+ Key_Space, this, SLOT(slotForward()),
+ false, true);
+
+ d->accelerators->insert("Previous Image SHIFT+Key_Space", i18n("Previous Image"),
+ i18n("Load Previous Image"),
+ SHIFT+Key_Space, this, SLOT(slotBackward()),
+ false, true);
+
+ d->accelerators->insert("Previous Image Key_Backspace", i18n("Previous Image"),
+ i18n("Load Previous Image"),
+ Key_Backspace, this, SLOT(slotBackward()),
+ false, true);
+
+ d->accelerators->insert("Next Image Key_Next", i18n("Next Image"),
+ i18n("Load Next Image"),
+ Key_Next, this, SLOT(slotForward()),
+ false, true);
+
+ d->accelerators->insert("Previous Image Key_Prior", i18n("Previous Image"),
+ i18n("Load Previous Image"),
+ Key_Prior, this, SLOT(slotBackward()),
+ false, true);
+
+ d->accelerators->insert("Zoom Plus Key_Plus", i18n("Zoom in"),
+ i18n("Zoom in on image"),
+ Key_Plus, d->previewView, SLOT(slotIncreaseZoom()),
+ false, true);
+
+ d->accelerators->insert("Zoom Plus Key_Minus", i18n("Zoom out"),
+ i18n("Zoom out from image"),
+ Key_Minus, d->previewView, 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;
+
+ QString 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 (QPtrList<ImageInfo>::const_iterator it = l.begin(); it != l.end(); ++it)
+ {
+ QString 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 KIO
+ 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))
+ {
+ QString 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;
+
+ Q_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()
+{
+ KConfig* 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, QString());
+ 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
+ {
+
+#if QT_VERSION >= 0x030300
+ setWindowState( windowState() & ~WindowFullScreen );
+#else
+ showNormal();
+#endif
+ menuBar()->show();
+ statusBar()->show();
+ leftDock()->show();
+ rightDock()->show();
+ topDock()->show();
+ bottomDock()->show();
+
+ QObject* obj = child("ToolBar","KToolBar");
+
+ if (obj)
+ {
+ KToolBar* toolBar = static_cast<KToolBar*>(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();
+
+ QObject* obj = child("ToolBar","KToolBar");
+
+ if (obj)
+ {
+ KToolBar* toolBar = static_cast<KToolBar*>(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()
+{
+ QPtrListIterator<KToolBar> it = toolBarIterator();
+ KToolBar* bar;
+
+ for( ; it.current()!=0L ; ++it)
+ {
+ bar=it.current();
+
+ if (bar->area())
+ bar->area()->show();
+ else
+ bar->show();
+ }
+}
+
+void LightTableWindow::hideToolBars()
+{
+ QPtrListIterator<KToolBar> it = toolBarIterator();
+ KToolBar* bar;
+
+ for( ; it.current()!=0L ; ++it)
+ {
+ bar=it.current();
+
+ if (bar->area())
+ bar->area()->hide();
+ else
+ bar->hide();
+ }
+}
+
+void LightTableWindow::plugActionAccel(KAction* action)
+{
+ if (!action)
+ return;
+
+ d->accelerators->insert(action->text(),
+ action->text(),
+ action->whatsThis(),
+ action->shortcut(),
+ action,
+ SLOT(activate()));
+}
+
+void LightTableWindow::unplugActionAccel(KAction* action)
+{
+ d->accelerators->remove(action->text());
+}
+
+void LightTableWindow::slotDonateMoney()
+{
+ KApplication::kApplication()->invokeBrowser("http://www.digikam.org/?q=donation");
+}
+
+void LightTableWindow::slotContribute()
+{
+ KApplication::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(KGlobal::config(), "LightTable Settings");
+ KEditToolbar dlg(factory(), this);
+
+ connect(&dlg, SIGNAL(newToolbarConfig()),
+ this, SLOT(slotNewToolbarConfig()));
+
+ dlg.exec();
+}
+
+void LightTableWindow::slotNewToolbarConfig()
+{
+ applyMainWindowSettings(KGlobal::config(), "LightTable Settings");
+}
+
+void LightTableWindow::slotSetup()
+{
+ Setup setup(this, 0);
+
+ if (setup.exec() != QDialog::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()
+{
+ QStringList 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 QString& 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/digikam/utilities/lighttable/lighttablewindow.h b/digikam/utilities/lighttable/lighttablewindow.h
new file mode 100644
index 0000000..388d28e
--- /dev/null
+++ b/digikam/utilities/lighttable/lighttablewindow.h
@@ -0,0 +1,161 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+
+// KDE includes.
+
+#include <kurl.h>
+#include <kmainwindow.h>
+
+// Local includes.
+
+#include "imageinfo.h"
+
+class KAction;
+
+namespace Digikam
+{
+
+class SlideShowSettings;
+class ThumbBarItem;
+class LightTableWindowPriv;
+
+class LightTableWindow : public KMainWindow
+{
+ Q_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(QCloseEvent* e);
+ void setupActions();
+ void setupConnections();
+ void setupUserArea();
+ void setupStatusBar();
+ void setupAccelerators();
+ void slideShow(bool startWithCurrent, SlideShowSettings& settings);
+ void showToolBars();
+ void hideToolBars();
+ void plugActionAccel(KAction* action);
+ void unplugActionAccel(KAction* 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 QString& theme);
+
+private:
+
+ LightTableWindowPriv *d;
+
+ static LightTableWindow *m_instance;
+};
+
+} // namespace Digikam
+
+#endif /* LIGHTTABLEWINDOW_H */
diff --git a/digikam/utilities/lighttable/lighttablewindowprivate.h b/digikam/utilities/lighttable/lighttablewindowprivate.h
new file mode 100644
index 0000000..f77eacd
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qsplitter.h>
+
+// KDE includes.
+
+#include <kaction.h>
+#include <kaccel.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;
+
+ QSplitter *hSplitter;
+ QSplitter *vSplitter;
+
+ // Rating actions.
+ KAction *star0;
+ KAction *star1;
+ KAction *star2;
+ KAction *star3;
+ KAction *star4;
+ KAction *star5;
+
+ KAction *forwardAction;
+ KAction *backwardAction;
+ KAction *firstAction;
+ KAction *lastAction;
+
+ KAction *setItemLeftAction;
+ KAction *setItemRightAction;
+ KAction *clearListAction;
+ KAction *editItemAction;
+ KAction *removeItemAction;
+ KAction *fileDeleteAction;
+ KAction *slideShowAction;
+ KAction *donateMoneyAction;
+ KAction *contributeAction;
+ KAction *zoomPlusAction;
+ KAction *zoomMinusAction;
+ KAction *zoomTo100percents;
+ KAction *zoomFitToWindowAction;
+ KAction *rawCameraListAction;
+
+ KSelectAction *themeMenuAction;
+
+ KToggleAction *fullScreenAction;
+ KToggleAction *syncPreviewAction;
+ KToggleAction *navigateByPairAction;
+ KToggleAction *showMenuBarAction;
+
+ KAccel *accelerators;
+
+ LightTableBar *barView;
+
+ LightTableView *previewView;
+
+ StatusZoomBar *leftZoomBar;
+ StatusZoomBar *rightZoomBar;
+
+ StatusProgressBar *statusProgressBar;
+
+ ImagePropertiesSideBarDB *leftSidebar;
+ ImagePropertiesSideBarDB *rightSidebar;
+};
+
+} // namespace Digikam
diff --git a/digikam/utilities/lighttable/lighttablewindowui.rc b/digikam/utilities/lighttable/lighttablewindowui.rc
new file mode 100644
index 0000000..ae7ce72
--- /dev/null
+++ b/digikam/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/digikam/utilities/scripts/Makefile.am b/digikam/utilities/scripts/Makefile.am
new file mode 100644
index 0000000..198f6c0
--- /dev/null
+++ b/digikam/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/digikam/utilities/scripts/digitaglinktree b/digikam/utilities/scripts/digitaglinktree
new file mode 100644
index 0000000..8d0d12c
--- /dev/null
+++ b/digikam/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/digikam/utilities/scripts/digitaglinktree.1 b/digikam/utilities/scripts/digitaglinktree.1
new file mode 100644
index 0000000..fdfe9e0
--- /dev/null
+++ b/digikam/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/digikam/utilities/setup/Makefile.am b/digikam/utilities/setup/Makefile.am
new file mode 100644
index 0000000..249819d
--- /dev/null
+++ b/digikam/utilities/setup/Makefile.am
@@ -0,0 +1,29 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/utilities/cameragui \
+ -I$(top_srcdir)/digikam/utilities/batch \
+ -I$(top_srcdir)/digikam/utilities/imageeditor/canvas \
+ -I$(top_srcdir)/digikam/libs/dialogs \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dimg/loaders \
+ -I$(top_srcdir)/digikam/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)
+
diff --git a/digikam/utilities/setup/cameraselection.cpp b/digikam/utilities/setup/cameraselection.cpp
new file mode 100644
index 0000000..1a6084d
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qcombobox.h>
+#include <qvgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qlistview.h>
+#include <qvbuttongroup.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+#include <kactivelabel.h>
+#include <kurlrequester.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kcursor.h>
+#include <kapplication.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;
+ }
+
+ QVButtonGroup *portButtonGroup;
+
+ QRadioButton *usbButton;
+ QRadioButton *serialButton;
+
+ QLabel *portPathLabel;
+
+ QComboBox *portPathComboBox;
+
+ QString UMSCameraNameActual;
+ QString UMSCameraNameShown;
+ QString PTPCameraNameShown;
+
+ QStringList serialPortList;
+
+ QListView *listView;
+
+ KLineEdit *titleEdit;
+
+ KURLRequester *umsMountURL;
+
+ SearchTextBar *searchBar;
+};
+
+CameraSelection::CameraSelection( QWidget* 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 = QString("Directory Browse"); // Don't be i18n!
+ d->UMSCameraNameShown = i18n("Mounted Camera");
+ d->PTPCameraNameShown = QString("USB PTP Class Camera");
+
+ QGridLayout* mainBoxLayout = new QGridLayout(plainPage(), 6, 1, 0, KDialog::spacingHint());
+ mainBoxLayout->setColStretch(0, 10);
+ mainBoxLayout->setRowStretch(6, 10);
+
+ // --------------------------------------------------------------
+
+ d->listView = new QListView(plainPage());
+ d->listView->addColumn(i18n("Camera List"));
+ d->listView->setAllColumnsShowFocus(true);
+ d->listView->setResizeMode(QListView::LastColumn);
+ d->listView->setMinimumWidth(350);
+ QWhatsThis::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");
+
+ // --------------------------------------------------------------
+
+ QVGroupBox* titleBox = new QVGroupBox( i18n("Camera Title"), plainPage() );
+ d->titleEdit = new KLineEdit( titleBox );
+ QWhatsThis::add(d->titleEdit, i18n("<p>Set here the name used in digiKam interface to "
+ "identify this camera.</p>"));
+
+ // --------------------------------------------------------------
+
+ d->portButtonGroup = new QVButtonGroup( i18n("Camera Port Type"), plainPage() );
+ d->portButtonGroup->setRadioButtonExclusive( true );
+
+ d->usbButton = new QRadioButton( d->portButtonGroup );
+ d->usbButton->setText( i18n( "USB" ) );
+ QWhatsThis::add(d->usbButton, i18n("<p>Select this option if your camera is connected to your "
+ "computer using an USB cable.</p>"));
+
+ d->serialButton = new QRadioButton( d->portButtonGroup );
+ d->serialButton->setText( i18n( "Serial" ) );
+ QWhatsThis::add(d->serialButton, i18n("<p>Select this option if your camera is connected to your "
+ "computer using a serial cable.</p>"));
+
+ // --------------------------------------------------------------
+
+ QVGroupBox* portPathBox = new QVGroupBox( i18n( "Camera Port Path" ), plainPage() );
+ d->portPathLabel = new QLabel( portPathBox);
+ d->portPathLabel->setText( i18n( "Note: only for serial port camera" ) );
+
+ d->portPathComboBox = new QComboBox( false, portPathBox );
+ d->portPathComboBox->setDuplicatesEnabled( false );
+ QWhatsThis::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>"));
+
+ // --------------------------------------------------------------
+
+ QVGroupBox* umsMountBox = new QVGroupBox(i18n("Camera Mount Path"), plainPage());
+
+ QLabel* umsMountLabel = new QLabel( umsMountBox );
+ umsMountLabel->setText(i18n("Note: only for USB/IEEE mass storage camera"));
+
+ d->umsMountURL = new KURLRequester( QString("/mnt/camera"), umsMountBox);
+ d->umsMountURL->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly);
+ QWhatsThis::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>"));
+
+ // --------------------------------------------------------------
+
+ QGroupBox* box2 = new QGroupBox( 0, Qt::Vertical, plainPage() );
+ box2->setFrameStyle( QFrame::NoFrame );
+ QGridLayout* box2Layout = new QGridLayout( box2->layout(), 1, 5 );
+
+ QLabel* logo = new QLabel( box2 );
+
+ KIconLoader* iconLoader = KApplication::kApplication()->iconLoader();
+ logo->setPixmap(iconLoader->loadIcon("digikam", KIcon::NoGroup, 64,
+ KIcon::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, SIGNAL(linkClicked(const QString &)),
+ link, SLOT(openLink(const QString &)));
+
+ connect(link, SIGNAL(linkClicked(const QString &)),
+ this, SLOT(slotUMSCameraLinkUsed()));
+
+ disconnect(link2, SIGNAL(linkClicked(const QString &)),
+ link2, SLOT(openLink(const QString &)));
+
+ connect(link2, SIGNAL(linkClicked(const QString &)),
+ this, SLOT(slotPTPCameraLinkUsed()));
+
+ connect(d->listView, SIGNAL(selectionChanged(QListViewItem *)),
+ this, SLOT(slotSelectionChanged(QListViewItem *)));
+
+ connect(d->portButtonGroup, SIGNAL(clicked(int)),
+ this, SLOT(slotPortChanged()));
+
+ connect(this, SIGNAL(okClicked()),
+ this, SLOT(slotOkClicked()));
+
+ connect(d->searchBar, SIGNAL(signalTextChanged(const QString&)),
+ this, SLOT(slotSearchTextChanged(const QString&)));
+
+ // Initialize --------------------------------------------------
+
+ getCameraList();
+ getSerialPortList();
+ kapp->restoreOverrideCursor();
+}
+
+CameraSelection::~CameraSelection()
+{
+ delete d;
+}
+
+void CameraSelection::slotUMSCameraLinkUsed()
+{
+ QListViewItem *item = d->listView->findItem(d->UMSCameraNameShown, 0);
+ if (item)
+ {
+ d->listView->setCurrentItem(item);
+ d->listView->ensureItemVisible(item);
+ }
+}
+
+void CameraSelection::slotPTPCameraLinkUsed()
+{
+ QListViewItem *item = d->listView->findItem(d->PTPCameraNameShown, 0);
+ if (item)
+ {
+ d->listView->setCurrentItem(item);
+ d->listView->ensureItemVisible(item);
+ }
+}
+
+void CameraSelection::setCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path)
+{
+ QString camModel(model);
+
+ if (camModel == d->UMSCameraNameActual)
+ camModel = d->UMSCameraNameShown;
+
+ QListViewItem* 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;
+ QStringList clist;
+ QString cname;
+
+ GPCamera::getSupportedCameras(count, clist);
+
+ for (int i = 0 ; i < count ; i++)
+ {
+ cname = clist[i];
+ if (cname == d->UMSCameraNameActual)
+ new QListViewItem(d->listView, d->UMSCameraNameShown);
+ else
+ new QListViewItem(d->listView, cname);
+ }
+}
+
+void CameraSelection::getSerialPortList()
+{
+ QStringList 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(QListViewItem *item)
+{
+ if (!item) return;
+
+ QString 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(QString("NONE"), 0);
+ d->portPathComboBox->setEnabled(false);
+
+ d->umsMountURL->setEnabled(true);
+ d->umsMountURL->clear();
+ d->umsMountURL->setURL(QString("/mnt/camera"));
+ return;
+ }
+ else
+ {
+ d->umsMountURL->setEnabled(true);
+ d->umsMountURL->clear();
+ d->umsMountURL->setURL(QString("/"));
+ d->umsMountURL->setEnabled(false);
+ }
+
+ d->titleEdit->setText(model);
+
+ QStringList 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( QString("usb:"), 0 );
+ d->portPathComboBox->setEnabled(false);
+ return;
+ }
+
+ if (d->serialButton->isChecked())
+ {
+ d->portPathComboBox->setEnabled(true);
+ d->portPathComboBox->clear();
+ d->portPathComboBox->insertStringList(d->serialPortList);
+ }
+}
+
+QString CameraSelection::currentTitle()
+{
+ return d->titleEdit->text();
+}
+
+QString CameraSelection::currentModel()
+{
+ QListViewItem* item = d->listView->currentItem();
+ if (!item)
+ return QString();
+
+ QString model(item->text(0));
+ if (model == d->UMSCameraNameShown)
+ model = d->UMSCameraNameActual;
+
+ return model;
+}
+
+QString CameraSelection::currentPortPath()
+{
+ return d->portPathComboBox->currentText();
+}
+
+QString CameraSelection::currentCameraPath()
+{
+ return d->umsMountURL->url();
+}
+
+void CameraSelection::slotOkClicked()
+{
+ emit signalOkClicked(currentTitle(), currentModel(),
+ currentPortPath(), currentCameraPath());
+}
+
+void CameraSelection::slotSearchTextChanged(const QString& filter)
+{
+ bool query = false;
+ QString search = filter.lower();
+
+ QListViewItemIterator it(d->listView);
+
+ for ( ; it.current(); ++it )
+ {
+ QListViewItem *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/digikam/utilities/setup/cameraselection.h b/digikam/utilities/setup/cameraselection.h
new file mode 100644
index 0000000..d090cde
--- /dev/null
+++ b/digikam/utilities/setup/cameraselection.h
@@ -0,0 +1,87 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+// KDE includes.
+
+#include <kdialogbase.h>
+
+class QListViewItem;
+
+namespace Digikam
+{
+
+class CameraSelectionPriv;
+
+class CameraSelection : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ CameraSelection(QWidget *parent=0);
+ ~CameraSelection();
+
+ void setCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path);
+
+ QString currentTitle();
+ QString currentModel();
+ QString currentPortPath();
+ QString currentCameraPath();
+
+signals:
+
+ void signalOkClicked(const QString& title, const QString& model,
+ const QString& port, const QString& path);
+
+private:
+
+ void getCameraList();
+ void getSerialPortList();
+
+private slots:
+
+ void slotPTPCameraLinkUsed();
+ void slotUMSCameraLinkUsed();
+ void slotSelectionChanged(QListViewItem *item);
+ void slotPortChanged();
+ void slotOkClicked();
+ void slotSearchTextChanged(const QString&);
+
+private:
+
+ CameraSelectionPriv *d;
+};
+
+} // namespace Digikam
+
+#endif // CAMERASELECTION_H
diff --git a/digikam/utilities/setup/setup.cpp b/digikam/utilities/setup/setup.cpp
new file mode 100644
index 0000000..7f19419
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qtabwidget.h>
+#include <qapplication.h>
+#include <qframe.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kapplication.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;
+ }
+
+ QFrame *page_general;
+ QFrame *page_tooltip;
+ QFrame *page_metadata;
+ QFrame *page_identity;
+ QFrame *page_collections;
+ QFrame *page_mime;
+ QFrame *page_lighttable;
+ QFrame *page_editor;
+ QFrame *page_dcraw;
+ QFrame *page_iofiles;
+ QFrame *page_slideshow;
+ QFrame *page_icc;
+ QFrame *page_plugins;
+ QFrame *page_camera;
+ QFrame *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(QWidget* 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", KIcon::SizeMedium));
+ d->generalPage = new SetupGeneral(d->page_general, this);
+
+ d->page_collections = addPage(i18n("Collections"), i18n("Album Collections"),
+ BarIcon("fileopen", KIcon::SizeMedium));
+ d->collectionsPage = new SetupCollections(d->page_collections);
+
+ d->page_identity = addPage(i18n("Identity"), i18n("Default IPTC identity information"),
+ BarIcon("identity", KIcon::SizeMedium));
+ d->identityPage = new SetupIdentity(d->page_identity);
+
+ d->page_metadata = addPage(i18n("Metadata"), i18n("Embedded Image Information Management"),
+ BarIcon("exifinfo", KIcon::SizeMedium));
+ d->metadataPage = new SetupMetadata(d->page_metadata);
+
+ d->page_tooltip = addPage(i18n("Tool Tip"), i18n("Album Items Tool Tip Settings"),
+ BarIcon("filetypes", KIcon::SizeMedium));
+ d->tooltipPage = new SetupToolTip(d->page_tooltip);
+
+ d->page_mime = addPage(i18n("Mime Types"), i18n("File (MIME) Types Settings"),
+ BarIcon("kcmsystem", KIcon::SizeMedium));
+ d->mimePage = new SetupMime(d->page_mime);
+
+ d->page_lighttable = addPage(i18n("Light Table"), i18n("Light Table Settings"),
+ BarIcon("lighttable", KIcon::SizeMedium));
+ d->lighttablePage = new SetupLightTable(d->page_lighttable);
+
+ d->page_editor = addPage(i18n("Image Editor"), i18n("Image Editor General Settings"),
+ BarIcon("image", KIcon::SizeMedium));
+ d->editorPage = new SetupEditor(d->page_editor);
+
+ d->page_iofiles = addPage(i18n("Save Images"), i18n("Image Editor: Settings for Saving Images Files"),
+ BarIcon("filesave", KIcon::SizeMedium));
+ d->iofilesPage = new SetupIOFiles(d->page_iofiles);
+
+ d->page_dcraw = addPage(i18n("RAW decoding"), i18n("RAW Files Decoding Settings"),
+ BarIcon("kdcraw", KIcon::SizeMedium));
+ d->dcrawPage = new SetupDcraw(d->page_dcraw);
+
+ d->page_icc = addPage(i18n("Color Management"), i18n("Image Editor Color Management Settings"),
+ BarIcon("colorize", KIcon::SizeMedium));
+ d->iccPage = new SetupICC(d->page_icc, this);
+
+ d->page_plugins = addPage(i18n("Kipi Plugins"), i18n("Main Interface Plug-in Settings"),
+ BarIcon("kipi", KIcon::SizeMedium));
+ d->pluginsPage = new SetupPlugins(d->page_plugins);
+
+ d->page_slideshow = addPage(i18n("Slide Show"), i18n("Slide Show Settings"),
+ BarIcon("slideshow", KIcon::SizeMedium));
+ d->slideshowPage = new SetupSlideShow(d->page_slideshow);
+
+ d->page_camera = addPage(i18n("Cameras"), i18n("Camera Settings"),
+ BarIcon("digitalcam", KIcon::SizeMedium));
+ d->cameraPage = new SetupCamera(d->page_camera);
+
+ d->page_misc = addPage(i18n("Miscellaneous"), i18n("Miscellaneous Settings"),
+ BarIcon("misc", KIcon::SizeMedium));
+ d->miscPage = new SetupMisc(d->page_misc);
+
+ connect(this, SIGNAL(okClicked()),
+ this, SLOT(slotOkClicked()) );
+
+ if (page != LastPageUsed)
+ showPage((int) page);
+ else
+ {
+ KConfig* config = kapp->config();
+ config->setGroup("General Settings");
+ showPage(config->readNumEntry("Setup Page", General));
+ }
+
+ show();
+}
+
+Setup::~Setup()
+{
+ KConfig* 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())
+ {
+ QString 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/digikam/utilities/setup/setup.h b/digikam/utilities/setup/setup.h
new file mode 100644
index 0000000..a611ec4
--- /dev/null
+++ b/digikam/utilities/setup/setup.h
@@ -0,0 +1,80 @@
+/* ============================================================
+ *
+ * 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
+{
+ Q_OBJECT
+
+public:
+
+ enum Page
+ {
+ LastPageUsed = -1,
+ General = 0,
+ ToolTip,
+ Metadata,
+ Identify,
+ Collections,
+ Mime,
+ LightTable,
+ Editor,
+ Dcraw,
+ IOFiles,
+ Slideshow,
+ IccProfiles,
+ KipiPlugins,
+ Camera,
+ Miscellaneous
+ };
+
+ Setup(QWidget* 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/digikam/utilities/setup/setupcamera.cpp b/digikam/utilities/setup/setupcamera.cpp
new file mode 100644
index 0000000..d0ed10f
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qgroupbox.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qdatetime.h>
+#include <qlistview.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurllabel.h>
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kcursor.h>
+#include <kapplication.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;
+ }
+
+ QPushButton *addButton;
+ QPushButton *removeButton;
+ QPushButton *editButton;
+ QPushButton *autoDetectButton;
+
+ QListView *listView;
+};
+
+SetupCamera::SetupCamera( QWidget* parent )
+ : QWidget( parent )
+{
+ d = new SetupCameraPriv;
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(parent);
+ QGridLayout* groupBoxLayout = new QGridLayout( this, 2, 5, 0, KDialog::spacingHint() );
+
+ d->listView = new QListView( 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);
+ QWhatsThis::add( d->listView, i18n("<p>Here you can see the digital camera list used by digiKam "
+ "via the Gphoto interface."));
+
+ // -------------------------------------------------------------
+
+ d->addButton = new QPushButton( this );
+ d->removeButton = new QPushButton( this );
+ d->editButton = new QPushButton( this );
+ d->autoDetectButton = new QPushButton( 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("find"));
+ d->removeButton->setEnabled(false);
+ d->editButton->setEnabled(false);
+
+ QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding );
+
+ KURLLabel *gphotoLogoLabel = new KURLLabel(this);
+ gphotoLogoLabel->setText(QString());
+ gphotoLogoLabel->setURL("http://www.gphoto.org");
+ KGlobal::dirs()->addResourceType("logo-gphoto", KGlobal::dirs()->kde_default("data") + "digikam/data");
+ QString directory = KGlobal::dirs()->findResourceDir("logo-gphoto", "logo-gphoto.png");
+ gphotoLogoLabel->setPixmap( QPixmap( directory + "logo-gphoto.png" ) );
+ QToolTip::add(gphotoLogoLabel, i18n("Visit Gphoto project website"));
+
+ groupBoxLayout->setAlignment( Qt::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, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(processGphotoURL(const QString&)));
+
+ connect(d->listView, SIGNAL(selectionChanged()),
+ this, SLOT(slotSelectionChanged()));
+
+ connect(d->addButton, SIGNAL(clicked()),
+ this, SLOT(slotAddCamera()));
+
+ connect(d->removeButton, SIGNAL(clicked()),
+ this, SLOT(slotRemoveCamera()));
+
+ connect(d->editButton, SIGNAL(clicked()),
+ this, SLOT(slotEditCamera()));
+
+ connect(d->autoDetectButton, SIGNAL(clicked()),
+ this, SLOT(slotAutoDetectCamera()));
+
+ // Add cameras --------------------------------------
+
+ CameraList* clist = CameraList::instance();
+
+ if (clist)
+ {
+ QPtrList<CameraType>* cl = clist->cameraList();
+
+ for (CameraType *ctype = cl->first(); ctype;
+ ctype = cl->next())
+ {
+ new QListViewItem(d->listView, ctype->title(), ctype->model(),
+ ctype->port(), ctype->path(),
+ ctype->lastAccess().toString(Qt::ISODate));
+ }
+ }
+}
+
+SetupCamera::~SetupCamera()
+{
+ delete d;
+}
+
+void SetupCamera::processGphotoURL(const QString& url)
+{
+ KApplication::kApplication()->invokeBrowser(url);
+}
+
+void SetupCamera::slotSelectionChanged()
+{
+ QListViewItem *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, SIGNAL(signalOkClicked(const QString&, const QString&,
+ const QString&, const QString&)),
+ this, SLOT(slotAddedCamera(const QString&, const QString&,
+ const QString&, const QString&)));
+
+ select->show();
+}
+
+void SetupCamera::slotRemoveCamera()
+{
+ QListViewItem *item = d->listView->currentItem();
+ if (!item) return;
+
+ delete item;
+}
+
+void SetupCamera::slotEditCamera()
+{
+ QListViewItem *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, SIGNAL(signalOkClicked(const QString&, const QString&,
+ const QString&, const QString&)),
+ this, SLOT(slotEditedCamera(const QString&, const QString&,
+ const QString&, const QString&)));
+
+ select->show();
+}
+
+void SetupCamera::slotAutoDetectCamera()
+{
+ QString 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 QListViewItem(d->listView, model, model, port, "/",
+ QDateTime::currentDateTime().toString(Qt::ISODate));
+ }
+}
+
+void SetupCamera::slotAddedCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path)
+{
+ new QListViewItem(d->listView, title, model, port, path,
+ QDateTime::currentDateTime().toString(Qt::ISODate));
+}
+
+void SetupCamera::slotEditedCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path)
+{
+ QListViewItem *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();
+
+ QListViewItemIterator it(d->listView);
+
+ for ( ; it.current(); ++it )
+ {
+ QListViewItem *item = it.current();
+ QDateTime lastAccess = QDateTime::currentDateTime();
+
+ if (!item->text(4).isEmpty())
+ lastAccess = QDateTime::fromString(item->text(4), Qt::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/digikam/utilities/setup/setupcamera.h b/digikam/utilities/setup/setupcamera.h
new file mode 100644
index 0000000..e1cc432
--- /dev/null
+++ b/digikam/utilities/setup/setupcamera.h
@@ -0,0 +1,72 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupCameraPriv;
+
+class SetupCamera : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupCamera( QWidget* parent = 0 );
+ ~SetupCamera();
+
+ void applySettings();
+
+private slots:
+
+ void processGphotoURL(const QString& url);
+
+ void slotSelectionChanged();
+
+ void slotAddCamera();
+ void slotRemoveCamera();
+ void slotEditCamera();
+ void slotAutoDetectCamera();
+
+ void slotAddedCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path);
+ void slotEditedCamera(const QString& title, const QString& model,
+ const QString& port, const QString& path);
+
+private:
+
+ SetupCameraPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif // SETUPCAMERA_H
diff --git a/digikam/utilities/setup/setupcollections.cpp b/digikam/utilities/setup/setupcollections.cpp
new file mode 100644
index 0000000..7ae7800
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qvgroupbox.h>
+#include <qhgroupbox.h>
+#include <qgroupbox.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qdir.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <klistbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kdeversion.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;
+ }
+
+ QListBox *albumCollectionBox;
+
+ QPushButton *addCollectionButton;
+ QPushButton *delCollectionButton;
+};
+
+SetupCollections::SetupCollections(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupCollectionsPriv;
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(parent);
+ QGridLayout *collectionGroupLayout = new QGridLayout( this, 2, 5, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ d->albumCollectionBox = new KListBox(this);
+ QWhatsThis::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(QScrollView::AlwaysOn);
+
+ d->addCollectionButton = new QPushButton( i18n("&Add..."), this);
+ d->delCollectionButton = new QPushButton( i18n("&Delete"), this);
+
+ d->addCollectionButton->setIconSet(SmallIcon("add"));
+ d->delCollectionButton->setIconSet(SmallIcon("remove"));
+ d->delCollectionButton->setEnabled(false);
+
+ QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding );
+
+ collectionGroupLayout->setAlignment( Qt::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, SIGNAL(selectionChanged()),
+ this, SLOT(slotCollectionSelectionChanged()));
+
+ connect(d->addCollectionButton, SIGNAL(clicked()),
+ this, SLOT(slotAddCollection()));
+
+ connect(d->delCollectionButton, SIGNAL(clicked()),
+ this, SLOT(slotDelCollection()));
+
+ // --------------------------------------------------------
+
+ readSettings();
+ adjustSize();
+ mainLayout->addWidget(this);
+}
+
+SetupCollections::~SetupCollections()
+{
+ delete d;
+}
+
+void SetupCollections::applySettings()
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+
+ if (!settings) return;
+
+ QStringList collectionList;
+
+ for (QListBoxItem *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)
+ QString newCollection =
+ KInputDialog::getText(i18n("New Collection Name"),
+ i18n("Enter new collection name:"),
+ QString(), &ok, this);
+#else
+ QString newCollection =
+ KLineEditDlg::getText(i18n("New Collection Name"),
+ i18n("Enter new collection name:"),
+ QString(), &ok, this);
+#endif
+
+ if (!ok) return;
+
+ bool found = false;
+ for (QListBoxItem *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;
+
+ QListBoxItem* item = d->albumCollectionBox->item(index);
+ if (!item) return;
+ delete item;
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/setup/setupcollections.h b/digikam/utilities/setup/setupcollections.h
new file mode 100644
index 0000000..de00da2
--- /dev/null
+++ b/digikam/utilities/setup/setupcollections.h
@@ -0,0 +1,65 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupCollectionsPriv;
+
+class SetupCollections : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupCollections(QWidget* 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/digikam/utilities/setup/setupdcraw.cpp b/digikam/utilities/setup/setupdcraw.cpp
new file mode 100644
index 0000000..0ee5987
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcolor.h>
+#include <qhbox.h>
+#include <qvgroupbox.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdialog.h>
+#include <kconfig.h>
+#include <kapplication.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(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupDcrawPriv;
+ QVBoxLayout *layout = new QVBoxLayout(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, SIGNAL(signalSixteenBitsImageToggled(bool)),
+ this, 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()
+{
+ KConfig* 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()
+{
+ KConfig* 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/digikam/utilities/setup/setupdcraw.h b/digikam/utilities/setup/setupdcraw.h
new file mode 100644
index 0000000..fdc5e0f
--- /dev/null
+++ b/digikam/utilities/setup/setupdcraw.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class SetupDcrawPriv;
+
+class DIGIKAM_EXPORT SetupDcraw : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupDcraw(QWidget* parent = 0);
+ ~SetupDcraw();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void slotSixteenBitsImageToggled(bool);
+
+private:
+
+ SetupDcrawPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPDCRAW_H
diff --git a/digikam/utilities/setup/setupeditor.cpp b/digikam/utilities/setup/setupeditor.cpp
new file mode 100644
index 0000000..c942aaa
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qcolor.h>
+#include <qhbox.h>
+#include <qvgroupbox.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kcolorbutton.h>
+#include <knuminput.h>
+#include <kconfig.h>
+#include <kapplication.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;
+ }
+
+ QHBox *colorBox;
+
+ QCheckBox *hideToolBar;
+ QCheckBox *themebackgroundColor;
+ QCheckBox *useRawImportTool;
+
+ KColorButton *backgroundColor;
+ KColorButton *underExposureColor;
+ KColorButton *overExposureColor;
+};
+
+SetupEditor::SetupEditor(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupEditorPriv;
+ QVBoxLayout *layout = new QVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ QVGroupBox *interfaceOptionsGroup = new QVGroupBox(i18n("Interface Options"), parent);
+
+ d->themebackgroundColor = new QCheckBox(i18n("&Use theme background color"), interfaceOptionsGroup);
+
+ QWhatsThis::add(d->themebackgroundColor, i18n("<p>Enable this option to use background theme "
+ "color in image editor area"));
+
+ d->colorBox = new QHBox(interfaceOptionsGroup);
+
+ QLabel *backgroundColorlabel = new QLabel(i18n("&Background color:"), d->colorBox);
+
+ d->backgroundColor = new KColorButton(d->colorBox);
+ backgroundColorlabel->setBuddy(d->backgroundColor);
+ QWhatsThis::add(d->backgroundColor, i18n("<p>Customize background color to use "
+ "in image editor area."));
+
+ d->hideToolBar = new QCheckBox(i18n("H&ide toolbar in fullscreen mode"), interfaceOptionsGroup);
+
+ d->useRawImportTool = new QCheckBox(i18n("Use Raw Import Tool to handle Raw image"), interfaceOptionsGroup);
+ QWhatsThis::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."));
+
+ // --------------------------------------------------------
+
+ QVGroupBox *exposureOptionsGroup = new QVGroupBox(i18n("Exposure Indicators"), parent);
+
+ QHBox *underExpoBox = new QHBox(exposureOptionsGroup);
+ QLabel *underExpoColorlabel = new QLabel( i18n("&Under-exposure color:"), underExpoBox);
+ d->underExposureColor = new KColorButton(underExpoBox);
+ underExpoColorlabel->setBuddy(d->underExposureColor);
+ QWhatsThis::add(d->underExposureColor, i18n("<p>Customize the color used in image editor to identify "
+ "under-exposed pixels."));
+
+ QHBox *overExpoBox = new QHBox(exposureOptionsGroup);
+ QLabel *overExpoColorlabel = new QLabel( i18n("&Over-exposure color:"), overExpoBox);
+ d->overExposureColor = new KColorButton(overExpoBox);
+ overExpoColorlabel->setBuddy(d->overExposureColor);
+ QWhatsThis::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, SIGNAL(toggled(bool)),
+ this, SLOT(slotThemeBackgroundColor(bool)));
+
+ readSettings();
+}
+
+SetupEditor::~SetupEditor()
+{
+ delete d;
+}
+
+void SetupEditor::slotThemeBackgroundColor(bool e)
+{
+ d->colorBox->setEnabled(!e);
+}
+
+void SetupEditor::readSettings()
+{
+ KConfig* config = kapp->config();
+ QColor Black(Qt::black);
+ QColor White(Qt::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()
+{
+ KConfig* 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/digikam/utilities/setup/setupeditor.h b/digikam/utilities/setup/setupeditor.h
new file mode 100644
index 0000000..0fa9d3c
--- /dev/null
+++ b/digikam/utilities/setup/setupeditor.h
@@ -0,0 +1,62 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupEditorPriv;
+
+class SetupEditor : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupEditor(QWidget* parent = 0);
+ ~SetupEditor();
+
+ void applySettings();
+
+private slots:
+
+ void slotThemeBackgroundColor(bool);
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupEditorPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPEDITOR_H
diff --git a/digikam/utilities/setup/setupgeneral.cpp b/digikam/utilities/setup/setupgeneral.cpp
new file mode 100644
index 0000000..45cfff4
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qvbuttongroup.h>
+#include <qvgroupbox.h>
+#include <qhgroupbox.h>
+#include <qgroupbox.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qdir.h>
+#include <qlistbox.h>
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qfileinfo.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kdialogbase.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <kmessagebox.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;
+ }
+
+ QLabel *iconTreeThumbLabel;
+
+ QCheckBox *iconShowNameBox;
+ QCheckBox *iconShowSizeBox;
+ QCheckBox *iconShowDateBox;
+ QCheckBox *iconShowModDateBox;
+ QCheckBox *iconShowResolutionBox;
+ QCheckBox *iconShowCommentsBox;
+ QCheckBox *iconShowTagsBox;
+ QCheckBox *iconShowRatingBox;
+ QCheckBox *previewLoadFullImageSize;
+ QCheckBox *showFolderTreeViewItemsCount;
+
+ QComboBox *iconTreeThumbSize;
+ QComboBox *rightClickActionComboBox;
+
+ KURLRequester *albumPathEdit;
+
+ KDialogBase *mainDialog;
+};
+
+SetupGeneral::SetupGeneral(QWidget* parent, KDialogBase* dialog )
+ : QWidget(parent)
+{
+ d = new SetupGeneralPriv;
+ d->mainDialog = dialog;
+ QVBoxLayout *layout = new QVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ QHGroupBox *albumPathBox = new QHGroupBox(parent);
+ albumPathBox->setTitle(i18n("Album &Library Path"));
+
+ d->albumPathEdit = new KURLRequester(albumPathBox);
+ d->albumPathEdit->setMode(KFile::Directory | KFile::LocalOnly | KFile::ExistingOnly);
+ QToolTip::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, SIGNAL(urlSelected(const QString &)),
+ this, SLOT(slotChangeAlbumPath(const QString &)));
+
+ connect(d->albumPathEdit, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotPathEdited(const QString&)) );
+
+ layout->addWidget(albumPathBox);
+
+ // --------------------------------------------------------
+
+ QVGroupBox *iconTextGroup = new QVGroupBox(i18n("Thumbnail Information"), parent);
+
+ d->iconShowNameBox = new QCheckBox(i18n("Show file &name"), iconTextGroup);
+ QWhatsThis::add( d->iconShowNameBox, i18n("<p>Set this option to show the file name below the image thumbnail."));
+
+ d->iconShowSizeBox = new QCheckBox(i18n("Show file si&ze"), iconTextGroup);
+ QWhatsThis::add( d->iconShowSizeBox, i18n("<p>Set this option to show the file size below the image thumbnail."));
+
+ d->iconShowDateBox = new QCheckBox(i18n("Show camera creation &date"), iconTextGroup);
+ QWhatsThis::add( d->iconShowDateBox, i18n("<p>Set this option to show the camera creation date "
+ "below the image thumbnail."));
+
+ d->iconShowModDateBox = new QCheckBox(i18n("Show file &modification date"), iconTextGroup);
+ QWhatsThis::add( d->iconShowModDateBox, i18n("<p>Set this option to show the file modification date "
+ "below the image thumbnail."));
+
+ d->iconShowCommentsBox = new QCheckBox(i18n("Show digiKam &captions"), iconTextGroup);
+ QWhatsThis::add( d->iconShowCommentsBox, i18n("<p>Set this option to show the digiKam captions "
+ "below the image thumbnail."));
+
+ d->iconShowTagsBox = new QCheckBox(i18n("Show digiKam &tags"), iconTextGroup);
+ QWhatsThis::add( d->iconShowTagsBox, i18n("<p>Set this option to show the digiKam tags "
+ "below the image thumbnail."));
+
+ d->iconShowRatingBox = new QCheckBox(i18n("Show digiKam &rating"), iconTextGroup);
+ QWhatsThis::add( d->iconShowRatingBox, i18n("<p>Set this option to show the digiKam rating "
+ "below the image thumbnail."));
+
+ d->iconShowResolutionBox = new QCheckBox(i18n("Show ima&ge dimensions (warning: slow)"), iconTextGroup);
+ QWhatsThis::add( d->iconShowResolutionBox, i18n("<p>Set this option to show the image size in pixels "
+ "below the image thumbnail."));
+
+ layout->addWidget(iconTextGroup);
+
+ // --------------------------------------------------------
+
+ QVGroupBox *interfaceOptionsGroup = new QVGroupBox(i18n("Interface Options"), parent);
+ interfaceOptionsGroup->setColumnLayout(0, Qt::Vertical );
+ interfaceOptionsGroup->layout()->setMargin(KDialog::marginHint());
+ QGridLayout* ifaceSettingsLayout = new QGridLayout(interfaceOptionsGroup->layout(), 3, 4, KDialog::spacingHint());
+
+ d->iconTreeThumbLabel = new QLabel(i18n("Sidebar thumbnail size:"), interfaceOptionsGroup);
+ d->iconTreeThumbSize = new QComboBox(false, interfaceOptionsGroup);
+ d->iconTreeThumbSize->insertItem("16");
+ d->iconTreeThumbSize->insertItem("22");
+ d->iconTreeThumbSize->insertItem("32");
+ d->iconTreeThumbSize->insertItem("48");
+ QToolTip::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 QCheckBox(i18n("Show count of items in all tree-view"), interfaceOptionsGroup);
+ ifaceSettingsLayout->addMultiCellWidget(d->showFolderTreeViewItemsCount, 1, 1, 0, 4);
+
+
+ QLabel *rightClickLabel = new QLabel(i18n("Thumbnail click action:"), interfaceOptionsGroup);
+ d->rightClickActionComboBox = new QComboBox(false, interfaceOptionsGroup);
+ d->rightClickActionComboBox->insertItem(i18n("Show embedded preview"), AlbumSettings::ShowPreview);
+ d->rightClickActionComboBox->insertItem(i18n("Start image editor"), AlbumSettings::StartEditor);
+ QToolTip::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 QCheckBox(i18n("Embedded preview loads full image size"), interfaceOptionsGroup);
+ QWhatsThis::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 QString &result)
+{
+ if (KURL(result).equals(KURL(QDir::homeDirPath()), true))
+ {
+ KMessageBox::sorry(0, i18n("Sorry you can't use your home directory as album library."));
+ return;
+ }
+
+ QFileInfo 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 QString& newPath)
+{
+ if (newPath.isEmpty())
+ {
+ d->mainDialog->enableButtonOK(false);
+ return;
+ }
+
+ if (!newPath.startsWith("/"))
+ {
+ d->albumPathEdit->setURL(QDir::homeDirPath() + '/' + newPath);
+ }
+
+ QFileInfo targetPath(newPath);
+ QDir dir(newPath);
+ d->mainDialog->enableButtonOK(dir.exists() && dir.path() != QDir::homeDirPath());
+}
+
+} // namespace Digikam
+
diff --git a/digikam/utilities/setup/setupgeneral.h b/digikam/utilities/setup/setupgeneral.h
new file mode 100644
index 0000000..3c3a5d0
--- /dev/null
+++ b/digikam/utilities/setup/setupgeneral.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+class KDialogBase;
+
+namespace Digikam
+{
+
+class SetupGeneralPriv;
+
+class SetupGeneral : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupGeneral(QWidget* parent = 0, KDialogBase* dialog = 0);
+ ~SetupGeneral();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void slotChangeAlbumPath(const QString &);
+ void slotPathEdited(const QString&);
+
+private:
+
+ SetupGeneralPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPGENERAL_H
diff --git a/digikam/utilities/setup/setupicc.cpp b/digikam/utilities/setup/setupicc.cpp
new file mode 100644
index 0000000..6411d09
--- /dev/null
+++ b/digikam/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>
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qvgroupbox.h>
+#include <qhgroupbox.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qiconset.h>
+#include <qpixmap.h>
+#include <qpushbutton.h>
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qdir.h>
+#include <qtooltip.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kurlrequester.h>
+#include <klineedit.h>
+#include <kconfig.h>
+#include <kcombobox.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kurllabel.h>
+#include <kiconloader.h>
+#include <kglobalsettings.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;
+ }
+
+ QLabel *monitorIcon;
+ QLabel *monitorProfiles;
+
+ QCheckBox *enableColorManagement;
+ QCheckBox *bpcAlgorithm;
+ QCheckBox *managedView;
+
+ QRadioButton *defaultApplyICC;
+ QRadioButton *defaultAskICC;
+
+ QPushButton *infoWorkProfiles;
+ QPushButton *infoMonitorProfiles;
+ QPushButton *infoInProfiles;
+ QPushButton *infoProofProfiles;
+
+ QVGroupBox *behaviourGB;
+ QHGroupBox *defaultPathGB;
+ QGroupBox *profilesGB;
+ QVGroupBox *advancedSettingsGB;
+
+ // Maps to store profile descriptions and profile file path
+ QMap<QString, QString> inICCPath;
+ QMap<QString, QString> workICCPath;
+ QMap<QString, QString> proofICCPath;
+ QMap<QString, QString> monitorICCPath;
+
+ KURLRequester *defaultPathKU;
+
+ KComboBox *renderingIntentKC;
+
+ KDialogBase *mainDialog;
+
+ SqueezedComboBox *inProfilesKC;
+ SqueezedComboBox *workProfilesKC;
+ SqueezedComboBox *proofProfilesKC;
+ SqueezedComboBox *monitorProfilesKC;
+};
+
+SetupICC::SetupICC(QWidget* parent, KDialogBase* dialog )
+ : QWidget(parent)
+{
+ d = new SetupICCPriv();
+ d->mainDialog = dialog;
+ QVBoxLayout *layout = new QVBoxLayout( parent, 0, KDialog::spacingHint());
+
+ // --------------------------------------------------------
+
+ QGroupBox *colorPolicy = new QGroupBox(0, Qt::Horizontal, i18n("Color Management Policy"), parent);
+ QGridLayout* grid = new QGridLayout( colorPolicy->layout(), 1, 2, KDialog::spacingHint());
+
+ d->enableColorManagement = new QCheckBox(colorPolicy);
+ d->enableColorManagement->setText(i18n("Enable Color Management"));
+ QWhatsThis::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(QString());
+ lcmsLogoLabel->setURL("http://www.littlecms.com");
+ KGlobal::dirs()->addResourceType("logo-lcms", KGlobal::dirs()->kde_default("data") + "digikam/data");
+ QString directory = KGlobal::dirs()->findResourceDir("logo-lcms", "logo-lcms.png");
+ lcmsLogoLabel->setPixmap( QPixmap( directory + "logo-lcms.png" ) );
+ QToolTip::add(lcmsLogoLabel, i18n("Visit Little CMS project website"));
+
+ d->behaviourGB = new QVGroupBox(i18n("Behavior"), colorPolicy);
+ QButtonGroup *behaviourOptions = new QButtonGroup(2, Qt::Vertical, d->behaviourGB);
+ behaviourOptions->setFrameStyle( QFrame::NoFrame );
+ behaviourOptions->setInsideMargin(0);
+
+ d->defaultApplyICC = new QRadioButton(behaviourOptions);
+ d->defaultApplyICC->setText(i18n("Apply when opening an image in the Image Editor"));
+ QWhatsThis::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 QRadioButton(behaviourOptions);
+ d->defaultAskICC->setText(i18n("Ask when opening an image in the Image Editor"));
+ QWhatsThis::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 QHGroupBox(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);
+ QWhatsThis::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 QGroupBox(0, Qt::Horizontal, i18n("ICC Profiles Settings"), parent);
+ QGridLayout* grid2 = new QGridLayout( d->profilesGB->layout(), 4, 3, KDialog::spacingHint());
+ grid2->setColStretch(2, 10);
+
+ d->managedView = new QCheckBox(d->profilesGB);
+ d->managedView->setText(i18n("Use color managed view (warning: slow)"));
+ QWhatsThis::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 QLabel(d->profilesGB);
+ d->monitorIcon->setPixmap(SmallIcon("tv"));
+ d->monitorProfiles = new QLabel(i18n("Monitor:"), d->profilesGB);
+ d->monitorProfilesKC = new SqueezedComboBox(d->profilesGB);
+ d->monitorProfiles->setBuddy(d->monitorProfilesKC);
+ QWhatsThis::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 QPushButton(i18n("Info..."), d->profilesGB);
+ QWhatsThis::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);
+
+ QLabel *workIcon = new QLabel(d->profilesGB);
+ workIcon->setPixmap(SmallIcon("tablet"));
+ QLabel *workProfiles = new QLabel(i18n("Workspace:"), d->profilesGB);
+ d->workProfilesKC = new SqueezedComboBox(d->profilesGB);
+ workProfiles->setBuddy(d->workProfilesKC);
+ QWhatsThis::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 QPushButton(i18n("Info..."), d->profilesGB);
+ QWhatsThis::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);
+
+ QLabel *inIcon = new QLabel(d->profilesGB);
+ inIcon->setPixmap(SmallIcon("camera"));
+ QLabel *inProfiles = new QLabel(i18n("Input:"), d->profilesGB);
+ d->inProfilesKC = new SqueezedComboBox(d->profilesGB);
+ inProfiles->setBuddy(d->inProfilesKC);
+ QWhatsThis::add( d->inProfilesKC, i18n("<p>You must select the profile for your input device "
+ "(usually, your camera, scanner...)</p>"));
+ d->infoInProfiles = new QPushButton(i18n("Info..."), d->profilesGB);
+ QWhatsThis::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);
+
+ QLabel *proofIcon = new QLabel(d->profilesGB);
+ proofIcon->setPixmap(SmallIcon("printer1"));
+ QLabel *proofProfiles = new QLabel(i18n("Soft proof:"), d->profilesGB);
+ d->proofProfilesKC = new SqueezedComboBox(d->profilesGB);
+ proofProfiles->setBuddy(d->proofProfilesKC);
+ QWhatsThis::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 QPushButton(i18n("Info..."), d->profilesGB);
+ QWhatsThis::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 QVGroupBox(i18n("Advanced Settings"), parent);
+
+ d->bpcAlgorithm = new QCheckBox(d->advancedSettingsGB);
+ d->bpcAlgorithm->setText(i18n("Use black point compensation"));
+ QWhatsThis::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>"));
+
+ QHBox *hbox2 = new QHBox(d->advancedSettingsGB);
+ QLabel *lablel = new QLabel(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");
+ QWhatsThis::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, SIGNAL(toggled(bool)),
+ this, SLOT(slotToggleManagedView(bool)));
+
+ connect(lcmsLogoLabel, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(processLCMSURL(const QString&)));
+
+ connect(d->enableColorManagement, SIGNAL(toggled(bool)),
+ this, SLOT(slotToggledWidgets(bool)));
+
+ connect(d->infoProofProfiles, SIGNAL(clicked()),
+ this, SLOT(slotClickedProof()) );
+
+ connect(d->infoInProfiles, SIGNAL(clicked()),
+ this, SLOT(slotClickedIn()) );
+
+ connect(d->infoMonitorProfiles, SIGNAL(clicked()),
+ this, SLOT(slotClickedMonitor()) );
+
+ connect(d->infoWorkProfiles, SIGNAL(clicked()),
+ this, SLOT(slotClickedWork()));
+
+ connect(d->defaultPathKU, SIGNAL(urlSelected(const QString&)),
+ this, SLOT(slotFillCombos(const QString&)));
+
+ // --------------------------------------------------------
+
+ adjustSize();
+ readSettings();
+ slotToggledWidgets(d->enableColorManagement->isChecked());
+ slotToggleManagedView(d->managedView->isChecked());
+}
+
+SetupICC::~SetupICC()
+{
+ delete d;
+}
+
+void SetupICC::processLCMSURL(const QString& url)
+{
+ KApplication::kApplication()->invokeBrowser(url);
+}
+
+void SetupICC::applySettings()
+{
+ KConfig* 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)
+{
+ KConfig* config = kapp->config();
+ config->setGroup("Color Management");
+
+ if (!restore)
+ d->enableColorManagement->setChecked(config->readBoolEntry("EnableCM", false));
+
+ d->defaultPathKU->setURL(config->readPathEntry("DefaultPath", QString()));
+ 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 QString& path)
+{
+ fillCombos(path, true);
+}
+
+void SetupICC::fillCombos(const QString& 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();
+ QDir 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.
+ QDir userProfilesDir(path, "*.icc;*.icm", QDir::Files);
+ const QFileInfoList* usersFiles = userProfilesDir.entryInfoList();
+ DDebug() << "Scanning ICC profiles from user repository: " << path << endl;
+
+ if ( !parseProfilesfromDir(usersFiles) )
+ {
+ if (report)
+ {
+ QString 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.
+ KGlobal::dirs()->addResourceType("profiles", KGlobal::dirs()->kde_default("data") + "digikam/profiles");
+ QString digiKamProfilesPath = KGlobal::dirs()->findResourceDir("profiles", "srgb.icm");
+ QDir digiKamProfilesDir(digiKamProfilesPath, "*.icc;*.icm", QDir::Files);
+ const QFileInfoList* 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 QFileInfoList* files)
+{
+ cmsHPROFILE tmpProfile=0;
+ bool findIccFiles=false;
+
+ if (files)
+ {
+ QFileInfoListIterator it(*files);
+ QFileInfo *fileInfo=0;
+
+ while ((fileInfo = it.current()) != 0)
+ {
+ if (fileInfo->isFile() && fileInfo->isReadable())
+ {
+ QString fileName = fileInfo->filePath();
+ tmpProfile = cmsOpenProfileFromFile(QFile::encodeName(fileName), "r");
+
+ if (tmpProfile == NULL)
+ {
+ DDebug() << "Error: Parsed profile is NULL (invalid profile); " << fileName << endl;
+ cmsCloseProfile(tmpProfile);
+ ++it;
+ QString 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 (QFile::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;
+ }
+
+ QString profileDescription = QString((cmsTakeProductDesc(tmpProfile)));
+
+ switch ((int)cmsGetDeviceClass(tmpProfile))
+ {
+ case icSigInputClass:
+ {
+ if (QString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ d->inICCPath.insert(fileName, fileName);
+ else
+ d->inICCPath.insert(QString(cmsTakeProductDesc(tmpProfile)), fileName);
+
+ DDebug() << "ICC file: " << fileName << " ==> Input device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ case icSigDisplayClass:
+ {
+ if (QString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ {
+ d->monitorICCPath.insert(fileName, fileName);
+ d->workICCPath.insert(fileName, fileName);
+ }
+ else
+ {
+ d->monitorICCPath.insert(QString(cmsTakeProductDesc(tmpProfile)), fileName);
+ d->workICCPath.insert(QString(cmsTakeProductDesc(tmpProfile)), fileName);
+ }
+
+ DDebug() << "ICC file: " << fileName << " ==> Monitor device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ case icSigOutputClass:
+ {
+ if (QString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ d->proofICCPath.insert(fileName, fileName);
+ else
+ d->proofICCPath.insert(QString(cmsTakeProductDesc(tmpProfile)), fileName);
+
+ DDebug() << "ICC file: " << fileName << " ==> Output device class ("
+ << cmsGetDeviceClass(tmpProfile) << ")" << endl;
+ findIccFiles = true;
+ break;
+ }
+ case icSigColorSpaceClass:
+ {
+ if (QString(cmsTakeProductDesc(tmpProfile)).isEmpty())
+ {
+ d->inICCPath.insert(fileName, fileName);
+ d->workICCPath.insert(fileName, fileName);
+ }
+ else
+ {
+ d->inICCPath.insert(QString(cmsTakeProductDesc(tmpProfile)), fileName);
+ d->workICCPath.insert(QString(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 QString& 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()
+{
+ KConfig* 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.
+
+ QDir tmpPath(config->readPathEntry("DefaultPath", QString()));
+ DDebug() << "ICC profiles repository is: " << tmpPath.dirName() << endl;
+
+ if ( tmpPath.exists() && tmpPath.isReadable() )
+ return true;
+
+ return false;
+}
+
+} // namespace Digikam
diff --git a/digikam/utilities/setup/setupicc.h b/digikam/utilities/setup/setupicc.h
new file mode 100644
index 0000000..2182f58
--- /dev/null
+++ b/digikam/utilities/setup/setupicc.h
@@ -0,0 +1,85 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+#include <qmap.h>
+#include <qdir.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class KDialogBase;
+
+namespace Digikam
+{
+
+class SetupICCPriv;
+
+class DIGIKAM_EXPORT SetupICC : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupICC(QWidget* parent = 0, KDialogBase* dialog = 0);
+ ~SetupICC();
+
+ void applySettings();
+
+ static bool iccRepositoryIsValid();
+
+private:
+
+ void readSettings(bool restore=false);
+ void fillCombos(const QString& path, bool report);
+ void enableWidgets();
+ void disableWidgets();
+ void profileInfo(const QString&);
+ bool parseProfilesfromDir(const QFileInfoList* files);
+
+private slots:
+
+ void processLCMSURL(const QString&);
+ void slotToggledWidgets(bool);
+ void slotToggleManagedView(bool);
+ void slotFillCombos(const QString&);
+ void slotClickedIn();
+ void slotClickedWork();
+ void slotClickedMonitor();
+ void slotClickedProof();
+
+private:
+
+ SetupICCPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPICC_H
diff --git a/digikam/utilities/setup/setupidentity.cpp b/digikam/utilities/setup/setupidentity.cpp
new file mode 100644
index 0000000..2076044
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qhgroupbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qvalidator.h>
+
+// KDE includes.
+
+#include <klocale.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(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupIdentityPriv;
+ QVBoxLayout *layout = new QVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ // IPTC only accept printable Ascii char.
+ QRegExp asciiRx("[\x20-\x7F]+$");
+ QValidator *asciiValidator = new QRegExpValidator(asciiRx, this);
+
+ QGroupBox *photographerIdGroup = new QGroupBox(0, Qt::Horizontal, i18n("Photographer and Copyright Information"), parent);
+ QGridLayout* grid = new QGridLayout( photographerIdGroup->layout(), 1, 1, KDialog::spacingHint());
+
+ QLabel *label1 = new QLabel(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);
+ QWhatsThis::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>"));
+
+ QLabel *label2 = new QLabel(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);
+ QWhatsThis::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>"));
+
+ // --------------------------------------------------------
+
+ QGroupBox *creditsGroup = new QGroupBox(0, Qt::Horizontal, i18n("Credit and Copyright"), parent);
+ QGridLayout* grid2 = new QGridLayout( creditsGroup->layout(), 2, 1, KDialog::spacingHint());
+
+ QLabel *label3 = new QLabel(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);
+ QWhatsThis::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>"));
+
+ QLabel *label4 = new QLabel(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);
+ QWhatsThis::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>"));
+
+ QLabel *label5 = new QLabel(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);
+ QWhatsThis::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/digikam/utilities/setup/setupidentity.h b/digikam/utilities/setup/setupidentity.h
new file mode 100644
index 0000000..add330b
--- /dev/null
+++ b/digikam/utilities/setup/setupidentity.h
@@ -0,0 +1,59 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupIdentityPriv;
+
+class SetupIdentity : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupIdentity(QWidget* parent = 0);
+ ~SetupIdentity();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupIdentityPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif // SETUP_IDENTITY_H
diff --git a/digikam/utilities/setup/setupiofiles.cpp b/digikam/utilities/setup/setupiofiles.cpp
new file mode 100644
index 0000000..f728bc2
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kconfig.h>
+#include <kapplication.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(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupIOFilesPriv;
+
+ QVBoxLayout* vbox = new QVBoxLayout(parent);
+
+ //-- JPEG Settings ------------------------------------------------------
+
+ d->JPEGOptions = new JPEGSettings(parent);
+ KSeparator *line1 = new KSeparator(Horizontal, parent);
+ vbox->addWidget(d->JPEGOptions);
+ vbox->addWidget(line1);
+
+ //-- PNG Settings -------------------------------------------------------
+
+ d->PNGOptions = new PNGSettings(parent);
+ KSeparator *line2 = new KSeparator(Horizontal, parent);
+ vbox->addWidget(d->PNGOptions);
+ vbox->addWidget(line2);
+
+ //-- TIFF Settings ------------------------------------------------------
+
+ d->TIFFOptions = new TIFFSettings(parent);
+ KSeparator *line3 = new KSeparator(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()
+{
+ KConfig* 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()
+{
+ KConfig* 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/digikam/utilities/setup/setupiofiles.h b/digikam/utilities/setup/setupiofiles.h
new file mode 100644
index 0000000..8b4940c
--- /dev/null
+++ b/digikam/utilities/setup/setupiofiles.h
@@ -0,0 +1,62 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class SetupIOFilesPriv;
+
+class DIGIKAM_EXPORT SetupIOFiles : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupIOFiles(QWidget* parent = 0);
+ ~SetupIOFiles();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupIOFilesPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPIOFILES_H
diff --git a/digikam/utilities/setup/setuplighttable.cpp b/digikam/utilities/setup/setuplighttable.cpp
new file mode 100644
index 0000000..bb4eb37
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qcolor.h>
+#include <qhbox.h>
+#include <qvgroupbox.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kconfig.h>
+#include <kapplication.h>
+
+// Local includes.
+
+#include "setuplighttable.h"
+#include "setuplighttable.moc"
+
+namespace Digikam
+{
+class SetupLightTablePriv
+{
+public:
+
+ SetupLightTablePriv()
+ {
+ hideToolBar = 0;
+ autoSyncPreview = 0;
+ autoLoadOnRightPanel = 0;
+ loadFullImageSize = 0;
+ }
+
+ QCheckBox *hideToolBar;
+ QCheckBox *autoSyncPreview;
+ QCheckBox *autoLoadOnRightPanel;
+ QCheckBox *loadFullImageSize;
+};
+
+SetupLightTable::SetupLightTable(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupLightTablePriv;
+ QVBoxLayout *layout = new QVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ QVGroupBox *interfaceOptionsGroup = new QVGroupBox(i18n("Interface Options"), parent);
+
+
+ d->autoSyncPreview = new QCheckBox(i18n("Synchronize panels automatically"), interfaceOptionsGroup);
+ QWhatsThis::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 QCheckBox(i18n("Selecting a thumbbar item loads image to the right panel"),
+ interfaceOptionsGroup);
+ QWhatsThis::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 QCheckBox(i18n("Load full image size"), interfaceOptionsGroup);
+ QWhatsThis::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 QCheckBox(i18n("H&ide toolbar in fullscreen mode"), interfaceOptionsGroup);
+
+ // --------------------------------------------------------
+
+ layout->addWidget(interfaceOptionsGroup);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ readSettings();
+}
+
+SetupLightTable::~SetupLightTable()
+{
+ delete d;
+}
+
+void SetupLightTable::readSettings()
+{
+ KConfig* config = kapp->config();
+ QColor Black(Qt::black);
+ QColor White(Qt::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()
+{
+ KConfig* 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/digikam/utilities/setup/setuplighttable.h b/digikam/utilities/setup/setuplighttable.h
new file mode 100644
index 0000000..1b30d6a
--- /dev/null
+++ b/digikam/utilities/setup/setuplighttable.h
@@ -0,0 +1,58 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupLightTablePriv;
+
+class SetupLightTable : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupLightTable(QWidget* parent = 0);
+ ~SetupLightTable();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupLightTablePriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPLIGHTTABLE_H
diff --git a/digikam/utilities/setup/setupmetadata.cpp b/digikam/utilities/setup/setupmetadata.cpp
new file mode 100644
index 0000000..0060b1a
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qvgroupbox.h>
+#include <qhgroupbox.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+#include <qhbox.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kactivelabel.h>
+#include <kdialog.h>
+#include <kurllabel.h>
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+#include <kstandarddirs.h>
+#include <kapplication.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;
+
+ QCheckBox *saveCommentsBox;
+ QCheckBox *ExifRotateBox;
+ QCheckBox *ExifSetOrientationBox;
+ QCheckBox *saveRatingBox;
+ QCheckBox *saveTagsIptcBox;
+ QCheckBox *saveDateTimeBox;
+ QCheckBox *savePhotographerIdIptcBox;
+ QCheckBox *saveCreditsIptcBox;
+};
+
+SetupMetadata::SetupMetadata(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupMetadataPriv;
+ QVBoxLayout *mainLayout = new QVBoxLayout(parent, 0, KDialog::spacingHint());
+
+ // --------------------------------------------------------
+
+ QGroupBox *ExifGroup = new QGroupBox(1, Qt::Horizontal, i18n("EXIF Actions"), parent);
+
+ d->ExifRotateBox = new QCheckBox(ExifGroup);
+ d->ExifRotateBox->setText(i18n("Show images/thumbs &rotated according to orientation tag"));
+
+ d->ExifSetOrientationBox = new QCheckBox(ExifGroup);
+ d->ExifSetOrientationBox->setText(i18n("Set orientation tag to normal after rotate/flip"));
+
+ // --------------------------------------------------------
+
+ QGroupBox *IptcGroup = new QGroupBox(1, Qt::Horizontal, i18n("IPTC Actions"), parent);
+
+ d->saveTagsIptcBox = new QCheckBox(IptcGroup);
+ d->saveTagsIptcBox->setText(i18n("&Save image tags as \"Keywords\" tag"));
+ QWhatsThis::add( d->saveTagsIptcBox, i18n("<p>Turn this option on to store the image tags "
+ "in the IPTC <i>Keywords</i> tag."));
+
+ d->savePhotographerIdIptcBox = new QCheckBox(IptcGroup);
+ d->savePhotographerIdIptcBox->setText(i18n("&Save default photographer identity as tags"));
+ QWhatsThis::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 QCheckBox(IptcGroup);
+ d->saveCreditsIptcBox->setText(i18n("&Save default credit and copyright identity as tags"));
+ QWhatsThis::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."));
+
+ // --------------------------------------------------------
+
+ QGroupBox *commonGroup = new QGroupBox(1, Qt::Horizontal, i18n("Common Metadata Actions"), parent);
+
+ d->saveCommentsBox = new QCheckBox(commonGroup);
+ d->saveCommentsBox->setText(i18n("&Save image captions as embedded text"));
+ QWhatsThis::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 QCheckBox(commonGroup);
+ d->saveDateTimeBox->setText(i18n("&Save image timestamps as tags"));
+ QWhatsThis::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 QCheckBox(commonGroup);
+ d->saveRatingBox->setText(i18n("&Save image rating as tags"));
+ QWhatsThis::add( d->saveRatingBox, i18n("<p>Turn this option on to store the image rating "
+ "in the EXIF tag and IPTC <i>Urgency</i> tag."));
+
+ // --------------------------------------------------------
+
+ QHBox *hbox = new QHBox(parent);
+
+ KURLLabel *exiv2LogoLabel = new KURLLabel(hbox);
+ exiv2LogoLabel->setText(QString());
+ exiv2LogoLabel->setURL("http://www.exiv2.org");
+ KGlobal::dirs()->addResourceType("logo-exiv2", KGlobal::dirs()->kde_default("data") + "digikam/data");
+ QString directory = KGlobal::dirs()->findResourceDir("logo-exiv2", "logo-exiv2.png");
+ exiv2LogoLabel->setPixmap( QPixmap( directory + "logo-exiv2.png" ) );
+ QToolTip::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, SIGNAL(leftClickedURL(const QString&)),
+ this, SLOT(processExiv2URL(const QString&)));
+
+ connect(d->ExifRotateBox, SIGNAL(toggled(bool)),
+ this, SLOT(slotExifAutoRotateToggled(bool)));
+}
+
+SetupMetadata::~SetupMetadata()
+{
+ delete d;
+}
+
+void SetupMetadata::processExiv2URL(const QString& url)
+{
+ KApplication::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/digikam/utilities/setup/setupmetadata.h b/digikam/utilities/setup/setupmetadata.h
new file mode 100644
index 0000000..ad38621
--- /dev/null
+++ b/digikam/utilities/setup/setupmetadata.h
@@ -0,0 +1,66 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupMetadataPriv;
+
+class SetupMetadata : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupMetadata(QWidget* parent = 0);
+ ~SetupMetadata();
+
+ void applySettings();
+
+ bool exifAutoRotateAsChanged();
+
+private:
+
+ void readSettings();
+
+private slots:
+
+ void processExiv2URL(const QString&);
+ void slotExifAutoRotateToggled(bool);
+
+private:
+
+ SetupMetadataPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPMETADATA_H
diff --git a/digikam/utilities/setup/setupmime.cpp b/digikam/utilities/setup/setupmime.cpp
new file mode 100644
index 0000000..bf1acf1
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qhbox.h>
+#include <qhgroupbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qwhatsthis.h>
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+
+// KDE includes.
+
+#include <klocale.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;
+ }
+
+ QToolButton *revertImageFileFilterBtn;
+ QToolButton *revertMovieFileFilterBtn;
+ QToolButton *revertAudioFileFilterBtn;
+ QToolButton *revertRawFileFilterBtn;
+
+ QLineEdit *imageFileFilterEdit;
+ QLineEdit *movieFileFilterEdit;
+ QLineEdit *audioFileFilterEdit;
+ QLineEdit *rawFileFilterEdit;
+};
+
+SetupMime::SetupMime(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupMimePriv;
+ QVBoxLayout *layout = new QVBoxLayout(parent, 0, KDialog::spacingHint());
+
+ // --------------------------------------------------------
+
+ QGroupBox *imageFileFilterBox = new QGroupBox(0, Qt::Horizontal, i18n("Image Files"), parent);
+ QGridLayout* grid1 = new QGridLayout(imageFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ QLabel *logoLabel1 = new QLabel(imageFileFilterBox);
+ logoLabel1->setPixmap(DesktopIcon("image"));
+
+ QLabel *imageFileFilterLabel = new QLabel(imageFileFilterBox);
+ imageFileFilterLabel->setText(i18n("Show only &image files with extensions:"));
+
+ QHBox *hbox1 = new QHBox(imageFileFilterBox);
+ d->imageFileFilterEdit = new QLineEdit(hbox1);
+ QWhatsThis::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 QToolButton(hbox1);
+ d->revertImageFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ QToolTip::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);
+
+ // --------------------------------------------------------
+
+ QGroupBox *movieFileFilterBox = new QGroupBox(0, Qt::Horizontal, i18n("Movie Files"), parent);
+ QGridLayout* grid2 = new QGridLayout(movieFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ QLabel *logoLabel2 = new QLabel(movieFileFilterBox);
+ logoLabel2->setPixmap(DesktopIcon("video"));
+
+ QLabel *movieFileFilterLabel = new QLabel(movieFileFilterBox);
+ movieFileFilterLabel->setText(i18n("Show only &movie files with extensions:"));
+
+ QHBox *hbox2 = new QHBox(movieFileFilterBox);
+ d->movieFileFilterEdit = new QLineEdit(hbox2);
+ QWhatsThis::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 KDE movie player."));
+ movieFileFilterLabel->setBuddy(d->movieFileFilterEdit);
+ hbox2->setStretchFactor(d->movieFileFilterEdit, 10);
+
+ d->revertMovieFileFilterBtn = new QToolButton(hbox2);
+ d->revertMovieFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ QToolTip::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);
+
+ // --------------------------------------------------------
+
+ QGroupBox *audioFileFilterBox = new QGroupBox(0, Qt::Horizontal, i18n("Audio Files"), parent);
+ QGridLayout* grid3 = new QGridLayout(audioFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ QLabel *logoLabel3 = new QLabel(audioFileFilterBox);
+ logoLabel3->setPixmap(DesktopIcon("sound"));
+
+ QLabel *audioFileFilterLabel = new QLabel(audioFileFilterBox);
+ audioFileFilterLabel->setText(i18n("Show only &audio files with extensions:"));
+
+ QHBox *hbox3 = new QHBox(audioFileFilterBox);
+ d->audioFileFilterEdit = new QLineEdit(hbox3);
+ QWhatsThis::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 KDE audio player."));
+ audioFileFilterLabel->setBuddy(d->audioFileFilterEdit);
+ hbox3->setStretchFactor(d->audioFileFilterEdit, 10);
+
+ d->revertAudioFileFilterBtn = new QToolButton(hbox3);
+ d->revertAudioFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ QToolTip::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);
+
+ // --------------------------------------------------------
+
+ QGroupBox *rawFileFilterBox = new QGroupBox(0, Qt::Horizontal, i18n("RAW Files"), parent);
+ QGridLayout* grid4 = new QGridLayout(rawFileFilterBox->layout(), 1, 1, KDialog::spacingHint());
+
+ QLabel *logoLabel4 = new QLabel(rawFileFilterBox);
+ logoLabel4->setPixmap(DesktopIcon("kdcraw"));
+
+ QLabel *rawFileFilterLabel = new QLabel(rawFileFilterBox);
+ rawFileFilterLabel->setText(i18n("Show only &RAW files with extensions:"));
+
+ QHBox *hbox4 = new QHBox(rawFileFilterBox);
+ d->rawFileFilterEdit = new QLineEdit(hbox4);
+ QWhatsThis::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 QToolButton(hbox4);
+ d->revertRawFileFilterBtn->setIconSet(SmallIcon("reload_page"));
+ QToolTip::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, SIGNAL(clicked()),
+ this, SLOT(slotRevertImageFileFilter()));
+
+ connect(d->revertMovieFileFilterBtn, SIGNAL(clicked()),
+ this, SLOT(slotRevertMovieFileFilter()));
+
+ connect(d->revertAudioFileFilterBtn, SIGNAL(clicked()),
+ this, SLOT(slotRevertAudioFileFilter()));
+
+ connect(d->revertRawFileFilterBtn, SIGNAL(clicked()),
+ this, 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/digikam/utilities/setup/setupmime.h b/digikam/utilities/setup/setupmime.h
new file mode 100644
index 0000000..e078d99
--- /dev/null
+++ b/digikam/utilities/setup/setupmime.h
@@ -0,0 +1,65 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupMimePriv;
+
+class SetupMime : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupMime(QWidget* 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/digikam/utilities/setup/setupmisc.cpp b/digikam/utilities/setup/setupmisc.cpp
new file mode 100644
index 0000000..4bd7554
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qvgroupbox.h>
+#include <qcheckbox.h>
+
+// KDE includes.
+
+#include <klocale.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;
+ }
+
+ QCheckBox* showSplashCheck;
+ QCheckBox* showTrashDeleteDialogCheck;
+ QCheckBox* sidebarApplyDirectlyCheck;
+ QCheckBox* scanAtStart;
+};
+
+SetupMisc::SetupMisc(QWidget* parent)
+ : QWidget( parent )
+{
+ d = new SetupMiscPriv;
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(parent);
+ QVBoxLayout *layout = new QVBoxLayout( this, 0, KDialog::spacingHint() );
+
+ // --------------------------------------------------------
+
+ d->showTrashDeleteDialogCheck = new QCheckBox(i18n("Show confirmation dialog when moving items to the &trash"), this);
+ layout->addWidget(d->showTrashDeleteDialogCheck);
+
+ // --------------------------------------------------------
+
+ d->sidebarApplyDirectlyCheck = new QCheckBox(i18n("Apply changes in the &right sidebar without confirmation"), this);
+ layout->addWidget(d->sidebarApplyDirectlyCheck);
+
+ // --------------------------------------------------------
+
+ d->showSplashCheck = new QCheckBox(i18n("&Show splash screen at startup"), this);
+ layout->addWidget(d->showSplashCheck);
+
+ // --------------------------------------------------------
+
+ d->scanAtStart = new QCheckBox(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/digikam/utilities/setup/setupmisc.h b/digikam/utilities/setup/setupmisc.h
new file mode 100644
index 0000000..ff0934a
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupMiscPriv;
+
+class SetupMisc : public QWidget
+{
+public:
+
+ SetupMisc(QWidget* parent);
+ ~SetupMisc();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupMiscPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif /* SETUPMISC_H */
diff --git a/digikam/utilities/setup/setupplugins.cpp b/digikam/utilities/setup/setupplugins.cpp
new file mode 100644
index 0000000..c4f4244
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qstring.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <klocale.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;
+ }
+
+ QLabel* pluginsNumber;
+
+ KIPI::ConfigWidget* kipiConfig;
+};
+
+SetupPlugins::SetupPlugins(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupPluginsPriv;
+ QVBoxLayout *layout = new QVBoxLayout(parent);
+ d->pluginsNumber = new QLabel(parent);
+ d->pluginsNumber->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+ d->kipiConfig = KIPI::PluginLoader::instance()->configWidget( parent );
+ QString pluginsListHelp = i18n("<p>A list of available Kipi plugins appears below.");
+ QWhatsThis::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/digikam/utilities/setup/setupplugins.h b/digikam/utilities/setup/setupplugins.h
new file mode 100644
index 0000000..88411dd
--- /dev/null
+++ b/digikam/utilities/setup/setupplugins.h
@@ -0,0 +1,55 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupPluginsPriv;
+
+class SetupPlugins : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupPlugins(QWidget* parent = 0);
+ ~SetupPlugins();
+
+ void initPlugins(int kipiPluginsNumber);
+ void applyPlugins();
+
+private:
+
+ SetupPluginsPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPPLUGINS_H
diff --git a/digikam/utilities/setup/setupslideshow.cpp b/digikam/utilities/setup/setupslideshow.cpp
new file mode 100644
index 0000000..88929f5
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+
+// KDE includes.
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <knuminput.h>
+#include <kconfig.h>
+#include <kapplication.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;
+ }
+
+ QCheckBox *startWithCurrent;
+ QCheckBox *loopMode;
+ QCheckBox *printName;
+ QCheckBox *printDate;
+ QCheckBox *printApertureFocal;
+ QCheckBox *printExpoSensitivity;
+ QCheckBox *printMakeModel;
+ QCheckBox *printComment;
+
+ KIntNumInput *delayInput;
+};
+
+SetupSlideShow::SetupSlideShow(QWidget* parent )
+ : QWidget(parent)
+{
+ d = new SetupSlideShowPriv;
+ QVBoxLayout *layout = new QVBoxLayout( parent );
+
+ d->delayInput = new KIntNumInput(5, parent);
+ d->delayInput->setRange(1, 3600, 1, true );
+ d->delayInput->setLabel( i18n("&Delay between images:"), AlignLeft|AlignTop );
+ QWhatsThis::add( d->delayInput, i18n("<p>The delay, in seconds, between images."));
+
+ d->startWithCurrent = new QCheckBox(i18n("Start with current image"), parent);
+ QWhatsThis::add( d->startWithCurrent, i18n("<p>If this option is enabled, slideshow will be started "
+ "with currently selected image."));
+
+ d->loopMode = new QCheckBox(i18n("Display in a loop"), parent);
+ QWhatsThis::add( d->loopMode, i18n("<p>Run the slideshow in endless repetition."));
+
+ d->printName = new QCheckBox(i18n("Print image file name"), parent);
+ QWhatsThis::add( d->printName, i18n("<p>Print the image file name at the bottom of the screen."));
+
+ d->printDate = new QCheckBox(i18n("Print image creation date"), parent);
+ QWhatsThis::add( d->printDate, i18n("<p>Print the image creation time/date at the bottom of the screen."));
+
+ d->printApertureFocal = new QCheckBox(i18n("Print camera aperture and focal length"), parent);
+ QWhatsThis::add( d->printApertureFocal, i18n("<p>Print the camera aperture and focal length at the bottom of the screen."));
+
+ d->printExpoSensitivity = new QCheckBox(i18n("Print camera exposure and sensitivity"), parent);
+ QWhatsThis::add( d->printExpoSensitivity, i18n("<p>Print the camera exposure and sensitivity at the bottom of the screen."));
+
+ d->printMakeModel = new QCheckBox(i18n("Print camera make and model"), parent);
+ QWhatsThis::add( d->printMakeModel, i18n("<p>Print the camera make and model at the bottom of the screen."));
+
+ d->printComment = new QCheckBox(i18n("Print image caption"), parent);
+ QWhatsThis::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()
+{
+ KConfig* 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()
+{
+ KConfig* 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/digikam/utilities/setup/setupslideshow.h b/digikam/utilities/setup/setupslideshow.h
new file mode 100644
index 0000000..70fc777
--- /dev/null
+++ b/digikam/utilities/setup/setupslideshow.h
@@ -0,0 +1,63 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+namespace Digikam
+{
+
+class SetupSlideShowPriv;
+
+class DIGIKAM_EXPORT SetupSlideShow : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupSlideShow(QWidget* parent = 0);
+ ~SetupSlideShow();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupSlideShowPriv* d;
+
+};
+
+} // namespace Digikam
+
+#endif /* SETUPSLIDESHOW_H */
diff --git a/digikam/utilities/setup/setuptooltip.cpp b/digikam/utilities/setup/setuptooltip.cpp
new file mode 100644
index 0000000..2dd343b
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qlayout.h>
+#include <qvgroupbox.h>
+#include <qcheckbox.h>
+#include <qwhatsthis.h>
+
+// KDE includes.
+
+#include <klocale.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;
+ }
+
+ QCheckBox *showToolTipsBox;
+
+ QCheckBox *showFileNameBox;
+ QCheckBox *showFileDateBox;
+ QCheckBox *showFileSizeBox;
+ QCheckBox *showImageTypeBox;
+ QCheckBox *showImageDimBox;
+
+ QCheckBox *showPhotoMakeBox;
+ QCheckBox *showPhotoDateBox;
+ QCheckBox *showPhotoFocalBox;
+ QCheckBox *showPhotoExpoBox;
+ QCheckBox *showPhotoModeBox;
+ QCheckBox *showPhotoFlashBox;
+ QCheckBox *showPhotoWbBox;
+
+ QCheckBox *showAlbumNameBox;
+ QCheckBox *showCommentsBox;
+ QCheckBox *showTagsBox;
+ QCheckBox *showRatingBox;
+
+ QVGroupBox *fileSettingBox;
+ QVGroupBox *photoSettingBox;
+ QVGroupBox *digikamSettingBox;
+};
+
+SetupToolTip::SetupToolTip(QWidget* parent)
+ : QWidget(parent)
+{
+ d = new SetupToolTipPriv;
+ QVBoxLayout *layout = new QVBoxLayout( parent, 0, KDialog::spacingHint() );
+
+ d->showToolTipsBox = new QCheckBox(i18n("Show album items toolti&ps"), parent);
+ QWhatsThis::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 QVGroupBox(i18n("File/Image Information"), parent);
+
+ d->showFileNameBox = new QCheckBox(i18n("Show file name"), d->fileSettingBox);
+ QWhatsThis::add( d->showFileNameBox, i18n("<p>Set this option to display the image file name."));
+
+ d->showFileDateBox = new QCheckBox(i18n("Show file date"), d->fileSettingBox);
+ QWhatsThis::add( d->showFileDateBox, i18n("<p>Set this option to display the image file date."));
+
+ d->showFileSizeBox = new QCheckBox(i18n("Show file size"), d->fileSettingBox);
+ QWhatsThis::add( d->showFileSizeBox, i18n("<p>Set this option to display the image file size."));
+
+ d->showImageTypeBox = new QCheckBox(i18n("Show image type"), d->fileSettingBox);
+ QWhatsThis::add( d->showImageTypeBox, i18n("<p>Set this option to display the image type."));
+
+ d->showImageDimBox = new QCheckBox(i18n("Show image dimensions"), d->fileSettingBox);
+ QWhatsThis::add( d->showImageDimBox, i18n("<p>Set this option to display the image dimensions in pixels."));
+
+ layout->addWidget(d->fileSettingBox);
+
+ // --------------------------------------------------------
+
+ d->photoSettingBox = new QVGroupBox(i18n("Photograph Information"), parent);
+
+ d->showPhotoMakeBox = new QCheckBox(i18n("Show camera make and model"), d->photoSettingBox);
+ QWhatsThis::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 QCheckBox(i18n("Show camera date"), d->photoSettingBox);
+ QWhatsThis::add( d->showPhotoDateBox, i18n("<p>Set this option to display the date when the image was taken."));
+
+ d->showPhotoFocalBox = new QCheckBox(i18n("Show camera aperture and focal"), d->photoSettingBox);
+ QWhatsThis::add( d->showPhotoFocalBox, i18n("<p>Set this option to display the camera aperture and focal settings "
+ "used to take the image."));
+
+ d->showPhotoExpoBox = new QCheckBox(i18n("Show camera exposure and sensitivity"), d->photoSettingBox);
+ QWhatsThis::add( d->showPhotoExpoBox, i18n("<p>Set this option to display the camera exposure and sensitivity "
+ "used to take the image."));
+
+ d->showPhotoModeBox = new QCheckBox(i18n("Show camera mode and program"), d->photoSettingBox);
+ QWhatsThis::add( d->showPhotoModeBox, i18n("<p>Set this option to display the camera mode and program "
+ "used to take the image."));
+
+ d->showPhotoFlashBox = new QCheckBox(i18n("Show camera flash settings"), d->photoSettingBox);
+ QWhatsThis::add( d->showPhotoFlashBox, i18n("<p>Set this option to display the camera flash settings "
+ "used to take the image."));
+
+ d->showPhotoWbBox = new QCheckBox(i18n("Show camera white balance settings"), d->photoSettingBox);
+ QWhatsThis::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 QVGroupBox(i18n("digiKam Information"), parent);
+
+ d->showAlbumNameBox = new QCheckBox(i18n("Show album name"), d->digikamSettingBox);
+ QWhatsThis::add( d->showAlbumNameBox, i18n("<p>Set this option to display the album name."));
+
+ d->showCommentsBox = new QCheckBox(i18n("Show image caption"), d->digikamSettingBox);
+ QWhatsThis::add( d->showCommentsBox, i18n("<p>Set this option to display the image captions."));
+
+ d->showTagsBox = new QCheckBox(i18n("Show image tags"), d->digikamSettingBox);
+ QWhatsThis::add( d->showTagsBox, i18n("<p>Set this option to display the image tags."));
+
+ d->showRatingBox = new QCheckBox(i18n("Show image rating"), d->digikamSettingBox);
+ QWhatsThis::add( d->showRatingBox, i18n("<p>Set this option to display the image rating."));
+
+ layout->addWidget(d->digikamSettingBox);
+ layout->addStretch();
+
+ // --------------------------------------------------------
+
+ connect(d->showToolTipsBox, SIGNAL(toggled(bool)),
+ d->fileSettingBox, SLOT(setEnabled(bool)));
+
+ connect(d->showToolTipsBox, SIGNAL(toggled(bool)),
+ d->photoSettingBox, SLOT(setEnabled(bool)));
+
+ connect(d->showToolTipsBox, SIGNAL(toggled(bool)),
+ d->digikamSettingBox, 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/digikam/utilities/setup/setuptooltip.h b/digikam/utilities/setup/setuptooltip.h
new file mode 100644
index 0000000..30dd005
--- /dev/null
+++ b/digikam/utilities/setup/setuptooltip.h
@@ -0,0 +1,58 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+namespace Digikam
+{
+
+class SetupToolTipPriv;
+
+class SetupToolTip : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SetupToolTip(QWidget* parent = 0);
+ ~SetupToolTip();
+
+ void applySettings();
+
+private:
+
+ void readSettings();
+
+private:
+
+ SetupToolTipPriv* d;
+};
+
+} // namespace Digikam
+
+#endif // SETUPTOOLTIP_H
diff --git a/digikam/utilities/slideshow/Makefile.am b/digikam/utilities/slideshow/Makefile.am
new file mode 100644
index 0000000..29f8992
--- /dev/null
+++ b/digikam/utilities/slideshow/Makefile.am
@@ -0,0 +1,17 @@
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/digikam/digikam \
+ -I$(top_srcdir)/digikam/libs/dimg \
+ -I$(top_srcdir)/digikam/libs/dmetadata \
+ -I$(top_srcdir)/digikam/libs/themeengine \
+ -I$(top_srcdir)/digikam/libs/threadimageio \
+ $(LIBKDCRAW_CFLAGS) \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libslideshow.la
+
+libslideshow_la_SOURCES = toolbar.cpp slideshow.cpp
+
+libslideshow_la_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+
diff --git a/digikam/utilities/slideshow/slideshow.cpp b/digikam/utilities/slideshow/slideshow.cpp
new file mode 100644
index 0000000..3929c72
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qtimer.h>
+#include <qpixmap.h>
+#include <qdesktopwidget.h>
+#include <qevent.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qfont.h>
+
+// KDE includes.
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdeversion.h>
+#include <kglobalsettings.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;
+
+ QTimer *mouseMoveTimer; // To hide cursor when not moved.
+ QTimer *timer;
+
+ QPixmap pixmap;
+
+ DImg preview;
+
+ KURL currentImage;
+
+ PreviewLoadThread *previewThread;
+ PreviewLoadThread *previewPreloadThread;
+
+ ToolBar *toolBar;
+
+ SlideShowSettings settings;
+};
+
+SlideShow::SlideShow(const SlideShowSettings& settings)
+ : QWidget(0, 0, WStyle_StaysOnTop | WType_Popup |
+ WX11BypassWM | WDestructiveClose)
+{
+ d = new SlideShowPriv;
+ d->settings = settings;
+
+ // ---------------------------------------------------------------
+
+#if KDE_IS_VERSION(3,2,0)
+ QRect deskRect = KGlobalSettings::desktopGeometry(this);
+ d->deskX = deskRect.x();
+ d->deskY = deskRect.y();
+ d->deskWidth = deskRect.width();
+ d->deskHeight = deskRect.height();
+#else
+ QRect deskRect = QApplication::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(Qt::black);
+
+ // ---------------------------------------------------------------
+
+ d->toolBar = new ToolBar(this);
+ d->toolBar->hide();
+ if (!d->settings.loop)
+ d->toolBar->setEnabledPrev(false);
+
+ connect(d->toolBar, SIGNAL(signalPause()),
+ this, SLOT(slotPause()));
+
+ connect(d->toolBar, SIGNAL(signalPlay()),
+ this, SLOT(slotPlay()));
+
+ connect(d->toolBar, SIGNAL(signalNext()),
+ this, SLOT(slotNext()));
+
+ connect(d->toolBar, SIGNAL(signalPrev()),
+ this, SLOT(slotPrev()));
+
+ connect(d->toolBar, SIGNAL(signalClose()),
+ this, SLOT(slotClose()));
+
+ // ---------------------------------------------------------------
+
+ d->previewThread = new PreviewLoadThread();
+ d->previewPreloadThread = new PreviewLoadThread();
+ d->timer = new QTimer(this);
+ d->mouseMoveTimer = new QTimer(this);
+
+ connect(d->previewThread, SIGNAL(signalImageLoaded(const LoadingDescription &, const DImg &)),
+ this, SLOT(slotGotImagePreview(const LoadingDescription &, const DImg&)));
+
+ connect(d->mouseMoveTimer, SIGNAL(timeout()),
+ this, SLOT(slotMouseMoveTimeOut()));
+
+ connect(d->timer, SIGNAL(timeout()),
+ this, 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(),
+ QMAX(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(),
+ QMAX(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(),
+ QMAX(d->deskWidth, d->deskHeight), d->settings.exifRotate));
+ }
+}
+
+void SlideShow::updatePixmap()
+{
+ d->pixmap = QPixmap(size());
+ d->pixmap.fill(Qt::black);
+ QPainter p(&(d->pixmap));
+
+ if (!d->currentImage.path().isEmpty())
+ {
+ if (!d->preview.isNull())
+ {
+ // Preview extraction is complete... Draw the image.
+
+ QPixmap pix(d->preview.smoothScale(width(), height(), QSize::ScaleMin).convertToPixmap());
+ p.drawPixmap((width()-pix.width())/2,
+ (height()-pix.height())/2, pix,
+ 0, 0, pix.width(), pix.height());
+
+ QString 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 = QString();
+
+ if (!photoInfo.make.isEmpty())
+ str = photoInfo.make;
+
+ if (!photoInfo.model.isEmpty())
+ {
+ if (!photoInfo.make.isEmpty())
+ str += QString(" / ");
+
+ str += photoInfo.model;
+ }
+
+ printInfoText(p, offset, str);
+ }
+
+ // Display the Exposure and Sensitivity.
+
+ if (d->settings.printExpoSensitivity)
+ {
+ str = QString();
+
+ if (!photoInfo.exposureTime.isEmpty())
+ str = photoInfo.exposureTime;
+
+ if (!photoInfo.sensitivity.isEmpty())
+ {
+ if (!photoInfo.exposureTime.isEmpty())
+ str += QString(" / ");
+
+ str += i18n("%1 ISO").arg(photoInfo.sensitivity);
+ }
+
+ printInfoText(p, offset, str);
+ }
+
+ // Display the Aperture and Focal.
+
+ if (d->settings.printApertureFocal)
+ {
+ str = QString();
+
+ if (!photoInfo.aperture.isEmpty())
+ str = photoInfo.aperture;
+
+ if (photoInfo.focalLength35mm.isEmpty())
+ {
+ if (!photoInfo.focalLength.isEmpty())
+ {
+ if (!photoInfo.aperture.isEmpty())
+ str += QString(" / ");
+
+ str += photoInfo.focalLength;
+ }
+ }
+ else
+ {
+ if (!photoInfo.aperture.isEmpty())
+ str += QString(" / ");
+
+ if (!photoInfo.focalLength.isEmpty())
+ str += QString("%1 (35mm: %2)").arg(photoInfo.focalLength).arg(photoInfo.focalLength35mm);
+ else
+ str += QString("35mm: %1)").arg(photoInfo.focalLength35mm);
+ }
+
+ printInfoText(p, offset, str);
+ }
+
+ // Display the Creation Date.
+
+ if (d->settings.printDate)
+ {
+ if (photoInfo.dateTime.isValid())
+ {
+ str = KGlobal::locale()->formatDateTime(photoInfo.dateTime, true, true);
+ printInfoText(p, offset, str);
+ }
+ }
+
+ // Display the image File Name.
+
+ if (d->settings.printName)
+ {
+ str = QString("%1 (%2/%3)").arg(d->currentImage.filename())
+ .arg(QString::number(d->fileIndex + 1))
+ .arg(QString::number(d->settings.fileList.count()));
+
+ printInfoText(p, offset, str);
+ }
+ }
+ else
+ {
+ // ...or preview extraction is failed.
+
+ p.setPen(Qt::white);
+ p.drawText(0, 0, d->pixmap.width(), d->pixmap.height(),
+ Qt::AlignCenter|Qt::WordBreak,
+ i18n("Cannot display image\n\"%1\"")
+ .arg(d->currentImage.fileName()));
+ }
+ }
+ else
+ {
+ // End of Slide Show.
+
+ QPixmap logo = kapp->iconLoader()->loadIcon("digikam", KIcon::NoGroup, 128,
+ KIcon::DefaultState, 0, true);
+
+ QFont fn(font());
+ fn.setPointSize(fn.pointSize()+10);
+ fn.setBold(true);
+
+ p.setFont(fn);
+ p.setPen(Qt::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(QPainter &p, int &offset, const QString& str)
+{
+ if (!str.isEmpty())
+ {
+ offset += 20;
+ p.setPen(Qt::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(Qt::white);
+ p.drawText(10, height()-offset, str);
+ }
+}
+
+void SlideShow::printComments(QPainter &p, int &offset, const QString& comments)
+{
+ QStringList commentsByLines;
+
+ uint commentsIndex = 0; // Comments QString index
+
+ while (commentsIndex < comments.length())
+ {
+ QString newLine;
+ bool breakLine = false; // End Of Line found
+ uint currIndex; // Comments QString current index
+
+ // Check miminal lines dimension
+
+ uint commentsLinesLengthLocal = MAXSTRINGLEN;
+
+ for (currIndex = commentsIndex; currIndex < comments.length() && !breakLine; currIndex++ )
+ {
+ if( comments[currIndex] == QChar('\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] == QChar('\n')) ? true : false;
+
+ if (breakLine)
+ newLine.append(QString(" "));
+ 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(QPaintEvent *)
+{
+ bitBlt(this, 0, 0, &d->pixmap,
+ 0, 0, d->pixmap.width(),
+ d->pixmap.height(), Qt::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(QWheelEvent * 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(QMouseEvent *e)
+{
+ if (d->endOfShow)
+ close();
+
+ if (e->button() == Qt::LeftButton)
+ {
+ d->timer->stop();
+ d->pause = true;
+ d->toolBar->setPaused(true);
+ slotNext();
+ }
+ else if (e->button() == Qt::RightButton && d->fileIndex-1 >= 0)
+ {
+ d->timer->stop();
+ d->pause = true;
+ d->toolBar->setPaused(true);
+ slotPrev();
+ }
+}
+
+void SlideShow::keyPressEvent(QKeyEvent *event)
+{
+ if (!event)
+ return;
+
+ d->toolBar->keyPressEvent(event);
+}
+
+void SlideShow::mouseMoveEvent(QMouseEvent *e)
+{
+ setCursor(QCursor(Qt::ArrowCursor));
+ d->mouseMoveTimer->start(1000, true);
+
+ if (!d->toolBar->canHide())
+ return;
+
+ QPoint 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()
+{
+ QPoint pos(QCursor::pos());
+ if ((pos.y() < (d->deskY+20)) ||
+ (pos.y() > (d->deskY+d->deskHeight-20-1)))
+ return;
+
+ setCursor(QCursor(Qt::BlankCursor));
+}
+
+} // NameSpace Digikam
diff --git a/digikam/utilities/slideshow/slideshow.h b/digikam/utilities/slideshow/slideshow.h
new file mode 100644
index 0000000..03834e1
--- /dev/null
+++ b/digikam/utilities/slideshow/slideshow.h
@@ -0,0 +1,90 @@
+/* ============================================================
+ *
+ * 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
+
+// Qt includes.
+
+#include <qwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+#include "loadingdescription.h"
+#include "slideshowsettings.h"
+
+namespace Digikam
+{
+
+class DImg;
+class SlideShowPriv;
+
+class DIGIKAM_EXPORT SlideShow : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ SlideShow(const SlideShowSettings& settings);
+ ~SlideShow();
+
+ void setCurrent(const KURL& url);
+
+protected:
+
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void wheelEvent(QWheelEvent *);
+
+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(QPainter &p, int &offset, const QString& str);
+ void printComments(QPainter &p, int &offset, const QString& comments);
+
+private:
+
+ SlideShowPriv *d;
+};
+
+} // NameSpace Digikam
+
+#endif /* SLIDE_SHOW_H */
diff --git a/digikam/utilities/slideshow/slideshowsettings.h b/digikam/utilities/slideshow/slideshowsettings.h
new file mode 100644
index 0000000..74b9661
--- /dev/null
+++ b/digikam/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
+
+// Qt includes.
+
+#include <qmap.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 */
+ QString 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 */
+ QMap<KURL, SlidePictureInfo> pictInfoMap;
+};
+
+} // namespace Digikam
+
+#endif // SLIDESHOWSETTINGSCONTAINER_H
diff --git a/digikam/utilities/slideshow/toolbar.cpp b/digikam/utilities/slideshow/toolbar.cpp
new file mode 100644
index 0000000..7b3f8f3
--- /dev/null
+++ b/digikam/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.
+ *
+ * ============================================================ */
+
+// Qt includes.
+
+#include <qtoolbutton.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+
+// KDE includes.
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <klocale.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;
+
+ QToolButton *playBtn;
+ QToolButton *stopBtn;
+ QToolButton *nextBtn;
+ QToolButton *prevBtn;
+};
+
+ToolBar::ToolBar(QWidget* parent)
+ : QWidget(parent)
+{
+ d = new ToolBarPriv;
+
+ QHBoxLayout* lay = new QHBoxLayout(this);
+ d->playBtn = new QToolButton(this);
+ d->prevBtn = new QToolButton(this);
+ d->nextBtn = new QToolButton(this);
+ d->stopBtn = new QToolButton(this);
+ d->playBtn->setToggleButton(true);
+
+ KIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("player_pause", KIcon::NoGroup, 22));
+ d->prevBtn->setIconSet(loader->loadIcon("back", KIcon::NoGroup, 22));
+ d->nextBtn->setIconSet(loader->loadIcon("forward", KIcon::NoGroup, 22));
+ d->stopBtn->setIconSet(loader->loadIcon("stop", KIcon::NoGroup, 22));
+
+ lay->addWidget(d->playBtn);
+ lay->addWidget(d->prevBtn);
+ lay->addWidget(d->nextBtn);
+ lay->addWidget(d->stopBtn);
+
+ setBackgroundMode(Qt::NoBackground);
+ adjustSize();
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ connect(d->playBtn, SIGNAL(toggled(bool)),
+ this, SLOT(slotPlayBtnToggled()));
+
+ connect(d->nextBtn, SIGNAL(clicked()),
+ this, SLOT(slotNexPrevClicked()));
+
+ connect(d->prevBtn, SIGNAL(clicked()),
+ this, SLOT(slotNexPrevClicked()));
+
+ connect(d->nextBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalNext()));
+
+ connect(d->prevBtn, SIGNAL(clicked()),
+ this, SIGNAL(signalPrev()));
+
+ connect(d->stopBtn, SIGNAL(clicked()),
+ this, 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;
+ KIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("player_play", KIcon::NoGroup, 22));
+ emit signalPause();
+ }
+ else
+ {
+ d->canHide = true;
+ KIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("player_pause", KIcon::NoGroup, 22));
+ emit signalPlay();
+ }
+}
+
+void ToolBar::slotNexPrevClicked()
+{
+ if (!d->playBtn->isOn())
+ {
+ d->playBtn->setOn(true);
+ d->canHide = false;
+ KIconLoader* loader = kapp->iconLoader();
+ d->playBtn->setIconSet(loader->loadIcon("player_play", KIcon::NoGroup, 22));
+ emit signalPause();
+ }
+}
+
+void ToolBar::keyPressEvent(QKeyEvent *event)
+{
+ switch(event->key())
+ {
+ case(Qt::Key_Space):
+ {
+ if (d->playBtn->isEnabled())
+ d->playBtn->animateClick();
+ break;
+ }
+ case(Qt::Key_Prior):
+ {
+ if (d->prevBtn->isEnabled())
+ d->prevBtn->animateClick();
+ break;
+ }
+ case(Qt::Key_Next):
+ {
+ if (d->nextBtn->isEnabled())
+ d->nextBtn->animateClick();
+ break;
+ }
+ case(Qt::Key_Escape):
+ {
+ if (d->stopBtn->isEnabled())
+ d->stopBtn->animateClick();
+ break;
+ }
+ default:
+ break;
+ }
+
+ event->accept();
+}
+
+} // Namespace Digikam
+
diff --git a/digikam/utilities/slideshow/toolbar.h b/digikam/utilities/slideshow/toolbar.h
new file mode 100644
index 0000000..25b15ba
--- /dev/null
+++ b/digikam/utilities/slideshow/toolbar.h
@@ -0,0 +1,84 @@
+/* ============================================================
+ *
+ * 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 <qwidget.h>
+
+// Local includes.
+
+#include "digikam_export.h"
+
+class QToolButton;
+
+namespace Digikam
+{
+
+class ToolBarPriv;
+
+class DIGIKAM_EXPORT ToolBar : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ ToolBar(QWidget* 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(QKeyEvent *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 */