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-02-25
0007  * Description : Table view column helpers: Item 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_item.h"
0017 
0018 // Qt includes
0019 
0020 #include <QLocale>
0021 
0022 // KDE includes
0023 
0024 #include <klocalizedstring.h>
0025 
0026 // Local includes
0027 
0028 #include "digikam_debug.h"
0029 #include "iteminfo.h"
0030 #include "coredbinfocontainers.h"
0031 #include "itempropertiestab.h"
0032 
0033 namespace Digikam
0034 {
0035 
0036 namespace TableViewColumns
0037 {
0038 
0039 ColumnItemProperties::ColumnItemProperties(TableViewShared* const tableViewShared,
0040                                            const TableViewColumnConfiguration& pConfiguration,
0041                                            const SubColumn pSubColumn,
0042                                            QObject* const parent)
0043     : TableViewColumn(tableViewShared, pConfiguration, parent),
0044       subColumn      (pSubColumn)
0045 {
0046 }
0047 
0048 ColumnItemProperties::~ColumnItemProperties()
0049 {
0050 }
0051 
0052 QStringList ColumnItemProperties::getSubColumns()
0053 {
0054     QStringList columns;
0055     columns << QLatin1String("width")
0056             << QLatin1String("height")
0057             << QLatin1String("dimensions")
0058             << QLatin1String("pixelcount")
0059             << QLatin1String("bitdepth")
0060             << QLatin1String("colormode")
0061             << QLatin1String("itemtype")
0062             << QLatin1String("itemcreationdatetime")
0063             << QLatin1String("itemdigitizationtime")
0064             << QLatin1String("itemaspectratio")
0065             << QLatin1String("similarity");
0066 
0067     return columns;
0068 }
0069 
0070 TableViewColumnDescription ColumnItemProperties::getDescription()
0071 {
0072     TableViewColumnDescription description(QLatin1String("item-properties"), i18n("Item properties"));
0073     description.setIcon(QLatin1String("view-preview"));
0074 
0075     description.addSubColumn(TableViewColumnDescription(QLatin1String("width"),                i18n("Width")));
0076     description.addSubColumn(TableViewColumnDescription(QLatin1String("height"),               i18n("Height")));
0077     description.addSubColumn(TableViewColumnDescription(QLatin1String("dimensions"),           i18n("Dimensions")));
0078     description.addSubColumn(TableViewColumnDescription(QLatin1String("pixelcount"),           i18n("Pixel count")));
0079     description.addSubColumn(TableViewColumnDescription(QLatin1String("bitdepth"),             i18n("Bit depth")));
0080     description.addSubColumn(TableViewColumnDescription(QLatin1String("colormode"),            i18n("Color mode")));
0081     description.addSubColumn(TableViewColumnDescription(QLatin1String("itemtype"),             i18n("Type")));
0082     description.addSubColumn(TableViewColumnDescription(QLatin1String("itemcreationdatetime"), i18n("Creation date/time")));
0083     description.addSubColumn(TableViewColumnDescription(QLatin1String("itemdigitizationtime"), i18n("Digitization date/time")));
0084     description.addSubColumn(TableViewColumnDescription(QLatin1String("itemaspectratio"),      i18n("Aspect ratio")));
0085     description.addSubColumn(TableViewColumnDescription(QLatin1String("similarity"),           i18n("Similarity")));
0086 
0087     return description;
0088 }
0089 
0090 QString ColumnItemProperties::getTitle() const
0091 {
0092     switch (subColumn)
0093     {
0094         case SubColumnWidth:
0095         {
0096             return i18n("Width");
0097         }
0098 
0099         case SubColumnHeight:
0100         {
0101             return i18n("Height");
0102         }
0103 
0104         case SubColumnDimensions:
0105         {
0106             return i18n("Dimensions");
0107         }
0108 
0109         case SubColumnPixelCount:
0110         {
0111             return i18n("Pixel count");
0112         }
0113 
0114         case SubColumnBitDepth:
0115         {
0116             return i18n("Bit depth");
0117         }
0118 
0119         case SubColumnColorMode:
0120         {
0121             return i18n("Color mode");
0122         }
0123 
0124         case SubColumnType:
0125         {
0126             return i18n("Type");
0127         }
0128 
0129         case SubColumnCreationDateTime:
0130         {
0131             return i18n("Creation date/time");
0132         }
0133 
0134         case SubColumnDigitizationDateTime:
0135         {
0136             return i18n("Digitization date/time");
0137         }
0138 
0139         case SubColumnAspectRatio:
0140         {
0141             return i18n("Aspect ratio");
0142         }
0143 
0144         case SubColumnSimilarity:
0145         {
0146             return i18n("Similarity");
0147         }
0148     }
0149 
0150     return QString();
0151 }
0152 
0153 TableViewColumn::ColumnFlags ColumnItemProperties::getColumnFlags() const
0154 {
0155     ColumnFlags flags(ColumnNoFlags);
0156 
0157     if (
0158         (subColumn == SubColumnHeight)               ||
0159         (subColumn == SubColumnWidth)                ||
0160         (subColumn == SubColumnDimensions)           ||
0161         (subColumn == SubColumnBitDepth)             ||
0162         (subColumn == SubColumnPixelCount)           ||
0163         (subColumn == SubColumnCreationDateTime)     ||
0164         (subColumn == SubColumnDigitizationDateTime) ||
0165         (subColumn == SubColumnAspectRatio)          ||
0166         (subColumn == SubColumnSimilarity)
0167        )
0168     {
0169         flags |= ColumnCustomSorting;
0170     }
0171 
0172     return flags;
0173 }
0174 
0175 QVariant ColumnItemProperties::data(TableViewModel::Item* const item, const int role) const
0176 {
0177     if (
0178         (role != Qt::DisplayRole) &&
0179         (role != Qt::TextAlignmentRole)
0180        )
0181     {
0182         return QVariant();
0183     }
0184 
0185     if (role == Qt::TextAlignmentRole)
0186     {
0187         switch (subColumn)
0188         {
0189             case SubColumnHeight:
0190             case SubColumnWidth:
0191             case SubColumnPixelCount:
0192             {
0193                 return QVariant(Qt::Alignment(Qt::AlignRight | Qt::AlignVCenter));
0194             }
0195 
0196             default:
0197             {
0198                 return QVariant();
0199             }
0200         }
0201     }
0202 
0203     const ItemInfo info = s->tableViewModel->infoFromItem(item);
0204 
0205     switch (subColumn)
0206     {
0207         case SubColumnWidth:
0208         {
0209             return QLocale().toString(info.dimensions().width());
0210         }
0211 
0212         case SubColumnHeight:
0213         {
0214             return QLocale().toString(info.dimensions().height());
0215         }
0216 
0217         case SubColumnDimensions:
0218         {
0219             const QSize imgSize = info.dimensions();
0220 
0221             if (imgSize.isNull())
0222             {
0223                 return QString();
0224             }
0225 
0226             const QString widthString  = QLocale().toString(imgSize.width());
0227             const QString heightString = QLocale().toString(imgSize.height());
0228 
0229             return QString::fromUtf8("%1x%2").arg(widthString).arg(heightString);
0230         }
0231 
0232         case SubColumnPixelCount:
0233         {
0234             const QSize imgSize  = info.dimensions();
0235             const int pixelCount = imgSize.height() * imgSize.width();
0236 
0237             if (pixelCount == 0)
0238             {
0239                 return QString();
0240             }
0241 
0242             /// @todo make this configurable with si-prefixes
0243 
0244             return QLocale().toString(pixelCount);
0245         }
0246 
0247         case SubColumnAspectRatio:
0248         {
0249             const QSize imgSize = info.dimensions();
0250             QString aspectRatioString;
0251 
0252             if (!ItemPropertiesTab::aspectRatioToString(imgSize.width(), imgSize.height(), aspectRatioString))
0253             {
0254                 return QString();
0255             }
0256 
0257             return aspectRatioString;
0258         }
0259 
0260         case SubColumnBitDepth:
0261         {
0262             const ImageCommonContainer commonInfo = info.imageCommonContainer();
0263             const int bitDepth                    = commonInfo.colorDepth;
0264 
0265             return QString::fromUtf8("%1 bpp").arg(bitDepth);
0266         }
0267 
0268         case SubColumnColorMode:
0269         {
0270             const ImageCommonContainer commonInfo = info.imageCommonContainer();
0271 
0272             return commonInfo.colorModel;
0273         }
0274 
0275         case SubColumnType:
0276         {
0277             const ImageCommonContainer commonInfo = info.imageCommonContainer();
0278 
0279             return commonInfo.format;
0280         }
0281 
0282         case SubColumnCreationDateTime:
0283         {
0284             const QDateTime creationDateTime = info.dateTime();
0285 
0286             return QLocale().toString(creationDateTime, QLocale::ShortFormat);
0287         }
0288 
0289         case SubColumnDigitizationDateTime:
0290         {
0291             const ImageCommonContainer commonInfo = info.imageCommonContainer();
0292             const QDateTime digitizationDateTime  = commonInfo.digitizationDate;
0293 
0294             return QLocale().toString(digitizationDateTime, QLocale::ShortFormat);
0295         }
0296         case SubColumnSimilarity:
0297         {
0298             qlonglong referenceImageId = info.currentReferenceImage();
0299             double similarity = info.currentSimilarity() * 100;
0300 
0301             if (referenceImageId == info.id())
0302             {
0303                 similarity = 100.00;
0304             }
0305 
0306             return QLocale().toString(similarity,'f',2);
0307         }
0308     }
0309 
0310     return QVariant();
0311 }
0312 
0313 TableViewColumn::ColumnCompareResult ColumnItemProperties::compare(TableViewModel::Item* const itemA,
0314                                                                    TableViewModel::Item* const itemB) const
0315 {
0316     const ItemInfo infoA = s->tableViewModel->infoFromItem(itemA);
0317     const ItemInfo infoB = s->tableViewModel->infoFromItem(itemB);
0318 
0319     switch (subColumn)
0320     {
0321         case SubColumnHeight:
0322         {
0323             const int heightA = infoA.dimensions().height();
0324             const int heightB = infoB.dimensions().height();
0325 
0326             return compareHelper<int>(heightA, heightB);
0327         }
0328 
0329         case SubColumnWidth:
0330         {
0331             const int widthA = infoA.dimensions().width();
0332             const int widthB = infoB.dimensions().width();
0333 
0334             return compareHelper<int>(widthA, widthB);
0335         }
0336 
0337         case SubColumnDimensions:
0338         {
0339             const int widthA                      = infoA.dimensions().width();
0340             const int widthB                      = infoB.dimensions().width();
0341             const ColumnCompareResult widthResult = compareHelper<int>(widthA, widthB);
0342 
0343             if (widthResult != CmpEqual)
0344             {
0345                 return widthResult;
0346             }
0347 
0348             const int heightA = infoA.dimensions().height();
0349             const int heightB = infoB.dimensions().height();
0350 
0351             return compareHelper<int>(heightA, heightB);
0352         }
0353 
0354         case SubColumnPixelCount:
0355         {
0356             const int widthA      = infoA.dimensions().width();
0357             const int widthB      = infoB.dimensions().width();
0358             const int heightA     = infoA.dimensions().height();
0359             const int heightB     = infoB.dimensions().height();
0360             const int pixelCountA = widthA*heightA;
0361             const int pixelCountB = widthB*heightB;
0362 
0363             return compareHelper<int>(pixelCountA, pixelCountB);
0364         }
0365 
0366         case SubColumnAspectRatio:
0367         {
0368             const int widthA  = infoA.dimensions().width();
0369             const int widthB  = infoB.dimensions().width();
0370             const int heightA = infoA.dimensions().height();
0371             const int heightB = infoB.dimensions().height();
0372 
0373             if ((heightA == 0) || (heightB == 0))
0374             {
0375                 // at least one of the two does not have valid data,
0376                 // sort based on which one has data at all
0377 
0378                 return compareHelper<int>(heightA, heightB);
0379             }
0380 
0381             const qreal aspectRatioA = qreal(widthA) / qreal(heightA);
0382             const qreal aspectRatioB = qreal(widthB) / qreal(heightB);
0383 
0384             /// @todo use fuzzy compare?
0385 
0386             return compareHelper<qreal>(aspectRatioA, aspectRatioB);
0387         }
0388 
0389         case SubColumnBitDepth:
0390         {
0391             const ImageCommonContainer commonInfoA = infoA.imageCommonContainer();
0392             const int bitDepthA                    = commonInfoA.colorDepth;
0393             const ImageCommonContainer commonInfoB = infoB.imageCommonContainer();
0394             const int bitDepthB                    = commonInfoB.colorDepth;
0395 
0396             return compareHelper<int>(bitDepthA, bitDepthB);
0397         }
0398 
0399         case SubColumnCreationDateTime:
0400         {
0401             const QDateTime dtA = infoA.dateTime();
0402             const QDateTime dtB = infoB.dateTime();
0403 
0404             return compareHelper<QDateTime>(dtA, dtB);
0405         }
0406 
0407         case SubColumnDigitizationDateTime:
0408         {
0409             const ImageCommonContainer commonInfoA = infoA.imageCommonContainer();
0410             const ImageCommonContainer commonInfoB = infoB.imageCommonContainer();
0411             const QDateTime dtA                    = commonInfoA.digitizationDate;
0412             const QDateTime dtB                    = commonInfoB.digitizationDate;
0413 
0414             return compareHelper<QDateTime>(dtA, dtB);
0415         }
0416         case SubColumnSimilarity:
0417         {
0418             qlonglong referenceImageIdA = infoA.currentReferenceImage();
0419             qlonglong referenceImageIdB = infoB.currentReferenceImage();
0420 
0421             if (referenceImageIdA == referenceImageIdB)
0422             {
0423                 // make sure that the original image has always the highest similarity.
0424 
0425                 double infoASimilarity = infoA.id() == referenceImageIdA ? 1.0 : infoA.currentSimilarity();
0426                 double infoBSimilarity = infoB.id() == referenceImageIdB ? 1.0 : infoB.currentSimilarity();
0427 
0428                 return compareHelper<double>(infoASimilarity, infoBSimilarity);
0429             }
0430             else
0431             {
0432                 qCWarning(DIGIKAM_GENERAL_LOG) << "item: items have different fuzzy search reference images. Sorting is not possible.";
0433 
0434                 return CmpEqual;
0435             }
0436         }
0437 
0438         default:
0439         {
0440             qCWarning(DIGIKAM_GENERAL_LOG) << "item: unimplemented comparison, subColumn=" << subColumn;
0441 
0442             return CmpEqual;
0443         }
0444     }
0445 }
0446 
0447 } // namespace TableViewColumns
0448 
0449 } // namespace Digikam
0450 
0451 #include "moc_tableview_column_item.cpp"