File indexing completed on 2025-01-19 03:57:59

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-06-17
0007  * Description : Find Duplicates tree-view search album item.
0008  *
0009  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "findduplicatesalbumitem.h"
0016 
0017 // Qt includes
0018 
0019 #include <QCollator>
0020 #include <QPainter>
0021 #include <QIcon>
0022 
0023 // Local includes
0024 
0025 #include "digikam_debug.h"
0026 #include "albummanager.h"
0027 #include "coredbsearchxml.h"
0028 #include "deletedialog.h"
0029 #include "itemviewutilities.h"
0030 #include "dio.h"
0031 
0032 namespace Digikam
0033 {
0034 
0035 class Q_DECL_HIDDEN FindDuplicatesAlbumItem::Private
0036 {
0037 
0038 public:
0039 
0040     explicit Private()
0041       : hasThumb  (false),
0042         album     (nullptr),
0043         itemCount (0)
0044     {
0045         collator.setNumericMode(true);
0046         collator.setIgnorePunctuation(false);
0047         collator.setCaseSensitivity(Qt::CaseSensitive);
0048     }
0049 
0050     bool      hasThumb;
0051 
0052     SAlbum*   album;
0053     int       itemCount;
0054 
0055     QCollator collator;
0056 
0057     ItemInfo  refImgInfo;
0058 };
0059 
0060 FindDuplicatesAlbumItem::FindDuplicatesAlbumItem(QTreeWidget* const parent, SAlbum* const album)
0061     : QTreeWidgetItem(parent),
0062       d              (new Private)
0063 {
0064     d->album = album;
0065 
0066     if (d->album)
0067     {
0068         qlonglong refImage = d->album->title().toLongLong();
0069         d->refImgInfo      = ItemInfo(refImage);
0070         setText(Column::REFERENCE_IMAGE, d->refImgInfo.name());
0071         setText(Column::REFERENCE_DATE,  d->refImgInfo.dateTime().toString(Qt::ISODate));
0072 
0073         PAlbum* const physicalAlbum = AlbumManager::instance()->findPAlbum(d->refImgInfo.albumId());
0074         if (physicalAlbum)
0075         {
0076             setText(Column::REFERENCE_ALBUM, physicalAlbum->prettyUrl());
0077         }
0078 
0079         calculateInfos();
0080     }
0081 
0082     setThumb(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(parent->iconSize().width(),
0083                                                                     QIcon::Disabled), false);
0084 }
0085 
0086 FindDuplicatesAlbumItem::~FindDuplicatesAlbumItem()
0087 {
0088     delete d;
0089 }
0090 
0091 bool FindDuplicatesAlbumItem::hasValidThumbnail() const
0092 {
0093     return d->hasThumb;
0094 }
0095 
0096 QList<ItemInfo> FindDuplicatesAlbumItem::duplicatedItems()
0097 {
0098     if (itemCount() <= 1)
0099     {
0100         return QList<ItemInfo>();
0101     }
0102 
0103     SearchXmlReader reader(d->album->query());
0104     reader.readToFirstField();
0105 
0106     QList<ItemInfo> toRemove;
0107 
0108     const QList<qlonglong>& list = reader.valueToLongLongList();
0109     const qlonglong refImage     = d->album->title().toLongLong();
0110 
0111     Q_FOREACH (const qlonglong& imageId, list)
0112     {
0113         if (imageId == refImage)
0114         {
0115             continue;
0116         }
0117 
0118         toRemove.append(ItemInfo(imageId));
0119     }
0120 
0121     return toRemove;
0122 }
0123 
0124 void FindDuplicatesAlbumItem::calculateInfos(const QList<qlonglong>& deletedImages)
0125 {
0126     if (!d->album)
0127     {
0128         return;
0129     }
0130 
0131     qlonglong refImage = d->album->title().toLongLong();
0132 /*
0133     qCDebug(DIGIKAM_GENERAL_LOG) << "Calculating info for album" << refImage;
0134 */
0135     SearchXmlReader reader(d->album->query());
0136     reader.readToFirstField();
0137 
0138     // Get the defined image ids.
0139 
0140     const QList<qlonglong>& list = reader.valueToLongLongList();
0141 
0142     // Only images that are not removed/obsolete should be shown.
0143 
0144     QList<qlonglong> filteredList;
0145     double avgSim = 0.0;
0146 
0147     Q_FOREACH (const qlonglong& imageId, list)
0148     {
0149         ItemInfo info(imageId);
0150 
0151         // If image is not deleted in this moment and was also not
0152         // removed before.
0153 
0154         if (!deletedImages.contains(imageId) && !info.isRemoved())
0155         {
0156             filteredList << imageId;
0157 
0158             if (imageId != refImage)
0159             {
0160                 avgSim += info.similarityTo(refImage);
0161             }
0162         }
0163     }
0164 
0165     d->itemCount = filteredList.count();
0166 /*
0167     qCDebug(DIGIKAM_GENERAL_LOG) << "New Item count:" << d->itemCount;
0168 */
0169     if (d->itemCount > 1)
0170     {
0171         avgSim /= d->itemCount - (filteredList.contains(refImage) ? 1 : 0);
0172     }
0173     else
0174     {
0175         this->setHidden(true);
0176     }
0177 
0178     setText(Column::RESULT_COUNT,   QString::number(d->itemCount));
0179     setText(Column::AVG_SIMILARITY, QString::number(avgSim, 'f', 2));
0180 }
0181 
0182 int FindDuplicatesAlbumItem::itemCount() const
0183 {
0184     return d->itemCount;
0185 }
0186 
0187 void FindDuplicatesAlbumItem::setThumb(const QPixmap& pix, bool hasThumb)
0188 {
0189     int iconSize = treeWidget()->iconSize().width();
0190     QPixmap pixmap(iconSize + 2, iconSize + 2);
0191     pixmap.fill(Qt::transparent);
0192 
0193     QPainter p(&pixmap);
0194     p.drawPixmap((pixmap.width()  / 2) - (pix.width()  / 2),
0195                  (pixmap.height() / 2) - (pix.height() / 2), pix);
0196 
0197     QIcon icon = QIcon(pixmap);
0198 
0199     // We make sure the preview icon stays the same regardless of the role
0200 
0201     icon.addPixmap(pixmap, QIcon::Selected, QIcon::On);
0202     icon.addPixmap(pixmap, QIcon::Selected, QIcon::Off);
0203     icon.addPixmap(pixmap, QIcon::Active,   QIcon::On);
0204     icon.addPixmap(pixmap, QIcon::Active,   QIcon::Off);
0205     icon.addPixmap(pixmap, QIcon::Normal,   QIcon::On);
0206     icon.addPixmap(pixmap, QIcon::Normal,   QIcon::Off);
0207     setIcon(Column::REFERENCE_IMAGE, icon);
0208 
0209     d->hasThumb = hasThumb;
0210 }
0211 
0212 SAlbum* FindDuplicatesAlbumItem::album() const
0213 {
0214     return d->album;
0215 }
0216 
0217 QUrl FindDuplicatesAlbumItem::refUrl() const
0218 {
0219     return d->refImgInfo.fileUrl();
0220 }
0221 
0222 bool FindDuplicatesAlbumItem::operator<(const QTreeWidgetItem& other) const
0223 {
0224     int result = 0;
0225     int column = treeWidget()->sortColumn();
0226 
0227     if      (column == Column::AVG_SIMILARITY)
0228     {
0229         result = (text(column).toDouble() < other.text(column).toDouble()) ? -1 : 0;
0230     }
0231     else if (column == Column::RESULT_COUNT)
0232     {
0233         result = (text(column).toInt() < other.text(column).toInt()) ? -1 : 0;
0234     }
0235     else
0236     {
0237         result = d->collator.compare(text(column), other.text(column));
0238     }
0239 
0240     return (result < 0);
0241 }
0242 
0243 } // namespace Digikam