diff options
Diffstat (limited to 'kipi-plugins/timeadjust/timeadjustdialog.cpp')
-rw-r--r-- | kipi-plugins/timeadjust/timeadjustdialog.cpp | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/kipi-plugins/timeadjust/timeadjustdialog.cpp b/kipi-plugins/timeadjust/timeadjustdialog.cpp new file mode 100644 index 0000000..394c110 --- /dev/null +++ b/kipi-plugins/timeadjust/timeadjustdialog.cpp @@ -0,0 +1,550 @@ +/* ============================================================ + * + * This file is a part of kipi-plugins project + * http://www.kipi-plugins.org + * + * Date : 2004-05-16 + * Description : a plugin to set time stamp of picture files. + * + * Copyright (C) 2003-2005 by Jesper Pedersen <blackie@kde.org> + * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * + * 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. + * + * ============================================================ */ + +// C Ansi includes. + +extern "C" +{ +#include <sys/types.h> +#include <utime.h> +} + +// Qt includes. + +#include <qtooltip.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qvbuttongroup.h> +#include <qvgroupbox.h> +#include <qgroupbox.h> +#include <qhbox.h> +#include <qcheckbox.h> +#include <qradiobutton.h> +#include <qfile.h> +#include <qspinbox.h> +#include <qgrid.h> +#include <qpushbutton.h> +#include <qframe.h> +#include <qtoolbutton.h> + +// KDE includes. + +#include <kiconloader.h> +#include <kdebug.h> +#include <klocale.h> +#include <kapplication.h> +#include <kaboutdata.h> +#include <khelpmenu.h> +#include <kiconloader.h> +#include <kpopupmenu.h> +#include <kstandarddirs.h> +#include <kdatetimewidget.h> +#include <kconfig.h> +#include <kmessagebox.h> + +// LibKipi includes. + +#include <libkipi/interface.h> +#include <libkipi/imageinfo.h> + +// LibKExiv2 includes. + +#include <libkexiv2/kexiv2.h> + +// Local includes. + +#include "kpaboutdata.h" +#include "pluginsversion.h" +#include "timeadjustdialog.h" +#include "timeadjustdialog.moc" + +namespace KIPITimeAdjustPlugin +{ + +class TimeAdjustDialogPrivate +{ + +public: + + TimeAdjustDialogPrivate() + { + add = 0; + subtract = 0; + exif = 0; + custom = 0; + syncEXIFDateCheck = 0; + syncIPTCDateCheck = 0; + exampleBox = 0; + adjustValGrp = 0; + adjustTypeGrp = 0; + infoLabel = 0; + exampleAdj = 0; + secs = 0; + minutes = 0; + hours = 0; + days = 0; + months = 0; + years = 0; + dateCreatedSel = 0; + interface = 0; + about = 0; + todayBtn = 0; + } + + QRadioButton *add; + QRadioButton *subtract; + QRadioButton *exif; + QRadioButton *custom; + + QToolButton *todayBtn; + + QCheckBox *syncEXIFDateCheck; + QCheckBox *syncIPTCDateCheck; + + QVGroupBox *exampleBox; + QVButtonGroup *adjustValGrp; + QButtonGroup *adjustTypeGrp; + + QLabel *infoLabel; + QLabel *exampleAdj; + + QSpinBox *secs; + QSpinBox *minutes; + QSpinBox *hours; + QSpinBox *days; + QSpinBox *months; + QSpinBox *years; + + QDateTime exampleDate; + + KDateTimeWidget *dateCreatedSel; + + KURL::List images; + + KIPI::Interface *interface; + + KIPIPlugins::KPAboutData *about; +}; + +TimeAdjustDialog::TimeAdjustDialog(KIPI::Interface* interface, QWidget* parent) + : KDialogBase(Plain, i18n("Adjust Time & Date"), Help|Ok|Cancel, + Ok, parent, 0, true, true) +{ + d = new TimeAdjustDialogPrivate; + d->interface = interface; + + QVBoxLayout *vlay = new QVBoxLayout(plainPage()); + + // -- About data and help button ---------------------------------------- + + d->about = new KIPIPlugins::KPAboutData(I18N_NOOP("Time Adjust"), + 0, + KAboutData::License_GPL, + I18N_NOOP("A Kipi plugin for adjusting time stamp of picture files"), + "(c) 2003-2005, Jesper K. Pedersen\n" + "(c) 2006-2008, Gilles Caulier"); + + d->about->addAuthor("Jesper K. Pedersen", I18N_NOOP("Author"), + "blackie@kde.org"); + + d->about->addAuthor("Gilles Caulier", I18N_NOOP("Developper and maintainer"), + "caulier dot gilles at gmail dot com"); + + QPushButton *helpButton = actionButton(Help); + KHelpMenu* helpMenu = new KHelpMenu(this, d->about, false); + helpMenu->menu()->removeItemAt(0); + helpMenu->menu()->insertItem(i18n("Plugin Handbook"), this, SLOT(slotHelp()), 0, -1, 0); + helpButton->setPopup(helpMenu->menu()); + + // -- Adjustment type ------------------------------------------------------------ + + QVGroupBox *adjGB = new QVGroupBox(i18n("Adjustment Type"), plainPage()); + d->adjustTypeGrp = new QButtonGroup(1, Qt::Horizontal, adjGB); + d->add = new QRadioButton(i18n("Add"), d->adjustTypeGrp); + d->subtract = new QRadioButton(i18n("Subtract"), d->adjustTypeGrp); + d->exif = new QRadioButton(i18n("Set file date to EXIF/IPTC creation date"), d->adjustTypeGrp); + d->custom = new QRadioButton(i18n("Custom date"), d->adjustTypeGrp); + + d->adjustTypeGrp->setFrameStyle(QFrame::NoFrame); + d->adjustTypeGrp->setInsideMargin(0); + d->adjustTypeGrp->setRadioButtonExclusive(true); + + QHBox *hbox = new QHBox(d->adjustTypeGrp); + QLabel *space1 = new QLabel(hbox); + space1->setFixedWidth(15); + d->dateCreatedSel = new KDateTimeWidget(hbox); + QLabel *space2 = new QLabel(hbox); + space2->setFixedWidth(15); + d->todayBtn = new QToolButton(hbox); + d->todayBtn->setIconSet(SmallIcon("today")); + QToolTip::add(d->todayBtn, i18n("Reset to current date")); + new QLabel(hbox); + + d->syncEXIFDateCheck = new QCheckBox(i18n("Update EXIF creation date"), d->adjustTypeGrp); + d->syncIPTCDateCheck = new QCheckBox(i18n("Update IPTC creation date"), d->adjustTypeGrp); + + vlay->addWidget(adjGB); + + // -- Adjustments ------------------------------------------------------------ + + d->adjustValGrp = new QVButtonGroup(i18n("Adjustments"), plainPage()); + vlay->addWidget(d->adjustValGrp); + + QWidget* grid = new QWidget(d->adjustValGrp); + QGridLayout* gridLay = new QGridLayout(grid, 1, 7, spacingHint()); + gridLay->setColStretch( 2, 1 ); + gridLay->setColStretch( 5, 1 ); + + QLabel* label = new QLabel( i18n("Hours:"), grid ); + d->hours = new QSpinBox( 0, 1000, 1, grid ); + gridLay->addWidget( label, 0, 0 ); + gridLay->addWidget( d->hours, 0, 1 ); + + label = new QLabel( i18n("Minutes:"), grid ); + d->minutes = new QSpinBox( 0, 1000, 1, grid ); + gridLay->addWidget( label, 0, 3 ); + gridLay->addWidget( d->minutes, 0, 4 ); + + label = new QLabel( i18n("Seconds:"), grid ); + d->secs = new QSpinBox( 0, 1000, 1, grid ); + gridLay->addWidget( label, 0, 6 ); + gridLay->addWidget( d->secs, 0, 7 ); + + label = new QLabel( i18n("Days:"), grid ); + d->days = new QSpinBox( 0, 1000, 1, grid ); + gridLay->addWidget( label, 1, 0 ); + gridLay->addWidget( d->days, 1, 1 ); + + label = new QLabel( i18n("Months:"), grid ); + d->months = new QSpinBox( 0, 1000, 1, grid ); + gridLay->addWidget( label, 1, 3 ); + gridLay->addWidget( d->months, 1, 4 ); + + label = new QLabel( i18n("Years:"), grid ); + d->years = new QSpinBox( 0, 1000, 1, grid ); + gridLay->addWidget( label, 1, 6 ); + gridLay->addWidget( d->years, 1, 7 ); + + // -- Example ------------------------------------------------------------ + + d->exampleBox = new QVGroupBox(i18n("Example"), plainPage()); + vlay->addWidget(d->exampleBox); + + d->infoLabel = new QLabel(d->exampleBox); + d->exampleAdj = new QLabel(d->exampleBox); + d->exampleAdj->setAlignment(Qt::AlignCenter); + + vlay->addStretch(); + + // -- Slots/Signals ------------------------------------------------------ + + connect(d->adjustTypeGrp, SIGNAL( clicked(int) ), + this, SLOT( slotAdjustmentTypeChanged() )); + + connect(d->secs, SIGNAL( valueChanged( int ) ), + this, SLOT( slotUpdateExample() )); + + connect(d->minutes, SIGNAL( valueChanged( int ) ), + this, SLOT( slotUpdateExample() )); + + connect(d->hours, SIGNAL( valueChanged( int ) ), + this, SLOT( slotUpdateExample() )); + + connect(d->days, SIGNAL( valueChanged( int ) ), + this, SLOT( slotUpdateExample() )); + + connect(d->months, SIGNAL( valueChanged( int ) ), + this, SLOT( slotUpdateExample() )); + + connect(d->years, SIGNAL( valueChanged( int ) ), + this, SLOT( slotUpdateExample() )); + + connect(d->todayBtn, SIGNAL(clicked()), + this, SLOT(slotResetDateToCurrent())); + + // ----------------------------------------------------------------------- + + readSettings(); + slotAdjustmentTypeChanged(); +} + +TimeAdjustDialog::~TimeAdjustDialog() +{ + delete d->about; + delete d; +} + +void TimeAdjustDialog::slotHelp() +{ + KApplication::kApplication()->invokeHelp("timeadjust", "kipi-plugins"); +} + +void TimeAdjustDialog::slotResetDateToCurrent() +{ + d->dateCreatedSel->setDateTime(QDateTime::currentDateTime()); +} + +void TimeAdjustDialog::closeEvent(QCloseEvent *e) +{ + if (!e) return; + saveSettings(); + e->accept(); +} + +void TimeAdjustDialog::slotCancel() +{ + saveSettings(); + KDialogBase::slotCancel(); +} + +void TimeAdjustDialog::readSettings() +{ + KConfig config("kipirc"); + config.setGroup("Time Adjust Settings"); + + int adjType = config.readNumEntry("Adjustment Type", 0); // add by default. + if (adjType == 0) d->add->setChecked(true); + if (adjType == 1) d->subtract->setChecked(true); + if (adjType == 2) d->exif->setChecked(true); + if (adjType == 3) d->custom->setChecked(true); + + QDateTime current = QDateTime::currentDateTime(); + d->dateCreatedSel->setDateTime(config.readDateTimeEntry("Custom Date", ¤t)); + + d->syncEXIFDateCheck->setChecked(config.readBoolEntry("Sync EXIF Date", true)); + d->syncIPTCDateCheck->setChecked(config.readBoolEntry("Sync IPTC Date", true)); + resize(configDialogSize(config, QString("Time Adjust Dialog"))); +} + +void TimeAdjustDialog::saveSettings() +{ + KConfig config("kipirc"); + config.setGroup("Time Adjust Settings"); + + int adjType = 0; // add + if (d->subtract->isChecked()) adjType = 1; + if (d->exif->isChecked()) adjType = 2; + if (d->custom->isChecked()) adjType = 3; + config.writeEntry("Adjustment Type", adjType); + + config.writeEntry("Custom Date", d->dateCreatedSel->dateTime()); + + config.writeEntry("Sync EXIF Date", d->syncEXIFDateCheck->isChecked()); + config.writeEntry("Sync IPTC Date", d->syncIPTCDateCheck->isChecked()); + saveDialogSize(config, QString("Time Adjust Dialog")); + config.sync(); +} + +void TimeAdjustDialog::setImages(const KURL::List& images) +{ + d->images.clear(); + int exactCount = 0; + int inexactCount = 0; + + for( KURL::List::ConstIterator it = images.begin(); it != images.end(); ++it ) + { + KIPI::ImageInfo info = d->interface->info( *it ); + if (info.isTimeExact()) + { + exactCount++; + d->exampleDate = info.time(); + d->images.append(*it); + } + else + inexactCount++; + } + + if ( inexactCount > 0 ) + { + QString tmpLabel = i18n("1 image will be changed; ", + "%n images will be changed; ", + exactCount) + + i18n("1 image will be skipped due to an inexact date.", + "%n images will be skipped due to inexact dates.", + inexactCount ); + + d->infoLabel->setText(tmpLabel); + } + else + { + d->infoLabel->setText(i18n("1 image will be changed", + "%n images will be changed", + d->images.count())); + } + // PENDING(blackie) handle all images being inexact. + + slotUpdateExample(); +} + +void TimeAdjustDialog::slotUpdateExample() +{ + QString oldDate = d->exampleDate.toString(Qt::LocalDate); + QDateTime date = updateTime(KURL(), d->exampleDate); + QString newDate = date.toString(Qt::LocalDate); + d->exampleAdj->setText(i18n("<b>%1</b><br>would, for example, " + "change into<br><b>%2</b>") + .arg(oldDate).arg(newDate)); +} + +void TimeAdjustDialog::slotAdjustmentTypeChanged() +{ + d->exampleBox->setEnabled(false); + d->adjustValGrp->setEnabled(false); + d->dateCreatedSel->setEnabled(false); + d->todayBtn->setEnabled(false); + d->syncEXIFDateCheck->setEnabled(false); + d->syncIPTCDateCheck->setEnabled(false); + + if (d->add->isChecked() || d->subtract->isChecked()) + { + d->exampleBox->setEnabled(true); + d->adjustValGrp->setEnabled(true); + d->syncEXIFDateCheck->setEnabled(true); + d->syncIPTCDateCheck->setEnabled(true); + } + else if (d->custom->isChecked()) + { + d->dateCreatedSel->setEnabled(true); + d->todayBtn->setEnabled(true); + d->syncEXIFDateCheck->setEnabled(true); + d->syncIPTCDateCheck->setEnabled(true); + } +} + +void TimeAdjustDialog::slotOk() +{ + KURL::List updatedURLs; + QStringList errorFiles; + + for( KURL::List::ConstIterator it = d->images.begin(); it != d->images.end(); ++it ) + { + KURL url = *it; + KIPI::ImageInfo info = d->interface->info(url); + QDateTime dateTime = info.time(); + dateTime = updateTime(info.path(), info.time()); + info.setTime(dateTime); + + if (d->syncEXIFDateCheck->isChecked() || d->syncIPTCDateCheck->isChecked()) + { + bool ret = true; + if (!KExiv2Iface::KExiv2::isReadOnly(url.path())) + { + KExiv2Iface::KExiv2 exiv2Iface; + + ret &= exiv2Iface.load(url.path()); + if (ret) + { + if (d->syncEXIFDateCheck->isChecked()) + { + ret &= exiv2Iface.setExifTagString("Exif.Image.DateTime", + dateTime.toString(QString("yyyy:MM:dd hh:mm:ss")).ascii()); + ret &= exiv2Iface.setExifTagString("Exif.Photo.DateTimeOriginal", + dateTime.toString(QString("yyyy:MM:dd hh:mm:ss")).ascii()); + } + + if (d->syncIPTCDateCheck->isChecked()) + { + ret &= exiv2Iface.setIptcTagString("Iptc.Application2.DateCreated", + dateTime.date().toString(Qt::ISODate)); + ret &= exiv2Iface.setIptcTagString("Iptc.Application2.TimeCreated", + dateTime.time().toString(Qt::ISODate)); + } + + ret &= exiv2Iface.save(url.path()); + + if (!ret) + { + kdDebug() << "Failed to save metadata to file " << url.fileName() << endl; + } + } + else + { + kdDebug() << "Failed to load metadata from file " << url.fileName() << endl; + } + } + + if (!ret) + errorFiles.append(url.fileName()); + else + updatedURLs.append(url); + } + + // See B.K.O #138880: set the file acess and modification time (after than Exiv2 play with metadata). + struct utimbuf ut; + ut.modtime = dateTime.toTime_t(); + ut.actime = dateTime.toTime_t(); + ::utime(QFile::encodeName(url.path()), &ut); + } + + // We use kipi interface refreshImages() method to tell to host than + // metadata from pictures have changed and need to be re-read. + d->interface->refreshImages(d->images); + + if (!errorFiles.isEmpty() && (d->syncEXIFDateCheck->isChecked() || d->syncIPTCDateCheck->isChecked())) + { + KMessageBox::informationList( + kapp->activeWindow(), + i18n("Unable to set date and time like picture metadata from:"), + errorFiles, + i18n("Adjust Time & Date")); + } + + saveSettings(); + accept(); +} + +QDateTime TimeAdjustDialog::updateTime(const KURL& url, const QDateTime& time) const +{ + if (d->custom->isChecked()) + { + return d->dateCreatedSel->dateTime(); + } + else if (d->exif->isChecked()) + { + KExiv2Iface::KExiv2 exiv2Iface; + if ( !exiv2Iface.load(url.path()) ) + return time; + + QDateTime newTime = exiv2Iface.getImageDateTime(); + if (newTime.isValid()) + return newTime; + else + return time; + } + else + { + int sign = -1; + if (d->add->isChecked()) + sign = 1; + + QDateTime newTime = time.addSecs( sign * ( d->secs->value() + + 60*d->minutes->value() + + 60*60*d->hours->value() + + 24*60*60*d->days->value() ) ); + newTime = newTime.addMonths( sign * d->months->value() ); + newTime = newTime.addYears( sign * d->years->value() ); + return newTime; + } +} + +} // NameSpace KIPITimeAdjustPlugin |