1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2017-05-06
7  * Description : interface to item information for shared tools
8  *               based on DMetadata. This interface is used in all cases
9  *               where no database is available (aka Showfoto).
10  *
11  * Copyright (C) 2017-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
12  * Copyright (C) 2019-2020 by Minh Nghia Duong <minhnghiaduong997 at gmail dot com>
13  *
14  * This program is free software; you can redistribute it
15  * and/or modify it under the terms of the GNU General
16  * Public License as published by the Free Software Foundation;
17  * either version 2, or (at your option)
18  * any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * ============================================================ */
26 
27 #include "dmetainfoiface.h"
28 
29 // Qt includes
30 
31 #include <QFileInfo>
32 #include <QStandardPaths>
33 #include <QScopedPointer>
34 
35 // KDE includes
36 
37 #include <klocalizedstring.h>
38 
39 // Local includes
40 
41 #include "dmetadata.h"
42 #include "photoinfocontainer.h"
43 #include "videoinfocontainer.h"
44 #include "template.h"
45 #include "dfileselector.h"
46 #include "digikam_debug.h"
47 
48 namespace Digikam
49 {
50 
51 class Q_DECL_HIDDEN DMetaInfoIface::Private
52 {
53 public:
54 
Private()55     explicit Private()
56       : dirSelector(nullptr)
57     {
58     }
59 
60     DFileSelector* dirSelector;
61     QList<QUrl>    urls;
62 };
63 
DMetaInfoIface(QObject * const parent,const QList<QUrl> & lst)64 DMetaInfoIface::DMetaInfoIface(QObject* const parent, const QList<QUrl>& lst)
65     : DInfoInterface(parent),
66       d             (new Private)
67 {
68     d->urls = lst;
69 }
70 
~DMetaInfoIface()71 DMetaInfoIface::~DMetaInfoIface()
72 {
73     delete d;
74 }
75 
slotDateTimeForUrl(const QUrl & url,const QDateTime &,bool)76 void DMetaInfoIface::slotDateTimeForUrl(const QUrl& url, const QDateTime& /*dt*/, bool /*updModDate*/)
77 {
78     emit signalItemChanged(url);
79 }
80 
slotMetadataChangedForUrl(const QUrl & url)81 void DMetaInfoIface::slotMetadataChangedForUrl(const QUrl& url)
82 {
83     emit signalItemChanged(url);
84 }
85 
parseAlbumItemsRecursive()86 void DMetaInfoIface::parseAlbumItemsRecursive()
87 {
88     emit signalAlbumItemsRecursiveCompleted(d->urls);
89 }
90 
currentAlbumItems() const91 QList<QUrl> DMetaInfoIface::currentAlbumItems() const
92 {
93     return d->urls;
94 }
95 
currentSelectedItems() const96 QList<QUrl> DMetaInfoIface::currentSelectedItems() const
97 {
98     // No multiple items selection is available in this interface.
99 
100     return currentAlbumItems();
101 }
102 
allAlbumItems() const103 QList<QUrl> DMetaInfoIface::allAlbumItems() const
104 {
105     // No album management is available in this interface.
106 
107     return currentAlbumItems();
108 }
109 
itemInfo(const QUrl & url) const110 DMetaInfoIface::DInfoMap DMetaInfoIface::itemInfo(const QUrl& url) const
111 {
112     DInfoMap map;
113 
114     if (d->urls.contains(url))
115     {
116         QScopedPointer<DMetadata> meta(new DMetadata(url.toLocalFile()));
117         QString   def = QLatin1String("x-default");
118         QFileInfo info(url.toLocalFile());
119 
120         map.insert(QLatin1String("name"),            info.fileName());
121         map.insert(QLatin1String("title"),           meta->getItemTitles()[def].caption);
122         map.insert(QLatin1String("comment"),         meta->getItemComments()[def].caption);
123         map.insert(QLatin1String("orientation"),     (int)meta->getItemOrientation());
124         map.insert(QLatin1String("datetime"),        meta->getItemDateTime());
125         map.insert(QLatin1String("rating"),          meta->getItemRating());
126         map.insert(QLatin1String("colorlabel"),      meta->getItemColorLabel());
127         map.insert(QLatin1String("picklabel"),       meta->getItemPickLabel());
128         map.insert(QLatin1String("filesize"),        (qlonglong)info.size());
129         map.insert(QLatin1String("dimensions"),      meta->getItemDimensions());
130 
131         // Get digiKam Tags Path list of picture from metadata.
132         // Ex.: "City/Paris/Monuments/Notre Dame"
133 
134         QStringList tagsPath;
135         meta->getItemTagsPath(tagsPath);
136         map.insert(QLatin1String("tagspath"),        tagsPath);
137 
138         // Get digiKam Tags name (keywords) list of picture from metadata.
139         // Ex.: "Notre Dame"
140 
141         QStringList keywords = meta->getMetadataField(MetadataInfo::Keywords).toStringList();
142         map.insert(QLatin1String("keywords"),        keywords);
143 
144         // Get GPS location of picture from metadata.
145 
146         double lat = 0.0;
147         double lng = 0.0;
148         double alt = 0.0;
149 
150         if (meta->getGPSInfo(lat, lng, alt))
151         {
152             map.insert(QLatin1String("latitude"),    lat);
153             map.insert(QLatin1String("longitude"),   lng);
154             map.insert(QLatin1String("altitude"),    alt);
155         }
156 
157         // Get Copyright information of picture from metadata.
158 
159         Template temp;
160         meta->getCopyrightInformation(temp);
161 
162         map.insert(QLatin1String("creators"),        temp.authors());
163         map.insert(QLatin1String("credit"),          temp.credit());
164         map.insert(QLatin1String("rights"),          temp.copyright().value(def));
165         map.insert(QLatin1String("source"),          temp.source());
166 
167         PhotoInfoContainer photoInfo = meta->getPhotographInformation();
168         map.insert(QLatin1String("lens"),            photoInfo.lens);
169         map.insert(QLatin1String("make"),            photoInfo.make);
170         map.insert(QLatin1String("model"),           photoInfo.model);
171         map.insert(QLatin1String("exposuretime"),    photoInfo.exposureTime);
172         map.insert(QLatin1String("sensitivity"),     photoInfo.sensitivity);
173         map.insert(QLatin1String("aperture"),        photoInfo.aperture);
174         map.insert(QLatin1String("focallength"),     photoInfo.focalLength);
175         map.insert(QLatin1String("focalLength35mm"), photoInfo.focalLength35mm);
176 
177         // Get Video information from metadata
178 
179         VideoInfoContainer videoInfo = meta->getVideoInformation();
180         map.insert(QLatin1String("videocodec"),      videoInfo.videoCodec);
181 
182         // TODO: add more video metadata as needed
183     }
184 
185     return map;
186 }
187 
setItemInfo(const QUrl & url,const DInfoMap & map) const188 void DMetaInfoIface::setItemInfo(const QUrl& url, const DInfoMap& map) const
189 {
190     QScopedPointer<DMetadata> meta(new DMetadata(url.toLocalFile()));
191     QStringList keys = map.keys();
192 
193     if (map.contains(QLatin1String("orientation")))
194     {
195         meta->setItemOrientation((DMetadata::ImageOrientation)map[QLatin1String("orientation")].toInt());
196         keys.removeAll(QLatin1String("orientation"));
197     }
198 
199     if (map.contains(QLatin1String("rating")))
200     {
201         meta->setItemRating(map[QLatin1String("rating")].toInt());
202         keys.removeAll(QLatin1String("rating"));
203     }
204 
205     if (map.contains(QLatin1String("colorlabel")))
206     {
207         meta->setItemColorLabel(map[QLatin1String("colorlabel")].toInt());
208         keys.removeAll(QLatin1String("colorlabel"));
209     }
210 
211     if (map.contains(QLatin1String("picklabel")))
212     {
213         meta->setItemPickLabel(map[QLatin1String("picklabel")].toInt());
214         keys.removeAll(QLatin1String("picklabel"));
215     }
216 
217     if (!keys.isEmpty())
218     {
219         qCWarning(DIGIKAM_GENERAL_LOG) << "Keys not yet supported in DMetaInfoIface::setItemInfo():" << keys;
220     }
221 }
222 
supportAlbums() const223 bool DMetaInfoIface::supportAlbums() const
224 {
225     return false;
226 }
227 
uploadWidget(QWidget * const parent) const228 QWidget* DMetaInfoIface::uploadWidget(QWidget* const parent) const
229 {
230     if (!d->dirSelector)
231     {
232         d->dirSelector = new DFileSelector(parent);
233         d->dirSelector->setFileDlgMode(QFileDialog::Directory);
234         d->dirSelector->setFileDlgOptions(QFileDialog::ShowDirsOnly);
235         d->dirSelector->setFileDlgTitle(i18n("Destination Folder"));
236         d->dirSelector->lineEdit()->setPlaceholderText(i18n("Output Destination Path"));
237 
238         connect(d->dirSelector, SIGNAL(signalUrlSelected(QUrl)),
239                 this, SIGNAL(signalUploadUrlChanged()));
240     }
241 
242     QFileInfo info(!d->urls.isEmpty() ? d->urls[0].toLocalFile() : QString());
243     d->dirSelector->setFileDlgPath(info.absolutePath());
244 
245     return d->dirSelector;
246 }
247 
uploadUrl() const248 QUrl DMetaInfoIface::uploadUrl() const
249 {
250     return QUrl::fromLocalFile(d->dirSelector->fileDlgPath());
251 }
252 
defaultUploadUrl() const253 QUrl DMetaInfoIface::defaultUploadUrl() const
254 {
255     QUrl place       = QUrl::fromLocalFile(QDir::homePath());
256     QStringList pics = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
257 
258     if (!pics.isEmpty())
259     {
260         place = QUrl::fromLocalFile(pics.first());
261     }
262 
263     QList<QUrl> lst = currentAlbumItems();
264 
265     if (!lst.isEmpty())
266     {
267         QUrl trg = lst.first().adjusted(QUrl::RemoveFilename);
268 
269         if (!trg.isEmpty())
270         {
271             place = trg;
272         }
273     }
274 
275     return place;
276 }
277 
deleteImage(const QUrl & url)278 void DMetaInfoIface::deleteImage(const QUrl& url)
279 {
280 
281 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
282 
283     QFile::moveToTrash(url.toLocalFile());
284 
285 #else
286 
287     QFile::remove(url.toLocalFile());
288 
289 #endif
290 
291     emit signalRemoveImageFromAlbum(url);
292 }
293 
294 #ifdef HAVE_MARBLE
295 
currentGPSItems() const296 QList<GPSItemContainer*> DMetaInfoIface::currentGPSItems() const
297 {
298     QList<GPSItemContainer*> items;
299 
300     foreach (const QUrl& url, currentSelectedItems())
301     {
302         items << new GPSItemContainer(url);
303     }
304 
305     return items;
306 }
307 
308 #endif
309 
310 } // namespace Digikam
311