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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2012-05-22
0007  * Description : Qt model for camera entries
0008  *
0009  * SPDX-FileCopyrightText: 2012 by Islam Wazery <wazery at ubuntu dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #ifndef DIGIKAM_IMPORT_IMAGE_MODEL_H
0016 #define DIGIKAM_IMPORT_IMAGE_MODEL_H
0017 
0018 // Qt includes
0019 
0020 #include <QAbstractListModel>
0021 #include <QUrl>
0022 
0023 // Local includes
0024 
0025 #include "dragdropimplementations.h"
0026 #include "camerathumbsctrl.h"
0027 #include "camiteminfo.h"
0028 
0029 namespace Digikam
0030 {
0031 class AbstractItemDragDropHandler;
0032 
0033 class ImportItemModel : public QAbstractListModel, public DragDropModelImplementation
0034 {
0035     Q_OBJECT
0036 
0037 public:
0038 
0039     enum ImportItemModelRoles
0040     {
0041         /**
0042          * An ImportItemModel* pointer to this model
0043          */
0044         ImportItemModelPointerRole = Qt::UserRole,
0045         ImportItemModelInternalId  = Qt::UserRole + 1,
0046 
0047         /**
0048          * Returns a thumbnail pixmap. May be implemented by subclasses.
0049          * Returns either a valid pixmap or a null QVariant.
0050          */
0051         ThumbnailRole               = Qt::UserRole + 2,
0052         /**
0053          * Return (optional) extraData field
0054          */
0055         ExtraDataRole               = Qt::UserRole + 3,
0056 
0057         /**
0058          * Returns the number of duplicate indexes for the same image id
0059          */
0060         ExtraDataDuplicateCount     = Qt::UserRole + 6,
0061 
0062         FilterModelRoles            = Qt::UserRole + 100
0063     };
0064 
0065 public:
0066 
0067     explicit ImportItemModel(QObject* const parent = nullptr);
0068     ~ImportItemModel() override;
0069 
0070     /**
0071      * Used to set the camera controller, and connect with it.
0072      */
0073     virtual void setCameraThumbsController(CameraThumbsCtrl* const controller);
0074 
0075     /**
0076      * If a cache is kept, lookup by file path is fast,
0077      * without a cache it is O(n). Default is false.
0078      */
0079     void setKeepsFileUrlCache(bool keepCache);
0080     bool keepsFileUrlCache() const;
0081 
0082     /**
0083      * Returns the CamItemInfo object, reference from the underlying data pointed to by the index.
0084      * For camItemInfo and camItemInfoId If the index is not valid they will return a null CamItemInfo, and 0
0085      * respectively, camItemInfoRef must not be called with an invalid index as it will crash.
0086      */
0087     CamItemInfo      camItemInfo(const QModelIndex& index)           const;
0088     CamItemInfo&     camItemInfoRef(const QModelIndex& index)        const;
0089     qlonglong        camItemId(const QModelIndex& index)             const;
0090     CamItemInfoList  camItemInfos(const QList<QModelIndex>& indexes) const;
0091     QList<qlonglong> camItemIds(const QList<QModelIndex>& indexes)   const;
0092 
0093     /**
0094      * Returns the CamItemInfo object, reference from the underlying data of
0095      * the given row (parent is the invalid QModelIndex, column is 0).
0096      * Note that camItemInfoRef must not be called with an invalid index as it will crash.
0097      */
0098     CamItemInfo  camItemInfo(int row)    const;
0099     CamItemInfo& camItemInfoRef(int row) const;
0100     qlonglong    camItemId(int row)      const;
0101 
0102     /**
0103      * Return the index of a given CamItemInfo, if it exists in the model.
0104      */
0105     QModelIndex        indexForCamItemInfo(const CamItemInfo& info)   const;
0106     QList<QModelIndex> indexesForCamItemInfo(const CamItemInfo& info) const;
0107     QModelIndex        indexForCamItemId(qlonglong id)                const;
0108     QList<QModelIndex> indexesForCamItemId(qlonglong id)              const;
0109 
0110     /**
0111      * Returns the index or CamItemInfo object from the underlying data for
0112      * the given file url. In case of multiple occurrences of the same file, the simpler
0113      * overrides returns any one found first, use the QList methods to retrieve all occurrences.
0114      */
0115     QModelIndex        indexForUrl(const QUrl& fileUrl)   const;
0116     QList<QModelIndex> indexesForUrl(const QUrl& fileUrl) const;
0117     CamItemInfo        camItemInfo(const QUrl& fileUrl)   const;
0118     QList<CamItemInfo> camItemInfos(const QUrl& fileUrl)  const;
0119 
0120     /**
0121      * Clears the CamItemInfos and resets the model.
0122      */
0123     void clearCamItemInfos();
0124 
0125     /**
0126      * addCamItemInfo() is asynchronous if a prepocessor is set.
0127      * This method first adds the info, synchronously.
0128      * Only afterwards, the preprocessor will have the opportunity to process it.
0129      * This method also bypasses any incremental updates.
0130      */
0131     void addCamItemInfoSynchronously(const CamItemInfo& info);
0132     void addCamItemInfosSynchronously(const Digikam::CamItemInfoList& infos);
0133 
0134     /**
0135      * Clears and adds infos.
0136      */
0137     void setCamItemInfos(const CamItemInfoList& infos);
0138 
0139     QList<CamItemInfo> camItemInfos()       const;
0140     QList<qlonglong>   camItemIds()         const;
0141     QList<CamItemInfo> uniqueCamItemInfos() const;
0142 
0143     bool hasImage(qlonglong id)             const;
0144     bool hasImage(const CamItemInfo& info)  const;
0145 
0146     bool isEmpty()                          const;
0147 
0148     /**
0149      * Remove the given infos or indexes directly from the model.
0150      */
0151     void removeIndex(const QModelIndex& index);
0152     void removeIndexs(const QList<QModelIndex>& indexes);
0153     void removeCamItemInfo(const CamItemInfo& info);
0154     void removeCamItemInfos(const QList<CamItemInfo>& infos);
0155 
0156     int numberOfIndexesForCamItemInfo(const CamItemInfo& info) const;
0157     int numberOfIndexesForCamItemId(qlonglong id)              const;
0158 
0159     /**
0160      * Retrieve the CamItemInfo object from the data() function of the given index
0161      * The index may be from a QSortFilterProxyModel as long as an ImportItemModel is at the end.
0162      */
0163     static CamItemInfo retrieveCamItemInfo(const QModelIndex& index);
0164     static qlonglong   retrieveCamItemId(const QModelIndex& index);
0165 
0166     /// QAbstractListModel implementation
0167     int           rowCount(const QModelIndex& parent)                            const override;
0168     QVariant      data(const QModelIndex& index, int role)                       const override;
0169     QVariant      headerData(int section, Qt::Orientation orientation, int role) const override;
0170     Qt::ItemFlags flags(const QModelIndex& index)                                const override;
0171     QModelIndex   index(int row, int column, const QModelIndex& parent)          const override;
0172 
0173     /// DragDrop methods
0174     DECLARE_MODEL_DRAG_DROP_METHODS
0175 
0176     /**
0177      * Enable sending of itemInfosAboutToBeRemoved and itemsInfosRemoved signals.
0178      * Default: false
0179      */
0180     void setSendRemovalSignals(bool send);
0181 
0182     /**
0183      * Returns true if this model is currently refreshing.
0184      * For a preprocessor this means that, although the preprocessor may currently have
0185      * processed all it got, more batches are to be expected.
0186      */
0187     bool isRefreshing() const;
0188 
0189 Q_SIGNALS:
0190 
0191     /**
0192      * Informs that ItemInfos will be added to the model.
0193      * This signal is sent before the model data is changed and views are informed.
0194      */
0195     void itemInfosAboutToBeAdded(const QList<CamItemInfo>& infos);
0196 
0197     /**
0198      * Informs that ItemInfos have been added to the model.
0199      * This signal is sent after the model data is changed and views are informed.
0200      */
0201     void itemInfosAdded(const QList<CamItemInfo>& infos);
0202 
0203     /**
0204      * Informs that CamItemInfos will be removed from the model.
0205      * This signal is sent before the model data is changed and views are informed.
0206      * Note: You need to explicitly enable sending of this signal. It is not sent
0207      * in clearCamItemInfos().
0208      */
0209     void itemInfosAboutToBeRemoved(const QList<CamItemInfo>& infos);
0210 
0211     /**
0212      * Informs that CamItemInfos have been removed from the model.
0213      * This signal is sent after the model data is changed and views are informed.
0214      * Note: You need to explicitly enable sending of this signal. It is not sent
0215      * in clearCamItemInfos().
0216      */
0217     void itemInfosRemoved(const QList<CamItemInfo>& infos);
0218 
0219     /**
0220      * Connect to this signal only if you are the current preprocessor.
0221      */
0222     void preprocess(const QList<CamItemInfo>& infos);
0223     void processAdded(const QList<CamItemInfo>& infos);
0224 
0225     /**
0226      * Signals that the model is right now ready to start an incremental refresh.
0227      * This is guaranteed only for the scope of emitting this signal.
0228      */
0229     void readyForIncrementalRefresh();
0230 
0231     /**
0232      * Signals that the model has finished currently with all scheduled
0233      * refreshing, full or incremental, and all preprocessing.
0234      * The model is in polished, clean situation right now.
0235      */
0236     void allRefreshingFinished();
0237 
0238 public Q_SLOTS:
0239 
0240     void reAddCamItemInfos(const CamItemInfoList& infos);
0241     void reAddingFinished();
0242     void slotFileDeleted(const QString& folder, const QString& file, bool status);
0243     void slotFileUploaded(const CamItemInfo& info);
0244     void addCamItemInfo(const CamItemInfo& info);
0245     void addCamItemInfos(const CamItemInfoList& infos);
0246 
0247 protected:
0248 
0249     /**
0250      * Subclasses that add CamItemInfos in batches shall call startRefresh()
0251      * when they start sending batches and finishRefresh() when they have finished.
0252      * No incremental refreshes will be started while listing.
0253      * A clearCamItemInfos() always stops listing, calling finishRefresh() is then not necessary.
0254      */
0255     void startRefresh();
0256     void finishRefresh();
0257 
0258     /**
0259      * As soon as the model is ready to start an incremental refresh, the signal
0260      * readyForIncrementalRefresh() will be emitted. The signal will be emitted inline
0261      * if the model is ready right now.
0262      */
0263     void requestIncrementalRefresh();
0264     bool hasIncrementalRefreshPending() const;
0265 
0266     /**
0267      * Starts an incremental refresh operation. You shall only call this method from a slot
0268      * connected to readyForIncrementalRefresh(). To initiate an incremental refresh,
0269      * call requestIncrementalRefresh().
0270      */
0271     void startIncrementalRefresh();
0272     void finishIncrementalRefresh();
0273 
0274     void emitDataChangedForAll();
0275     void emitDataChangedForSelections(const QItemSelection& selection);
0276 
0277     /**
0278      * Called when the internal storage is cleared.
0279      */
0280     virtual void camItemInfosCleared() {};
0281 
0282     /**
0283      * Called before rowsAboutToBeRemoved
0284      */
0285     virtual void itemInfosAboutToBeRemoved(int /*begin*/, int /*end*/) {};
0286 
0287 private:
0288 
0289     void appendInfos(const CamItemInfoList& infos);
0290     void publiciseInfos(const CamItemInfoList& infos);
0291     void cleanSituationChecks();
0292     void removeRowPairs(const QList<QPair<int, int> >& toRemove);
0293     void removeRowPairsWithCheck(const QList<QPair<int, int> >& toRemove);
0294 
0295 public:
0296 
0297     // NOTE: Declared public because it's used in ItemModelIncrementalUpdater class
0298     class Private;
0299 
0300 private:
0301 
0302     // Disable
0303     ImportItemModel(const ImportItemModel&)            = delete;
0304     ImportItemModel& operator=(const ImportItemModel&) = delete;
0305 
0306 private:
0307 
0308     Private* const d;
0309 };
0310 
0311 } // namespace Digikam
0312 
0313 Q_DECLARE_METATYPE(Digikam::ImportItemModel*)
0314 
0315 #endif // DIGIKAM_IMPORT_IMAGE_MODEL_H