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