diff --git a/core/utilities/timeadjust/timeadjustdialog.cpp b/core/utilities/timeadjust/timeadjustdialog.cpp index 0a6330b148..1dab1c2b29 100644 --- a/core/utilities/timeadjust/timeadjustdialog.cpp +++ b/core/utilities/timeadjust/timeadjustdialog.cpp @@ -1,442 +1,442 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-05-16 - * Description : a plugin to set time stamp of picture files. + * Description : dialog to set time stamp of picture files. * * Copyright (C) 2012 by Smit Mehta * Copyright (C) 2003-2005 by Jesper Pedersen * Copyright (C) 2006-2015 by Gilles Caulier * Copyright (c) 2018 by Maik Qualmann * * 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 "timeadjustdialog.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include // Local includes #include "dmetadata.h" #include "dprogresswdg.h" #include "digikam_debug.h" #include "dinfointerface.h" #include "timeadjustlist.h" #include "digikam_version.h" #include "timeadjustthread.h" #include "timeadjustsettings.h" namespace Digikam { class Q_DECL_HIDDEN TimeAdjustDialog::Private { public: Private() { settingsView = 0; progressBar = 0; listView = 0; thread = 0; iface = 0; } TimeAdjustSettings* settingsView; QMap itemsUsedMap; // Map of item urls and Used Timestamps. QMap itemsUpdatedMap; // Map of item urls and Updated Timestamps. QMap itemsStatusMap; // Map of item urls and status flag. DProgressWdg* progressBar; TimeAdjustList* listView; TimeAdjustThread* thread; DInfoInterface* iface; }; TimeAdjustDialog::TimeAdjustDialog(QWidget* const parent, DInfoInterface* const iface) : WSToolDialog(parent), d(new Private) { setWindowTitle(i18n("Adjust Time & Date")); setModal(true); setMinimumSize(900, 500); d->iface = iface; startButton()->setText(i18nc("@action:button", "&Apply")); startButton()->setToolTip(i18nc("@info:tooltip", "Write the corrected date and time for each image")); startButton()->setIcon(QIcon::fromTheme(QLatin1String("dialog-ok-apply"))); QWidget* const mainWidget = new QWidget(this); setMainWidget(mainWidget); QGridLayout* const mainLayout = new QGridLayout(mainWidget); d->listView = new TimeAdjustList(mainWidget); d->settingsView = new TimeAdjustSettings(mainWidget); //d->settingsView->setImageList(d->listView); d->progressBar = new DProgressWdg(mainWidget); d->progressBar->reset(); d->progressBar->hide(); // ---------------------------------------------------------------------------- mainLayout->addWidget(d->listView, 0, 0, 2, 1); mainLayout->addWidget(d->settingsView, 0, 1, 1, 1); mainLayout->addWidget(d->progressBar, 1, 1, 1, 1); mainLayout->setColumnStretch(0, 10); mainLayout->setRowStretch(0, 10); mainLayout->setContentsMargins(QMargins()); // -- Thread Slots/Signals ---------------------------------------------- d->thread = new TimeAdjustThread(this); connect(d->thread, SIGNAL(finished()), this, SLOT(slotThreadFinished())); connect(d->thread, SIGNAL(signalProcessStarted(QUrl)), this, SLOT(slotProcessStarted(QUrl))); connect(d->thread, SIGNAL(signalProcessEnded(QUrl,int)), this, SLOT(slotProcessEnded(QUrl,int))); connect(d->progressBar, SIGNAL(signalProgressCanceled()), this, SLOT(slotCancelThread())); // -- Dialog Slots/Signals ----------------------------------------------- connect(startButton(), &QPushButton::clicked, this, &TimeAdjustDialog::slotApplyClicked); connect(this, &WSToolDialog::cancelClicked, this, &TimeAdjustDialog::slotCancelThread); connect(this, &QDialog::finished, this, &TimeAdjustDialog::slotDialogFinished); connect(d->settingsView, SIGNAL(signalSettingsChanged()), this, SLOT(slotReadTimestamps())); // ----------------------------------------------------------------------- setBusy(false); readSettings(); foreach (const QUrl& url, d->iface->currentSelectedItems()) { d->itemsUsedMap.insert(url, QDateTime()); } d->listView->setIface(d->iface); d->listView->loadImagesFromCurrentSelection(); slotReadTimestamps(); } TimeAdjustDialog::~TimeAdjustDialog() { delete d; } void TimeAdjustDialog::closeEvent(QCloseEvent* e) { if (!e) { return; } slotDialogFinished(); e->accept(); } void TimeAdjustDialog::slotDialogFinished() { saveSettings(); } void TimeAdjustDialog::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Time Adjust Settings")); //d->settingsView->readSettings(group); winId(); KConfigGroup group2 = config->group(QLatin1String("Time Adjust Dialog")); KWindowConfig::restoreWindowSize(windowHandle(), group2); resize(windowHandle()->size()); } void TimeAdjustDialog::saveSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Time Adjust Settings")); //d->settingsView->saveSettings(group); KConfigGroup group2 = config->group(QLatin1String("Time Adjust Dialog")); KWindowConfig::saveWindowSize(windowHandle(), group2); } void TimeAdjustDialog::disableApplTimestamp() { //d->settingsView->disableApplTimestamp(); } void TimeAdjustDialog::slotReadTimestamps() { foreach (const QUrl& url, d->itemsUsedMap.keys()) { d->itemsUsedMap.insert(url, QDateTime()); } TimeAdjustContainer prm = d->settingsView->settings(); switch (prm.dateSource) { case TimeAdjustContainer::APPDATE: { readApplicationTimestamps(); break; } case TimeAdjustContainer::FILEDATE: { readFileTimestamps(); break; } case TimeAdjustContainer::METADATADATE: { readMetadataTimestamps(); break; } default: // CUSTOMDATE { foreach (const QUrl& url, d->itemsUsedMap.keys()) { d->itemsUsedMap.insert(url, d->settingsView->settings().customDate); } break; } } updateListView(); } void TimeAdjustDialog::readApplicationTimestamps() { QList floatingDateItems; foreach (const QUrl& url, d->itemsUsedMap.keys()) { DItemInfo info(d->iface->itemInfo(url)); if (info.dateTime().isValid()) { d->itemsUsedMap.insert(url, info.dateTime()); } else { floatingDateItems.append(url); d->itemsUsedMap.insert(url, QDateTime()); } } // TODO (blackie): handle all items in listview with inexact timestamp through floatingDateItems. } void TimeAdjustDialog::readFileTimestamps() { foreach (const QUrl& url, d->itemsUsedMap.keys()) { QFileInfo fileInfo(url.toLocalFile()); d->itemsUsedMap.insert(url, fileInfo.lastModified()); } } void TimeAdjustDialog::readMetadataTimestamps() { foreach (const QUrl& url, d->itemsUsedMap.keys()) { DMetadata meta; if (!meta.load(url.toLocalFile())) { d->itemsUsedMap.insert(url, QDateTime()); continue; } QDateTime curImageDateTime; TimeAdjustContainer prm = d->settingsView->settings(); switch (prm.metadataSource) { case TimeAdjustContainer::EXIFIPTCXMP: curImageDateTime = meta.getImageDateTime(); break; case TimeAdjustContainer::EXIFCREATED: curImageDateTime = QDateTime::fromString(meta.getExifTagString("Exif.Image.DateTime"), QLatin1String("yyyy:MM:dd hh:mm:ss")); break; case TimeAdjustContainer::EXIFORIGINAL: curImageDateTime = QDateTime::fromString(meta.getExifTagString("Exif.Photo.DateTimeOriginal"), QLatin1String("yyyy:MM:dd hh:mm:ss")); break; case TimeAdjustContainer::EXIFDIGITIZED: curImageDateTime = QDateTime::fromString(meta.getExifTagString("Exif.Photo.DateTimeDigitized"), QLatin1String("yyyy:MM:dd hh:mm:ss")); break; case TimeAdjustContainer::IPTCCREATED: // we have to truncate the timezone from the time, otherwise it cannot be converted to a QTime curImageDateTime = QDateTime(QDate::fromString(meta.getIptcTagString("Iptc.Application2.DateCreated"), Qt::ISODate), QTime::fromString(meta.getIptcTagString("Iptc.Application2.TimeCreated").left(8), Qt::ISODate)); break; case TimeAdjustContainer::XMPCREATED: curImageDateTime = QDateTime::fromString(meta.getXmpTagString("Xmp.xmp.CreateDate"), QLatin1String("yyyy:MM:dd hh:mm:ss")); break; default: // curImageDateTime stays invalid break; }; d->itemsUsedMap.insert(url, curImageDateTime); } } void TimeAdjustDialog::slotApplyClicked() { d->itemsStatusMap.clear(); TimeAdjustContainer prm = d->settingsView->settings(); if (prm.atLeastOneUpdateToProcess()) { d->progressBar->show(); d->progressBar->progressScheduled(i18n("Adjust Time and Date"), true, true); d->progressBar->progressThumbnailChanged(QIcon::fromTheme(QLatin1String("kipi")).pixmap(22, 22)); d->progressBar->setMaximum(d->itemsUsedMap.keys().size()); d->thread->setSettings(prm); d->thread->setUpdatedDates(d->itemsUpdatedMap); if (!d->thread->isRunning()) { d->thread->start(); } setBusy(true); } else { QMessageBox::critical(QApplication::activeWindow(), i18n("Adjust Time & Date"), i18n("Select at least one option")); } } void TimeAdjustDialog::slotCancelThread() { if (d->thread->isRunning()) { d->thread->cancel(); } } void TimeAdjustDialog::setBusy(bool busy) { setRejectButtonMode(busy ? QDialogButtonBox::Cancel : QDialogButtonBox::Close); startButton()->setEnabled(!busy); } void TimeAdjustDialog::slotProcessStarted(const QUrl& url) { d->listView->processing(url); } void TimeAdjustDialog::slotProcessEnded(const QUrl& url, int status) { d->listView->processed(url, (status == TimeAdjustList::NOPROCESS_ERROR)); d->itemsStatusMap.insert(url, status); d->progressBar->setValue(d->progressBar->value()+1); } void TimeAdjustDialog::slotThreadFinished() { d->listView->setStatus(d->itemsStatusMap); setBusy(false); d->progressBar->hide(); d->progressBar->progressCompleted(); saveSettings(); } void TimeAdjustDialog::updateListView() { QApplication::setOverrideCursor(Qt::WaitCursor); TimeAdjustContainer prm = d->settingsView->settings(); d->listView->setItemDates(d->itemsUsedMap, TimeAdjustList::TIMESTAMP_USED); // TODO : this loop can take a while, especially when items mist is huge. // Moving this loop code to ActionThread is the right way for the future. foreach (const QUrl& url, d->itemsUsedMap.keys()) { d->itemsUpdatedMap.insert(url, prm.calculateAdjustedDate(d->itemsUsedMap.value(url))); } d->listView->setItemDates(d->itemsUpdatedMap, TimeAdjustList::TIMESTAMP_UPDATED); QApplication::restoreOverrideCursor(); } } // namespace Digikam diff --git a/core/utilities/timeadjust/timeadjustdialog.h b/core/utilities/timeadjust/timeadjustdialog.h index 2c86e652aa..85d5eb50cd 100644 --- a/core/utilities/timeadjust/timeadjustdialog.h +++ b/core/utilities/timeadjust/timeadjustdialog.h @@ -1,108 +1,108 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-05-16 - * Description : a plugin to set time stamp of picture files. + * Description : dialog to set time stamp of picture files. * * Copyright (C) 2012 by Smit Mehta * Copyright (C) 2003-2005 by Jesper Pedersen * Copyright (C) 2006-2018 by Gilles Caulier * Copyright (c) 2018 by Maik Qualmann * * 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 DIGIKAM_TIME_ADJUST_DIALOG_H #define DIGIKAM_TIME_ADJUST_DIALOG_H // Qt includes #include #include // Local includes #include "wstooldialog.h" #include "digikam_export.h" #include "timeadjustsettings.h" namespace Digikam { class DInfoInterface; class DIGIKAM_EXPORT TimeAdjustDialog : public WSToolDialog { Q_OBJECT public: explicit TimeAdjustDialog(QWidget* const parent, DInfoInterface* const iface); ~TimeAdjustDialog(); void disableApplTimestamp(); Q_SIGNALS: void signalMyCloseClicked(); private Q_SLOTS: void slotApplyClicked(); void slotDialogFinished(); void slotThreadFinished(); void slotCancelThread(); void slotProcessStarted(const QUrl&); void slotProcessEnded(const QUrl&, int); void setBusy(bool); /** Read the Used Timestamps for all selected files * (according to the newly selected source timestamp type), * this will also implicitly update listview info. */ void slotReadTimestamps(); private: /** Called by readTimestamps() to get KIPI host timestamps */ void readApplicationTimestamps(); /** Called by readTimestamps() to get file timestamps */ void readFileTimestamps(); /** Called by readTimestamps() to get file metadata timestamps */ void readMetadataTimestamps(); void readSettings(); void saveSettings(); void updateListView(); protected: void closeEvent(QCloseEvent*); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_TIME_ADJUST_DIALOG_H diff --git a/core/utilities/timeadjust/timeadjustlist.cpp b/core/utilities/timeadjust/timeadjustlist.cpp index 5646adce96..1d1c60b119 100644 --- a/core/utilities/timeadjust/timeadjustlist.cpp +++ b/core/utilities/timeadjust/timeadjustlist.cpp @@ -1,113 +1,109 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-17-04 * Description : time adjust images list. * * Copyright (C) 2012 by Smit Mehta * Copyright (C) 2012-2015 by Gilles Caulier * Copyright (c) 2018 by Maik Qualmann * * 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 "timeadjustlist.h" // Qt includes #include // KDE includes #include -// Local includes - -#include "timeadjustthread.h" - namespace Digikam { TimeAdjustList::TimeAdjustList(QWidget* const parent) : DImagesList(parent) { setControlButtonsPlacement(DImagesList::NoControlButtons); listView()->setColumn(static_cast(TIMESTAMP_USED), i18n("Timestamp Used"), true); listView()->setColumn(static_cast(TIMESTAMP_UPDATED), i18n("Timestamp Updated"), true); listView()->setColumn(static_cast(STATUS), i18n("Status"), true); } TimeAdjustList::~TimeAdjustList() { } void TimeAdjustList::setItemDates(const QMap& map, FieldType type) { foreach (const QUrl& url, map.keys()) { DImagesListViewItem* const item = listView()->findItem(url); if (item) { QDateTime dt = map.value(url); if (dt.isValid()) { item->setText(type, QLocale().toString(dt, QLocale::ShortFormat)); } else { item->setText(type, i18n("not valid")); } } } } void TimeAdjustList::setStatus(const QMap& status) { foreach (const QUrl& url, status.keys()) { DImagesListViewItem* const item = listView()->findItem(url); if (item) { QStringList errors; int flags = status.value(url); if (flags & META_TIME_ERROR) { errors << i18n("Failed to update metadata timestamp"); } if (flags & FILE_TIME_ERROR) { errors << i18n("Failed to update file timestamp"); } if (errors.isEmpty()) { item->setText(STATUS, i18n("Processed without error")); } else { item->setText(STATUS, errors.join(QLatin1String(" | "))); } } } } } // namespace Digikam diff --git a/core/utilities/timeadjust/timeadjustthread.cpp b/core/utilities/timeadjust/timeadjustthread.cpp index 2351a6d39a..e1099d5465 100644 --- a/core/utilities/timeadjust/timeadjustthread.cpp +++ b/core/utilities/timeadjust/timeadjustthread.cpp @@ -1,133 +1,112 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-05-16 * Description : time adjust thread. * * Copyright (C) 2012 by Smit Mehta * Copyright (C) 2012-2018 by Gilles Caulier * Copyright (c) 2018 by Maik Qualmann * * 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 "timeadjustthread.h" // Qt Includes #include // Local includes #include "digikam_debug.h" #include "dinfointerface.h" #include "timeadjusttask.h" namespace Digikam { class Q_DECL_HIDDEN TimeAdjustThread::Private { public: explicit Private() { } // Settings from GUI. TimeAdjustContainer settings; // Map of item urls and Updated Timestamps. QMap itemsMap; }; TimeAdjustThread::TimeAdjustThread(QObject* const parent) : ActionThreadBase(parent), d(new Private) { } TimeAdjustThread::~TimeAdjustThread() { // cancel the thread cancel(); // wait for the thread to finish wait(); delete d; } void TimeAdjustThread::setUpdatedDates(const QMap& map) { d->itemsMap = map; ActionJobCollection collection; foreach (const QUrl& url, d->itemsMap.keys()) { TimeAdjustTask* const t = new TimeAdjustTask(url); t->setSettings(d->settings); t->setItemsMap(map); connect(t, SIGNAL(signalProcessStarted(QUrl)), this, SIGNAL(signalProcessStarted(QUrl))); connect(t, SIGNAL(signalProcessEnded(QUrl,int)), this, SIGNAL(signalProcessEnded(QUrl,int))); connect(this, SIGNAL(signalCancelTask()), t, SLOT(cancel()), Qt::QueuedConnection); collection.insert(t, 0); } appendJobs(collection); } void TimeAdjustThread::setSettings(const TimeAdjustContainer& settings) { d->settings = settings; } void TimeAdjustThread::cancel() { if (isRunning()) emit signalCancelTask(); ActionThreadBase::cancel(); } -/** Static public method also called from GUI to update listview information about new filename - * computed with timeStamp. - */ -QUrl TimeAdjustThread::newUrl(const QUrl& url, const QDateTime& dt) -{ - if (!dt.isValid()) - return QUrl(); - - QFileInfo fi(url.path()); - - QString newFileName = fi.baseName(); - newFileName += QLatin1Char('-'); - newFileName += dt.toString(QLatin1String("yyyyMMddThhmmss")); - newFileName += QLatin1Char('.'); - newFileName += fi.completeSuffix(); - - QUrl newUrl = url; - newUrl.setPath(newUrl.path() + newFileName); - - return newUrl; -} } // namespace Digikam diff --git a/core/utilities/timeadjust/timeadjustthread.h b/core/utilities/timeadjust/timeadjustthread.h index 40716cb9a2..30a30aad57 100644 --- a/core/utilities/timeadjust/timeadjustthread.h +++ b/core/utilities/timeadjust/timeadjustthread.h @@ -1,76 +1,74 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2004-05-16 * Description : time adjust thread. * * Copyright (C) 2012 by Smit Mehta * Copyright (C) 2012-2018 by Gilles Caulier * Copyright (c) 2018 by Maik Qualmann * * 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 DIGIKAM_TIME_ADJUST_THREAD_H #define DIGIKAM_TIME_ADJUST_THREAD_H // Qt includes #include #include #include #include #include // Local includes #include "actionthreadbase.h" #include "timeadjustcontainer.h" namespace Digikam { class TimeAdjustThread : public ActionThreadBase { Q_OBJECT public: explicit TimeAdjustThread(QObject* const parent); ~TimeAdjustThread(); void setUpdatedDates(const QMap& map); void setSettings(const TimeAdjustContainer& settings); void cancel(); - static QUrl newUrl(const QUrl& url, const QDateTime& dt); - Q_SIGNALS: void signalProcessStarted(const QUrl&); void signalProcessEnded(const QUrl&, int); void signalCancelTask(); public: class Private; private: Private* const d; }; } // namespace Digikam #endif // DIGIKAM_TIME_ADJUST_THREAD_H