diff --git a/libs/database/utils/dio.cpp b/libs/database/utils/dio.cpp index b7ff0caae9..1e836d8da8 100644 --- a/libs/database/utils/dio.cpp +++ b/libs/database/utils/dio.cpp @@ -1,552 +1,547 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-05-17 * Description : low level files management interface. * * Copyright (C) 2005 by Renchi Raju * Copyright (C) 2012-2013 by Marcel Wiesweg * Copyright (C) 2015 by Mohamed Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "dio.h" // Qt includes #include // Local includes #include "digikam_debug.h" #include "imageinfo.h" #include "albummanager.h" #include "coredb.h" #include "coredbaccess.h" #include "album.h" #include "dmetadata.h" #include "loadingcacheinterface.h" #include "metadatasettings.h" #include "scancontroller.h" #include "thumbnailloadthread.h" #include "iojobsmanager.h" #include "collectionmanager.h" #include "dnotificationwrapper.h" #include "progressmanager.h" #include "digikamapp.h" #include "iojobdata.h" namespace Digikam { SidecarFinder::SidecarFinder(const QList& files) { process(files); } SidecarFinder::SidecarFinder(const QUrl& file) { process(QList() << file); } void SidecarFinder::process(const QList& files) { foreach(const QUrl& url, files) { if (DMetadata::hasSidecar(url.toLocalFile())) { localFiles << DMetadata::sidecarUrl(url); localFileSuffixes << QLatin1String(".xmp"); qCDebug(DIGIKAM_DATABASE_LOG) << "Detected a sidecar" << localFiles.last(); } foreach(QString suffix, MetadataSettings::instance()->settings().sidecarExtensions) { suffix = QLatin1String(".") + suffix; QString sidecarName = url.toLocalFile() + suffix; if (QFileInfo::exists(sidecarName) && !localFiles.contains(QUrl::fromLocalFile(sidecarName))) { localFiles << QUrl::fromLocalFile(sidecarName); localFileSuffixes << suffix; qCDebug(DIGIKAM_DATABASE_LOG) << "Detected a sidecar" << localFiles.last(); } } localFiles << url; localFileSuffixes << QString(); } } // ------------------------------------------------------------------------------------------------ // TODO // Groups should not be resolved in dio, it should be handled in views. // This is already done for most things except for drag&drop, which is hard :) GroupedImagesFinder::GroupedImagesFinder(const QList& source) { process(source); } void GroupedImagesFinder::process(const QList& source) { QSet ids; foreach(const ImageInfo& info, source) { ids << info.id(); } infos.reserve(source.size()); foreach(const ImageInfo& info, source) { infos << info; if (info.hasGroupedImages()) { foreach(const ImageInfo& groupedImage, info.groupedImages()) { if (ids.contains(groupedImage.id())) { continue; } infos << groupedImage; ids << groupedImage.id(); } } } } // ------------------------------------------------------------------------------------------------ class DIOCreator { public: DIO object; }; Q_GLOBAL_STATIC(DIOCreator, creator) // ------------------------------------------------------------------------------------------------ DIO* DIO::instance() { return &creator->object; } DIO::DIO() { } DIO::~DIO() { } void DIO::cleanUp() { } // Album -> Album ----------------------------------------------------- void DIO::copy(PAlbum* const src, PAlbum* const dest) { if (!src || !dest) { return; } instance()->processJob(new IOJobData(IOJobData::CopyAlbum, src, dest)); } void DIO::move(PAlbum* const src, PAlbum* const dest) { if (!src || !dest) { return; } #ifdef Q_OS_WIN AlbumManager::instance()->removeWatchedPAlbums(src); #endif instance()->processJob(new IOJobData(IOJobData::MoveAlbum, src, dest)); } // Images -> Album ---------------------------------------------------- void DIO::copy(const QList& infos, PAlbum* const dest) { if (!dest) { return; } instance()->processJob(new IOJobData(IOJobData::CopyImage, infos, dest)); } void DIO::move(const QList& infos, PAlbum* const dest) { if (!dest) { return; } instance()->processJob(new IOJobData(IOJobData::MoveImage, infos, dest)); } // External files -> album -------------------------------------------- void DIO::copy(const QUrl& src, PAlbum* const dest) { copy(QList() << src, dest); } void DIO::copy(const QList& srcList, PAlbum* const dest) { if (!dest) { return; } instance()->processJob(new IOJobData(IOJobData::CopyFiles, srcList, dest)); } void DIO::move(const QUrl& src, PAlbum* const dest) { move(QList() << src, dest); } void DIO::move(const QList& srcList, PAlbum* const dest) { if (!dest) { return; } instance()->processJob(new IOJobData(IOJobData::MoveFiles, srcList, dest)); } // Rename -------------------------------------------------------------- void DIO::rename(const ImageInfo& info, const QString& newName) { instance()->processJob(new IOJobData(IOJobData::Rename, info, newName)); } // Delete -------------------------------------------------------------- void DIO::del(const QList& infos, bool useTrash) { instance()->processJob(new IOJobData(useTrash ? IOJobData::Trash : IOJobData::Delete, infos)); } void DIO::del(const ImageInfo& info, bool useTrash) { del(QList() << info, useTrash); } void DIO::del(PAlbum* const album, bool useTrash) { if (!album) { return; } #ifdef Q_OS_WIN AlbumManager::instance()->removeWatchedPAlbums(album); #endif instance()->createJob(new IOJobData(useTrash ? IOJobData::Trash : IOJobData::Delete, QList() << album->fileUrl())); } // ------------------------------------------------------------------------------------------------ void DIO::processJob(IOJobData* const data) { const int operation = data->operation(); if (operation == IOJobData::CopyImage || operation == IOJobData::MoveImage) { // this is a fast db operation, do here GroupedImagesFinder finder(data->imageInfos()); data->setImageInfos(finder.infos); QStringList filenames; QList ids; foreach(const ImageInfo& info, data->imageInfos()) { filenames << info.name(); ids << info.id(); } ScanController::instance()->hintAtMoveOrCopyOfItems(ids, data->destAlbum(), filenames); } else if (operation == IOJobData::CopyAlbum || operation == IOJobData::MoveAlbum) { ScanController::instance()->hintAtMoveOrCopyOfAlbum(data->srcAlbum(), data->destAlbum()); createJob(data); return; } else if (operation == IOJobData::Delete || operation == IOJobData::Trash) { qCDebug(DIGIKAM_DATABASE_LOG) << "Number of files to be deleted:" << data->sourceUrls().count(); } else if (operation == IOJobData::Rename) { PAlbum* const album = AlbumManager::instance()->findPAlbum(data->imageInfo().albumId()); if (album) { ScanController::instance()->hintAtMoveOrCopyOfItem(data->imageInfo().id(), album, data->destUrl().fileName()); } SidecarFinder finder(data->srcUrl()); + data->setSourceUrls(finder.localFiles); for (int i = 0 ; i < finder.localFiles.length() ; ++i) { - IOJobData* const newdata = new IOJobData(IOJobData::Rename, data->imageInfos()); - newdata->setSourceUrls(QList() << finder.localFiles.at(i)); - newdata->setDestUrl(QUrl::fromLocalFile(data->destUrl().toLocalFile() + - finder.localFileSuffixes.at(i))); - createJob(newdata); + data->setDestUrl(finder.localFiles.at(i), + QUrl::fromLocalFile(data->destUrl().toLocalFile() + + finder.localFileSuffixes.at(i))); } - delete data; + createJob(data); return; } SidecarFinder finder(data->sourceUrls()); data->setSourceUrls(finder.localFiles); createJob(data); } void DIO::createJob(IOJobData* const data) { if (data->sourceUrls().isEmpty()) { delete data; return; } ProgressItem* item = 0; IOJobsThread* jobThread = 0; const int operation = data->operation(); if (operation == IOJobData::CopyAlbum || operation == IOJobData::CopyImage || operation == IOJobData::CopyFiles) { item = getProgressItem(operation); if (!item || item->totalCompleted()) { item = ProgressManager::instance()->createProgressItem(QLatin1String("DIOCopy"), i18n("Copy"), QString(), true, false); } item->setTotalItems(item->totalItems() + data->sourceUrls().count()); jobThread = IOJobsManager::instance()->startCopy(data); } else if (operation == IOJobData::MoveAlbum || operation == IOJobData::MoveImage || operation == IOJobData::MoveFiles) { item = getProgressItem(operation); if (!item || item->totalCompleted()) { item = ProgressManager::instance()->createProgressItem(QLatin1String("DIOMove"), i18n("Move"), QString(), true, false); } item->setTotalItems(item->totalItems() + data->sourceUrls().count()); jobThread = IOJobsManager::instance()->startMove(data); } else if (operation == IOJobData::Rename) { - if (data->sourceUrls().count() != 1) - { - qCDebug(DIGIKAM_DATABASE_LOG) << "Invalid operation: renaming is not 1:1"; - return; - } - jobThread = IOJobsManager::instance()->startRenameFile(data); connect(jobThread, SIGNAL(signalRenamed(QUrl)), this, SIGNAL(signalRenameSucceeded(QUrl))); connect(jobThread, SIGNAL(signalRenameFailed(QUrl)), this, SIGNAL(signalRenameFailed(QUrl))); } else if (operation == IOJobData::Delete || operation == IOJobData::DFiles) { item = getProgressItem(operation); if (!item || item->totalCompleted()) { item = ProgressManager::instance()->createProgressItem(QLatin1String("DIODelete"), i18n("Delete"), QString(), true, false); } item->setTotalItems(item->totalItems() + data->sourceUrls().count()); jobThread = IOJobsManager::instance()->startDelete(data); } else if (operation == IOJobData::Trash) { item = getProgressItem(operation); if (!item || item->totalCompleted()) { item = ProgressManager::instance()->createProgressItem(QLatin1String("DIOTrash"), i18n("Trash"), QString(), true, false); } item->setTotalItems(item->totalItems() + data->sourceUrls().count()); jobThread = IOJobsManager::instance()->startDelete(data); } else { qCDebug(DIGIKAM_DATABASE_LOG) << "Unknown IOJob operation:" << operation; return; } connect(jobThread, SIGNAL(signalOneProccessed(int)), this, SLOT(slotOneProccessed(int))); connect(jobThread, SIGNAL(finished()), this, SLOT(slotResult())); if (item) { connect(item, SIGNAL(progressItemCanceled(ProgressItem*)), jobThread, SLOT(slotCancel())); connect(item, SIGNAL(progressItemCanceled(ProgressItem*)), this, SLOT(slotCancel(ProgressItem*))); } } void DIO::slotResult() { IOJobsThread* const jobThread = dynamic_cast(sender()); if (!jobThread || !jobThread->jobData()) { return; } IOJobData* const data = jobThread->jobData(); const int operation = data->operation(); if (operation == IOJobData::MoveImage) { // update the image infos CoreDbAccess access; foreach(const ImageInfo& info, data->imageInfos()) { if (data->processedUrls().contains(info.fileUrl())) { access.db()->moveItem(info.albumId(), info.name(), data->destAlbum()->id(), info.name()); } } } else if (operation == IOJobData::Rename) { // If we rename a file, the name changes. This is equivalent to a move. // Do this in database, too. - if (data->processedUrls().contains(data->imageInfo().fileUrl())) + QUrl srcUrl(data->imageInfo().fileUrl()); + + if (data->processedUrls().contains(srcUrl)) { CoreDbAccess().db()->moveItem(data->imageInfo().albumId(), - data->srcUrl().fileName(), + srcUrl.fileName(), data->imageInfo().albumId(), - data->destUrl().fileName()); + data->destUrl(srcUrl).fileName()); // delete thumbnail - ThumbnailLoadThread::deleteThumbnail(data->srcUrl().toLocalFile()); - LoadingCacheInterface::fileChanged(data->destUrl().toLocalFile()); + ThumbnailLoadThread::deleteThumbnail(srcUrl.toLocalFile()); + LoadingCacheInterface::fileChanged(data->destUrl(srcUrl).toLocalFile()); } } if (jobThread->hasErrors() && operation != IOJobData::Rename) { // Pop-up a message about the error. QString errors = QStringList(jobThread->errorsList()).join(QLatin1String("\n")); DNotificationWrapper(QString(), errors, DigikamApp::instance(), DigikamApp::instance()->windowTitle()); } ProgressItem* const item = getProgressItem(operation); slotCancel(item); } void DIO::slotCancel(ProgressItem* item) { if (item) { item->setComplete(); } } void DIO::slotOneProccessed(int operation) { ProgressItem* const item = getProgressItem(operation); if (item) { item->advance(1); } } ProgressItem* DIO::getProgressItem(int operation) { ProgressItem* item = 0; switch (operation) { case IOJobData::CopyAlbum: case IOJobData::CopyImage: case IOJobData::CopyFiles: item = ProgressManager::instance()->findItembyId(QLatin1String("DIOCopy")); break; case IOJobData::MoveAlbum: case IOJobData::MoveImage: case IOJobData::MoveFiles: item = ProgressManager::instance()->findItembyId(QLatin1String("DIOMove")); break; case IOJobData::Trash: item = ProgressManager::instance()->findItembyId(QLatin1String("DIOTrash")); break; case IOJobData::Delete: item = ProgressManager::instance()->findItembyId(QLatin1String("DIODelete")); break; default: break; } return item; } } // namespace Digikam diff --git a/libs/iojobs/iojob.cpp b/libs/iojobs/iojob.cpp index 4ecc9875ee..b0349c534c 100644 --- a/libs/iojobs/iojob.cpp +++ b/libs/iojobs/iojob.cpp @@ -1,488 +1,490 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2015-06-15 * Description : IO Jobs for file systems jobs * * Copyright (C) 2015 by Mohamed Anwer * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "iojob.h" // Qt includes #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "dtrash.h" #include "coredb.h" #include "coredbaccess.h" #include "collectionmanager.h" #include "albummanager.h" #include "dfileoperations.h" namespace Digikam { IOJob::IOJob() { } // -------------------------------------------- CopyJob::CopyJob(IOJobData* const data) { m_data = data; } void CopyJob::run() { while (m_data && !m_cancel) { QUrl srcUrl = m_data->getNextUrl(); if (srcUrl.isEmpty()) { break; } QFileInfo srcInfo(srcUrl.toLocalFile()); QDir dstDir(m_data->destUrl().toLocalFile()); if (!srcInfo.exists()) { emit error(i18n("File/Folder %1 does not exist anymore", srcInfo.baseName())); emit signalOneProccessed(m_data->operation()); continue; } if (!dstDir.exists()) { emit error(i18n("Album %1 does not exist anymore", dstDir.dirName())); emit signalOneProccessed(m_data->operation()); continue; } // Checking if there is a file with the same name in destination folder QString destenationName = srcInfo.isFile() ? srcInfo.fileName() : srcInfo.dir().dirName(); QString destenation = dstDir.path() + QLatin1Char('/') + destenationName; QFileInfo fileInfoForDestination(destenation); if (fileInfoForDestination.exists()) { emit error(i18n("A file or folder named %1 already exists in %2", srcInfo.baseName(), QDir::toNativeSeparators(dstDir.path()))); emit signalOneProccessed(m_data->operation()); continue; } if (m_data->operation() == IOJobData::MoveAlbum || m_data->operation() == IOJobData::MoveImage || m_data->operation() == IOJobData::MoveFiles) { if (srcInfo.isDir()) { QDir srcDir(srcInfo.filePath()); if (!srcDir.rename(srcDir.path(), destenation)) { // If QDir::rename fails, try copy and remove. if (!DFileOperations::copyFolderRecursively(srcDir.path(), dstDir.path())) { emit error(i18n("Could not move folder %1 to album %2", QDir::toNativeSeparators(srcDir.path()), QDir::toNativeSeparators(dstDir.path()))); emit signalOneProccessed(m_data->operation()); continue; } else if (!srcDir.removeRecursively()) { emit error(i18n("Could not move folder %1 to album %2. " "The folder %1 was copied as well to album %2", QDir::toNativeSeparators(srcDir.path()), QDir::toNativeSeparators(dstDir.path()))); } } } else { QFile srcFile(srcInfo.filePath()); if (!srcFile.rename(destenation)) { emit error(i18n("Could not move file %1 to album %2", srcInfo.filePath(), QDir::toNativeSeparators(dstDir.path()))); emit signalOneProccessed(m_data->operation()); continue; } } } else { if (srcInfo.isDir()) { QDir srcDir(srcInfo.filePath()); if (!DFileOperations::copyFolderRecursively(srcDir.path(), dstDir.path())) { emit error(i18n("Could not copy folder %1 to album %2", QDir::toNativeSeparators(srcDir.path()), QDir::toNativeSeparators(dstDir.path()))); emit signalOneProccessed(m_data->operation()); continue; } } else { if (!QFile::copy(srcInfo.filePath(), destenation)) { emit error(i18n("Could not copy file %1 to album %2", QDir::toNativeSeparators(srcInfo.path()), QDir::toNativeSeparators(dstDir.path()))); emit signalOneProccessed(m_data->operation()); continue; } } } emit signalOneProccessed(m_data->operation()); m_data->addProcessedUrl(srcUrl); } emit signalDone(); } // -------------------------------------------- DeleteJob::DeleteJob(IOJobData* const data) { m_data = data; } void DeleteJob::run() { while (m_data && !m_cancel) { QUrl deleteUrl = m_data->getNextUrl(); if (deleteUrl.isEmpty()) { break; } bool useTrash = (m_data->operation() == IOJobData::Trash); QFileInfo fileInfo(deleteUrl.toLocalFile()); qCDebug(DIGIKAM_IOJOB_LOG) << "Deleting: " << fileInfo.filePath(); qCDebug(DIGIKAM_IOJOB_LOG) << "File exists?" << fileInfo.exists(); qCDebug(DIGIKAM_IOJOB_LOG) << "Is to trash?" << useTrash; if (!fileInfo.exists()) { emit error(i18n("File/Folder %1 does not exist", QDir::toNativeSeparators(fileInfo.filePath()))); emit signalOneProccessed(m_data->operation()); continue; } if (useTrash) { if (fileInfo.isDir()) { if (!DTrash::deleteDirRecursivley(deleteUrl.toLocalFile())) { emit error(i18n("Couldn't move folder %1 to collection trash", QDir::toNativeSeparators(fileInfo.path()))); emit signalOneProccessed(m_data->operation()); continue; } } else { if (!DTrash::deleteImage(deleteUrl.toLocalFile())) { emit error(i18n("Couldn't move image %1 to collection trash", QDir::toNativeSeparators(fileInfo.filePath()))); emit signalOneProccessed(m_data->operation()); continue; } } } else { if (fileInfo.isDir()) { QDir dir(fileInfo.filePath()); if (!dir.removeRecursively()) { emit error(i18n("Album %1 could not be removed", QDir::toNativeSeparators(fileInfo.path()))); emit signalOneProccessed(m_data->operation()); continue; } if (m_data->operation() == IOJobData::Delete) { CoreDbAccess access; // If the images in the directory should be marked as obsolete // get all files recursively and remove all image information // for which the file path leads to an image id. QList imageIds; QDirIterator iter(dir); while (iter.hasNext()) { // get the next path and advance the iterator QString filePath = iter.next(); // Use the file info to get the file type QFileInfo info = iter.fileInfo(); if (info.isFile()) { qlonglong imageId = getItemFromUrl(QUrl::fromLocalFile(filePath)); if (imageId != -1) { imageIds << imageId; } } } // Mark all image ids as obsolete. foreach(qlonglong imageId, imageIds) { access.db()->setItemStatus(imageId, DatabaseItem::Status::Obsolete); } } } else { QFile file(fileInfo.filePath()); if (!file.remove()) { emit error(i18n("Image %1 could not be removed", QDir::toNativeSeparators(fileInfo.filePath()))); emit signalOneProccessed(m_data->operation()); continue; } if (m_data->operation() == IOJobData::Delete) { CoreDbAccess access; // Mark the image info of the removed file as obsolete qlonglong imageId = getItemFromUrl(QUrl::fromLocalFile(fileInfo.filePath())); if (imageId != -1) { access.db()->setItemStatus(imageId, DatabaseItem::Status::Obsolete); } } } } emit signalOneProccessed(m_data->operation()); m_data->addProcessedUrl(deleteUrl); } emit signalDone(); } qlonglong DeleteJob::getItemFromUrl(const QUrl& url) { QString fileName = url.fileName(); // Get the album path, i.e. collection + album. For this, // get the n leftmost characters where n is the complete path without the size of the filename QString completePath = url.toLocalFile(); QString albumPath = CollectionManager::instance()->album(completePath); qlonglong imageId = -1; // Get the album and with this the image id of the image to trash. PAlbum* const pAlbum = AlbumManager::instance()->findPAlbum(QUrl::fromLocalFile(completePath)); if (pAlbum) { imageId = CoreDbAccess().db()->getItemFromAlbum(pAlbum->id(), fileName); } return imageId; } // -------------------------------------------- RenameFileJob::RenameFileJob(IOJobData* const data) { m_data = data; } void RenameFileJob::run() { while (m_data && !m_cancel) { QUrl renameUrl = m_data->getNextUrl(); if (renameUrl.isEmpty()) { break; } - qCDebug(DIGIKAM_IOJOB_LOG) << "Destination Url:" << m_data->destUrl(); + QUrl destUrl = m_data->destUrl(renameUrl); - if (QFileInfo(m_data->destUrl().toLocalFile()).exists()) + qCDebug(DIGIKAM_IOJOB_LOG) << "Destination Url:" << destUrl; + + if (QFileInfo(destUrl.toLocalFile()).exists()) { qCDebug(DIGIKAM_IOJOB_LOG) << "File with the same name exists!"; emit error(i18n("Image with the same name %1 already there", - QDir::toNativeSeparators(m_data->destUrl().toLocalFile()))); + QDir::toNativeSeparators(destUrl.toLocalFile()))); emit signalOneProccessed(m_data->operation()); emit signalRenameFailed(renameUrl); continue; } QFile file(renameUrl.toLocalFile()); qCDebug(DIGIKAM_IOJOB_LOG) << "Trying to rename" << renameUrl.toLocalFile() << "to" - << m_data->destUrl().toLocalFile(); + << destUrl.toLocalFile(); - if (!file.rename(m_data->destUrl().toLocalFile())) + if (!file.rename(destUrl.toLocalFile())) { qCDebug(DIGIKAM_IOJOB_LOG) << "File couldn't be renamed!"; emit error(i18n("Image %1 could not be renamed", QDir::toNativeSeparators(renameUrl.toLocalFile()))); emit signalOneProccessed(m_data->operation()); emit signalRenameFailed(renameUrl); continue; } emit signalOneProccessed(m_data->operation()); m_data->addProcessedUrl(renameUrl); emit signalRenamed(renameUrl); } emit signalDone(); } // ---------------------------------------------- DTrashItemsListingJob::DTrashItemsListingJob(const QString& collectionPath) { m_collectionPath = collectionPath; } void DTrashItemsListingJob::run() { DTrashItemInfo itemInfo; QString collectionTrashFilesPath = m_collectionPath + QLatin1Char('/') + DTrash::TRASH_FOLDER + QLatin1Char('/') + DTrash::FILES_FOLDER; qCDebug(DIGIKAM_IOJOB_LOG) << "Collection trash files path:" << collectionTrashFilesPath; QDir filesDir(collectionTrashFilesPath); foreach (const QFileInfo& fileInfo, filesDir.entryInfoList(QDir::Files)) { qCDebug(DIGIKAM_IOJOB_LOG) << "File in trash:" << fileInfo.filePath(); itemInfo.trashPath = fileInfo.filePath(); DTrash::extractJsonForItem(m_collectionPath, fileInfo.baseName(), itemInfo); emit trashItemInfo(itemInfo); } emit signalDone(); } // ---------------------------------------------- RestoreDTrashItemsJob::RestoreDTrashItemsJob(const DTrashItemInfoList& infos) { m_dtrashItemInfoList = infos; } void RestoreDTrashItemsJob::run() { foreach (const DTrashItemInfo& item, m_dtrashItemInfoList) { QUrl srcToRename = QUrl::fromLocalFile(item.collectionPath); QUrl newName = DFileOperations::getUniqueFileUrl(srcToRename); QFileInfo fi(item.collectionPath); if (!fi.dir().exists()) { fi.dir().mkpath(fi.dir().path()); } if (!QFile::rename(item.trashPath, newName.toLocalFile())) { qCDebug(DIGIKAM_IOJOB_LOG) << "Trash file couldn't be renamed!"; } else { QFile::remove(item.jsonFilePath); } } emit signalDone(); } // ---------------------------------------------- DeleteDTrashItemsJob::DeleteDTrashItemsJob(const DTrashItemInfoList& infos) { m_dtrashItemInfoList = infos; } void DeleteDTrashItemsJob::run() { CoreDbAccess access; foreach (const DTrashItemInfo& item, m_dtrashItemInfoList) { QFile::remove(item.trashPath); QFile::remove(item.jsonFilePath); // Set the status of the image id to obsolete, i.e. to remove. access.db()->setItemStatus(item.imageId, DatabaseItem::Status::Obsolete); } emit signalDone(); } } // namespace Digikam diff --git a/libs/iojobs/iojobdata.cpp b/libs/iojobs/iojobdata.cpp index b183611ceb..2c19e223cf 100644 --- a/libs/iojobs/iojobdata.cpp +++ b/libs/iojobs/iojobdata.cpp @@ -1,239 +1,246 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2018-02-24 * Description : Container for IOJob data. * * Copyright (C) 2018 by Maik Qualmann * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "iojobdata.h" // Qt includes #include // Local includes #include "album.h" #include "imageinfo.h" #include "digikam_debug.h" namespace Digikam { class IOJobData::Private { public: Private() : operation(0), srcAlbum(0), destAlbum(0) { } int operation; PAlbum* srcAlbum; PAlbum* destAlbum; + QMap changeDestMap; QList imageInfoList; QList sourceUrlList; - QList processedUrlList; + QList processedList; QUrl destUrl; QMutex lock; }; IOJobData::IOJobData(int operation, const QList& infos, PAlbum* const dest) : d(new Private) { d->operation = operation; d->destAlbum = dest; setImageInfos(infos); if (d->destAlbum) { d->destUrl = d->destAlbum->fileUrl(); } } IOJobData::IOJobData(int operation, const QList& urls, PAlbum* const dest) : d(new Private) { d->operation = operation; d->sourceUrlList = urls; d->destAlbum = dest; if (d->destAlbum) { d->destUrl = d->destAlbum->fileUrl(); } } IOJobData::IOJobData(int operation, PAlbum* const src, PAlbum* const dest) : d(new Private) { d->operation = operation; d->srcAlbum = src; d->destAlbum = dest; - d->sourceUrlList.clear(); - if (d->srcAlbum) { d->sourceUrlList << d->srcAlbum->fileUrl(); } if (d->destAlbum) { d->destUrl = d->destAlbum->fileUrl(); } } IOJobData::IOJobData(int operation, const QList& urls, const QUrl& dest) : d(new Private) { d->operation = operation; d->sourceUrlList = urls; d->destUrl = dest; } -IOJobData::IOJobData(int operation, const ImageInfo& info, const QString& newName) +IOJobData::IOJobData(int operation, + const ImageInfo& info, + const QString& newName) : d(new Private) { d->operation = operation; setImageInfos(QList() << info); d->destUrl = srcUrl().adjusted(QUrl::RemoveFilename); d->destUrl.setPath(d->destUrl.path() + newName); } IOJobData::~IOJobData() { delete d; } void IOJobData::setImageInfos(const QList& infos) { d->imageInfoList = infos; d->sourceUrlList.clear(); foreach(const ImageInfo& info, d->imageInfoList) { d->sourceUrlList << info.fileUrl(); } } void IOJobData::setSourceUrls(const QList& urls) { d->sourceUrlList = urls; } -void IOJobData::setDestUrl(const QUrl& url) +void IOJobData::setDestUrl(const QUrl& srcUrl, + const QUrl& destUrl) { - d->destUrl = url; + d->changeDestMap.insert(srcUrl, destUrl); } void IOJobData::addProcessedUrl(const QUrl& url) { - d->processedUrlList << url; + d->processedList << url; } int IOJobData::operation() const { return d->operation; } PAlbum* IOJobData::srcAlbum() const { return d->srcAlbum; } PAlbum* IOJobData::destAlbum() const { return d->destAlbum; } QUrl IOJobData::srcUrl() const { if (d->sourceUrlList.isEmpty()) { return QUrl(); } return d->sourceUrlList.first(); } -QUrl IOJobData::destUrl() const +QUrl IOJobData::destUrl(const QUrl& srcUrl) const { - return d->destUrl; + if (srcUrl.isEmpty()) + { + return d->destUrl; + } + + return d->changeDestMap.value(srcUrl, d->destUrl); } QUrl IOJobData::getNextUrl() const { d->lock.lock(); QUrl url; if (!d->sourceUrlList.isEmpty()) { url = d->sourceUrlList.takeFirst(); } d->lock.unlock(); return url; } ImageInfo IOJobData::imageInfo() const { if (d->imageInfoList.isEmpty()) { return ImageInfo(); } return d->imageInfoList.first(); } QList IOJobData::sourceUrls() const { return d->sourceUrlList; } QList IOJobData::imageInfos() const { return d->imageInfoList; } QList IOJobData::processedUrls() const { - return d->processedUrlList; + return d->processedList; } } // namespace Digikam diff --git a/libs/iojobs/iojobdata.h b/libs/iojobs/iojobdata.h index d70df8120b..c63c0bc556 100644 --- a/libs/iojobs/iojobdata.h +++ b/libs/iojobs/iojobdata.h @@ -1,113 +1,115 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2018-02-24 * Description : Container for IOJob data. * * Copyright (C) 2018 by Maik Qualmann * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef IOJOB_DATA_H #define IOJOB_DATA_H // Qt includes #include #include // Local includes #include "digikam_export.h" namespace Digikam { class PAlbum; class ImageInfo; class DIGIKAM_EXPORT IOJobData { public: enum Operation { CopyAlbum = 1 << 0, CopyImage = 1 << 1, CopyFiles = 1 << 2, MoveAlbum = 1 << 3, MoveImage = 1 << 4, MoveFiles = 1 << 5, Rename = 1 << 6, Delete = 1 << 7, DFiles = 1 << 8, // not mark as obsolete in the database Trash = 1 << 9 }; explicit IOJobData(int operation, const QList& infos, PAlbum* const dest = 0); explicit IOJobData(int operation, const QList& urls, PAlbum* const dest = 0); explicit IOJobData(int operation, PAlbum* const src, PAlbum* const dest); explicit IOJobData(int operation, const QList& urls, const QUrl& dest); explicit IOJobData(int operation, const ImageInfo& info, const QString& newName); ~IOJobData(); void setImageInfos(const QList& infos); void setSourceUrls(const QList& urls); - void setDestUrl(const QUrl& url); + + void setDestUrl(const QUrl& srcUrl, + const QUrl& destUrl); void addProcessedUrl(const QUrl& url); - int operation() const; + int operation() const; - PAlbum* srcAlbum() const; - PAlbum* destAlbum() const; + PAlbum* srcAlbum() const; + PAlbum* destAlbum() const; - QUrl srcUrl() const; - QUrl destUrl() const; - QUrl getNextUrl() const; + QUrl srcUrl() const; + QUrl destUrl(const QUrl& srcUrl = QUrl()) const; + QUrl getNextUrl() const; - ImageInfo imageInfo() const; + ImageInfo imageInfo() const; - QList sourceUrls() const; - QList imageInfos() const; + QList sourceUrls() const; + QList imageInfos() const; - QList processedUrls() const; + QList processedUrls() const; private: class Private; Private* const d; }; } // namespace Digikam #endif // IOJOB_DATA_H