1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2010-04-30
7 * Description : Graphics View items for DImg
8 *
9 * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "dimgpreviewitem.h"
25 #include "dimgitems_p.h"
26
27 // Qt includes
28
29 #include <QApplication>
30 #include <QScreen>
31
32 // KDE includes
33
34 #include <klocalizedstring.h>
35
36 // Local includes
37
38 #include "iccsettings.h"
39 #include "loadingcacheinterface.h"
40 #include "loadingdescription.h"
41 #include "previewloadthread.h"
42 #include "previewsettings.h"
43
44 namespace Digikam
45 {
46
DImgPreviewItem(QGraphicsItem * const parent)47 DImgPreviewItem::DImgPreviewItem(QGraphicsItem* const parent)
48 : GraphicsDImgItem(*new DImgPreviewItemPrivate, parent)
49 {
50 Q_D(DImgPreviewItem);
51
52 d->init(this);
53 }
54
DImgPreviewItem(DImgPreviewItemPrivate & dd,QGraphicsItem * const parent)55 DImgPreviewItem::DImgPreviewItem(DImgPreviewItemPrivate& dd, QGraphicsItem* const parent)
56 : GraphicsDImgItem(dd, parent)
57 {
58 Q_D(DImgPreviewItem);
59
60 d->init(this);
61 }
62
DImgPreviewItemPrivate()63 DImgPreviewItem::DImgPreviewItemPrivate::DImgPreviewItemPrivate()
64 : state (DImgPreviewItem::NoImage),
65 exifRotate (false),
66 previewSize (1024),
67 previewThread (nullptr),
68 preloadThread (nullptr)
69 {
70 }
71
init(DImgPreviewItem * const q)72 void DImgPreviewItem::DImgPreviewItemPrivate::init(DImgPreviewItem* const q)
73 {
74 previewThread = new PreviewLoadThread;
75 preloadThread = new PreviewLoadThread;
76 preloadThread->setPriority(QThread::LowPriority);
77
78 QObject::connect(previewThread, SIGNAL(signalImageLoaded(LoadingDescription,DImg)),
79 q, SLOT(slotGotImagePreview(LoadingDescription,DImg)));
80
81 QObject::connect(preloadThread, SIGNAL(signalImageLoaded(LoadingDescription,DImg)),
82 q, SLOT(preloadNext()));
83
84 // get preview size from screen size, but limit from VGA to WQXGA
85
86 previewSize = qBound(640,
87 qMax(qApp->primaryScreen()->availableGeometry().height(),
88 qApp->primaryScreen()->availableGeometry().width()),
89 2560);
90
91 LoadingCacheInterface::connectToSignalFileChanged(q, SLOT(slotFileChanged(QString)));
92
93 QObject::connect(IccSettings::instance(), SIGNAL(signalICCSettingsChanged(ICCSettingsContainer,ICCSettingsContainer)),
94 q, SLOT(iccSettingsChanged(ICCSettingsContainer,ICCSettingsContainer)));
95 }
96
~DImgPreviewItem()97 DImgPreviewItem::~DImgPreviewItem()
98 {
99 Q_D(DImgPreviewItem);
100
101 delete d->previewThread;
102 delete d->preloadThread;
103 }
104
setDisplayingWidget(QWidget * const widget)105 void DImgPreviewItem::setDisplayingWidget(QWidget* const widget)
106 {
107 Q_D(DImgPreviewItem);
108
109 d->previewThread->setDisplayingWidget(widget);
110 }
111
setPreviewSettings(const PreviewSettings & settings)112 void DImgPreviewItem::setPreviewSettings(const PreviewSettings& settings)
113 {
114 Q_D(DImgPreviewItem);
115
116 if (settings == d->previewSettings)
117 {
118 return;
119 }
120
121 d->previewSettings = settings;
122 reload();
123 }
124
path() const125 QString DImgPreviewItem::path() const
126 {
127 Q_D(const DImgPreviewItem);
128
129 return d->path;
130 }
131
setPath(const QString & path,bool rePreview)132 void DImgPreviewItem::setPath(const QString& path, bool rePreview)
133 {
134 Q_D(DImgPreviewItem);
135
136 if ((path == d->path) && !rePreview)
137 {
138 return;
139 }
140
141 d->path = path;
142
143 if (d->path.isNull())
144 {
145 d->state = NoImage;
146 emit stateChanged(d->state);
147 }
148 else
149 {
150 d->state = Loading;
151 d->previewThread->load(d->path, d->previewSettings, d->previewSize);
152
153 emit stateChanged(d->state);
154 }
155
156 d->preloadThread->stopLoading();
157 }
158
setPreloadPaths(const QStringList & pathsToPreload)159 void DImgPreviewItem::setPreloadPaths(const QStringList& pathsToPreload)
160 {
161 Q_D(DImgPreviewItem);
162
163 d->pathsToPreload = pathsToPreload;
164 preloadNext();
165 }
166
approximates(const QSizeF & s1,const QSizeF & s2)167 static bool approximates(const QSizeF& s1, const QSizeF& s2)
168 {
169 if (s1 == s2)
170 {
171 return true;
172 }
173
174 double widthRatio = s1.width() / s2.width();
175
176 if ((widthRatio < 0.98) || (widthRatio > 1.02))
177 {
178 return false;
179 }
180
181 double heightRatio = s1.height() / s2.height();
182
183 if ((heightRatio < 0.98) || (heightRatio > 1.02))
184 {
185 return false;
186 }
187
188 return true;
189 }
190
userLoadingHint() const191 QString DImgPreviewItem::userLoadingHint() const
192 {
193 Q_D(const DImgPreviewItem);
194
195 switch (d->state)
196 {
197 case NoImage:
198 {
199 return QString();
200 }
201
202 case Loading:
203 {
204 return i18n("Loading...");
205 }
206
207 case ImageLoaded:
208 {
209 if (d->image.detectedFormat() == DImg::RAW)
210 {
211 if (d->image.attribute(QLatin1String("fromRawEmbeddedPreview")).toBool())
212 {
213 return i18n("Embedded JPEG Preview");
214 }
215 else
216 {
217 return i18n("Half Size Raw Preview");
218 }
219 }
220 else
221 {
222 if (approximates(d->image.originalSize(), d->image.size()))
223 {
224 //return i18n("Full Size Preview");
225 return QString();
226 }
227 else
228 {
229 return i18n("Reduced Size Preview");
230 }
231 }
232
233 return QString(); // To please compiler without warnings.
234 }
235
236 default: // ImageLoadingFailed:
237 {
238 break;
239 }
240 }
241
242 return i18n("Failed to load image");
243 }
244
reload()245 void DImgPreviewItem::reload()
246 {
247 Q_D(DImgPreviewItem);
248
249 QString path = d->path;
250 d->path.clear();
251 setPath(path);
252 }
253
state() const254 DImgPreviewItem::State DImgPreviewItem::state() const
255 {
256 Q_D(const DImgPreviewItem);
257
258 return d->state;
259 }
260
isLoaded() const261 bool DImgPreviewItem::isLoaded() const
262 {
263 Q_D(const DImgPreviewItem);
264
265 return (d->state == ImageLoaded);
266 }
267
slotGotImagePreview(const LoadingDescription & description,const DImg & image)268 void DImgPreviewItem::slotGotImagePreview(const LoadingDescription& description, const DImg& image)
269 {
270 Q_D(DImgPreviewItem);
271
272 if ((description.filePath != d->path) || description.isThumbnail())
273 {
274 return;
275 }
276
277 if (image.isNull())
278 {
279 setImage(DImg());
280
281 d->state = ImageLoadingFailed;
282 emit stateChanged(d->state);
283 emit loadingFailed();
284 }
285 else
286 {
287 setImage(image);
288
289 d->state = ImageLoaded;
290 emit stateChanged(d->state);
291 emit loaded();
292 }
293
294 preloadNext();
295 }
296
preloadNext()297 void DImgPreviewItem::preloadNext()
298 {
299 Q_D(DImgPreviewItem);
300
301 if (!isLoaded() || d->pathsToPreload.isEmpty())
302 {
303 return;
304 }
305
306 QString preloadPath = d->pathsToPreload.takeFirst();
307 d->preloadThread->load(preloadPath, d->previewSettings, d->previewSize);
308 }
309
slotFileChanged(const QString & path)310 void DImgPreviewItem::slotFileChanged(const QString& path)
311 {
312 Q_D(DImgPreviewItem);
313
314 if (d->path == path)
315 {
316 reload();
317 }
318 }
319
iccSettingsChanged(const ICCSettingsContainer & current,const ICCSettingsContainer & previous)320 void DImgPreviewItem::iccSettingsChanged(const ICCSettingsContainer& current, const ICCSettingsContainer& previous)
321 {
322 if ((current.enableCM != previous.enableCM) ||
323 (current.useManagedPreviews != previous.useManagedPreviews) ||
324 (current.monitorProfile != previous.monitorProfile))
325 {
326 reload();
327 }
328 }
329
330 } // namespace Digikam
331