1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2007-01-05
7  * Description : Metadata handling
8  *
9  * Copyright (C) 2007-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  * Copyright (C) 2007-2021 by Gilles Caulier <caulier dot gilles 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 #ifndef DIGIKAM_METADATA_HUB_H
26 #define DIGIKAM_METADATA_HUB_H
27 
28 // Qt includes
29 
30 #include <QList>
31 #include <QStringList>
32 #include <QDateTime>
33 #include <QMap>
34 
35 // Local includes
36 
37 #include "metaenginesettings.h"
38 #include "captionvalues.h"
39 #include "dmetadata.h"
40 #include "dimg.h"
41 
42 namespace Digikam
43 {
44 
45 class ApplicationSettings;
46 class ItemInfo;
47 class Template;
48 
49 class MetadataHub
50 {
51 public:
52 
53     /**
54      * The status enum describes the result of joining several metadata sets.
55      * If only one set has been added, the status is always MetadataAvailable.
56      * If no set has been added, the status is always MetadataInvalid
57      */
58     enum Status
59     {
60         MetadataInvalid,   ///< not yet filled with any value
61         MetadataAvailable  ///< only one data set has been added, or a common value is available
62     };
63 
64     enum WriteMode
65     {
66         /**
67          * Write all available information
68          */
69         FullWrite,
70 
71         /**
72          * Do a full write if and only if
73          *     - metadata fields changed
74          *     - the changed fields shall be written according to write settings
75          * "Changed" in this context means changed by one of the set... methods,
76          * the load() methods are ignored for this attribute.
77          * This mode allows to avoid write operations when e.g. the user does not want
78          * keywords to be written and only changes keywords.
79          */
80         FullWriteIfChanged,
81 
82         /**
83          * Write only the changed parts.
84          * Metadata fields which cannot be changed from MetadataHub (photographer ID etc.)
85          * will never be written
86          */
87         PartialWrite
88     };
89 
90     enum WriteComponents
91     {
92         WRITE_DATETIME  = 1,
93         WRITE_TITLE     = 2,
94         WRITE_COMMENTS  = 4,
95         WRITE_PICKLABEL = 8,
96         WRITE_COLORLABEL= 16,
97         WRITE_RATING    = 32,
98         WRITE_TEMPLATE  = 64,
99         WRITE_TAGS      = 128,
100         WRITE_POSITION  = 256,
101         WRITE_ALL       = 511
102     };
103     Q_DECLARE_FLAGS(WriteComponent, WriteComponents)
104 
105 public:
106 
107     /**
108      * Constructs a MetadataHub.
109      */
110     MetadataHub();
111     ~MetadataHub();
112 
113     void reset();
114 
115     // --------------------------------------------------
116 
117     /**
118      * Add metadata information contained in the ItemInfo object.
119      * This method (or in combination with the other load methods)
120      * can be called multiple times on the same MetadataHub object.
121      * In this case, the metadata will be combined.
122      */
123     void load(const ItemInfo& info);
124 
125 //    /**
126 //     * Add metadata information from the meta engine object
127 //     */
128 //    void load(const DMetadata& metadata);
129 
130 //    /**
131 //     * Load metadata information from the given file.
132 //     * (Uses DMetadata, QFileInfo)
133 //     * @returns True if the metadata could be loaded
134 //     */
135 //    bool load(const QString& filePath, const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
136 
137     // --------------------------------------------------
138 
139     /**
140      * @brief writeToMetadata - write to metadata using image info to retrieve tags and filepath
141      *                          use this method when multiple image infos are loaded in hub
142      * @param info - image info to retrieve current tags
143      * @param writeMode
144      * @param settings
145      * @return true           - if everything is successful
146      */
147     bool writeToMetadata(const ItemInfo& info,
148                          WriteComponent writeMode = WRITE_ALL,
149                          bool ignoreLazySync = false,
150                          const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
151 
152 
153     /**
154      * Constructs a meta engine object for given filePath,
155      * calls the above method, writes the changes out to the file,
156      * and notifies the ItemAttributesWatch.
157      * WARNING: Do not use this method when multiple image infos are loaded
158      *          It will result in disjoint tags not being written
159      *          Use writeToMetadata(Image info ...) instead
160      * @return Returns if the file has been touched
161      */
162     bool write(const QString& filePath,
163                WriteComponent writeMode = WRITE_ALL,
164                bool ignoreLazySync = false,
165                const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
166 
167     /**
168      * Constructs a meta engine object from the metadata stored in the given DImg object,
169      * calls the above method, and changes the stored metadata in the DImg object.
170      * @return Returns if the DImg object has been touched
171      */
172     bool write(const DImg& image,
173                WriteComponent writeMode = WRITE_ALL,
174                bool ignoreLazySync = false,
175                const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
176 
177     /**
178      * Will write only Tags to image. Used by TagsManager to write tags to image
179      * Other metadata are not updated.
180      * @return if tags were successfully written.
181      */
182     bool writeTags(const QString& filePath,
183                    WriteComponent writeMode = WRITE_ALL,
184                    const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
185 
186     /**
187      * @brief writeTags - used to deduplicate code from writeTags and usual write, all write to tags
188      *                    operations must be done here
189      * @param metadata  - meta engine object that apply changes
190      * @param saveTags  - save switch
191      * @return          - if tags were successfully set
192      */
193     bool writeTags(const DMetadata& metadata, bool saveTags);
194 
195     /**
196      * @brief cleanupTags - remove duplicates and obsolete tags before setting metadata
197      * @param toClean     - tag list to be cleared and de-duplicated
198      * @return            - clean tag list
199      */
200     QStringList cleanupTags(const QStringList& toClean);
201 
202     /**
203      * With the currently applied changes, the given writeMode and settings,
204      * returns if write(DMetadata), write(QString) or write(DImg) will actually
205      * apply any changes.
206      */
207     bool willWriteMetadata(Digikam::MetadataHub::WriteComponent writeMode = WRITE_ALL,
208                            const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings()) const;
209 
210     /**
211      * @brief writeToBaloo - write tags, comments and rating to KDE Nepomuk replacement: Baloo
212      * @param filePath     - path to file to add comments, tags and rating
213      * @param settings     - metadata settings to be set
214      */
215     void writeToBaloo(const QString& filePath,
216                       const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
217 
218 
219     // --------------------------------------------------
220 
221     /**
222      * Dedicated method to set face rectangles from database
223      * When called from outside the metadatahub and  ItemInfo is cached,
224      * method dimension() can return wrong values, QSize must be specified
225      * manually
226      */
227     void loadFaceTags(const ItemInfo& info, const QSize& size);
228 
229     /**
230      * Get face tag names and face tag regions.
231      * This is used for metadata synchronization in Image Editor
232      */
233     QMultiMap<QString, QVariant> getFaceTags();
234 
235     /**
236      * Set new face tags
237      */
238     void setFaceTags(QMultiMap<QString, QVariant> newFaceTags, QSize size);
239 
240 protected:
241 
242     /**
243      * Applies the set of metadata contained in this MetadataHub
244      * to the given meta engine object.
245      * The MetaEngineSettingsContainer determine whether data is actually
246      * set or not.
247      * The following metadata fields may be set (depending on settings):
248      * - Comment
249      * - Date
250      * - Rating
251      * - Tags
252      * - Photographer ID (data from settings)
253      * - Credits (data from settings)
254      *
255      * The data fields taken from this MetadataHub object are only set if
256      * their status is MetadataAvailable.
257      * If the status is MetadataInvalid or MetadataDisjoint, the respective
258      * metadata field is not touched.
259      * @return Returns true if the metadata object has been touched
260      */
261     bool write(DMetadata& metadata,
262                WriteComponent writeMode = WRITE_ALL,
263                const MetaEngineSettingsContainer& settings = MetaEngineSettings::instance()->settings());
264 
265     void load(const QDateTime& dateTime,
266               const CaptionsMap& titles,
267               const CaptionsMap& comment,
268               int colorLabel, int pickLabel,
269               int rating, const Template& t);
270 
271     void loadTags(const QList<int>& loadedTagIds);
272     void loadTags(const QStringList& loadedTagPaths);
273     void notifyTagDeleted(int id);
274 
275     void applyChangeNotifications();
276 
277 private:
278 
279     bool writeFaceTagsMap(const DMetadata& metadata, bool saveFaces);
280 
281 private:
282 
283     class Private;
284     Private* const d;
285 
286 private:
287 
288     Q_DISABLE_COPY(MetadataHub)
289 };
290 
291 } // namespace Digikam
292 
293 Q_DECLARE_OPERATORS_FOR_FLAGS(Digikam::MetadataHub::WriteComponent)
294 
295 #endif // DIGIKAM_METADATA_HUB_H
296