File indexing completed on 2025-01-19 03:55:48

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-05-05
0007  * Description : file action manager
0008  *
0009  * SPDX-FileCopyrightText: 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "fileactionmngr_p.h"
0017 
0018 // KDE includes
0019 
0020 #include <klocalizedstring.h>
0021 
0022 // Local includes
0023 
0024 #include "digikam_debug.h"
0025 #include "thumbnailloadthread.h"
0026 #include "loadingcacheinterface.h"
0027 
0028 namespace Digikam
0029 {
0030 
0031 FileActionMngr::Private::Private(FileActionMngr* const qq)
0032     : q(qq)
0033 {
0034     qRegisterMetaType<MetadataHub*>("MetadataHub*");
0035     qRegisterMetaType<FileActionItemInfoList>("FileActionItemInfoList");
0036     qRegisterMetaType<FileActionItemInfoList*>("FileActionItemInfoList*");
0037     qRegisterMetaType<QList<ItemInfo> >("QList<ItemInfo>");
0038 
0039     dbWorker   = new FileActionMngrDatabaseWorker(this);
0040     fileWorker = new ParallelAdapter<FileWorkerInterface>();
0041 
0042     while (!fileWorker->optimalWorkerCountReached())
0043     {
0044         fileWorker->add(new FileActionMngrFileWorker(this));
0045     }
0046 
0047     sleepTimer = new QTimer(this);
0048     sleepTimer->setSingleShot(true);
0049     sleepTimer->setInterval(1000);
0050 
0051     connectToDatabaseWorker();
0052 
0053     connectDatabaseToFileWorker();
0054 
0055     connect(this, SIGNAL(signalTransform(FileActionItemInfoList,int)),
0056             fileWorker, SLOT(transform(FileActionItemInfoList,int)),
0057             Qt::DirectConnection);
0058 
0059     fileWorker->connect(SIGNAL(imageDataChanged(QString,bool,bool)),
0060                         this, SLOT(slotImageDataChanged(QString,bool,bool)));
0061 
0062     connect(&dbProgress, SIGNAL(lastItemCompleted()),
0063             this, SLOT(slotLastProgressItemCompleted()));
0064 
0065     connect(&fileProgress, SIGNAL(lastItemCompleted()),
0066             this, SLOT(slotLastProgressItemCompleted()));
0067 
0068     connect(sleepTimer, SIGNAL(timeout()),
0069             this, SLOT(slotSleepTimer()));
0070 }
0071 
0072 void FileActionMngr::Private::connectToDatabaseWorker()
0073 {
0074     WorkerObject::connectAndSchedule(this, SIGNAL(signalAddTags(FileActionItemInfoList,QList<int>)),
0075                                      dbWorker, SLOT(assignTags(FileActionItemInfoList,QList<int>)));
0076 
0077     WorkerObject::connectAndSchedule(this, SIGNAL(signalRemoveTags(FileActionItemInfoList,QList<int>)),
0078                                      dbWorker, SLOT(removeTags(FileActionItemInfoList,QList<int>)));
0079 
0080     WorkerObject::connectAndSchedule(this, SIGNAL(signalAssignPickLabel(FileActionItemInfoList,int)),
0081                                      dbWorker, SLOT(assignPickLabel(FileActionItemInfoList,int)));
0082 
0083     WorkerObject::connectAndSchedule(this, SIGNAL(signalAssignColorLabel(FileActionItemInfoList,int)),
0084                                      dbWorker, SLOT(assignColorLabel(FileActionItemInfoList,int)));
0085 
0086     WorkerObject::connectAndSchedule(this, SIGNAL(signalAssignRating(FileActionItemInfoList,int)),
0087                                      dbWorker, SLOT(assignRating(FileActionItemInfoList,int)));
0088 
0089     WorkerObject::connectAndSchedule(this, SIGNAL(signalEditGroup(int,ItemInfo,FileActionItemInfoList)),
0090                                      dbWorker, SLOT(editGroup(int,ItemInfo,FileActionItemInfoList)));
0091 
0092     WorkerObject::connectAndSchedule(this, SIGNAL(signalSetExifOrientation(FileActionItemInfoList,int)),
0093                                      dbWorker, SLOT(setExifOrientation(FileActionItemInfoList,int)));
0094 
0095     WorkerObject::connectAndSchedule(this, SIGNAL(signalApplyMetadata(FileActionItemInfoList,DisjointMetadata*)),
0096                                      dbWorker, SLOT(applyMetadata(FileActionItemInfoList,DisjointMetadata*)));
0097 
0098     WorkerObject::connectAndSchedule(this, SIGNAL(signalCopyAttributes(FileActionItemInfoList,QStringList)),
0099                                      dbWorker, SLOT(copyAttributes(FileActionItemInfoList,QStringList)));
0100 }
0101 
0102 void FileActionMngr::Private::connectDatabaseToFileWorker()
0103 {
0104     connect(dbWorker, SIGNAL(writeMetadataToFiles(FileActionItemInfoList)),
0105             fileWorker, SLOT(writeMetadataToFiles(FileActionItemInfoList)),
0106             Qt::DirectConnection);
0107 
0108     connect(dbWorker, SIGNAL(writeMetadata(FileActionItemInfoList,int)),
0109             fileWorker, SLOT(writeMetadata(FileActionItemInfoList,int)),
0110             Qt::DirectConnection);
0111 
0112     connect(dbWorker, SIGNAL(writeOrientationToFiles(FileActionItemInfoList,int)),
0113             fileWorker, SLOT(writeOrientationToFiles(FileActionItemInfoList,int)),
0114             Qt::DirectConnection);
0115 }
0116 
0117 FileActionMngr::Private::~Private()
0118 {
0119     delete dbWorker;
0120     delete fileWorker;
0121 }
0122 
0123 bool FileActionMngr::Private::isActive() const
0124 {
0125     return dbProgress.activeProgressItems || fileProgress.activeProgressItems;
0126 }
0127 
0128 bool FileActionMngr::Private::shallSendForWriting(qlonglong id)
0129 {
0130     QMutexLocker lock(&mutex);
0131 
0132     if (scheduledToWrite.contains(id))
0133     {
0134         return false;
0135     }
0136 
0137     scheduledToWrite << id;
0138 
0139     return true;
0140 }
0141 
0142 void FileActionMngr::Private::startingToWrite(const QList<ItemInfo>& infos)
0143 {
0144     QMutexLocker lock(&mutex);
0145 
0146     Q_FOREACH (const ItemInfo& info, infos)
0147     {
0148         scheduledToWrite.remove(info.id());
0149     }
0150 }
0151 
0152 void FileActionMngr::Private::slotSleepTimer()
0153 {
0154     if (!dbProgress.activeProgressItems)
0155     {
0156         dbWorker->deactivate();
0157     }
0158 
0159     if (!fileProgress.activeProgressItems)
0160     {
0161         fileWorker->deactivate();
0162     }
0163 }
0164 
0165 void FileActionMngr::Private::slotLastProgressItemCompleted()
0166 {
0167     if (!isActive())
0168     {
0169         Q_EMIT signalTasksFinished();
0170     }
0171 
0172     sleepTimer->start();
0173 }
0174 
0175 void FileActionMngr::Private::slotImageDataChanged(const QString& path, bool removeThumbnails, bool notifyCache)
0176 {
0177     // must be done from the UI thread, touches pixmaps
0178 
0179     if (removeThumbnails)
0180     {
0181         ThumbnailLoadThread::deleteThumbnail(path);
0182     }
0183 
0184     if (notifyCache)
0185     {
0186         LoadingCacheInterface::fileChanged(path);
0187     }
0188 }
0189 
0190 PrivateProgressItemCreator* FileActionMngr::Private::dbProgressCreator()
0191 {
0192     return &dbProgress;
0193 }
0194 
0195 PrivateProgressItemCreator* FileActionMngr::Private::fileProgressCreator()
0196 {
0197     return &fileProgress;
0198 }
0199 
0200 ProgressItem* PrivateProgressItemCreator::createProgressItem(const QString& action) const
0201 {
0202     return new ProgressItem(nullptr, ProgressManager::instance()->getUniqueID(), action, QString(), true, true);
0203 }
0204 
0205 void PrivateProgressItemCreator::addProgressItem(ProgressItem* const item)
0206 {
0207     activeProgressItems.ref();
0208 
0209     connect(item, SIGNAL(progressItemCompleted(ProgressItem*)),
0210             this, SLOT(slotProgressItemCompleted()),
0211             Qt::DirectConnection);
0212 
0213     connect(item, SIGNAL(progressItemCanceled(ProgressItem*)),
0214             this, SLOT(slotProgressItemCanceled(ProgressItem*)),
0215             Qt::DirectConnection);
0216 
0217     ProgressManager::addProgressItem(item);
0218 }
0219 
0220 void PrivateProgressItemCreator::slotProgressItemCompleted()
0221 {
0222     if (!activeProgressItems.deref())
0223     {
0224         Q_EMIT lastItemCompleted();
0225     }
0226 }
0227 
0228 void PrivateProgressItemCreator::slotProgressItemCanceled(ProgressItem* item)
0229 {
0230     FileActionMngr::instance()->shutDown();
0231     item->setComplete();
0232 }
0233 
0234 } // namespace Digikam
0235 
0236 #include "moc_fileactionmngr_p.cpp"