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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-04-09
0007  * Description : Collection location management
0008  *
0009  * SPDX-FileCopyrightText: 2007-2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #ifndef DIGIKAM_COLLECTION_MANAGER_H
0016 #define DIGIKAM_COLLECTION_MANAGER_H
0017 
0018 // Qt includes
0019 
0020 #include <QString>
0021 #include <QStringList>
0022 #include <QUrl>
0023 #include <QObject>
0024 
0025 // Local includes
0026 
0027 #include "digikam_export.h"
0028 
0029 namespace Digikam
0030 {
0031 
0032 class CollectionLocation;
0033 class AlbumRootChangeset;
0034 
0035 class DIGIKAM_DATABASE_EXPORT CollectionManager : public QObject
0036 {
0037     Q_OBJECT
0038 
0039 public:
0040 
0041     enum LocationCheckResult
0042     {
0043         /// The check did not succeed, status unknown
0044         LocationInvalidCheck,
0045 
0046         /// All right. The accompanying message may be empty.
0047         LocationAllRight,
0048 
0049         /// Location can be added, but the user should be aware of a problem
0050         LocationHasProblems,
0051 
0052         /// Adding the location will fail (e.g. there is already a location for the path)
0053         LocationNotAllowed
0054     };
0055 
0056 public:
0057 
0058     static CollectionManager* instance();
0059     static void cleanUp();
0060 
0061     /**
0062      * Disables the collection watch.
0063      * It will be reenabled as soon as refresh() is called
0064      * or any other action triggered.
0065      */
0066     void setWatchDisabled();
0067 
0068     /**
0069      * Clears all locations and re-reads the lists of collection locations.
0070      * Enables the watch.
0071      */
0072     void refresh();
0073 
0074 private Q_SLOTS:
0075 
0076     void deviceAdded(const QString&);
0077     void deviceRemoved(const QString&);
0078     void accessibilityChanged(bool, const QString&);
0079 
0080 private:
0081 
0082     // Disabled
0083     CollectionManager();
0084     explicit CollectionManager(QObject*) = delete;
0085     ~CollectionManager() override;
0086 
0087     void clearLocations();
0088 
0089     Q_PRIVATE_SLOT(d, void slotTriggerUpdateVolumesList())
0090 
0091 Q_SIGNALS: // internal use only with slotTriggerUpdateVolumesList()
0092 
0093     void triggerUpdateVolumesList();
0094 
0095     // -----------------------------------------------------------------------------
0096 
0097     /** @name Operations on Collection Location
0098      */
0099 
0100     //@{
0101 
0102 public:
0103 
0104     /**
0105      * Add the given file system location as new collection location.
0106      * Type and availability will be detected.
0107      * On failure returns null. This would be the case if the given
0108      * url is already contained in another collection location.
0109      * You may pass an optional user-visible label that will be stored in the database.
0110      * The label has no further meaning and can be freely chosen.
0111      *
0112      * CollectionLocation objects returned are simple data containers.
0113      * If the corresponding location is returned, the data is still safe to access,
0114      * but does not represent anything.
0115      * Therefore, do not store returned objects, but prefer to retrieve them freshly.
0116      */
0117     CollectionLocation addLocation(const QUrl& fileUrl,
0118                                    const QString& label = QString());
0119     CollectionLocation addNetworkLocation(const QUrl& fileUrl,
0120                                           const QString& label = QString());
0121     CollectionLocation refreshLocation(const CollectionLocation& location, int newType,
0122                                        const QStringList& pathList,
0123                                        const QString& label = QString());
0124 
0125     /**
0126      * Analyzes the given file path. Creates an info message
0127      * describing the result of identification or possible problems.
0128      * The text is i18n'ed and can be presented to the user.
0129      * The returned result enum describes the test result.
0130      */
0131     LocationCheckResult checkLocation(const QUrl& fileUrl, QList<CollectionLocation>& assumeDeleted,
0132                                       QString* message = nullptr, QString* suggestedMessageIconName = nullptr);
0133     LocationCheckResult checkNetworkLocation(const QUrl& fileUrl, QList<CollectionLocation>& assumeDeleted,
0134                                              QString* message = nullptr, QString* suggestedMessageIconName = nullptr);
0135 
0136     /**
0137      * Removes the given location. This means that all images contained on the
0138      * location will be removed from the database, all tags will be lost.
0139      */
0140     void removeLocation(const CollectionLocation& location);
0141 
0142     /**
0143      * Sets the label of the given location
0144      */
0145     void setLabel(const CollectionLocation& location, const QString& label);
0146 
0147     /**
0148      * Changes the CollectionLocation::Type of the given location
0149      */
0150     void changeType(const CollectionLocation& location, int type);
0151 
0152     /**
0153      * Checks the locations of type HardWired. If one of these is not available currently,
0154      * it is added to the list of disappeared locations.
0155      * This case may happen if a file system is changed, a backup restored or other actions
0156      * taken that change the UUID, although the data may still be available and mounted.
0157      * If there are hard-wired volumes available which are candidates for a newly appeared
0158      * volume (in fact those that do not contain any collections currently), they are
0159      * added to the map, identifier -> i18n'ed user presentable description.
0160      * The identifier can be used for changeVolume.
0161      */
0162     QList<CollectionLocation> checkHardWiredLocations();
0163 
0164     /**
0165      * For a given disappeared location (retrieved from checkHardWiredLocations())
0166      * retrieve a user-presentable technical description (excluding the CollectionLocation's label)
0167      * and a list of identifiers and corresponding user presentable strings of candidates
0168      * to where the given location may have been moved.
0169      */
0170     void migrationCandidates(const CollectionLocation& disappearedLocation,
0171                              QString* const technicalDescription,
0172                              QStringList* const candidateIdentifiers,
0173                              QStringList* const candidateDescriptions);
0174 
0175     /**
0176      * Migrates the existing collection to a new volume, identified by an internal identifier
0177      * as returned by checkHardWiredLocations().
0178      * Use this _only_ to react to changes like those detailed for checkHardWiredLocations;
0179      * the actual data pointed to shall be unchanged.
0180      */
0181     void migrateToVolume(const CollectionLocation& location, const QString& identifier);
0182 
0183     /**
0184      * Returns a list of all CollectionLocations stored in the database
0185      */
0186     QList<CollectionLocation> allLocations();
0187 
0188     /**
0189      * Returns a list of all currently available CollectionLocations
0190      */
0191     QList<CollectionLocation> allAvailableLocations();
0192 
0193     /**
0194      * Returns the location for the given album root id
0195      */
0196     CollectionLocation locationForAlbumRootId(int id);
0197 
0198     /**
0199      * Returns the CollectionLocation that contains the given album root.
0200      * The path must be an album root with isAlbumRoot() == true.
0201      * Returns 0 if no collection location matches.
0202      * Only available (or hidden, but available) locations are guaranteed to be found.
0203      */
0204     CollectionLocation locationForAlbumRoot(const QUrl& fileUrl);
0205     CollectionLocation locationForAlbumRootPath(const QString& albumRootPath);
0206 
0207     /**
0208      * Returns the CollectionLocation that contains the given path.
0209      * Equivalent to calling locationForAlbumRoot(albumRoot(fileUrl)).
0210      * Only available (or hidden, but available) locations are guaranteed to be found.
0211      */
0212     CollectionLocation locationForUrl(const QUrl& fileUrl);
0213     CollectionLocation locationForPath(const QString& filePath);
0214 
0215 private:
0216 
0217     void updateLocations();
0218 
0219 Q_SIGNALS:
0220 
0221     /**
0222      * Emitted when the status of a collection location changed.
0223      * This means that the location became available, hidden or unavailable.
0224      *
0225      * An added location will change its status after addition,
0226      * from Null to Available, Hidden or Unavailable.
0227      *
0228      * A removed location will change its status to Deleted
0229      * during the removal; in this case, you shall not use the object
0230      * passed with this signal with any method of CollectionManager.
0231      *
0232      * The second signal argument is of type CollectionLocation::Status
0233      * and describes the status before the state change occurred
0234      */
0235     void locationStatusChanged(const CollectionLocation& location, int oldStatus);
0236 
0237     /**
0238      * Emitted when the label of a collection location is changed
0239      */
0240     void locationPropertiesChanged(const CollectionLocation& location);
0241 
0242     //@}
0243 
0244     // -----------------------------------------------------------------------------
0245 
0246     /** @name Operations on Albums
0247      */
0248 
0249     //@{
0250 
0251 public:
0252 
0253     /**
0254      * Returns a list of the paths of all currently available root paths
0255      */
0256     QStringList allAvailableAlbumRootPaths();
0257 
0258     /**
0259      * Returns the album root path with the given id.
0260      * Returns a null QString if the root path does not exist or is not available.
0261      */
0262     QString albumRootPath(int id);
0263 
0264     /**
0265      * Returns the album root label with the given id.
0266      * Returns a null QString if the root path does not exist or is not available.
0267      */
0268     QString albumRootLabel(int id);
0269 
0270     //@{
0271     /**
0272      * For a given path, the part of the path that forms the album root is returned,
0273      * ending without a slash. Example: "/media/fotos/Paris 2007" gives "/media/fotos".
0274      * Only available (or hidden, but available) album roots are guaranteed to be found.
0275      */
0276     QUrl    albumRoot(const QUrl& fileUrl);
0277     QString albumRootPath(const QUrl& fileUrl);
0278     QString albumRootPath(const QString& filePath);
0279     //@}
0280 
0281     /**
0282      * Returns true if the given path forms an album root.
0283      * It will return false if the path is a path below an album root,
0284      * or if the path does not belong to an album root.
0285      * Example: "/media/fotos/Paris 2007" is an album with album root "/media/fotos".
0286      *          "/media/fotos" returns true, "/media/fotos/Paris 2007" and "/media" return false.
0287      * Only available (or hidden, but available) album roots are guaranteed to be found.
0288      */
0289     bool    isAlbumRoot(const QUrl& fileUrl);
0290 
0291     /**
0292      * The file path should not end with the directory slash. Using CoreDbUrl's method is fine.
0293      */
0294     bool    isAlbumRoot(const QString& filePath);
0295 
0296     //@{
0297     /**
0298      * Returns the album part of the given file path, i.e. the album root path
0299      * at the beginning is removed and the second part, starting with "/", ending without a slash,
0300      * is returned. Example: "/media/fotos/Paris 2007" gives "/Paris 2007"
0301      * Returns a null QString if the file path is not located in an album root.
0302      * Returns "/" if the file path is an album root.
0303      * Note that trailing slashes are removed in the return value, regardless if there was
0304      * one or not.
0305      * Note that you have to feed a path/url pointing to a directory. File names cannot
0306      * be recognized as such by this method, and will be treated as a directory.
0307      */
0308     QString album(const QUrl& fileUrl);
0309     QString album(const QString& filePath);
0310     QString album(const CollectionLocation& location, const QUrl& fileUrl);
0311     QString album(const CollectionLocation& location, const QString& filePath);
0312     //@}
0313 
0314     //@{
0315     /**
0316      * Returns just one album root, out of the list of available location,
0317      * the one that is most suitable to serve as a default, e.g.
0318      * to suggest as default place when the user wants to add files.
0319      */
0320     QUrl    oneAlbumRoot();
0321     QString oneAlbumRootPath();
0322     //@}
0323 
0324 private Q_SLOTS:
0325 
0326     void slotAlbumRootChange(const AlbumRootChangeset& changeset);
0327 
0328     //@}
0329 
0330 public:
0331 
0332     class Private;
0333 
0334 private:
0335 
0336     static CollectionManager* m_instance;
0337 
0338     Private* const d;
0339 
0340     friend class Private;
0341     friend class CoreDbWatch;
0342     friend class CoreDbAccess;
0343 };
0344 
0345 } // namespace Digikam
0346 
0347 #endif // DIGIKAM_COLLECTION_MANAGER_H