File indexing completed on 2025-01-19 03:50:49

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: Thumbnail column
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_thumbnail.h"
0017 
0018 // Qt includes
0019 
0020 #include <QPainter>
0021 #include <QStyleOptionViewItem>
0022 
0023 // KDE includes
0024 
0025 #include <klocalizedstring.h>
0026 
0027 // Local includes
0028 
0029 #include "itemfiltermodel.h"
0030 #include "tableview.h"
0031 #include "thumbnailloadthread.h"
0032 #include "thumbnailsize.h"
0033 #include "metaengine.h"
0034 
0035 namespace
0036 {
0037     const int ThumbnailBorder = 2;
0038 }
0039 
0040 namespace Digikam
0041 {
0042 
0043 namespace TableViewColumns
0044 {
0045 
0046 ColumnThumbnail::ColumnThumbnail(TableViewShared* const tableViewShared,
0047                                  const TableViewColumnConfiguration& pConfiguration,
0048                                  QWidget* const parent)
0049     : TableViewColumn(tableViewShared, pConfiguration, parent),
0050       m_thumbnailSize(s->tableView->getThumbnailSize().size()),
0051       m_displayWidget(parent)
0052 {
0053     connect(s->thumbnailLoadThread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)),
0054             this, SLOT(slotThumbnailLoaded(LoadingDescription,QPixmap)));
0055 }
0056 
0057 ColumnThumbnail::~ColumnThumbnail()
0058 {
0059 }
0060 
0061 bool ColumnThumbnail::CreateFromConfiguration(TableViewShared* const tableViewShared,
0062                                               const TableViewColumnConfiguration& pConfiguration,
0063                                               TableViewColumn** const pNewColumn,
0064                                               QWidget* const parent)
0065 {
0066     if (pConfiguration.columnId != QLatin1String("thumbnail"))
0067     {
0068         return false;
0069     }
0070 
0071     *pNewColumn = new ColumnThumbnail(tableViewShared, pConfiguration, parent);
0072 
0073     return true;
0074 }
0075 
0076 TableViewColumnDescription ColumnThumbnail::getDescription()
0077 {
0078     return TableViewColumnDescription(QLatin1String("thumbnail"), i18n("Thumbnail"));
0079 }
0080 
0081 TableViewColumn::ColumnFlags ColumnThumbnail::getColumnFlags() const
0082 {
0083     return ColumnCustomPainting;
0084 }
0085 
0086 QString ColumnThumbnail::getTitle() const
0087 {
0088     return i18n("Thumbnail");
0089 }
0090 
0091 QVariant ColumnThumbnail::data(TableViewModel::Item* const item, const int role) const
0092 {
0093     Q_UNUSED(item)
0094     Q_UNUSED(role)
0095 
0096     // we do not return any data, but paint(...) something
0097 
0098     return QVariant();
0099 }
0100 
0101 bool ColumnThumbnail::paint(QPainter* const painter, const QStyleOptionViewItem& option, TableViewModel::Item* const item) const
0102 {
0103     if (option.state & QStyle::State_Selected)
0104     {
0105         painter->fillRect(option.rect, option.palette.highlight());
0106     }
0107 
0108     const ItemInfo info = s->tableViewModel->infoFromItem(item);
0109 
0110     if (!info.isNull())
0111     {
0112         QSize availableSize = option.rect.size() - QSize(ThumbnailBorder, ThumbnailBorder);
0113         QSize imageSize     = info.dimensions();
0114         int maxSize         = m_thumbnailSize;
0115 
0116         // When the image is rotated, swap width and height.
0117 
0118         if (info.orientation() > MetaEngine::ORIENTATION_VFLIP)
0119         {
0120             imageSize.transpose();
0121         }
0122 
0123         if (imageSize.isValid() && (imageSize.width() > imageSize.height()))
0124         {
0125             // for landscape pictures, try to use all available horizontal space
0126 
0127             qreal scaleFactor = qreal(availableSize.height()) / qreal(imageSize.height());
0128             maxSize           = imageSize.width() * scaleFactor;
0129         }
0130 
0131         // Calculate the maximum thumbnail size
0132         // The idea here is that for landscape images, we adjust the height to
0133         // to be as high as the row height as long as the width can stretch enough
0134         // because the column is wider than the thumbnail size.
0135 
0136         maxSize    = qMin(maxSize, availableSize.width());
0137 
0138         // However, digiKam limits the thumbnail size, so we also do that here
0139 
0140         maxSize    = qMin(maxSize, (int)ThumbnailSize::maxThumbsSize());
0141         double dpr = m_displayWidget->devicePixelRatio();
0142         maxSize    = qRound((double)maxSize * dpr);
0143 
0144         QPixmap thumbnail;
0145 
0146         if (s->thumbnailLoadThread->find(info.thumbnailIdentifier(), thumbnail, maxSize))
0147         {
0148             thumbnail.setDevicePixelRatio(dpr);
0149 
0150             /// @todo Is slotThumbnailLoaded still called when the thumbnail is found right away?
0151 
0152             QSize pixmapSize = (QSizeF(thumbnail.size()) / dpr).toSize();
0153             pixmapSize       = pixmapSize.boundedTo(availableSize);
0154             QSize alignSize  = option.rect.size();
0155 
0156             QPoint startPoint((alignSize.width()  - pixmapSize.width())  / 2,
0157                               (alignSize.height() - pixmapSize.height()) / 2);
0158             startPoint      += option.rect.topLeft();
0159 
0160             painter->drawPixmap(QRect(startPoint, pixmapSize), thumbnail,
0161                                 QRect(QPoint(0, 0), thumbnail.size()));
0162 
0163             return true;
0164         }
0165     }
0166 
0167     // we did not get to paint a thumbnail...
0168 
0169     return false;
0170 }
0171 
0172 QSize ColumnThumbnail::sizeHint(const QStyleOptionViewItem& option, TableViewModel::Item* const item) const
0173 {
0174     Q_UNUSED(option)
0175     Q_UNUSED(item)
0176 
0177     /// @todo On portrait pictures, the borders are too close. There should be a gap. Is this setting okay?
0178 
0179     const int thumbnailSizeWithBorder = m_thumbnailSize+ThumbnailBorder;
0180 
0181     return QSize(thumbnailSizeWithBorder, thumbnailSizeWithBorder);
0182 }
0183 
0184 void ColumnThumbnail::slotThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap& thumb)
0185 {
0186     if (thumb.isNull())
0187     {
0188         return;
0189     }
0190 
0191     /// @todo Find a way to do this without the ItemFilterModel
0192 
0193     const QModelIndex imageModelIndex = s->imageModel->indexForPath(loadingDescription.filePath);
0194 
0195     if (!imageModelIndex.isValid())
0196     {
0197         return;
0198     }
0199 
0200     const qlonglong imageId = s->imageModel->imageId(imageModelIndex);
0201 
0202     Q_EMIT signalDataChanged(imageId);
0203 }
0204 
0205 void ColumnThumbnail::updateThumbnailSize()
0206 {
0207     /// @todo Set minimum column width to m_thumbnailSize
0208 
0209     m_thumbnailSize = s->tableView->getThumbnailSize().size();
0210 
0211     Q_EMIT signalAllDataChanged();
0212 }
0213 
0214 } // namespace TableViewColumns
0215 
0216 } // namespace Digikam
0217 
0218 #include "moc_tableview_column_thumbnail.cpp"