00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "abstractalbummodel.moc"
00025 #include "abstractalbummodelpriv.h"
00026
00027
00028
00029 #include <klocale.h>
00030 #include <kglobal.h>
00031
00032
00033
00034 #include "albummanager.h"
00035 #include "albumthumbnailloader.h"
00036 #include "albummodeldragdrophandler.h"
00037
00038 namespace Digikam
00039 {
00040
00041 AbstractAlbumModel::AbstractAlbumModel(Album::Type albumType, Album *rootAlbum, RootAlbumBehavior rootBehavior,
00042 QObject *parent)
00043 : QAbstractItemModel(parent), d(new AlbumModelPriv)
00044 {
00045 d->type = albumType;
00046 d->rootAlbum = rootAlbum;
00047 d->rootBehavior = rootBehavior;
00048
00049 connect(AlbumManager::instance(), SIGNAL(signalAlbumAboutToBeAdded(Album*, Album*, Album*)),
00050 this, SLOT(slotAlbumAboutToBeAdded(Album*, Album*, Album*)));
00051
00052 connect(AlbumManager::instance(), SIGNAL(signalAlbumAdded(Album*)),
00053 this, SLOT(slotAlbumAdded(Album*)));
00054
00055 connect(AlbumManager::instance(), SIGNAL(signalAlbumAboutToBeDeleted(Album*)),
00056 this, SLOT(slotAlbumAboutToBeDeleted(Album*)));
00057
00058 connect(AlbumManager::instance(), SIGNAL(signalAlbumHasBeenDeleted(void *)),
00059 this, SLOT(slotAlbumHasBeenDeleted(void *)));
00060
00061 connect(AlbumManager::instance(), SIGNAL(signalAlbumsCleared()),
00062 this, SLOT(slotAlbumsCleared()));
00063
00064 connect(AlbumManager::instance(), SIGNAL(signalAlbumIconChanged(Album*)),
00065 this, SLOT(slotAlbumIconChanged(Album*)));
00066
00067 connect(AlbumManager::instance(), SIGNAL(signalAlbumRenamed(Album*)),
00068 this, SLOT(slotAlbumRenamed(Album*)));
00069 }
00070
00071 AbstractAlbumModel::~AbstractAlbumModel()
00072 {
00073 delete d;
00074 }
00075
00076 QVariant AbstractAlbumModel::data(const QModelIndex& index, int role) const
00077 {
00078 if (!index.isValid())
00079 return QVariant();
00080
00081 Album *a = static_cast<Album*>(index.internalPointer());
00082
00083 return albumData(a, role);
00084 }
00085
00086 QVariant AbstractAlbumModel::albumData(Album *a, int role) const
00087 {
00088 switch (role)
00089 {
00090 case Qt::DisplayRole:
00091 return a->title();
00092 case Qt::ToolTipRole:
00093 return a->title();
00094 case Qt::DecorationRole:
00095
00096 return decorationRole(a);
00097 case AlbumTypeRole:
00098 return a->type();
00099 case AlbumPointerRole:
00100 return QVariant::fromValue(a);
00101 }
00102 return QVariant();
00103 }
00104
00105 QVariant AbstractAlbumModel::headerData(int section, Qt::Orientation orientation, int role) const
00106 {
00107 Q_UNUSED(orientation)
00108 if (section == 0 && role == Qt::DisplayRole)
00109 return columnHeader();
00110 return QVariant();
00111 }
00112
00113 int AbstractAlbumModel::rowCount(const QModelIndex& parent) const
00114 {
00115 if (parent.isValid())
00116 {
00117 Album *a = static_cast<Album*>(parent.internalPointer());
00118 return d->numberOfChildren(a);
00119 }
00120 else
00121 {
00122 if (!d->rootAlbum)
00123 return 0;
00124
00125 if (d->rootBehavior == IncludeRootAlbum)
00126 return 1;
00127 else
00128 return d->numberOfChildren(d->rootAlbum);
00129 }
00130 }
00131
00132 int AbstractAlbumModel::columnCount(const QModelIndex &) const
00133 {
00134 return 1;
00135 }
00136
00137 Qt::ItemFlags AbstractAlbumModel::flags(const QModelIndex& index) const
00138 {
00139 if (!index.isValid())
00140 return 0;
00141
00142 Album *a = static_cast<Album*>(index.internalPointer());
00143 return itemFlags(a);
00144 }
00145
00146 bool AbstractAlbumModel::hasChildren(const QModelIndex& parent) const
00147 {
00148 if (parent.isValid())
00149 {
00150 Album *a = static_cast<Album*>(parent.internalPointer());
00151 return a->firstChild();
00152 }
00153 else
00154 {
00155 if (!d->rootAlbum)
00156 return false;
00157
00158 if (d->rootBehavior == IncludeRootAlbum)
00159 return 1;
00160 else
00161 return d->rootAlbum->firstChild();
00162 }
00163 }
00164
00165 QModelIndex AbstractAlbumModel::index(int row, int column, const QModelIndex& parent) const
00166 {
00167 if (column != 0)
00168 return QModelIndex();
00169
00170 if (parent.isValid())
00171 {
00172 Album *parentAlbum = static_cast<Album*>(parent.internalPointer());
00173 Album *a = d->findNthChild(parentAlbum, row);
00174 if (a)
00175 return createIndex(row, column, a);
00176 }
00177 else
00178 {
00179 if (!d->rootAlbum)
00180 return QModelIndex();
00181
00182 if (d->rootBehavior == IncludeRootAlbum)
00183 {
00184 if (row == 0)
00185 return createIndex(0, 0, d->rootAlbum);
00186 }
00187 else
00188 {
00189 Album *a = d->findNthChild(d->rootAlbum, row);
00190 if (a)
00191 return createIndex(row, column, a);
00192 }
00193 }
00194 return QModelIndex();
00195 }
00196
00197 QModelIndex AbstractAlbumModel::parent(const QModelIndex& index) const
00198 {
00199 if (index.isValid())
00200 {
00201 Album *a = static_cast<Album*>(index.internalPointer());
00202 return indexForAlbum(a->parent());
00203 }
00204 return QModelIndex();
00205 }
00206
00207 Qt::DropActions AbstractAlbumModel::supportedDropActions() const
00208 {
00209 return Qt::CopyAction|Qt::MoveAction;
00210 }
00211
00212 QStringList AbstractAlbumModel::mimeTypes() const
00213 {
00214 if (d->dragDropHandler)
00215 return d->dragDropHandler->mimeTypes();
00216 return QStringList();
00217 }
00218
00219 bool AbstractAlbumModel::dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &)
00220 {
00221
00222 return false;
00223 }
00224
00225 QMimeData *AbstractAlbumModel::mimeData(const QModelIndexList& indexes) const
00226 {
00227 if (!d->dragDropHandler)
00228 return 0;
00229
00230 QList<Album*> albums;
00231 foreach (const QModelIndex& index, indexes)
00232 {
00233 Album *a = albumForIndex(index);
00234 if (a)
00235 albums << a;
00236 }
00237 return d->dragDropHandler->createMimeData(albums);
00238 }
00239
00240 void AbstractAlbumModel::setEnableDrag(bool enable)
00241 {
00242 d->itemDrag = enable;
00243 }
00244
00245 void AbstractAlbumModel::setEnableDrop(bool enable)
00246 {
00247 d->itemDrop = enable;
00248 }
00249
00250 void AbstractAlbumModel::setDragDropHandler(AlbumModelDragDropHandler *handler)
00251 {
00252 d->dragDropHandler = handler;
00253 }
00254
00255 AlbumModelDragDropHandler *AbstractAlbumModel::dragDropHandler() const
00256 {
00257 return d->dragDropHandler;
00258 }
00259
00260 QModelIndex AbstractAlbumModel::indexForAlbum(Album *a) const
00261 {
00262 if (!a)
00263 return QModelIndex();
00264
00265 if (!filterAlbum(a))
00266 return QModelIndex();
00267
00268
00269 if (a == d->rootAlbum)
00270 {
00271 if (d->rootBehavior == IncludeRootAlbum)
00272
00273 return createIndex(0, 0, a);
00274 else
00275
00276 return QModelIndex();
00277 }
00278
00279
00280 int row = d->findIndexAsChild(a);
00281 return createIndex(row, 0, a);
00282 }
00283
00284 Album *AbstractAlbumModel::albumForIndex(const QModelIndex& index) const
00285 {
00286 return static_cast<Album*>(index.internalPointer());
00287 }
00288
00289 Album *AbstractAlbumModel::rootAlbum() const
00290 {
00291 return d->rootAlbum;
00292 }
00293
00294 QModelIndex AbstractAlbumModel::rootAlbumIndex() const
00295 {
00296 return indexForAlbum(d->rootAlbum);
00297 }
00298
00299 Album::Type AbstractAlbumModel::albumType() const
00300 {
00301 return d->type;
00302 }
00303
00304 QVariant AbstractAlbumModel::decorationRole(Album *) const
00305 {
00306 return QVariant();
00307 }
00308
00309 QString AbstractAlbumModel::columnHeader() const
00310 {
00311 return i18n("Album");
00312 }
00313
00314 Qt::ItemFlags AbstractAlbumModel::itemFlags(Album *) const
00315 {
00316 Qt::ItemFlags f = Qt::ItemIsSelectable|Qt::ItemIsEnabled;
00317 if (d->itemDrag)
00318 f |= Qt::ItemIsDragEnabled;
00319 if (d->itemDrop)
00320 f |= Qt::ItemIsDropEnabled;
00321 return f;
00322 }
00323
00324 bool AbstractAlbumModel::filterAlbum(Album *album) const
00325 {
00326 return album && album->type() == d->type;
00327 }
00328
00329 void AbstractAlbumModel::slotAlbumAboutToBeAdded(Album *album, Album *parent, Album *prev)
00330 {
00331 if (!filterAlbum(album))
00332 return;
00333
00334
00335 int row = prev ? d->findIndexAsChild(prev)+1 : 0;
00336 QModelIndex parentIndex = indexForAlbum(parent);
00337 beginInsertRows(parentIndex, row, row);
00338
00339
00340
00341
00342 if (album->isRoot() && !d->rootAlbum)
00343 d->rootAlbum = album;
00344
00345
00346 d->addingAlbum = album;
00347 }
00348
00349 void AbstractAlbumModel::slotAlbumAdded(Album *album)
00350 {
00351 if (d->addingAlbum == album)
00352 {
00353
00354 bool isRoot = d->addingAlbum == d->rootAlbum;
00355 d->addingAlbum = 0;
00356 endInsertRows();
00357 if (isRoot)
00358 emit rootAlbumAvailable();
00359 }
00360 }
00361
00362 void AbstractAlbumModel::slotAlbumAboutToBeDeleted(Album *album)
00363 {
00364 if (!filterAlbum(album))
00365 return;
00366
00367
00368 int row = d->findIndexAsChild(album);
00369 QModelIndex parent = indexForAlbum(album->parent());
00370 albumCleared(album);
00371 beginRemoveRows(parent, row, row);
00372
00373
00374 d->removingAlbum = album;
00375 }
00376
00377 void AbstractAlbumModel::slotAlbumHasBeenDeleted(void *p)
00378 {
00379 if (d->removingAlbum == p)
00380 {
00381 d->removingAlbum = 0;
00382 endRemoveRows();
00383 }
00384 }
00385
00386 void AbstractAlbumModel::slotAlbumsCleared()
00387 {
00388 d->rootAlbum = 0;
00389 reset();
00390 allAlbumsCleared();
00391 }
00392
00393 void AbstractAlbumModel::slotAlbumIconChanged(Album* album)
00394 {
00395 QModelIndex index = indexForAlbum(album);
00396 emit dataChanged(index, index);
00397 }
00398
00399 void AbstractAlbumModel::slotAlbumRenamed(Album *album)
00400 {
00401 QModelIndex index = indexForAlbum(album);
00402 emit dataChanged(index, index);
00403 }
00404
00405
00406
00407 AbstractSpecificAlbumModel::AbstractSpecificAlbumModel(Album::Type albumType,
00408 Album *rootAlbum,
00409 RootAlbumBehavior rootBehavior,
00410 QObject *parent)
00411 : AbstractAlbumModel(albumType, rootAlbum, rootBehavior, parent)
00412 {
00413 }
00414
00415 void AbstractSpecificAlbumModel::setupThumbnailLoading()
00416 {
00417 AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance();
00418
00419 connect(loader, SIGNAL(signalThumbnail(Album *, const QPixmap&)),
00420 this, SLOT(slotGotThumbnailFromIcon(Album *, const QPixmap&)));
00421
00422 connect(loader, SIGNAL(signalFailed(Album *)),
00423 this, SLOT(slotThumbnailLost(Album *)));
00424
00425 connect(loader, SIGNAL(signalReloadThumbnails()),
00426 this, SLOT(slotReloadThumbnails()));
00427 }
00428
00429 QString AbstractSpecificAlbumModel::columnHeader() const
00430 {
00431 return m_columnHeader;
00432 }
00433
00434 void AbstractSpecificAlbumModel::setColumnHeader(const QString& header)
00435 {
00436 m_columnHeader = header;
00437 emit headerDataChanged(Qt::Horizontal, 0, 0);
00438 }
00439
00440 void AbstractSpecificAlbumModel::slotGotThumbnailFromIcon(Album *album, const QPixmap&)
00441 {
00442
00443
00444 if (!filterAlbum(album))
00445 return;
00446
00447 QModelIndex index = indexForAlbum(album);
00448 emit dataChanged(index, index);
00449 }
00450
00451 void AbstractSpecificAlbumModel::slotThumbnailLost(Album *)
00452 {
00453
00454 }
00455
00456 void AbstractSpecificAlbumModel::slotReloadThumbnails()
00457 {
00458
00459 emitDataChangedForChildren(rootAlbum());
00460 }
00461
00462 void AbstractSpecificAlbumModel::emitDataChangedForChildren(Album *album)
00463 {
00464 if (!album)
00465 return;
00466
00467 for (Album *child = album->firstChild(); child; child = child->next())
00468 {
00469 if (filterAlbum(child))
00470 {
00471
00472 emitDataChangedForChildren(child);
00473
00474
00475 QModelIndex index = indexForAlbum(child);
00476 emit dataChanged(index, index);
00477 }
00478 }
00479 }
00480
00481
00482
00483 AbstractCountingAlbumModel::AbstractCountingAlbumModel(Album::Type albumType, Album *rootAlbum,
00484 RootAlbumBehavior rootBehavior,
00485 QObject *parent)
00486 : AbstractSpecificAlbumModel(albumType, rootAlbum, rootBehavior, parent)
00487 {
00488 m_showCount = false;
00489 }
00490
00491 void AbstractCountingAlbumModel::setShowCount(bool show)
00492 {
00493 if (m_showCount != show)
00494 {
00495 m_showCount = show;
00496 emitDataChangedForChildren(rootAlbum());
00497 }
00498 }
00499
00500 bool AbstractCountingAlbumModel::showCount() const
00501 {
00502 return m_showCount;
00503 }
00504
00505 void AbstractCountingAlbumModel::excludeChildrenCount(const QModelIndex& index)
00506 {
00507 Album *album = albumForIndex(index);
00508 if (!album)
00509 return;
00510 m_includeChildrenAlbums.remove(album->id());
00511 updateCount(album);
00512 }
00513
00514 void AbstractCountingAlbumModel::includeChildrenCount(const QModelIndex& index)
00515 {
00516 Album *album = albumForIndex(index);
00517 if (!album)
00518 return;
00519 m_includeChildrenAlbums << album->id();
00520 updateCount(album);
00521 }
00522
00523 void AbstractCountingAlbumModel::setCountMap(const QMap<int, int>& idCountMap)
00524 {
00525 m_countMap = idCountMap;
00526 QMap<int, int>::const_iterator it = m_countMap.constBegin();
00527 for (; it != m_countMap.constEnd(); ++it)
00528 updateCount(albumForId(it.key()));
00529 }
00530
00531 void AbstractCountingAlbumModel::updateCount(Album *album)
00532 {
00533 if (!album)
00534 return;
00535
00536 QHash<int, int>::iterator includeIt = m_countHashReady.find(album->id());
00537 bool changed = false;
00538
00539
00540 int count = m_countMap.value(album->id());
00541
00542
00543 if (m_includeChildrenAlbums.contains(album->id()))
00544 {
00545 AlbumIterator it(album);
00546 while ( it.current() )
00547 {
00548 count += m_countMap.value((*it)->id());
00549 ++it;
00550 }
00551 }
00552
00553
00554 if (includeIt == m_countHashReady.end())
00555 {
00556 changed = true;
00557 m_countHashReady[album->id()] = count;
00558 }
00559 else
00560 {
00561 changed = (includeIt.value() != count);
00562 includeIt.value() = count;
00563 }
00564
00565
00566 if (changed)
00567 {
00568 QModelIndex index = indexForAlbum(album);
00569 emit dataChanged(index, index);
00570 }
00571 }
00572
00573 void AbstractCountingAlbumModel::setCount(Album *album, int count)
00574 {
00575 if (!album)
00576 return;
00577
00578 QHash<int, int>::iterator includeIt = m_countHashReady.find(album->id());
00579 bool changed = false;
00580
00581
00582 if (includeIt == m_countHashReady.end())
00583 {
00584 changed = true;
00585 m_countHashReady[album->id()] = count;
00586 }
00587 else
00588 {
00589 changed = (includeIt.value() != count);
00590 includeIt.value() = count;
00591 }
00592
00593
00594 if (changed)
00595 {
00596 QModelIndex index = indexForAlbum(album);
00597 emit dataChanged(index, index);
00598 }
00599 }
00600
00601 QVariant AbstractCountingAlbumModel::albumData(Album *album, int role) const
00602 {
00603 if (role == Qt::DisplayRole && m_showCount && !album->isRoot())
00604 {
00605 QHash<int, int>::const_iterator it = m_countHashReady.constFind(album->id());
00606 if (it != m_countHashReady.constEnd())
00607 return QString("%1 (%2)").arg(albumName(album)).arg(it.value());
00608 }
00609 return AbstractSpecificAlbumModel::albumData(album, role);
00610 }
00611
00612 QString AbstractCountingAlbumModel::albumName(Album *album) const
00613 {
00614 return album->title();
00615 }
00616
00617 void AbstractCountingAlbumModel::albumCleared(Album *album)
00618 {
00619 m_countMap.remove(album->id());
00620 m_countHashReady.remove(album->id());
00621 m_includeChildrenAlbums.remove(album->id());
00622 }
00623
00624 void AbstractCountingAlbumModel::allAlbumsCleared()
00625 {
00626 m_countMap.clear();
00627 m_countHashReady.clear();
00628 m_includeChildrenAlbums.clear();
00629 }
00630
00631
00632
00633 AbstractCheckableAlbumModel::AbstractCheckableAlbumModel(Album::Type albumType, Album *rootAlbum,
00634 RootAlbumBehavior rootBehavior,
00635 QObject *parent)
00636 : AbstractCountingAlbumModel(albumType, rootAlbum, rootBehavior, parent)
00637 {
00638 m_extraFlags = 0;
00639 }
00640
00641 void AbstractCheckableAlbumModel::setCheckable(bool isCheckable)
00642 {
00643 if (isCheckable)
00644 m_extraFlags |= Qt::ItemIsUserCheckable;
00645 else
00646 {
00647 m_extraFlags &= ~Qt::ItemIsUserCheckable;
00648 resetCheckedAlbums();
00649 }
00650 }
00651
00652 bool AbstractCheckableAlbumModel::isCheckable() const
00653 {
00654 return m_extraFlags & Qt::ItemIsUserCheckable;
00655 }
00656
00657 void AbstractCheckableAlbumModel::setTristate(bool isTristate)
00658 {
00659 if (isTristate)
00660 m_extraFlags |= Qt::ItemIsTristate;
00661 else
00662 m_extraFlags &= ~Qt::ItemIsTristate;
00663 }
00664
00665 bool AbstractCheckableAlbumModel::isTristate() const
00666 {
00667 return m_extraFlags & Qt::ItemIsTristate;
00668 }
00669
00670 bool AbstractCheckableAlbumModel::isChecked(Album *album) const
00671 {
00672 return m_checkedAlbums.value(album, Qt::Unchecked) == Qt::Checked;
00673 }
00674
00675 Qt::CheckState AbstractCheckableAlbumModel::checkState(Album *album) const
00676 {
00677 return m_checkedAlbums.value(album, Qt::Unchecked);
00678 }
00679
00680 void AbstractCheckableAlbumModel::setChecked(Album *album, bool isChecked)
00681 {
00682 setData(indexForAlbum(album), isChecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
00683 }
00684
00685 void AbstractCheckableAlbumModel::setCheckState(Album *album, Qt::CheckState state)
00686 {
00687 setData(indexForAlbum(album), state, Qt::CheckStateRole);
00688 }
00689
00690 void AbstractCheckableAlbumModel::toggleChecked(Album *album)
00691 {
00692 setChecked(album, !isChecked(album));
00693 }
00694
00695 QList<Album *> AbstractCheckableAlbumModel::checkedAlbums() const
00696 {
00697
00698 return m_checkedAlbums.keys(Qt::Checked);
00699 }
00700
00701 void AbstractCheckableAlbumModel::resetCheckedAlbums()
00702 {
00703 QList<Album *> oldChecked = m_checkedAlbums.keys();
00704 m_checkedAlbums.clear();
00705 foreach(Album *album, oldChecked)
00706 {
00707 QModelIndex index = indexForAlbum(album);
00708 emit dataChanged(index, index);
00709 emit checkStateChanged(album, Qt::Unchecked);
00710 }
00711 }
00712
00713 QVariant AbstractCheckableAlbumModel::albumData(Album *a, int role) const
00714 {
00715 if (role == Qt::CheckStateRole)
00716 {
00717 if (m_extraFlags & Qt::ItemIsUserCheckable)
00718 {
00719
00720
00721 return m_checkedAlbums.value(a, Qt::Unchecked);
00722 }
00723 }
00724
00725 return AbstractCountingAlbumModel::albumData(a, role);
00726 }
00727
00728 Qt::ItemFlags AbstractCheckableAlbumModel::flags(const QModelIndex& index) const
00729 {
00730 return AbstractCountingAlbumModel::flags(index) | m_extraFlags;
00731 }
00732
00733 bool AbstractCheckableAlbumModel::setData(const QModelIndex& index, const QVariant& value, int role)
00734 {
00735 if (role == Qt::CheckStateRole)
00736 {
00737 Qt::CheckState state = (Qt::CheckState)value.toInt();
00738 Album *album = albumForIndex(index);
00739 if (!album)
00740 return false;
00741 m_checkedAlbums.insert(album, state);
00742 emit dataChanged(index, index);
00743 emit checkStateChanged(album, state);
00744 return true;
00745 }
00746 else
00747 return AbstractCountingAlbumModel::setData(index, value, role);
00748 }
00749
00750 void AbstractCheckableAlbumModel::albumCleared(Album *album)
00751 {
00752 m_checkedAlbums.remove(album);
00753 AbstractCountingAlbumModel::albumCleared(album);
00754 }
00755
00756 void AbstractCheckableAlbumModel::allAlbumsCleared()
00757 {
00758 m_checkedAlbums.clear();
00759 AbstractCountingAlbumModel::allAlbumsCleared();
00760 }
00761
00762 }