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 // Qt includes
0019 
0020 #include <QPointer>
0021 #include <QProgressDialog>
0022 
0023 // KDE includes
0024 
0025 #include <klocalizedstring.h>
0026 
0027 // Local includes
0028 
0029 #include "digikam_debug.h"
0030 #include "applicationsettings.h"
0031 #include "iteminfotasksplitter.h"
0032 #include "loadingcacheinterface.h"
0033 #include "metadatahub.h"
0034 #include "metaenginesettings.h"
0035 #include "thumbnailloadthread.h"
0036 #include "disjointmetadata.h"
0037 
0038 namespace Digikam
0039 {
0040 
0041 class Q_DECL_HIDDEN FileActionMngrCreator
0042 {
0043 public:
0044 
0045     FileActionMngr object;
0046 };
0047 
0048 Q_GLOBAL_STATIC(FileActionMngrCreator, metadataManagercreator)
0049 
0050 FileActionMngr* FileActionMngr::instance()
0051 {
0052     return &metadataManagercreator->object;
0053 }
0054 
0055 FileActionMngr::FileActionMngr()
0056     : d(new Private(this))
0057 {
0058 
0059     connect(d->fileWorker, SIGNAL(imageChangeFailed(QString,QStringList)),
0060             this, SIGNAL(signalImageChangeFailed(QString,QStringList)));
0061 }
0062 
0063 FileActionMngr::~FileActionMngr()
0064 {
0065     shutDown();
0066     delete d;
0067 }
0068 
0069 bool FileActionMngr::requestShutDown()
0070 {
0071     if (!isActive())
0072     {
0073         shutDown();
0074         return true;
0075     }
0076 
0077     QPointer<QProgressDialog> dialog = new QProgressDialog;
0078     dialog->setMinimum(0);
0079     dialog->setMaximum(0);
0080     dialog->setMinimumDuration(100);
0081     dialog->setLabelText(i18nc("@label", "Finishing tasks"));
0082 
0083     connect(d, SIGNAL(signalTasksFinished()),
0084             dialog, SLOT(accept()));
0085 
0086     dialog->exec();
0087 
0088     // Either, we finished and all is fine, or the user cancelled and we kill
0089     shutDown();
0090 
0091     return true;
0092 }
0093 
0094 void FileActionMngr::shutDown()
0095 {
0096     d->dbWorker->deactivate();
0097     d->fileWorker->deactivate();
0098     d->dbWorker->wait();
0099     d->fileWorker->wait();
0100 }
0101 
0102 bool FileActionMngr::isActive()
0103 {
0104     return d->isActive();
0105 }
0106 
0107 void FileActionMngr::assignTags(const QList<qlonglong>& ids, const QList<int>& tagIDs)
0108 {
0109     assignTags(ItemInfoList(ids), tagIDs);
0110 }
0111 
0112 void FileActionMngr::assignTag(const ItemInfo& info, int tagID)
0113 {
0114     assignTags(QList<ItemInfo>() << info, QList<int>() << tagID);
0115 }
0116 
0117 void FileActionMngr::assignTag(const QList<ItemInfo>& infos, int tagID)
0118 {
0119     assignTags(infos, QList<int>() << tagID);
0120 }
0121 
0122 void FileActionMngr::assignTags(const ItemInfo& info, const QList<int>& tagIDs)
0123 {
0124     assignTags(QList<ItemInfo>() << info, tagIDs);
0125 }
0126 
0127 void FileActionMngr::assignTags(const QList<ItemInfo>& infos, const QList<int>& tagIDs)
0128 {
0129     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0130     taskList.schedulingForDB(i18n("Assigning image tags"), d->dbProgressCreator());
0131     d->assignTags(taskList, tagIDs);
0132 }
0133 
0134 void FileActionMngr::removeTag(const ItemInfo& info, int tagID)
0135 {
0136     removeTags(QList<ItemInfo>() << info, QList<int>() << tagID);
0137 }
0138 
0139 void FileActionMngr::removeTag(const QList<ItemInfo>& infos, int tagID)
0140 {
0141     removeTags(infos, QList<int>() << tagID);
0142 }
0143 
0144 void FileActionMngr::removeTags(const ItemInfo& info, const QList<int>& tagIDs)
0145 {
0146     removeTags(QList<ItemInfo>() << info, tagIDs);
0147 }
0148 
0149 void FileActionMngr::removeTags(const QList<ItemInfo>& infos, const QList<int>& tagIDs)
0150 {
0151     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0152     taskList.schedulingForDB(i18n("Removing image tags"), d->dbProgressCreator());
0153     d->removeTags(taskList, tagIDs);
0154 }
0155 
0156 void FileActionMngr::assignPickLabel(const ItemInfo& info, int pickId)
0157 {
0158     assignPickLabel(QList<ItemInfo>() << info, pickId);
0159 }
0160 
0161 void FileActionMngr::assignColorLabel(const ItemInfo& info, int colorId)
0162 {
0163     assignColorLabel(QList<ItemInfo>() << info, colorId);
0164 }
0165 
0166 void FileActionMngr::assignPickLabel(const QList<ItemInfo>& infos, int pickId)
0167 {
0168     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0169     taskList.schedulingForDB(i18n("Assigning image pick label"), d->dbProgressCreator());
0170     d->assignPickLabel(taskList, pickId);
0171 }
0172 
0173 void FileActionMngr::assignColorLabel(const QList<ItemInfo>& infos, int colorId)
0174 {
0175     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0176     taskList.schedulingForDB(i18n("Assigning image color label"), d->dbProgressCreator());
0177     d->assignColorLabel(taskList, colorId);
0178 }
0179 
0180 void FileActionMngr::assignRating(const ItemInfo& info, int rating)
0181 {
0182     assignRating(QList<ItemInfo>() << info, rating);
0183 }
0184 
0185 void FileActionMngr::assignRating(const QList<ItemInfo>& infos, int rating)
0186 {
0187     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0188     taskList.schedulingForDB(i18n("Assigning image ratings"), d->dbProgressCreator());
0189     d->assignRating(taskList, rating);
0190 }
0191 
0192 void FileActionMngr::addToGroup(const ItemInfo& pick, const QList<ItemInfo>& infos)
0193 {
0194     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0195     taskList.schedulingForDB(i18n("Editing group"), d->dbProgressCreator());
0196     d->editGroup(AddToGroup, pick, taskList);
0197 }
0198 
0199 void FileActionMngr::removeFromGroup(const ItemInfo& info)
0200 {
0201     removeFromGroup(QList<ItemInfo>() << info);
0202 }
0203 
0204 void FileActionMngr::removeFromGroup(const QList<ItemInfo>& infos)
0205 {
0206     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0207     taskList.schedulingForDB(i18n("Editing group"), d->dbProgressCreator());
0208     d->editGroup(RemoveFromGroup, ItemInfo(), taskList);
0209 }
0210 
0211 void FileActionMngr::ungroup(const ItemInfo& info)
0212 {
0213     ungroup(QList<ItemInfo>() << info);
0214 }
0215 
0216 void FileActionMngr::ungroup(const QList<ItemInfo>& infos)
0217 {
0218     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0219     taskList.schedulingForDB(i18n("Editing group"), d->dbProgressCreator());
0220     d->editGroup(Ungroup, ItemInfo(), taskList);
0221 }
0222 
0223 void FileActionMngr::setExifOrientation(const QList<ItemInfo>& infos, int orientation)
0224 {
0225     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0226     taskList.schedulingForDB(i18n("Updating orientation in database"), d->dbProgressCreator());
0227     d->setExifOrientation(taskList, orientation);
0228 }
0229 
0230 /*
0231 void FileActionMngr::applyMetadata(const QList<ItemInfo>& infos, const MetadataHub& hub)
0232 {
0233     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0234     taskList.schedulingForDB(i18n("Applying metadata"), d->dbProgressCreator());
0235     // create hub parent-less, we will need to clone() it in a thread,
0236     // and that does not work with parent in a different thread
0237     // d->applyMetadata(taskList, new MetadataHubOnTheRoad(hub));
0238 }
0239 */
0240 
0241 void FileActionMngr::applyMetadata(const QList<ItemInfo>& infos, const DisjointMetadata& hub)
0242 {
0243     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0244     taskList.schedulingForDB(i18n("Applying metadata"), d->dbProgressCreator());
0245 
0246     DisjointMetadata* const hub2 = new DisjointMetadata();
0247     hub2->setDataFields(hub.dataFields());
0248     d->applyMetadata(taskList, hub2);
0249 }
0250 
0251 void FileActionMngr::applyMetadata(const QList<ItemInfo>& infos, DisjointMetadata* hub)
0252 {
0253 /*
0254     if (hub->parent())
0255     {
0256         qCDebug(DIGIKAM_GENERAL_LOG) << "MetadataHubOnTheRoad object must not have a QObject parent";
0257         delete hub;
0258         return;
0259     }
0260 */
0261     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0262     taskList.schedulingForDB(i18n("Applying metadata"), d->dbProgressCreator());
0263     d->applyMetadata(taskList, hub);
0264 }
0265 
0266 void FileActionMngr::transform(const QList<ItemInfo>& infos, MetaEngineRotation::TransformationAction action)
0267 {
0268     FileActionItemInfoList taskList = FileActionItemInfoList::create(infos);
0269     taskList.schedulingForWrite(i18n("Rotating images"), d->fileProgressCreator());
0270 
0271     for (ItemInfoTaskSplitter splitter(taskList); splitter.hasNext();)
0272     {
0273         d->transform(splitter.next(), action);
0274     }
0275 }
0276 
0277 void FileActionMngr::copyAttributes(const ItemInfo& source, const QString& derivedPath)
0278 {
0279     copyAttributes(source, QStringList() << derivedPath);
0280 }
0281 
0282 void FileActionMngr::copyAttributes(const ItemInfo& source, const QStringList& derivedPaths)
0283 {
0284     FileActionItemInfoList taskList = FileActionItemInfoList::create(QList<ItemInfo>() << source);
0285     taskList.schedulingForDB(i18n("Copying attributes"), d->dbProgressCreator());
0286     d->copyAttributes(taskList, derivedPaths);
0287 }
0288 
0289 } // namespace Digikam
0290 
0291 #include "moc_fileactionmngr.cpp"