1 /* ============================================================ 2 * 3 * This file is a part of digiKam project 4 * https://www.digikam.org 5 * 6 * Date : 2009-03-23 7 * Description : Qt Model for Albums 8 * 9 * Copyright (C) 2008-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 10 * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com> 11 * Copyright (C) 2012-2021 by Gilles Caulier <caulier dot gilles at gmail dot com> 12 * 13 * This program is free software; you can redistribute it 14 * and/or modify it under the terms of the GNU General 15 * Public License as published by the Free Software Foundation; 16 * either version 2, or (at your option) 17 * any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * ============================================================ */ 25 26 #ifndef DIGIKAM_ABSTRACT_ALBUM_MODEL_H 27 #define DIGIKAM_ABSTRACT_ALBUM_MODEL_H 28 29 // Qt includes 30 31 #include <QAbstractItemModel> 32 #include <QHash> 33 #include <QPixmap> 34 #include <QSet> 35 36 // Local includes 37 38 #include "album.h" 39 #include "digikam_export.h" 40 41 namespace Digikam 42 { 43 44 class Album; 45 class AlbumManager; 46 class AlbumModelDragDropHandler; 47 48 class DIGIKAM_GUI_EXPORT AbstractAlbumModel : public QAbstractItemModel 49 { 50 Q_OBJECT 51 52 public: 53 54 /** 55 * AbstractAlbumModel is the abstract base class for all models that 56 * present Album objects as managed by AlbumManager. 57 * You will want to create an instance of the base classes. 58 */ 59 enum RootAlbumBehavior 60 { 61 /** 62 * The root album will be included as a single parent item 63 * with all top-level album as children 64 */ 65 IncludeRootAlbum, 66 /** 67 * The root album will not be included, but all top-level album 68 * are represented as top-level items in this view 69 */ 70 IgnoreRootAlbum 71 }; 72 73 enum AlbumDataRole 74 { 75 /// Returns the album title. Principally the same as display role, but without any additions. 76 AlbumTitleRole = Qt::UserRole, 77 /// Returns the Album::Type of the associated album 78 AlbumTypeRole = Qt::UserRole + 1, 79 /// Returns a pointer to the associated Album object 80 AlbumPointerRole = Qt::UserRole + 2, 81 /// Returns the id of the associated Album object 82 AlbumIdRole = Qt::UserRole + 3, 83 /// Returns the global id (unique across all album types) 84 AlbumGlobalIdRole = Qt::UserRole + 4, 85 /// Returns the data to sort on 86 AlbumSortRole = Qt::UserRole + 5 87 }; 88 89 public: 90 91 /** 92 * Create an AbstractAlbumModel object for albums with the given type. 93 * Pass the root album if it is already available. 94 * Do not use this class directly, but one of the subclasses. 95 */ 96 explicit AbstractAlbumModel(Album::Type albumType, 97 Album* const rootAlbum, 98 RootAlbumBehavior rootBehavior = IncludeRootAlbum, 99 QObject* const parent = nullptr); 100 ~AbstractAlbumModel() override; 101 102 /** 103 * Set a drag drop handler 104 */ 105 void setDragDropHandler(AlbumModelDragDropHandler* handler); 106 107 /** 108 * Returns the drag drop handler, or 0 if none is installed 109 */ 110 AlbumModelDragDropHandler* dragDropHandler() const; 111 112 /** 113 * Returns the album object associated with the given model index 114 */ 115 Album* albumForIndex(const QModelIndex& index) const; 116 117 /** 118 * Return the QModelIndex for the given album, or an invalid index if 119 * the album is not contained in this model. 120 */ 121 QModelIndex indexForAlbum(Album* album) const; 122 123 /** 124 * Returns the album represented by the index. In contrast to albumForIndex(), 125 * the index can be from any proxy model, as long as an AbstractAlbumModel is at the end. 126 */ 127 static Album* retrieveAlbum(const QModelIndex& index); 128 129 Album* rootAlbum() const; 130 131 /** 132 * Return the index corresponding to the root album. If the policy is IgnoreRootAlbum, this is an invalid index. 133 */ 134 QModelIndex rootAlbumIndex() const; 135 136 /** 137 * Returns the root album behavior set for this model 138 */ 139 RootAlbumBehavior rootAlbumBehavior() const; 140 141 /** 142 * Returns the Album::Type of the contained albums 143 */ 144 Album::Type albumType() const; 145 146 /** 147 * Returns true if the album model a face tag model 148 */ 149 bool isFaceTagModel() const; 150 151 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 152 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 153 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 154 int columnCount(const QModelIndex& parent = QModelIndex()) const override; 155 Qt::ItemFlags flags(const QModelIndex& index) const override; 156 bool hasChildren(const QModelIndex& parent = QModelIndex()) const override; 157 QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; 158 QModelIndex parent(const QModelIndex& index) const override; 159 160 Qt::DropActions supportedDropActions() const override; 161 QStringList mimeTypes() const override; 162 bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; 163 QMimeData* mimeData(const QModelIndexList& indexes) const override; 164 165 Q_SIGNALS: 166 167 /** 168 * This is initialized once after creation, if the root album becomes available, 169 * if it was not already available at time of construction. 170 * This is emitted regardless of root album policy. 171 */ 172 void rootAlbumAvailable(); 173 174 protected: 175 176 /** 177 * Switch on drag and drop globally for all items. Default is true. 178 * For per-item cases reimplement itemFlags(). 179 */ 180 void setEnableDrag(bool enable); 181 void setEnableDrop(bool enable); 182 void setFaceTagModel(bool enable); 183 184 /** 185 * NOTE: these can be reimplemented in a subclass 186 */ 187 188 /// For subclassing convenience: A part of the implementation of data() 189 virtual QVariant albumData(Album* a, int role) const; 190 191 /// For subclassing convenience: A part of the implementation of data() 192 virtual QVariant decorationRoleData(Album* a) const; 193 194 /// For subclassing convenience: A part of the implementation of data() 195 virtual QVariant fontRoleData(Album* a) const; 196 197 /// For subclassing convenience: A part of the implementation of data() 198 virtual QVariant sortRoleData(Album* a) const; 199 200 /// For subclassing convenience: A part of the implementation of headerData() 201 virtual QString columnHeader() const; 202 203 /// For subclassing convenience: A part of the implementation of itemFlags() 204 virtual Qt::ItemFlags itemFlags(Album* album) const; 205 206 /** 207 * Returns true for those and only those albums that shall be contained in this model. 208 * They must have a common root album, which is set in the constructor. 209 */ 210 virtual bool filterAlbum(Album* album) const; 211 212 /// Notification when an entry is removed albumCleared(Album *)213 virtual void albumCleared(Album* /*album*/) {}; 214 215 /// Notification when all entries are removed allAlbumsCleared()216 virtual void allAlbumsCleared() {}; 217 218 protected Q_SLOTS: 219 220 void slotAlbumAboutToBeAdded(Album* album, Album* parent, Album* prev); 221 void slotAlbumAdded(Album*); 222 void slotAlbumAboutToBeDeleted(Album* album); 223 void slotAlbumHasBeenDeleted(quintptr); 224 void slotAlbumsCleared(); 225 void slotAlbumIconChanged(Album* album); 226 void slotAlbumRenamed(Album* album); 227 228 private: 229 230 class Private; 231 Private* const d; 232 }; 233 234 // ------------------------------------------------------------------ 235 236 class DIGIKAM_GUI_EXPORT AbstractSpecificAlbumModel : public AbstractAlbumModel 237 { 238 Q_OBJECT 239 240 public: 241 242 /// Abstract base class, do not instantiate. 243 explicit AbstractSpecificAlbumModel(Album::Type albumType, 244 Album* const rootAlbum, 245 RootAlbumBehavior rootBehavior = IncludeRootAlbum, 246 QObject* const parent = nullptr); 247 248 protected: 249 250 QString columnHeader() const override; 251 void setColumnHeader(const QString& header); 252 253 /// You need to call this from your constructor if you intend to load the thumbnail facilities of this class 254 void setupThumbnailLoading(); 255 void emitDataChangedForChildren(Album* album); 256 257 protected Q_SLOTS: 258 259 void slotGotThumbnailFromIcon(Album* album, const QPixmap& thumbnail); 260 void slotThumbnailLost(Album* album); 261 void slotReloadThumbnails(); 262 263 protected: 264 265 QString m_columnHeader; 266 }; 267 268 // ------------------------------------------------------------------ 269 270 class DIGIKAM_GUI_EXPORT AbstractCountingAlbumModel : public AbstractSpecificAlbumModel 271 { 272 Q_OBJECT 273 274 public: 275 276 /// Supports displaying a count alongside the album name in DisplayRole 277 278 explicit AbstractCountingAlbumModel(Album::Type albumType, 279 Album* const rootAlbum, 280 RootAlbumBehavior rootBehavior = IncludeRootAlbum, 281 QObject* const parent = nullptr); 282 ~AbstractCountingAlbumModel() override; 283 284 bool showCount() const; 285 286 /** 287 * Returns the number of included items for this album. 288 * 289 * @return positive value or -1 if unknown 290 */ 291 virtual int albumCount(Album* album) const; 292 293 protected: 294 295 /** 296 * Call this method in children class contructors to init signal/slots connections. 297 */ 298 void setup(); 299 300 public Q_SLOTS: 301 302 /// Call to enable or disable showing the count. Default is false. 303 void setShowCount(bool show); 304 305 /** 306 * Enable displaying the count. Set a map of album id -> count (excluding children). 307 * If an album is not contained, no count is displayed. To display a count of 0, 308 * there must be an entry album id -> 0. 309 */ 310 void setCountMap(const QMap<int, int>& idCountMap); 311 312 /** 313 * Displays only the count of the album, without adding child albums' counts. 314 * This is the default. 315 * Can connect to QTreeView's expanded() signal. 316 */ 317 void excludeChildrenCount(const QModelIndex& index); 318 319 /** 320 * Displays sum of the count of the album and child albums' counts. 321 * Can connect to QTreeView's collapsed() signal. 322 */ 323 void includeChildrenCount(const QModelIndex& index); 324 325 protected: 326 327 /// If you do not use setCountMap, excludeChildrenCount and includeChildrenCount, you can set a count here. 328 void setCount(Album* album, int count); 329 330 /// need to implement in subclass 331 virtual Album* albumForId(int id) const = 0; 332 333 /// Can reimplement in subclass 334 virtual QString albumName(Album* a) const; 335 336 /// Reimplemented from parent classes 337 QVariant albumData(Album* a, int role) const override; 338 void albumCleared(Album* album) override; 339 void allAlbumsCleared() override; 340 341 protected Q_SLOTS: 342 343 void slotAlbumMoved(Album* album); 344 345 private: 346 347 void updateCount(Album* album); 348 349 private: 350 351 class Private; 352 Private* const d; 353 }; 354 355 // ------------------------------------------------------------------ 356 357 class DIGIKAM_GUI_EXPORT AbstractCheckableAlbumModel : public AbstractCountingAlbumModel 358 { 359 Q_OBJECT 360 361 public: 362 363 /** 364 * Abstract base class that manages the check state of Albums. 365 * Call setCheckable(true) to enable checkable albums. 366 */ 367 368 explicit AbstractCheckableAlbumModel(Album::Type albumType, 369 Album* const rootAlbum, 370 RootAlbumBehavior rootBehavior = IncludeRootAlbum, 371 QObject* const parent = nullptr); 372 ~AbstractCheckableAlbumModel() override; 373 374 /// Triggers if the albums in this model are checkable 375 void setCheckable(bool isCheckable); 376 bool isCheckable() const; 377 378 /** 379 * Triggers if the root album is checkable. 380 * Only applicable if the root album is contained at all, and if isCheckable() is true. 381 */ 382 void setRootCheckable(bool rootIsCheckable); 383 bool rootIsCheckable() const; 384 385 /** 386 * Triggers if the albums in this model are tristate. 387 * Used to allow the user to actively set a third state, 388 * don't use if you only want to display a third state. 389 * Note that you want to set setCheckable(true) before. 390 */ 391 void setTristate(bool isTristate); 392 bool isTristate() const; 393 394 /** 395 * Sets a special tristate mode, which offers the 396 * three modes "unchecked", "added" and "excluded", 397 * where "excluded" corresponds to partially checked internally, 398 * but is reflected in the treeview through the decoration only. 399 */ 400 void setAddExcludeTristate(bool b); 401 bool isAddExcludeTristate() const; 402 403 /// Returns if the given album has the check state Checked 404 bool isChecked(Album* album) const; 405 406 /// Returns the check state of the album 407 Qt::CheckState checkState(Album* album) const; 408 409 /// Returns a list of album with check state Checked 410 QList<Album*> checkedAlbums() const; 411 412 /// Returns a list of album with partially check state Checked 413 QList<Album*> partiallyCheckedAlbums() const; 414 415 public Q_SLOTS: 416 417 /// Sets the check state of album to Checked or Unchecked 418 void setChecked(Album* album, bool isChecked); 419 420 /// Sets the check state of the album 421 void setCheckState(Album* album, Qt::CheckState state); 422 423 /// Toggles the check state of album between Checked or Unchecked 424 void toggleChecked(Album* album); 425 426 /// Resets the checked state of all albums to Qt::Unchecked 427 void resetAllCheckedAlbums(); 428 429 /// Resets the checked state of all albums under the given parent 430 void resetCheckedAlbums(const QModelIndex& parent = QModelIndex()); 431 432 /// Resets the checked state of all parents of the child including it. 433 void resetCheckedParentAlbums(const QModelIndex& child); 434 435 /// Checks all albums beneath the given parent 436 void checkAllAlbums(const QModelIndex& parent = QModelIndex()); 437 438 /// Checks all parent albums starting at the child, including it. 439 void checkAllParentAlbums(const QModelIndex& child); 440 441 /// Inverts the checked state of all albums under the given parent. 442 void invertCheckedAlbums(const QModelIndex& parent = QModelIndex()); 443 444 /// Sets the checked state recursively for all children of and the given album. 445 void setCheckStateForChildren(Album* album, Qt::CheckState state); 446 447 /// Sets the checked state recursively for all parents of and the given album. 448 void setCheckStateForParents(Album* album, Qt::CheckState state); 449 450 Q_SIGNALS: 451 452 /** 453 * Emitted when the check state of an album changes. 454 * checkState contains the new Qt::CheckState of album 455 */ 456 void checkStateChanged(Album* album, Qt::CheckState checkState); 457 458 protected: 459 460 /** 461 * If in AddExcludeTristate mode, changes the icon as to indicate the state. 462 */ 463 void prepareAddExcludeDecoration(Album* a, QPixmap& icon) const; 464 465 QVariant albumData(Album* a, int role) const override; 466 Qt::ItemFlags flags(const QModelIndex& index) const override; 467 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; 468 469 void albumCleared(Album* album) override; 470 void allAlbumsCleared() override; 471 472 private: 473 474 void setDataForParents(const QModelIndex& child, const QVariant& value, int role = Qt::EditRole); 475 void setDataForChildren(const QModelIndex& parent, const QVariant& value, int role = Qt::EditRole); 476 477 private: 478 479 class Private; 480 Private* const d; 481 }; 482 483 } // namespace Digikam 484 485 #endif // DIGIKAM_ABSTRACT_ALBUM_MODEL_H 486