File indexing completed on 2025-03-09 03:57:07
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-08-08 0007 * Description : an option to provide date information to the parser 0008 * 0009 * SPDX-FileCopyrightText: 2009-2012 by Andi Clemens <andi dot clemens at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "dateoption.h" 0016 0017 // Qt includes 0018 0019 #include <QDateTime> 0020 #include <QPointer> 0021 #include <QTimer> 0022 #include <QValidator> 0023 #include <QRegularExpression> 0024 0025 // KDE includes 0026 0027 #include <klocalizedstring.h> 0028 0029 // Local includes 0030 0031 #include "digikam_debug.h" 0032 #include "ui_dateoptiondialogwidget.h" 0033 0034 namespace Digikam 0035 { 0036 0037 static QString getDateFormatLinkText() 0038 { 0039 const QString dateFormatLink = QString::fromUtf8("<a href='https://doc.qt.io/qt-5.15/qdatetime.html#toString'>%1</a>"); 0040 const QString dateFormatLinkDescr = i18nc("@info: date format settings", "format settings"); 0041 0042 return dateFormatLink.arg(dateFormatLinkDescr); 0043 } 0044 0045 // -------------------------------------------------------- 0046 0047 DateFormat::DateFormat() 0048 { 0049 m_map.insert(Standard, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Standard"), QLatin1String("yyyyMMddThhmmss"))); 0050 m_map.insert(ISO, DateFormatDescriptor(i18nc("@item:inlistbox date format", "ISO"), Qt::ISODate)); 0051 m_map.insert(FullText, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Text"), Qt::TextDate)); 0052 m_map.insert(UnixTimeStamp, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Unix Time Stamp"), QVariant())); 0053 m_map.insert(Custom, DateFormatDescriptor(i18nc("@item:inlistbox date format", "Custom"), QVariant())); 0054 } 0055 0056 DateFormat::Type DateFormat::type(const QString& identifier) 0057 { 0058 if (identifier.isEmpty()) 0059 { 0060 return Standard; 0061 } 0062 0063 for (int i = 0 ; i < m_map.size() ; ++i) 0064 { 0065 if (m_map.at(i).first == identifier) 0066 { 0067 return (Type)i; 0068 } 0069 } 0070 0071 return Standard; 0072 } 0073 0074 QString DateFormat::identifier(Type type) 0075 { 0076 return m_map.at((int)type).first; 0077 } 0078 0079 QVariant DateFormat::format(Type type) 0080 { 0081 return m_map.at((int)type).second; 0082 } 0083 0084 QVariant DateFormat::format(const QString& identifier) 0085 { 0086 if (identifier.isEmpty()) 0087 { 0088 return m_map.at(Standard).second; 0089 } 0090 0091 Q_FOREACH (const DateFormatDescriptor& desc, m_map) 0092 { 0093 if (desc.first == identifier) 0094 { // cppcheck-suppress useStlAlgorithm 0095 return desc.second; 0096 } 0097 } 0098 return QVariant(); 0099 } 0100 0101 // -------------------------------------------------------- 0102 0103 DateOptionDialog::DateOptionDialog(Rule* parent) 0104 : RuleDialog(parent), 0105 ui (new Ui::DateOptionDialogWidget) 0106 { 0107 QWidget* const mainWidget = new QWidget(this); 0108 ui->setupUi(mainWidget); 0109 0110 // -------------------------------------------------------- 0111 0112 // fill the date source combobox 0113 0114 ui->dateSourcePicker->addItem(i18nc("@item: Get date information from the image", "Image"), 0115 QVariant(FromImage)); 0116 /* 0117 ui->dateSourcePicker->addItem(i18nc("Get date information from the current date", "Current Date"), 0118 QVariant(CurrentDateTime)); 0119 */ 0120 ui->dateSourcePicker->addItem(i18nc("@item: Set a fixed date", "Fixed Date"), 0121 QVariant(FixedDateTime)); 0122 0123 // fill the date format combobox 0124 0125 DateFormat df; 0126 0127 Q_FOREACH (const DateFormat::DateFormatDescriptor& desc, df.map()) 0128 { 0129 ui->dateFormatPicker->addItem(desc.first); 0130 } 0131 0132 // set the datePicker and timePicker to the current local datetime 0133 0134 QDateTime currentDateTime = QDateTime::currentDateTime(); 0135 ui->datePicker->setDate(currentDateTime.date()); 0136 ui->timePicker->setTime(currentDateTime.time()); 0137 0138 ui->dateFormatLink->setOpenExternalLinks(true); 0139 ui->dateFormatLink->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard); 0140 ui->dateFormatLink->setText(getDateFormatLinkText()); 0141 0142 QRegularExpression validRegExp(QLatin1String("[^/]+")); 0143 QValidator* const validator = new QRegularExpressionValidator(validRegExp, this); 0144 ui->customFormatInput->setValidator(validator); 0145 ui->customFormatInput->setPlaceholderText(i18nc("@info", "Enter custom format")); 0146 0147 // -------------------------------------------------------- 0148 0149 connect(ui->dateSourcePicker, SIGNAL(currentIndexChanged(int)), 0150 this, SLOT(slotDateSourceChanged(int))); 0151 0152 connect(ui->dateFormatPicker, SIGNAL(currentIndexChanged(int)), 0153 this, SLOT(slotDateFormatChanged(int))); 0154 0155 connect(ui->customFormatInput, SIGNAL(textChanged(QString)), 0156 this, SLOT(slotCustomFormatChanged(QString))); 0157 0158 // -------------------------------------------------------- 0159 0160 ui->dateFormatPicker->setCurrentIndex(DateFormat::Standard); 0161 slotDateFormatChanged(ui->dateFormatPicker->currentIndex()); 0162 0163 // -------------------------------------------------------- 0164 0165 setSettingsWidget(mainWidget); 0166 } 0167 0168 DateOptionDialog::~DateOptionDialog() 0169 { 0170 delete ui; 0171 } 0172 0173 DateOptionDialog::DateSource DateOptionDialog::dateSource() 0174 { 0175 QVariant v = ui->dateSourcePicker->itemData(ui->dateSourcePicker->currentIndex()); 0176 bool ok = true; 0177 int choice = v.toInt(&ok); 0178 0179 return (static_cast<DateSource>(choice)); 0180 } 0181 0182 QString DateOptionDialog::formattedDateTime(const QDateTime& date) 0183 { 0184 switch (ui->dateFormatPicker->currentIndex()) 0185 { 0186 case DateFormat::Custom: 0187 { 0188 return (date.toString(ui->customFormatInput->text())); 0189 } 0190 0191 case DateFormat::UnixTimeStamp: 0192 { 0193 return (QString::fromUtf8("%1").arg(date.toMSecsSinceEpoch())); 0194 } 0195 0196 default: 0197 { 0198 break; 0199 } 0200 } 0201 0202 DateFormat df; 0203 QVariant v; 0204 0205 v = df.format(static_cast<DateFormat::Type>(ui->dateFormatPicker->currentIndex())); 0206 QString result; 0207 0208 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0209 0210 if (v.typeId() == QVariant::String) 0211 0212 #else 0213 0214 if (v.type() == QVariant::String) 0215 0216 #endif 0217 0218 { 0219 result = date.toString(v.toString()); 0220 } 0221 else 0222 { 0223 result = date.toString((Qt::DateFormat)v.toInt()); 0224 } 0225 0226 return result; 0227 } 0228 0229 void DateOptionDialog::slotDateSourceChanged(int index) 0230 { 0231 Q_UNUSED(index) 0232 ui->fixedDateContainer->setEnabled(dateSource() == FixedDateTime); 0233 } 0234 0235 void DateOptionDialog::slotDateFormatChanged(int index) 0236 { 0237 bool custom = (index == DateFormat::Custom); 0238 ui->customFormatInput->setEnabled(custom); 0239 ui->dateFormatLink->setEnabled(custom); 0240 ui->dateFormatLink->setVisible(custom); 0241 0242 updateExampleLabel(); 0243 } 0244 0245 void DateOptionDialog::slotCustomFormatChanged(const QString&) 0246 { 0247 updateExampleLabel(); 0248 } 0249 0250 void DateOptionDialog::updateExampleLabel() 0251 { 0252 QString result = i18nc("@info", "example: ") + formattedDateTime(QDateTime::currentDateTime()); 0253 ui->exampleLabel->setText(result); 0254 } 0255 0256 // -------------------------------------------------------- 0257 0258 DateOption::DateOption() 0259 : Option(i18nc("@info", "Date && Time..."), 0260 i18nc("@info", "Add date and time information"), 0261 QLatin1String("view-calendar")) 0262 { 0263 addToken(QLatin1String("[date]"), i18nc("@item", "Date and time (standard format)")); 0264 addToken(QLatin1String("[date:||key||]"), i18nc("@item", "Date and time") + QLatin1String(" (||key|| = Standard|ISO|UnixTimeStamp|Text)")); 0265 addToken(QLatin1String("[date:||format||]"), i18nc("@item", "Date and time") + QLatin1String(" (") + getDateFormatLinkText() + QLatin1Char(')')); 0266 0267 QRegularExpression reg(QLatin1String("\\[date(:(.*))?\\]")); 0268 reg.setPatternOptions(QRegularExpression::InvertedGreedinessOption); 0269 setRegExp(reg); 0270 } 0271 0272 QString DateOption::parseOperation(ParseSettings& settings, const QRegularExpressionMatch& match) 0273 { 0274 0275 QString token = match.captured(2); 0276 0277 // search for quoted token parameters (indicates custom formatting) 0278 0279 const int MIN_TOKEN_SIZE = 2; 0280 0281 if ((token.size() > MIN_TOKEN_SIZE) && 0282 (token.startsWith(QLatin1Char('"')) && token.endsWith(QLatin1Char('"')))) 0283 { 0284 token = token.remove(0, 1); 0285 token.chop(1); 0286 } 0287 0288 // check if the datetime was already set in the parseSettings objects (most likely during the camera import) 0289 0290 QDateTime dateTime; 0291 0292 if (!(settings.creationTime.isNull()) && (settings.creationTime.isValid())) 0293 { 0294 dateTime = settings.creationTime; 0295 } 0296 else 0297 { 0298 // lets try to re-read the file information 0299 0300 ItemInfo info = ItemInfo::fromUrl(settings.fileUrl); 0301 0302 if (!info.isNull()) 0303 { 0304 dateTime = info.dateTime(); 0305 } 0306 0307 if (dateTime.isNull() || !dateTime.isValid()) 0308 { 0309 // still no date info, use Qt file information 0310 0311 QFileInfo fileInfo(settings.fileUrl.toLocalFile()); 0312 dateTime = fileInfo.birthTime(); 0313 } 0314 } 0315 0316 // do we have a valid date? 0317 0318 if (dateTime.isNull()) 0319 { 0320 return QString(); 0321 } 0322 0323 QString result; 0324 DateFormat df; 0325 QVariant v = df.format(token); 0326 0327 if (v.isNull()) 0328 { 0329 // we seem to use custom format settings or UnixTimeStamp here 0330 0331 switch (df.type(token)) 0332 { 0333 case DateFormat::UnixTimeStamp: 0334 { 0335 result = QString::fromUtf8("%1").arg(dateTime.toMSecsSinceEpoch()); 0336 break; 0337 } 0338 0339 default: 0340 { 0341 result = dateTime.toString(token); 0342 break; 0343 } 0344 } 0345 } 0346 else 0347 { 0348 0349 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0350 0351 if (v.typeId() == QVariant::String) 0352 0353 #else 0354 0355 if (v.type() == QVariant::String) 0356 0357 #endif 0358 0359 { 0360 result = dateTime.toString(v.toString()); 0361 } 0362 else 0363 { 0364 result = dateTime.toString((Qt::DateFormat)v.toInt()); 0365 } 0366 } 0367 0368 return result; 0369 } 0370 0371 void DateOption::slotTokenTriggered(const QString& token) 0372 { 0373 Q_UNUSED(token) 0374 0375 QPointer<DateOptionDialog> dlg = new DateOptionDialog(this); 0376 0377 QString dateString; 0378 0379 if (dlg->exec() == QDialog::Accepted) 0380 { 0381 DateFormat df; 0382 int index = dlg->ui->dateFormatPicker->currentIndex(); 0383 0384 // use custom date format? 0385 0386 if (dlg->dateSource() == DateOptionDialog::FixedDateTime) 0387 { 0388 QDateTime date; 0389 date.setDate(dlg->ui->datePicker->date()); 0390 date.setTime(dlg->ui->timePicker->time()); 0391 0392 QVariant v = (index == DateFormat::Custom) ? dlg->ui->customFormatInput->text() 0393 : df.format((DateFormat::Type)index); 0394 0395 if (v.isNull()) 0396 { 0397 // we seem to use UnixTimeStamp here 0398 0399 switch (index) 0400 { 0401 case DateFormat::UnixTimeStamp: 0402 { 0403 dateString = QString::fromUtf8("%1").arg(date.toMSecsSinceEpoch()); 0404 break; 0405 } 0406 0407 default: 0408 { 0409 break; 0410 } 0411 } 0412 } 0413 else 0414 { 0415 0416 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0417 0418 if (v.typeId() == QVariant::String) 0419 0420 #else 0421 0422 if (v.type() == QVariant::String) 0423 0424 #endif 0425 0426 { 0427 dateString = date.toString(v.toString()); 0428 } 0429 else 0430 { 0431 dateString = date.toString((Qt::DateFormat)v.toInt()); 0432 } 0433 } 0434 } 0435 0436 // use predefined keywords for date formatting 0437 0438 else 0439 { 0440 QString tokenStr = QLatin1String("[date:%1]"); 0441 0442 switch (index) 0443 { 0444 case DateFormat::Standard: 0445 { 0446 dateString = tokenStr.arg(QLatin1String("")); 0447 dateString.remove(QLatin1Char(':')); 0448 break; 0449 } 0450 0451 case DateFormat::Custom: 0452 { 0453 dateString = tokenStr.arg(QString::fromUtf8("\"%1\"").arg(dlg->ui->customFormatInput->text())); 0454 break; 0455 } 0456 0457 default: 0458 { 0459 QString identifier = df.identifier((DateFormat::Type) index); 0460 dateString = tokenStr.arg(identifier); 0461 break; 0462 } 0463 } 0464 } 0465 } 0466 0467 delete dlg; 0468 0469 Q_EMIT signalTokenTriggered(dateString); 0470 } 0471 0472 } // namespace Digikam 0473 0474 #include "moc_dateoption.cpp"