diff options
Diffstat (limited to 'src/utilities/cameragui/cameraui.cpp')
-rw-r--r-- | src/utilities/cameragui/cameraui.cpp | 1734 |
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 |