File indexing completed on 2025-01-05 03:53:47

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2004-06-15
0007  * Description : digiKam album types
0008  *
0009  * SPDX-FileCopyrightText: 2004-2005 by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2014-2015 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #ifndef DIGIKAM_ALBUM_H
0018 #define DIGIKAM_ALBUM_H
0019 
0020 // Qt includes
0021 
0022 #include <QMap>
0023 #include <QUrl>
0024 #include <QList>
0025 #include <QString>
0026 #include <QObject>
0027 #include <QMetaType>
0028 #include <QReadWriteLock>
0029 
0030 // Local includes
0031 
0032 #include "coredbalbuminfo.h"
0033 #include "digikam_export.h"
0034 
0035 namespace Digikam
0036 {
0037 
0038 /**
0039  * Album list type definition.
0040  */
0041 class Album;
0042 typedef QList<Album*> AlbumList;
0043 
0044 class CoreDbUrl;
0045 
0046 /**
0047  * \class Album
0048  * \brief Abstract base class for all album types
0049  *
0050  * A class which provides an abstraction for a type Album. This class is meant to
0051  * be derived and every time a new Album Type is defined add a enum corresponding
0052  * to that to Album::Type
0053  *
0054  * This class provides a means of building a tree representation for
0055  * Albums @see Album::setParent().
0056  */
0057 class DIGIKAM_GUI_EXPORT Album
0058 {
0059 public:
0060 
0061     enum Type
0062     {
0063         PHYSICAL=0, ///< A physical album type @see PAlbum
0064         TAG,        ///< A tag      album type @see TAlbum
0065         DATE,       ///< A date     album type @see DAlbum
0066         SEARCH,     ///< A search   album type @see SAlbum
0067         FACE        ///< A faces    album type @see FAlbum
0068     };
0069 
0070     /**
0071      * @return the parent album for this album
0072      */
0073     Album* parent()                         const;
0074 
0075     /**
0076      * @return the first child of this album or 0 if no children
0077      */
0078     Album* firstChild()                     const;
0079 
0080     /**
0081      * @return the last child of this album or 0 if no children
0082      */
0083     Album* lastChild()                      const;
0084 
0085     /**
0086      * @return the next sibling of this album of this album or 0
0087      * if no next sibling
0088      * @see AlbumIterator
0089      */
0090     Album* next()                           const;
0091 
0092     /**
0093      * @return the previous sibling of this album of this album or 0 if no
0094      * previous sibling
0095      * @see AlbumIterator
0096      */
0097     Album* prev()                           const;
0098 
0099     /**
0100      * @return the child of this album at row
0101      */
0102     Album* childAtRow(int row)              const;
0103 
0104     /**
0105      * @return a list of all child Albums
0106      */
0107     AlbumList childAlbums(bool recursive = false);
0108 
0109     /**
0110      * @return a list of all child Albums
0111      */
0112     QList<int> childAlbumIds(bool recursive = false);
0113 
0114     /**
0115      * @return the type of album
0116      * @see Type
0117      */
0118     Type type()                             const;
0119 
0120     /**
0121      * Each album has a @p ID uniquely identifying it in the set of Albums of
0122      * a Type
0123      *
0124      * \note The @p ID for a root Album is always 0
0125      *
0126      * @return the @p ID of the album
0127      * @see globalID()
0128      */
0129     int id()                                const;
0130 
0131     /**
0132      * An album ID is only unique among the set of all Albums of its Type.
0133      * This is a global Identifier which will uniquely identifying the Album
0134      * among all Albums
0135      *
0136      * \note If you are adding a new Album Type make sure to update
0137      * this implementation.
0138      *
0139      * You can always get the @p ID of the album using something like
0140      *
0141      * \code
0142      * int albumID = rootAlbum->globalID() - album->globalID();
0143      * \endcode
0144      *
0145      * @return the @p globalID of the album
0146      * @see id()
0147      */
0148     int globalID()                          const;
0149 
0150     /**
0151      * @return the @p childCount of the album
0152      */
0153     int childCount()                        const;
0154 
0155     /**
0156      * @return the @p rowFromAlbum of the album
0157      */
0158     int rowFromAlbum()                      const;
0159 
0160     /**
0161      * @return the @p title aka name of the album
0162      */
0163     QString title()                         const;
0164 
0165     /**
0166      * @return the kde url of the album
0167      */
0168     virtual CoreDbUrl databaseUrl()         const = 0;
0169 
0170     /**
0171      * @return true is the album is a Root Album
0172      */
0173     bool isRoot()                           const;
0174 
0175     /**
0176      * @return true if the @p album is in the parent hierarchy
0177      *
0178      * @param album the album to check whether it belongs in the child
0179      * hierarchy
0180      */
0181     bool isAncestorOf(Album* const album)   const;
0182 
0183     /**
0184      * @return true if the Album was created by Labels Tree
0185      *
0186      */
0187     bool isUsedByLabelsTree()               const;
0188 
0189     /**
0190      * @return true if the album was created to be a trash
0191      *         virtual album
0192      */
0193     bool isTrashAlbum()                     const;
0194 
0195     /**
0196      * This allows to associate some "extra" data to a Album. As one
0197      * Album can be used by several objects (often views) which all need
0198      * to add some data, you have to use a key to reference your extra data
0199      * within the Album.
0200      *
0201      * That way a Album can hold and provide access to all those views
0202      * separately.
0203      *
0204      * for eg,
0205      *
0206      * \code
0207      * album->setExtraData( this, searchFolderItem );
0208      * \endcode
0209      *
0210      * and can later access the searchFolderItem by doing
0211      *
0212      * \code
0213      * SearchFolderItem *item = static_cast<SearchFolderItem*>(album->extraData(this));
0214      * \endcode
0215      *
0216      * Note: you have to remove and destroy the data you associated yourself
0217      * when you don't need it anymore!
0218      *
0219      * @param key the key of the extra data
0220      * @param value the value of the extra data
0221      * @see extraData
0222      * @see removeExtraData
0223      */
0224     void setExtraData(const void* const key, void* const value);
0225 
0226     /**
0227      * Remove the associated extra data associated with @p key
0228      *
0229      * @param key the key of the extra data
0230      * @see setExtraData
0231      * @see extraData
0232      */
0233     void removeExtraData(const void* const key);
0234 
0235     /**
0236      * Retrieve the associated extra data associated with @p key
0237      *
0238      * @param key the key of the extra data
0239      * @see setExtraData
0240      * @see extraData
0241      */
0242     void* extraData(const void* const key)  const;
0243 
0244     /**
0245      * Sets the property m_usedByLabelsTree to true if the search album
0246      * was created using the Colors and labels tree view
0247      *
0248      * @param isUsed => the status of the usage
0249      */
0250     void setUsedByLabelsTree(bool isUsed);
0251 
0252     /**
0253      * @brief Produces the global id
0254      * @param type The type of the album
0255      * @param id the (type-specific) id of the album
0256      * @return the global id
0257      */
0258     static int globalID(Type type, int id);
0259 
0260 protected:
0261 
0262     /**
0263      * Constructor
0264      */
0265     Album(Album::Type type, int id, bool root);
0266 
0267     /**
0268      * Destructor
0269      *
0270      * this will also recursively delete all child Albums
0271      */
0272     virtual ~Album();
0273 
0274     /**
0275      * Delete all child albums and also remove any associated extra data
0276      */
0277     void clear();
0278 
0279     /**
0280      * @internal use only
0281      *
0282      * Set a new title for the album
0283      *
0284      * @param title new title for the album
0285      */
0286     void setTitle(const QString& title);
0287 
0288     /**
0289      * @internal use only
0290      *
0291      * Set the parent of the album
0292      *
0293      * @param parent set the parent album of album to @p parent
0294      */
0295     void setParent(Album* const parent);
0296 
0297     /**
0298      * @internal use only
0299      *
0300      * Insert an Album as a child for this album
0301      *
0302      * @param child the Album to add as child
0303      */
0304     void insertChild(Album* const child);
0305 
0306     /**
0307      * @internal use only
0308      *
0309      * Remove a Album from the children list for this album
0310      *
0311      * @param child the Album to remove
0312      */
0313     void removeChild(Album* const child);
0314 
0315 private:
0316 
0317      // Disable
0318     Album()                         = delete;
0319     Album& operator==(const Album&) = delete;
0320     Q_DISABLE_COPY(Album)
0321 
0322 private:
0323 
0324     bool                     m_root;
0325     bool                     m_usedByLabelsTree;
0326     volatile bool            m_albumInDeletion;
0327 
0328     int                      m_id;
0329 
0330     QString                  m_name;
0331     QString                  m_title;
0332 
0333     QMap<const void*, void*> m_extraMap;
0334 
0335     QList<Album*>            m_childCache;
0336     mutable QReadWriteLock   m_cacheLock;
0337 
0338     Type                     m_type;
0339 
0340     Album*                   m_parent;
0341 
0342     friend class AlbumManager;
0343 };
0344 
0345 /**
0346  * \class PAlbum
0347  *
0348  * A Physical Album representation
0349  */
0350 class DIGIKAM_GUI_EXPORT PAlbum : public Album
0351 {
0352 public:
0353 
0354     /// Constructor for root album
0355     explicit PAlbum(const QString& title);
0356 
0357     /// Constructor for album root albums
0358     PAlbum(int albumRoot, const QString& label);
0359 
0360     /// Constructor for normal albums
0361     PAlbum(int albumRoot, const QString& parentPath, const QString& title, int id);
0362 
0363     /// Constructor for Trash album
0364     PAlbum(const QString& parentPath, int albumRoot);
0365     ~PAlbum() override;
0366 
0367     void setCaption(const QString& caption);
0368     void setCategory(const QString& category);
0369     void setDate(const QDate& date);
0370 
0371     QString     albumRootPath()  const;
0372     QString     albumRootLabel() const;
0373     int         albumRootId()    const;
0374     QString     caption()        const;
0375     QString     category()       const;
0376     QDate       date()           const;
0377     QString     albumPath()      const;
0378     QString     prettyUrl()      const;
0379     QString     folderPath()     const;
0380     CoreDbUrl   databaseUrl()    const override;
0381     QUrl        fileUrl()        const;
0382     qlonglong   iconId()         const;
0383     bool        isAlbumRoot()    const;
0384 
0385 private:
0386 
0387     /**
0388      * A special integer for Trash virtual folders Ids;
0389      * That gets decremented not incremented
0390      */
0391     static int m_uniqueTrashId;
0392 
0393     bool       m_isAlbumRootAlbum;
0394 
0395     int        m_albumRootId;
0396 
0397     QString    m_path;
0398     QString    m_parentPath;
0399     QString    m_category;
0400     QString    m_caption;
0401     qlonglong  m_iconId;
0402 
0403     QDate      m_date;
0404 
0405     friend class AlbumManager;
0406 };
0407 
0408 /**
0409  * \class TAlbum
0410  *
0411  * A Tag Album representation
0412  */
0413 class DIGIKAM_GUI_EXPORT TAlbum : public Album
0414 {
0415 public:
0416 
0417     TAlbum(const QString& title, int id, bool root=false);
0418     ~TAlbum() override;
0419 
0420     /**
0421      * @return The tag path, e.g. "/People/Friend/John" if leadingSlash is true,
0422      *         "People/Friend/John" if leadingSlash if false.
0423      *         The root TAlbum returns "/" resp. "".
0424      */
0425     QString                tagPath(bool leadingSlash = true) const;
0426     QString                standardIconName()                const;
0427     CoreDbUrl              databaseUrl()                     const override;
0428     QString                prettyUrl()                       const;
0429     QString                icon()                            const;
0430     qlonglong              iconId()                          const;
0431     QList<int>             tagIDs()                          const;
0432 
0433     bool                   isInternalTag()                   const;
0434     bool                   hasProperty(const QString& key)   const;
0435     QString                property(const QString& key)      const;
0436     QMap<QString, QString> properties()                      const;
0437 
0438 private:
0439 
0440     int       m_pid;
0441 
0442     QString   m_icon;
0443     qlonglong m_iconId;
0444 
0445     friend class AlbumManager;
0446 };
0447 
0448 /**
0449  * \class DAlbum
0450  *
0451  * A Date Album representation
0452  */
0453 class DIGIKAM_GUI_EXPORT DAlbum : public Album
0454 {
0455 public:
0456 
0457     enum Range
0458     {
0459         Month = 0,
0460         Year
0461     };
0462 
0463 public:
0464 
0465     explicit DAlbum(const QDate& date, bool root=false, Range range=Month);
0466     ~DAlbum() override;
0467 
0468     QDate     date()        const;
0469     Range     range()       const;
0470     CoreDbUrl databaseUrl() const override;
0471 
0472 private:
0473 
0474     static int m_uniqueID;
0475     QDate      m_date;
0476     Range      m_range;
0477 
0478     friend class AlbumManager;
0479 };
0480 
0481 /**
0482  * \class SAlbum
0483  *
0484  * A Search Album representation
0485  */
0486 class DIGIKAM_GUI_EXPORT SAlbum : public Album
0487 {
0488 public:
0489 
0490     SAlbum(const QString& title, int id, bool root=false);
0491     ~SAlbum() override;
0492 
0493     CoreDbUrl            databaseUrl()        const override;
0494     QString              query()              const;
0495     DatabaseSearch::Type searchType()         const;
0496     bool                 isNormalSearch()     const;
0497     bool                 isAdvancedSearch()   const;
0498     bool                 isKeywordSearch()    const;
0499     bool                 isTimelineSearch()   const;
0500     bool                 isHaarSearch()       const;
0501     bool                 isMapSearch()        const;
0502     bool                 isDuplicatesSearch() const;
0503 
0504     /**
0505      * Indicates whether this album is a temporary search or not.
0506      *
0507      * @return true if this is a temporary search album, else false
0508      */
0509     bool                 isTemporarySearch()  const;
0510 
0511     QString              displayTitle()       const;
0512 
0513     /**
0514      * Returns the title of search albums that is used to mark them as a
0515      * temporary search that isn't saved officially yet and is only used for
0516      * viewing purposes.
0517      *
0518      * @param type the type of the search to get the temporary title for
0519      * @param haarType there are several haar searches, so that this search type
0520      *                 needs a special handling
0521      * @return string that identifies this album uniquely as an unsaved search
0522      */
0523     static QString getTemporaryTitle(DatabaseSearch::Type type,
0524                                      DatabaseSearch::HaarSearchType haarType = DatabaseSearch::HaarImageSearch);
0525 
0526     /**
0527      * Returns the title for a temporary haar search depending on the sub-type
0528      * used for this search
0529      *
0530      * @param haarType type of the haar search to get the name for
0531      * @return string that identifies this album uniquely as an unsaved search
0532      */
0533     static QString getTemporaryHaarTitle(DatabaseSearch::HaarSearchType haarType);
0534 
0535 private:
0536 
0537     void setSearch(DatabaseSearch::Type type, const QString& query);
0538 
0539 private:
0540 
0541     QString              m_query;
0542     DatabaseSearch::Type m_searchType;
0543 
0544     friend class AlbumManager;
0545 };
0546 
0547 /**
0548  *  \class AlbumIterator
0549  *
0550  *  Iterate over all children of this Album.
0551  *  \note It will not include the specified album
0552  *
0553  *  Example usage:
0554  *  \code
0555  *  AlbumIterator it(album);
0556  *  while ( it.current() )
0557  *  {
0558  *     qCDebug(DIGIKAM_GENERAL_LOG) << "Album: " << it.current()->title();
0559  *     ++it;
0560  *  }
0561  * \endcode
0562  *
0563  *  \warning Do not delete albums using this iterator.
0564  */
0565 class DIGIKAM_GUI_EXPORT AlbumIterator
0566 {
0567 public:
0568 
0569     explicit AlbumIterator(Album* const album);
0570     ~AlbumIterator();
0571 
0572     AlbumIterator& operator++();
0573     Album*         operator*();
0574     Album*         current() const;
0575 
0576 private:
0577 
0578     // Disable
0579     AlbumIterator() = delete;
0580     Q_DISABLE_COPY(AlbumIterator)
0581 
0582 private:
0583 
0584     Album* m_current;
0585     Album* m_root;
0586 };
0587 
0588 } // namespace Digikam
0589 
0590 Q_DECLARE_METATYPE(Digikam::Album*)
0591 Q_DECLARE_METATYPE(QList<Digikam::TAlbum*>)
0592 
0593 #endif // DIGIKAM_ALBUM_H