File indexing completed on 2025-01-19 03:53:24

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 - private containers.
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_P_H
0016 #define DIGIKAM_COLLECTION_MANAGER_P_H
0017 
0018 #include "collectionmanager.h"
0019 
0020 // Qt includes
0021 
0022 #include <QDir>
0023 #include <QDirIterator>
0024 #include <QCoreApplication>
0025 #include <QCryptographicHash>
0026 #include <QReadWriteLock>
0027 #include <QUrlQuery>
0028 #include <QThread>
0029 #include <QUuid>
0030 
0031 // KDE includes
0032 
0033 #include <klocalizedstring.h>
0034 
0035 // Solid includes
0036 
0037 #if defined(Q_CC_CLANG)
0038 #   pragma clang diagnostic push
0039 #   pragma clang diagnostic ignored "-Wnonportable-include-path"
0040 #endif
0041 
0042 #include <solid/device.h>
0043 #include <solid/deviceinterface.h>
0044 #include <solid/devicenotifier.h>
0045 #include <solid/storageaccess.h>
0046 #include <solid/storagedrive.h>
0047 #include <solid/storagevolume.h>
0048 #include <solid/opticaldisc.h>
0049 #include <solid/predicate.h>
0050 
0051 #if defined(Q_CC_CLANG)
0052 #   pragma clang diagnostic pop
0053 #endif
0054 
0055 // Local includes
0056 
0057 #include "digikam_debug.h"
0058 #include "coredbaccess.h"
0059 #include "coredbchangesets.h"
0060 #include "coredbtransaction.h"
0061 #include "coredb.h"
0062 #include "collectionscanner.h"
0063 #include "collectionlocation.h"
0064 #include "filereadwritelock.h"
0065 
0066 namespace Digikam
0067 {
0068 
0069 class Q_DECL_HIDDEN AlbumRootLocation : public CollectionLocation
0070 {
0071 
0072 public:
0073 
0074     AlbumRootLocation()
0075       : available(false),
0076         hidden   (false)
0077     {
0078     }
0079 
0080     explicit AlbumRootLocation(const AlbumRootInfo& info)
0081     {
0082         qCDebug(DIGIKAM_DATABASE_LOG) << "Creating new Location " << info.specificPath << " uuid " << info.identifier;
0083         m_id              = info.id;
0084         m_type            = (Type)info.type;
0085         QString path      = info.specificPath;
0086         m_caseSensitivity = (CaseSensitivity)info.caseSensitivity;
0087 
0088         if ((path != QLatin1String("/")) &&
0089             path.endsWith(QLatin1Char('/')))
0090         {
0091             path.chop(1);
0092         }
0093 
0094         specificPath = path;
0095         identifier   = info.identifier;
0096         m_label      = info.label;
0097 
0098         m_path.clear();
0099 
0100         setStatus((CollectionLocation::Status)info.status);
0101     }
0102 
0103     void setStatusFromFlags()
0104     {
0105         if (hidden)
0106         {
0107             m_status = CollectionLocation::LocationHidden;
0108         }
0109         else
0110         {
0111             if (available)
0112             {
0113                 m_status = CollectionLocation::LocationAvailable;
0114             }
0115             else
0116             {
0117                 m_status = CollectionLocation::LocationUnavailable;
0118             }
0119         }
0120     }
0121 
0122     void setCaseSensitivity(CollectionLocation::CaseSensitivity c)
0123     {
0124         m_caseSensitivity = c;
0125     }
0126 
0127     void setStatus(CollectionLocation::Status s)
0128     {
0129         m_status = s;
0130 
0131         // status is exclusive, and Hidden wins
0132         // but really both states are independent
0133         // - a hidden location might or might not be available
0134 
0135         if      (m_status == CollectionLocation::LocationAvailable)
0136         {
0137             available = true;
0138             hidden    = false;
0139         }
0140         else if (m_status == CollectionLocation::LocationHidden)
0141         {
0142             available = false;
0143             hidden    = true;
0144         }
0145         else // Unavailable, Null, Deleted
0146         {
0147             available = false;
0148             hidden    = false;
0149         }
0150     }
0151 
0152     void setId(int id)
0153     {
0154         m_id = id;
0155     }
0156 
0157     void setAbsolutePath(const QString& path)
0158     {
0159         m_path = path;
0160     }
0161 
0162     void setType(Type type)
0163     {
0164         m_type = type;
0165     }
0166 
0167     void setLabel(const QString& label)
0168     {
0169         m_label = label;
0170     }
0171 
0172 public:
0173 
0174     QString specificPath;
0175     bool    available;
0176     bool    hidden;
0177 };
0178 
0179 // -------------------------------------------------
0180 
0181 class Q_DECL_HIDDEN SolidVolumeInfo
0182 {
0183 
0184 public:
0185 
0186     SolidVolumeInfo()
0187         : isRemovable  (false),
0188           isOpticalDisc(false),
0189           isMounted    (false)
0190     {
0191     }
0192 
0193     bool isNull() const
0194     {
0195         return path.isNull();
0196     }
0197 
0198 public:
0199 
0200     QString udi;            ///< Solid device UDI of the StorageAccess device
0201     QString path;           ///< mount path of volume, with trailing slash
0202     QString uuid;           ///< UUID as from Solid
0203     QString label;          ///< volume label (think of CDs)
0204     bool    isRemovable;    ///< may be removed
0205     bool    isOpticalDisc;  ///< is an optical disk device as CD/DVD/BR
0206     bool    isMounted;      ///< is mounted on File System.
0207 };
0208 
0209 // -------------------------------------------------
0210 
0211 class Q_DECL_HIDDEN CollectionManager::Private
0212 {
0213 
0214 public:
0215 
0216     explicit Private(CollectionManager* const s);
0217 
0218     /// hack for Solid's threading problems
0219     QList<SolidVolumeInfo> actuallyListVolumes();
0220     void                   slotTriggerUpdateVolumesList();
0221     QList<SolidVolumeInfo> volumesListCache;
0222 
0223 
0224     /// Access Solid and return a list of storage volumes
0225     QList<SolidVolumeInfo> listVolumes();
0226 
0227     /**
0228      *  Find from a given list (usually the result of listVolumes) the volume
0229      *  corresponding to the location
0230      */
0231     SolidVolumeInfo findVolumeForLocation(const AlbumRootLocation* location, const QList<SolidVolumeInfo>& volumes);
0232 
0233     /**
0234      *  Find from a given list (usually the result of listVolumes) the volume
0235      *  on which the file path specified by the url is located.
0236      */
0237     SolidVolumeInfo findVolumeForUrl(const QUrl& fileUrl, const QList<SolidVolumeInfo>& volumes);
0238 
0239     /// Create the volume identifier for the given volume info
0240     QString volumeIdentifier(const SolidVolumeInfo& info);
0241 
0242     /// Create a volume identifier based on the path only
0243     QString volumeIdentifier(const QString& path);
0244 
0245     /// Create a network share identifier based on the mountpaths
0246     QString networkShareIdentifier(const QStringList& paths);
0247 
0248     /// Return the path, if location has a path-only identifier. Else returns a null string.
0249     QString pathFromIdentifier(const AlbumRootLocation* location);
0250 
0251     /// Return the path, if location has a path-only identifier. Else returns a null string.
0252     QStringList networkShareMountPathsFromIdentifier(const AlbumRootLocation* location);
0253 
0254     /// Create an MD5 hash of the top-level entries (file names, not file content) of the given path
0255     static QString directoryHash(const QString& path);
0256 
0257     /// Check if a location for specified path exists, assuming the given list of locations was deleted
0258     bool checkIfExists(const QString& path, QList<CollectionLocation> assumeDeleted);
0259 
0260     /// Make a user presentable description, regardless of current location status
0261     QString technicalDescription(const AlbumRootLocation* location);
0262 
0263      /// Get the file UUID in the collection root if possible.
0264     QString getCollectionUUID(const QString& path);
0265 
0266     /// Check or create the file UUID in the collection root if possible.
0267     bool checkCollectionUUID(AlbumRootLocation* const location, const QString& path);
0268 
0269 public:
0270 
0271     QReadWriteLock                lock;
0272     QMap<int, AlbumRootLocation*> locations;
0273     bool                          changingDB;
0274     QStringList                   udisToWatch;
0275     bool                          watchEnabled;
0276     CollectionManager*            s;
0277 };
0278 
0279 // -------------------------------------------------
0280 
0281 class Q_DECL_HIDDEN ChangingDB
0282 {
0283 
0284 public:
0285 
0286     explicit ChangingDB(CollectionManager::Private* const dd)
0287         : d(dd)
0288     {
0289         d->changingDB = true;
0290     }
0291 
0292     ~ChangingDB()
0293     {
0294         d->changingDB = false;
0295     }
0296 
0297 public:
0298 
0299     CollectionManager::Private* const d;
0300 };
0301 
0302 } // namespace Digikam
0303 
0304 #endif // DIGIKAM_COLLECTION_MANAGER_P_H