File indexing completed on 2025-04-27 03:58:23

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-04-30
0007  * Description : Graphics View items for DImg
0008  *
0009  * SPDX-FileCopyrightText: 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "dimgpreviewitem.h"
0016 #include "dimgitems_p.h"
0017 
0018 // Qt includes
0019 
0020 #include <QApplication>
0021 #include <QScreen>
0022 
0023 // KDE includes
0024 
0025 #include <klocalizedstring.h>
0026 
0027 // Local includes
0028 
0029 #include "iccsettings.h"
0030 #include "loadingcacheinterface.h"
0031 #include "loadingdescription.h"
0032 #include "previewloadthread.h"
0033 #include "previewsettings.h"
0034 
0035 namespace Digikam
0036 {
0037 
0038 DImgPreviewItem::DImgPreviewItem(QGraphicsItem* const parent)
0039     : GraphicsDImgItem(*new DImgPreviewItemPrivate, parent)
0040 {
0041     Q_D(DImgPreviewItem);
0042 
0043     d->init(this);
0044 }
0045 
0046 DImgPreviewItem::DImgPreviewItem(DImgPreviewItemPrivate& dd, QGraphicsItem* const parent)
0047     : GraphicsDImgItem(dd, parent)
0048 {
0049     Q_D(DImgPreviewItem);
0050 
0051     d->init(this);
0052 }
0053 
0054 DImgPreviewItem::DImgPreviewItemPrivate::DImgPreviewItemPrivate()
0055     : state         (DImgPreviewItem::NoImage),
0056       exifRotate    (false),
0057       previewSize   (1024),
0058       previewThread (nullptr),
0059       preloadThread (nullptr)
0060 {
0061 }
0062 
0063 void DImgPreviewItem::DImgPreviewItemPrivate::init(DImgPreviewItem* const q)
0064 {
0065     previewThread = new PreviewLoadThread;
0066     preloadThread = new PreviewLoadThread;
0067     preloadThread->setPriority(QThread::LowPriority);
0068 
0069     QObject::connect(previewThread, SIGNAL(signalImageLoaded(LoadingDescription,DImg)),
0070                      q, SLOT(slotGotImagePreview(LoadingDescription,DImg)));
0071 
0072     QObject::connect(preloadThread, SIGNAL(signalImageLoaded(LoadingDescription,DImg)),
0073                      q, SLOT(preloadNext()));
0074 
0075     // get preview size from screen size, but limit from VGA to WQXGA
0076 
0077     previewSize = qBound(640,
0078                          qMax(qApp->primaryScreen()->availableGeometry().height(),
0079                               qApp->primaryScreen()->availableGeometry().width()),
0080                          2560);
0081 
0082     LoadingCacheInterface::connectToSignalFileChanged(q, SLOT(slotFileChanged(QString)));
0083 
0084     QObject::connect(IccSettings::instance(), SIGNAL(signalICCSettingsChanged(ICCSettingsContainer,ICCSettingsContainer)),
0085                      q, SLOT(iccSettingsChanged(ICCSettingsContainer,ICCSettingsContainer)));
0086 }
0087 
0088 DImgPreviewItem::~DImgPreviewItem()
0089 {
0090     Q_D(DImgPreviewItem);
0091 
0092     delete d->previewThread;
0093     delete d->preloadThread;
0094 }
0095 
0096 void DImgPreviewItem::setDisplayingWidget(QWidget* const widget)
0097 {
0098     Q_D(DImgPreviewItem);
0099 
0100     d->previewThread->setDisplayingWidget(widget);
0101 }
0102 
0103 void DImgPreviewItem::setPreviewSettings(const PreviewSettings& settings)
0104 {
0105     Q_D(DImgPreviewItem);
0106 
0107     if (settings == d->previewSettings)
0108     {
0109         return;
0110     }
0111 
0112     d->previewSettings = settings;
0113     reload();
0114 }
0115 
0116 QString DImgPreviewItem::path() const
0117 {
0118     Q_D(const DImgPreviewItem);
0119 
0120     return d->path;
0121 }
0122 
0123 void DImgPreviewItem::setPath(const QString& path, bool rePreview)
0124 {
0125     Q_D(DImgPreviewItem);
0126 
0127     if ((path == d->path) && !rePreview)
0128     {
0129         return;
0130     }
0131 
0132     d->path = path;
0133 
0134     if (d->path.isNull())
0135     {
0136         d->state = NoImage;
0137         Q_EMIT stateChanged(d->state);
0138     }
0139     else
0140     {
0141         d->state = Loading;
0142         d->previewThread->load(d->path, d->previewSettings, d->previewSize);
0143 
0144         Q_EMIT stateChanged(d->state);
0145     }
0146 
0147     d->preloadThread->stopLoading();
0148 }
0149 
0150 void DImgPreviewItem::setPreloadPaths(const QStringList& pathsToPreload)
0151 {
0152     Q_D(DImgPreviewItem);
0153 
0154     d->pathsToPreload = pathsToPreload;
0155     preloadNext();
0156 }
0157 
0158 static bool approximates(const QSizeF& s1, const QSizeF& s2)
0159 {
0160     if (s1 == s2)
0161     {
0162         return true;
0163     }
0164 
0165     double widthRatio = s1.width() / s2.width();
0166 
0167     if ((widthRatio < 0.98) || (widthRatio > 1.02))
0168     {
0169         return false;
0170     }
0171 
0172     double heightRatio = s1.height() / s2.height();
0173 
0174     if ((heightRatio < 0.98) || (heightRatio > 1.02))
0175     {
0176         return false;
0177     }
0178 
0179     return true;
0180 }
0181 
0182 QString DImgPreviewItem::userLoadingHint() const
0183 {
0184     Q_D(const DImgPreviewItem);
0185 
0186     switch (d->state)
0187     {
0188         case NoImage:
0189         {
0190             return QString();
0191         }
0192 
0193         case Loading:
0194         {
0195             return i18n("Loading...");
0196         }
0197 
0198         case ImageLoaded:
0199         {
0200             if (d->image.detectedFormat() == DImg::RAW)
0201             {
0202                 if      (d->image.attribute(QLatin1String("fromRawEmbeddedPreview")).toBool())
0203                 {
0204                     return i18n("Embedded JPEG Preview");
0205                 }
0206                 else if (approximates(d->image.originalSize(), d->image.size()))
0207                 {
0208                     return QString();
0209                 }
0210                 else
0211                 {
0212                     return i18n("Half Size Raw Preview");
0213                 }
0214             }
0215             else
0216             {
0217                 if (approximates(d->image.originalSize(), d->image.size()))
0218                 {
0219                     //return i18n("Full Size Preview");
0220                     return QString();
0221                 }
0222                 else
0223                 {
0224                     return i18n("Reduced Size Preview");
0225                 }
0226             }
0227 
0228             return QString();   // To please compiler without warnings.
0229         }
0230 
0231         default: // ImageLoadingFailed:
0232         {
0233             break;
0234         }
0235     }
0236 
0237     return i18n("Failed to load image");
0238 }
0239 
0240 void DImgPreviewItem::reload()
0241 {
0242     Q_D(DImgPreviewItem);
0243 
0244     QString path = d->path;
0245     d->path.clear();
0246     setPath(path);
0247 }
0248 
0249 DImgPreviewItem::State DImgPreviewItem::state() const
0250 {
0251     Q_D(const DImgPreviewItem);
0252 
0253     return d->state;
0254 }
0255 
0256 bool DImgPreviewItem::isLoaded() const
0257 {
0258     Q_D(const DImgPreviewItem);
0259 
0260     return (d->state == ImageLoaded);
0261 }
0262 
0263 void DImgPreviewItem::slotGotImagePreview(const LoadingDescription& description, const DImg& image)
0264 {
0265     Q_D(DImgPreviewItem);
0266 
0267     if ((description.filePath != d->path) || description.isThumbnail())
0268     {
0269         return;
0270     }
0271 
0272     if (image.isNull())
0273     {
0274         setImage(DImg());
0275 
0276         d->state = ImageLoadingFailed;
0277         Q_EMIT stateChanged(d->state);
0278         Q_EMIT loadingFailed();
0279     }
0280     else
0281     {
0282         setImage(image);
0283 
0284         d->state = ImageLoaded;
0285         Q_EMIT stateChanged(d->state);
0286         Q_EMIT loaded();
0287     }
0288 
0289     preloadNext();
0290 }
0291 
0292 void DImgPreviewItem::preloadNext()
0293 {
0294     Q_D(DImgPreviewItem);
0295 
0296     if (!isLoaded() || d->pathsToPreload.isEmpty())
0297     {
0298         return;
0299     }
0300 
0301     QString preloadPath = d->pathsToPreload.takeFirst();
0302     d->preloadThread->load(preloadPath, d->previewSettings, d->previewSize);
0303 }
0304 
0305 void DImgPreviewItem::slotFileChanged(const QString& path)
0306 {
0307     Q_D(DImgPreviewItem);
0308 
0309     if (d->path == path)
0310     {
0311         reload();
0312     }
0313 }
0314 
0315 void DImgPreviewItem::iccSettingsChanged(const ICCSettingsContainer& current, const ICCSettingsContainer& previous)
0316 {
0317     if ((current.enableCM != previous.enableCM)                     ||
0318         (current.useManagedPreviews != previous.useManagedPreviews) ||
0319         (current.monitorProfile != previous.monitorProfile))
0320     {
0321         reload();
0322     }
0323 }
0324 
0325 } // namespace Digikam
0326 
0327 #include "moc_dimgpreviewitem.cpp"