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 : 2004-05-16 0007 * Description : dialog to set time stamp of picture files. 0008 * 0009 * SPDX-FileCopyrightText: 2012 by Smit Mehta <smit dot meh at gmail dot com> 0010 * SPDX-FileCopyrightText: 2003-2005 by Jesper Pedersen <blackie at kde dot org> 0011 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * SPDX-FileCopyrightText: 2018-2021 by Maik Qualmann <metzpinguin at gmail dot com> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "timeadjustdialog.h" 0019 0020 // Qt includes 0021 0022 #include <QButtonGroup> 0023 #include <QCheckBox> 0024 #include <QCloseEvent> 0025 #include <QComboBox> 0026 #include <QCursor> 0027 #include <QFile> 0028 #include <QFileInfo> 0029 #include <QGridLayout> 0030 #include <QGroupBox> 0031 #include <QLabel> 0032 #include <QMap> 0033 #include <QTimer> 0034 #include <QPointer> 0035 #include <QPushButton> 0036 #include <QRadioButton> 0037 #include <QSpinBox> 0038 #include <QDateTime> 0039 #include <QTimeEdit> 0040 #include <QToolButton> 0041 #include <QVBoxLayout> 0042 #include <QApplication> 0043 #include <QMessageBox> 0044 #include <QWindow> 0045 #include <QScopedPointer> 0046 0047 // KDE includes 0048 0049 #include <kconfiggroup.h> 0050 #include <ksharedconfig.h> 0051 #include <klocalizedstring.h> 0052 0053 // Local includes 0054 0055 #include "dmetadata.h" 0056 #include "dprogresswdg.h" 0057 #include "digikam_debug.h" 0058 #include "dxmlguiwindow.h" 0059 #include "timeadjustlist.h" 0060 #include "digikam_version.h" 0061 #include "timeadjustthread.h" 0062 0063 namespace DigikamGenericTimeAdjustPlugin 0064 { 0065 0066 class Q_DECL_HIDDEN TimeAdjustDialog::Private 0067 { 0068 0069 public: 0070 0071 explicit Private() 0072 : settingsView(nullptr), 0073 previewTimer(nullptr), 0074 updateTimer (nullptr), 0075 exitAfterOk (false), 0076 progressBar (nullptr), 0077 listView (nullptr), 0078 thread (nullptr), 0079 iface (nullptr) 0080 { 0081 } 0082 0083 TimeAdjustSettings* settingsView; 0084 0085 QMap<QUrl, int> itemsUsedMap; // Map of item urls and index. 0086 0087 QTimer* previewTimer; 0088 QTimer* updateTimer; 0089 0090 bool exitAfterOk; 0091 0092 DProgressWdg* progressBar; 0093 TimeAdjustList* listView; 0094 0095 TimeAdjustThread* thread; 0096 0097 DInfoInterface* iface; 0098 }; 0099 0100 TimeAdjustDialog::TimeAdjustDialog(QWidget* const parent, DInfoInterface* const iface) 0101 : DPluginDialog(parent, QLatin1String("Time Adjust Dialog")), 0102 d (new Private) 0103 { 0104 setWindowTitle(i18nc("@title:window", "Adjust Time & Date")); 0105 setMinimumSize(900, 500); 0106 setModal(true); 0107 0108 d->iface = iface; 0109 0110 m_buttons->addButton(QDialogButtonBox::Yes); 0111 m_buttons->addButton(QDialogButtonBox::Apply); 0112 m_buttons->addButton(QDialogButtonBox::Close); 0113 m_buttons->button(QDialogButtonBox::Yes)->setText(i18n("OK")); 0114 m_buttons->button(QDialogButtonBox::Yes)->setAutoDefault(false); 0115 m_buttons->button(QDialogButtonBox::Apply)->setAutoDefault(false); 0116 m_buttons->button(QDialogButtonBox::Close)->setAutoDefault(false); 0117 0118 m_buttons->button(QDialogButtonBox::Yes)->setToolTip(i18nc("@info:tooltip", 0119 "Write the corrected date and time for each image and close dialog")); 0120 m_buttons->button(QDialogButtonBox::Apply)->setToolTip(i18nc("@info:tooltip", 0121 "Write the corrected date and time for each image")); 0122 0123 0124 QWidget* const mainWidget = new QWidget(this); 0125 QVBoxLayout* const vbx = new QVBoxLayout(this); 0126 vbx->addWidget(mainWidget); 0127 vbx->addWidget(m_buttons); 0128 setLayout(vbx); 0129 0130 QGridLayout* const mainLayout = new QGridLayout(mainWidget); 0131 d->listView = new TimeAdjustList(mainWidget); 0132 d->settingsView = new TimeAdjustSettings(mainWidget, true); 0133 d->progressBar = new DProgressWdg(mainWidget); 0134 d->progressBar->reset(); 0135 d->progressBar->hide(); 0136 0137 // ---------------------------------------------------------------------------- 0138 0139 mainLayout->addWidget(d->listView, 0, 0, 2, 1); 0140 mainLayout->addWidget(d->settingsView, 0, 1, 1, 1); 0141 mainLayout->addWidget(d->progressBar, 1, 1, 1, 1); 0142 mainLayout->setColumnStretch(0, 10); 0143 mainLayout->setRowStretch(0, 10); 0144 mainLayout->setContentsMargins(QMargins()); 0145 0146 // ---------------------------------------------------------------------------- 0147 0148 d->previewTimer = new QTimer(this); 0149 d->previewTimer->setSingleShot(true); 0150 d->previewTimer->setInterval(500); 0151 0152 d->updateTimer = new QTimer(this); 0153 d->updateTimer->setSingleShot(true); 0154 d->updateTimer->setInterval(250); 0155 0156 connect(d->previewTimer, SIGNAL(timeout()), 0157 this, SLOT(slotPreviewTimer())); 0158 0159 connect(d->updateTimer, SIGNAL(timeout()), 0160 this, SLOT(slotUpdateTimer())); 0161 0162 // -- Thread Slots/Signals ---------------------------------------------- 0163 0164 d->thread = new TimeAdjustThread(this, d->iface); 0165 0166 connect(d->thread, SIGNAL(signalProcessEnded(QUrl,QDateTime,QDateTime,int)), 0167 this, SLOT(slotProcessEnded(QUrl,QDateTime,QDateTime,int))); 0168 0169 connect(d->thread, SIGNAL(signalPreviewReady(QUrl,QDateTime,QDateTime)), 0170 this, SLOT(slotPreviewReady(QUrl,QDateTime,QDateTime))); 0171 0172 connect(d->thread, SIGNAL(signalDateTimeForUrl(QUrl,QDateTime,bool)), 0173 d->iface, SLOT(slotDateTimeForUrl(QUrl,QDateTime,bool))); 0174 0175 connect(d->progressBar, SIGNAL(signalProgressCanceled()), 0176 this, SLOT(slotCancelThread())); 0177 0178 connect(d->thread, SIGNAL(signalProcessStarted(QUrl)), 0179 this, SLOT(slotProcessStarted(QUrl))); 0180 0181 connect(d->thread, SIGNAL(finished()), 0182 this, SLOT(slotThreadFinished())); 0183 0184 // -- Dialog Slots/Signals ----------------------------------------------- 0185 0186 connect(m_buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), 0187 this, SLOT(slotCancelThread())); 0188 0189 connect(m_buttons->button(QDialogButtonBox::Apply), SIGNAL(clicked()), 0190 this, SLOT(slotUpdateTimestamps())); 0191 0192 connect(m_buttons->button(QDialogButtonBox::Yes), SIGNAL(clicked()), 0193 this, SLOT(slotOkExitTimestamps())); 0194 0195 connect(d->settingsView, SIGNAL(signalSettingsChangedTool()), 0196 this, SLOT(slotPreviewTimestamps())); 0197 0198 connect(d->settingsView, SIGNAL(signalSettingsChanged()), 0199 this, SLOT(slotPreviewTimestamps())); 0200 0201 connect(this, SIGNAL(finished(int)), 0202 this, SLOT(slotDialogFinished())); 0203 0204 connect(d->listView->listView(), &DItemsListView::itemSelectionChanged, 0205 this, [this]() 0206 { 0207 d->settingsView->setCurrentItemUrl(d->listView->getCurrentUrl()); 0208 } 0209 ); 0210 0211 // ----------------------------------------------------------------------- 0212 0213 setBusy(false); 0214 readSettings(); 0215 0216 int index = 0; 0217 0218 d->listView->setIface(d->iface); 0219 d->listView->loadImagesFromCurrentSelection(); 0220 0221 Q_FOREACH (const QUrl& url, d->listView->imageUrls()) 0222 { 0223 d->itemsUsedMap.insert(url, index); 0224 ++index; 0225 } 0226 0227 slotPreviewTimestamps(); 0228 } 0229 0230 TimeAdjustDialog::~TimeAdjustDialog() 0231 { 0232 if (d->thread->isRunning()) 0233 { 0234 d->thread->cancel(); 0235 d->thread->wait(); 0236 } 0237 0238 delete d; 0239 } 0240 0241 void TimeAdjustDialog::closeEvent(QCloseEvent* e) 0242 { 0243 if (d->thread->isRunning()) 0244 { 0245 d->thread->cancel(); 0246 d->thread->wait(); 0247 0248 e->ignore(); 0249 0250 return; 0251 } 0252 0253 slotDialogFinished(); 0254 0255 e->accept(); 0256 } 0257 0258 void TimeAdjustDialog::slotDialogFinished() 0259 { 0260 saveSettings(); 0261 } 0262 0263 void TimeAdjustDialog::readSettings() 0264 { 0265 TimeAdjustContainer prm; 0266 0267 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0268 KConfigGroup group = config->group(QLatin1String("Time Adjust Settings")); 0269 0270 prm.customDate = group.readEntry(QLatin1String("Custom Date"), QDateTime()); 0271 prm.customDate.setTimeSpec(Qt::UTC); 0272 prm.customTime = group.readEntry(QLatin1String("Custom Time"), QDateTime()); 0273 prm.customTime.setTimeSpec(Qt::UTC); 0274 prm.adjustmentType = group.readEntry(QLatin1String("Adjustment Type"), 0); 0275 prm.adjustmentDays = group.readEntry(QLatin1String("Adjustment Days"), 0); 0276 prm.adjustmentTime = group.readEntry(QLatin1String("Adjustment Time"), QDateTime()); 0277 prm.adjustmentTime.setTimeSpec(Qt::UTC); 0278 0279 prm.updIfAvailable = group.readEntry(QLatin1String("Update Only If Available Time"), true); 0280 prm.updFileModDate = group.readEntry(QLatin1String("Update File Modification Time"), true); 0281 prm.updEXIFModDate = group.readEntry(QLatin1String("Update EXIF Modification Time"), true); 0282 prm.updEXIFOriDate = group.readEntry(QLatin1String("Update EXIF Original Time"), true); 0283 prm.updEXIFDigDate = group.readEntry(QLatin1String("Update EXIF Digitization Time"), true); 0284 prm.updEXIFThmDate = group.readEntry(QLatin1String("Update EXIF Thumbnail Time"), true); 0285 prm.updIPTCDate = group.readEntry(QLatin1String("Update IPTC Time"), true); 0286 prm.updXMPVideo = group.readEntry(QLatin1String("Update XMP Video Time"), true); 0287 prm.updXMPDate = group.readEntry(QLatin1String("Update XMP Creation Time"), true); 0288 0289 prm.dateSource = group.readEntry(QLatin1String("Use Timestamp Type"), 0); 0290 prm.metadataSource = group.readEntry(QLatin1String("Meta Timestamp Type"), 0); 0291 prm.fileDateSource = group.readEntry(QLatin1String("File Timestamp Type"), 0); 0292 0293 d->settingsView->setSettings(prm); 0294 } 0295 0296 void TimeAdjustDialog::saveSettings() 0297 { 0298 TimeAdjustContainer prm = d->settingsView->settings(); 0299 0300 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0301 KConfigGroup group = config->group(QLatin1String("Time Adjust Settings")); 0302 0303 group.writeEntry(QLatin1String("Custom Date"), prm.customDate); 0304 group.writeEntry(QLatin1String("Custom Time"), prm.customTime); 0305 0306 group.writeEntry(QLatin1String("Adjustment Type"), prm.adjustmentType); 0307 group.writeEntry(QLatin1String("Adjustment Days"), prm.adjustmentDays); 0308 group.writeEntry(QLatin1String("Adjustment Time"), prm.adjustmentTime); 0309 0310 group.writeEntry(QLatin1String("Update Only If Available Time"), prm.updIfAvailable); 0311 group.writeEntry(QLatin1String("Update File Modification Time"), prm.updFileModDate); 0312 group.writeEntry(QLatin1String("Update EXIF Modification Time"), prm.updEXIFModDate); 0313 group.writeEntry(QLatin1String("Update EXIF Original Time"), prm.updEXIFOriDate); 0314 group.writeEntry(QLatin1String("Update EXIF Digitization Time"), prm.updEXIFDigDate); 0315 group.writeEntry(QLatin1String("Update EXIF Thumbnail Time"), prm.updEXIFThmDate); 0316 group.writeEntry(QLatin1String("Update IPTC Time"), prm.updIPTCDate); 0317 group.writeEntry(QLatin1String("Update XMP Video Time"), prm.updXMPVideo); 0318 group.writeEntry(QLatin1String("Update XMP Creation Time"), prm.updXMPDate); 0319 0320 group.writeEntry(QLatin1String("Use Timestamp Type"), prm.dateSource); 0321 group.writeEntry(QLatin1String("Meta Timestamp Type"), prm.metadataSource); 0322 group.writeEntry(QLatin1String("File Timestamp Type"), prm.fileDateSource); 0323 } 0324 0325 void TimeAdjustDialog::slotPreviewTimestamps() 0326 { 0327 if (d->thread->isRunning()) 0328 { 0329 d->thread->cancel(); 0330 d->thread->wait(); 0331 } 0332 0333 d->previewTimer->start(); 0334 } 0335 0336 void TimeAdjustDialog::slotUpdateTimestamps() 0337 { 0338 if (d->thread->isRunning()) 0339 { 0340 d->thread->cancel(); 0341 d->thread->wait(); 0342 } 0343 0344 d->updateTimer->start(); 0345 } 0346 0347 void TimeAdjustDialog::slotOkExitTimestamps() 0348 { 0349 d->exitAfterOk = true; 0350 0351 slotUpdateTimestamps(); 0352 } 0353 0354 void TimeAdjustDialog::slotPreviewTimer() 0355 { 0356 d->listView->setWaitStatus(); 0357 0358 d->thread->setSettings(d->settingsView->settings()); 0359 d->thread->setPreviewDates(d->itemsUsedMap); 0360 d->thread->start(); 0361 } 0362 0363 void TimeAdjustDialog::slotUpdateTimer() 0364 { 0365 d->listView->setWaitStatus(); 0366 0367 d->progressBar->show(); 0368 d->progressBar->setMaximum(d->itemsUsedMap.keys().size()); 0369 d->progressBar->progressScheduled(i18nc("@info", "Adjust Time and Date"), true, true); 0370 d->progressBar->progressThumbnailChanged(QIcon::fromTheme(QLatin1String("appointment-new")).pixmap(22, 22)); 0371 0372 d->thread->setSettings(d->settingsView->settings()); 0373 d->thread->setUpdatedDates(d->itemsUsedMap); 0374 d->thread->start(); 0375 0376 setBusy(true); 0377 } 0378 0379 void TimeAdjustDialog::slotCancelThread() 0380 { 0381 if (d->thread->isRunning()) 0382 { 0383 d->thread->cancel(); 0384 d->thread->wait(); 0385 } 0386 0387 d->exitAfterOk = false; 0388 0389 if (m_buttons->button(QDialogButtonBox::Yes)->isEnabled()) 0390 { 0391 accept(); 0392 } 0393 } 0394 0395 void TimeAdjustDialog::setBusy(bool busy) 0396 { 0397 if (busy) 0398 { 0399 m_buttons->button(QDialogButtonBox::Close)->setText(i18nc("@action", "Cancel")); 0400 m_buttons->button(QDialogButtonBox::Close)->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel"))); 0401 m_buttons->button(QDialogButtonBox::Close)->setToolTip(i18nc("@info", "Cancel current operation")); 0402 } 0403 else 0404 { 0405 m_buttons->button(QDialogButtonBox::Close)->setText(i18nc("@action", "Close")); 0406 m_buttons->button(QDialogButtonBox::Close)->setIcon(QIcon::fromTheme(QLatin1String("window-close"))); 0407 m_buttons->button(QDialogButtonBox::Close)->setToolTip(i18nc("@info", "Close window")); 0408 } 0409 0410 m_buttons->button(QDialogButtonBox::Apply)->setEnabled(!busy); 0411 m_buttons->button(QDialogButtonBox::Yes)->setEnabled(!busy); 0412 d->settingsView->setEnabled(!busy); 0413 } 0414 0415 void TimeAdjustDialog::slotProcessStarted(const QUrl& url) 0416 { 0417 d->listView->processing(url); 0418 } 0419 0420 void TimeAdjustDialog::slotPreviewReady(const QUrl& url, 0421 const QDateTime& org, 0422 const QDateTime& adj) 0423 { 0424 d->listView->setStatus(url, org, adj); 0425 } 0426 0427 void TimeAdjustDialog::slotProcessEnded(const QUrl& url, 0428 const QDateTime& org, 0429 const QDateTime& adj, int status) 0430 { 0431 d->listView->processed(url, (status == TimeAdjustList::NOPROCESS_ERROR)); 0432 d->listView->setStatus(url, org, adj, status); 0433 0434 d->progressBar->setValue(d->progressBar->value() + 1); 0435 } 0436 0437 void TimeAdjustDialog::slotThreadFinished() 0438 { 0439 setBusy(false); 0440 d->progressBar->hide(); 0441 d->progressBar->progressCompleted(); 0442 0443 if (d->exitAfterOk) 0444 { 0445 accept(); 0446 } 0447 } 0448 0449 } // namespace DigikamGenericTimeAdjustPlugin 0450 0451 #include "moc_timeadjustdialog.cpp"