1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2014-09-19
7  * Description : slide properties widget
8  *
9  * Copyright (C) 2014-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2019-2020 by Minh Nghia Duong <minhnghiaduong997 at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "slideproperties.h"
26 
27 // Qt includes
28 
29 #include <QTextDocument>
30 #include <QApplication>
31 #include <QDateTime>
32 #include <QPainter>
33 #include <QPixmap>
34 #include <QLocale>
35 
36 // KDE includes
37 
38 #include <klocalizedstring.h>
39 
40 // Local includes
41 
42 #include "digikam_debug.h"
43 #include "dinfointerface.h"
44 #include "itempropertiestab.h"
45 
46 using namespace Digikam;
47 
48 namespace DigikamGenericSlideShowPlugin
49 {
50 
51 class Q_DECL_HIDDEN SlideProperties::Private
52 {
53 public:
54 
Private()55     explicit Private()
56         : maxStringLen(80),
57           paintEnabled(true),
58           settings    (nullptr)
59     {
60     }
61 
62     const int                maxStringLen;
63     bool                     paintEnabled;
64 
65     QUrl                     url;
66 
67     SlideShowSettings*       settings;
68 
69     DInfoInterface::DInfoMap infoMap;
70 };
71 
SlideProperties(SlideShowSettings * const settings,QWidget * const parent)72 SlideProperties::SlideProperties(SlideShowSettings* const settings, QWidget* const parent)
73     : QWidget(parent),
74       d      (new Private)
75 {
76     setMouseTracking(true);
77     d->settings = settings;
78 }
79 
~SlideProperties()80 SlideProperties::~SlideProperties()
81 {
82     delete d;
83 }
84 
setCurrentUrl(const QUrl & url)85 void SlideProperties::setCurrentUrl(const QUrl& url)
86 {
87     d->infoMap = d->settings->iface->itemInfo(url);
88     d->url     = url;
89 
90     update();
91 }
92 
paintEvent(QPaintEvent *)93 void SlideProperties::paintEvent(QPaintEvent*)
94 {
95     if (!d->paintEnabled)
96     {
97         return;
98     }
99 
100     QPainter p(this);
101     p.setFont(d->settings->captionFont);
102 
103     DItemInfo item(d->infoMap);
104 
105     QString str;
106 /*
107     PhotoInfoContainer photoInfo = d->info.photoInfo;
108 */
109     QString comment  = item.comment();
110     QString title    = item.title();
111     QStringList tags = item.keywords();
112     int offset       = 0;
113 
114     // Display tag names.
115 
116     if (d->settings->printTags)
117     {
118         printTags(p, offset, tags);
119     }
120 
121     // Display Titles.
122 
123     if (d->settings->printTitle)
124     {
125         str.clear();
126 
127         if (!title.isEmpty())
128         {
129             str += title;
130             printInfoText(p, offset, str);
131         }
132     }
133 
134     // Display Captions if no Titles.
135 
136     if (d->settings->printCapIfNoTitle)
137     {
138         str.clear();
139 
140         if (title.isEmpty())
141         {
142             str += comment;
143             printComments(p, offset, str);
144         }
145     }
146 
147     // Display Comments.
148 
149     if (d->settings->printComment)
150     {
151         str = comment;
152         printComments(p, offset, str);
153     }
154 
155     // Display Make and Model.
156 
157     if (d->settings->printMakeModel)
158     {
159         str.clear();
160 
161         QString make  = item.make();
162         QString model = item.model();
163 
164         if (!make.isEmpty())
165         {
166             ItemPropertiesTab::shortenedMakeInfo(make);
167             str = make;
168         }
169 
170         if (!model.isEmpty())
171         {
172             if (!make.isEmpty())
173             {
174                 str += QLatin1String(" / ");
175             }
176 
177             ItemPropertiesTab::shortenedModelInfo(model);
178             str += model;
179         }
180 
181         printInfoText(p, offset, str);
182     }
183 
184     // Display Lens model.
185 
186     if (d->settings->printLensModel)
187     {
188         str.clear();
189 
190         QString lens = item.lens();
191 
192         if (!lens.isEmpty())
193         {
194             str = lens;
195             printInfoText(p, offset, str);
196         }
197     }
198 
199     // Display Exposure and Sensitivity.
200 
201     if (d->settings->printExpoSensitivity)
202     {
203         str.clear();
204 
205         QString exposureTime = item.exposureTime();
206         QString sensitivity  = item.sensitivity();
207 
208         if (!exposureTime.isEmpty())
209         {
210             str = exposureTime;
211         }
212 
213         if (!sensitivity.isEmpty())
214         {
215             if (!exposureTime.isEmpty())
216             {
217                 str += QLatin1String(" / ");
218             }
219 
220             str += i18n("%1 ISO", sensitivity);
221         }
222 
223         printInfoText(p, offset, str);
224     }
225 
226     // Display Aperture and Focal.
227 
228     if (d->settings->printApertureFocal)
229     {
230         str.clear();
231 
232         QString aperture        = item.aperture();
233         QString focalLength     = item.focalLength();
234         QString focalLength35mm = item.focalLength35mm();
235 
236         if (!aperture.isEmpty())
237         {
238             str = aperture;
239         }
240 
241         if (focalLength35mm.isEmpty())
242         {
243             if (!focalLength.isEmpty())
244             {
245                 if (!aperture.isEmpty())
246                 {
247                     str += QLatin1String(" / ");
248                 }
249 
250                 str += focalLength;
251             }
252         }
253         else
254         {
255             if (!aperture.isEmpty())
256             {
257                 str += QLatin1String(" / ");
258             }
259 
260             if (!focalLength.isEmpty())
261             {
262                 str += QString::fromUtf8("%1 (%2)").arg(focalLength).arg(focalLength35mm);
263             }
264             else
265             {
266                 str += QString::fromUtf8("%1").arg(focalLength35mm);
267             }
268         }
269 
270         printInfoText(p, offset, str);
271     }
272 
273     // Display Creation Date.
274 
275     if (d->settings->printDate)
276     {
277         QDateTime dateTime = item.dateTime();
278 
279         if (dateTime.isValid())
280         {
281             str = QLocale().toString(dateTime, QLocale::ShortFormat);
282             printInfoText(p, offset, str);
283         }
284     }
285 
286     // Display image File Name.
287 
288     if (d->settings->printName)
289     {
290         printInfoText(p, offset, d->url.fileName());
291     }
292 }
293 
printInfoText(QPainter & p,int & offset,const QString & str,const QColor & pcol)294 void SlideProperties::printInfoText(QPainter& p, int& offset, const QString& str, const QColor& pcol)
295 {
296     if (!str.isEmpty())
297     {
298         offset += QFontMetrics(p.font()).lineSpacing();
299         p.setPen(Qt::black);
300 
301         for (int x = -1 ; x <= 1 ; ++x)
302         {
303             for (int y = offset + 1 ; y >= offset - 1 ; --y)
304             {
305                 p.drawText(x, p.window().height() - y, str);
306             }
307         }
308 
309         p.setPen(pcol);
310         p.drawText(0, p.window().height() - offset, str);
311     }
312 }
313 
printComments(QPainter & p,int & offset,const QString & comments)314 void SlideProperties::printComments(QPainter& p, int& offset, const QString& comments)
315 {
316     QStringList commentsByLines;
317 
318     uint commentsIndex = 0;     // Comments QString index
319 
320     while (commentsIndex < (uint)comments.length())
321     {
322         QString newLine;
323         bool breakLine = false; // End Of Line found
324         uint currIndex;         // Comments QString current index
325 
326         // Check minimal lines dimension
327 
328         uint commentsLinesLengthLocal = d->maxStringLen;
329 
330         for (currIndex = commentsIndex ;
331              (currIndex < (uint)comments.length()) && !breakLine ; ++currIndex)
332         {
333             if ((comments.at(currIndex) == QLatin1Char('\n')) || comments.at(currIndex).isSpace())
334             {
335                 breakLine = true;
336             }
337         }
338 
339         if (commentsLinesLengthLocal <= (currIndex - commentsIndex))
340         {
341             commentsLinesLengthLocal = (currIndex - commentsIndex);
342         }
343 
344         breakLine = false;
345 
346         for (currIndex = commentsIndex ;
347              (currIndex <= (commentsIndex + commentsLinesLengthLocal)) &&
348              (currIndex < (uint)comments.length()) && !breakLine ;
349              ++currIndex)
350         {
351             breakLine = (comments.at(currIndex) == QLatin1Char('\n')) ? true : false;
352 
353             if (breakLine)
354             {
355                 newLine.append(QLatin1Char(' '));
356             }
357             else
358             {
359                 newLine.append(comments.at(currIndex));
360             }
361         }
362 
363         commentsIndex = currIndex; // The line is ended
364 
365         if (commentsIndex != (uint)comments.length())
366         {
367             while (!newLine.endsWith(QLatin1Char(' ')))
368             {
369                 newLine.truncate(newLine.length() - 1);
370                 --commentsIndex;
371             }
372         }
373 
374         commentsByLines.prepend(newLine.trimmed());
375     }
376 
377     for (int i = 0 ; i < (int)commentsByLines.count() ; ++i)
378     {
379         printInfoText(p, offset, commentsByLines.at(i));
380     }
381 }
382 
printTags(QPainter & p,int & offset,QStringList & tags)383 void SlideProperties::printTags(QPainter& p, int& offset, QStringList& tags)
384 {
385     tags.sort();
386 
387     QString str = tags.join(QLatin1String(", "));
388 
389     if (!str.isEmpty())
390     {
391         printInfoText(p, offset, str, qApp->palette().color(QPalette::Link).name());
392     }
393 }
394 
togglePaintEnabled()395 void SlideProperties::togglePaintEnabled()
396 {
397     d->paintEnabled = !d->paintEnabled;
398     update();
399 }
400 
401 } // namespace DigikamGenericSlideShowPlugin
402