1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2015-08-17
7  * Description : Helper class for Image Description Editor Tab
8  *
9  * Copyright (C) 2015 by Veaceslav Munteanu <veaceslav dot munteanu90 at gmail dot com>
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 #ifndef DIGIKAM_DISJOINT_METADATA_H
25 #define DIGIKAM_DISJOINT_METADATA_H
26 
27 // Qt includes
28 
29 #include <QString>
30 #include <QMap>
31 #include <QObject>
32 #include <QDateTime>
33 
34 // Local includes
35 
36 #include "disjointmetadatadatafields.h"
37 #include "metaenginesettings.h"
38 
39 namespace Digikam
40 {
41 
42 class ItemInfo;
43 class CaptionsMap;
44 class Template;
45 
46 class DisjointMetadata : public QObject
47 {
48     Q_OBJECT
49 
50 public:
51 
52     enum WriteMode
53     {
54         /**
55          * Write all available information
56          */
57         FullWrite,
58 
59         /**
60          * Do a full write if and only if
61          *     - metadata fields changed
62          *     - the changed fields shall be written according to write settings
63          * "Changed" in this context means changed by one of the set... methods,
64          * the load() methods are ignored for this attribute.
65          * This mode allows to avoid write operations when e.g. the user does not want
66          * keywords to be written and only changes keywords.
67          */
68         FullWriteIfChanged,
69 
70         /**
71          * Write only the changed parts.
72          * Metadata fields which cannot be changed from MetadataHub (photographer ID etc.)
73          * will never be written
74          */
75         PartialWrite
76     };
77 
78 public:
79 
80     DisjointMetadata();
81     ~DisjointMetadata()                                                           override;
82 
83 
84     DisjointMetadataDataFields dataFields()                                 const;
85     void setDataFields(const DisjointMetadataDataFields& data);
86 
87     void reset();
88 
89     void load(const ItemInfo& info);
90 
91     //@{
92 
93     /**
94      * Returnsthe metadata field Status.
95      */
96     DisjointMetadataDataFields::Status dateTimeStatus()                     const;
97     DisjointMetadataDataFields::Status titlesStatus()                       const;
98     DisjointMetadataDataFields::Status commentsStatus()                     const;
99     DisjointMetadataDataFields::Status pickLabelStatus()                    const;
100     DisjointMetadataDataFields::Status colorLabelStatus()                   const;
101     DisjointMetadataDataFields::Status ratingStatus()                       const;
102     DisjointMetadataDataFields::Status templateStatus()                     const;
103 
104     DisjointMetadataDataFields::Status tagStatus(int albumId)               const;
105     DisjointMetadataDataFields::Status tagStatus(const QString& tagPath)    const;
106 
107     //@}
108 
109     //@{
110 
111     /**
112      * Returns if the metadata field has been changed
113      * with the corresponding setter method.
114      */
115     bool dateTimeChanged()                                                  const;
116     bool titlesChanged()                                                    const;
117     bool commentsChanged()                                                  const;
118     bool pickLabelChanged()                                                 const;
119     bool colorLabelChanged()                                                const;
120     bool ratingChanged()                                                    const;
121     bool templateChanged()                                                  const;
122     bool tagsChanged()                                                      const;
123 
124     //@}
125 
126     //@{
127 
128     /**
129      * Set metadata field to the given value,
130      * and the metadata field status to the corresponding DisjointMetadataDataFields::MetadataAvailable.
131      */
132     void setDateTime(const QDateTime& dateTime,
133                      DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
134     void setTitles(const CaptionsMap& titles,
135                    DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
136     void setComments(const CaptionsMap& comments,
137                      DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
138     void setPickLabel(int pickId,
139                       DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
140     void setColorLabel(int colorId,
141                        DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
142     void setRating(int rating,
143                    DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
144     void setMetadataTemplate(const Template& t,
145                              DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
146     void setTag(int albumID,
147                 DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
148 
149     //@}
150 
151     /**
152      * Returns the dateTime.
153      * If status is DisjointMetadataDataFields::MetadataDisjoint, the earliest date is returned.
154      *                                (see dateTimeInterval())
155      * If status is DisjointMetadataDataFields::MetadataInvalid, an invalid date is returned.
156      */
157     QDateTime   dateTime()                                                  const;
158 
159     /**
160      * Returns a map all alternate language titles.
161      * If status is DisjointMetadataDataFields::MetadataDisjoint, the first loaded map is returned.
162      * If status is DisjointMetadataDataFields::MetadataInvalid, CaptionMap() is returned.
163      */
164     CaptionsMap titles()                                                    const;
165 
166     /**
167      * Returns a map all alternate language omments .
168      * If status is DisjointMetadataDataFields::MetadataDisjoint, the first loaded map is returned.
169      * If status is DisjointMetadataDataFields::MetadataInvalid, CaptionMap() is returned.
170      */
171     CaptionsMap comments()                                                  const;
172 
173     /**
174      * Returns the Pick Label id (see PickLabel values in globals.h).
175      * If status is DisjointMetadataDataFields::MetadataDisjoint, the None Label is returned.
176      *                                (see pickLabelInterval())
177      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
178      */
179     int         pickLabel()                                                 const;
180 
181     /**
182      * Returns the Color Label id (see ColorLabel values in globals.h).
183      * If status is DisjointMetadataDataFields::MetadataDisjoint, the None Label is returned.
184      *                                (see colorLabelInterval())
185      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
186      */
187     int         colorLabel()                                                const;
188 
189     /**
190      * Returns the rating.
191      * If status is DisjointMetadataDataFields::MetadataDisjoint, the lowest rating is returned.
192      *                                (see ratingInterval())
193      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
194      */
195     int         rating()                                                    const;
196 
197     /**
198      * Returns the metadata template.
199      * If status is DisjointMetadataDataFields::MetadataDisjoint, the first loaded template is returned.
200      * If status is DisjointMetadataDataFields::MetadataInvalid, 0 is returned.
201      */
202     Template    metadataTemplate()                                          const;
203 
204     /**
205      * Returns the earliest and latest date.
206      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
207      * If status is DisjointMetadataDataFields::MetadataInvalid, invalid dates are returned.
208      */
209     void        dateTimeInterval(QDateTime& lowest,
210                                  QDateTime& highest)                        const;
211 
212     /**
213      * Returns the lowest and highest Pick Label id (see PickLabel values from globals.h).
214      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
215      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
216      */
217     void        pickLabelInterval(int& lowest,
218                                   int& highest)                             const;
219 
220     /**
221      * Returns the lowest and highest Color Label id (see ColorLabel values from globals.h).
222      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
223      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
224      */
225     void        colorLabelInterval(int& lowest,
226                                    int& highest)                            const;
227 
228     /**
229      * Returns the lowest and highest rating.
230      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
231      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
232      */
233     void        ratingInterval(int& lowest,
234                                int& highest)                                const;
235 
236     /**
237      * Returns a QStringList with all tags with status DisjointMetadataDataFields::MetadataAvailable.
238      * (i.e., the intersection of tags from all loaded metadata sets)
239      */
240     QStringList keywords()                                                  const;
241 
242     /**
243      * Returns a map with the status for each tag.
244      * Any tag that was set on one of the loaded images is contained in the map.
245      * (If a tag is not contained in the map, it was not set on any of the loaded images)
246      * If the tag was set on all loaded images, the status is DisjointMetadataDataFields::MetadataAvailable.
247      * If the tag was set on at least one, but not all of the loaded images, the status is DisjointMetadataDataFields::MetadataDisjoint.
248      */
249     QMap<int, DisjointMetadataDataFields::Status> tags()                    const;
250 
251     void resetChanged();
252 
253     /**
254      * Applies the set of metadata contained in this MetadataHub
255      * to the given ItemInfo object.
256      * @return Returns true if the info object has been changed
257      */
258     bool write(ItemInfo info, WriteMode writeMode = FullWrite);
259 
260     /**
261      * With the currently applied changes, the given writeMode and settings,
262      * returns if write(DMetadata), write(QString) or write(DImg) will actually
263      * apply any changes.
264      */
265     bool willWriteMetadata(WriteMode writeMode,
266                            const MetaEngineSettingsContainer& settings =
267                                MetaEngineSettings::instance()->settings()) const;
268 
269     /**
270      * @brief changedFlags - used for selective metadata write. The result will be passed to metadatahub and it will
271      *                     - write it to disk
272      * @return - metadatahub flags encoded as int
273      */
274     int changedFlags();
275 
276 private Q_SLOTS:
277 
278     void slotTagDeleted(int tagId);
279     void slotInvalidate();
280 
281 private:
282 
283     void load(const QDateTime& dateTime,
284               const CaptionsMap& titles,
285               const CaptionsMap& comment,
286               int colorLabel, int pickLabel,
287               int rating, const Template& t);
288 
289     void loadTags(const QList<int>& tagIds);
290     void notifyTagDeleted(int id);
291     void applyChangeNotifications();
292 
293 private:
294 
295     // Disable
296     explicit DisjointMetadata(QObject*) = delete;
297 
298     // Disable copy constructor and operator to prevent potential slicing with this class, reported by Clazy static analyzer.
299     // https://github.com/KDE/clazy/blob/master/docs/checks/README-copyable-polymorphic.md
300     // Use DisjointMetadataDataFields container setter and getter instead.
301     // TODO: remove legacy implementations for these methods later if no side effect.
302     DisjointMetadata(const DisjointMetadata& other);
303     DisjointMetadata& operator=(const DisjointMetadata& other);
304 
305 private:
306 
307     class Private;
308     Private* d;
309 };
310 
311 } // namespace Digikam
312 
313 #endif // DIGIKAM_DISJOINT_METADATA_H
314