File indexing completed on 2025-01-19 03:51:26
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2012-12-31 0007 * Description : time adjust actions using threads. 0008 * 0009 * SPDX-FileCopyrightText: 2012 by Smit Mehta <smit dot meh at gmail dot com> 0010 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2018-2021 by Maik Qualmann <metzpinguin at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "timeadjusttask.h" 0018 0019 // Qt includes 0020 0021 #include <QFile> 0022 #include <QScopedPointer> 0023 #include <qplatformdefs.h> 0024 0025 // Local includes 0026 0027 #include "dmetadata.h" 0028 #include "digikam_debug.h" 0029 #include "dinfointerface.h" 0030 #include "dfileoperations.h" 0031 #include "timeadjustlist.h" 0032 #include "metaenginesettings.h" 0033 0034 namespace DigikamGenericTimeAdjustPlugin 0035 { 0036 0037 class Q_DECL_HIDDEN TimeAdjustTask::Private 0038 { 0039 public: 0040 0041 explicit Private() 0042 : thread(nullptr) 0043 { 0044 } 0045 0046 // Settings from GUI. 0047 0048 TimeAdjustContainer settings; 0049 0050 TimeAdjustThread* thread; 0051 0052 QUrl url; 0053 }; 0054 0055 TimeAdjustTask::TimeAdjustTask(const QUrl& url, TimeAdjustThread* const thread) 0056 : ActionJob(), 0057 d(new Private) 0058 { 0059 d->url = url; 0060 d->thread = thread; 0061 } 0062 0063 TimeAdjustTask::~TimeAdjustTask() 0064 { 0065 cancel(); 0066 delete d; 0067 } 0068 0069 void TimeAdjustTask::setSettings(const TimeAdjustContainer& settings) 0070 { 0071 d->settings = settings; 0072 } 0073 0074 void TimeAdjustTask::run() 0075 { 0076 if (m_cancel) 0077 { 0078 return; 0079 } 0080 0081 Q_EMIT signalProcessStarted(d->url); 0082 0083 QDateTime org = d->thread->readTimestamp(d->url); 0084 QDateTime adj = d->settings.calculateAdjustedDate(org, d->thread->indexForUrl(d->url)); 0085 0086 if (!adj.isValid()) 0087 { 0088 Q_EMIT signalProcessEnded(d->url, org, adj, TimeAdjustList::META_TIME_ERROR); 0089 Q_EMIT signalDone(); 0090 return; 0091 } 0092 0093 if (m_cancel) 0094 { 0095 return; 0096 } 0097 0098 bool metadataChanged = false; 0099 bool writeToSidecar = (MetaEngineSettings::instance()->settings() 0100 .metadataWritingMode != DMetadata::WRITE_TO_FILE_ONLY); 0101 bool writeWithExifTool = (MetaEngineSettings::instance()->settings().writeWithExifTool); 0102 0103 int status = TimeAdjustList::NOPROCESS_ERROR; 0104 0105 QString exifDateTimeFormat = QLatin1String("yyyy:MM:dd hh:mm:ss"); 0106 QString xmpDateTimeFormat = QLatin1String("yyyy-MM-ddThh:mm:ss"); 0107 0108 const QMap<QString, bool>& tagsMap = d->settings.getDateTimeTagsMap(); 0109 QMap<QString, bool>::const_iterator it; 0110 0111 QScopedPointer<DMetadata> meta(new DMetadata); 0112 0113 if (meta->load(d->url.toLocalFile())) 0114 { 0115 for (it = tagsMap.constBegin() ; it != tagsMap.constEnd() ; ++it) 0116 { 0117 if (!it.value()) 0118 { 0119 continue; 0120 } 0121 0122 bool ret = true; 0123 0124 if (it.key().startsWith(QLatin1String("Exif.")) && 0125 (meta->canWriteExif(d->url.toLocalFile()) || 0126 writeWithExifTool || 0127 writeToSidecar) 0128 ) 0129 { 0130 if (!d->settings.updIfAvailable || 0131 !meta->getExifTagString(it.key().toLatin1().constData()).isEmpty()) 0132 { 0133 ret &= meta->setExifTagString(it.key().toLatin1().constData(), 0134 adj.toString(exifDateTimeFormat)); 0135 0136 metadataChanged = true; 0137 } 0138 } 0139 else if (it.key().startsWith(QLatin1String("Iptc.")) && 0140 (meta->canWriteIptc(d->url.toLocalFile()) || 0141 writeWithExifTool || 0142 writeToSidecar) 0143 ) 0144 { 0145 if (!d->settings.updIfAvailable || 0146 !meta->getIptcTagString(it.key().toLatin1().constData()).isEmpty()) 0147 { 0148 if (it.key().contains(QLatin1String("Date"))) 0149 { 0150 ret &= meta->setIptcTagString(it.key().toLatin1().constData(), 0151 adj.date().toString(Qt::ISODate)); 0152 0153 metadataChanged = true; 0154 } 0155 else if (it.key().contains(QLatin1String("Time"))) 0156 { 0157 ret &= meta->setIptcTagString(it.key().toLatin1().constData(), 0158 adj.time().toString(Qt::ISODate)); 0159 0160 metadataChanged = true; 0161 } 0162 } 0163 } 0164 else if (it.key().startsWith(QLatin1String("Xmp.")) && 0165 (meta->canWriteXmp(d->url.toLocalFile()) || 0166 writeWithExifTool || 0167 writeToSidecar) 0168 ) 0169 { 0170 if (!d->settings.updIfAvailable || 0171 !meta->getXmpTagString(it.key().toLatin1().constData()).isEmpty()) 0172 { 0173 ret &= meta->setXmpTagString(it.key().toLatin1().constData(), 0174 adj.toString(xmpDateTimeFormat)); 0175 0176 metadataChanged = true; 0177 } 0178 } 0179 0180 if (!ret) 0181 { 0182 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Failed to set metadata for tag" << it.key(); 0183 0184 status |= TimeAdjustList::META_TIME_ERROR; 0185 0186 break; 0187 } 0188 } 0189 0190 if ((status == TimeAdjustList::NOPROCESS_ERROR) && metadataChanged) 0191 { 0192 if (!meta->save(d->url.toLocalFile())) 0193 { 0194 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Failed to update metadata in file" << d->url.fileName(); 0195 0196 status |= TimeAdjustList::META_TIME_ERROR; 0197 } 0198 } 0199 } 0200 else 0201 { 0202 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Failed to load metadata from file" << d->url.fileName(); 0203 0204 status |= TimeAdjustList::META_TIME_ERROR; 0205 } 0206 0207 if (d->settings.updFileModDate) 0208 { 0209 if (!DFileOperations::setModificationTime(d->url.toLocalFile(), adj)) 0210 { 0211 status |= TimeAdjustList::FILE_TIME_ERROR; 0212 } 0213 } 0214 0215 if (d->settings.updFileModDate && writeToSidecar && DMetadata::hasSidecar(d->url.toLocalFile())) 0216 { 0217 if (!DFileOperations::setModificationTime(DMetadata::sidecarPath(d->url.toLocalFile()), adj)) 0218 { 0219 status |= TimeAdjustList::FILE_TIME_ERROR; 0220 } 0221 } 0222 0223 if ((status & TimeAdjustList::META_TIME_ERROR) != TimeAdjustList::META_TIME_ERROR) 0224 { 0225 Q_EMIT signalDateTimeForUrl(d->url, adj, d->settings.updFileModDate); 0226 } 0227 0228 Q_EMIT signalProcessEnded(d->url, org, adj, status); 0229 Q_EMIT signalDone(); 0230 } 0231 0232 // ------------------------------------------------------------------ 0233 0234 class Q_DECL_HIDDEN TimePreviewTask::Private 0235 { 0236 public: 0237 0238 explicit Private() 0239 : thread(nullptr) 0240 { 0241 } 0242 0243 // Settings from GUI. 0244 0245 TimeAdjustContainer settings; 0246 0247 TimeAdjustThread* thread; 0248 0249 QUrl url; 0250 }; 0251 0252 TimePreviewTask::TimePreviewTask(const QUrl& url, TimeAdjustThread* const thread) 0253 : ActionJob(), 0254 d(new Private) 0255 { 0256 d->url = url; 0257 d->thread = thread; 0258 } 0259 0260 TimePreviewTask::~TimePreviewTask() 0261 { 0262 cancel(); 0263 delete d; 0264 } 0265 0266 void TimePreviewTask::setSettings(const TimeAdjustContainer& settings) 0267 { 0268 d->settings = settings; 0269 } 0270 0271 void TimePreviewTask::run() 0272 { 0273 if (m_cancel) 0274 { 0275 return; 0276 } 0277 0278 QDateTime org = d->thread->readTimestamp(d->url); 0279 QDateTime adj = d->settings.calculateAdjustedDate(org, d->thread->indexForUrl(d->url)); 0280 0281 Q_EMIT signalPreviewReady(d->url, org, adj); 0282 Q_EMIT signalDone(); 0283 } 0284 0285 } // namespace DigikamGenericTimeAdjustPlugin 0286 0287 #include "moc_timeadjusttask.cpp"