/* ============================================================
 *
 * 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 <tdestandarddirs.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, tdeApp->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 = tdeApp->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 = tdeApp->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)
{
    tdeApp->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
