File indexing completed on 2025-01-19 03:59:23

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2004-09-16
0007  * Description : Import tool interface
0008  *
0009  * SPDX-FileCopyrightText: 2004-2005 by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2006-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0012  * SPDX-FileCopyrightText: 2012      by Andi Clemens <andi dot clemens at gmail dot com>
0013  * SPDX-FileCopyrightText: 2012      by Islam Wazery <wazery at ubuntu dot com>
0014  *
0015  * SPDX-License-Identifier: GPL-2.0-or-later
0016  *
0017  * ============================================================ */
0018 
0019 #include "importui_p.h"
0020 
0021 namespace Digikam
0022 {
0023 
0024 ImportUI* ImportUI::m_instance = nullptr;
0025 
0026 ImportUI::ImportUI(const QString& cameraTitle, const QString& model,
0027                    const QString& port, const QString& path, int startIndex)
0028     : DXmlGuiWindow(nullptr),
0029       d            (new Private)
0030 {
0031     setConfigGroupName(QLatin1String("Camera Settings"));
0032 
0033     setXMLFile(QLatin1String("importui5.rc"));
0034     setFullScreenOptions(FS_IMPORTUI);
0035     setWindowFlags(Qt::Window);
0036 
0037     m_instance = this;
0038 
0039     // --------------------------------------------------------
0040 
0041     QString title  = CameraNameHelper::cameraName(cameraTitle);
0042     d->cameraTitle = (title.isEmpty()) ? cameraTitle : title;
0043     setCaption(d->cameraTitle);
0044 
0045     setupCameraController(model, port, path);
0046     setupUserArea();
0047     setInitialSorting();
0048     setupActions();
0049     setupStatusBar();
0050     setupAccelerators();
0051 
0052     // -- Make signals/slots connections ---------------------------------
0053 
0054     setupConnections();
0055     sidebarTabTitleStyleChanged();
0056     slotColorManagementOptionsChanged();
0057 
0058     // -- Read settings --------------------------------------------------
0059 
0060     readSettings();
0061     setAutoSaveSettings(configGroupName(), true);
0062 
0063     // -------------------------------------------------------------------
0064 
0065     //d->historyUpdater = new CameraHistoryUpdater(this);
0066 
0067     //connect (d->historyUpdater, SIGNAL(signalHistoryMap(CHUpdateItemMap)),
0068     //this, SLOT(slotRefreshIconView(CHUpdateItemMap)));
0069 
0070     //connect(d->historyUpdater, SIGNAL(signalBusy(bool)),
0071     //        this, SLOT(slotBusy(bool)));
0072 
0073     // --------------------------------------------------------
0074 
0075     d->progressTimer = new QTimer(this);
0076 
0077     connect(d->progressTimer, SIGNAL(timeout()),
0078             this, SLOT(slotProgressTimerDone()));
0079 
0080     // --------------------------------------------------------
0081 
0082     d->renameCustomizer->setStartIndex(startIndex);
0083     d->view->setFocus();
0084 
0085     // -- Init icon view zoom factor --------------------------
0086 
0087     slotThumbSizeChanged(ImportSettings::instance()->getDefaultIconSize());
0088     slotZoomSliderChanged(ImportSettings::instance()->getDefaultIconSize());
0089 
0090     // try to connect in the end, this allows us not to block the UI to show up..
0091     QTimer::singleShot(0, d->controller, SLOT(slotConnect()));
0092 }
0093 
0094 ImportUI::~ImportUI()
0095 {
0096     saveSettings();
0097     disconnect(d->view, nullptr, this, nullptr);
0098 
0099     delete d->view;
0100     delete d->rightSideBar;
0101     delete d->controller;
0102 
0103     m_instance = nullptr;
0104 
0105     delete d;
0106 }
0107 
0108 ImportUI* ImportUI::instance()
0109 {
0110     return m_instance;
0111 }
0112 
0113 void ImportUI::setupUserArea()
0114 {
0115     DHBox* const widget = new DHBox(this);
0116     d->splitter         = new SidebarSplitter(widget);
0117     DVBox* const vbox   = new DVBox(d->splitter);
0118     d->view             = new ImportView(this, vbox);
0119     d->view->importFilterModel()->setCameraThumbsController(d->camThumbsCtrl);
0120     d->view->importFilterModel()->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural());
0121     d->historyView      = new DHistoryView(vbox);
0122     d->rightSideBar     = new ImportItemPropertiesSideBarImport(widget, d->splitter, Qt::RightEdge, true);
0123     d->rightSideBar->setObjectName(QLatin1String("CameraGui Sidebar Right"));
0124     d->splitter->setFrameStyle(QFrame::NoFrame);
0125     d->splitter->setFrameShadow(QFrame::Plain);
0126     d->splitter->setFrameShape(QFrame::NoFrame);
0127     d->splitter->setOpaqueResize(false);
0128     d->splitter->setStretchFactor(d->splitter->indexOf(vbox), 10);      // set iconview default size to max.
0129 
0130     vbox->setStretchFactor(d->view, 10);
0131     vbox->setStretchFactor(d->historyView, 2);
0132     vbox->setContentsMargins(QMargins());
0133     vbox->setSpacing(0);
0134 
0135     d->errorWidget = new DNotificationWidget(vbox);
0136     d->errorWidget->setMessageType(DNotificationWidget::Error);
0137     d->errorWidget->setCloseButtonVisible(false);
0138     d->errorWidget->hide();
0139 
0140     // -------------------------------------------------------------------------
0141 
0142     d->advBox = new DExpanderBox(d->rightSideBar);
0143     d->advBox->setObjectName(QLatin1String("Camera Settings Expander"));
0144 
0145     d->renameCustomizer = new RenameCustomizer(d->advBox, d->cameraTitle);
0146     d->renameCustomizer->setWhatsThis(i18nc("@info", "Set how digiKam will rename files as they are downloaded."));
0147     d->advBox->addItem(d->renameCustomizer, QIcon::fromTheme(QLatin1String("insert-image")), i18nc("@item", "File Renaming Options"),
0148                        QLatin1String("RenameCustomizer"), true);
0149 
0150     // -- Albums Auto-creation options -----------------------------------------
0151 
0152     d->albumCustomizer = new AlbumCustomizer(d->advBox);
0153     d->advBox->addItem(d->albumCustomizer, QIcon::fromTheme(QLatin1String("folder-new")), i18nc("@item", "Auto-creation of Albums"),
0154                        QLatin1String("AlbumBox"), false);
0155 
0156     // -- On the Fly options ---------------------------------------------------
0157 
0158     d->advancedSettings = new AdvancedSettings(d->advBox);
0159     d->advBox->addItem(d->advancedSettings, QIcon::fromTheme(QLatin1String("system-run")), i18nc("@item", "On the Fly Operations (JPEG only)"),
0160                        QLatin1String("OnFlyBox"), true);
0161 
0162     // -- DNG convert options --------------------------------------------------
0163 
0164     d->dngConvertSettings = new DNGConvertSettings(d->advBox);
0165     d->advBox->addItem(d->dngConvertSettings, QIcon::fromTheme(QLatin1String("image-x-adobe-dng")), i18nc("@item", "DNG Convert Options"),
0166                        QLatin1String("DNGSettings"), false);
0167 
0168     // -- Scripting options ----------------------------------------------------
0169 
0170     d->scriptingSettings = new ScriptingSettings(d->advBox);
0171     d->advBox->addItem(d->scriptingSettings, QIcon::fromTheme(QLatin1String("utilities-terminal")), i18nc("@item", "Scripting"),
0172                        QLatin1String("ScriptingBox"), false);
0173     d->advBox->addStretch();
0174 
0175     d->rightSideBar->appendTab(d->advBox, QIcon::fromTheme(QLatin1String("configure")), i18nc("@title", "Settings"));
0176     d->rightSideBar->loadState();
0177 
0178     // -------------------------------------------------------------------------
0179 
0180     setCentralWidget(widget);
0181 }
0182 
0183 void ImportUI::setupActions()
0184 {
0185     d->cameraActions            = new QActionGroup(this);
0186     KActionCollection* const ac = actionCollection();
0187 
0188     // -- File menu ----------------------------------------------------
0189 
0190     d->cameraCancelAction = new QAction(QIcon::fromTheme(QLatin1String("process-stop")), i18nc("@action Cancel process", "Cancel"), this);
0191     connect(d->cameraCancelAction, SIGNAL(triggered()), this, SLOT(slotCancelButton()));
0192     ac->addAction(QLatin1String("importui_cancelprocess"), d->cameraCancelAction);
0193     d->cameraCancelAction->setEnabled(false);
0194 
0195     // -----------------------------------------------------------------
0196 
0197     d->cameraInfoAction = new QAction(QIcon::fromTheme(QLatin1String("camera-photo")), i18nc("@action Information about camera", "Information"), this);
0198     connect(d->cameraInfoAction, SIGNAL(triggered()), this, SLOT(slotInformation()));
0199     ac->addAction(QLatin1String("importui_info"), d->cameraInfoAction);
0200     d->cameraActions->addAction(d->cameraInfoAction);
0201 
0202     // -----------------------------------------------------------------
0203 
0204     d->cameraCaptureAction = new QAction(QIcon::fromTheme(QLatin1String("webcamreceive")), i18nc("@action Capture photo from camera", "Capture"), this);
0205     connect(d->cameraCaptureAction, SIGNAL(triggered()), this, SLOT(slotCapture()));
0206     ac->addAction(QLatin1String("importui_capture"), d->cameraCaptureAction);
0207     d->cameraActions->addAction(d->cameraCaptureAction);
0208 
0209     // -----------------------------------------------------------------
0210 
0211     QAction* const closeAction = buildStdAction(StdCloseAction, this, SLOT(slotClose()), this);
0212     ac->addAction(QLatin1String("importui_close"), closeAction);
0213 
0214     // -- Edit menu ----------------------------------------------------
0215 
0216     d->selectAllAction = new QAction(i18nc("@action:inmenu", "Select All"), this);
0217     connect(d->selectAllAction, SIGNAL(triggered()), d->view, SLOT(slotSelectAll()));
0218     ac->addAction(QLatin1String("importui_selectall"), d->selectAllAction);
0219     ac->setDefaultShortcut(d->selectAllAction, Qt::CTRL | Qt::Key_A);
0220     d->cameraActions->addAction(d->selectAllAction);
0221 
0222     // -----------------------------------------------------------------
0223 
0224     d->selectNoneAction = new QAction(i18nc("@action:inmenu", "Select None"), this);
0225     connect(d->selectNoneAction, SIGNAL(triggered()), d->view, SLOT(slotSelectNone()));
0226     ac->addAction(QLatin1String("importui_selectnone"), d->selectNoneAction);
0227     ac->setDefaultShortcut(d->selectNoneAction, Qt::CTRL | Qt::SHIFT | Qt::Key_A);
0228     d->cameraActions->addAction(d->selectNoneAction);
0229 
0230     // -----------------------------------------------------------------
0231 
0232     d->selectInvertAction = new QAction(i18nc("@action:inmenu", "Invert Selection"), this);
0233     connect(d->selectInvertAction, SIGNAL(triggered()), d->view, SLOT(slotSelectInvert()));
0234     ac->addAction(QLatin1String("importui_selectinvert"), d->selectInvertAction);
0235     ac->setDefaultShortcut(d->selectInvertAction, Qt::CTRL | Qt::Key_Asterisk);
0236     d->cameraActions->addAction(d->selectInvertAction);
0237 
0238     // -----------------------------------------------------------
0239 
0240     d->selectNewItemsAction = new QAction(QIcon::fromTheme(QLatin1String("folder-favorites")), i18nc("@action:inmenu", "Select New Items"), this);
0241     connect(d->selectNewItemsAction, SIGNAL(triggered()), this, SLOT(slotSelectNew()));
0242     ac->addAction(QLatin1String("importui_selectnewitems"), d->selectNewItemsAction);
0243     d->cameraActions->addAction(d->selectNewItemsAction);
0244 
0245     // -----------------------------------------------------------
0246 
0247     d->selectLockedItemsAction = new QAction(QIcon::fromTheme(QLatin1String("object-locked")), i18nc("@action:inmenu", "Select Locked Items"), this);
0248     connect(d->selectLockedItemsAction, SIGNAL(triggered()), this, SLOT(slotSelectLocked()));
0249     ac->addAction(QLatin1String("importui_selectlockeditems"), d->selectLockedItemsAction);
0250     ac->setDefaultShortcut(d->selectLockedItemsAction, Qt::CTRL | Qt::Key_L);
0251     d->cameraActions->addAction(d->selectLockedItemsAction);
0252 
0253     // --- Download actions ----------------------------------------------------
0254 
0255     d->downloadAction = new QMenu(i18nc("@title:menu", "Download"), this);
0256     d->downloadAction->setIcon(QIcon::fromTheme(QLatin1String("document-save")));
0257     ac->addAction(QLatin1String("importui_imagedownload"), d->downloadAction->menuAction());
0258     d->cameraActions->addAction(d->downloadAction->menuAction());
0259 
0260     d->downloadNewAction = new QAction(QIcon::fromTheme(QLatin1String("folder-favorites")), i18nc("@action", "Download New"), this);
0261     connect(d->downloadNewAction, SIGNAL(triggered()), this, SLOT(slotDownloadNew()));
0262     ac->addAction(QLatin1String("importui_imagedownloadnew"), d->downloadNewAction);
0263     ac->setDefaultShortcut(d->downloadNewAction, Qt::CTRL | Qt::Key_N);
0264     d->downloadAction->addAction(d->downloadNewAction);
0265     d->cameraActions->addAction(d->downloadNewAction);
0266 
0267     connect(d->downloadAction->menuAction(), SIGNAL(triggered()),
0268             d->downloadNewAction, SLOT(trigger()));
0269 
0270     d->downloadSelectedAction = new QAction(QIcon::fromTheme(QLatin1String("document-save")), i18nc("@action", "Download Selected"), this);
0271     connect(d->downloadSelectedAction, SIGNAL(triggered()), this, SLOT(slotDownloadSelected()));
0272     ac->addAction(QLatin1String("importui_imagedownloadselected"), d->downloadSelectedAction);
0273     d->downloadSelectedAction->setEnabled(false);
0274     d->downloadAction->addAction(d->downloadSelectedAction);
0275     d->cameraActions->addAction(d->downloadSelectedAction);
0276 
0277     d->downloadAllAction = new QAction(QIcon::fromTheme(QLatin1String("document-save")), i18nc("@action", "Download All"), this);
0278     connect(d->downloadAllAction, SIGNAL(triggered()), this, SLOT(slotDownloadAll()));
0279     ac->addAction(QLatin1String("importui_imagedownloadall"), d->downloadAllAction);
0280     d->downloadAction->addAction(d->downloadAllAction);
0281     d->cameraActions->addAction(d->downloadAllAction);
0282 
0283     // -------------------------------------------------------------------------
0284 
0285     d->downloadDelNewAction = new QAction(i18nc("@action", "Download && Delete New"), this);
0286     connect(d->downloadDelNewAction, SIGNAL(triggered()), this, SLOT(slotDownloadAndDeleteNew()));
0287     ac->addAction(QLatin1String("importui_imagedownloaddeletenew"), d->downloadDelNewAction);
0288     ac->setDefaultShortcut(d->downloadDelNewAction, Qt::CTRL | Qt::SHIFT | Qt::Key_N);
0289     d->cameraActions->addAction(d->downloadDelNewAction);
0290 
0291     // -----------------------------------------------------------------
0292 
0293     d->downloadDelSelectedAction = new QAction(i18nc("@action", "Download && Delete Selected"), this);
0294     connect(d->downloadDelSelectedAction, SIGNAL(triggered()), this, SLOT(slotDownloadAndDeleteSelected()));
0295     ac->addAction(QLatin1String("importui_imagedownloaddeleteselected"), d->downloadDelSelectedAction);
0296     d->downloadDelSelectedAction->setEnabled(false);
0297     d->cameraActions->addAction(d->downloadDelSelectedAction);
0298 
0299     // -------------------------------------------------------------------------
0300 
0301     d->downloadDelAllAction = new QAction(i18nc("@action", "Download && Delete All"), this);
0302     connect(d->downloadDelAllAction, SIGNAL(triggered()), this, SLOT(slotDownloadAndDeleteAll()));
0303     ac->addAction(QLatin1String("importui_imagedownloaddeleteall"), d->downloadDelAllAction);
0304     d->cameraActions->addAction(d->downloadDelAllAction);
0305 
0306     // -------------------------------------------------------------------------
0307 
0308     d->uploadAction = new QAction(QIcon::fromTheme(QLatin1String("media-flash-sd-mmc")), i18nc("@action", "Upload..."), this);
0309     connect(d->uploadAction, SIGNAL(triggered()), this, SLOT(slotUpload()));
0310     ac->addAction(QLatin1String("importui_imageupload"), d->uploadAction);
0311     ac->setDefaultShortcut(d->uploadAction, Qt::CTRL | Qt::Key_U);
0312     d->cameraActions->addAction(d->uploadAction);
0313 
0314     // -------------------------------------------------------------------------
0315 
0316     d->lockAction = new QAction(QIcon::fromTheme(QLatin1String("object-locked")), i18nc("@action", "Toggle Lock"), this);
0317     connect(d->lockAction, SIGNAL(triggered()), this, SLOT(slotToggleLock()));
0318     ac->addAction(QLatin1String("importui_imagelock"), d->lockAction);
0319     ac->setDefaultShortcut(d->lockAction, Qt::CTRL | Qt::Key_G);
0320     d->cameraActions->addAction(d->lockAction);
0321 
0322     // -------------------------------------------------------------------------
0323 
0324     d->markAsDownloadedAction = new QAction(QIcon::fromTheme(QLatin1String("dialog-ok-apply")), i18nc("@action", "Mark as downloaded"), this);
0325     connect(d->markAsDownloadedAction, SIGNAL(triggered()), this, SLOT(slotMarkAsDownloaded()));
0326     ac->addAction(QLatin1String("importui_imagemarkasdownloaded"), d->markAsDownloadedAction);
0327     d->cameraActions->addAction(d->markAsDownloadedAction);
0328 
0329     // --- Delete actions ------------------------------------------------------
0330 
0331     d->deleteAction = new QMenu(i18nc("@title:menu", "Delete"), this);
0332     d->deleteAction->setIcon(QIcon::fromTheme(QLatin1String("edit-delete")));
0333     ac->addAction(QLatin1String("importui_delete"), d->deleteAction->menuAction());
0334     d->cameraActions->addAction(d->deleteAction->menuAction());
0335 
0336     d->deleteSelectedAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("@action:inmenu delete item", "Delete Selected"), this);
0337     connect(d->deleteSelectedAction, SIGNAL(triggered()), this, SLOT(slotDeleteSelected()));
0338     ac->addAction(QLatin1String("importui_imagedeleteselected"), d->deleteSelectedAction);
0339     ac->setDefaultShortcut(d->deleteSelectedAction, Qt::Key_Delete);
0340     d->deleteSelectedAction->setEnabled(false);
0341     d->deleteAction->addAction(d->deleteSelectedAction);
0342     d->cameraActions->addAction(d->deleteSelectedAction);
0343 
0344     d->deleteAllAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("@action:inmenu delete item", "Delete All"), this);
0345     connect(d->deleteAllAction, SIGNAL(triggered()), this, SLOT(slotDeleteAll()));
0346     ac->addAction(QLatin1String("importui_imagedeleteall"), d->deleteAllAction);
0347     d->deleteAction->addAction(d->deleteAllAction);
0348     d->cameraActions->addAction(d->deleteAllAction);
0349 
0350     d->deleteNewAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18nc("@action:inmenu delete item", "Delete New"), this);
0351     connect(d->deleteNewAction, SIGNAL(triggered()), this, SLOT(slotDeleteNew()));
0352     ac->addAction(QLatin1String("importui_imagedeletenew"), d->deleteNewAction);
0353     d->deleteAction->addAction(d->deleteNewAction);
0354     d->cameraActions->addAction(d->deleteNewAction);
0355 
0356     // --- Icon view, items preview, and map actions ------------------------------------------------------
0357 
0358     d->imageViewSelectionAction = new KSelectAction(QIcon::fromTheme(QLatin1String("view-preview")), i18nc("@title:group", "Views"), this);
0359     ac->addAction(QLatin1String("importui_view_selection"), d->imageViewSelectionAction);
0360 
0361     d->iconViewAction = new QAction(QIcon::fromTheme(QLatin1String("view-list-icons")),
0362                                     i18nc("@action Go to thumbnails (icon) view", "Thumbnails"), this);
0363     d->iconViewAction->setCheckable(true);
0364     ac->addAction(QLatin1String("importui_icon_view"), d->iconViewAction);
0365     connect(d->iconViewAction, SIGNAL(triggered()), d->view, SLOT(slotIconView()));
0366     d->imageViewSelectionAction->addAction(d->iconViewAction);
0367 
0368     d->camItemPreviewAction = new QAction(QIcon::fromTheme(QLatin1String("view-preview")),
0369                                                 i18nc("@action View the selected image", "Preview Item"), this);
0370     d->camItemPreviewAction->setCheckable(true);
0371     ac->addAction(QLatin1String("importui_item_view"), d->camItemPreviewAction);
0372     ac->setDefaultShortcut(d->camItemPreviewAction, Qt::Key_F3);
0373     connect(d->camItemPreviewAction, SIGNAL(triggered()), d->view, SLOT(slotImagePreview()));
0374     d->imageViewSelectionAction->addAction(d->camItemPreviewAction);
0375 
0376 #ifdef HAVE_GEOLOCATION
0377     d->mapViewAction = new QAction(QIcon::fromTheme(QLatin1String("globe")),
0378                                    i18nc("@action Switch to map view", "Map"), this);
0379     d->mapViewAction->setCheckable(true);
0380     ac->addAction(QLatin1String("importui_map_view"), d->mapViewAction);
0381     connect(d->mapViewAction, SIGNAL(triggered()), d->view, SLOT(slotMapWidgetView()));
0382     d->imageViewSelectionAction->addAction(d->mapViewAction);
0383 #endif // HAVE_GEOLOCATION
0384 
0385     /// @todo Add table view stuff here
0386 
0387     // -- Item Sorting ------------------------------------------------------------
0388 
0389     d->itemSortAction                    = new KSelectAction(i18nc("@title:menu", "&Sort Items"), this);
0390     d->itemSortAction->setWhatsThis(i18nc("@info:whatsthis", "The value by which the items are sorted in the thumbnail view"));
0391     ac->addAction(QLatin1String("item_sort"), d->itemSortAction);
0392 
0393     // map to CamItemSortSettings enum
0394     QAction* const sortByNameAction     = d->itemSortAction->addAction(i18nc("@item:inmenu Sort by", "By Name"));
0395     QAction* const sortByPathAction     = d->itemSortAction->addAction(i18nc("@item:inmenu Sort by", "By Path"));
0396     QAction* const sortByDateAction     = d->itemSortAction->addAction(i18nc("@item:inmenu Sort by", "By Date"));
0397     QAction* const sortByFileSizeAction = d->itemSortAction->addAction(i18nc("@item:inmenu Sort by", "By Size"));
0398     QAction* const sortByRatingAction   = d->itemSortAction->addAction(i18nc("@item:inmenu Sort by", "By Rating"));
0399     QAction* const sortByDownloadAction = d->itemSortAction->addAction(i18nc("@item:inmenu Sort by", "By Download State"));
0400 
0401     connect(sortByNameAction, &QAction::triggered,
0402             this, [this]() { d->view->slotSortImagesBy((int)CamItemSortSettings::SortByFileName); });
0403 
0404     connect(sortByPathAction, &QAction::triggered,
0405             this, [this]() { d->view->slotSortImagesBy((int)CamItemSortSettings::SortByFilePath); });
0406 
0407     connect(sortByDateAction, &QAction::triggered,
0408             this, [this]() { d->view->slotSortImagesBy((int)CamItemSortSettings::SortByCreationDate); });
0409 
0410     connect(sortByFileSizeAction, &QAction::triggered,
0411             this, [this]() { d->view->slotSortImagesBy((int)CamItemSortSettings::SortByFileSize); });
0412 
0413     connect(sortByRatingAction, &QAction::triggered,
0414             this, [this]() { d->view->slotSortImagesBy((int)CamItemSortSettings::SortByRating); });
0415 
0416     connect(sortByDownloadAction, &QAction::triggered,
0417             this, [this]() { d->view->slotSortImagesBy((int)CamItemSortSettings::SortByDownloadState); });
0418 
0419     d->itemSortAction->setCurrentItem(ImportSettings::instance()->getImageSortBy());
0420 
0421     // -- Item Sort Order ------------------------------------------------------------
0422 
0423     d->itemSortOrderAction                    = new KSelectAction(i18nc("@action", "Item Sorting &Order"), this);
0424     d->itemSortOrderAction->setWhatsThis(i18nc("@info:whatsthis", "Defines whether items are sorted in ascending or descending manner."));
0425     ac->addAction(QLatin1String("item_sort_order"), d->itemSortOrderAction);
0426 
0427     QAction* const sortAscendingAction  = d->itemSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-ascending")),
0428                                                                             i18nc("@item:inmenu Sorting Order", "Ascending"));
0429     QAction* const sortDescendingAction = d->itemSortOrderAction->addAction(QIcon::fromTheme(QLatin1String("view-sort-descending")),
0430                                                                             i18nc("@item:inmenu Sorting Order", "Descending"));
0431 
0432     connect(sortAscendingAction, &QAction::triggered,
0433             this, [this]() { d->view->slotSortImagesOrder((int)CamItemSortSettings::AscendingOrder); });
0434 
0435     connect(sortDescendingAction, &QAction::triggered,
0436             this, [this]() { d->view->slotSortImagesOrder((int)CamItemSortSettings::DescendingOrder); });
0437 
0438     d->itemSortOrderAction->setCurrentItem(ImportSettings::instance()->getImageSortOrder());
0439 
0440     // -- Item Grouping ------------------------------------------------------------
0441 
0442     d->itemsGroupAction                  = new KSelectAction(i18nc("@title:menu", "&Group Items"), this);
0443     d->itemsGroupAction->setWhatsThis(i18nc("@info:whatsthis", "The categories in which the items in the thumbnail view are displayed"));
0444     ac->addAction(QLatin1String("item_group"), d->itemsGroupAction);
0445 
0446     // map to CamItemSortSettings enum
0447     QAction* const noCategoriesAction  = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "Flat List"));
0448     QAction* const groupByFolderAction = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "By Folder"));
0449     QAction* const groupByFormatAction = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "By Format"));
0450     QAction* const groupByDateAction   = d->itemsGroupAction->addAction(i18nc("@item:inmenu Group Items", "By Date"));
0451 
0452     connect(noCategoriesAction, &QAction::triggered,
0453             this, [this]() { d->view->slotSeparateImages((int)CamItemSortSettings::NoCategories); });
0454 
0455     connect(groupByFolderAction, &QAction::triggered,
0456             this, [this]() { d->view->slotSeparateImages((int)CamItemSortSettings::CategoryByFolder); });
0457 
0458     connect(groupByFormatAction, &QAction::triggered,
0459             this, [this]() { d->view->slotSeparateImages((int)CamItemSortSettings::CategoryByFormat); });
0460 
0461     connect(groupByDateAction, &QAction::triggered,
0462             this, [this]() { d->view->slotSeparateImages((int)CamItemSortSettings::CategoryByDate); });
0463 
0464     d->itemsGroupAction->setCurrentItem(ImportSettings::instance()->getImageSeparationMode());
0465 
0466     // -- Standard 'View' menu actions ---------------------------------------------
0467 
0468     d->increaseThumbsAction = buildStdAction(StdZoomInAction, d->view, SLOT(slotZoomIn()), this);
0469     d->increaseThumbsAction->setEnabled(false);
0470     ac->addAction(QLatin1String("importui_zoomplus"), d->increaseThumbsAction);
0471 
0472     d->decreaseThumbsAction = buildStdAction(StdZoomOutAction, d->view, SLOT(slotZoomOut()), this);
0473     d->decreaseThumbsAction->setEnabled(false);
0474     ac->addAction(QLatin1String("importui_zoomminus"), d->decreaseThumbsAction);
0475 
0476     d->zoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18nc("@action:inmenu", "Fit to &Window"), this);
0477     connect(d->zoomFitToWindowAction, SIGNAL(triggered()), d->view, SLOT(slotFitToWindow()));
0478     ac->addAction(QLatin1String("import_zoomfit2window"), d->zoomFitToWindowAction);
0479     ac->setDefaultShortcut(d->zoomFitToWindowAction, Qt::CTRL | Qt::ALT | Qt::Key_E);
0480 
0481     d->zoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18nc("@action:inmenu", "Zoom to 100%"), this);
0482     connect(d->zoomTo100percents, SIGNAL(triggered()), d->view, SLOT(slotZoomTo100Percents()));
0483     ac->addAction(QLatin1String("import_zoomto100percents"), d->zoomTo100percents);
0484     ac->setDefaultShortcut(d->zoomTo100percents, Qt::CTRL | Qt::Key_Period);
0485 
0486     // ------------------------------------------------------------------------------------------------
0487 
0488     d->viewCMViewAction = new QAction(QIcon::fromTheme(QLatin1String("video-display")), i18nc("@action", "Color-Managed View"), this);
0489     d->viewCMViewAction->setCheckable(true);
0490     connect(d->viewCMViewAction, SIGNAL(triggered()), this, SLOT(slotToggleColorManagedView()));
0491     ac->addAction(QLatin1String("color_managed_view"), d->viewCMViewAction);
0492     ac->setDefaultShortcut(d->viewCMViewAction, Qt::Key_F12);
0493 
0494     // ------------------------------------------------------------------------------------------------
0495 
0496     createFullScreenAction(QLatin1String("importui_fullscreen"));
0497     createSidebarActions();
0498 
0499     d->showLogAction = new QAction(QIcon::fromTheme(QLatin1String("edit-find")), i18nc("@option:check", "Show History"), this);
0500     d->showLogAction->setCheckable(true);
0501     connect(d->showLogAction, SIGNAL(triggered()), this, SLOT(slotShowLog()));
0502     ac->addAction(QLatin1String("importui_showlog"), d->showLogAction);
0503     ac->setDefaultShortcut(d->showLogAction, Qt::CTRL | Qt::Key_H);
0504 
0505     d->showBarAction = new QAction(QIcon::fromTheme(QLatin1String("view-choose")), i18nc("@option:check", "Show Thumbbar"), this);
0506     d->showBarAction->setCheckable(true);
0507     connect(d->showBarAction, SIGNAL(triggered()), this, SLOT(slotToggleShowBar()));
0508     ac->addAction(QLatin1String("showthumbs"), d->showBarAction);
0509     ac->setDefaultShortcut(d->showBarAction, Qt::CTRL | Qt::Key_T);
0510     d->showBarAction->setEnabled(false);
0511 
0512     // ---------------------------------------------------------------------------------
0513 
0514     ThemeManager::instance()->registerThemeActions(this);
0515 
0516     // Standard 'Help' menu actions
0517     createHelpActions(QLatin1String("camera_import"));
0518 
0519     // Provides a menu entry that allows showing/hiding the toolbar(s)
0520     setStandardToolBarMenuEnabled(true);
0521 
0522     // Provides a menu entry that allows showing/hiding the statusbar
0523     createStandardStatusBarAction();
0524 
0525     // Standard 'Configure' menu actions
0526     createSettingsActions();
0527 
0528     // -- Keyboard-only actions added to <MainWindow> ----------------------------------
0529 
0530     QAction* const altBackwardAction = new QAction(i18nc("@action", "Previous Image"), this);
0531     ac->addAction(QLatin1String("importui_backward_shift_space"), altBackwardAction);
0532     ac->setDefaultShortcut(altBackwardAction, Qt::SHIFT | Qt::Key_Space);
0533     connect(altBackwardAction, SIGNAL(triggered()), d->view, SLOT(slotPrevItem()));
0534 
0535     // ---------------------------------------------------------------------------------
0536 
0537     d->connectAction = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action Connection failed, try again?", "Retry"), this);
0538     connect(d->connectAction, SIGNAL(triggered()), d->controller, SLOT(slotConnect()));
0539 
0540     createGUI(xmlFile());
0541     cleanupActions();
0542 
0543     showMenuBarAction()->setChecked(!menuBar()->isHidden());  // NOTE: workaround for bug #171080
0544 }
0545 
0546 void ImportUI::updateActions()
0547 {
0548     const CamItemInfoList& list = d->view->selectedCamItemInfos();
0549     bool hasSelection           = !list.isEmpty();
0550 
0551     d->downloadDelSelectedAction->setEnabled(hasSelection && d->controller->cameraDeleteSupport());
0552     d->deleteSelectedAction->setEnabled(hasSelection && d->controller->cameraDeleteSupport());
0553     d->camItemPreviewAction->setEnabled(hasSelection && cameraUseUMSDriver());
0554     d->downloadSelectedAction->setEnabled(hasSelection);
0555     d->lockAction->setEnabled(hasSelection);
0556 
0557     if (hasSelection)
0558     {
0559         // only enable "Mark as downloaded" if at least one
0560         // selected image has not been downloaded
0561         bool haveNotDownloadedItem = false;
0562 
0563         Q_FOREACH (const CamItemInfo& info, list)
0564         {
0565             haveNotDownloadedItem = !(info.downloaded == CamItemInfo::DownloadedYes);
0566 
0567             if (haveNotDownloadedItem)
0568             {
0569                 break;
0570             }
0571         }
0572 
0573         d->markAsDownloadedAction->setEnabled(haveNotDownloadedItem);
0574     }
0575     else
0576     {
0577         d->markAsDownloadedAction->setEnabled(false);
0578     }
0579 }
0580 
0581 void ImportUI::setupConnections()
0582 {
0583     //TODO: Needs testing.
0584     connect(d->advancedSettings, SIGNAL(signalDownloadNameChanged()),
0585             this, SLOT(slotUpdateRenamePreview()));
0586 
0587     connect(d->dngConvertSettings, SIGNAL(signalDownloadNameChanged()),
0588             this, SLOT(slotUpdateRenamePreview()));
0589 
0590     connect(d->historyView, SIGNAL(signalEntryClicked(QVariant)),
0591             this, SLOT(slotHistoryEntryClicked(QVariant)));
0592 
0593     connect(IccSettings::instance(), SIGNAL(signalSettingsChanged()),
0594             this, SLOT(slotColorManagementOptionsChanged()));
0595 
0596     // -------------------------------------------------------------------------
0597 
0598     connect(d->view, SIGNAL(signalImageSelected(CamItemInfoList,CamItemInfoList)),
0599             this, SLOT(slotImageSelected(CamItemInfoList,CamItemInfoList)));
0600 
0601     connect(d->view, SIGNAL(signalSwitchedToPreview()),
0602             this, SLOT(slotSwitchedToPreview()));
0603 
0604     connect(d->view, SIGNAL(signalSwitchedToIconView()),
0605             this, SLOT(slotSwitchedToIconView()));
0606 
0607     connect(d->view, SIGNAL(signalSwitchedToMapView()),
0608             this, SLOT(slotSwitchedToMapView()));
0609 
0610     connect(d->view, SIGNAL(signalNewSelection(bool)),
0611             this, SLOT(slotNewSelection(bool)));
0612 
0613     // -------------------------------------------------------------------------
0614 
0615     connect(d->view, SIGNAL(signalThumbSizeChanged(int)),
0616             this, SLOT(slotThumbSizeChanged(int)));
0617 
0618     connect(d->view, SIGNAL(signalZoomChanged(double)),
0619             this, SLOT(slotZoomChanged(double)));
0620 
0621     connect(d->zoomBar, SIGNAL(signalZoomSliderChanged(int)),
0622             this, SLOT(slotZoomSliderChanged(int)));
0623 
0624     connect(d->zoomBar, SIGNAL(signalZoomValueEdited(double)),
0625             d->view, SLOT(setZoomFactor(double)));
0626 
0627     connect(this, SIGNAL(signalWindowHasMoved()),
0628             d->zoomBar, SLOT(slotUpdateTrackerPos()));
0629 
0630     // -------------------------------------------------------------------------
0631 
0632     connect(CollectionManager::instance(), SIGNAL(locationStatusChanged(CollectionLocation,int)),
0633             this, SLOT(slotCollectionLocationStatusChanged(CollectionLocation,int)));
0634 
0635     connect(ApplicationSettings::instance(), SIGNAL(setupChanged()),
0636             this, SLOT(slotSetupChanged()));
0637 
0638     connect(d->renameCustomizer, SIGNAL(signalChanged()),
0639             this, SLOT(slotUpdateRenamePreview()));
0640 }
0641 
0642 void ImportUI::setupStatusBar()
0643 {
0644     d->statusProgressBar = new StatusProgressBar(statusBar());
0645     d->statusProgressBar->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0646     d->statusProgressBar->setNotificationTitle(d->cameraTitle, QIcon::fromTheme(QLatin1String("camera-photo")));
0647     statusBar()->addWidget(d->statusProgressBar, 100);
0648 
0649     //------------------------------------------------------------------------------
0650 
0651     d->cameraFreeSpace = new FreeSpaceWidget(statusBar(), 100);
0652 
0653     if (cameraUseGPhotoDriver())
0654     {
0655         d->cameraFreeSpace->setMode(FreeSpaceWidget::GPhotoCamera);
0656         connect(d->controller, SIGNAL(signalFreeSpace(qint64,qint64)),
0657                 this, SLOT(slotCameraFreeSpaceInfo(qint64,qint64)));
0658     }
0659     else
0660     {
0661         d->cameraFreeSpace->setMode(FreeSpaceWidget::UMSCamera);
0662         d->cameraFreeSpace->setPath(d->controller->cameraPath());
0663     }
0664 
0665     statusBar()->addWidget(d->cameraFreeSpace, 1);
0666 
0667     //------------------------------------------------------------------------------
0668 
0669     d->albumLibraryFreeSpace = new FreeSpaceWidget(statusBar(), 100);
0670     d->albumLibraryFreeSpace->setMode(FreeSpaceWidget::AlbumLibrary);
0671     statusBar()->addWidget(d->albumLibraryFreeSpace, 1);
0672     refreshCollectionFreeSpace();
0673 
0674     //------------------------------------------------------------------------------
0675 
0676     // TODO: Replace it with FilterStatusBar after advanced filtering is implemented.
0677 
0678     d->filterComboBox = new ImportFilterComboBox(statusBar());
0679     setFilter(d->filterComboBox->currentFilter());
0680     statusBar()->addWidget(d->filterComboBox, 1);
0681 
0682     connect(d->filterComboBox, SIGNAL(signalFilterChanged(Filter*)),
0683             this, SLOT(setFilter(Filter*)));
0684 
0685     //------------------------------------------------------------------------------
0686 
0687     d->zoomBar = new DZoomBar(statusBar());
0688     d->zoomBar->setZoomToFitAction(d->zoomFitToWindowAction);
0689     d->zoomBar->setZoomTo100Action(d->zoomTo100percents);
0690     d->zoomBar->setZoomPlusAction(d->increaseThumbsAction);
0691     d->zoomBar->setZoomMinusAction(d->decreaseThumbsAction);
0692     d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl);
0693     statusBar()->addPermanentWidget(d->zoomBar, 1);
0694 }
0695 
0696 void ImportUI::setupCameraController(const QString& model, const QString& port, const QString& path)
0697 {
0698     d->controller = new CameraController(this, d->cameraTitle, model, port, path);
0699 
0700     connect(d->controller, SIGNAL(signalConnected(bool)),
0701             this, SLOT(slotConnected(bool)),
0702             Qt::QueuedConnection);
0703 
0704     connect(d->controller, SIGNAL(signalLogMsg(QString,DHistoryView::EntryType,QString,QString)),
0705             this, SLOT(slotLogMsg(QString,DHistoryView::EntryType,QString,QString)),
0706             Qt::QueuedConnection);
0707 
0708     connect(d->controller, SIGNAL(signalCameraInformation(QString,QString,QString)),
0709             this, SLOT(slotCameraInformation(QString,QString,QString)),
0710             Qt::QueuedConnection);
0711 
0712     connect(d->controller, SIGNAL(signalBusy(bool)),
0713             this, SLOT(slotBusy(bool)),
0714             Qt::QueuedConnection);
0715 
0716     connect(d->controller, SIGNAL(signalFolderList(QStringList)),
0717             this, SLOT(slotFolderList(QStringList)),
0718             Qt::QueuedConnection);
0719 
0720     connect(d->controller, SIGNAL(signalDownloaded(QString,QString,QString,int)),
0721             this, SLOT(slotDownloaded(QString,QString,QString,int)),
0722             Qt::BlockingQueuedConnection);
0723 
0724     connect(d->controller, SIGNAL(signalDeleted(QString,QString,bool)),
0725             this, SLOT(slotDeleted(QString,QString,bool)),
0726             Qt::QueuedConnection);
0727 
0728     connect(d->controller, SIGNAL(signalLocked(QString,QString,bool)),
0729             this, SLOT(slotLocked(QString,QString,bool)),
0730             Qt::QueuedConnection);
0731 
0732     connect(d->controller, SIGNAL(signalMetadata(QString,QString,MetaEngineData)),
0733             this, SLOT(slotMetadata(QString,QString,MetaEngineData)),
0734             Qt::QueuedConnection);
0735 
0736     connect(d->controller, SIGNAL(signalUploaded(CamItemInfo)),
0737             this, SLOT(slotUploaded(CamItemInfo)),
0738             Qt::QueuedConnection);
0739 
0740     d->controller->start();
0741 
0742     // Setup Thumbnails controller -------------------------------------------------------
0743 
0744     d->camThumbsCtrl = new CameraThumbsCtrl(d->controller, this);
0745 }
0746 
0747 CameraThumbsCtrl* ImportUI::getCameraThumbsCtrl() const
0748 {
0749     return d->camThumbsCtrl;
0750 }
0751 
0752 void ImportUI::setupAccelerators()
0753 {
0754     KActionCollection* const ac = actionCollection();
0755 
0756     QAction* const escapeAction = new QAction(i18nc("@action", "Exit Preview Mode"), this);
0757     ac->addAction(QLatin1String("exit_preview_mode"), escapeAction);
0758     ac->setDefaultShortcut(escapeAction, Qt::Key_Escape);
0759     connect(escapeAction, SIGNAL(triggered()), this, SIGNAL(signalEscapePressed()));
0760 
0761     QAction* const nextImageAction = new QAction(i18nc("@action","Next Image"), this);
0762     nextImageAction->setIcon(QIcon::fromTheme(QLatin1String("go-next")));
0763     ac->addAction(QLatin1String("next_image"), nextImageAction);
0764     ac->setDefaultShortcut(nextImageAction, Qt::Key_Space);
0765     connect(nextImageAction, SIGNAL(triggered()), d->view, SLOT(slotNextItem()));
0766 
0767     QAction* const previousImageAction = new QAction(i18nc("@action", "Previous Image"), this);
0768     previousImageAction->setIcon(QIcon::fromTheme(QLatin1String("go-previous")));
0769     ac->addAction(QLatin1String("previous_image"), previousImageAction);
0770     ac->setDefaultShortcuts(previousImageAction, QList<QKeySequence>() << Qt::Key_Backspace << (Qt::SHIFT | Qt::Key_Space));
0771     connect(previousImageAction, SIGNAL(triggered()), d->view, SLOT(slotPrevItem()));
0772 
0773     QAction* const firstImageAction = new QAction(i18nc("@action Go to first image", "First Image"), this);
0774     ac->addAction(QLatin1String("first_image"), firstImageAction);
0775     ac->setDefaultShortcut(firstImageAction, Qt::Key_Home);
0776     connect(firstImageAction, SIGNAL(triggered()), d->view, SLOT(slotFirstItem()));
0777 
0778     QAction* const lastImageAction = new QAction(i18nc("@action Go to last image", "Last Image"), this);
0779     ac->addAction(QLatin1String("last_image"), lastImageAction);
0780     ac->setDefaultShortcut(lastImageAction, Qt::Key_End);
0781     connect(lastImageAction, SIGNAL(triggered()), d->view, SLOT(slotLastItem()));
0782 }
0783 
0784 void ImportUI::readSettings()
0785 {
0786     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0787     KConfigGroup group        = config->group(d->configGroupName);
0788 
0789     readFullScreenSettings(group);
0790 
0791     d->showBarAction->setChecked(ImportSettings::instance()->getShowThumbbar());
0792     d->showLogAction->setChecked(group.readEntry(QLatin1String("ShowLog"), false));
0793     d->albumCustomizer->readSettings(group);
0794     d->advancedSettings->readSettings(group);
0795     d->dngConvertSettings->readSettings(group);
0796     d->scriptingSettings->readSettings(group);
0797 
0798     d->advBox->readSettings(group);
0799 
0800     d->splitter->restoreState(group);
0801 
0802     slotShowLog();
0803 }
0804 
0805 void ImportUI::saveSettings()
0806 {
0807     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0808     KConfigGroup group        = config->group(d->configGroupName);
0809 
0810     ImportSettings::instance()->setShowThumbbar(d->showBarAction->isChecked());
0811     ImportSettings::instance()->saveSettings();
0812     group.writeEntry(QLatin1String("ShowLog"), d->showLogAction->isChecked());
0813     d->albumCustomizer->saveSettings(group);
0814     d->advancedSettings->saveSettings(group);
0815     d->dngConvertSettings->saveSettings(group);
0816     d->scriptingSettings->saveSettings(group);
0817 
0818     d->advBox->writeSettings(group);
0819 
0820     d->rightSideBar->saveState();
0821     d->splitter->saveState(group);
0822     d->filterComboBox->saveSettings();
0823 
0824     config->sync();
0825 }
0826 
0827 bool ImportUI::isBusy() const
0828 {
0829     return d->busy;
0830 }
0831 
0832 bool ImportUI::isClosed() const
0833 {
0834     return d->closed;
0835 }
0836 
0837 QString ImportUI::cameraTitle() const
0838 {
0839     return d->cameraTitle;
0840 }
0841 
0842 DownloadSettings ImportUI::downloadSettings() const
0843 {
0844     DownloadSettings settings = d->advancedSettings->settings();
0845     d->dngConvertSettings->settings(&settings);
0846     d->scriptingSettings->settings(&settings);
0847     return settings;
0848 }
0849 
0850 void ImportUI::setInitialSorting()
0851 {
0852     d->view->slotSeparateImages(ImportSettings::instance()->getImageSeparationMode());
0853     d->view->slotSortImagesBy(ImportSettings::instance()->getImageSortBy());
0854     d->view->slotSortImagesOrder(ImportSettings::instance()->getImageSortOrder());
0855 }
0856 
0857 void ImportUI::slotCancelButton()
0858 {
0859     d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
0860                                              i18nc("@info:status", "Canceling current operation, please wait..."));
0861     d->controller->slotCancel();
0862 
0863     d->currentlyDeleting.clear();
0864 
0865     postProcessAfterDownload();
0866 
0867     refreshFreeSpace();
0868 }
0869 
0870 void ImportUI::refreshFreeSpace()
0871 {
0872     if (cameraUseGPhotoDriver())
0873     {
0874         d->controller->getFreeSpace();
0875     }
0876     else
0877     {
0878         d->cameraFreeSpace->refresh();
0879     }
0880 }
0881 
0882 void ImportUI::closeEvent(QCloseEvent* e)
0883 {
0884     if (dialogClosed())
0885     {
0886         DXmlGuiWindow::closeEvent(e);
0887     }
0888     else
0889     {
0890         e->ignore();
0891     }
0892 }
0893 
0894 void ImportUI::moveEvent(QMoveEvent* e)
0895 {
0896     Q_UNUSED(e)
0897     Q_EMIT signalWindowHasMoved();
0898 }
0899 
0900 void ImportUI::slotClose()
0901 {
0902     close();
0903 }
0904 
0905 bool ImportUI::dialogClosed()
0906 {
0907     if (d->closed)
0908     {
0909         return true;
0910     }
0911 
0912     if (isBusy())
0913     {
0914         if (QMessageBox::question(this, qApp->applicationName(),
0915                                   i18nc("@info", "Do you want to close the dialog "
0916                                         "and cancel the current operation?"),
0917                                   QMessageBox::Yes | QMessageBox::No
0918                                  ) == QMessageBox::No)
0919         {
0920             return false;
0921         }
0922     }
0923 
0924     d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
0925                                              i18nc("@info:status", "Disconnecting from camera, please wait..."));
0926 
0927     if (d->waitAutoRotate)
0928     {
0929         hide();
0930         d->waitAutoRotate = false;
0931 
0932         return false;
0933     }
0934 
0935     if (isBusy())
0936     {
0937         d->controller->slotCancel();
0938 
0939         // will be read in slotBusy later and finishDialog
0940         // will be called only when everything is finished
0941 
0942         d->closed = true;
0943     }
0944     else
0945     {
0946         d->closed = true;
0947         finishDialog();
0948     }
0949 
0950     return true;
0951 }
0952 
0953 void ImportUI::finishDialog()
0954 {
0955     // Look if an item have been downloaded to computer during camera GUI session.
0956     // If yes, update the starting number value used to rename camera items from camera list.
0957 
0958     if (d->view->downloadedCamItemInfos() > 0)
0959     {
0960         CameraList* const clist = CameraList::defaultList();
0961 
0962         if (clist)
0963         {
0964             clist->changeCameraStartIndex(d->cameraTitle, d->renameCustomizer->startIndex());
0965         }
0966     }
0967 
0968     deleteLater();
0969 
0970     if (!d->lastDestURL.isEmpty())
0971     {
0972         Q_EMIT signalLastDestination(d->lastDestURL);
0973     }
0974 
0975     saveSettings();
0976 }
0977 
0978 void ImportUI::slotBusy(bool val)
0979 {
0980     if (!val)   // Camera is available for actions.
0981     {
0982         if (!d->busy)
0983         {
0984             return;
0985         }
0986 
0987         d->busy = false;
0988         d->view->setEnabled(true);
0989         d->advBox->setEnabled(true);
0990         d->cameraActions->setEnabled(true);
0991         d->cameraCancelAction->setEnabled(false);
0992 
0993         // selection-dependent update of lockAction, markAsDownloadedAction,
0994         // downloadSelectedAction, downloadDelSelectedAction, deleteSelectedAction
0995 
0996         updateActions();
0997 
0998         m_animLogo->stop();
0999         d->statusProgressBar->setProgressValue(0);
1000         d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("@info:status busy state", "Ready"));
1001 
1002         // like WDestructiveClose, but after camera controller operation has safely finished
1003 
1004         if (d->closed)
1005         {
1006             finishDialog();
1007         }
1008     }
1009     else    // Camera is busy.
1010     {
1011         if (d->busy)
1012         {
1013             return;
1014         }
1015 
1016         if (!m_animLogo->running())
1017         {
1018             m_animLogo->start();
1019         }
1020 
1021         d->busy = true;
1022         d->cameraActions->setEnabled(false);
1023     }
1024 }
1025 
1026 void ImportUI::slotZoomSliderChanged(int size)
1027 {
1028     d->view->setThumbSize(size);
1029 }
1030 
1031 void ImportUI::slotZoomChanged(double zoom)
1032 {
1033     double zmin = d->view->zoomMin();
1034     double zmax = d->view->zoomMax();
1035     d->zoomBar->setZoom(zoom, zmin, zmax);
1036 
1037     if (!fullScreenIsActive())
1038     {
1039         d->zoomBar->triggerZoomTrackerToolTip();
1040     }
1041 }
1042 
1043 void ImportUI::slotThumbSizeChanged(int size)
1044 {
1045     d->zoomBar->setThumbsSize(size);
1046 
1047     if (!fullScreenIsActive())
1048     {
1049         d->zoomBar->triggerZoomTrackerToolTip();
1050     }
1051 }
1052 
1053 void ImportUI::slotConnected(bool val)
1054 {
1055     if (!val)
1056     {
1057         d->errorWidget->setText(i18nc("@info", "Failed to connect to the camera. "
1058                                                "Please make sure it is connected "
1059                                                "properly and turned on."));
1060 
1061         d->errorWidget->clearAllActions();
1062         d->errorWidget->addAction(d->connectAction);
1063         d->errorWidget->addAction(d->showPreferencesAction);
1064         d->errorWidget->animatedShow();
1065     }
1066     else
1067     {
1068         // disable unsupported actions
1069 
1070         d->uploadAction->setEnabled(d->controller->cameraUploadSupport());
1071 
1072         d->cameraCaptureAction->setEnabled(d->controller->cameraCaptureImageSupport());
1073 
1074         d->errorWidget->hide();
1075         refreshFreeSpace();
1076 
1077         // FIXME ugly c&p from slotFolderList
1078 
1079         KSharedConfig::Ptr config = KSharedConfig::openConfig();
1080         KConfigGroup group        = config->group(d->configGroupName);
1081         bool useMetadata          = group.readEntry(d->configUseFileMetadata, false);
1082         d->controller->listRootFolder(useMetadata);
1083     }
1084 }
1085 
1086 void ImportUI::slotFolderList(const QStringList& folderList)
1087 {
1088     if (d->closed)
1089     {
1090         return;
1091     }
1092 
1093     d->statusProgressBar->setProgressValue(0);
1094     d->statusProgressBar->setProgressTotalSteps(0);
1095 
1096     KSharedConfig::Ptr config = KSharedConfig::openConfig();
1097     KConfigGroup group        = config->group(d->configGroupName);
1098     bool useMetadata          = group.readEntry(d->configUseFileMetadata, false);
1099 
1100     // when getting a list of subfolders, request their contents and also their subfolders
1101 
1102     for (QStringList::const_iterator it = folderList.constBegin() ;
1103          it != folderList.constEnd() ; ++it)
1104     {
1105         d->controller->listFiles(*it, useMetadata);
1106         d->controller->listFolders(*it);
1107     }
1108 }
1109 
1110 void ImportUI::setFilter(Filter* filter)
1111 {
1112     d->view->importFilterModel()->setFilter(filter);
1113 }
1114 
1115 void ImportUI::slotCapture()
1116 {
1117     if (d->busy)
1118     {
1119         return;
1120     }
1121 
1122     CaptureDlg* const captureDlg = new CaptureDlg(this, d->controller, d->cameraTitle);
1123     captureDlg->show();
1124 }
1125 
1126 void ImportUI::slotInformation()
1127 {
1128     if (d->busy)
1129     {
1130         return;
1131     }
1132 
1133     d->controller->getCameraInformation();
1134 }
1135 
1136 void ImportUI::slotCameraInformation(const QString& summary, const QString& manual, const QString& about)
1137 {
1138     CameraInfoDialog* const infoDlg = new CameraInfoDialog(this, summary, manual, about);
1139     infoDlg->show();
1140 }
1141 
1142 void ImportUI::slotUpload()
1143 {
1144     if (d->busy)
1145     {
1146         return;
1147     }
1148 
1149     QList<QUrl> urls = ImageDialog::getImageURLs(this,
1150                                                  QUrl::fromLocalFile(CollectionManager::instance()->oneAlbumRootPath()),
1151                                                  i18nc("@title:window", "Select Image to Upload"));
1152 
1153     if (!urls.isEmpty())
1154     {
1155         slotUploadItems(urls);
1156     }
1157 }
1158 
1159 void ImportUI::slotUploadItems(const QList<QUrl>& urls)
1160 {
1161     if (d->busy)
1162     {
1163         return;
1164     }
1165 
1166     if (urls.isEmpty())
1167     {
1168         return;
1169     }
1170 
1171     if (d->cameraFreeSpace->isValid())
1172     {
1173         // Check if space require to upload new items in camera is enough.
1174 
1175         qint64 totalBytesSize = 0;
1176 
1177         for (QList<QUrl>::const_iterator it = urls.constBegin() ; it != urls.constEnd() ; ++it)
1178         {
1179             QFileInfo fi((*it).toLocalFile());
1180             totalBytesSize += fi.size();
1181         }
1182 
1183         if (totalBytesSize >= d->cameraFreeSpace->bytesAvail())
1184         {
1185             QMessageBox::critical(this, qApp->applicationName(),
1186                                   i18nc("@info", "There is not enough free space on the Camera Medium "
1187                                         "to upload pictures.\n\n"
1188                                         "Space require: %1\n"
1189                                         "Available free space: %2",
1190                                         ItemPropertiesTab::humanReadableBytesCount(totalBytesSize),
1191                                         ItemPropertiesTab::humanReadableBytesCount(d->cameraFreeSpace->bytesAvail())));
1192             return;
1193         }
1194     }
1195 
1196     QMap<QString, int> map           = countItemsByFolders();
1197     QPointer<CameraFolderDialog> dlg = new CameraFolderDialog(this, map, d->controller->cameraTitle(),
1198                                                               d->controller->cameraPath());
1199 
1200     if (dlg->exec() != QDialog::Accepted)
1201     {
1202         delete dlg;
1203         return;
1204     }
1205 
1206     // since we access members here, check if the pointer is still valid
1207 
1208     if (!dlg)
1209     {
1210         return;
1211     }
1212 
1213     QString cameraFolder = dlg->selectedFolderPath();
1214 
1215     for (QList<QUrl>::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it)
1216     {
1217         QFileInfo fi((*it).toLocalFile());
1218 
1219         if (!fi.exists())
1220         {
1221             continue;
1222         }
1223 
1224         if (fi.isDir())
1225         {
1226             continue;
1227         }
1228 
1229         QString ext  = QLatin1Char('.') + fi.completeSuffix();
1230         QString name = fi.fileName();
1231         name.truncate(fi.fileName().length() - ext.length());
1232 
1233         bool ok;
1234 
1235         CamItemInfo uploadInfo;
1236         uploadInfo.folder = cameraFolder;
1237         uploadInfo.name   = name + ext;
1238 
1239         while (d->view->hasImage(uploadInfo))
1240         {
1241             QString msg(i18nc("@info", "Camera Folder \"%1\" already contains the item \"%2\".\n"
1242                               "Please enter a new filename (without extension):",
1243                               QDir::toNativeSeparators(cameraFolder), fi.fileName()));
1244             uploadInfo.name = QInputDialog::getText(this,
1245                                                     i18nc("@title:window", "File Already Exists"),
1246                                                     msg,
1247                                                     QLineEdit::Normal,
1248                                                     name,
1249                                                     &ok) + ext;
1250 
1251             if (!ok)
1252             {
1253                 return;
1254             }
1255         }
1256 
1257         d->controller->upload(fi, uploadInfo.name, cameraFolder);
1258     }
1259 
1260     delete dlg;
1261 }
1262 
1263 void ImportUI::slotUploaded(const CamItemInfo& /*itemInfo*/)
1264 {
1265     if (d->closed)
1266     {
1267         return;
1268     }
1269 
1270     refreshFreeSpace();
1271 }
1272 
1273 void ImportUI::slotDownloadNew()
1274 {
1275     slotSelectNew();
1276     QTimer::singleShot(0, this, SLOT(slotDownloadSelected()));
1277 }
1278 
1279 void ImportUI::slotDownloadAndDeleteNew()
1280 {
1281     slotSelectNew();
1282     QTimer::singleShot(0, this, SLOT(slotDownloadAndDeleteSelected()));
1283 }
1284 
1285 void ImportUI::slotDownloadSelected()
1286 {
1287     slotDownload(true, false);
1288 }
1289 
1290 void ImportUI::slotDownloadAndDeleteSelected()
1291 {
1292     slotDownload(true, true);
1293 }
1294 
1295 void ImportUI::slotDownloadAll()
1296 {
1297     slotDownload(false, false);
1298 }
1299 
1300 void ImportUI::slotDownloadAndDeleteAll()
1301 {
1302     slotDownload(false, true);
1303 }
1304 
1305 void ImportUI::slotDownload(bool onlySelected, bool deleteAfter, Album* album)
1306 {
1307     if (d->albumCustomizer->autoAlbumDateEnabled()                                    &&
1308         (d->albumCustomizer->folderDateFormat() == AlbumCustomizer::CustomDateFormat) &&
1309         !d->albumCustomizer->customDateFormatIsValid())
1310     {
1311         QMessageBox::information(this, qApp->applicationName(),
1312                                  i18nc("@info", "Your custom target album date format is not valid. Please check your settings..."));
1313         return;
1314     }
1315 
1316     // See bug #143934: force to select all items to prevent problem.
1317 
1318     if (!onlySelected)
1319     {
1320         d->view->slotSelectAll();
1321     }
1322 
1323     // Update the download names.
1324     slotNewSelection(d->view->selectedUrls().count() > 0);
1325 
1326     // -- Get the destination album from digiKam library ---------------
1327 
1328     PAlbum* pAlbum = nullptr;
1329 
1330     if (!album)
1331     {
1332         AlbumManager* const man   = AlbumManager::instance();
1333 
1334         // Check if default target album option is enabled.
1335 
1336         KSharedConfig::Ptr config = KSharedConfig::openConfig();
1337         KConfigGroup group        = config->group(d->configGroupName);
1338         bool useDefaultTarget     = group.readEntry(d->configUseDefaultTargetAlbum, false);
1339 
1340         if (useDefaultTarget)
1341         {
1342             PAlbum* const pa = man->findPAlbum(group.readEntry(d->configDefaultTargetAlbumId, 0));
1343 
1344             if (pa)
1345             {
1346                 CollectionLocation cl = CollectionManager::instance()->locationForAlbumRootId(pa->albumRootId());
1347 
1348                 if (!cl.isAvailable() || cl.isNull())
1349                 {
1350                     QMessageBox::information(this, qApp->applicationName(),
1351                                              i18nc("@info", "Collection which host your default target album set to process "
1352                                                    "download from camera device is not available. Please select another one from "
1353                                                    "camera configuration dialog."));
1354                     return;
1355                 }
1356             }
1357             else
1358             {
1359                 QMessageBox::information(this, qApp->applicationName(),
1360                                          i18nc("@info", "Your default target album set to process download "
1361                                                "from camera device is not available. Please select another one from "
1362                                                "camera configuration dialog."));
1363                 return;
1364             }
1365 
1366             pAlbum = pa;
1367         }
1368         else
1369         {
1370             AlbumList list = man->currentAlbums();
1371             int albumId    = 0;
1372 
1373             if (!list.isEmpty())
1374             {
1375                 albumId = group.readEntry(d->configLastTargetAlbum, list.first()->globalID());
1376             }
1377 
1378             album = man->findAlbum(albumId);
1379 
1380             if (album && album->type() != Album::PHYSICAL)
1381             {
1382                 album = nullptr;
1383             }
1384 
1385             QString header(i18nc("@info", "Please select the destination album from the digiKam library to "
1386                                  "import the camera pictures into."));
1387 
1388             album  = AlbumSelectDialog::selectAlbum(this, dynamic_cast<PAlbum*>(album), header);
1389             pAlbum = dynamic_cast<PAlbum*>(album);
1390 
1391             if (!pAlbum)
1392             {
1393                 qCDebug(DIGIKAM_IMPORTUI_LOG) << "Destination Album is null";
1394                 return;
1395             }
1396 
1397             group.writeEntry(d->configLastTargetAlbum, album->globalID());
1398         }
1399     }
1400     else
1401     {
1402         pAlbum = dynamic_cast<PAlbum*>(album);
1403     }
1404 
1405     if (!pAlbum)
1406     {
1407         qCDebug(DIGIKAM_IMPORTUI_LOG) << "Destination Album is null";
1408         return;
1409     }
1410 
1411     CollectionLocation cl = CollectionManager::instance()->locationForAlbumRootId(pAlbum->albumRootId());
1412 
1413     if (!cl.isAvailable() || cl.isNull())
1414     {
1415         QMessageBox::information(this, qApp->applicationName(),
1416                                  i18nc("@info", "Collection selected as the destination album to download "
1417                                        "from the camera device is not available. Please select another "
1418                                        "destination album."));
1419         return;
1420     }
1421 
1422     // -- Check disk space ------------------------
1423     // See bug #139519: Always check free space available before to
1424     // download items selection from camera.
1425 
1426     if (!checkDiskSpace(pAlbum))
1427     {
1428         return;
1429     }
1430 
1431     // -- Prepare and download camera items ------------------------
1432     // Since we show camera items in reverse order, downloading need to be done also in reverse order.
1433 
1434     downloadCameraItems(pAlbum, onlySelected, deleteAfter);
1435 }
1436 
1437 void ImportUI::slotDownloaded(const QString& folder, const QString& file, const QString& temp, int status)
1438 {
1439     if (status == CamItemInfo::DownloadedYes)
1440     {
1441         QFileInfo tempInfo(temp);
1442         QUrl downloadUrl       = QUrl::fromLocalFile(tempInfo.path());
1443         QScopedPointer<DMetadata> metadata(new DMetadata(temp));
1444         QDateTime creationDate = metadata->getItemDateTime();
1445 
1446         if (!creationDate.isValid())
1447         {
1448             creationDate = tempInfo.birthTime();
1449 
1450             if (!creationDate.isValid())
1451             {
1452                 creationDate = tempInfo.lastModified();
1453             }
1454         }
1455 
1456         if (!createSubAlbums(downloadUrl, tempInfo.suffix(), creationDate))
1457         {
1458             downloadUrl = QUrl::fromLocalFile(tempInfo.path());
1459         }
1460 
1461         QString dest = downloadUrl.toLocalFile() + QLatin1Char('/') + tempInfo.fileName();
1462 
1463         if (DMetadata::hasSidecar(temp))
1464         {
1465             QString sctemp = DMetadata::sidecarPath(temp);
1466             QString scdest = DMetadata::sidecarPath(dest);
1467 
1468             if (!DFileOperations::renameFile(sctemp, scdest))
1469             {
1470                 slotLogMsg(xi18n("Failed to move sidecar file for <filename>%1</filename>", tempInfo.fileName()),
1471                                  DHistoryView::ErrorEntry);
1472             }
1473         }
1474 
1475         if (!DFileOperations::renameFile(temp, dest))
1476         {
1477             slotLogMsg(xi18n("Failed to move file for <filename>%1</filename>", tempInfo.fileName()),
1478                              DHistoryView::ErrorEntry);
1479         }
1480 
1481         d->downloadedItemList << dest;
1482         d->downloadedDateHash.insert(dest, creationDate);
1483         d->downloadedInfoHash.insert(dest, qMakePair(folder, file));
1484 
1485         if (!d->foldersToScan.contains(downloadUrl.toLocalFile()))
1486         {
1487             d->foldersToScan << downloadUrl.toLocalFile();
1488         }
1489     }
1490 
1491     if ((status == CamItemInfo::DownloadedYes) ||
1492         (status == CamItemInfo::DownloadFailed))
1493     {
1494         int curr = d->statusProgressBar->progressValue();
1495         d->statusProgressBar->setProgressValue(curr + 1);
1496     }
1497 
1498     CamItemInfo& info = d->view->camItemInfoRef(folder, file);
1499 
1500     if (!info.isNull())
1501     {
1502         setDownloaded(info, status);
1503 
1504         bool previewItems = ImportSettings::instance()->getPreviewItemsWhileDownload();
1505 
1506         if (status == CamItemInfo::DownloadStarted && previewItems)
1507         {
1508             Q_EMIT signalPreviewRequested(info, true);
1509         }
1510 
1511         if (d->rightSideBar->url() == info.url())
1512         {
1513             updateRightSideBar(info);
1514         }
1515 
1516         if (info.downloaded == CamItemInfo::DownloadedYes)
1517         {
1518             CoreDbDownloadHistory::setDownloaded(QString::fromUtf8(d->controller->cameraMD5ID()),
1519                                                  info.name,
1520                                                  info.size,
1521                                                  info.ctime);
1522         }
1523     }
1524 
1525     // Download all items is complete ?
1526 
1527     if (d->statusProgressBar->progressValue() == d->statusProgressBar->progressTotalSteps())
1528     {
1529         if (d->deleteAfter)
1530         {
1531             // No need passive pop-up here, because we will ask to confirm items deletion with dialog.
1532 
1533             QTimer::singleShot(0, this, SLOT(slotDeleteAfterDownload()));
1534         }
1535 
1536         postProcessAfterDownload();
1537     }
1538 }
1539 
1540 void ImportUI::slotMarkAsDownloaded()
1541 {
1542     Q_FOREACH (const CamItemInfo& info, d->view->selectedCamItemInfos())
1543     {
1544         setDownloaded(d->view->camItemInfoRef(info.folder, info.name), CamItemInfo::DownloadedYes);
1545 
1546         CoreDbDownloadHistory::setDownloaded(QString::fromUtf8(d->controller->cameraMD5ID()),
1547                                              info.name,
1548                                              info.size,
1549                                              info.ctime);
1550     }
1551 }
1552 
1553 void ImportUI::slotToggleLock()
1554 {
1555     const CamItemInfoList& list = d->view->selectedCamItemInfos();
1556     int count                   = list.count();
1557 
1558     if (count > 0)
1559     {
1560         d->statusProgressBar->setProgressValue(0);
1561         d->statusProgressBar->setProgressTotalSteps(count);
1562         d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode);
1563     }
1564 
1565     Q_FOREACH (const CamItemInfo& info, list)
1566     {
1567         QString folder = info.folder;
1568         QString file   = info.name;
1569         int writePerm  = info.writePermissions;
1570         bool lock      = true;
1571 
1572         // If item is currently locked, unlock it.
1573 
1574         if (writePerm == 0)
1575         {
1576             lock = false;
1577         }
1578 
1579         d->controller->lockFile(folder, file, lock);
1580     }
1581 }
1582 
1583 void ImportUI::slotLocked(const QString& folder, const QString& file, bool status)
1584 {
1585     if (status)
1586     {
1587         CamItemInfo& info = d->view->camItemInfoRef(folder, file);
1588 
1589         if (!info.isNull())
1590         {
1591             toggleLock(info);
1592 
1593             if (d->rightSideBar->url() == info.url())
1594             {
1595                 updateRightSideBar(info);
1596             }
1597         }
1598     }
1599 
1600     int curr = d->statusProgressBar->progressValue();
1601     d->statusProgressBar->setProgressValue(curr + 1);
1602 }
1603 
1604 void ImportUI::slotUpdateRenamePreview()
1605 {
1606     const CamItemInfoList& list = d->view->selectedCamItemInfos();
1607 
1608     if (list.isEmpty())
1609     {
1610        d->renameCustomizer->setPreviewText(QString());
1611 
1612        return;
1613     }
1614 
1615     const CamItemInfo& info   = list.constFirst();
1616     DownloadSettings settings = downloadSettings();
1617 
1618     if (info.isNull())
1619     {
1620         d->renameCustomizer->setPreviewText(QString());
1621 
1622         return;
1623     }
1624 
1625     QString newName = info.name;
1626 
1627     if (d->renameCustomizer->useDefault())
1628     {
1629         newName = d->renameCustomizer->newName(info.name);
1630     }
1631     else if (d->renameCustomizer->isEnabled())
1632     {
1633         newName = d->renameCustomizer->newName(info.url().toLocalFile());
1634     }
1635 
1636     if (settings.convertJpeg && info.mime == QLatin1String("image/jpeg"))
1637     {
1638         QFileInfo     fi(newName);
1639         QString ext = fi.suffix();
1640 
1641         if (!ext.isEmpty())
1642         {
1643             if (ext[0].isUpper() && ext[ext.length()-1].isUpper())
1644             {
1645                 ext = settings.losslessFormat.toUpper();
1646             }
1647             else if (ext[0].isUpper())
1648             {
1649                 ext    = settings.losslessFormat.toLower();
1650                 ext[0] = ext[0].toUpper();
1651             }
1652             else
1653             {
1654                 ext = settings.losslessFormat.toLower();
1655             }
1656 
1657             newName = fi.completeBaseName() + QLatin1Char('.') + ext;
1658         }
1659         else
1660         {
1661             newName = newName + QLatin1Char('.') + settings.losslessFormat.toLower();
1662         }
1663     }
1664     else if (settings.convertDng && info.mime == QLatin1String("image/x-raw"))
1665     {
1666         QFileInfo     fi(newName);
1667         QString ext = fi.suffix();
1668 
1669         if (!ext.isEmpty())
1670         {
1671             if (ext[0].isUpper() && (ext[ext.length()-1].isUpper() || ext[ext.length()-1].isDigit()))
1672             {
1673                 ext = QLatin1String("DNG");
1674             }
1675             else if (ext[0].isUpper())
1676             {
1677                 ext = QLatin1String("Dng");
1678             }
1679             else
1680             {
1681                 ext = QLatin1String("dng");
1682             }
1683 
1684             newName = fi.completeBaseName() + QLatin1Char('.') + ext;
1685         }
1686         else
1687         {
1688             newName = newName + QLatin1Char('.') + QLatin1String("dng");
1689         }
1690     }
1691 
1692     CamItemInfo& refInfo = d->view->camItemInfoRef(info.folder, info.name);
1693 
1694     if (!refInfo.isNull())
1695     {
1696         d->renameCustomizer->setPreviewText(newName);
1697         refInfo.downloadName = newName;
1698     }
1699 }
1700 
1701 // FIXME: the new pictures are marked by CameraHistoryUpdater which is not working yet.
1702 
1703 void ImportUI::slotSelectNew()
1704 {
1705     CamItemInfoList toBeSelected;
1706 
1707     Q_FOREACH (const CamItemInfo& info, d->view->allItems())
1708     {
1709         if (info.downloaded == CamItemInfo::DownloadedNo)
1710         {
1711             toBeSelected << info;
1712         }
1713     }
1714 
1715     d->view->setSelectedCamItemInfos(toBeSelected);
1716 }
1717 
1718 void ImportUI::slotSelectLocked()
1719 {
1720     CamItemInfoList toBeSelected;
1721 
1722     Q_FOREACH (const CamItemInfo& info, d->view->allItems())
1723     {
1724         if (info.writePermissions == 0)
1725         {
1726             toBeSelected << info;
1727         }
1728     }
1729 
1730     d->view->setSelectedCamItemInfos(toBeSelected);
1731 }
1732 
1733 void ImportUI::toggleLock(CamItemInfo& info)
1734 {
1735     if (!info.isNull())
1736     {
1737         if (info.writePermissions == 0)
1738         {
1739             info.writePermissions = 1;
1740         }
1741         else
1742         {
1743             info.writePermissions = 0;
1744         }
1745     }
1746 }
1747 
1748 // TODO is this really necessary? why not just use the folders from listfolders call?
1749 
1750 QMap<QString, int> ImportUI::countItemsByFolders() const
1751 {
1752     QString                      path;
1753     QMap<QString, int>           map;
1754     QMap<QString, int>::iterator it;
1755 
1756     Q_FOREACH (const CamItemInfo& info, d->view->allItems())
1757     {
1758         path = info.folder;
1759 
1760         if (!path.isEmpty() && path.endsWith(QLatin1Char('/')))
1761         {
1762             path.truncate(path.length() - 1);
1763         }
1764 
1765         it = map.find(path);
1766 
1767         if (it == map.end())
1768         {
1769             map.insert(path, 1);
1770         }
1771         else
1772         {
1773             it.value() ++;
1774         }
1775     }
1776 
1777     return map;
1778 }
1779 
1780 void ImportUI::setDownloaded(CamItemInfo& itemInfo, int status)
1781 {
1782     itemInfo.downloaded = status;
1783     d->progressValue    = 0;
1784 
1785     if (itemInfo.downloaded == CamItemInfo::DownloadStarted)
1786     {
1787         d->progressTimer->start(500);
1788     }
1789     else
1790     {
1791         d->progressTimer->stop();
1792     }
1793 }
1794 
1795 void ImportUI::slotProgressTimerDone()
1796 {
1797     d->progressTimer->start(300);
1798 }
1799 
1800 void ImportUI::itemsSelectionSizeInfo(qint64& fSizeBytes, qint64& dSizeBytes)
1801 {
1802     fSizeBytes = 0;  // Files size
1803     dSizeBytes = 0;  // Estimated space requires to download and process files.
1804 
1805     const QList<QUrl>& selected = d->view->selectedUrls();
1806     DownloadSettings settings   = downloadSettings();
1807 
1808     Q_FOREACH (const CamItemInfo& info, d->view->allItems())
1809     {
1810         if (selected.contains(info.url()))
1811         {
1812             qint64 size = info.size;
1813 
1814             if (size < 0) // -1 if size is not provided by camera
1815             {
1816                 continue;
1817             }
1818 
1819             fSizeBytes += size;
1820 
1821             if (info.mime == QLatin1String("image/jpeg"))
1822             {
1823                 if (settings.convertJpeg)
1824                 {
1825                     // Estimated size is around 5 x original size when JPEG=>PNG.
1826 
1827                     dSizeBytes += size * 5;
1828                 }
1829                 else if (settings.autoRotate)
1830                 {
1831                     // We need a double size to perform rotation.
1832 
1833                     dSizeBytes += size * 2;
1834                 }
1835                 else
1836                 {
1837                     // Real file size is added.
1838 
1839                     dSizeBytes += size;
1840                 }
1841             }
1842             else if (settings.convertDng && info.mime == QLatin1String("image/x-raw"))
1843             {
1844                 // Estimated size is around 2 x original size when RAW=>DNG.
1845 
1846                 dSizeBytes += size * 2;
1847             }
1848             else
1849             {
1850                 dSizeBytes += size;
1851             }
1852 
1853         }
1854     }
1855 }
1856 
1857 void ImportUI::checkItem4Deletion(const CamItemInfo& info, QStringList& folders, QStringList& files,
1858                                   CamItemInfoList& deleteList, CamItemInfoList& lockedList)
1859 {
1860     if (info.writePermissions != 0)  // Item not locked ?
1861     {
1862         QString folder = info.folder;
1863         QString file   = info.name;
1864         folders.append(folder);
1865         files.append(file);
1866         deleteList.append(info);
1867     }
1868     else
1869     {
1870         lockedList.append(info);
1871     }
1872 }
1873 
1874 void ImportUI::deleteItems(bool onlySelected, bool onlyDownloaded)
1875 {
1876     QStringList     folders;
1877     QStringList     files;
1878     CamItemInfoList deleteList;
1879     CamItemInfoList lockedList;
1880     const CamItemInfoList& list = onlySelected ? d->view->selectedCamItemInfos() : d->view->allItems();
1881 
1882     Q_FOREACH (const CamItemInfo& info, list)
1883     {
1884         if (onlyDownloaded)
1885         {
1886             if (info.downloaded == CamItemInfo::DownloadedYes)
1887             {
1888                 checkItem4Deletion(info, folders, files, deleteList, lockedList);
1889             }
1890         }
1891         else
1892         {
1893             checkItem4Deletion(info, folders, files, deleteList, lockedList);
1894         }
1895     }
1896 
1897     // If we want to delete some locked files, just give a feedback to user.
1898 
1899     if (!lockedList.isEmpty())
1900     {
1901         QString infoMsg(i18nc("@info", "The items listed below are locked by camera (read-only). "
1902                               "These items will not be deleted. If you really want to delete these items, "
1903                               "please unlock them and try again."));
1904         CameraMessageBox::informationList(d->camThumbsCtrl, this, i18nc("@title", "Information"), infoMsg, lockedList);
1905     }
1906 
1907     if (folders.isEmpty())
1908     {
1909         return;
1910     }
1911 
1912     QString warnMsg(i18ncp("@info", "About to delete this image.\n"
1913                            "Deleted file is unrecoverable.\n"
1914                            "Are you sure?",
1915                            "About to delete these %1 images.\n"
1916                            "Deleted files are unrecoverable.\n"
1917                            "Are you sure?",
1918                            deleteList.count()));
1919 
1920     if (CameraMessageBox::warningContinueCancelList(d->camThumbsCtrl,
1921                                                     this,
1922                                                     i18nc("@title: confirm delete items dialog", "Warning"),
1923                                                     warnMsg,
1924                                                     deleteList,
1925                                                     QLatin1String("DontAskAgainToDeleteItemsFromCamera"))
1926         ==  QMessageBox::Yes)
1927     {
1928         QStringList::const_iterator itFolder = folders.constBegin();
1929         QStringList::const_iterator itFile   = files.constBegin();
1930 
1931         d->statusProgressBar->setProgressValue(0);
1932         d->statusProgressBar->setProgressTotalSteps(deleteList.count());
1933         d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode);
1934 
1935         // enable cancel action.
1936 
1937         d->cameraCancelAction->setEnabled(true);
1938 
1939         for ( ; itFolder != folders.constEnd() ; ++itFolder, ++itFile)
1940         {
1941             d->controller->deleteFile(*itFolder, *itFile);
1942 
1943             // the currentlyDeleting list is used to prevent loading items which
1944             // will immanently be deleted into the sidebar and wasting time
1945 
1946             d->currentlyDeleting.append(*itFolder + *itFile);
1947         }
1948     }
1949 }
1950 
1951 bool ImportUI::checkDiskSpace(PAlbum *pAlbum)
1952 {
1953     if (!pAlbum)
1954     {
1955         return false;
1956     }
1957 
1958     qint64 fSizeBytes = 0;
1959     qint64 dSizeBytes = 0;
1960     itemsSelectionSizeInfo(fSizeBytes, dSizeBytes);
1961     QString albumRootPath = pAlbum->albumRootPath();
1962     qint64 bytesAvail     = d->albumLibraryFreeSpace->bytesAvail(albumRootPath);
1963 
1964     if (dSizeBytes >= bytesAvail)
1965     {
1966         int result = QMessageBox::warning(this, i18nc("@title:window", "Insufficient Disk Space"),
1967                                           i18nc("@info", "There is not enough free space on the disk of the album you selected "
1968                                                 "to download and process the selected pictures from the camera.\n\n"
1969                                                 "Estimated space required: %1\n"
1970                                                 "Available free space: %2\n\n"
1971                                                 "Try Anyway?",
1972                                                 ItemPropertiesTab::humanReadableBytesCount(dSizeBytes),
1973                                                 ItemPropertiesTab::humanReadableBytesCount(bytesAvail)),
1974                                           QMessageBox::Yes | QMessageBox::No);
1975 
1976         if (result == QMessageBox::No)
1977         {
1978             return false;
1979         }
1980     }
1981 
1982     return true;
1983 }
1984 
1985 bool ImportUI::downloadCameraItems(PAlbum* pAlbum, bool onlySelected, bool deleteAfter)
1986 {
1987     const QList<QUrl>& selected   = d->view->selectedUrls();
1988     DownloadSettings settings     = downloadSettings();
1989     QUrl url                      = pAlbum->fileUrl();
1990     DownloadSettingsList allItems;
1991 
1992     // -- Download camera items -------------------------------
1993 
1994     Q_FOREACH (const CamItemInfo& info, d->view->allItems())
1995     {
1996         if (onlySelected && !selected.contains(info.url()))
1997         {
1998             continue;
1999         }
2000 
2001         settings.folder     = info.folder;
2002         settings.file       = info.name;
2003         settings.mime       = info.mime;
2004         settings.pickLabel  = info.pickLabel;
2005         settings.colorLabel = info.colorLabel;
2006         settings.rating     = info.rating;
2007         settings.dest       = url.toLocalFile();
2008 
2009         allItems.append(settings);
2010     }
2011 
2012     if (allItems.isEmpty())
2013     {
2014         return false;
2015     }
2016 
2017     d->lastDestURL = url;
2018     d->statusProgressBar->setNotify(true);
2019     d->statusProgressBar->setProgressValue(0);
2020     d->statusProgressBar->setProgressTotalSteps(allItems.count());
2021     d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode);
2022 
2023     // enable cancel action.
2024 
2025     d->cameraCancelAction->setEnabled(true);
2026 
2027     // disable settings tab here instead of slotBusy:
2028     // Only needs to be disabled while downloading
2029 
2030     d->advBox->setEnabled(false);
2031     d->view->setEnabled(false);
2032 
2033     d->deleteAfter = deleteAfter;
2034 
2035     d->downloadedItemList.clear();
2036     d->downloadedDateHash.clear();
2037     d->downloadedInfoHash.clear();
2038     d->foldersToScan.clear();
2039 
2040     d->controller->download(allItems);
2041 
2042     return true;
2043 }
2044 
2045 bool ImportUI::createSubAlbums(QUrl& downloadUrl, const QString& suffix, const QDateTime& dateTime)
2046 {
2047     bool success = true;
2048 
2049     if (d->albumCustomizer->autoAlbumDateEnabled())
2050     {
2051         success &= createDateBasedSubAlbum(downloadUrl, dateTime);
2052     }
2053 
2054     if (d->albumCustomizer->autoAlbumExtEnabled())
2055     {
2056         success &= createExtBasedSubAlbum(downloadUrl, suffix, dateTime.date());
2057     }
2058 
2059     return success;
2060 }
2061 
2062 bool ImportUI::createSubAlbum(QUrl& downloadUrl, const QString& subalbum, const QDate& date)
2063 {
2064     QString errMsg;
2065 
2066     if (!createAutoAlbum(downloadUrl, subalbum, date, errMsg))
2067     {
2068         slotLogMsg(errMsg, DHistoryView::ErrorEntry);
2069 
2070         return false;
2071     }
2072 
2073     downloadUrl = downloadUrl.adjusted(QUrl::StripTrailingSlash);
2074     downloadUrl.setPath(downloadUrl.path() + QLatin1Char('/') + subalbum);
2075 
2076     return true;
2077 }
2078 
2079 bool ImportUI::createDateBasedSubAlbum(QUrl& downloadUrl, const QDateTime& dateTime)
2080 {
2081     QString dirName;
2082 
2083     switch (d->albumCustomizer->folderDateFormat())
2084     {
2085         case AlbumCustomizer::TextDateFormat:
2086             dirName = dateTime.date().toString(Qt::TextDate);
2087             break;
2088 
2089         case AlbumCustomizer::LocalDateFormat:
2090             dirName = QLocale().toString(dateTime, QLocale::ShortFormat);
2091             break;
2092 
2093         case AlbumCustomizer::IsoDateFormat:
2094             dirName = dateTime.date().toString(Qt::ISODate);
2095             break;
2096 
2097         default:        // Custom
2098             dirName = dateTime.date().toString(d->albumCustomizer->customDateFormat());
2099             break;
2100     }
2101 
2102     return createSubAlbum(downloadUrl, dirName, dateTime.date());
2103 }
2104 
2105 bool ImportUI::createExtBasedSubAlbum(QUrl& downloadUrl, const QString& suffix, const QDate& date)
2106 {
2107     // We use the target file suffix to compute sub-albums name to take a care about
2108     // conversion on the fly option.
2109 
2110     QString subAlbum = suffix.toUpper();
2111 
2112     if      (
2113              (subAlbum == QLatin1String("JPEG")) ||
2114              (subAlbum == QLatin1String("JPE"))
2115             )
2116     {
2117         subAlbum = QLatin1String("JPG");
2118     }
2119     else if (subAlbum == QLatin1String("TIFF"))
2120     {
2121         subAlbum = QLatin1String("TIF");
2122     }
2123     else if (
2124              (subAlbum == QLatin1String("MPEG")) ||
2125              (subAlbum == QLatin1String("MPE"))  ||
2126              (subAlbum == QLatin1String("MTS"))
2127             )
2128     {
2129         subAlbum = QLatin1String("MPG");
2130     }
2131 
2132     return createSubAlbum(downloadUrl, subAlbum, date);
2133 }
2134 
2135 void ImportUI::slotDeleteAfterDownload()
2136 {
2137     deleteItems(true, true);
2138 }
2139 
2140 void ImportUI::slotDeleteSelected()
2141 {
2142     deleteItems(true, false);
2143 }
2144 
2145 void ImportUI::slotDeleteNew()
2146 {
2147     slotSelectNew();
2148     QTimer::singleShot(0, this, SLOT(slotDeleteSelected()));
2149 }
2150 
2151 void ImportUI::slotDeleteAll()
2152 {
2153     deleteItems(false, false);
2154 }
2155 
2156 void ImportUI::slotDeleted(const QString& folder, const QString& file, bool status)
2157 {
2158     if (status)
2159     {
2160         // do this after removeItem.
2161 
2162         d->currentlyDeleting.removeAll(folder + file);
2163     }
2164 
2165     int curr = d->statusProgressBar->progressValue();
2166     d->statusProgressBar->setProgressValue(curr + 1);
2167     refreshFreeSpace();
2168 }
2169 
2170 void ImportUI::slotMetadata(const QString& folder, const QString& file, const MetaEngineData& data)
2171 {
2172     CamItemInfo info = d->view->camItemInfo(folder, file);
2173 
2174     if (!info.isNull())
2175     {
2176         QScopedPointer<DMetadata> meta(new DMetadata);
2177         meta.data()->setData(data);
2178         d->rightSideBar->itemChanged(info, *meta);
2179     }
2180 }
2181 
2182 void ImportUI::slotNewSelection(bool hasSelection)
2183 {
2184     updateActions();
2185 
2186     const CamItemInfoList& list = d->view->selectedCamItemInfos();
2187 
2188     if (hasSelection && !list.isEmpty())
2189     {
2190         QList<ParseSettings> renameFiles;
2191         const CamItemInfo& info = list.constFirst();
2192 
2193         ParseSettings parseSettings;
2194 
2195         parseSettings.fileUrl      = info.url();
2196         parseSettings.creationTime = info.ctime;
2197         renameFiles.append(parseSettings);
2198 
2199         d->renameCustomizer->renameManager()->reset();
2200         d->renameCustomizer->renameManager()->addFiles(renameFiles);
2201         d->renameCustomizer->renameManager()->parseFiles();
2202 
2203         slotUpdateRenamePreview();
2204     }
2205     else
2206     {
2207         d->renameCustomizer->renameManager()->reset();
2208         d->renameCustomizer->setPreviewText(QString());
2209     }
2210 
2211     qint64 fSizeBytes = 0;
2212     qint64 dSizeBytes = 0;
2213     itemsSelectionSizeInfo(fSizeBytes, dSizeBytes);
2214     d->albumLibraryFreeSpace->setEstimatedDSizeBytes(dSizeBytes);
2215 }
2216 
2217 void ImportUI::slotImageSelected(const CamItemInfoList& selection, const CamItemInfoList& listAll)
2218 {
2219     if (d->cameraCancelAction->isEnabled())
2220     {
2221         return;
2222     }
2223 
2224     int num_images = listAll.count();
2225 
2226     switch (selection.count())
2227     {
2228         case 0:
2229         {
2230             d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
2231                                                      i18ncp("@info:status",
2232                                                             "No item selected (%1 item)",
2233                                                             "No item selected (%1 items)",
2234                                                             num_images));
2235 
2236             d->rightSideBar->slotNoCurrentItem();
2237             break;
2238         }
2239 
2240         case 1:
2241         {
2242             // if selected item is in the list of item which will be deleted, set no current item
2243 
2244             if (!d->currentlyDeleting.contains(selection.first().folder + selection.first().name))
2245             {
2246                 updateRightSideBar(selection.first());
2247 
2248                 int index = listAll.indexOf(selection.first()) + 1;
2249 
2250                 d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
2251                                                          i18nc("@info:status Filename of first selected item of number of items",
2252                                                                "\"%1\" (%2 of %3)",
2253                                                                selection.first().url().fileName(), index, num_images));
2254             }
2255             else
2256             {
2257                 d->rightSideBar->slotNoCurrentItem();
2258                 d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
2259                                                          i18ncp("@info:status",
2260                                                                 "No item selected (%1 item)",
2261                                                                 "No item selected (%1 items)",
2262                                                                 num_images));
2263             }
2264 
2265             break;
2266         }
2267 
2268         default:
2269         {
2270             d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode,
2271                                                      i18ncp("@info:status", "%2/%1 item selected",
2272                                                             "%2/%1 items selected",
2273                                                             num_images, selection.count()));
2274             break;
2275         }
2276     }
2277 }
2278 
2279 void ImportUI::updateRightSideBar(const CamItemInfo& info)
2280 {
2281     d->rightSideBar->itemChanged(info, DMetadata());
2282 
2283     if (!d->busy)
2284     {
2285         d->controller->getMetadata(info.folder, info.name);
2286     }
2287 }
2288 
2289 QString ImportUI::identifyCategoryforMime(const QString& mime)
2290 {
2291     return mime.split(QLatin1Char('/')).at(0);
2292 }
2293 
2294 void ImportUI::postProcessAfterDownload()
2295 {
2296     if (d->downloadedItemList.isEmpty())
2297     {
2298         return;
2299     }
2300 
2301     KSharedConfig::Ptr config              = KSharedConfig::openConfig();
2302     KConfigGroup group                     = config->group(d->configGroupName);
2303     SetupCamera::ConflictRule conflictRule = (SetupCamera::ConflictRule)group.readEntry(d->configFileSaveConflictRule,
2304                                                                                         (int)SetupCamera::DIFFNAME);
2305 
2306     // Is auto-rotate option checked?
2307 
2308     bool autoRotate = downloadSettings().autoRotate;
2309     QList<ParseSettings> renameFiles;
2310     QStringList renamedItemsList;
2311 
2312     Q_FOREACH (const QString& srcFile, d->downloadedItemList)
2313     {
2314         ParseSettings parseSettings;
2315 
2316         parseSettings.fileUrl      = QUrl::fromLocalFile(srcFile);
2317         parseSettings.creationTime = d->downloadedDateHash.value(srcFile);
2318         renameFiles.append(parseSettings);
2319     }
2320 
2321     d->renameCustomizer->renameManager()->reset();
2322     d->renameCustomizer->renameManager()->setCutFileName(39);
2323     d->renameCustomizer->renameManager()->addFiles(renameFiles);
2324     d->renameCustomizer->renameManager()->parseFiles();
2325 
2326     Q_FOREACH (const QString& srcFile, d->downloadedItemList)
2327     {
2328         QFileInfo srcInfo(srcFile);
2329 
2330         QString newName;
2331         QString orgName = srcInfo.fileName().mid(39);
2332 
2333         if (d->renameCustomizer->useDefault())
2334         {
2335             newName = d->renameCustomizer->newName(orgName);
2336         }
2337         else
2338         {
2339             newName = d->renameCustomizer->newName(srcFile);
2340         }
2341 
2342         if (newName == srcInfo.fileName())
2343         {
2344             newName = orgName;
2345         }
2346 
2347         QString dstFile = srcInfo.path() + QLatin1Char('/') + newName;
2348         QFileInfo dstInfo(dstFile);
2349 
2350         if      (dstInfo.exists() && (conflictRule == SetupCamera::SKIPFILE))
2351         {
2352             QFile::remove(srcFile);
2353 
2354             slotLogMsg(xi18n("Skipped file <filename>%1</filename>", dstInfo.fileName()),
2355                        DHistoryView::WarningEntry);
2356 
2357             QPair<QString, QString> fPair = d->downloadedInfoHash.value(srcFile);
2358             CamItemInfo& info             = d->view->camItemInfoRef(fPair.first,
2359                                                                     fPair.second);
2360 
2361             if (!info.isNull())
2362             {
2363                 setDownloaded(info, CamItemInfo::DownloadedNo);
2364             }
2365 
2366             continue;
2367         }
2368         else if (conflictRule != SetupCamera::OVERWRITE)
2369         {
2370             bool newurl = false;
2371             dstFile     = DFileOperations::getUniqueFileUrl(QUrl::fromLocalFile(dstFile), &newurl).toLocalFile();
2372             dstInfo     = QFileInfo(dstFile);
2373 
2374             if (newurl)
2375             {
2376                 slotLogMsg(xi18n("Rename file to <filename>%1</filename>", dstInfo.fileName()),
2377                                  DHistoryView::WarningEntry);
2378             }
2379         }
2380 
2381         // move the file to the destination file
2382 
2383         if (DMetadata::hasSidecar(srcFile))
2384         {
2385             QString sctemp = DMetadata::sidecarPath(srcFile);
2386             QString scdest = DMetadata::sidecarPath(dstFile);
2387 
2388             qCDebug(DIGIKAM_IMPORTUI_LOG) << "File" << sctemp << " has a sidecar, renaming it to " << scdest;
2389 
2390             // remove scdest file if it exist
2391 
2392             if ((sctemp != scdest) && QFile::exists(sctemp) && QFile::exists(scdest))
2393             {
2394                 QFile::remove(scdest);
2395             }
2396 
2397             if (!DFileOperations::renameFile(sctemp, scdest))
2398             {
2399                 slotLogMsg(xi18n("Failed to save sidecar file for <filename>%1</filename>", dstInfo.fileName()),
2400                            DHistoryView::ErrorEntry);
2401             }
2402         }
2403 
2404         // remove dest file if it exist
2405 
2406         if ((srcFile != dstFile) && QFile::exists(srcFile) && QFile::exists(dstFile))
2407         {
2408             QFile::remove(dstFile);
2409         }
2410 
2411         if (!DFileOperations::renameFile(srcFile, dstFile))
2412         {
2413             qCDebug(DIGIKAM_IMPORTUI_LOG) << "Renaming " << srcFile << " to " << dstFile << " failed";
2414 
2415             // rename failed. delete the temp file
2416 
2417             QFile::remove(srcFile);
2418 
2419             slotLogMsg(xi18n("Failed to download <filename>%1</filename>", dstInfo.fileName()),
2420                        DHistoryView::ErrorEntry);
2421         }
2422         else
2423         {
2424             renamedItemsList << dstFile;
2425         }
2426     }
2427 
2428     NewItemsFinder* const tool = new NewItemsFinder(NewItemsFinder::ScheduleCollectionScan, d->foldersToScan);
2429     tool->start();
2430 
2431     d->foldersToScan.clear();
2432     d->downloadedItemList.clear();
2433     d->downloadedDateHash.clear();
2434     d->downloadedInfoHash.clear();
2435 
2436     // Pop-up a notification to inform user when all is done,
2437     // and inform if auto-rotation will take place.
2438 
2439     if (autoRotate)
2440     {
2441         d->waitAutoRotate = true;
2442 
2443         connect(tool, &NewItemsFinder::signalComplete,
2444                 this, [=]()
2445             {
2446                 ItemInfoList infoList;
2447 
2448                 Q_FOREACH (const QString& dstFile, renamedItemsList)
2449                 {
2450                     ItemInfo itemInfo = ItemInfo::fromLocalFile(dstFile);
2451 
2452                     if (itemInfo.format() == QLatin1String("JPG"))
2453                     {
2454                         infoList << itemInfo;
2455                     }
2456                 }
2457 
2458                 if (!infoList.isEmpty())
2459                 {
2460                     FileActionMngr::instance()->transform(infoList, MetaEngineRotation::NoTransformation);
2461                 }
2462 
2463                 if (d->waitAutoRotate)
2464                 {
2465                     d->waitAutoRotate = false;
2466                 }
2467                 else
2468                 {
2469                     close();
2470                 }
2471             }
2472         );
2473 
2474         DNotificationWrapper(QLatin1String("cameradownloaded"),
2475                              i18nc("@info Popup notification",
2476                                    "Images download finished, you can now detach "
2477                                    "your camera while the images are auto-rotated"),
2478                              this, windowTitle());
2479     }
2480     else
2481     {
2482         DNotificationWrapper(QLatin1String("cameradownloaded"),
2483                              i18nc("@info Popup notification",
2484                                    "Images download finished"),
2485                              this, windowTitle());
2486     }
2487 }
2488 
2489 bool ImportUI::createAutoAlbum(const QUrl& parentURL, const QString& sub,
2490                                const QDate& date, QString& errMsg) const
2491 {
2492     QUrl url(parentURL);
2493     url = url.adjusted(QUrl::StripTrailingSlash);
2494     url.setPath(url.path() + QLatin1Char('/') + sub);
2495 
2496     // first stat to see if the album exists
2497 
2498     QFileInfo info(url.toLocalFile());
2499 
2500     if (info.exists())
2501     {
2502         // now check if its really a directory
2503 
2504         if (info.isDir())
2505         {
2506             return true;
2507         }
2508         else
2509         {
2510             errMsg = i18nc("@info", "A file with the same name (\"%1\") already exists in folder \"%2\".",
2511                            sub, QDir::toNativeSeparators(parentURL.toLocalFile()));
2512             return false;
2513         }
2514     }
2515 
2516     // looks like the directory does not exist, try to create it.
2517     // First we make sure that the parent exists.
2518 
2519     PAlbum* parent = AlbumManager::instance()->findPAlbum(parentURL);
2520 
2521     if (!parent)
2522     {
2523         errMsg = i18nc("@info", "Failed to find Album for path \"%1\".",
2524                        QDir::toNativeSeparators(parentURL.toLocalFile()));
2525         return false;
2526     }
2527 
2528     // Create the album, with any parent albums required for the structure
2529 
2530     QUrl albumUrl(parentURL);
2531 
2532     Q_FOREACH (const QString& folder, sub.split(QLatin1Char('/'), QT_SKIP_EMPTY_PARTS))
2533     {
2534         albumUrl      = albumUrl.adjusted(QUrl::StripTrailingSlash);
2535         albumUrl.setPath(albumUrl.path() + QLatin1Char('/') + folder);
2536 
2537         PAlbum* album = AlbumManager::instance()->findPAlbum(albumUrl);
2538 
2539         if (!album)
2540         {
2541             album = AlbumManager::instance()->createPAlbum(parent, folder, QString(), date, QString(), errMsg);
2542 
2543             if (!album)
2544             {
2545                 return false;
2546             }
2547         }
2548 
2549         parent = album;
2550     }
2551 
2552     return true;
2553 }
2554 
2555 void ImportUI::slotSetup()
2556 {
2557     Setup::execDialog(this);
2558 }
2559 
2560 void ImportUI::slotCameraFreeSpaceInfo(qint64 bytesSize, qint64 bytesAvail)
2561 {
2562     d->cameraFreeSpace->addInformation(bytesSize, bytesSize - bytesAvail, bytesAvail, QString());
2563 }
2564 
2565 bool ImportUI::cameraDeleteSupport() const
2566 {
2567     return d->controller->cameraDeleteSupport();
2568 }
2569 
2570 bool ImportUI::cameraUploadSupport() const
2571 {
2572     return d->controller->cameraUploadSupport();
2573 }
2574 
2575 bool ImportUI::cameraMkDirSupport() const
2576 {
2577     return d->controller->cameraMkDirSupport();
2578 }
2579 
2580 bool ImportUI::cameraDelDirSupport() const
2581 {
2582     return d->controller->cameraDelDirSupport();
2583 }
2584 
2585 bool ImportUI::cameraUseUMSDriver() const
2586 {
2587     return d->controller->cameraDriverType() == DKCamera::UMSDriver;
2588 }
2589 
2590 bool ImportUI::cameraUseGPhotoDriver() const
2591 {
2592     return d->controller->cameraDriverType() == DKCamera::GPhotoDriver;
2593 }
2594 
2595 void ImportUI::enableZoomPlusAction(bool val)
2596 {
2597     d->increaseThumbsAction->setEnabled(val);
2598 }
2599 
2600 void ImportUI::enableZoomMinusAction(bool val)
2601 {
2602     d->decreaseThumbsAction->setEnabled(val);
2603 }
2604 
2605 void ImportUI::slotComponentsInfo()
2606 {
2607     showDigikamComponentsInfo();
2608 }
2609 
2610 void ImportUI::slotDBStat()
2611 {
2612     showDigikamDatabaseStat();
2613 }
2614 
2615 void ImportUI::slotOnlineVersionCheck()
2616 {
2617     Setup::onlineVersionCheck();
2618 }
2619 
2620 void ImportUI::refreshCollectionFreeSpace()
2621 {
2622     d->albumLibraryFreeSpace->setPaths(CollectionManager::instance()->allAvailableAlbumRootPaths());
2623 }
2624 
2625 void ImportUI::slotCollectionLocationStatusChanged(const CollectionLocation&, int)
2626 {
2627     refreshCollectionFreeSpace();
2628 }
2629 
2630 void ImportUI::slotToggleShowBar()
2631 {
2632     showThumbBar(d->showBarAction->isChecked());
2633 }
2634 
2635 void ImportUI::slotLogMsg(const QString& msg, DHistoryView::EntryType type,
2636                           const QString& folder, const QString& file)
2637 {
2638     d->statusProgressBar->setProgressText(msg);
2639     QStringList meta;
2640     meta << folder << file;
2641     d->historyView->addEntry(msg, type, QVariant(meta));
2642 }
2643 
2644 void ImportUI::slotShowLog()
2645 {
2646     d->showLogAction->isChecked() ? d->historyView->show() : d->historyView->hide();
2647 }
2648 
2649 void ImportUI::slotHistoryEntryClicked(const QVariant& metadata)
2650 {
2651     QStringList meta = metadata.toStringList();
2652     QString folder   = meta.at(0);
2653     QString file     = meta.at(1);
2654     d->view->scrollTo(folder, file);
2655 }
2656 
2657 void ImportUI::showSideBars(bool visible)
2658 {
2659     visible ? d->rightSideBar->restore()
2660             : d->rightSideBar->backup();
2661 }
2662 
2663 void ImportUI::slotToggleRightSideBar()
2664 {
2665     d->rightSideBar->isExpanded() ? d->rightSideBar->shrink()
2666                                   : d->rightSideBar->expand();
2667 }
2668 
2669 void ImportUI::slotPreviousRightSideBarTab()
2670 {
2671     d->rightSideBar->activePreviousTab();
2672 }
2673 
2674 void ImportUI::slotNextRightSideBarTab()
2675 {
2676     d->rightSideBar->activeNextTab();
2677 }
2678 
2679 void ImportUI::showThumbBar(bool visible)
2680 {
2681     d->view->toggleShowBar(visible);
2682 }
2683 
2684 bool ImportUI::thumbbarVisibility() const
2685 {
2686     return d->showBarAction->isChecked();
2687 }
2688 
2689 void ImportUI::slotSwitchedToPreview()
2690 {
2691     d->zoomBar->setBarMode(DZoomBar::PreviewZoomCtrl);
2692     d->imageViewSelectionAction->setCurrentAction(d->camItemPreviewAction);
2693     toogleShowBar();
2694 }
2695 
2696 void ImportUI::slotSwitchedToIconView()
2697 {
2698     d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl);
2699     d->imageViewSelectionAction->setCurrentAction(d->iconViewAction);
2700     toogleShowBar();
2701 }
2702 
2703 void ImportUI::slotSwitchedToMapView()
2704 {
2705     d->zoomBar->setBarMode(DZoomBar::ThumbsSizeCtrl);
2706 
2707 #ifdef HAVE_GEOLOCATION
2708 
2709     d->imageViewSelectionAction->setCurrentAction(d->mapViewAction);
2710 
2711 #endif
2712 
2713     toogleShowBar();
2714 }
2715 
2716 void ImportUI::customizedFullScreenMode(bool set)
2717 {
2718     toolBarMenuAction()->setEnabled(!set);
2719     showMenuBarAction()->setEnabled(!set);
2720     showStatusBarAction()->setEnabled(!set);
2721     set ? d->showBarAction->setEnabled(false)
2722         : toogleShowBar();
2723 
2724     d->view->toggleFullScreen(set);
2725 }
2726 
2727 void ImportUI::toogleShowBar()
2728 {
2729     switch (d->view->viewMode())
2730     {
2731         case ImportStackedView::PreviewImageMode:
2732         case ImportStackedView::MediaPlayerMode:
2733             d->showBarAction->setEnabled(true);
2734             break;
2735 
2736         default:
2737             d->showBarAction->setEnabled(false);
2738             break;
2739     }
2740 }
2741 
2742 void ImportUI::slotSetupChanged()
2743 {
2744     d->filterComboBox->updateFilter();
2745     setFilter(d->filterComboBox->currentFilter());
2746     d->view->importFilterModel()->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural());
2747 
2748     // Load full-screen options
2749 
2750     KConfigGroup group = KSharedConfig::openConfig()->group(ApplicationSettings::instance()->generalConfigGroupName());
2751     readFullScreenSettings(group);
2752 
2753     d->view->applySettings();
2754     sidebarTabTitleStyleChanged();
2755 }
2756 
2757 void ImportUI::sidebarTabTitleStyleChanged()
2758 {
2759     d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle());
2760     d->rightSideBar->applySettings();
2761 }
2762 
2763 void ImportUI::slotToggleColorManagedView()
2764 {
2765     if (!IccSettings::instance()->isEnabled())
2766     {
2767         return;
2768     }
2769 
2770     bool cmv = !IccSettings::instance()->settings().useManagedPreviews;
2771     IccSettings::instance()->setUseManagedPreviews(cmv);
2772     d->camThumbsCtrl->clearCache();
2773 }
2774 
2775 void ImportUI::slotColorManagementOptionsChanged()
2776 {
2777     ICCSettingsContainer settings = IccSettings::instance()->settings();
2778 
2779     d->viewCMViewAction->blockSignals(true);
2780     d->viewCMViewAction->setEnabled(settings.enableCM);
2781     d->viewCMViewAction->setChecked(settings.useManagedPreviews);
2782     d->viewCMViewAction->blockSignals(false);
2783 }
2784 
2785 } // namespace Digikam
2786 
2787 #include "moc_importui.cpp"