diff --git a/libs/database/utils/dio.cpp b/libs/database/utils/dio.cpp index 505b7c5ba7..04b7ef6b15 100644 --- a/libs/database/utils/dio.cpp +++ b/libs/database/utils/dio.cpp @@ -1,547 +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) { 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) << "Deleting files:" << data->sourceUrls(); } 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()); 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); } delete 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; 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::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 if (operation == IOJobData::Delete) { 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); } 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(); 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 (QFileInfo::exists(data->destUrl().toLocalFile())) + if (data->processedUrls().contains(data->imageInfo().fileUrl())) { CoreDbAccess().db()->moveItem(data->imageInfo().albumId(), data->srcUrl().fileName(), data->imageInfo().albumId(), data->destUrl().fileName()); // delete thumbnail ThumbnailLoadThread::deleteThumbnail(data->srcUrl().toLocalFile()); LoadingCacheInterface::fileChanged(data->destUrl().toLocalFile()); } } if (jobThread->hasErrors()) { // 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 ea6cba33ed..3f552978f1 100644 --- a/libs/iojobs/iojob.cpp +++ b/libs/iojobs/iojob.cpp @@ -1,477 +1,487 @@ /* ============================================================ * * 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) { if (m_cancel) { return; } 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) { if (m_cancel) { return; } 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; } 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; } // Mark the image info of the removed file as obsolete CoreDbAccess access; 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(const QUrl& srcToRename, const QUrl& newUrl) +RenameFileJob::RenameFileJob(IOJobData* const data) { - m_srcToRename = srcToRename; - m_newUrl = newUrl; + m_data = data; } void RenameFileJob::run() { - if (m_newUrl.isEmpty()) + while (m_data) { - emit signalRenameFailed(m_srcToRename); - emit signalDone(); - return; - } + if (m_cancel) + { + return; + } - qCDebug(DIGIKAM_IOJOB_LOG) << "Destination Url:" << m_newUrl; + QUrl renameUrl = m_data->getNextUrl(); - if (QFileInfo(m_newUrl.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_newUrl.toLocalFile()))); - emit signalRenameFailed(m_srcToRename); - emit signalDone(); - return; - } + if (renameUrl.isEmpty()) + { + break; + } - QFile file(m_srcToRename.toLocalFile()); + qCDebug(DIGIKAM_IOJOB_LOG) << "Destination Url:" << m_data->destUrl(); - qCDebug(DIGIKAM_IOJOB_LOG) << "Trying to rename" - << m_srcToRename.toLocalFile() << "to" - << m_newUrl.toLocalFile(); + if (QFileInfo(m_data->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()))); + emit signalOneProccessed(m_data->operation()); + emit signalRenameFailed(renameUrl); + continue; + } - if (!file.rename(m_newUrl.toLocalFile())) - { - qCDebug(DIGIKAM_IOJOB_LOG) << "File couldn't be renamed!"; - emit error(i18n("Image %1 could not be renamed", - QDir::toNativeSeparators(m_srcToRename.toLocalFile()))); - emit signalRenameFailed(m_srcToRename); - emit signalDone(); - return; + QFile file(renameUrl.toLocalFile()); + + qCDebug(DIGIKAM_IOJOB_LOG) << "Trying to rename" + << renameUrl.toLocalFile() << "to" + << m_data->destUrl().toLocalFile(); + + if (!file.rename(m_data->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 signalRenamed(m_srcToRename); 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!"; return; } 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/iojob.h b/libs/iojobs/iojob.h index 9fb397cded..9f669b7ced 100644 --- a/libs/iojobs/iojob.h +++ b/libs/iojobs/iojob.h @@ -1,187 +1,186 @@ /* ============================================================ * * 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. * * ============================================================ */ #ifndef IOJOB_H #define IOJOB_H // Qt includes #include // Local includes #include "actionthreadbase.h" #include "dtrashiteminfo.h" #include "digikam_export.h" #include "iojobdata.h" namespace Digikam { class ImageInfo; class DIGIKAM_EXPORT IOJob : public ActionJob { Q_OBJECT protected: IOJob(); Q_SIGNALS: void signalOneProccessed(int operation); void error(const QString& errMsg); }; // --------------------------------------- class DIGIKAM_EXPORT CopyJob : public IOJob { Q_OBJECT public: CopyJob(IOJobData* const data); protected: void run(); private: IOJobData* m_data; }; // --------------------------------------- class DIGIKAM_EXPORT DeleteJob : public IOJob { Q_OBJECT public: DeleteJob(IOJobData* const data); protected: void run(); private: qlonglong getItemFromUrl(const QUrl& url); private: IOJobData* m_data; }; // --------------------------------------- class DIGIKAM_EXPORT RenameFileJob : public IOJob { Q_OBJECT public: - RenameFileJob(const QUrl& srcToRename, const QUrl& newName); + RenameFileJob(IOJobData* const data); Q_SIGNALS: void signalRenamed(const QUrl& oldUrl); void signalRenameFailed(const QUrl& oldUrl); protected: void run(); private: - QUrl m_srcToRename; - QUrl m_newUrl; + IOJobData* m_data; }; // ---------------------------------------------- class DIGIKAM_EXPORT DTrashItemsListingJob : public IOJob { Q_OBJECT public: DTrashItemsListingJob(const QString& collectionPath); Q_SIGNALS: void trashItemInfo(const DTrashItemInfo& info); protected: void run(); private: QString m_collectionPath; }; // ---------------------------------------------- class DIGIKAM_EXPORT RestoreDTrashItemsJob : public IOJob { Q_OBJECT public: RestoreDTrashItemsJob(const DTrashItemInfoList& infos); protected: void run(); private: DTrashItemInfoList m_dtrashItemInfoList; }; // ---------------------------------------------- class DIGIKAM_EXPORT DeleteDTrashItemsJob : public IOJob { Q_OBJECT public: DeleteDTrashItemsJob(const DTrashItemInfoList& infos); protected: void run(); private: DTrashItemInfoList m_dtrashItemInfoList; }; } // namespace Digikam #endif // IOJOB_H diff --git a/libs/iojobs/iojobsthread.cpp b/libs/iojobs/iojobsthread.cpp index 1d4014967c..e4dc8706ef 100644 --- a/libs/iojobs/iojobsthread.cpp +++ b/libs/iojobs/iojobsthread.cpp @@ -1,254 +1,254 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2015-06-15 * Description : IO Jobs thread for file system 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 "iojobsthread.h" // Qt includes #include #include // Local includes #include "iojob.h" #include "iojobdata.h" #include "digikam_debug.h" #include "coredb.h" #include "coredbaccess.h" namespace Digikam { class IOJobsThread::Private { public: Private() : jobsCount(0), isCanceled(false), jobData(0) { } int jobsCount; bool isCanceled; IOJobData* jobData; QList errorsList; }; IOJobsThread::IOJobsThread(QObject* const parent) : ActionThreadBase(parent), d(new Private) { } IOJobsThread::~IOJobsThread() { delete d->jobData; delete d; } void IOJobsThread::copy(IOJobData* const data) { d->jobData = data; ActionJobCollection collection; for (int i = 0; i < maximumNumberOfThreads(); i++) { CopyJob* const j = new CopyJob(data); connectOneJob(j); collection.insert(j, 0); d->jobsCount++; } appendJobs(collection); } void IOJobsThread::move(IOJobData* const data) { d->jobData = data; ActionJobCollection collection; for (int i = 0; i < maximumNumberOfThreads(); i++) { CopyJob* const j = new CopyJob(data); connectOneJob(j); collection.insert(j, 0); d->jobsCount++; } appendJobs(collection); } void IOJobsThread::deleteFiles(IOJobData* const data) { d->jobData = data; ActionJobCollection collection; for (int i = 0; i < maximumNumberOfThreads(); i++) { DeleteJob* const j = new DeleteJob(data); connectOneJob(j); collection.insert(j, 0); d->jobsCount++; } appendJobs(collection); } void IOJobsThread::renameFile(IOJobData* const data) { d->jobData = data; ActionJobCollection collection; - RenameFileJob* const j = new RenameFileJob(data->srcUrl(), data->destUrl()); + RenameFileJob* const j = new RenameFileJob(data); connectOneJob(j); connect(j, SIGNAL(signalRenamed(QUrl)), this, SIGNAL(signalRenamed(QUrl))); connect(j, SIGNAL(signalRenameFailed(QUrl)), this, SIGNAL(signalRenameFailed(QUrl))); collection.insert(j, 0); d->jobsCount++; appendJobs(collection); } void IOJobsThread::listDTrashItems(const QString& collectionPath) { ActionJobCollection collection; DTrashItemsListingJob* const j = new DTrashItemsListingJob(collectionPath); connect(j, SIGNAL(trashItemInfo(DTrashItemInfo)), this, SIGNAL(collectionTrashItemInfo(DTrashItemInfo))); connect(j, SIGNAL(signalDone()), this, SIGNAL(finished())); collection.insert(j, 0); d->jobsCount++; appendJobs(collection); } void IOJobsThread::restoreDTrashItems(const DTrashItemInfoList& items) { ActionJobCollection collection; RestoreDTrashItemsJob* const j = new RestoreDTrashItemsJob(items); connect(j, SIGNAL(signalDone()), this, SIGNAL(finished())); collection.insert(j, 0); d->jobsCount++; appendJobs(collection); } void IOJobsThread::deleteDTrashItems(const DTrashItemInfoList& items) { ActionJobCollection collection; DeleteDTrashItemsJob* const j = new DeleteDTrashItemsJob(items); connect(j, SIGNAL(signalDone()), this, SIGNAL(finished())); collection.insert(j, 0); d->jobsCount++; appendJobs(collection); } bool IOJobsThread::isCanceled() { return d->isCanceled; } bool IOJobsThread::hasErrors() { return !d->errorsList.isEmpty(); } QList& IOJobsThread::errorsList() { return d->errorsList; } void IOJobsThread::connectOneJob(IOJob* const j) { connect(j, SIGNAL(error(QString)), this, SLOT(slotError(QString))); connect(j, SIGNAL(signalDone()), this, SLOT(slotOneJobFinished())); connect(j, SIGNAL(signalOneProccessed(int)), this, SIGNAL(signalOneProccessed(int))); } void IOJobsThread::slotOneJobFinished() { d->jobsCount--; if (d->jobsCount == 0) { emit finished(); qCDebug(DIGIKAM_IOJOB_LOG) << "Thread Finished"; } } void IOJobsThread::slotError(const QString& errString) { d->errorsList.append(errString); } void IOJobsThread::slotCancel() { d->isCanceled = true; ActionThreadBase::cancel(); } IOJobData* IOJobsThread::jobData() { return d->jobData; } } // namespace Digikam