File indexing completed on 2025-01-05 03:54:12
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-03-05 0007 * Description : Qt item model for database entries 0008 * 0009 * SPDX-FileCopyrightText: 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #ifndef DIGIKAM_ITEM_MODEL_H 0017 #define DIGIKAM_ITEM_MODEL_H 0018 0019 // Qt includes 0020 0021 #include <QAbstractListModel> 0022 0023 // Local includes 0024 0025 #include "dragdropimplementations.h" 0026 #include "iteminfo.h" 0027 #include "digikam_export.h" 0028 0029 class QItemSelection; 0030 0031 namespace Digikam 0032 { 0033 0034 class AlbumChangeset; 0035 class ImageChangeset; 0036 class ImageTagChangeset; 0037 0038 namespace DatabaseFields 0039 { 0040 class Set; 0041 } 0042 0043 class DIGIKAM_DATABASE_EXPORT ItemModel : public QAbstractListModel, 0044 public DragDropModelImplementation 0045 { 0046 Q_OBJECT 0047 0048 public: 0049 0050 enum ItemModelRoles 0051 { 0052 /** 0053 * An ItemModel* pointer to this model 0054 */ 0055 ItemModelPointerRole = Qt::UserRole, 0056 ItemModelInternalId = Qt::UserRole + 1, 0057 0058 /** 0059 * Returns a thumbnail pixmap. May be implemented by subclasses. 0060 * Returns either a valid pixmap or a null QVariant. 0061 */ 0062 ThumbnailRole = Qt::UserRole + 2, 0063 0064 /** 0065 * Returns a QDateTime with the creation date 0066 */ 0067 CreationDateRole = Qt::UserRole + 3, 0068 0069 /** 0070 * Return (optional) extraData field 0071 */ 0072 ExtraDataRole = Qt::UserRole + 5, 0073 0074 /** 0075 * Returns the number of duplicate indexes for the same image id 0076 */ 0077 ExtraDataDuplicateCount = Qt::UserRole + 6, 0078 0079 /** 0080 * Roles which are defined here but not implemented by ItemModel 0081 * Returns position of item in Left Light Table preview. 0082 */ 0083 LTLeftPanelRole = Qt::UserRole + 50, 0084 0085 /** 0086 * Returns position of item in Right Light Table preview. 0087 */ 0088 LTRightPanelRole = Qt::UserRole + 51, 0089 0090 /** 0091 * For use by subclasses 0092 */ 0093 SubclassRoles = Qt::UserRole + 100, 0094 0095 /** 0096 * For use by filter models 0097 */ 0098 FilterModelRoles = Qt::UserRole + 500 0099 }; 0100 0101 public: 0102 0103 explicit ItemModel(QObject* const parent = nullptr); 0104 ~ItemModel() override; 0105 0106 /** 0107 * If a cache is kept, lookup by file path is fast, 0108 * without a cache it is O(n). Default is false. 0109 */ 0110 void setKeepsFilePathCache(bool keepCache); 0111 bool keepsFilePathCache() const; 0112 0113 /** 0114 * Set a set of database fields to watch. 0115 * If either of these is changed, dataChanged() will be emitted. 0116 * Default is no flag (no signal will be emitted). 0117 */ 0118 void setWatchFlags(const DatabaseFields::Set& set); 0119 0120 /** 0121 * Returns the ItemInfo object, reference or image id from the underlying data 0122 * pointed to by the index. 0123 * If the index is not valid, imageInfo will return a null ItemInfo, imageId will 0124 * return 0, imageInfoRef must not be called with an invalid index. 0125 */ 0126 ItemInfo imageInfo(const QModelIndex& index) const; 0127 ItemInfo& imageInfoRef(const QModelIndex& index) const; 0128 qlonglong imageId(const QModelIndex& index) const; 0129 QList<ItemInfo> imageInfos(const QList<QModelIndex>& indexes) const; 0130 QList<qlonglong> imageIds(const QList<QModelIndex>& indexes) const; 0131 0132 /** 0133 * Returns the ItemInfo object, reference or image id from the underlying data 0134 * of the given row (parent is the invalid QModelIndex, column is 0). 0135 * Note that imageInfoRef will crash if index is invalid. 0136 */ 0137 ItemInfo imageInfo(int row) const; 0138 ItemInfo& imageInfoRef(int row) const; 0139 qlonglong imageId(int row) const; 0140 0141 /** 0142 * Return the index for the given ItemInfo or id, if contained in this model. 0143 */ 0144 QModelIndex indexForItemInfo(const ItemInfo& info) const; 0145 QModelIndex indexForItemInfo(const ItemInfo& info, const QVariant& extraValue) const; 0146 QModelIndex indexForImageId(qlonglong id) const; 0147 QModelIndex indexForImageId(qlonglong id, const QVariant& extraValue) const; 0148 QList<QModelIndex> indexesForItemInfo(const ItemInfo& info) const; 0149 QList<QModelIndex> indexesForImageId(qlonglong id) const; 0150 0151 int numberOfIndexesForItemInfo(const ItemInfo& info) const; 0152 int numberOfIndexesForImageId(qlonglong id) const; 0153 0154 /** 0155 * Returns the index or ItemInfo object from the underlying data 0156 * for the given file path. This is fast if keepsFilePathCache is enabled. 0157 * The file path is as returned by ItemInfo.filePath(). 0158 * In case of multiple occurrences of the same file, the simpler variants return 0159 * any one found first, use the QList methods to retrieve all occurrences. 0160 */ 0161 QModelIndex indexForPath(const QString& filePath) const; 0162 ItemInfo imageInfo(const QString& filePath) const; 0163 QList<QModelIndex> indexesForPath(const QString& filePath) const; 0164 QList<ItemInfo> imageInfos(const QString& filePath) const; 0165 0166 /** 0167 * Main entry point for subclasses adding image infos to the model. 0168 * If you list entries not unique per image id, you must add an extraValue 0169 * so that every entry is unique by imageId and extraValues. 0170 * Please note that these methods do not prevent addition of duplicate entries. 0171 */ 0172 void addItemInfo(const ItemInfo& info); 0173 void addItemInfos(const QList<ItemInfo>& infos); 0174 void addItemInfos(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0175 0176 /** 0177 * Clears image infos and resets model. 0178 */ 0179 void clearItemInfos(); 0180 0181 /** 0182 * Clears and adds the infos. 0183 */ 0184 void setItemInfos(const QList<ItemInfo>& infos); 0185 0186 /** 0187 * Directly remove the given indexes or infos from the model. 0188 */ 0189 void removeIndex(const QModelIndex& indexes); 0190 void removeIndexes(const QList<QModelIndex>& indexes); 0191 void removeItemInfo(const ItemInfo& info); 0192 void removeItemInfos(const QList<ItemInfo>& infos); 0193 void removeItemInfos(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0194 0195 /** 0196 * addItemInfo() is asynchronous if a prepocessor is set. 0197 * This method first adds the info, synchronously. 0198 * Only afterwards, the preprocessor will have the opportunity to process it. 0199 * This method also bypasses any incremental updates. 0200 * Please note that these methods do not prevent addition of duplicate entries. 0201 */ 0202 void addItemInfoSynchronously(const ItemInfo& info); 0203 void addItemInfosSynchronously(const QList<ItemInfo>& infos); 0204 void addItemInfosSynchronously(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0205 0206 /** 0207 * Add the given entries. Method returns immediately, the 0208 * addition may happen later asynchronously. 0209 * These methods prevent the addition of duplicate entries. 0210 */ 0211 void ensureHasItemInfo(const ItemInfo& info); 0212 void ensureHasItemInfos(const QList<ItemInfo>& infos); 0213 void ensureHasItemInfos(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0214 0215 /** 0216 * Ensure that all images grouped on the given leader are contained in the model. 0217 */ 0218 void ensureHasGroupedImages(const ItemInfo& groupLeader); 0219 0220 QList<ItemInfo> imageInfos() const; 0221 QList<qlonglong> imageIds() const; 0222 QList<ItemInfo> uniqueItemInfos() const; 0223 0224 bool hasImage(qlonglong id) const; 0225 bool hasImage(const ItemInfo& info) const; 0226 bool hasImage(const ItemInfo& info, const QVariant& extraValue) const; 0227 bool hasImage(qlonglong id, const QVariant& extraValue) const; 0228 0229 bool isEmpty() const; 0230 int itemCount() const; 0231 0232 // Drag and Drop 0233 DECLARE_MODEL_DRAG_DROP_METHODS 0234 0235 /** 0236 * Install an object as a preprocessor for ItemInfos added to this model. 0237 * For every QList of ItemInfos added to addItemInfo, the signal preprocess() 0238 * will be emitted. The preprocessor may process the items and shall then readd 0239 * them by calling reAddItemInfos(). It may take some time to process. 0240 * It shall discard any held infos when the modelReset() signal is sent. 0241 * It shall call readdFinished() when no reset occurred and all infos on the way have been readded. 0242 * This means that only after calling this method, you shall make three connections 0243 * (preprocess -> your slot, your signal -> reAddItemInfos, your signal -> reAddingFinished) 0244 * and make or already hold a connection modelReset() -> your slot. 0245 * There is only one preprocessor at a time, a previously set object will be disconnected. 0246 */ 0247 void setPreprocessor(QObject* const processor); 0248 void unsetPreprocessor(QObject* const processor); 0249 0250 /** 0251 * Returns true if this model is currently refreshing. 0252 * For a preprocessor this means that, although the preprocessor may currently have 0253 * processed all it got, more batches are to be expected. 0254 */ 0255 bool isRefreshing() const; 0256 0257 /** 0258 * Enable sending of imageInfosAboutToBeRemoved and imageInfosRemoved signals. 0259 * Default: false 0260 */ 0261 void setSendRemovalSignals(bool send); 0262 0263 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 0264 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 0265 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 0266 Qt::ItemFlags flags(const QModelIndex& index) const override; 0267 QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const override; 0268 0269 /** 0270 * Retrieves the imageInfo object from the data() method of the given index. 0271 * The index may be from a QSortFilterProxyModel as long as an ItemModel is at the end. 0272 */ 0273 static ItemInfo retrieveItemInfo(const QModelIndex& index); 0274 static qlonglong retrieveImageId(const QModelIndex& index); 0275 0276 Q_SIGNALS: 0277 0278 /** 0279 * Informs that ItemInfos will be added to the model. 0280 * This signal is sent before the model data is changed and views are informed. 0281 */ 0282 void imageInfosAboutToBeAdded(const QList<ItemInfo>& infos); 0283 0284 /** 0285 * Informs that ItemInfos have been added to the model. 0286 * This signal is sent after the model data is changed and views are informed. 0287 */ 0288 void imageInfosAdded(const QList<ItemInfo>& infos); 0289 0290 /** 0291 * Informs that ItemInfos will be removed from the model. 0292 * This signal is sent before the model data is changed and views are informed. 0293 * Note: You need to explicitly enable sending of this signal. It is not sent 0294 * in clearItemInfos(). 0295 */ 0296 void imageInfosAboutToBeRemoved(const QList<ItemInfo>& infos); 0297 0298 /** 0299 * Informs that ItemInfos have been removed from the model. 0300 * This signal is sent after the model data is changed and views are informed. * 0301 * Note: You need to explicitly enable sending of this signal. It is not sent 0302 * in clearItemInfos(). 0303 */ 0304 void imageInfosRemoved(const QList<ItemInfo>& infos); 0305 0306 /** 0307 * Connect to this signal only if you are the current preprocessor. 0308 */ 0309 void preprocess(const QList<ItemInfo>& infos, const QList<QVariant>&); 0310 void processAdded(const QList<ItemInfo>& infos, const QList<QVariant>&); 0311 0312 /** 0313 * If an ImageChangeset affected indexes of this model with changes as set in watchFlags(), 0314 * this signal contains the changeset and the affected indexes. 0315 */ 0316 void imageChange(const ImageChangeset&, const QItemSelection&); 0317 0318 /** 0319 * If an ImageTagChangeset affected indexes of this model, 0320 * this signal contains the changeset and the affected indexes. 0321 */ 0322 void imageTagChange(const ImageTagChangeset&, const QItemSelection&); 0323 0324 /** 0325 * Signals that the model is right now ready to start an incremental refresh. 0326 * This is guaranteed only for the scope of emitting this signal. 0327 */ 0328 void readyForIncrementalRefresh(); 0329 0330 /** 0331 * Signals that the model has finished currently with all scheduled 0332 * refreshing, full or incremental, and all preprocessing. 0333 * The model is in polished, clean situation right now. 0334 */ 0335 void allRefreshingFinished(); 0336 0337 public Q_SLOTS: 0338 0339 void reAddItemInfos(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0340 void reAddingFinished(); 0341 0342 protected: 0343 0344 /** 0345 * Subclasses that add ItemInfos in batches shall call startRefresh() 0346 * when they start sending batches and finishRefresh() when they have finished. 0347 * No incremental refreshes will be started while listing. 0348 * A clearItemInfos() always stops listing, calling finishRefresh() is then not necessary. 0349 */ 0350 void startRefresh(); 0351 void finishRefresh(); 0352 0353 /** 0354 * As soon as the model is ready to start an incremental refresh, the signal 0355 * readyForIncrementalRefresh() will be emitted. The signal will be emitted inline 0356 * if the model is ready right now. 0357 */ 0358 void requestIncrementalRefresh(); 0359 bool hasIncrementalRefreshPending() const; 0360 0361 /** 0362 * Starts an incremental refresh operation. You shall only call this method from a slot 0363 * connected to readyForIncrementalRefresh(). To initiate an incremental refresh, 0364 * call requestIncrementalRefresh(). 0365 */ 0366 void startIncrementalRefresh(); 0367 void finishIncrementalRefresh(); 0368 0369 void emitDataChangedForAll(); 0370 void emitDataChangedForSelection(const QItemSelection& selection); 0371 0372 /** 0373 * Called when the internal storage is cleared 0374 */ 0375 virtual void imageInfosCleared() {}; 0376 0377 /** 0378 * Called before rowsAboutToBeRemoved 0379 */ 0380 virtual void imageInfosAboutToBeRemoved(int /*begin*/, int /*end*/) {}; 0381 0382 protected Q_SLOTS: 0383 0384 virtual void slotAlbumChange(const AlbumChangeset& changeset); 0385 virtual void slotImageChange(const ImageChangeset& changeset); 0386 virtual void slotImageTagChange(const ImageTagChangeset& changeset); 0387 0388 private: 0389 0390 void appendInfos(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0391 void appendInfosChecked(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0392 void publiciseInfos(const QList<ItemInfo>& infos, const QList<QVariant>& extraValues); 0393 void cleanSituationChecks(); 0394 void removeRowPairsWithCheck(const QList<QPair<int, int> >& toRemove); 0395 void removeRowPairs(const QList<QPair<int, int> >& toRemove); 0396 0397 public: 0398 0399 // Declared public because it's used in ItemModelIncrementalUpdater class 0400 class Private; 0401 0402 private: 0403 0404 // Disable 0405 ItemModel(const ItemModel&) = delete; 0406 ItemModel& operator=(const ItemModel&) = delete; 0407 0408 Private* const d; 0409 }; 0410 0411 } // namespace Digikam 0412 0413 Q_DECLARE_METATYPE(Digikam::ItemModel*) 0414 0415 #endif // DIGIKAM_ITEM_MODEL_H