summaryrefslogtreecommitdiffstats
path: root/src/utilities/cameragui/cameraui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/utilities/cameragui/cameraui.cpp')
-rw-r--r--src/utilities/cameragui/cameraui.cpp1734
1 files changed, 1734 insertions, 0 deletions
diff --git a/src/utilities/cameragui/cameraui.cpp b/src/utilities/cameragui/cameraui.cpp
new file mode 100644
index 00000000..8b531ea2
--- /dev/null
+++ b/src/utilities/cameragui/cameraui.cpp
@@ -0,0 +1,1734 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-09-16
+ * Description : Camera interface dialog
+ *
+ * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
+ * Copyright (C) 2006-2009 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software Foundation;
+ * either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ============================================================ */
+
+#define CAMERA_INFO_MENU_ID 255
+
+// TQt includes.
+
+#include <tqvgroupbox.h>
+#include <tqlayout.h>
+#include <tqpushbutton.h>
+#include <tqtoolbutton.h>
+#include <tqiconview.h>
+#include <tqvbox.h>
+#include <tqhbox.h>
+#include <tqpopupmenu.h>
+#include <tqsplitter.h>
+#include <tqpixmap.h>
+#include <tqcombobox.h>
+#include <tqtoolbox.h>
+#include <tqframe.h>
+#include <tqvbuttongroup.h>
+#include <tqradiobutton.h>
+#include <tqcheckbox.h>
+#include <tqlineedit.h>
+#include <tqtooltip.h>
+#include <tqtimer.h>
+#include <tqwhatsthis.h>
+#include <tqfile.h>
+#include <tqfileinfo.h>
+
+// KDE includes.
+
+#include <tdefiledialog.h>
+#include <kimageio.h>
+#include <tdeaboutdata.h>
+#include <tdemessagebox.h>
+#include <kprogress.h>
+#include <tdeglobal.h>
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tdeapplication.h>
+#include <kiconloader.h>
+#include <tdepopupmenu.h>
+#include <kstandarddirs.h>
+#include <khelpmenu.h>
+#include <kcalendarsystem.h>
+#include <kurllabel.h>
+#include <ksqueezedtextlabel.h>
+
+#if KDE_IS_VERSION(3,2,0)
+#include <kinputdialog.h>
+#else
+#include <klineeditdlg.h>
+#endif
+
+// LibKDcraw includes.
+
+#include <libkdcraw/version.h>
+#include <libkdcraw/kdcraw.h>
+
+#if KDCRAW_VERSION < 0x000106
+#include <libkdcraw/dcrawbinary.h>
+#endif
+
+// Local includes.
+
+#include "daboutdata.h"
+#include "ddebug.h"
+#include "thumbnailsize.h"
+#include "kdatetimeedit.h"
+#include "sidebar.h"
+#include "scanlib.h"
+#include "downloadsettingscontainer.h"
+#include "imagepropertiessidebarcamgui.h"
+#include "albummanager.h"
+#include "albumsettings.h"
+#include "album.h"
+#include "albumselectdialog.h"
+#include "renamecustomizer.h"
+#include "animwidget.h"
+#include "freespacewidget.h"
+#include "camerafolderdialog.h"
+#include "camerainfodialog.h"
+#include "cameraiconview.h"
+#include "cameraiconitem.h"
+#include "cameracontroller.h"
+#include "cameralist.h"
+#include "cameratype.h"
+#include "cameraui.h"
+#include "cameraui.moc"
+
+namespace Digikam
+{
+
+class CameraUIPriv
+{
+public:
+
+ enum SettingsTab
+ {
+ RENAMEFILEPAGE=0,
+ AUTOALBUMPAGE,
+ ONFLYPAGE
+ };
+
+ enum DateFormatOptions
+ {
+ IsoDateFormat=0,
+ TextDateFormat,
+ LocalDateFormat
+ };
+
+ CameraUIPriv()
+ {
+ deleteAfter = false;
+ busy = false;
+ closed = false;
+ helpMenu = 0;
+ advBox = 0;
+ downloadMenu = 0;
+ deleteMenu = 0;
+ imageMenu = 0;
+ cancelBtn = 0;
+ splitter = 0;
+ rightSidebar = 0;
+ fixDateTimeCheck = 0;
+ autoRotateCheck = 0;
+ autoAlbumDateCheck = 0;
+ autoAlbumExtCheck = 0;
+ status = 0;
+ progress = 0;
+ controller = 0;
+ view = 0;
+ renameCustomizer = 0;
+ anim = 0;
+ dateTimeEdit = 0;
+ setPhotographerId = 0;
+ setCredits = 0;
+ losslessFormat = 0;
+ convertJpegCheck = 0;
+ formatLabel = 0;
+ folderDateLabel = 0;
+ folderDateFormat = 0;
+ freeSpaceWidget = 0;
+ }
+
+ bool deleteAfter;
+ bool busy;
+ bool closed;
+
+ TQString cameraTitle;
+
+ TQStringList currentlyDeleting;
+ TQStringList foldersToScan;
+ TQStringList cameraFolderList;
+
+ TQPopupMenu *downloadMenu;
+ TQPopupMenu *deleteMenu;
+ TQPopupMenu *imageMenu;
+
+ TQToolButton *cancelBtn;
+
+ TQToolBox *advBox;
+
+ TQCheckBox *autoRotateCheck;
+ TQCheckBox *autoAlbumDateCheck;
+ TQCheckBox *autoAlbumExtCheck;
+ TQCheckBox *fixDateTimeCheck;
+ TQCheckBox *setPhotographerId;
+ TQCheckBox *setCredits;
+ TQCheckBox *convertJpegCheck;
+
+ TQLabel *formatLabel;
+ TQLabel *folderDateLabel;
+
+ TQComboBox *losslessFormat;
+ TQComboBox *folderDateFormat;
+
+ TQSplitter *splitter;
+
+ TQDateTime lastAccess;
+
+ KProgress *progress;
+
+ KSqueezedTextLabel *status;
+
+ KURL lastDestURL;
+
+ KHelpMenu *helpMenu;
+
+ KDateTimeEdit *dateTimeEdit;
+
+ CameraController *controller;
+
+ CameraIconView *view;
+
+ RenameCustomizer *renameCustomizer;
+
+ AnimWidget *anim;
+
+ ImagePropertiesSideBarCamGui *rightSidebar;
+
+ FreeSpaceWidget *freeSpaceWidget;
+};
+
+CameraUI::CameraUI(TQWidget* /*parent*/, const TQString& cameraTitle,
+ const TQString& model, const TQString& port,
+ const TQString& path, const TQDateTime lastAccess)
+ : KDialogBase(Plain, cameraTitle,
+ Help|User1|User2|User3|Close, Close,
+ 0, // B.K.O # 116485: no parent for this modal dialog.
+ 0, false, true,
+ i18n("D&elete"),
+ i18n("&Download"),
+ i18n("&Images"))
+{
+ d = new CameraUIPriv;
+ d->lastAccess = lastAccess;
+ d->cameraTitle = cameraTitle;
+ setHelp("camerainterface.anchor", "digikam");
+
+ // -------------------------------------------------------------------------
+
+ TQGridLayout* viewBoxLayout = new TQGridLayout(plainPage(), 2, 7);
+
+ TQHBox* widget = new TQHBox(plainPage());
+ d->splitter = new TQSplitter(widget);
+ d->view = new CameraIconView(this, d->splitter);
+
+ TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1);
+ d->view->setSizePolicy(rightSzPolicy);
+
+ d->rightSidebar = new ImagePropertiesSideBarCamGui(widget, "CameraGui Sidebar Right", d->splitter,
+ Sidebar::Right, true);
+ d->splitter->setFrameStyle( TQFrame::NoFrame );
+ d->splitter->setFrameShadow( TQFrame::Plain );
+ d->splitter->setFrameShape( TQFrame::NoFrame );
+ d->splitter->setOpaqueResize(false);
+
+ // -------------------------------------------------------------------------
+
+ d->advBox = new TQToolBox(d->rightSidebar);
+ d->renameCustomizer = new RenameCustomizer(d->advBox, d->cameraTitle);
+ d->view->setRenameCustomizer(d->renameCustomizer);
+
+ TQWhatsThis::add( d->advBox, i18n("<p>Set how digiKam will rename files as they are downloaded."));
+
+ d->advBox->insertItem(CameraUIPriv::RENAMEFILEPAGE, d->renameCustomizer,
+ SmallIconSet("fileimport"), i18n("File Renaming Options"));
+
+ // -- Albums Auto-creation options -----------------------------------------
+
+ TQWidget* albumBox = new TQWidget(d->advBox);
+ TQVBoxLayout* albumVlay = new TQVBoxLayout(albumBox, marginHint(), spacingHint());
+ d->autoAlbumExtCheck = new TQCheckBox(i18n("Extension-based sub-albums"), albumBox);
+ d->autoAlbumDateCheck = new TQCheckBox(i18n("Date-based sub-albums"), albumBox);
+ TQHBox *hbox1 = new TQHBox(albumBox);
+ d->folderDateLabel = new TQLabel(i18n("Date format:"), hbox1);
+ d->folderDateFormat = new TQComboBox(hbox1);
+ d->folderDateFormat->insertItem(i18n("ISO"), CameraUIPriv::IsoDateFormat);
+ d->folderDateFormat->insertItem(i18n("Full Text"), CameraUIPriv::TextDateFormat);
+ d->folderDateFormat->insertItem(i18n("Local Settings"), CameraUIPriv::LocalDateFormat);
+ albumVlay->addWidget(d->autoAlbumExtCheck);
+ albumVlay->addWidget(d->autoAlbumDateCheck);
+ albumVlay->addWidget(hbox1);
+ albumVlay->addStretch();
+
+ TQWhatsThis::add( albumBox, i18n("<p>Set how digiKam creates albums automatically when downloading."));
+ TQWhatsThis::add( d->autoAlbumExtCheck, i18n("<p>Enable this option if you want to download your "
+ "pictures into automatically created file extension-based sub-albums of the destination "
+ "album. This way, you can separate JPEG and RAW files as they are downloaded from your camera."));
+ TQWhatsThis::add( d->autoAlbumDateCheck, i18n("<p>Enable this option if you want to "
+ "download your pictures into automatically created file date-based sub-albums "
+ "of the destination album."));
+ TQWhatsThis::add( d->folderDateFormat, i18n("<p>Select your preferred date format used to "
+ "create new albums. The options available are:<p>"
+ "<b>ISO</b>: the date format is in accordance with ISO 8601 "
+ "(YYYY-MM-DD). E.g.: <i>2006-08-24</i><p>"
+ "<b>Full Text</b>: the date format is in a user-readable string. "
+ "E.g.: <i>Thu Aug 24 2006</i><p>"
+ "<b>Local Settings</b>: the date format depending on TDE control panel settings.<p>"));
+
+ d->advBox->insertItem(CameraUIPriv::AUTOALBUMPAGE, albumBox, SmallIconSet("folder-new"),
+ i18n("Auto-creation of Albums"));
+
+ // -- On the Fly options ---------------------------------------------------
+
+ TQWidget* onFlyBox = new TQWidget(d->advBox);
+ TQVBoxLayout* onFlyVlay = new TQVBoxLayout(onFlyBox, marginHint(), spacingHint());
+ d->setPhotographerId = new TQCheckBox(i18n("Set default photographer identity"), onFlyBox);
+ d->setCredits = new TQCheckBox(i18n("Set default credit and copyright"), onFlyBox);
+ d->fixDateTimeCheck = new TQCheckBox(i18n("Fix internal date && time"), onFlyBox);
+ d->dateTimeEdit = new KDateTimeEdit(onFlyBox, "datepicker");
+ d->autoRotateCheck = new TQCheckBox(i18n("Auto-rotate/flip image"), onFlyBox);
+ d->convertJpegCheck = new TQCheckBox(i18n("Convert to lossless file format"), onFlyBox);
+ TQHBox *hbox2 = new TQHBox(onFlyBox);
+ d->formatLabel = new TQLabel(i18n("New image format:"), hbox2);
+ d->losslessFormat = new TQComboBox(hbox2);
+ d->losslessFormat->insertItem("PNG", 0);
+ onFlyVlay->addWidget(d->setPhotographerId);
+ onFlyVlay->addWidget(d->setCredits);
+ onFlyVlay->addWidget(d->fixDateTimeCheck);
+ onFlyVlay->addWidget(d->dateTimeEdit);
+ onFlyVlay->addWidget(d->autoRotateCheck);
+ onFlyVlay->addWidget(d->convertJpegCheck);
+ onFlyVlay->addWidget(hbox2);
+ onFlyVlay->addStretch();
+
+ TQWhatsThis::add( onFlyBox, i18n("<p>Set here all options to fix/transform JPEG files automatically "
+ "as they are downloaded."));
+ TQWhatsThis::add( d->autoRotateCheck, i18n("<p>Enable this option if you want images automatically "
+ "rotated or flipped using EXIF information provided by the camera."));
+ TQWhatsThis::add( d->setPhotographerId, i18n("<p>Enable this option to store the default "
+ "photographer identity in the IPTC tags using digiKam's metadata settings."));
+ TQWhatsThis::add( d->setCredits, i18n("<p>Enable this option to store the default credit "
+ "and copyright information in the IPTC tags using digiKam's metadata settings."));
+ TQWhatsThis::add( d->fixDateTimeCheck, i18n("<p>Enable this option to set date and time metadata "
+ "tags to the right values if your camera does not set "
+ "these tags correctly when pictures are taken. The values will "
+ "be saved in the DateTimeDigitized and DateTimeCreated EXIF/IPTC fields."));
+ TQWhatsThis::add( d->convertJpegCheck, i18n("<p>Enable this option to automatically convert "
+ "all JPEG files to a lossless image format. <b>Note:</b> Image conversion can take a "
+ "while on a slow computer."));
+ TQWhatsThis::add( d->losslessFormat, i18n("<p>Select your preferred lossless image file format to "
+ "convert to. <b>Note:</b> All metadata will be preserved during the conversion."));
+
+ d->advBox->insertItem(CameraUIPriv::ONFLYPAGE, onFlyBox, SmallIconSet("system-run"),
+ i18n("On the Fly Operations (JPEG only)"));
+
+ d->rightSidebar->appendTab(d->advBox, SmallIcon("configure"), i18n("Settings"));
+ d->rightSidebar->loadViewState();
+
+ // -------------------------------------------------------------------------
+
+ d->cancelBtn = new TQToolButton(plainPage());
+ d->cancelBtn->setSizePolicy( TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum ) );
+ d->cancelBtn->setPixmap( SmallIcon( "cancel" ) );
+ d->cancelBtn->setEnabled(false);
+
+ d->status = new KSqueezedTextLabel(plainPage());
+ d->progress = new KProgress(plainPage());
+ d->progress->setMaximumHeight( fontMetrics().height()+4 );
+ d->progress->hide();
+
+ TQWidget *frame = new TQWidget(plainPage());
+ TQHBoxLayout* layout = new TQHBoxLayout(frame);
+ frame->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum));
+
+ KURLLabel *pixmapLogo = new KURLLabel( Digikam::webProjectUrl(), TQString(), frame );
+ pixmapLogo->setMargin(0);
+ pixmapLogo->setScaledContents( false );
+ pixmapLogo->setSizePolicy(TQSizePolicy( TQSizePolicy::Minimum, TQSizePolicy::Minimum));
+ TQToolTip::add(pixmapLogo, i18n("Visit digiKam project website"));
+ TDEGlobal::dirs()->addResourceType("logo-digikam", TDEGlobal::dirs()->kde_default("data") + "digikam/data");
+ TQString directory = TDEGlobal::dirs()->findResourceDir("logo-digikam", "logo-digikam.png");
+ pixmapLogo->setPixmap( TQPixmap( directory + "logo-digikam.png" ) );
+ pixmapLogo->setFocusPolicy(TQWidget::NoFocus);
+
+ d->anim = new AnimWidget(frame, pixmapLogo->height()-2);
+
+ layout->setMargin(0);
+ layout->setSpacing(0);
+ layout->addWidget( pixmapLogo );
+ layout->addWidget( d->anim );
+
+ d->freeSpaceWidget = new FreeSpaceWidget(plainPage(), 100);
+
+ viewBoxLayout->addMultiCellWidget(widget, 0, 0, 0, 7);
+ viewBoxLayout->addMultiCellWidget(d->cancelBtn, 2, 2, 0, 0);
+ viewBoxLayout->addMultiCellWidget(d->status, 2, 2, 2, 2);
+ viewBoxLayout->addMultiCellWidget(d->progress, 2, 2, 3, 3);
+ viewBoxLayout->addMultiCellWidget(d->freeSpaceWidget, 2, 2, 5, 5);
+ viewBoxLayout->addMultiCellWidget(frame, 2, 2, 7, 7);
+ viewBoxLayout->setRowSpacing(1, spacingHint());
+ viewBoxLayout->setColSpacing(1, spacingHint());
+ viewBoxLayout->setColSpacing(4, spacingHint());
+ viewBoxLayout->setColSpacing(6, spacingHint());
+ viewBoxLayout->setColStretch( 0, 0 );
+ viewBoxLayout->setColStretch( 1, 0 );
+ viewBoxLayout->setColStretch( 2, 3 );
+ viewBoxLayout->setColStretch( 3, 1 );
+ viewBoxLayout->setColStretch( 4, 0 );
+ viewBoxLayout->setColStretch( 5, 0 );
+ viewBoxLayout->setColStretch( 6, 0 );
+ viewBoxLayout->setColStretch( 7, 0 );
+
+ // -------------------------------------------------------------------------
+
+ d->imageMenu = new TQPopupMenu(this);
+ d->imageMenu->insertItem(i18n("Select &All"), d->view, TQ_SLOT(slotSelectAll()), CTRL+Key_A, 0);
+ d->imageMenu->insertItem(i18n("Select N&one"), d->view, TQ_SLOT(slotSelectNone()), CTRL+Key_U, 1);
+ d->imageMenu->insertItem(i18n("&Invert Selection"), d->view, TQ_SLOT(slotSelectInvert()), CTRL+Key_Asterisk, 2);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Select &New Items"), d->view, TQ_SLOT(slotSelectNew()), 0, 3);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Increase Thumbnail Size"), this, TQ_SLOT(slotIncreaseThumbSize()), CTRL+Key_Plus, 4);
+ d->imageMenu->insertItem(i18n("Decrease Thumbnail Size"), this, TQ_SLOT(slotDecreaseThumbSize()), CTRL+Key_Minus, 5);
+ d->imageMenu->insertSeparator();
+ d->imageMenu->insertItem(i18n("Toggle Lock"), this, TQ_SLOT(slotToggleLock()), 0, 6);
+ actionButton(User3)->setPopup(d->imageMenu);
+
+ // -------------------------------------------------------------------------
+
+ d->downloadMenu = new TQPopupMenu(this);
+ d->downloadMenu->insertItem(i18n("Download Selected"),
+ this, TQ_SLOT(slotDownloadSelected()), 0, 0);
+ d->downloadMenu->insertItem(i18n("Download All"),
+ this, TQ_SLOT(slotDownloadAll()), 0, 1);
+ d->downloadMenu->insertSeparator();
+ d->downloadMenu->insertItem(i18n("Download/Delete Selected"),
+ this, TQ_SLOT(slotDownloadAndDeleteSelected()), 0, 2);
+ d->downloadMenu->insertItem(i18n("Download/Delete All"),
+ this, TQ_SLOT(slotDownloadAndDeleteAll()), 0, 3);
+ d->downloadMenu->insertSeparator();
+ d->downloadMenu->insertItem(i18n("Upload..."),
+ this, TQ_SLOT(slotUpload()), 0, 4);
+ d->downloadMenu->setItemEnabled(0, false);
+ d->downloadMenu->setItemEnabled(2, false);
+ actionButton(User2)->setPopup(d->downloadMenu);
+
+ // -------------------------------------------------------------------------
+
+ d->deleteMenu = new TQPopupMenu(this);
+ d->deleteMenu->insertItem(i18n("Delete Selected"), this, TQ_SLOT(slotDeleteSelected()), 0, 0);
+ d->deleteMenu->insertItem(i18n("Delete All"), this, TQ_SLOT(slotDeleteAll()), 0, 1);
+ d->deleteMenu->setItemEnabled(0, false);
+ actionButton(User1)->setPopup(d->deleteMenu);
+
+ // -------------------------------------------------------------------------
+
+ TQPushButton *helpButton = actionButton( Help );
+ d->helpMenu = new KHelpMenu(this, kapp->aboutData(), false);
+ d->helpMenu->menu()->insertItem(SmallIcon("camera-photo"), i18n("Camera Information"),
+ this, TQ_SLOT(slotInformations()), 0, CAMERA_INFO_MENU_ID, 0);
+ helpButton->setPopup( d->helpMenu->menu() );
+
+ // -------------------------------------------------------------------------
+
+ connect(d->autoAlbumDateCheck, TQ_SIGNAL(toggled(bool)),
+ d->folderDateFormat, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->autoAlbumDateCheck, TQ_SIGNAL(toggled(bool)),
+ d->folderDateLabel, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)),
+ d->losslessFormat, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)),
+ d->formatLabel, TQ_SLOT(setEnabled(bool)));
+
+ connect(d->convertJpegCheck, TQ_SIGNAL(toggled(bool)),
+ d->view, TQ_SLOT(slotDownloadNameChanged()));
+
+ connect(d->fixDateTimeCheck, TQ_SIGNAL(toggled(bool)),
+ d->dateTimeEdit, TQ_SLOT(setEnabled(bool)));
+
+ connect(pixmapLogo, TQ_SIGNAL(leftClickedURL(const TQString&)),
+ this, TQ_SLOT(slotProcessURL(const TQString&)));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->view, TQ_SIGNAL(signalSelected(CameraIconViewItem*, bool)),
+ this, TQ_SLOT(slotItemsSelected(CameraIconViewItem*, bool)));
+
+ connect(d->view, TQ_SIGNAL(signalFileView(CameraIconViewItem*)),
+ this, TQ_SLOT(slotFileView(CameraIconViewItem*)));
+
+ connect(d->view, TQ_SIGNAL(signalUpload(const KURL::List&)),
+ this, TQ_SLOT(slotUploadItems(const KURL::List&)));
+
+ connect(d->view, TQ_SIGNAL(signalDownload()),
+ this, TQ_SLOT(slotDownloadSelected()));
+
+ connect(d->view, TQ_SIGNAL(signalDownloadAndDelete()),
+ this, TQ_SLOT(slotDownloadAndDeleteSelected()));
+
+ connect(d->view, TQ_SIGNAL(signalDelete()),
+ this, TQ_SLOT(slotDeleteSelected()));
+
+ connect(d->view, TQ_SIGNAL(signalToggleLock()),
+ this, TQ_SLOT(slotToggleLock()));
+
+ connect(d->view, TQ_SIGNAL(signalNewSelection(bool)),
+ this, TQ_SLOT(slotNewSelection(bool)));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalFirstItem()),
+ this, TQ_SLOT(slotFirstItem()));
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalNextItem()),
+ this, TQ_SLOT(slotNextItem()));
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalPrevItem()),
+ this, TQ_SLOT(slotPrevItem()));
+
+ connect(d->rightSidebar, TQ_SIGNAL(signalLastItem()),
+ this, TQ_SLOT(slotLastItem()));
+
+ // -------------------------------------------------------------------------
+
+ connect(d->cancelBtn, TQ_SIGNAL(clicked()),
+ this, TQ_SLOT(slotCancelButton()));
+
+ // -- Read settings & Check free space availability on album root path -----
+
+ readSettings();
+
+ // -- camera controller ----------------------------------------------------
+
+ d->controller = new CameraController(this, d->cameraTitle, model, port, path);
+
+ connect(d->controller, TQ_SIGNAL(signalConnected(bool)),
+ this, TQ_SLOT(slotConnected(bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalInfoMsg(const TQString&)),
+ d->status, TQ_SLOT(setText(const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalErrorMsg(const TQString&)),
+ this, TQ_SLOT(slotErrorMsg(const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalCameraInformations(const TQString&, const TQString&, const TQString&)),
+ this, TQ_SLOT(slotCameraInformations(const TQString&, const TQString&, const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalBusy(bool)),
+ this, TQ_SLOT(slotBusy(bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalFolderList(const TQStringList&)),
+ this, TQ_SLOT(slotFolderList(const TQStringList&)));
+
+ connect(d->controller, TQ_SIGNAL(signalFileList(const GPItemInfoList&)),
+ this, TQ_SLOT(slotFileList(const GPItemInfoList&)));
+
+ connect(d->controller, TQ_SIGNAL(signalThumbnail(const TQString&, const TQString&, const TQImage&)),
+ this, TQ_SLOT(slotThumbnail(const TQString&, const TQString&, const TQImage&)));
+
+ connect(d->controller, TQ_SIGNAL(signalDownloaded(const TQString&, const TQString&, int)),
+ this, TQ_SLOT(slotDownloaded(const TQString&, const TQString&, int)));
+
+ connect(d->controller, TQ_SIGNAL(signalSkipped(const TQString&, const TQString&)),
+ this, TQ_SLOT(slotSkipped(const TQString&, const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalDeleted(const TQString&, const TQString&, bool)),
+ this, TQ_SLOT(slotDeleted(const TQString&, const TQString&, bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalLocked(const TQString&, const TQString&, bool)),
+ this, TQ_SLOT(slotLocked(const TQString&, const TQString&, bool)));
+
+ connect(d->controller, TQ_SIGNAL(signalExifFromFile(const TQString&, const TQString&)),
+ this, TQ_SLOT(slotExifFromFile(const TQString&, const TQString&)));
+
+ connect(d->controller, TQ_SIGNAL(signalExifData(const TQByteArray&)),
+ this, TQ_SLOT(slotExifFromData(const TQByteArray&)));
+
+ connect(d->controller, TQ_SIGNAL(signalUploaded(const GPItemInfo&)),
+ this, TQ_SLOT(slotUploaded(const GPItemInfo&)));
+
+ // -------------------------------------------------------------------------
+
+ d->view->setFocus();
+ TQTimer::singleShot(0, d->controller, TQ_SLOT(slotConnect()));
+}
+
+CameraUI::~CameraUI()
+{
+ delete d->rightSidebar;
+ delete d->controller;
+ delete d;
+}
+
+void CameraUI::readSettings()
+{
+ TDEConfig* config = kapp->config();
+ config->setGroup("Camera Settings");
+ d->advBox->setCurrentIndex(config->readNumEntry("Settings Tab", CameraUIPriv::RENAMEFILEPAGE));
+ d->autoRotateCheck->setChecked(config->readBoolEntry("AutoRotate", true));
+ d->autoAlbumDateCheck->setChecked(config->readBoolEntry("AutoAlbumDate", false));
+ d->autoAlbumExtCheck->setChecked(config->readBoolEntry("AutoAlbumExt", false));
+ d->fixDateTimeCheck->setChecked(config->readBoolEntry("FixDateTime", false));
+ d->setPhotographerId->setChecked(config->readBoolEntry("SetPhotographerId", false));
+ d->setCredits->setChecked(config->readBoolEntry("SetCredits", false));
+ d->convertJpegCheck->setChecked(config->readBoolEntry("ConvertJpeg", false));
+ d->losslessFormat->setCurrentItem(config->readNumEntry("LossLessFormat", 0)); // PNG by default
+ d->folderDateFormat->setCurrentItem(config->readNumEntry("FolderDateFormat", CameraUIPriv::IsoDateFormat));
+
+ d->view->setThumbnailSize(ThumbnailSize((ThumbnailSize::Size)config->readNumEntry("ThumbnailSize",
+ ThumbnailSize::Large)));
+
+ if(config->hasKey("Splitter Sizes"))
+ d->splitter->setSizes(config->readIntListEntry("Splitter Sizes"));
+
+ d->dateTimeEdit->setEnabled(d->fixDateTimeCheck->isChecked());
+ d->losslessFormat->setEnabled(convertLosslessJpegFiles());
+ d->formatLabel->setEnabled(convertLosslessJpegFiles());
+ d->folderDateFormat->setEnabled(d->autoAlbumDateCheck->isChecked());
+ d->folderDateLabel->setEnabled(d->autoAlbumDateCheck->isChecked());
+
+ resize(configDialogSize("Camera Settings"));
+}
+
+void CameraUI::saveSettings()
+{
+ saveDialogSize("Camera Settings");
+
+ TDEConfig* config = kapp->config();
+ config->setGroup("Camera Settings");
+ config->writeEntry("Settings Tab", d->advBox->currentIndex());
+ config->writeEntry("AutoRotate", d->autoRotateCheck->isChecked());
+ config->writeEntry("AutoAlbumDate", d->autoAlbumDateCheck->isChecked());
+ config->writeEntry("AutoAlbumExt", d->autoAlbumExtCheck->isChecked());
+ config->writeEntry("FixDateTime", d->fixDateTimeCheck->isChecked());
+ config->writeEntry("SetPhotographerId", d->setPhotographerId->isChecked());
+ config->writeEntry("SetCredits", d->setCredits->isChecked());
+ config->writeEntry("ConvertJpeg", convertLosslessJpegFiles());
+ config->writeEntry("LossLessFormat", d->losslessFormat->currentItem());
+ config->writeEntry("ThumbnailSize", d->view->thumbnailSize().size());
+ config->writeEntry("Splitter Sizes", d->splitter->sizes());
+ config->writeEntry("FolderDateFormat", d->folderDateFormat->currentItem());
+ config->sync();
+}
+
+void CameraUI::slotProcessURL(const TQString& url)
+{
+ TDEApplication::kApplication()->invokeBrowser(url);
+}
+
+bool CameraUI::isBusy() const
+{
+ return d->busy;
+}
+
+bool CameraUI::isClosed() const
+{
+ return d->closed;
+}
+
+bool CameraUI::convertLosslessJpegFiles() const
+{
+ return d->convertJpegCheck->isChecked();
+}
+
+bool CameraUI::autoRotateJpegFiles() const
+{
+ return d->autoRotateCheck->isChecked();
+}
+
+TQString CameraUI::losslessFormat()
+{
+ return d->losslessFormat->currentText();
+}
+
+TQString CameraUI::cameraTitle() const
+{
+ return d->cameraTitle;
+}
+
+void CameraUI::slotCancelButton()
+{
+ d->status->setText(i18n("Cancelling current operation, please wait..."));
+ d->progress->hide();
+ TQTimer::singleShot(0, d->controller, TQ_SLOT(slotCancel()));
+ d->currentlyDeleting.clear();
+}
+
+void CameraUI::closeEvent(TQCloseEvent* e)
+{
+ if (dialogClosed())
+ e->accept();
+ else
+ e->ignore();
+}
+
+void CameraUI::slotClose()
+{
+ if (dialogClosed())
+ reject();
+}
+
+bool CameraUI::dialogClosed()
+{
+ if (d->closed)
+ return true;
+
+ if (isBusy())
+ {
+ if (KMessageBox::questionYesNo(this,
+ i18n("Do you want to close the dialog "
+ "and cancel the current operation?"))
+ == KMessageBox::No)
+ return false;
+ }
+
+ d->status->setText(i18n("Disconnecting from camera, please wait..."));
+ d->progress->hide();
+
+ if (isBusy())
+ {
+ d->controller->slotCancel();
+ // will be read in slotBusy later and finishDialog
+ // will be called only when everything is finished
+ d->closed = true;
+ }
+ else
+ {
+ d->closed = true;
+ finishDialog();
+ }
+
+ return true;
+}
+
+void CameraUI::finishDialog()
+{
+ // Look if an item have been downloaded to computer during camera gui session.
+ // If yes, update the lastAccess date property of camera in digiKam camera list.
+
+ if (d->view->itemsDownloaded() > 0)
+ {
+ CameraList* clist = CameraList::instance();
+ if (clist)
+ clist->changeCameraAccessTime(d->cameraTitle, TQDateTime::TQDateTime::currentDateTime());
+ }
+
+ // When a directory is created, a watch is put on it to spot new files
+ // but it can occur that the file is copied there before the watch is
+ // completely setup. That is why as an extra safeguard run scanlib
+ // over the folders we used. Bug: 119201
+
+ d->status->setText(i18n("Scanning for new files, please wait..."));
+ ScanLib sLib;
+ for (TQStringList::iterator it = d->foldersToScan.begin();
+ it != d->foldersToScan.end(); ++it)
+ {
+ //DDebug() << "Scanning " << (*it) << endl;
+ sLib.findMissingItems( (*it) );
+ }
+
+ // Never call finalScan after deleteLater() - ScanLib will call processEvent(),
+ // and the delete event may be executed!
+ deleteLater();
+
+ if(!d->lastDestURL.isEmpty())
+ emit signalLastDestination(d->lastDestURL);
+
+ saveSettings();
+}
+
+void CameraUI::slotBusy(bool val)
+{
+ if (!val)
+ {
+ if (!d->busy)
+ return;
+
+ d->busy = false;
+ d->cancelBtn->setEnabled(false);
+ d->view->viewport()->setEnabled(true);
+
+ d->advBox->setEnabled(true);
+ // B.K.O #127614: The Focus need to be restored in custom prefix widget.
+ //commenting this out again: If we do not disable, no need to restore focus
+ //d->renameCustomizer->restoreFocus();
+
+ enableButton(User3, true);
+ enableButton(User2, true);
+ enableButton(User1, true);
+ d->helpMenu->menu()->setItemEnabled(CAMERA_INFO_MENU_ID, true);
+
+ d->anim->stop();
+ d->status->setText(i18n("Ready"));
+ d->progress->hide();
+
+ // like WDestructiveClose, but after camera controller operation has safely finished
+ if (d->closed)
+ {
+ finishDialog();
+ }
+ }
+ else
+ {
+ if (d->busy)
+ return;
+
+ if (!d->anim->running())
+ d->anim->start();
+
+ d->busy = true;
+ d->cancelBtn->setEnabled(true);
+
+ // Has camera icon view item selection is used to control download post processing,
+ // all selection actions are disable when camera interface is busy.
+ d->view->viewport()->setEnabled(false);
+
+ // Settings tab is disabled in slotDownload, selectively when downloading
+ // Fast dis/enabling would create the impression of flicker, e.g. when retrieving EXIF from camera
+ //d->advBox->setEnabled(false);
+
+ enableButton(User3, false);
+ enableButton(User2, false);
+ enableButton(User1, false);
+ d->helpMenu->menu()->setItemEnabled(CAMERA_INFO_MENU_ID, false);
+ }
+}
+
+void CameraUI::slotIncreaseThumbSize()
+{
+ int thumbSize = d->view->thumbnailSize().size();
+ if (thumbSize >= ThumbnailSize::Huge) return;
+
+ thumbSize += ThumbnailSize::Step;
+
+ if (thumbSize >= ThumbnailSize::Huge)
+ {
+ d->imageMenu->setItemEnabled(4, false);
+ }
+ d->imageMenu->setItemEnabled(5, true);
+
+ d->view->setThumbnailSize(thumbSize);
+}
+
+void CameraUI::slotDecreaseThumbSize()
+{
+ int thumbSize = d->view->thumbnailSize().size();
+ if (thumbSize <= ThumbnailSize::Small) return;
+
+ thumbSize -= ThumbnailSize::Step;
+
+ if (thumbSize <= ThumbnailSize::Small)
+ {
+ d->imageMenu->setItemEnabled(5, false);
+ }
+ d->imageMenu->setItemEnabled(4, true);
+
+ d->view->setThumbnailSize(thumbSize);
+}
+
+void CameraUI::slotConnected(bool val)
+{
+ if (!val)
+ {
+ if (KMessageBox::warningYesNo(this,
+ i18n("Failed to connect to the camera. "
+ "Please make sure it is connected "
+ "properly and turned on. "
+ "Would you like to try again?"),
+ i18n("Connection Failed"),
+ i18n("Retry"),
+ i18n("Abort"))
+ == KMessageBox::Yes)
+ TQTimer::singleShot(0, d->controller, TQ_SLOT(slotConnect()));
+ else
+ close();
+ }
+ else
+ {
+ d->controller->listFolders();
+ }
+}
+
+void CameraUI::slotFolderList(const TQStringList& folderList)
+{
+ if (d->closed)
+ return;
+
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(0);
+ d->progress->show();
+
+ d->cameraFolderList = folderList;
+ for (TQStringList::const_iterator it = folderList.begin();
+ it != folderList.end(); ++it)
+ {
+ d->controller->listFiles(*it);
+ }
+}
+
+void CameraUI::slotFileList(const GPItemInfoList& fileList)
+{
+ if (d->closed)
+ return;
+
+ if (fileList.empty())
+ return;
+
+ kdDebug() << fileList.count() << endl;
+
+ // We sort the map by time stamp
+ // and we remove internal camera files which are not image/video/sounds.
+ TQStringList fileNames, fileExts;
+ TQFileInfo info;
+
+ // JVC camera (see B.K.O #133185).
+ fileNames.append("mgr_data");
+ fileNames.append("pgr_mgr");
+
+ // HP Photosmart camera (see B.K.O #156338).
+ fileExts.append("dsp");
+
+ // Minolta camera in PTP mode
+ fileExts.append("dps");
+
+ // We sort the map by time stamp.
+ GPItemInfoList sfileList;
+ GPItemInfoList::const_iterator it;
+ GPItemInfoList::iterator it2;
+
+ for(it = fileList.begin() ; it != fileList.end() ; ++it)
+ {
+ info.setFile((*it).name);
+ if (!fileNames.contains(info.fileName().lower()) &&
+ !fileExts.contains(info.extension(false).lower()))
+ {
+ kdDebug() << info.fileName() << " : " << (*it).mtime << endl;
+
+ for(it2 = sfileList.begin() ; it2 != sfileList.end() ; ++it2)
+ if ((*it2).mtime <= (*it).mtime) break;
+
+ sfileList.insert(it2, *it);
+ }
+ }
+
+ if (sfileList.empty())
+ return;
+
+ kdDebug() << sfileList.count() << endl;
+
+ GPItemInfoList::const_iterator it3 = sfileList.begin();
+
+ do
+ {
+ GPItemInfo item = *it3;
+
+ if (item.mtime > (time_t)d->lastAccess.toTime_t() && item.downloaded == GPItemInfo::DownloadUnknow)
+ item.downloaded = GPItemInfo::NewPicture;
+
+ d->view->addItem(item);
+ d->controller->getThumbnail(item.folder, item.name);
+ ++it3;
+ }
+ while(it3 != sfileList.end());
+
+ d->progress->setTotalSteps(d->progress->totalSteps() + fileList.count());
+}
+
+void CameraUI::slotThumbnail(const TQString& folder, const TQString& file,
+ const TQImage& thumbnail)
+{
+ d->view->setThumbnail(folder, file, thumbnail);
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::slotInformations()
+{
+ if (d->busy)
+ return;
+
+ d->controller->getCameraInformations();
+}
+
+void CameraUI::slotCameraInformations(const TQString& summary, const TQString& manual, const TQString& about)
+{
+ CameraInfoDialog *infoDlg = new CameraInfoDialog(this, summary, manual, about);
+ infoDlg->show();
+}
+
+void CameraUI::slotErrorMsg(const TQString& msg)
+{
+ KMessageBox::error(this, msg);
+}
+
+void CameraUI::slotUpload()
+{
+ if (d->busy)
+ return;
+
+ TQString fileformats;
+
+ TQStringList patternList = TQStringList::split('\n', KImageIO::pattern(KImageIO::Reading));
+
+ // All Images from list must been always the first entry given by KDE API
+ TQString allPictures = patternList[0];
+
+ // Add RAW file format to All Images" type mime and remplace current.
+#if KDCRAW_VERSION < 0x000106
+ allPictures.insert(allPictures.find("|"), TQString(KDcrawIface::DcrawBinary::instance()->rawFiles()));
+#else
+ allPictures.insert(allPictures.find("|"), TQString(KDcrawIface::KDcraw::rawFiles()));
+#endif
+ patternList.remove(patternList[0]);
+ patternList.prepend(allPictures);
+
+ // Added RAW file formats supported by dcraw program like a type mime.
+ // Nota: we cannot use here "image/x-raw" type mime from KDE because it uncomplete
+ // or unavailable(dcraw_0)(see file #121242 in B.K.O).
+#if KDCRAW_VERSION < 0x000106
+ patternList.append(TQString("\n%1|Camera RAW files").arg(TQString(KDcrawIface::DcrawBinary::instance()->rawFiles())));
+#else
+ patternList.append(TQString("\n%1|Camera RAW files").arg(TQString(KDcrawIface::KDcraw::rawFiles())));
+#endif
+
+ fileformats = patternList.join("\n");
+
+ DDebug () << "fileformats=" << fileformats << endl;
+
+ KURL::List urls = KFileDialog::getOpenURLs(AlbumManager::instance()->getLibraryPath(),
+ fileformats, this, i18n("Select Image to Upload"));
+ if (!urls.isEmpty())
+ slotUploadItems(urls);
+}
+
+void CameraUI::slotUploadItems(const KURL::List& urls)
+{
+ if (d->busy)
+ return;
+
+ if (urls.isEmpty())
+ return;
+
+ CameraFolderDialog dlg(this, d->view, d->cameraFolderList, d->controller->getCameraTitle(),
+ d->controller->getCameraPath());
+
+ if (dlg.exec() != TQDialog::Accepted)
+ return;
+
+ TQString cameraFolder = dlg.selectedFolderPath();
+
+ for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it)
+ {
+ TQFileInfo fi((*it).path());
+ if (!fi.exists()) continue;
+ if (fi.isDir()) continue;
+
+ TQString ext = TQString(".") + fi.extension();
+ TQString name = fi.fileName();
+ name.truncate(fi.fileName().length() - ext.length());
+
+ bool ok;
+
+ while (d->view->findItem(cameraFolder, name + ext))
+ {
+ TQString msg(i18n("Camera Folder <b>%1</b> already contains item <b>%2</b><br>"
+ "Please enter a new file name (without extension):")
+ .arg(cameraFolder).arg(fi.fileName()));
+#if KDE_IS_VERSION(3,2,0)
+ name = KInputDialog::getText(i18n("File already exists"), msg, name, &ok, this);
+
+#else
+ name = KLineEditDlg::getText(i18n("File already exists"), msg, name, &ok, this);
+#endif
+ if (!ok)
+ return;
+ }
+
+ d->controller->upload(fi, name + ext, cameraFolder);
+ }
+}
+
+void CameraUI::slotUploaded(const GPItemInfo& itemInfo)
+{
+ if (d->closed)
+ return;
+
+ d->view->addItem(itemInfo);
+ d->controller->getThumbnail(itemInfo.folder, itemInfo.name);
+}
+
+void CameraUI::slotDownloadSelected()
+{
+ slotDownload(true, false);
+}
+
+void CameraUI::slotDownloadAndDeleteSelected()
+{
+ slotDownload(true, true);
+}
+
+void CameraUI::slotDownloadAll()
+{
+ slotDownload(false, false);
+}
+
+void CameraUI::slotDownloadAndDeleteAll()
+{
+ slotDownload(false, true);
+}
+
+void CameraUI::slotDownload(bool onlySelected, bool deleteAfter, Album *album)
+{
+ // See B.K.O #143934: force to select all items to prevent problem
+ // when !renameCustomizer->useDefault() ==> iconItem->getDownloadName()
+ // can return an empty string in this case because it depends on selection.
+ if (!onlySelected)
+ d->view->slotSelectAll();
+
+ // See B.K.O #139519: Always check free space available before to
+ // download items selection from camera.
+ unsigned long fSize = 0;
+ unsigned long dSize = 0;
+ d->view->itemsSelectionSizeInfo(fSize, dSize);
+ if (d->freeSpaceWidget->isValid() && (dSize >= d->freeSpaceWidget->kBAvail()))
+ {
+ KMessageBox::error(this, i18n("There is no enough free space on Album Library Path "
+ "to download and process selected pictures from camera.\n\n"
+ "Estimated space require: %1\n"
+ "Available free space: %2")
+ .arg(TDEIO::convertSizeFromKB(dSize))
+ .arg(TDEIO::convertSizeFromKB(d->freeSpaceWidget->kBAvail())));
+ return;
+ }
+
+ TQString newDirName;
+ IconItem* firstItem = d->view->firstItem();
+ if (firstItem)
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(firstItem);
+
+ TQDateTime dateTime;
+ dateTime.setTime_t(iconItem->itemInfo()->mtime);
+
+ switch(d->folderDateFormat->currentItem())
+ {
+ case CameraUIPriv::TextDateFormat:
+ newDirName = dateTime.date().toString(TQt::TextDate);
+ break;
+ case CameraUIPriv::LocalDateFormat:
+ newDirName = dateTime.date().toString(TQt::LocalDate);
+ break;
+ default: // IsoDateFormat
+ newDirName = dateTime.date().toString(TQt::ISODate);
+ break;
+ }
+ }
+
+ // -- Get the destination album from digiKam library if necessary ---------------
+
+ if (!album)
+ {
+ AlbumManager* man = AlbumManager::instance();
+ album = man->currentAlbum();
+
+ if (album && album->type() != Album::PHYSICAL)
+ album = 0;
+
+ TQString header(i18n("<p>Please select the destination album from the digiKam library to "
+ "import the camera pictures into.</p>"));
+
+ album = AlbumSelectDialog::selectAlbum(this, (PAlbum*)album, header, newDirName,
+ d->autoAlbumDateCheck->isChecked());
+
+ if (!album) return;
+ }
+
+ PAlbum *pAlbum = dynamic_cast<PAlbum*>(album);
+ if (!pAlbum) return;
+
+ // -- Prepare downloading of camera items ------------------------
+
+ KURL url;
+ url.setPath(pAlbum->folderPath());
+
+ d->controller->downloadPrep();
+
+ DownloadSettingsContainer downloadSettings;
+ TQString downloadName;
+ time_t mtime;
+ int total = 0;
+
+ downloadSettings.autoRotate = d->autoRotateCheck->isChecked();
+ downloadSettings.fixDateTime = d->fixDateTimeCheck->isChecked();
+ downloadSettings.newDateTime = d->dateTimeEdit->dateTime();
+ downloadSettings.setPhotographerId = d->setPhotographerId->isChecked();
+ downloadSettings.setCredits = d->setCredits->isChecked();
+ downloadSettings.convertJpeg = convertLosslessJpegFiles();
+ downloadSettings.losslessFormat = losslessFormat();
+
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (settings)
+ {
+ downloadSettings.author = settings->getIptcAuthor();
+ downloadSettings.authorTitle = settings->getIptcAuthorTitle();
+ downloadSettings.credit = settings->getIptcCredit();
+ downloadSettings.source = settings->getIptcSource();
+ downloadSettings.copyright = settings->getIptcCopyright();
+ }
+
+ // -- Download camera items -------------------------------
+ // Since we show camera items in reverse order, downloading need to be done also in reverse order.
+
+ for (IconItem* item = d->view->lastItem(); item;
+ item = item->prevItem())
+ {
+ if (onlySelected && !(item->isSelected()))
+ continue;
+
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ downloadSettings.folder = iconItem->itemInfo()->folder;
+ downloadSettings.file = iconItem->itemInfo()->name;
+ downloadName = iconItem->getDownloadName();
+ mtime = iconItem->itemInfo()->mtime;
+
+ KURL u(url);
+ TQString errMsg;
+ TQDateTime dateTime;
+ dateTime.setTime_t(mtime);
+
+ // Auto sub-albums creation based on file date.
+
+ if (d->autoAlbumDateCheck->isChecked())
+ {
+ TQString dirName;
+
+ switch(d->folderDateFormat->currentItem())
+ {
+ case CameraUIPriv::TextDateFormat:
+ dirName = dateTime.date().toString(TQt::TextDate);
+ break;
+ case CameraUIPriv::LocalDateFormat:
+ dirName = dateTime.date().toString(TQt::LocalDate);
+ break;
+ default: // IsoDateFormat
+ dirName = dateTime.date().toString(TQt::ISODate);
+ break;
+ }
+ // See B.K.O #136927 : we need to support file system which do not
+ // handle upper case properly.
+ dirName = dirName.lower();
+ if (!createAutoAlbum(url, dirName, dateTime.date(), errMsg))
+ {
+ KMessageBox::error(this, errMsg);
+ return;
+ }
+
+ u.addPath(dirName);
+ }
+
+ // Auto sub-albums creation based on file extensions.
+
+ if (d->autoAlbumExtCheck->isChecked())
+ {
+ // We use the target file name to compute sub-albums name to take a care about
+ // convertion on the fly option.
+ TQFileInfo fi(downloadName);
+
+ TQString subAlbum = fi.extension(false).upper();
+ if (fi.extension(false).upper() == TQString("JPEG") ||
+ fi.extension(false).upper() == TQString("JPE"))
+ subAlbum = TQString("JPG");
+ if (fi.extension(false).upper() == TQString("TIFF"))
+ subAlbum = TQString("TIF");
+ if (fi.extension(false).upper() == TQString("MPEG") ||
+ fi.extension(false).upper() == TQString("MPE") ||
+ fi.extension(false).upper() == TQString("MPO"))
+ subAlbum = TQString("MPG");
+
+ // See B.K.O #136927 : we need to support file system which do not
+ // handle upper case properly.
+ subAlbum = subAlbum.lower();
+ if (!createAutoAlbum(u, subAlbum, dateTime.date(), errMsg))
+ {
+ KMessageBox::error(this, errMsg);
+ return;
+ }
+
+ u.addPath(subAlbum);
+ }
+
+ d->foldersToScan.append(u.path());
+ u.addPath(downloadName.isEmpty() ? downloadSettings.file : downloadName);
+
+ downloadSettings.dest = u.path();
+
+ d->controller->download(downloadSettings);
+ addFileExtension(TQFileInfo(u.path()).extension(false));
+ total++;
+ }
+
+ if (total <= 0)
+ return;
+
+ d->lastDestURL = url;
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(total);
+ d->progress->show();
+
+ // disable settings tab here instead of slotBusy:
+ // Only needs to be disabled while downloading
+ d->advBox->setEnabled(false);
+
+ d->deleteAfter = deleteAfter;
+}
+
+void CameraUI::slotDownloaded(const TQString& folder, const TQString& file, int status)
+{
+ CameraIconViewItem* iconItem = d->view->findItem(folder, file);
+ if (iconItem)
+ iconItem->setDownloaded(status);
+
+ if (status == GPItemInfo::DownloadedYes || status == GPItemInfo::DownloadFailed)
+ {
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+ }
+
+ // Download all items is complete.
+ if (d->progress->progress() == d->progress->totalSteps())
+ {
+ if (d->deleteAfter)
+ deleteItems(true, true);
+ }
+}
+
+void CameraUI::slotSkipped(const TQString& folder, const TQString& file)
+{
+ CameraIconViewItem* iconItem = d->view->findItem(folder, file);
+ if (iconItem)
+ iconItem->setDownloaded(GPItemInfo::DownloadedNo);
+
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::slotToggleLock()
+{
+ int count = 0;
+ for (IconItem* item = d->view->firstItem(); item;
+ item = item->nextItem())
+ {
+ CameraIconViewItem* iconItem = static_cast<CameraIconViewItem*>(item);
+ if (iconItem->isSelected())
+ {
+ TQString folder = iconItem->itemInfo()->folder;
+ TQString file = iconItem->itemInfo()->name;
+ int writePerm = iconItem->itemInfo()->writePermissions;
+ bool lock = true;
+
+ // If item is currently locked, unlock it.
+ if (writePerm == 0)
+ lock = false;
+
+ d->controller->lockFile(folder, file, lock);
+ count++;
+ }
+ }
+
+ if (count > 0)
+ {
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(count);
+ d->progress->show();
+ }
+}
+
+void CameraUI::slotLocked(const TQString& folder, const TQString& file, bool status)
+{
+ if (status)
+ {
+ CameraIconViewItem* iconItem = d->view->findItem(folder, file);
+ if (iconItem)
+ {
+ iconItem->toggleLock();
+ //if (iconItem->isSelected())
+ // slotItemsSelected(iconItem, true);
+ }
+ }
+
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::checkItem4Deletion(CameraIconViewItem* iconItem, TQStringList& folders, TQStringList& files,
+ TQStringList& deleteList, TQStringList& lockedList)
+{
+ if (iconItem->itemInfo()->writePermissions != 0) // Item not locked ?
+ {
+ TQString folder = iconItem->itemInfo()->folder;
+ TQString file = iconItem->itemInfo()->name;
+ folders.append(folder);
+ files.append(file);
+ deleteList.append(folder + TQString("/") + file);
+ }
+ else
+ {
+ lockedList.append(iconItem->itemInfo()->name);
+ }
+}
+
+void CameraUI::deleteItems(bool onlySelected, bool onlyDownloaded)
+{
+ TQStringList folders;
+ TQStringList files;
+ TQStringList deleteList;
+ TQStringList lockedList;
+
+ for (IconItem* item = d->view->firstItem(); item; item = item->nextItem())
+ {
+ CameraIconViewItem* iconItem = dynamic_cast<CameraIconViewItem*>(item);
+ if (iconItem)
+ {
+ if (onlySelected)
+ {
+ if (iconItem->isSelected())
+ {
+ if (onlyDownloaded)
+ {
+ if (iconItem->isDownloaded())
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ else
+ {
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ }
+ }
+ else // All items
+ {
+ if (onlyDownloaded)
+ {
+ if (iconItem->isDownloaded())
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ else
+ {
+ checkItem4Deletion(iconItem, folders, files, deleteList, lockedList);
+ }
+ }
+ }
+ }
+
+ // If we want to delete some locked files, just give a feedback to user.
+ if (!lockedList.isEmpty())
+ {
+ TQString infoMsg(i18n("The items listed below are locked by camera (read-only). "
+ "These items will not be deleted. If you really want to delete these items, "
+ "please unlock them and try again."));
+ KMessageBox::informationList(this, infoMsg, lockedList, i18n("Information"));
+ }
+
+ if (folders.isEmpty())
+ return;
+
+ TQString warnMsg(i18n("About to delete this image. "
+ "Deleted files are unrecoverable. "
+ "Are you sure?",
+ "About to delete these %n images. "
+ "Deleted files are unrecoverable. "
+ "Are you sure?",
+ deleteList.count()));
+ if (KMessageBox::warningContinueCancelList(this, warnMsg,
+ deleteList,
+ i18n("Warning"),
+ i18n("Delete"))
+ == KMessageBox::Continue)
+ {
+ TQStringList::iterator itFolder = folders.begin();
+ TQStringList::iterator itFile = files.begin();
+
+ d->progress->setProgress(0);
+ d->progress->setTotalSteps(deleteList.count());
+ d->progress->show();
+
+ for ( ; itFolder != folders.end(); ++itFolder, ++itFile)
+ {
+ d->controller->deleteFile(*itFolder, *itFile);
+ // the currentlyDeleting list is used to prevent loading items which
+ // will immenently be deleted into the sidebar and wasting time
+ d->currentlyDeleting.append(*itFolder + *itFile);
+ }
+ }
+}
+
+void CameraUI::slotDeleteSelected()
+{
+ deleteItems(true, false);
+}
+
+void CameraUI::slotDeleteAll()
+{
+ deleteItems(false, false);
+}
+
+void CameraUI::slotDeleted(const TQString& folder, const TQString& file, bool status)
+{
+ if (status)
+ {
+ d->view->removeItem(folder, file);
+ // do this after removeItem, which will signal to slotItemsSelected, which checks for the list
+ d->currentlyDeleting.remove(folder + file);
+ }
+
+ int curr = d->progress->progress();
+ d->progress->setProgress(curr+1);
+}
+
+void CameraUI::slotFileView(CameraIconViewItem* item)
+{
+ d->controller->openFile(item->itemInfo()->folder, item->itemInfo()->name);
+}
+
+void CameraUI::slotExifFromFile(const TQString& folder, const TQString& file)
+{
+ CameraIconViewItem* item = d->view->findItem(folder, file);
+ if (!item)
+ return;
+
+ d->rightSidebar->itemChanged(item->itemInfo(), folder + TQString("/") + file,
+ TQByteArray(), d->view, item);
+}
+
+void CameraUI::slotExifFromData(const TQByteArray& exifData)
+{
+ CameraIconViewItem* item = dynamic_cast<CameraIconViewItem*>(d->view->currentItem());
+
+ if (!item)
+ return;
+
+ KURL url(item->itemInfo()->folder + '/' + item->itemInfo()->name);
+
+ // Sometimes, GPhoto2 drivers return complete APP1 JFIF section. Exiv2 cannot
+ // decode (yet) exif metadata from APP1. We will find Exif header to get data at this place
+ // to please with Exiv2...
+
+ DDebug() << "Size of Exif metadata from camera = " << exifData.size() << endl;
+ char exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
+
+ if (!exifData.isEmpty())
+ {
+ int i = exifData.find(*exifHeader);
+ if (i != -1)
+ {
+ DDebug() << "Exif header found at position " << i << endl;
+ i = i + sizeof(exifHeader);
+ TQByteArray data(exifData.size()-i);
+ memcpy(data.data(), exifData.data()+i, data.size());
+ d->rightSidebar->itemChanged(item->itemInfo(), url, data, d->view, item);
+ return;
+ }
+ }
+
+ d->rightSidebar->itemChanged(item->itemInfo(), url, exifData, d->view, item);
+}
+
+void CameraUI::slotNewSelection(bool hasSelection)
+{
+ if (!d->renameCustomizer->useDefault())
+ {
+ d->downloadMenu->setItemEnabled(0, hasSelection);
+ d->downloadMenu->setItemEnabled(2, hasSelection);
+ }
+ else
+ {
+ d->downloadMenu->setItemEnabled(0, hasSelection);
+ d->downloadMenu->setItemEnabled(2, hasSelection);
+ }
+
+ unsigned long fSize = 0;
+ unsigned long dSize = 0;
+ d->view->itemsSelectionSizeInfo(fSize, dSize);
+ d->freeSpaceWidget->setEstimatedDSizeKb(dSize);
+}
+
+void CameraUI::slotItemsSelected(CameraIconViewItem* item, bool selected)
+{
+ d->downloadMenu->setItemEnabled(0, selected);
+ d->downloadMenu->setItemEnabled(2, selected);
+ d->deleteMenu->setItemEnabled(0, selected);
+
+ if (selected)
+ {
+ // if selected item is in the list of item which will be deleted, set no current item
+ if (d->currentlyDeleting.find(item->itemInfo()->folder + item->itemInfo()->name)
+ == d->currentlyDeleting.end())
+ {
+ KURL url(item->itemInfo()->folder + '/' + item->itemInfo()->name);
+ d->rightSidebar->itemChanged(item->itemInfo(), url, TQByteArray(), d->view, item);
+ d->controller->getExif(item->itemInfo()->folder, item->itemInfo()->name);
+ }
+ else
+ {
+ d->rightSidebar->slotNoCurrentItem();
+ }
+ }
+ else
+ d->rightSidebar->slotNoCurrentItem();
+}
+
+bool CameraUI::createAutoAlbum(const KURL& parentURL, const TQString& sub,
+ const TQDate& date, TQString& errMsg)
+{
+ KURL u(parentURL);
+ u.addPath(sub);
+
+ // first stat to see if the album exists
+ TQFileInfo info(u.path());
+ if (info.exists())
+ {
+ // now check if its really a directory
+ if (info.isDir())
+ return true;
+ else
+ {
+ errMsg = i18n("A file with same name (%1) exists in folder %2")
+ .arg(sub)
+ .arg(parentURL.path());
+ return false;
+ }
+ }
+
+ // looks like the directory does not exist, try to create it
+
+ AlbumManager* aman = AlbumManager::instance();
+ PAlbum* parent = aman->findPAlbum(parentURL);
+ if (!parent)
+ {
+ errMsg = i18n("Failed to find Album for path '%1'")
+ .arg(parentURL.path());
+ return false;
+ }
+
+ return aman->createPAlbum(parent, sub, TQString(""), date, TQString(""), errMsg);
+}
+
+void CameraUI::addFileExtension(const TQString& ext)
+{
+ AlbumSettings* settings = AlbumSettings::instance();
+ if (!settings)
+ return;
+
+ if (settings->getImageFileFilter().upper().contains(ext.upper()) ||
+ settings->getMovieFileFilter().upper().contains(ext.upper()) ||
+ settings->getAudioFileFilter().upper().contains(ext.upper()) ||
+ settings->getRawFileFilter().upper().contains(ext.upper()))
+ return;
+
+ settings->setImageFileFilter(settings->getImageFileFilter() + TQString(" *.") + ext);
+ emit signalAlbumSettingsChanged();
+}
+
+void CameraUI::slotFirstItem()
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->firstItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem);
+}
+
+void CameraUI::slotPrevItem()
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->currentItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem->prevItem());
+}
+
+void CameraUI::slotNextItem()
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->currentItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem->nextItem());
+}
+
+void CameraUI::slotLastItem(void)
+{
+ CameraIconViewItem *currItem = dynamic_cast<CameraIconViewItem*>(d->view->lastItem());
+ d->view->clearSelection();
+ d->view->updateContents();
+ if (currItem)
+ d->view->setCurrentItem(currItem);
+}
+
+// Backport KDialog::keyPressEvent() implementation from KDELibs to ignore Enter/Return Key events
+// to prevent any conflicts between dialog keys events and SpinBox keys events.
+
+void CameraUI::keyPressEvent(TQKeyEvent *e)
+{
+ if ( e->state() == 0 )
+ {
+ switch ( e->key() )
+ {
+ case Key_Escape:
+ e->accept();
+ reject();
+ break;
+ case Key_Enter:
+ case Key_Return:
+ e->ignore();
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ }
+ else
+ {
+ // accept the dialog when Ctrl-Return is pressed
+ if ( e->state() == ControlButton &&
+ (e->key() == Key_Return || e->key() == Key_Enter) )
+ {
+ e->accept();
+ accept();
+ }
+ else
+ {
+ e->ignore();
+ }
+ }
+}
+
+} // namespace Digikam