File indexing completed on 2025-04-27 03:57:26

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2015-08-17
0007  * Description : Helper class for Image Description Editor Tab
0008  *
0009  * SPDX-FileCopyrightText: 2015 by Veaceslav Munteanu <veaceslav dot munteanu90 at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #ifndef DIGIKAM_DISJOINT_METADATA_H
0016 #define DIGIKAM_DISJOINT_METADATA_H
0017 
0018 // Qt includes
0019 
0020 #include <QString>
0021 #include <QMap>
0022 #include <QObject>
0023 #include <QDateTime>
0024 
0025 // Local includes
0026 
0027 #include "digikam_export.h"
0028 #include "disjointmetadatadatafields.h"
0029 #include "metaenginesettings.h"
0030 
0031 namespace Digikam
0032 {
0033 
0034 class ItemInfo;
0035 class CaptionsMap;
0036 class Template;
0037 
0038 class DIGIKAM_GUI_EXPORT DisjointMetadata : public QObject
0039 {
0040     Q_OBJECT
0041 
0042 public:
0043 
0044     enum WriteMode
0045     {
0046         /**
0047          * Write all available information
0048          */
0049         FullWrite,
0050 
0051         /**
0052          * Do a full write if and only if
0053          *     - metadata fields changed
0054          *     - the changed fields shall be written according to write settings
0055          * "Changed" in this context means changed by one of the set... methods,
0056          * the load() methods are ignored for this attribute.
0057          * This mode allows to avoid write operations when e.g. the user does not want
0058          * keywords to be written and only changes keywords.
0059          */
0060         FullWriteIfChanged,
0061 
0062         /**
0063          * Write only the changed parts.
0064          * Metadata fields which cannot be changed from MetadataHub (photographer ID etc.)
0065          * will never be written
0066          */
0067         PartialWrite
0068     };
0069 
0070 public:
0071 
0072     DisjointMetadata();
0073     ~DisjointMetadata()                                                           override;
0074 
0075 
0076     DisjointMetadataDataFields dataFields()                                 const;
0077     void setDataFields(const DisjointMetadataDataFields& data);
0078 
0079     void reset();
0080 
0081     void load(const ItemInfo& info);
0082 
0083     //@{
0084 
0085     /**
0086      * Returns the metadata field Status.
0087      */
0088     DisjointMetadataDataFields::Status dateTimeStatus()                     const;
0089     DisjointMetadataDataFields::Status titlesStatus()                       const;
0090     DisjointMetadataDataFields::Status commentsStatus()                     const;
0091     DisjointMetadataDataFields::Status pickLabelStatus()                    const;
0092     DisjointMetadataDataFields::Status colorLabelStatus()                   const;
0093     DisjointMetadataDataFields::Status ratingStatus()                       const;
0094     DisjointMetadataDataFields::Status templateStatus()                     const;
0095 
0096     DisjointMetadataDataFields::Status tagStatus(int albumId)               const;
0097     DisjointMetadataDataFields::Status tagStatus(const QString& tagPath)    const;
0098 
0099     //@}
0100 
0101     //@{
0102 
0103     /**
0104      * Returns if the metadata field has been changed
0105      * with the corresponding setter method.
0106      */
0107     bool dateTimeChanged()                                                  const;
0108     bool titlesChanged()                                                    const;
0109     bool commentsChanged()                                                  const;
0110     bool pickLabelChanged()                                                 const;
0111     bool colorLabelChanged()                                                const;
0112     bool ratingChanged()                                                    const;
0113     bool templateChanged()                                                  const;
0114     bool tagsChanged()                                                      const;
0115 
0116     //@}
0117 
0118     //@{
0119 
0120     /**
0121      * Set metadata field to the given value,
0122      * and the metadata field status to the corresponding DisjointMetadataDataFields::MetadataAvailable.
0123      */
0124     void setDateTime(const QDateTime& dateTime,
0125                      DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0126     void setTitles(const CaptionsMap& titles,
0127                    DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0128     void setComments(const CaptionsMap& comments,
0129                      DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0130     void setPickLabel(int pickId,
0131                       DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0132     void setColorLabel(int colorId,
0133                        DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0134     void setRating(int rating,
0135                    DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0136     void setMetadataTemplate(const Template& t,
0137                              DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0138     void setTag(int albumID,
0139                 DisjointMetadataDataFields::Status status = DisjointMetadataDataFields::MetadataAvailable);
0140 
0141     /**
0142      * Special case if the metadata of color, pick or rating has already been changed outside.
0143      * Replace with current values as if there is no change.
0144      */
0145     void replaceColorLabel(int colorId);
0146     void replacePickLabel(int pickId);
0147     void replaceRating(int rating);
0148 
0149     //@}
0150 
0151     /**
0152      * Returns the dateTime.
0153      * If status is DisjointMetadataDataFields::MetadataDisjoint, the earliest date is returned.
0154      *                                (see dateTimeInterval())
0155      * If status is DisjointMetadataDataFields::MetadataInvalid, an invalid date is returned.
0156      */
0157     QDateTime   dateTime()                                                  const;
0158 
0159     /**
0160      * Returns a map all alternate language titles.
0161      * If status is DisjointMetadataDataFields::MetadataDisjoint, the first loaded map is returned.
0162      * If status is DisjointMetadataDataFields::MetadataInvalid, CaptionMap() is returned.
0163      */
0164     CaptionsMap titles()                                                    const;
0165 
0166     /**
0167      * Returns a map all alternate language omments .
0168      * If status is DisjointMetadataDataFields::MetadataDisjoint, the first loaded map is returned.
0169      * If status is DisjointMetadataDataFields::MetadataInvalid, CaptionMap() is returned.
0170      */
0171     CaptionsMap comments()                                                  const;
0172 
0173     /**
0174      * Returns the Pick Label id (see PickLabel values in globals.h).
0175      * If status is DisjointMetadataDataFields::MetadataDisjoint, the None Label is returned.
0176      *                                (see pickLabelInterval())
0177      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
0178      */
0179     int         pickLabel()                                                 const;
0180 
0181     /**
0182      * Returns the Color Label id (see ColorLabel values in globals.h).
0183      * If status is DisjointMetadataDataFields::MetadataDisjoint, the None Label is returned.
0184      *                                (see colorLabelInterval())
0185      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
0186      */
0187     int         colorLabel()                                                const;
0188 
0189     /**
0190      * Returns the rating.
0191      * If status is DisjointMetadataDataFields::MetadataDisjoint, the lowest rating is returned.
0192      *                                (see ratingInterval())
0193      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
0194      */
0195     int         rating()                                                    const;
0196 
0197     /**
0198      * Returns the metadata template.
0199      * If status is DisjointMetadataDataFields::MetadataDisjoint, the first loaded template is returned.
0200      * If status is DisjointMetadataDataFields::MetadataInvalid, 0 is returned.
0201      */
0202     Template    metadataTemplate()                                          const;
0203 
0204     /**
0205      * Returns the earliest and latest date.
0206      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
0207      * If status is DisjointMetadataDataFields::MetadataInvalid, invalid dates are returned.
0208      */
0209     void        dateTimeInterval(QDateTime& lowest,
0210                                  QDateTime& highest)                        const;
0211 
0212     /**
0213      * Returns the lowest and highest Pick Label id (see PickLabel values from globals.h).
0214      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
0215      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
0216      */
0217     void        pickLabelInterval(int& lowest,
0218                                   int& highest)                             const;
0219 
0220     /**
0221      * Returns the lowest and highest Color Label id (see ColorLabel values from globals.h).
0222      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
0223      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
0224      */
0225     void        colorLabelInterval(int& lowest,
0226                                    int& highest)                            const;
0227 
0228     /**
0229      * Returns the lowest and highest rating.
0230      * If status is DisjointMetadataDataFields::MetadataAvailable, the values are the same.
0231      * If status is DisjointMetadataDataFields::MetadataInvalid, -1 is returned.
0232      */
0233     void        ratingInterval(int& lowest,
0234                                int& highest)                                const;
0235 
0236     /**
0237      * Returns a QStringList with all tags with status DisjointMetadataDataFields::MetadataAvailable.
0238      * (i.e., the intersection of tags from all loaded metadata sets)
0239      */
0240     QStringList keywords()                                                  const;
0241 
0242     /**
0243      * Returns a map with the status for each tag.
0244      * Any tag that was set on one of the loaded images is contained in the map.
0245      * (If a tag is not contained in the map, it was not set on any of the loaded images)
0246      * If the tag was set on all loaded images, the status is DisjointMetadataDataFields::MetadataAvailable.
0247      * If the tag was set on at least one, but not all of the loaded images, the status is DisjointMetadataDataFields::MetadataDisjoint.
0248      */
0249     QMap<int, DisjointMetadataDataFields::Status> tags()                    const;
0250 
0251     void resetChanged();
0252 
0253     /**
0254      * Applies the set of metadata contained in this MetadataHub
0255      * to the given ItemInfo object.
0256      * @return Returns true if the info object has been changed
0257      */
0258     bool write(ItemInfo info, WriteMode writeMode = FullWrite);
0259 
0260     /**
0261      * With the currently applied changes, the given writeMode and settings,
0262      * returns if write(DMetadata), write(QString) or write(DImg) will actually
0263      * apply any changes.
0264      */
0265     bool willWriteMetadata(WriteMode writeMode,
0266                            const MetaEngineSettingsContainer& settings =
0267                                MetaEngineSettings::instance()->settings()) const;
0268 
0269     /**
0270      * @brief changedFlags - used for selective metadata write. The result will be passed to metadatahub and it will
0271      *                     - write it to disk
0272      * @return - metadatahub flags encoded as int
0273      */
0274     int changedFlags();
0275 
0276 private Q_SLOTS:
0277 
0278     void slotTagDeleted(int tagId);
0279     void slotInvalidate();
0280 
0281 private:
0282 
0283     void load(const QDateTime& dateTime,
0284               const CaptionsMap& titles,
0285               const CaptionsMap& comment,
0286               int colorLabel, int pickLabel,
0287               int rating, const Template& t);
0288 
0289     void loadTags(const QList<int>& tagIds);
0290     void notifyTagDeleted(int id);
0291     void applyChangeNotifications();
0292 
0293 private:
0294 
0295     // Disable
0296     explicit DisjointMetadata(QObject*) = delete;
0297 
0298     // Disable copy constructor and operator to prevent potential slicing with this class, reported by Clazy static analyzer.
0299     // https://github.com/KDE/clazy/blob/master/docs/checks/README-copyable-polymorphic.md
0300     // Use DisjointMetadataDataFields container setter and getter instead.
0301     // TODO: remove legacy implementations for these methods later if no side effect.
0302     DisjointMetadata(const DisjointMetadata& other);
0303     DisjointMetadata& operator=(const DisjointMetadata& other);
0304 
0305 private:
0306 
0307     class Private;
0308     Private* d;
0309 };
0310 
0311 } // namespace Digikam
0312 
0313 #endif // DIGIKAM_DISJOINT_METADATA_H