File indexing completed on 2025-01-19 03:50:48
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2013-03-14 0007 * Description : Table view column helpers: Photo properties 0008 * 0009 * SPDX-FileCopyrightText: 2017-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2013 by Michael G. Hansen <mike at mghansen dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "tableview_column_photo.h" 0017 0018 // Qt includes 0019 0020 #include <QFormLayout> 0021 #include <QComboBox> 0022 #include <QLocale> 0023 0024 // KDE includes 0025 0026 #include <klocalizedstring.h> 0027 0028 // Local includes 0029 0030 #include "digikam_debug.h" 0031 #include "coredbinfocontainers.h" 0032 #include "itempropertiestab.h" 0033 #include "dmetadata.h" 0034 #include "iteminfo.h" 0035 0036 namespace Digikam 0037 { 0038 0039 namespace TableViewColumns 0040 { 0041 0042 ColumnPhotoProperties::ColumnPhotoProperties(TableViewShared* const tableViewShared, 0043 const TableViewColumnConfiguration& pConfiguration, 0044 const SubColumn pSubColumn, 0045 QObject* const parent) 0046 : TableViewColumn(tableViewShared, pConfiguration, parent), 0047 subColumn (pSubColumn) 0048 { 0049 } 0050 0051 ColumnPhotoProperties::~ColumnPhotoProperties() 0052 { 0053 } 0054 0055 QStringList ColumnPhotoProperties::getSubColumns() 0056 { 0057 QStringList columns; 0058 columns << QLatin1String("cameramaker") 0059 << QLatin1String("cameramodel") 0060 << QLatin1String("lens") 0061 << QLatin1String("aperture") 0062 << QLatin1String("focal") 0063 << QLatin1String("exposure") 0064 << QLatin1String("sensitivity") 0065 << QLatin1String("modeprogram") 0066 << QLatin1String("flash") 0067 << QLatin1String("whitebalance"); 0068 0069 return columns; 0070 } 0071 0072 TableViewColumnDescription ColumnPhotoProperties::getDescription() 0073 { 0074 TableViewColumnDescription description(QLatin1String("photo-properties"), i18nc("@info: tableview", "Photo properties")); 0075 description.setIcon(QLatin1String("camera-photo")); 0076 0077 description.addSubColumn(TableViewColumnDescription(QLatin1String("cameramaker"), i18nc("@title: tableview", "Camera maker"))); 0078 description.addSubColumn(TableViewColumnDescription(QLatin1String("cameramodel"), i18nc("@title: tableview", "Camera model"))); 0079 description.addSubColumn(TableViewColumnDescription(QLatin1String("lens"), i18nc("@title: tableview", "Lens"))); 0080 description.addSubColumn(TableViewColumnDescription(QLatin1String("aperture"), i18nc("@title: tableview", "Aperture"))); 0081 description.addSubColumn(TableViewColumnDescription(QLatin1String("focal"), i18nc("@title: tableview", "Focal length"))); 0082 description.addSubColumn(TableViewColumnDescription(QLatin1String("exposure"), i18nc("@title: tableview", "Exposure"))); 0083 description.addSubColumn(TableViewColumnDescription(QLatin1String("sensitivity"), i18nc("@title: tableview", "Sensitivity"))); 0084 description.addSubColumn(TableViewColumnDescription(QLatin1String("modeprogram"), i18nc("@title: tableview", "Mode/program"))); 0085 description.addSubColumn(TableViewColumnDescription(QLatin1String("flash"), i18nc("@title: tableview", "Flash"))); 0086 description.addSubColumn(TableViewColumnDescription(QLatin1String("whitebalance"), i18nc("@title: tableview", "White balance"))); 0087 0088 return description; 0089 } 0090 0091 QString ColumnPhotoProperties::getTitle() const 0092 { 0093 switch (subColumn) 0094 { 0095 case SubColumnCameraMaker: 0096 { 0097 return i18nc("@title: tableview", "Camera maker"); 0098 } 0099 0100 case SubColumnCameraModel: 0101 { 0102 return i18nc("@title: tableview", "Camera model"); 0103 } 0104 0105 case SubColumnLens: 0106 { 0107 return i18nc("@title: tableview", "Lens"); 0108 } 0109 0110 case SubColumnAperture: 0111 { 0112 return i18nc("@title: tableview", "Aperture"); 0113 } 0114 0115 case SubColumnFocal: 0116 { 0117 return i18nc("@title: tableview", "Focal length"); 0118 } 0119 0120 case SubColumnExposure: 0121 { 0122 return i18nc("@title: tableview", "Exposure"); 0123 } 0124 0125 case SubColumnSensitivity: 0126 { 0127 return i18nc("@title: tableview", "Sensitivity"); 0128 } 0129 0130 case SubColumnModeProgram: 0131 { 0132 return i18nc("@title: tableview", "Mode/program"); 0133 } 0134 0135 case SubColumnFlash: 0136 { 0137 return i18nc("@title: tableview", "Flash"); 0138 } 0139 0140 case SubColumnWhiteBalance: 0141 { 0142 return i18nc("@title: tableview", "White balance"); 0143 } 0144 } 0145 0146 return QString(); 0147 } 0148 0149 TableViewColumn::ColumnFlags ColumnPhotoProperties::getColumnFlags() const 0150 { 0151 ColumnFlags flags(ColumnNoFlags); 0152 0153 if ( 0154 (subColumn == SubColumnAperture) || 0155 (subColumn == SubColumnFocal) || 0156 (subColumn == SubColumnExposure) || 0157 (subColumn == SubColumnSensitivity) 0158 ) 0159 { 0160 flags |= ColumnCustomSorting; 0161 } 0162 0163 if (subColumn == SubColumnExposure) 0164 { 0165 flags |= ColumnHasConfigurationWidget; 0166 } 0167 0168 return flags; 0169 } 0170 0171 QVariant ColumnPhotoProperties::data(TableViewModel::Item* const item, const int role) const 0172 { 0173 if (role != Qt::DisplayRole) 0174 { 0175 return QVariant(); 0176 } 0177 0178 switch (subColumn) 0179 { 0180 case SubColumnCameraMaker: 0181 { 0182 QString cameraMaker = s->tableViewModel->itemDatabaseFieldRaw(item, 0183 DatabaseFields::Set(DatabaseFields::Make)).toString(); 0184 ItemPropertiesTab::shortenedMakeInfo(cameraMaker); 0185 0186 return cameraMaker; 0187 } 0188 0189 case SubColumnCameraModel: 0190 { 0191 QString cameraModel = s->tableViewModel->itemDatabaseFieldRaw(item, 0192 DatabaseFields::Set(DatabaseFields::Model)).toString(); 0193 ItemPropertiesTab::shortenedModelInfo(cameraModel); 0194 0195 return cameraModel; 0196 } 0197 0198 case SubColumnLens: 0199 { 0200 const QString cameraLens = s->tableViewModel->itemDatabaseFieldRaw(item, 0201 DatabaseFields::Set(DatabaseFields::Lens)).toString(); 0202 0203 return cameraLens; 0204 } 0205 0206 case SubColumnAperture: 0207 { 0208 const QVariant apertureVariant = s->tableViewModel->itemDatabaseFieldRaw(item, 0209 DatabaseFields::Set(DatabaseFields::Aperture)); 0210 const QString apertureString = DMetadata::valueToString(apertureVariant, MetadataInfo::Aperture); 0211 0212 return apertureString; 0213 } 0214 0215 case SubColumnFocal: 0216 { 0217 /// @todo Make this configurable 0218 0219 const DatabaseFields::Set requiredSet = DatabaseFields::Set(DatabaseFields::FocalLength | DatabaseFields::FocalLength35); 0220 const TableViewModel::DatabaseFieldsHashRaw rawFields = s->tableViewModel->itemDatabaseFieldsRaw(item, requiredSet); 0221 const QVariant focalLengthVariant = rawFields.value(DatabaseFields::FocalLength); 0222 const QString focalLengthString = DMetadata::valueToString(focalLengthVariant, MetadataInfo::FocalLength); 0223 const QVariant focalLength35Variant = rawFields.value(DatabaseFields::FocalLength35); 0224 const QString focalLength35String = DMetadata::valueToString(focalLength35Variant, MetadataInfo::FocalLengthIn35mm); 0225 0226 if (focalLength35String.isEmpty()) 0227 { 0228 return focalLengthString; 0229 } 0230 0231 if (focalLengthString.isEmpty()) 0232 { 0233 return QString(); 0234 } 0235 0236 /// @todo What if only 35 mm is set? 0237 0238 return i18nc("@info: tableview", "%1 (%2)", focalLengthString, focalLength35String); 0239 } 0240 0241 case SubColumnExposure: 0242 { 0243 /// @todo Add a configuration option for fraction vs number, units s vs ms vs mus 0244 0245 const QVariant exposureVariant = s->tableViewModel->itemDatabaseFieldRaw(item, 0246 DatabaseFields::Set(DatabaseFields::ExposureTime)); 0247 0248 if (configuration.getSetting(QLatin1String("format"), QLatin1String("fraction")) == QLatin1String("fraction")) 0249 { 0250 const QString exposureString = DMetadata::valueToString(exposureVariant, MetadataInfo::ExposureTime); 0251 0252 return exposureString; 0253 } 0254 0255 if (!exposureVariant.isValid()) 0256 { 0257 return QString(); 0258 } 0259 0260 const QString unitKey = configuration.getSetting(QLatin1String("unit"), QLatin1String("seconds")); 0261 double multiplier = 1.0; 0262 KLocalizedString exposureTimeLocalizedString = ki18nc("@info: tableview", "%1 s"); 0263 0264 if (unitKey == QLatin1String("milliseconds")) 0265 { 0266 multiplier = 1000.0; 0267 exposureTimeLocalizedString = ki18nc("@info: tableview", "%1 ms"); 0268 } 0269 else if (unitKey == QLatin1String("microseconds")) 0270 { 0271 multiplier = 1000000.0; 0272 exposureTimeLocalizedString = ki18nc("@info: tableview", "%1 µs"); 0273 } 0274 0275 const double exposureTime = exposureVariant.toDouble() * multiplier; 0276 0277 /// @todo Seems like we have to check for 0 here, too, as an invalid value 0278 0279 if (exposureTime == 0) 0280 { 0281 return QString(); 0282 } 0283 0284 /// @todo Remove trailing zeros? 0285 /// @todo Align right? --> better align at decimal point 0286 0287 const QString exposureTimeString = exposureTimeLocalizedString.subs(QLocale().toString(exposureTime, 'g', 3)).toString(); 0288 0289 return exposureTimeString; 0290 } 0291 0292 case SubColumnSensitivity: 0293 { 0294 const QVariant sensitivityVariant = s->tableViewModel->itemDatabaseFieldRaw(item, 0295 DatabaseFields::Set(DatabaseFields::Sensitivity)); 0296 const QString sensitivityString = DMetadata::valueToString(sensitivityVariant, MetadataInfo::Sensitivity); 0297 0298 if (sensitivityString.isEmpty()) 0299 { 0300 return QString(); 0301 } 0302 0303 return i18nc("@info: tableview", "%1 ISO", sensitivityString); 0304 } 0305 0306 case SubColumnModeProgram: 0307 { 0308 const DatabaseFields::Set requiredSet = DatabaseFields::Set(DatabaseFields::ExposureMode | DatabaseFields::ExposureProgram); 0309 const TableViewModel::DatabaseFieldsHashRaw rawFields = s->tableViewModel->itemDatabaseFieldsRaw(item, requiredSet); 0310 const QVariant exposureModeVariant = rawFields.value(DatabaseFields::ExposureMode); 0311 const QString exposureModeString = DMetadata::valueToString(exposureModeVariant, MetadataInfo::ExposureMode); 0312 const QVariant exposureProgramVariant = rawFields.value(DatabaseFields::ExposureProgram); 0313 const QString exposureProgramString = DMetadata::valueToString(exposureProgramVariant, MetadataInfo::ExposureProgram); 0314 0315 if (exposureModeString.isEmpty() && exposureProgramString.isEmpty()) 0316 { 0317 return QString(); 0318 } 0319 else if (!exposureModeString.isEmpty() && exposureProgramString.isEmpty()) 0320 { 0321 return exposureModeString; 0322 } 0323 else if (exposureModeString.isEmpty() && !exposureProgramString.isEmpty()) 0324 { 0325 return exposureProgramString; 0326 } 0327 0328 return QString::fromUtf8("%1 / %2").arg(exposureModeString).arg(exposureProgramString); 0329 } 0330 0331 case SubColumnFlash: 0332 { 0333 const QVariant flashModeVariant = s->tableViewModel->itemDatabaseFieldRaw(item, 0334 DatabaseFields::Set(DatabaseFields::FlashMode)); 0335 const QString flashModeString = DMetadata::valueToString(flashModeVariant, MetadataInfo::FlashMode); 0336 0337 return flashModeString; 0338 } 0339 0340 case SubColumnWhiteBalance: 0341 { 0342 const QVariant whiteBalanceVariant = s->tableViewModel->itemDatabaseFieldRaw(item, 0343 DatabaseFields::Set(DatabaseFields::WhiteBalance)); 0344 const QString whiteBalanceString = DMetadata::valueToString(whiteBalanceVariant, MetadataInfo::WhiteBalance); 0345 0346 return whiteBalanceString; 0347 } 0348 } 0349 0350 return QVariant(); 0351 } 0352 0353 TableViewColumn::ColumnCompareResult ColumnPhotoProperties::compare(TableViewModel::Item* const itemA, TableViewModel::Item* const itemB) const 0354 { 0355 const ItemInfo infoA = s->tableViewModel->infoFromItem(itemA); 0356 const ItemInfo infoB = s->tableViewModel->infoFromItem(itemB); 0357 0358 switch (subColumn) 0359 { 0360 case SubColumnAperture: 0361 { 0362 const QVariant variantA = s->tableViewModel->itemDatabaseFieldRaw(itemA, 0363 DatabaseFields::Set(DatabaseFields::Aperture)); 0364 const QVariant variantB = s->tableViewModel->itemDatabaseFieldRaw(itemB, 0365 DatabaseFields::Set(DatabaseFields::Aperture)); 0366 const double apertureA = variantA.toDouble(); 0367 const double apertureB = variantB.toDouble(); 0368 0369 return compareHelper<double>(apertureA, apertureB); 0370 } 0371 0372 case SubColumnFocal: 0373 { 0374 /// @todo This just works if both have focal length set, not if focal length 35 has to be used 0375 0376 const QVariant variantA = s->tableViewModel->itemDatabaseFieldRaw(itemA, 0377 DatabaseFields::Set(DatabaseFields::FocalLength)); 0378 const QVariant variantB = s->tableViewModel->itemDatabaseFieldRaw(itemB, 0379 DatabaseFields::Set(DatabaseFields::FocalLength)); 0380 const double focalLengthA = variantA.toDouble(); 0381 const double focalLengthB = variantB.toDouble(); 0382 0383 return compareHelper<double>(focalLengthA, focalLengthB); 0384 } 0385 0386 case SubColumnExposure: 0387 { 0388 const QVariant variantA = s->tableViewModel->itemDatabaseFieldRaw(itemA, 0389 DatabaseFields::Set(DatabaseFields::ExposureTime)); 0390 const QVariant variantB = s->tableViewModel->itemDatabaseFieldRaw(itemB, 0391 DatabaseFields::Set(DatabaseFields::ExposureTime)); 0392 const double exposureTimeA = variantA.toDouble(); 0393 const double exposureTimeB = variantB.toDouble(); 0394 0395 return compareHelper<double>(exposureTimeA, exposureTimeB); 0396 } 0397 0398 case SubColumnSensitivity: 0399 { 0400 const QVariant variantA = s->tableViewModel->itemDatabaseFieldRaw(itemA, 0401 DatabaseFields::Set(DatabaseFields::Sensitivity)); 0402 const QVariant variantB = s->tableViewModel->itemDatabaseFieldRaw(itemB, 0403 DatabaseFields::Set(DatabaseFields::Sensitivity)); 0404 const double sensitivityA = variantA.toDouble(); 0405 const double sensitivityB = variantB.toDouble(); 0406 0407 return compareHelper<double>(sensitivityA, sensitivityB); 0408 } 0409 0410 default: 0411 { 0412 qCWarning(DIGIKAM_GENERAL_LOG) << "item: unimplemented comparison, subColumn=" << subColumn; 0413 0414 return CmpEqual; 0415 } 0416 } 0417 } 0418 0419 TableViewColumnConfigurationWidget* ColumnPhotoProperties::getConfigurationWidget(QWidget* const parentWidget) const 0420 { 0421 TableViewColumnConfiguration myConfiguration = getConfiguration(); 0422 0423 return (new ColumnPhotoConfigurationWidget(s, myConfiguration, parentWidget)); 0424 } 0425 0426 // --------------------------------------------------------------------------------------------------------------------- 0427 0428 ColumnPhotoConfigurationWidget::ColumnPhotoConfigurationWidget(TableViewShared* const sharedObject, 0429 const TableViewColumnConfiguration& columnConfiguration, 0430 QWidget* const parentWidget) 0431 : TableViewColumnConfigurationWidget(sharedObject, columnConfiguration, parentWidget), 0432 subColumn (ColumnPhotoProperties::SubColumnExposure), 0433 selectorExposureTimeFormat (nullptr), 0434 selectorExposureTimeUnit (nullptr) 0435 { 0436 ColumnPhotoProperties::getSubColumnIndex<ColumnPhotoProperties>(configuration.columnId, &subColumn); 0437 0438 switch (subColumn) 0439 { 0440 case ColumnPhotoProperties::SubColumnExposure: 0441 { 0442 QFormLayout* const box1 = new QFormLayout(); 0443 selectorExposureTimeFormat = new QComboBox(this); 0444 selectorExposureTimeFormat->addItem(i18nc("@info: tableview", "Fraction"), QLatin1String("fraction")); 0445 selectorExposureTimeFormat->addItem(i18nc("@info: tableview", "Rational"), QLatin1String("rational")); 0446 box1->addRow(i18nc("@info: tableview", "Format"), selectorExposureTimeFormat); 0447 0448 selectorExposureTimeUnit = new QComboBox(this); 0449 selectorExposureTimeUnit->addItem(i18nc("@info: tableview", "Seconds"), QLatin1String("seconds")); 0450 selectorExposureTimeUnit->addItem(i18nc("@info: tableview", "Milliseconds"), QLatin1String("milliseconds")); 0451 selectorExposureTimeUnit->addItem(i18nc("@info: tableview", "Microseconds"), QLatin1String("microseconds")); 0452 box1->addRow(i18nc("@info: tableview", "Unit"), selectorExposureTimeUnit); 0453 0454 setLayout(box1); 0455 0456 const int indexF = selectorExposureTimeFormat->findData(configuration.getSetting(QLatin1String("format"), QLatin1String("fraction"))); 0457 selectorExposureTimeFormat->setCurrentIndex((indexF >= 0) ? indexF : 0); 0458 const int indexU = selectorExposureTimeUnit->findData(configuration.getSetting(QLatin1String("unit"), QLatin1String("seconds"))); 0459 selectorExposureTimeUnit->setCurrentIndex((indexU >= 0) ? indexU : 0); 0460 0461 slotUpdateUI(); 0462 0463 connect(selectorExposureTimeFormat, SIGNAL(currentIndexChanged(int)), 0464 this, SLOT(slotUpdateUI())); 0465 break; 0466 } 0467 0468 default: 0469 { 0470 break; 0471 } 0472 } 0473 } 0474 0475 ColumnPhotoConfigurationWidget::~ColumnPhotoConfigurationWidget() 0476 { 0477 } 0478 0479 TableViewColumnConfiguration ColumnPhotoConfigurationWidget::getNewConfiguration() 0480 { 0481 const QString formatKey = selectorExposureTimeFormat->itemData(selectorExposureTimeFormat->currentIndex()).toString(); 0482 configuration.columnSettings.insert(QLatin1String("format"), formatKey); 0483 0484 const QString unitKey = selectorExposureTimeUnit->itemData(selectorExposureTimeUnit->currentIndex()).toString(); 0485 configuration.columnSettings.insert(QLatin1String("unit"), unitKey); 0486 0487 return configuration; 0488 } 0489 0490 void ColumnPhotoProperties::setConfiguration(const TableViewColumnConfiguration& newConfiguration) 0491 { 0492 configuration = newConfiguration; 0493 0494 Q_EMIT signalAllDataChanged(); 0495 } 0496 0497 void ColumnPhotoConfigurationWidget::slotUpdateUI() 0498 { 0499 if (selectorExposureTimeFormat) 0500 { 0501 const QString currentKey = selectorExposureTimeFormat->itemData(selectorExposureTimeFormat->currentIndex()).toString(); 0502 const bool needsUnits = (currentKey == QLatin1String("rational")); 0503 0504 selectorExposureTimeUnit->setEnabled(needsUnits); 0505 } 0506 } 0507 0508 } // namespace TableViewColumns 0509 0510 } // namespace Digikam 0511 0512 #include "moc_tableview_column_photo.cpp"