File indexing completed on 2025-11-09 04:10:13

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-05-31
0007  * Description : Figure out camera clock delta from a clock picture.
0008  *
0009  * SPDX-FileCopyrightText: 2009      by Pieter Edelman <p dot edelman at gmx dot net>
0010  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2014      by Michael G. Hansen <mike at mghansen dot de>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "clockphotodialog.h"
0018 
0019 // Qt includes
0020 
0021 #include <QDialogButtonBox>
0022 #include <QStandardPaths>
0023 #include <QDateTimeEdit>
0024 #include <QHBoxLayout>
0025 #include <QVBoxLayout>
0026 #include <QPushButton>
0027 #include <QScopedPointer>
0028 #include <QWindow>
0029 #include <QLabel>
0030 #include <QIcon>
0031 #include <QSize>
0032 #include <QDir>
0033 
0034 // KDE includes
0035 
0036 #include <kconfiggroup.h>
0037 #include <ksharedconfig.h>
0038 #include <klocalizedstring.h>
0039 
0040 // Local includes
0041 
0042 #include "dmetadata.h"
0043 #include "imagedialog.h"
0044 #include "timeadjustcontainer.h"
0045 #include "graphicsdimgview.h"
0046 #include "dimgpreviewitem.h"
0047 #include "dxmlguiwindow.h"
0048 
0049 namespace Digikam
0050 {
0051 
0052 class Q_DECL_HIDDEN ClockPhotoDialog::Private
0053 {
0054 
0055 public:
0056 
0057     explicit Private()
0058       : buttons       (nullptr),
0059         calendar      (nullptr),
0060         dtLabel       (nullptr),
0061         previewManager(nullptr)
0062     {
0063     }
0064 
0065     DeltaTime         deltaValues;
0066 
0067     QDialogButtonBox* buttons;
0068     QDateTimeEdit*    calendar;
0069     QDateTime         photoDateTime;
0070     QLabel*           dtLabel;
0071 
0072     GraphicsDImgView* previewManager;
0073 };
0074 
0075 ClockPhotoDialog::ClockPhotoDialog(QWidget* const parent, const QUrl& defaultUrl)
0076     : QDialog(parent),
0077       d      (new Private)
0078 {
0079     // This dialog should be modal with three buttons: Ok, Cancel, and load
0080     // photo. For this third button, the User1 button from KDialog is used.
0081     // The Ok button is only enable when a photo is loaded.
0082 
0083     setWindowTitle(i18nc("@title:window", "Determine Time Difference With Clock Photo"));
0084 
0085     d->buttons = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
0086     d->buttons->button(QDialogButtonBox::Cancel)->setDefault(true);
0087     d->buttons->button(QDialogButtonBox::Ok)->setEnabled(false);
0088     setMinimumWidth(500);
0089     setMinimumHeight(500);
0090     d->buttons->button(QDialogButtonBox::Apply)->setText(i18n("Load different photo"));
0091     d->buttons->button(QDialogButtonBox::Apply)->setIcon(QIcon::fromTheme(QLatin1String("document-open")));
0092 
0093     QWidget* const mainWidget = new QWidget(this);
0094     QVBoxLayout* const vBox   = new QVBoxLayout(mainWidget);
0095 
0096     // Some explanation.
0097 
0098     QLabel* const explanationLabel = new QLabel(i18n("If you have a photo in your set with a clock or "
0099                                                      "another external time source on it, you can load "
0100                                                      "it here and set the indicator to the (date and) "
0101                                                      "time displayed. The difference of your internal "
0102                                                      "camera clock will be determined from this "
0103                                                      "setting."));
0104     explanationLabel->setWordWrap(true);
0105     vBox->addWidget(explanationLabel);
0106 
0107     d->previewManager = new GraphicsDImgView(this);
0108     d->previewManager->setItem(new DImgPreviewItem());
0109     d->previewManager->setMinimumSize(QSize(200, 200));
0110     vBox->addWidget(d->previewManager);
0111 
0112     // The date and time entry widget allows the user to enter the date and time
0113     // displayed in the image. The format is explicitly set, otherwise seconds
0114     // might not get displayed.
0115 
0116     d->dtLabel  = new QLabel();
0117     d->calendar = new QDateTimeEdit();
0118     d->calendar->setDisplayFormat(QLatin1String("d MMMM yyyy, hh:mm:ss"));
0119     d->calendar->setCalendarPopup(true);
0120     d->calendar->setEnabled(false);
0121     QHBoxLayout* const hBox2 = new QHBoxLayout(mainWidget);
0122     hBox2->addStretch();
0123     hBox2->addWidget(d->dtLabel);
0124     hBox2->addWidget(d->calendar);
0125     vBox->addLayout(hBox2);
0126 
0127     vBox->addWidget(d->buttons);
0128     setLayout(vBox);
0129 
0130     // Setup the signals and slots.
0131 
0132     connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()),
0133             this, SLOT(slotOk()));
0134 
0135     connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
0136             this, SLOT(slotCancel()));
0137 
0138     connect(d->buttons->button(QDialogButtonBox::Apply), SIGNAL(clicked()),
0139             this, SLOT(slotLoadPhoto()));
0140 
0141     // Show the window.
0142 
0143     loadSettings();
0144     show();
0145 
0146     if (defaultUrl.isValid())
0147     {
0148         setImage(defaultUrl);
0149     }
0150     else
0151     {
0152         // No default url was given.
0153         // Upon initialization, present the user with a photo loading dialog. This
0154         // is done before the main dialog is drawn.
0155 
0156         slotLoadPhoto();
0157     }
0158 }
0159 
0160 ClockPhotoDialog::~ClockPhotoDialog()
0161 {
0162     delete d;
0163 }
0164 
0165 DeltaTime ClockPhotoDialog::deltaValues() const
0166 {
0167     return d->deltaValues;
0168 }
0169 
0170 bool ClockPhotoDialog::setImage(const QUrl& imageFile)
0171 {
0172     bool success = false;
0173     QString msg  = i18n("<font color=\"red\"><b>Could not load<br/>"
0174                         "image %1.</b></font>",
0175                         imageFile.fileName());
0176 
0177     d->previewManager->previewItem()->setPath(imageFile.toLocalFile(), true);
0178 
0179     // Try to read the datetime data.
0180 
0181     QScopedPointer<DMetadata> meta(new DMetadata);
0182 
0183     if (meta->load(imageFile.toLocalFile()))
0184     {
0185         d->photoDateTime = meta->getItemDateTime();
0186 
0187         if (d->photoDateTime.isValid())
0188         {
0189             msg = i18n("The clock date and time:");
0190 
0191             // Set the datetime widget to the photo datetime.
0192 
0193             d->calendar->setDateTime(d->photoDateTime);
0194             d->calendar->setEnabled(true);
0195             success = true;
0196         }
0197     }
0198 
0199     d->dtLabel->setText(msg);
0200 
0201     // Disable all the GUI elements if loading failed.
0202 
0203     d->calendar->setEnabled(success);
0204 
0205     // enable the ok button if loading succeeded
0206 
0207     d->buttons->button(QDialogButtonBox::Ok)->setEnabled(success);
0208 
0209     return success;
0210 }
0211 
0212 void ClockPhotoDialog::loadSettings()
0213 {
0214     KConfigGroup group = KSharedConfig::openConfig()->group(QLatin1String("Clock Photo Dialog"));
0215 
0216     winId();
0217     DXmlGuiWindow::restoreWindowSize(windowHandle(), group);
0218     resize(windowHandle()->size());
0219 }
0220 
0221 void ClockPhotoDialog::saveSettings()
0222 {
0223     KConfigGroup group = KSharedConfig::openConfig()->group(QLatin1String("Clock Photo Dialog"));
0224     DXmlGuiWindow::saveWindowSize(windowHandle(), group);
0225 }
0226 
0227 void ClockPhotoDialog::slotLoadPhoto()
0228 {
0229     QUrl place;
0230     QStringList pics = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
0231 
0232     if (pics.isEmpty())
0233     {
0234         place = QUrl::fromLocalFile(QDir::homePath());
0235     }
0236     else
0237     {
0238         place = QUrl::fromLocalFile(pics.first());
0239     }
0240 
0241     ImageDialog dlg(this, place, true, i18n("Select Image to Extract Clock Photo"));
0242 
0243     if (!dlg.url().isEmpty())
0244     {
0245         // If the user selected a proper photo, try to load it.
0246 
0247         setImage(dlg.url());
0248     }
0249 }
0250 
0251 void ClockPhotoDialog::slotOk()
0252 {
0253     // Called when the ok button is pressed. Calculate the time difference
0254     // between the photo and the user set datetime information, and store it in
0255     // the public variables.
0256 
0257     // Determine the number of seconds between the dates.
0258 
0259     int delta = d->photoDateTime.secsTo(d->calendar->dateTime());
0260 
0261     // If the photo datetime is newer than the user datetime, it results in subtraction.
0262 
0263     if (delta < 0)
0264     {
0265         d->deltaValues.deltaNegative = true;
0266         delta                       *= -1;
0267     }
0268     else
0269     {
0270         d->deltaValues.deltaNegative = false;
0271     }
0272 
0273     // Calculate the number of days, hours, minutes and seconds.
0274 
0275     d->deltaValues.deltaDays    = delta / 86400;
0276     delta                       = delta % 86400;
0277     d->deltaValues.deltaHours   = delta / 3600;
0278     delta                       = delta % 3600;
0279     d->deltaValues.deltaMinutes = delta / 60;
0280     delta                       = delta % 60;
0281     d->deltaValues.deltaSeconds = delta;
0282 
0283     // Accept the dialog.
0284 
0285     saveSettings();
0286     accept();
0287 }
0288 
0289 void ClockPhotoDialog::slotCancel()
0290 {
0291     saveSettings();
0292     reject();
0293 }
0294 
0295 } // namespace Digikam
0296 
0297 #include "moc_clockphotodialog.cpp"