File indexing completed on 2025-03-09 03:50:50

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-12-13
0007  * Description : a tool to blend bracketed images.
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2015      by Benjamin Girault <benjamin dot girault at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "bracketstack.h"
0017 
0018 // Qt includes
0019 
0020 #include <QHeaderView>
0021 #include <QPainter>
0022 #include <QIcon>
0023 
0024 // KDE includes
0025 
0026 #include <klocalizedstring.h>
0027 
0028 // Local includes
0029 
0030 #include "digikam_debug.h"
0031 #include "thumbnailloadthread.h"
0032 
0033 namespace DigikamGenericExpoBlendingPlugin
0034 {
0035 
0036 BracketStackItem::BracketStackItem(QTreeWidget* const parent)
0037     : QTreeWidgetItem(parent)
0038 {
0039     setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
0040     setCheckState(0, Qt::Unchecked);
0041     setThumbnail(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(treeWidget()->iconSize().width(), QIcon::Disabled));
0042 }
0043 
0044 void BracketStackItem::setUrl(const QUrl& url)
0045 {
0046     m_url = url;
0047     setText(1, m_url.fileName());
0048 }
0049 
0050 const QUrl& BracketStackItem::url() const
0051 {
0052     return m_url;
0053 }
0054 
0055 void BracketStackItem::setThumbnail(const QPixmap& pix)
0056 {
0057     int iconSize = qMax<int>(treeWidget()->iconSize().width(), treeWidget()->iconSize().height());
0058     QPixmap pixmap(iconSize+2, iconSize+2);
0059     pixmap.fill(Qt::transparent);
0060     QPainter p(&pixmap);
0061     p.drawPixmap((pixmap.width()/2) - (pix.width()/2), (pixmap.height()/2) - (pix.height()/2), pix);
0062     setIcon(0, QIcon(pixmap));
0063 }
0064 
0065 void BracketStackItem::setExposure(const QString& exp)
0066 {
0067     setText(2, exp);
0068 }
0069 
0070 bool BracketStackItem::isOn() const
0071 {
0072     return ((checkState(0) == Qt::Checked) ? true : false);
0073 }
0074 
0075 void BracketStackItem::setOn(bool b)
0076 {
0077     setCheckState(0, b ? Qt::Checked : Qt::Unchecked);
0078 }
0079 
0080 bool BracketStackItem::operator< (const QTreeWidgetItem& other) const
0081 {
0082     int column     = treeWidget()->sortColumn();
0083     double thisEv  = text(column).toDouble();
0084     double otherEv = other.text(column).toDouble();
0085 
0086     return (thisEv < otherEv);
0087 }
0088 
0089 // -------------------------------------------------------------------------
0090 
0091 BracketStackList::BracketStackList(QWidget* const parent)
0092     : QTreeWidget(parent)
0093 {
0094     setIconSize(QSize(64, 64));
0095     setSelectionMode(QAbstractItemView::SingleSelection);
0096     setSortingEnabled(true);
0097     setRootIsDecorated(false);
0098     setUniformRowHeights(true);
0099     setAllColumnsShowFocus(true);
0100     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0101     setColumnCount(3);
0102     setHeaderHidden(false);
0103     setDragEnabled(false);
0104     header()->setSectionResizeMode(QHeaderView::Stretch);
0105 
0106     QStringList labels;
0107     labels.append( i18nc("@title:column Processing checkbox", "Include for Enfuse") );
0108     labels.append( i18nc("@title:column Input file name", "File Name") );
0109     labels.append( i18nc("@title:column Input image exposure", "Exposure (EV)") );
0110     setHeaderLabels(labels);
0111 
0112     connect(ThumbnailLoadThread::defaultThread(), SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)),
0113             this, SLOT(slotThumbnail(LoadingDescription,QPixmap)));
0114 
0115     connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
0116             this, SLOT(slotItemClicked(QTreeWidgetItem*,int)));
0117 
0118     sortItems(2, Qt::DescendingOrder);
0119 }
0120 
0121 QList<QUrl> BracketStackList::urls()
0122 {
0123     QList<QUrl> list;
0124     QTreeWidgetItemIterator it(this);
0125 
0126     while (*it)
0127     {
0128         BracketStackItem* const item = dynamic_cast<BracketStackItem*>(*it);
0129 
0130         if (item && item->isOn())
0131         {
0132             list.append(item->url());
0133         }
0134 
0135         ++it;
0136     }
0137 
0138     return list;
0139 }
0140 
0141 BracketStackItem* BracketStackList::findItem(const QUrl& url)
0142 {
0143     QTreeWidgetItemIterator it(this);
0144 
0145     while (*it)
0146     {
0147         BracketStackItem* const lvItem = dynamic_cast<BracketStackItem*>(*it);
0148 
0149         if (lvItem && (lvItem->url() == url))
0150         {
0151             return lvItem;
0152         }
0153 
0154         ++it;
0155     }
0156 
0157     return nullptr;
0158 }
0159 
0160 void BracketStackList::addItems(const QList<QUrl>& list)
0161 {
0162     if (list.count() == 0)
0163     {
0164         return;
0165     }
0166 
0167     QList<QUrl> urls;
0168 
0169     for (const QUrl& imageUrl: list)
0170     {
0171         // Check if the new item already exist in the list.
0172 
0173         bool found = false;
0174 
0175         QTreeWidgetItemIterator iter(this);
0176 
0177         while (*iter)
0178         {
0179             BracketStackItem* const item = dynamic_cast<BracketStackItem*>(*iter);
0180 
0181             if (item->url() == imageUrl)
0182             {
0183                 found = true;
0184             }
0185 
0186             ++iter;
0187         }
0188 
0189         if (!found)
0190         {
0191             BracketStackItem* const item = new BracketStackItem(this);
0192             item->setUrl(imageUrl);
0193             item->setOn(true);
0194             urls.append(imageUrl);
0195         }
0196     }
0197 
0198     Q_FOREACH (const QUrl& url, urls)
0199     {
0200         ThumbnailLoadThread::defaultThread()->find(ThumbnailIdentifier(url.toLocalFile()));
0201     }
0202 
0203     Q_EMIT signalAddItems(urls);
0204 }
0205 
0206 void BracketStackList::slotThumbnail(const LoadingDescription& desc, const QPixmap& pix)
0207 {
0208     QTreeWidgetItemIterator it(this);
0209 
0210     while (*it)
0211     {
0212         BracketStackItem* const item = static_cast<BracketStackItem*>(*it);
0213 
0214         if (item->url() == QUrl::fromLocalFile(desc.filePath))
0215         {
0216             if (pix.isNull())
0217             {
0218                 item->setThumbnail(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(iconSize().width(), QIcon::Disabled));
0219             }
0220             else
0221             {
0222                 item->setThumbnail(pix.scaled(iconSize().width(), iconSize().height(), Qt::KeepAspectRatio));
0223             }
0224 
0225             return;
0226         }
0227 
0228         ++it;
0229     }
0230 }
0231 
0232 void BracketStackList::slotItemClicked(QTreeWidgetItem* item, int column)
0233 {
0234     BracketStackItem* const cItem = dynamic_cast<BracketStackItem*>(item);
0235 
0236     if (cItem && (column == 1))
0237     {
0238         Q_EMIT signalItemClicked(cItem->url());
0239     }
0240 }
0241 
0242 } // namespace DigikamGenericExpoBlendingPlugin
0243 
0244 #include "moc_bracketstack.cpp"