1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2009-08-08
7 * Description : an option to provide date information to the parser
8 *
9 * Copyright (C) 2009-2012 by Andi Clemens <andi dot clemens at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "dateoption.h"
25
26 // Qt includes
27
28 #include <QDateTime>
29 #include <QPointer>
30 #include <QTimer>
31 #include <QValidator>
32
33 // KDE includes
34
35 #include <klocalizedstring.h>
36
37 // Local includes
38
39 #include "digikam_debug.h"
40 #include "ui_dateoptiondialogwidget.h"
41
42 namespace Digikam
43 {
44
getDateFormatLinkText()45 static QString getDateFormatLinkText()
46 {
47 const QString dateFormatLink = QString::fromUtf8("<a href='https://qt-project.org/doc/qt-5.0/qtcore/qdatetime.html#toString'>%1</a>");
48 const QString dateFormatLinkDescr = i18nc("@info: date format settings", "format settings");
49
50 return dateFormatLink.arg(dateFormatLinkDescr);
51 }
52
53 // --------------------------------------------------------
54
DateFormat()55 DateFormat::DateFormat()
56 {
57 m_map.insert(Standard, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Standard"), QLatin1String("yyyyMMddThhmmss")));
58 m_map.insert(ISO, DateFormatDescriptor(i18nc("@item:inlistbox date format", "ISO"), Qt::ISODate));
59 m_map.insert(FullText, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Text"), Qt::TextDate));
60 m_map.insert(UnixTimeStamp, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Unix Time Stamp"), QVariant()));
61 m_map.insert(Custom, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Custom"), QVariant()));
62 }
63
type(const QString & identifier)64 DateFormat::Type DateFormat::type(const QString& identifier)
65 {
66 if (identifier.isEmpty())
67 {
68 return Standard;
69 }
70
71 for (int i = 0 ; i < m_map.size() ; ++i)
72 {
73 if (m_map.at(i).first == identifier)
74 {
75 return (Type)i;
76 }
77 }
78
79 return Standard;
80 }
81
identifier(Type type)82 QString DateFormat::identifier(Type type)
83 {
84 return m_map.at((int)type).first;
85 }
86
format(Type type)87 QVariant DateFormat::format(Type type)
88 {
89 return m_map.at((int)type).second;
90 }
91
format(const QString & identifier)92 QVariant DateFormat::format(const QString& identifier)
93 {
94 if (identifier.isEmpty())
95 {
96 return m_map.at(Standard).second;
97 }
98
99 foreach (const DateFormatDescriptor& desc, m_map)
100 {
101 if (desc.first == identifier)
102 {
103 return desc.second;
104 }
105 }
106 return QVariant();
107 }
108
109 // --------------------------------------------------------
110
DateOptionDialog(Rule * parent)111 DateOptionDialog::DateOptionDialog(Rule* parent)
112 : RuleDialog(parent),
113 ui(new Ui::DateOptionDialogWidget)
114 {
115 QWidget* const mainWidget = new QWidget(this);
116 ui->setupUi(mainWidget);
117
118 // --------------------------------------------------------
119
120 // fill the date source combobox
121
122 ui->dateSourcePicker->addItem(i18nc("@item: Get date information from the image", "Image"),
123 QVariant(FromImage));
124 /*
125 ui->dateSourcePicker->addItem(i18nc("Get date information from the current date", "Current Date"),
126 QVariant(CurrentDateTime));
127 */
128 ui->dateSourcePicker->addItem(i18nc("@item: Set a fixed date", "Fixed Date"),
129 QVariant(FixedDateTime));
130
131 // fill the date format combobox
132
133 DateFormat df;
134
135 foreach (const DateFormat::DateFormatDescriptor& desc, df.map())
136 {
137 ui->dateFormatPicker->addItem(desc.first);
138 }
139
140 // set the datePicker and timePicker to the current local datetime
141
142 QDateTime currentDateTime = QDateTime::currentDateTime();
143 ui->datePicker->setDate(currentDateTime.date());
144 ui->timePicker->setTime(currentDateTime.time());
145
146 ui->dateFormatLink->setOpenExternalLinks(true);
147 ui->dateFormatLink->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
148 ui->dateFormatLink->setText(getDateFormatLinkText());
149
150 QRegExp validRegExp(QLatin1String("[^/]+"));
151 QValidator* const validator = new QRegExpValidator(validRegExp, this);
152 ui->customFormatInput->setValidator(validator);
153 ui->customFormatInput->setPlaceholderText(i18nc("@info", "Enter custom format"));
154
155 // --------------------------------------------------------
156
157 connect(ui->dateSourcePicker, SIGNAL(currentIndexChanged(int)),
158 this, SLOT(slotDateSourceChanged(int)));
159
160 connect(ui->dateFormatPicker, SIGNAL(currentIndexChanged(int)),
161 this, SLOT(slotDateFormatChanged(int)));
162
163 connect(ui->customFormatInput, SIGNAL(textChanged(QString)),
164 this, SLOT(slotCustomFormatChanged(QString)));
165
166 // --------------------------------------------------------
167
168 ui->dateFormatPicker->setCurrentIndex(DateFormat::Standard);
169 slotDateFormatChanged(ui->dateFormatPicker->currentIndex());
170
171 // --------------------------------------------------------
172
173 setSettingsWidget(mainWidget);
174 }
175
~DateOptionDialog()176 DateOptionDialog::~DateOptionDialog()
177 {
178 delete ui;
179 }
180
dateSource()181 DateOptionDialog::DateSource DateOptionDialog::dateSource()
182 {
183 QVariant v = ui->dateSourcePicker->itemData(ui->dateSourcePicker->currentIndex());
184 bool ok = true;
185 int choice = v.toInt(&ok);
186
187 return static_cast<DateSource>(choice);
188 }
189
formattedDateTime(const QDateTime & date)190 QString DateOptionDialog::formattedDateTime(const QDateTime& date)
191 {
192 switch (ui->dateFormatPicker->currentIndex())
193 {
194 case DateFormat::Custom:
195 return date.toString(ui->customFormatInput->text());
196 break;
197
198 case DateFormat::UnixTimeStamp:
199 return QString::fromUtf8("%1").arg(date.toMSecsSinceEpoch());
200 break;
201
202 default:
203 break;
204 }
205
206 DateFormat df;
207 QVariant v;
208
209 v = df.format(static_cast<DateFormat::Type>(ui->dateFormatPicker->currentIndex()));
210 QString result;
211
212 if (v.type() == QVariant::String)
213 {
214 result = date.toString(v.toString());
215 }
216 else
217 {
218 result = date.toString((Qt::DateFormat)v.toInt());
219 }
220
221 return result;
222 }
223
slotDateSourceChanged(int index)224 void DateOptionDialog::slotDateSourceChanged(int index)
225 {
226 Q_UNUSED(index)
227 ui->fixedDateContainer->setEnabled(dateSource() == FixedDateTime);
228 }
229
slotDateFormatChanged(int index)230 void DateOptionDialog::slotDateFormatChanged(int index)
231 {
232 bool custom = (index == DateFormat::Custom);
233 ui->customFormatInput->setEnabled(custom);
234 ui->dateFormatLink->setEnabled(custom);
235 ui->dateFormatLink->setVisible(custom);
236
237 updateExampleLabel();
238 }
239
slotCustomFormatChanged(const QString &)240 void DateOptionDialog::slotCustomFormatChanged(const QString&)
241 {
242 updateExampleLabel();
243 }
244
updateExampleLabel()245 void DateOptionDialog::updateExampleLabel()
246 {
247 QString result = i18nc("@info", "example: ") + formattedDateTime(QDateTime::currentDateTime());
248 ui->exampleLabel->setText(result);
249 }
250
251 // --------------------------------------------------------
252
DateOption()253 DateOption::DateOption()
254 : Option(i18nc("@info", "Date && Time..."),
255 i18nc("@info", "Add date and time information"),
256 QLatin1String("view-calendar"))
257 {
258 addToken(QLatin1String("[date]"), i18nc("@item", "Date and time (standard format)"));
259 addToken(QLatin1String("[date:||key||]"), i18nc("@item", "Date and time") + QLatin1String(" (||key|| = Standard|ISO|UnixTimeStamp|Text)"));
260 addToken(QLatin1String("[date:||format||]"), i18nc("@item", "Date and time") + QLatin1String(" (") + getDateFormatLinkText() + QLatin1Char(')'));
261
262 QRegExp reg(QLatin1String("\\[date(:(.*))?\\]"));
263 reg.setMinimal(true);
264 setRegExp(reg);
265 }
266
parseOperation(ParseSettings & settings)267 QString DateOption::parseOperation(ParseSettings& settings)
268 {
269 const QRegExp& reg = regExp();
270
271 QString token = reg.cap(2);
272
273 // search for quoted token parameters (indicates custom formatting)
274
275 const int MIN_TOKEN_SIZE = 2;
276
277 if ((token.size() > MIN_TOKEN_SIZE) &&
278 (token.startsWith(QLatin1Char('"')) && token.endsWith(QLatin1Char('"'))))
279 {
280 token = token.remove(0, 1);
281 token.chop(1);
282 }
283
284 // check if the datetime was already set in the parseSettings objects (most likely during the camera import)
285
286 QDateTime dateTime;
287
288 if (!(settings.creationTime.isNull()) && (settings.creationTime.isValid()))
289 {
290 dateTime = settings.creationTime;
291 }
292 else
293 {
294 // lets try to re-read the file information
295
296 ItemInfo info = ItemInfo::fromUrl(settings.fileUrl);
297
298 if (!info.isNull())
299 {
300 dateTime = info.dateTime();
301 }
302
303 if (dateTime.isNull() || !dateTime.isValid())
304 {
305 // still no date info, use Qt file information
306
307 QFileInfo fileInfo(settings.fileUrl.toLocalFile());
308
309 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
310
311 dateTime = fileInfo.birthTime();
312
313 #else
314
315 dateTime = fileInfo.created();
316
317 #endif
318 }
319 }
320
321 // do we have a valid date?
322
323 if (dateTime.isNull())
324 {
325 return QString();
326 }
327
328 QString result;
329 DateFormat df;
330 QVariant v = df.format(token);
331
332 if (v.isNull())
333 {
334 // we seem to use custom format settings or UnixTimeStamp here
335
336 switch (df.type(token))
337 {
338 case DateFormat::UnixTimeStamp:
339 result = QString::fromUtf8("%1").arg(dateTime.toMSecsSinceEpoch());
340 break;
341
342 default:
343 result = dateTime.toString(token);
344 break;
345 }
346 }
347 else
348 {
349 if (v.type() == QVariant::String)
350 {
351 result = dateTime.toString(v.toString());
352 }
353 else
354 {
355 result = dateTime.toString((Qt::DateFormat)v.toInt());
356 }
357 }
358
359 return result;
360 }
361
slotTokenTriggered(const QString & token)362 void DateOption::slotTokenTriggered(const QString& token)
363 {
364 Q_UNUSED(token)
365
366 QPointer<DateOptionDialog> dlg = new DateOptionDialog(this);
367
368 QString dateString;
369
370 if (dlg->exec() == QDialog::Accepted)
371 {
372 DateFormat df;
373 int index = dlg->ui->dateFormatPicker->currentIndex();
374
375 // use custom date format?
376
377 if (dlg->dateSource() == DateOptionDialog::FixedDateTime)
378 {
379 QDateTime date;
380 date.setDate(dlg->ui->datePicker->date());
381 date.setTime(dlg->ui->timePicker->time());
382
383 QVariant v = (index == DateFormat::Custom) ? dlg->ui->customFormatInput->text()
384 : df.format((DateFormat::Type)index);
385
386 if (v.isNull())
387 {
388 // we seem to use UnixTimeStamp here
389
390 switch (index)
391 {
392 case DateFormat::UnixTimeStamp:
393 dateString = QString::fromUtf8("%1").arg(date.toMSecsSinceEpoch());
394 break;
395
396 default:
397 break;
398 }
399 }
400 else
401 {
402 if (v.type() == QVariant::String)
403 {
404 dateString = date.toString(v.toString());
405 }
406 else
407 {
408 dateString = date.toString((Qt::DateFormat)v.toInt());
409 }
410 }
411 }
412
413 // use predefined keywords for date formatting
414
415 else
416 {
417 QString tokenStr = QLatin1String("[date:%1]");
418
419 switch (index)
420 {
421 case DateFormat::Standard:
422 dateString = tokenStr.arg(QLatin1String(""));
423 dateString.remove(QLatin1Char(':'));
424 break;
425
426 case DateFormat::Custom:
427 dateString = tokenStr.arg(QString::fromUtf8("\"%1\"").arg(dlg->ui->customFormatInput->text()));
428 break;
429
430 default:
431 QString identifier = df.identifier((DateFormat::Type) index);
432 dateString = tokenStr.arg(identifier);
433 break;
434 }
435 }
436 }
437
438 delete dlg;
439
440 emit signalTokenTriggered(dateString);
441 }
442
443 } // namespace Digikam
444