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