1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2006-04-19
7  * Description : A tab to display general item information
8  *
9  * Copyright (C) 2006-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2013      by Michael G. Hansen <mike at mghansen dot de>
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 "itempropertiestab.h"
26 
27 // Qt includes
28 
29 #include <QGridLayout>
30 #include <QStyle>
31 #include <QDir>
32 #include <QFile>
33 #include <QPixmap>
34 #include <QPainter>
35 #include <QPair>
36 #include <QVariant>
37 #include <QApplication>
38 #include <QCollator>
39 #include <QIcon>
40 #include <QLocale>
41 #include <QTime>
42 #include <QtMath>
43 
44 // KDE includes
45 
46 #include <klocalizedstring.h>
47 
48 // Local includes
49 
50 #include "itempropertiestxtlabel.h"
51 #include "picklabelwidget.h"
52 #include "colorlabelwidget.h"
53 
54 namespace Digikam
55 {
56 
57 class Q_DECL_HIDDEN ItemPropertiesTab::Private
58 {
59 public:
60 
61     enum Section
62     {
63         FileProperties = 0,
64         ImageProperties,
65         PhotoProperties,
66         VideoProperties,
67         digiKamProperties
68     };
69 
70 public:
71 
Private()72     explicit Private()
73       : caption                   (nullptr),
74         pickLabel                 (nullptr),
75         colorLabel                (nullptr),
76         rating                    (nullptr),
77         tags                      (nullptr),
78         labelFile                 (nullptr),
79         labelFolder               (nullptr),
80         labelFileModifiedDate     (nullptr),
81         labelFileSize             (nullptr),
82         labelFileOwner            (nullptr),
83         labelFilePermissions      (nullptr),
84         labelImageMime            (nullptr),
85         labelImageDimensions      (nullptr),
86         labelImageRatio           (nullptr),
87         labelImageBitDepth        (nullptr),
88         labelImageColorMode       (nullptr),
89         labelHasSidecar           (nullptr),
90         labelPhotoMake            (nullptr),
91         labelPhotoModel           (nullptr),
92         labelPhotoDateTime        (nullptr),
93         labelPhotoLens            (nullptr),
94         labelPhotoAperture        (nullptr),
95         labelPhotoFocalLength     (nullptr),
96         labelPhotoExposureTime    (nullptr),
97         labelPhotoSensitivity     (nullptr),
98         labelPhotoExposureMode    (nullptr),
99         labelPhotoFlash           (nullptr),
100         labelPhotoWhiteBalance    (nullptr),
101         labelCaption              (nullptr),
102         labelTags                 (nullptr),
103         labelPickLabel            (nullptr),
104         labelColorLabel           (nullptr),
105         labelRating               (nullptr),
106         labelVideoAspectRatio     (nullptr),
107         labelVideoDuration        (nullptr),
108         labelVideoFrameRate       (nullptr),
109         labelVideoVideoCodec      (nullptr),
110         labelVideoAudioBitRate    (nullptr),
111         labelVideoAudioChannelType(nullptr),
112         labelVideoAudioCodec      (nullptr)
113     {
114     }
115 
116     DTextLabelName*  caption;
117     DTextLabelName*  pickLabel;
118     DTextLabelName*  colorLabel;
119     DTextLabelName*  rating;
120     DTextLabelName*  tags;
121 
122     DTextLabelValue* labelFile;
123     DTextLabelValue* labelFolder;
124     DTextLabelValue* labelFileModifiedDate;
125     DTextLabelValue* labelFileSize;
126     DTextLabelValue* labelFileOwner;
127     DTextLabelValue* labelFilePermissions;
128 
129     DTextLabelValue* labelImageMime;
130     DTextLabelValue* labelImageDimensions;
131     DTextLabelValue* labelImageRatio;
132     DTextLabelValue* labelImageBitDepth;
133     DTextLabelValue* labelImageColorMode;
134     DTextLabelValue* labelHasSidecar;
135 
136     DTextLabelValue* labelPhotoMake;
137     DTextLabelValue* labelPhotoModel;
138     DTextLabelValue* labelPhotoDateTime;
139     DTextLabelValue* labelPhotoLens;
140     DTextLabelValue* labelPhotoAperture;
141     DTextLabelValue* labelPhotoFocalLength;
142     DTextLabelValue* labelPhotoExposureTime;
143     DTextLabelValue* labelPhotoSensitivity;
144     DTextLabelValue* labelPhotoExposureMode;
145     DTextLabelValue* labelPhotoFlash;
146     DTextLabelValue* labelPhotoWhiteBalance;
147 
148     DTextLabelValue* labelCaption;
149     DTextLabelValue* labelTags;
150     DTextLabelValue* labelPickLabel;
151     DTextLabelValue* labelColorLabel;
152     DTextLabelValue* labelRating;
153 
154     DTextLabelValue* labelVideoAspectRatio;
155     DTextLabelValue* labelVideoDuration;
156     DTextLabelValue* labelVideoFrameRate;
157     DTextLabelValue* labelVideoVideoCodec;
158     DTextLabelValue* labelVideoAudioBitRate;
159     DTextLabelValue* labelVideoAudioChannelType;
160     DTextLabelValue* labelVideoAudioCodec;
161 };
162 
ItemPropertiesTab(QWidget * const parent)163 ItemPropertiesTab::ItemPropertiesTab(QWidget* const parent)
164     : DExpanderBox(parent),
165       d           (new Private)
166 {
167     setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
168     setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
169 
170     // --------------------------------------------------
171 
172     const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
173 
174     QWidget* const w1                  = new QWidget(this);
175     QGridLayout* const glay1           = new QGridLayout(w1);
176 
177     DTextLabelName* const file         = new DTextLabelName(i18nc("@label: item properties", "File: "),        w1);
178     DTextLabelName* const folder       = new DTextLabelName(i18nc("@label: item properties", "Folder: "),      w1);
179     DTextLabelName* const modifiedDate = new DTextLabelName(i18nc("@label: item properties", "Date: "),        w1);
180     DTextLabelName* const size         = new DTextLabelName(i18nc("@label: item properties", "Size: "),        w1);
181     DTextLabelName* const owner        = new DTextLabelName(i18nc("@label: item properties", "Owner: "),       w1);
182     DTextLabelName* const permissions  = new DTextLabelName(i18nc("@label: item properties", "Permissions: "), w1);
183 
184     d->labelFile                       = new DTextLabelValue(QString(), w1);
185     d->labelFolder                     = new DTextLabelValue(QString(), w1);
186     d->labelFileModifiedDate           = new DTextLabelValue(QString(), w1);
187     d->labelFileSize                   = new DTextLabelValue(QString(), w1);
188     d->labelFileOwner                  = new DTextLabelValue(QString(), w1);
189     d->labelFilePermissions            = new DTextLabelValue(QString(), w1);
190 
191     glay1->addWidget(file,                     0, 0, 1, 1);
192     glay1->addWidget(d->labelFile,             0, 1, 1, 1);
193     glay1->addWidget(folder,                   1, 0, 1, 1);
194     glay1->addWidget(d->labelFolder,           1, 1, 1, 1);
195     glay1->addWidget(modifiedDate,             2, 0, 1, 1);
196     glay1->addWidget(d->labelFileModifiedDate, 2, 1, 1, 1);
197     glay1->addWidget(size,                     3, 0, 1, 1);
198     glay1->addWidget(d->labelFileSize,         3, 1, 1, 1);
199     glay1->addWidget(owner,                    4, 0, 1, 1);
200     glay1->addWidget(d->labelFileOwner,        4, 1, 1, 1);
201     glay1->addWidget(permissions,              5, 0, 1, 1);
202     glay1->addWidget(d->labelFilePermissions,  5, 1, 1, 1);
203     glay1->setContentsMargins(spacing, spacing, spacing, spacing);
204     glay1->setColumnStretch(0, 10);
205     glay1->setColumnStretch(1, 25);
206     glay1->setSpacing(0);
207 
208     insertItem(ItemPropertiesTab::Private::FileProperties,
209                w1, QIcon::fromTheme(QLatin1String("dialog-information")),
210                i18nc("@title: item properties", "File Properties"), QLatin1String("FileProperties"), true);
211 
212     // --------------------------------------------------
213 
214     QWidget* const w2                = new QWidget(this);
215     QGridLayout* const glay2         = new QGridLayout(w2);
216 
217     DTextLabelName* const mime       = new DTextLabelName(i18nc("@label: item properties", "Type: "),         w2);
218     DTextLabelName* const dimensions = new DTextLabelName(i18nc("@label: item properties", "Dimensions: "),   w2);
219     DTextLabelName* const ratio      = new DTextLabelName(i18nc("@label: item properties", "Aspect Ratio: "), w2);
220     DTextLabelName* const bitDepth   = new DTextLabelName(i18nc("@label: item properties", "Bit depth: "),    w2);
221     DTextLabelName* const colorMode  = new DTextLabelName(i18nc("@label: item properties", "Color mode: "),   w2);
222     DTextLabelName* const hasSidecar = new DTextLabelName(i18nc("@label: item properties", "Sidecar: "),      w2);
223 
224     d->labelImageMime                = new DTextLabelValue(QString(), w2);
225     d->labelImageDimensions          = new DTextLabelValue(QString(), w2);
226     d->labelImageRatio               = new DTextLabelValue(QString(), w2);
227     d->labelImageBitDepth            = new DTextLabelValue(QString(), w2);
228     d->labelImageColorMode           = new DTextLabelValue(QString(), w2);
229     d->labelHasSidecar               = new DTextLabelValue(QString(), w2);
230 
231     glay2->addWidget(mime,                    0, 0, 1, 1);
232     glay2->addWidget(d->labelImageMime,       0, 1, 1, 1);
233     glay2->addWidget(dimensions,              1, 0, 1, 1);
234     glay2->addWidget(d->labelImageDimensions, 1, 1, 1, 1);
235     glay2->addWidget(ratio,                   2, 0, 1, 1);
236     glay2->addWidget(d->labelImageRatio,      2, 1, 1, 1);
237     glay2->addWidget(bitDepth,                3, 0, 1, 1);
238     glay2->addWidget(d->labelImageBitDepth,   3, 1, 1, 1);
239     glay2->addWidget(colorMode,               4, 0, 1, 1);
240     glay2->addWidget(d->labelImageColorMode,  4, 1, 1, 1);
241     glay2->addWidget(hasSidecar,              5, 0, 1, 1);
242     glay2->addWidget(d->labelHasSidecar,      5, 1, 1, 1);
243     glay2->setContentsMargins(spacing, spacing, spacing, spacing);
244     glay2->setColumnStretch(0, 10);
245     glay2->setColumnStretch(1, 25);
246     glay2->setSpacing(0);
247 
248     insertItem(ItemPropertiesTab::Private::ImageProperties,
249                w2, QIcon::fromTheme(QLatin1String("view-preview")),
250                i18nc("@title: item properties", "Item Properties"), QLatin1String("ItemProperties"), true);
251 
252     // --------------------------------------------------
253 
254     QWidget* const w3                  = new QWidget(this);
255     QGridLayout* const glay3           = new QGridLayout(w3);
256 
257     DTextLabelName* const make         = new DTextLabelName(i18nc("@label: item properties", "Make: "),          w3);
258     DTextLabelName* const model        = new DTextLabelName(i18nc("@label: item properties", "Model: "),         w3);
259     DTextLabelName* const photoDate    = new DTextLabelName(i18nc("@label: item properties", "Created: "),       w3);
260     DTextLabelName* const lens         = new DTextLabelName(i18nc("@label: item properties", "Lens: "),          w3);
261     DTextLabelName* const aperture     = new DTextLabelName(i18nc("@label: item properties", "Aperture: "),      w3);
262     DTextLabelName* const focalLength  = new DTextLabelName(i18nc("@label: item properties", "Focal: "),         w3);
263     DTextLabelName* const exposureTime = new DTextLabelName(i18nc("@label: item properties", "Exposure: "),      w3);
264     DTextLabelName* const sensitivity  = new DTextLabelName(i18nc("@label: item properties", "Sensitivity: "),   w3);
265     DTextLabelName* const exposureMode = new DTextLabelName(i18nc("@label: item properties", "Mode/Program: "),  w3);
266     DTextLabelName* const flash        = new DTextLabelName(i18nc("@label: item properties", "Flash: "),         w3);
267     DTextLabelName* const whiteBalance = new DTextLabelName(i18nc("@label: item properties", "White balance: "), w3);
268 
269     d->labelPhotoMake                  = new DTextLabelValue(QString(), w3);
270     d->labelPhotoModel                 = new DTextLabelValue(QString(), w3);
271     d->labelPhotoDateTime              = new DTextLabelValue(QString(), w3);
272     d->labelPhotoLens                  = new DTextLabelValue(QString(), w3);
273     d->labelPhotoAperture              = new DTextLabelValue(QString(), w3);
274     d->labelPhotoFocalLength           = new DTextLabelValue(QString(), w3);
275     d->labelPhotoExposureTime          = new DTextLabelValue(QString(), w3);
276     d->labelPhotoSensitivity           = new DTextLabelValue(QString(), w3);
277     d->labelPhotoExposureMode          = new DTextLabelValue(QString(), w3);
278     d->labelPhotoFlash                 = new DTextLabelValue(QString(), w3);
279     d->labelPhotoWhiteBalance          = new DTextLabelValue(QString(), w3);
280 
281     glay3->addWidget(make,                      0,  0, 1, 1);
282     glay3->addWidget(d->labelPhotoMake,         0,  1, 1, 1);
283     glay3->addWidget(model,                     1,  0, 1, 1);
284     glay3->addWidget(d->labelPhotoModel,        1,  1, 1, 1);
285     glay3->addWidget(photoDate,                 2,  0, 1, 1);
286     glay3->addWidget(d->labelPhotoDateTime,     2,  1, 1, 1);
287     glay3->addWidget(lens,                      3,  0, 1, 1);
288     glay3->addWidget(d->labelPhotoLens,         3,  1, 1, 1);
289     glay3->addWidget(aperture,                  4,  0, 1, 1);
290     glay3->addWidget(d->labelPhotoAperture,     4,  1, 1, 1);
291     glay3->addWidget(focalLength,               5,  0, 1, 1);
292     glay3->addWidget(d->labelPhotoFocalLength,  5,  1, 1, 1);
293     glay3->addWidget(exposureTime,              6,  0, 1, 1);
294     glay3->addWidget(d->labelPhotoExposureTime, 6,  1, 1, 1);
295     glay3->addWidget(sensitivity,               7,  0, 1, 1);
296     glay3->addWidget(d->labelPhotoSensitivity,  7,  1, 1, 1);
297     glay3->addWidget(exposureMode,              8,  0, 1, 1);
298     glay3->addWidget(d->labelPhotoExposureMode, 8,  1, 1, 1);
299     glay3->addWidget(flash,                     9,  0, 1, 1);
300     glay3->addWidget(d->labelPhotoFlash,        9,  1, 1, 1);
301     glay3->addWidget(whiteBalance,              10, 0, 1, 1);
302     glay3->addWidget(d->labelPhotoWhiteBalance, 10, 1, 1, 1);
303     glay3->setContentsMargins(spacing, spacing, spacing, spacing);
304     glay3->setColumnStretch(0, 10);
305     glay3->setColumnStretch(1, 25);
306     glay3->setSpacing(0);
307 
308     insertItem(ItemPropertiesTab::Private::PhotoProperties,
309                w3, QIcon::fromTheme(QLatin1String("camera-photo")),
310                i18nc("@title: item properties", "Photograph Properties"), QLatin1String("PhotographProperties"), true);
311 
312     // --------------------------------------------------
313 
314     QWidget* const w4                      = new QWidget(this);
315     QGridLayout* const glay4               = new QGridLayout(w4);
316 
317     DTextLabelName* const aspectRatio      = new DTextLabelName(i18nc("@label: item properties", "Aspect Ratio: "),       w4);
318     DTextLabelName* const duration         = new DTextLabelName(i18nc("@label: item properties", "Duration: "),           w4);
319     DTextLabelName* const frameRate        = new DTextLabelName(i18nc("@label: item properties", "Frame Rate: "),         w4);
320     DTextLabelName* const videoCodec       = new DTextLabelName(i18nc("@label: item properties", "Video Codec: "),        w4);
321     DTextLabelName* const audioBitRate     = new DTextLabelName(i18nc("@label: item properties", "Audio Bit Rate: "),     w4);
322     DTextLabelName* const audioChannelType = new DTextLabelName(i18nc("@label: item properties", "Audio Channel Type: "), w4);
323     DTextLabelName* const audioCodec       = new DTextLabelName(i18nc("@label: item properties", "Audio Codec: "),        w4);
324 
325     d->labelVideoAspectRatio               = new DTextLabelValue(QString(), w4);
326     d->labelVideoDuration                  = new DTextLabelValue(QString(), w4);
327     d->labelVideoFrameRate                 = new DTextLabelValue(QString(), w4);
328     d->labelVideoVideoCodec                = new DTextLabelValue(QString(), w4);
329     d->labelVideoAudioBitRate              = new DTextLabelValue(QString(), w4);
330     d->labelVideoAudioChannelType          = new DTextLabelValue(QString(), w4);
331     d->labelVideoAudioCodec                = new DTextLabelValue(QString(), w4);
332 
333     glay4->addWidget(aspectRatio,                   0, 0, 1, 1);
334     glay4->addWidget(d->labelVideoAspectRatio,      0, 1, 1, 1);
335     glay4->addWidget(duration,                      1, 0, 1, 1);
336     glay4->addWidget(d->labelVideoDuration,         1, 1, 1, 1);
337     glay4->addWidget(frameRate,                     2, 0, 1, 1);
338     glay4->addWidget(d->labelVideoFrameRate,        2, 1, 1, 1);
339     glay4->addWidget(videoCodec,                    3, 0, 1, 1);
340     glay4->addWidget(d->labelVideoVideoCodec,       3, 1, 1, 1);
341     glay4->addWidget(audioBitRate,                  4, 0, 1, 1);
342     glay4->addWidget(d->labelVideoAudioBitRate,     4, 1, 1, 1);
343     glay4->addWidget(audioChannelType,              5, 0, 1, 1);
344     glay4->addWidget(d->labelVideoAudioChannelType, 5, 1, 1, 1);
345     glay4->addWidget(audioCodec,                    6, 0, 1, 1);
346     glay4->addWidget(d->labelVideoAudioCodec,       6, 1, 1, 1);
347     glay4->setContentsMargins(spacing, spacing, spacing, spacing);
348     glay4->setColumnStretch(0, 10);
349     glay4->setColumnStretch(1, 25);
350     glay4->setSpacing(0);
351 
352     insertItem(ItemPropertiesTab::Private::VideoProperties,
353                w4, QIcon::fromTheme(QLatin1String("video-x-generic")),
354                i18nc("@title: item properties", "Audio/Video Properties"), QLatin1String("VideoProperties"), true);
355 
356     // --------------------------------------------------
357 
358     QWidget* const w5        = new QWidget(this);
359     QGridLayout* const glay5 = new QGridLayout(w5);
360 
361     d->caption               = new DTextLabelName(i18nc("@label: item properties", "Caption: "),     w5);
362     d->pickLabel             = new DTextLabelName(i18nc("@label: item properties", "Pick label: "),  w5);
363     d->colorLabel            = new DTextLabelName(i18nc("@label: item properties", "Color label: "), w5);
364     d->rating                = new DTextLabelName(i18nc("@label: item properties", "Rating: "),      w5);
365     d->tags                  = new DTextLabelName(i18nc("@label: item properties", "Tags: "),        w5);
366 
367     d->labelCaption          = new DTextLabelValue(QString(), w5);
368     d->labelPickLabel        = new DTextLabelValue(QString(), w5);
369     d->labelColorLabel       = new DTextLabelValue(QString(), w5);
370     d->labelRating           = new DTextLabelValue(QString(), w5);
371     d->labelTags             = new DTextLabelValue(QString(), w5);
372     d->labelTags->setElideMode(Qt::ElideLeft);
373 
374     glay5->addWidget(d->caption,         0, 0, 1, 1);
375     glay5->addWidget(d->labelCaption,    0, 1, 1, 1);
376     glay5->addWidget(d->tags,            1, 0, 1, 1);
377     glay5->addWidget(d->labelTags,       1, 1, 1, 1);
378     glay5->addWidget(d->pickLabel,       2, 0, 1, 1);
379     glay5->addWidget(d->labelPickLabel,  2, 1, 1, 1);
380     glay5->addWidget(d->colorLabel,      3, 0, 1, 1);
381     glay5->addWidget(d->labelColorLabel, 3, 1, 1, 1);
382     glay5->addWidget(d->rating,          4, 0, 1, 1);
383     glay5->addWidget(d->labelRating,     4, 1, 1, 1);
384     glay5->setContentsMargins(spacing, spacing, spacing, spacing);
385     glay5->setColumnStretch(0, 10);
386     glay5->setColumnStretch(1, 25);
387     glay5->setSpacing(0);
388 
389     insertItem(ItemPropertiesTab::Private::digiKamProperties,
390                w5, QIcon::fromTheme(QLatin1String("edit-text-frame-update")),
391                i18nc("@title: item properties", "digiKam Properties"), QLatin1String("DigikamProperties"), true);
392 
393     // --------------------------------------------------
394 
395     addStretch();
396 }
397 
~ItemPropertiesTab()398 ItemPropertiesTab::~ItemPropertiesTab()
399 {
400     delete d;
401 }
402 
setCurrentURL(const QUrl & url)403 void ItemPropertiesTab::setCurrentURL(const QUrl& url)
404 {
405     if (url.isEmpty())
406     {
407         d->labelFile->setAdjustedText();
408         d->labelFolder->setAdjustedText();
409         d->labelFileModifiedDate->setAdjustedText();
410         d->labelFileSize->setAdjustedText();
411         d->labelFileOwner->setAdjustedText();
412         d->labelFilePermissions->setAdjustedText();
413 
414         d->labelImageMime->setAdjustedText();
415         d->labelImageDimensions->setAdjustedText();
416         d->labelImageRatio->setAdjustedText();
417         d->labelImageBitDepth->setAdjustedText();
418         d->labelImageColorMode->setAdjustedText();
419         d->labelHasSidecar->setAdjustedText();
420 
421         d->labelPhotoMake->setAdjustedText();
422         d->labelPhotoModel->setAdjustedText();
423         d->labelPhotoDateTime->setAdjustedText();
424         d->labelPhotoLens->setAdjustedText();
425         d->labelPhotoAperture->setAdjustedText();
426         d->labelPhotoFocalLength->setAdjustedText();
427         d->labelPhotoExposureTime->setAdjustedText();
428         d->labelPhotoSensitivity->setAdjustedText();
429         d->labelPhotoExposureMode->setAdjustedText();
430         d->labelPhotoFlash->setAdjustedText();
431         d->labelPhotoWhiteBalance->setAdjustedText();
432 
433         d->labelCaption->setAdjustedText();
434         d->labelPickLabel->setAdjustedText();
435         d->labelColorLabel->setAdjustedText();
436         d->labelRating->setAdjustedText();
437         d->labelTags->setAdjustedText();
438 
439         d->labelVideoAspectRatio->setAdjustedText();
440         d->labelVideoDuration->setAdjustedText();
441         d->labelVideoFrameRate->setAdjustedText();
442         d->labelVideoVideoCodec->setAdjustedText();
443         d->labelVideoAudioBitRate->setAdjustedText();
444         d->labelVideoAudioChannelType->setAdjustedText();
445         d->labelVideoAudioCodec->setAdjustedText();
446 
447         setEnabled(false);
448         return;
449     }
450 
451     setEnabled(true);
452 
453     d->labelFile->setAdjustedText(url.fileName());
454     d->labelFolder->setAdjustedText(QDir::toNativeSeparators(url.adjusted(QUrl::RemoveFilename |
455                                                                           QUrl::StripTrailingSlash).toLocalFile()));
456 }
457 
setPhotoInfoDisable(const bool b)458 void ItemPropertiesTab::setPhotoInfoDisable(const bool b)
459 {
460     if (b)
461     {
462         widget(ItemPropertiesTab::Private::PhotoProperties)->hide();
463     }
464     else
465     {
466         widget(ItemPropertiesTab::Private::PhotoProperties)->show();
467     }
468 }
469 
setVideoInfoDisable(const bool b)470 void ItemPropertiesTab::setVideoInfoDisable(const bool b)
471 {
472     if (b)
473     {
474         widget(ItemPropertiesTab::Private::VideoProperties)->hide();
475     }
476     else
477     {
478         widget(ItemPropertiesTab::Private::VideoProperties)->show();
479     }
480 }
481 
setFileModifiedDate(const QString & str)482 void ItemPropertiesTab::setFileModifiedDate(const QString& str)
483 {
484     d->labelFileModifiedDate->setAdjustedText(str);
485 }
486 
setFileSize(const QString & str)487 void ItemPropertiesTab::setFileSize(const QString& str)
488 {
489     d->labelFileSize->setAdjustedText(str);
490 }
491 
setFileOwner(const QString & str)492 void ItemPropertiesTab::setFileOwner(const QString& str)
493 {
494     d->labelFileOwner->setAdjustedText(str);
495 }
496 
setFilePermissions(const QString & str)497 void ItemPropertiesTab::setFilePermissions(const QString& str)
498 {
499     d->labelFilePermissions->setAdjustedText(str);
500 }
501 
setImageMime(const QString & str)502 void ItemPropertiesTab::setImageMime(const QString& str)
503 {
504     d->labelImageMime->setAdjustedText(str);
505 }
506 
setItemDimensions(const QString & str)507 void ItemPropertiesTab::setItemDimensions(const QString& str)
508 {
509     d->labelImageDimensions->setAdjustedText(str);
510 }
511 
setImageRatio(const QString & str)512 void ItemPropertiesTab::setImageRatio(const QString& str)
513 {
514     d->labelImageRatio->setAdjustedText(str);
515 }
516 
setImageBitDepth(const QString & str)517 void ItemPropertiesTab::setImageBitDepth(const QString& str)
518 {
519     d->labelImageBitDepth->setAdjustedText(str);
520 }
521 
setImageColorMode(const QString & str)522 void ItemPropertiesTab::setImageColorMode(const QString& str)
523 {
524     d->labelImageColorMode->setAdjustedText(str);
525 }
526 
setHasSidecar(const QString & str)527 void ItemPropertiesTab::setHasSidecar(const QString& str)
528 {
529     d->labelHasSidecar->setAdjustedText(str);
530 }
531 
setPhotoMake(const QString & str)532 void ItemPropertiesTab::setPhotoMake(const QString& str)
533 {
534     d->labelPhotoMake->setAdjustedText(str);
535 }
536 
setPhotoModel(const QString & str)537 void ItemPropertiesTab::setPhotoModel(const QString& str)
538 {
539     d->labelPhotoModel->setAdjustedText(str);
540 }
541 
setPhotoDateTime(const QString & str)542 void ItemPropertiesTab::setPhotoDateTime(const QString& str)
543 {
544     d->labelPhotoDateTime->setAdjustedText(str);
545 }
546 
setPhotoLens(const QString & str)547 void ItemPropertiesTab::setPhotoLens(const QString& str)
548 {
549     d->labelPhotoLens->setAdjustedText(str);
550 }
551 
setPhotoAperture(const QString & str)552 void ItemPropertiesTab::setPhotoAperture(const QString& str)
553 {
554     d->labelPhotoAperture->setAdjustedText(str);
555 }
556 
setPhotoFocalLength(const QString & str)557 void ItemPropertiesTab::setPhotoFocalLength(const QString& str)
558 {
559     d->labelPhotoFocalLength->setAdjustedText(str);
560 }
561 
setPhotoExposureTime(const QString & str)562 void ItemPropertiesTab::setPhotoExposureTime(const QString& str)
563 {
564     d->labelPhotoExposureTime->setAdjustedText(str);
565 }
566 
setPhotoSensitivity(const QString & str)567 void ItemPropertiesTab::setPhotoSensitivity(const QString& str)
568 {
569     d->labelPhotoSensitivity->setAdjustedText(str);
570 }
571 
setPhotoExposureMode(const QString & str)572 void ItemPropertiesTab::setPhotoExposureMode(const QString& str)
573 {
574     d->labelPhotoExposureMode->setAdjustedText(str);
575 }
576 
setPhotoFlash(const QString & str)577 void ItemPropertiesTab::setPhotoFlash(const QString& str)
578 {
579     d->labelPhotoFlash->setAdjustedText(str);
580 }
581 
setPhotoWhiteBalance(const QString & str)582 void ItemPropertiesTab::setPhotoWhiteBalance(const QString& str)
583 {
584     d->labelPhotoWhiteBalance->setAdjustedText(str);
585 }
586 
showOrHideCaptionAndTags()587 void ItemPropertiesTab::showOrHideCaptionAndTags()
588 {
589     bool hasCaption    = !d->labelCaption->adjustedText().isEmpty();
590     bool hasPickLabel  = !d->labelPickLabel->adjustedText().isEmpty();
591     bool hasColorLabel = !d->labelColorLabel->adjustedText().isEmpty();
592     bool hasRating     = !d->labelRating->adjustedText().isEmpty();
593     bool hasTags       = !d->labelTags->adjustedText().isEmpty();
594 
595     d->caption->setVisible(hasCaption);
596     d->labelCaption->setVisible(hasCaption);
597     d->pickLabel->setVisible(hasPickLabel);
598     d->labelPickLabel->setVisible(hasPickLabel);
599     d->colorLabel->setVisible(hasColorLabel);
600     d->labelColorLabel->setVisible(hasColorLabel);
601     d->rating->setVisible(hasRating);
602     d->labelRating->setVisible(hasRating);
603     d->tags->setVisible(hasTags);
604     d->labelTags->setVisible(hasTags);
605 
606     widget(ItemPropertiesTab::Private::digiKamProperties)->setVisible(hasCaption   ||
607                                                                       hasRating    ||
608                                                                       hasTags      ||
609                                                                       hasPickLabel ||
610                                                                       hasColorLabel);
611 }
612 
setCaption(const QString & str)613 void ItemPropertiesTab::setCaption(const QString& str)
614 {
615     d->labelCaption->setAdjustedText(str);
616 }
617 
setColorLabel(int colorId)618 void ItemPropertiesTab::setColorLabel(int colorId)
619 {
620     if (colorId == NoColorLabel)
621     {
622         d->labelColorLabel->setAdjustedText(QString());
623     }
624     else
625     {
626         d->labelColorLabel->setAdjustedText(ColorLabelWidget::labelColorName((ColorLabel)colorId));
627     }
628 }
629 
setPickLabel(int pickId)630 void ItemPropertiesTab::setPickLabel(int pickId)
631 {
632     if (pickId == NoPickLabel)
633     {
634         d->labelPickLabel->setAdjustedText(QString());
635     }
636     else
637     {
638         d->labelPickLabel->setAdjustedText(PickLabelWidget::labelPickName((PickLabel)pickId));
639     }
640 }
641 
setRating(int rating)642 void ItemPropertiesTab::setRating(int rating)
643 {
644     QString str;
645 
646     if ((rating > RatingMin) && (rating <= RatingMax))
647     {
648         str = QLatin1Char(' ');
649 
650         for (int i = 0 ; i < rating ; ++i)
651         {
652             str += QChar(0x2730);
653             str += QLatin1Char(' ');
654         }
655     }
656 
657     d->labelRating->setAdjustedText(str);
658 }
659 
setVideoAspectRatio(const QString & str)660 void ItemPropertiesTab::setVideoAspectRatio(const QString& str)
661 {
662     d->labelVideoAspectRatio->setAdjustedText(str);
663 }
664 
setVideoAudioBitRate(const QString & str)665 void ItemPropertiesTab::setVideoAudioBitRate(const QString& str)
666 {
667     // use string given as parameter by default because it contains the value for "unavailable" if needed
668 
669     QString audioBitRateString = str;
670     bool ok                    = false;
671     const int audioBitRateInt  = str.toInt(&ok);
672 
673     if (ok)
674     {
675         audioBitRateString = QLocale().toString(audioBitRateInt);
676     }
677 
678     d->labelVideoAudioBitRate->setAdjustedText(audioBitRateString);
679 }
680 
setVideoAudioChannelType(const QString & str)681 void ItemPropertiesTab::setVideoAudioChannelType(const QString& str)
682 {
683     d->labelVideoAudioChannelType->setAdjustedText(str);
684 }
685 
setVideoAudioCodec(const QString & str)686 void ItemPropertiesTab::setVideoAudioCodec(const QString& str)
687 {
688     d->labelVideoAudioCodec->setAdjustedText(str);
689 }
690 
setVideoDuration(const QString & str)691 void ItemPropertiesTab::setVideoDuration(const QString& str)
692 {
693     // duration is given as a string in milliseconds
694     // use string given as parameter by default because it contains the value for "unavailable" if needed
695 
696     QString durationString = str;
697     bool ok                = false;
698     const int durationVal  = str.toInt(&ok);
699 
700     if (ok)
701     {
702         unsigned int r, d, h, m, s, f;
703         r = qAbs(durationVal);
704         d = r / 86400000;
705         r = r % 86400000;
706         h = r / 3600000;
707         r = r % 3600000;
708         m = r / 60000;
709         r = r % 60000;
710         s = r / 1000;
711         f = r % 1000;
712 
713         durationString = QString().asprintf("%d.%02d:%02d:%02d.%03d", d, h, m, s, f);
714     }
715 
716     d->labelVideoDuration->setAdjustedText(durationString);
717 }
718 
setVideoFrameRate(const QString & str)719 void ItemPropertiesTab::setVideoFrameRate(const QString& str)
720 {
721     // use string given as parameter by default because it contains the value for "unavailable" if needed
722 
723     QString frameRateString      = str;
724     bool ok;
725     const double frameRateDouble = str.toDouble(&ok);
726 
727     if (ok)
728     {
729         frameRateString = QLocale().toString(frameRateDouble) + i18nc("@info: item properties", " fps");
730     }
731 
732     d->labelVideoFrameRate->setAdjustedText(frameRateString);
733 }
734 
setVideoVideoCodec(const QString & str)735 void ItemPropertiesTab::setVideoVideoCodec(const QString& str)
736 {
737     d->labelVideoVideoCodec->setAdjustedText(str);
738 }
739 
setTags(const QStringList & tagPaths,const QStringList & tagNames)740 void ItemPropertiesTab::setTags(const QStringList& tagPaths, const QStringList& tagNames)
741 {
742     Q_UNUSED(tagNames);
743     d->labelTags->setAdjustedText(shortenedTagPaths(tagPaths).join(QLatin1Char('\n')));
744 }
745 
746 typedef QPair<QString, QVariant> PathValuePair;
747 
naturalLessThan(const PathValuePair & a,const PathValuePair & b)748 static bool naturalLessThan(const PathValuePair& a, const PathValuePair& b)
749 {
750     return (QCollator().compare(a.first, b.first) < 0);
751 }
752 
shortenedTagPaths(const QStringList & tagPaths,QList<QVariant> * identifiers)753 QStringList ItemPropertiesTab::shortenedTagPaths(const QStringList& tagPaths, QList<QVariant>* identifiers)
754 {
755     QList<PathValuePair> tagsSorted;
756 
757     if (identifiers)
758     {
759         for (int i = 0 ; i < tagPaths.size() ; ++i)
760         {
761             tagsSorted << PathValuePair(tagPaths.at(i), (*identifiers).at(i));
762         }
763     }
764     else
765     {
766         for (int i = 0 ; i < tagPaths.size() ; ++i)
767         {
768             tagsSorted << PathValuePair(tagPaths.at(i), QVariant());
769         }
770     }
771 
772     std::stable_sort(tagsSorted.begin(), tagsSorted.end(), naturalLessThan);
773 
774     if (identifiers)
775     {
776         identifiers->clear();
777     }
778 
779     QStringList tagsShortened;
780     QString previous;
781 
782     foreach (const PathValuePair& pair, tagsSorted)
783     {
784         const QString& tagPath   = pair.first;
785         QString shortenedPath    = tagPath;
786         QStringList currentPath  = tagPath.split(QLatin1Char('/'), QString::SkipEmptyParts);
787         QStringList previousPath = previous.split(QLatin1Char('/'), QString::SkipEmptyParts);
788         int depth;
789 
790         for (depth = 0 ; (depth < currentPath.size()) && (depth < previousPath.size()) ; ++depth)
791         {
792             if (currentPath.at(depth) != previousPath.at(depth))
793             {
794                 break;
795             }
796         }
797 
798         if (depth)
799         {
800             QString indent;
801             indent.fill(QLatin1Char(' '), qMin(depth, 5));
802 /*
803             indent += QChar(0x2026);
804 */
805             shortenedPath = indent + tagPath.section(QLatin1Char('/'), depth);
806         }
807 
808         shortenedPath.replace(QLatin1Char('/'), QLatin1String(" / "));
809         tagsShortened << shortenedPath;
810         previous = tagPath;
811 
812         if (identifiers)
813         {
814             (*identifiers) << pair.second;
815         }
816     }
817 
818     return tagsShortened;
819 }
820 
shortenedMakeInfo(QString & make)821 void ItemPropertiesTab::shortenedMakeInfo(QString& make)
822 {
823     make.remove(QLatin1String(" CORPORATION"),       Qt::CaseInsensitive);        // from Nikon, Pentax, and Olympus
824     make.remove(QLatin1String("EASTMAN "),           Qt::CaseInsensitive);        // from Kodak
825     make.remove(QLatin1String(" COMPANY"),           Qt::CaseInsensitive);        // from Kodak
826     make.remove(QLatin1String(" OPTICAL CO.,LTD"),   Qt::CaseInsensitive);        // from Olympus
827     make.remove(QLatin1String(" IMAGING CORP."),     Qt::CaseInsensitive);        // from Olympus
828     make.remove(QLatin1String(" Techwin co.,Ltd."),  Qt::CaseInsensitive);        // from Samsung
829     make.remove(QLatin1String("  Co.,Ltd."),         Qt::CaseInsensitive);        // from Minolta
830     make.remove(QLatin1String(" Electric Co.,Ltd."), Qt::CaseInsensitive);        // from Sanyo
831     make.remove(QLatin1String(" Electric Co.,Ltd"),  Qt::CaseInsensitive);        // from Sanyo
832 }
833 
shortenedModelInfo(QString & model)834 void ItemPropertiesTab::shortenedModelInfo(QString& model)
835 {
836     model.remove(QLatin1String("Canon "),           Qt::CaseInsensitive);
837     model.remove(QLatin1String("NIKON "),           Qt::CaseInsensitive);
838     model.remove(QLatin1String("PENTAX "),          Qt::CaseInsensitive);
839     model.remove(QLatin1String(" DIGITAL"),         Qt::CaseInsensitive);        // from Canon
840     model.remove(QLatin1String("KODAK "),           Qt::CaseInsensitive);
841     model.remove(QLatin1String(" CAMERA"),          Qt::CaseInsensitive);        // from Kodak
842 }
843 
844 /**
845  * Find rational approximation to given real number
846  *
847  *   val    : double value to convert as humain readable fraction
848  *   num    : fraction numerator
849  *   den    : fraction denominator
850  *   maxden : the maximum denominator allowed
851  *
852  * This function return approximation error of the fraction
853  *
854  * Based on the theory of continued fractions
855  * if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...)))
856  * Then best approximation is found by truncating this series
857  * wwith some adjustments in the last term.
858  *
859  * Note the fraction can be recovered as the first column of the matrix
860  *  ( a1 1 ) ( a2 1 ) ( a3 1 ) ...
861  *  ( 1  0 ) ( 1  0 ) ( 1  0 )
862  * Instead of keeping the sequence of continued fraction terms,
863  * we just keep the last partial product of these matrices.
864  *
865  * Details: stackoverflow.com/questions/95727/how-to-convert-floats-to-human-readable-fractions
866  *
867  */
doubleToHumanReadableFraction(double val,long * num,long * den,long maxden)868 double ItemPropertiesTab::doubleToHumanReadableFraction(double val, long* num, long* den, long maxden)
869 {
870     double x = val;
871     long   m[2][2];
872     long   ai;
873 
874     // Initialize matrix
875 
876     m[0][0] = m[1][1] = 1;
877     m[0][1] = m[1][0] = 0;
878 
879     // Loop finding terms until denominator gets too big
880 
881     while (m[1][0] * (ai = (long)x) + m[1][1] <= maxden)
882     {
883         long t  = m[0][0] * ai + m[0][1];
884         m[0][1] = m[0][0];
885         m[0][0] = t;
886         t       = m[1][0] * ai + m[1][1];
887         m[1][1] = m[1][0];
888         m[1][0] = t;
889 
890         if (x == (double)ai)
891         {
892             break;     // division by zero
893         }
894 
895         x       = 1 / (x - (double)ai);
896 
897         if (x > (double)0x7FFFFFFF)
898         {
899             break;     // representation failure
900         }
901     }
902 
903     // Now remaining x is between 0 and 1/ai
904     // Approx as either 0 or 1/m where m is max that will fit in maxden
905 
906     *num = m[0][0];
907     *den = m[1][0];
908 
909     // Return approximation error
910 
911     return (val - ((double)m[0][0] / (double)m[1][0]));
912 }
913 
aspectRatioToString(int width,int height,QString & arString)914 bool ItemPropertiesTab::aspectRatioToString(int width, int height, QString& arString)
915 {
916     if ((width == 0) || (height == 0))
917     {
918         return false;
919     }
920 
921     double ratio  = (double)qMax(width, height) / (double)qMin(width, height);
922     long   num    = 0;
923     long   den    = 0;
924 
925     doubleToHumanReadableFraction(ratio, &num, &den, 10);
926 
927     double aratio = (double)qMax(num, den) / (double)qMin(num, den);
928 
929     arString = i18nc("@info: width : height (Aspect Ratio)", "%1:%2 (%3)",
930                      (width > height) ? num : den,
931                      (width > height) ? den : num,
932                      QLocale().toString(aratio, 'g', 2));
933 
934     return true;
935 }
936 
permissionsString(const QFileInfo & fi)937 QString ItemPropertiesTab::permissionsString(const QFileInfo& fi)
938 {
939     QString str;
940     QFile::Permissions perms = fi.permissions();
941 
942     str.append(fi.isSymLink()                    ? QLatin1String("l") : QLatin1String("-"));
943 
944     str.append((perms & QFileDevice::ReadOwner)  ? QLatin1String("r") : QLatin1String("-"));
945     str.append((perms & QFileDevice::WriteOwner) ? QLatin1String("w") : QLatin1String("-"));
946     str.append((perms & QFileDevice::ExeOwner)   ? QLatin1String("x") : QLatin1String("-"));
947 
948     str.append((perms & QFileDevice::ReadGroup)  ? QLatin1String("r") : QLatin1String("-"));
949     str.append((perms & QFileDevice::WriteGroup) ? QLatin1String("w") : QLatin1String("-"));
950     str.append((perms & QFileDevice::ExeGroup)   ? QLatin1String("x") : QLatin1String("-"));
951 
952     str.append((perms & QFileDevice::ReadOther)  ? QLatin1String("r") : QLatin1String("-"));
953     str.append((perms & QFileDevice::WriteOther) ? QLatin1String("w") : QLatin1String("-"));
954     str.append((perms & QFileDevice::ExeOther)   ? QLatin1String("x") : QLatin1String("-"));
955 
956     return str;
957 }
958 
humanReadableBytesCount(qint64 bytes,bool si)959 QString ItemPropertiesTab::humanReadableBytesCount(qint64 bytes, bool si)
960 {
961     int unit        = si ? 1000 : 1024;
962     QString byteStr = i18nc("@info: unit file size in bytes", "B");
963     QString ret     = QString::number(bytes);
964 
965     if (bytes >= unit)
966     {
967         int exp     = (int)(qLn(bytes) / qLn(unit));
968         QString pre = QString(si ? QLatin1String("kMGTPEZY")
969                                  : QLatin1String("KMGTPEZY")).at(exp-1) + (si ? QLatin1String("")
970                                                                               : QLatin1String("i"));
971         ret         = QString().asprintf("%.1f %s", bytes / qPow(unit, exp), pre.toUtf8().constData());
972     }
973 
974     return (QString::fromUtf8("%1%2").arg(ret).arg(byteStr));
975 }
976 
977 } // namespace Digikam
978