00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <QStringList>
00027
00028
00029
00030 #include <klocale.h>
00031
00032
00033
00034 #include "ddebug.h"
00035 #include "album.h"
00036 #include "albummanager.h"
00037 #include "albumthumbnailloader.h"
00038 #include "albummodel.h"
00039 #include "albummodel.moc"
00040
00041 namespace Digikam
00042 {
00043
00044 class AlbumModelPriv
00045 {
00046 public:
00047
00048 AlbumModelPriv()
00049 {
00050 rootAlbum = 0;
00051 type = Album::PHYSICAL;
00052 rootBehavior = AbstractAlbumModel::IncludeRootAlbum;
00053 addingAlbum = 0;
00054 removingAlbum = 0;
00055 }
00056
00057 Album *rootAlbum;
00058 Album::Type type;
00059 AbstractAlbumModel::RootAlbumBehavior
00060 rootBehavior;
00061
00062 Album *addingAlbum;
00063 Album *removingAlbum;
00064
00065 Album *findNthChild(Album *parent, int n)
00066 {
00067
00068 Album *a = parent->firstChild();
00069 for (int i=0; i<n; i++)
00070 {
00071 a = a->next();
00072 if (!a)
00073 return 0;
00074 }
00075 return a;
00076 }
00077
00078 int findIndexAsChild(Album *child)
00079 {
00080
00081 Album *parent = child->parent();
00082 if (!parent)
00083 return 0;
00084 Album *a = parent->firstChild();
00085 int i = 0;
00086 while (a != child)
00087 {
00088 a = a->next();
00089 if (!a)
00090 return -1;
00091 i++;
00092 }
00093 return i;
00094 }
00095
00096 int numberOfChildren(Album *parent)
00097 {
00098 Album *a = parent->firstChild();
00099 int count = 0;
00100 while (a)
00101 {
00102 count++;
00103 a = a->next();
00104 }
00105 return count;
00106 }
00107 };
00108
00109 AbstractAlbumModel::AbstractAlbumModel(Album::Type albumType, Album *rootAlbum, RootAlbumBehavior rootBehavior,
00110 QObject *parent)
00111 : QAbstractItemModel(parent)
00112 {
00113 d = new AlbumModelPriv;
00114
00115 d->type = albumType;
00116 d->rootAlbum = rootAlbum;
00117 d->rootBehavior = rootBehavior;
00118
00119 connect(AlbumManager::instance(), SIGNAL(signalAlbumAboutToBeAdded(Album*, Album*, Album*)),
00120 this, SLOT(slotAlbumAboutToBeAdded(Album*, Album*, Album*)));
00121
00122 connect(AlbumManager::instance(), SIGNAL(signalAlbumAdded(Album*)),
00123 this, SLOT(slotAlbumAdded(Album*)));
00124
00125 connect(AlbumManager::instance(), SIGNAL(signalAlbumAboutToBeDeleted(Album*)),
00126 this, SLOT(slotAlbumAboutToBeDeleted(Album*)));
00127
00128 connect(AlbumManager::instance(), SIGNAL(signalAlbumHasBeenDeleted(void *)),
00129 this, SLOT(slotAlbumHasBeenDeleted(void *)));
00130
00131 connect(AlbumManager::instance(), SIGNAL(signalAlbumsCleared()),
00132 this, SLOT(slotAlbumsCleared()));
00133
00134 connect(AlbumManager::instance(), SIGNAL(signalAlbumIconChanged(Album*)),
00135 this, SLOT(slotAlbumIconChanged(Album*)));
00136
00137 connect(AlbumManager::instance(), SIGNAL(signalAlbumRenamed(Album*)),
00138 this, SLOT(slotAlbumRenamed(Album*)));
00139
00140
00141
00142 }
00143
00144 AbstractAlbumModel::~AbstractAlbumModel()
00145 {
00146 delete d;
00147 }
00148
00149 QVariant AbstractAlbumModel::data(const QModelIndex &index, int role) const
00150 {
00151 if (!index.isValid())
00152 return QVariant();
00153
00154 Album *a = static_cast<Album*>(index.internalPointer());
00155
00156 switch (role)
00157 {
00158 case Qt::DisplayRole:
00159 return a->title();
00160 case Qt::ToolTipRole:
00161 return a->title();
00162 case Qt::DecorationRole:
00163
00164 return decorationRole(a);
00165 case AlbumTypeRole:
00166 return a->type();
00167 case AlbumPointerRole:
00168 return a;
00169 }
00170 return QVariant();
00171 }
00172
00173 QVariant AbstractAlbumModel::headerData(int section, Qt::Orientation orientation, int role) const
00174 {
00175 Q_UNUSED(orientation)
00176 if (section == 0 && role == Qt::DisplayRole)
00177 return columnHeader();
00178 return QVariant();
00179 }
00180
00181 int AbstractAlbumModel::rowCount(const QModelIndex &parent) const
00182 {
00183 if (parent.isValid())
00184 {
00185 Album *a = static_cast<Album*>(parent.internalPointer());
00186 return d->numberOfChildren(a);
00187 }
00188 else
00189 {
00190 if (!d->rootAlbum)
00191 return 0;
00192
00193 if (d->rootBehavior == IncludeRootAlbum)
00194 return 1;
00195 else
00196 return d->numberOfChildren(d->rootAlbum);
00197 }
00198 }
00199
00200 int AbstractAlbumModel::columnCount(const QModelIndex &) const
00201 {
00202 return 1;
00203 }
00204
00205 Qt::ItemFlags AbstractAlbumModel::flags(const QModelIndex &index) const
00206 {
00207 if (!index.isValid())
00208 return 0;
00209
00210 Album *a = static_cast<Album*>(index.internalPointer());
00211 return itemFlags(a);
00212 }
00213
00214 bool AbstractAlbumModel::hasChildren(const QModelIndex &parent) const
00215 {
00216 if (parent.isValid())
00217 {
00218 Album *a = static_cast<Album*>(parent.internalPointer());
00219 return a->firstChild();
00220 }
00221 else
00222 {
00223 if (!d->rootAlbum)
00224 return false;
00225
00226 if (d->rootBehavior == IncludeRootAlbum)
00227 return 1;
00228 else
00229 return d->rootAlbum->firstChild();
00230 }
00231 }
00232
00233 QModelIndex AbstractAlbumModel::index(int row, int column, const QModelIndex &parent) const
00234 {
00235 if (column != 0)
00236 return QModelIndex();
00237
00238 if (parent.isValid())
00239 {
00240 Album *parentAlbum = static_cast<Album*>(parent.internalPointer());
00241 Album *a = d->findNthChild(parentAlbum, row);
00242 if (a)
00243 return createIndex(row, column, a);
00244 }
00245 else
00246 {
00247 if (!d->rootAlbum)
00248 return QModelIndex();
00249
00250 if (d->rootBehavior == IncludeRootAlbum)
00251 {
00252 if (row == 0)
00253 return createIndex(0, 0, d->rootAlbum);
00254 }
00255 else
00256 {
00257 Album *a = d->findNthChild(d->rootAlbum, row);
00258 if (a)
00259 return createIndex(row, column, a);
00260 }
00261 }
00262 return QModelIndex();
00263 }
00264
00265 QModelIndex AbstractAlbumModel::parent(const QModelIndex &index) const
00266 {
00267 if (index.isValid())
00268 {
00269 Album *a = static_cast<Album*>(index.internalPointer());
00270 return indexForAlbum(a->parent());
00271 }
00272 return QModelIndex();
00273 }
00274
00275 bool AbstractAlbumModel::setData(const QModelIndex &index, const QVariant &value, int role)
00276 {
00277
00278 return QAbstractItemModel::setData(index, value, role);
00279 }
00280
00281 Qt::DropActions AbstractAlbumModel::supportedDropActions() const
00282 {
00283
00284 return QAbstractItemModel::supportedDropActions();
00285 }
00286
00287 QStringList AbstractAlbumModel::mimeTypes() const
00288 {
00289
00290 return QAbstractItemModel::mimeTypes();
00291 }
00292
00293 bool AbstractAlbumModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
00294 {
00295
00296 return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
00297 }
00298
00299 QMimeData *AbstractAlbumModel::mimeData(const QModelIndexList &indexes) const
00300 {
00301
00302 return QAbstractItemModel::mimeData(indexes);
00303 }
00304
00305 QModelIndex AbstractAlbumModel::indexForAlbum(Album *a) const
00306 {
00307 if (!a)
00308 return QModelIndex();
00309
00310
00311 if (a == d->rootAlbum)
00312 {
00313 if (d->rootBehavior == IncludeRootAlbum)
00314
00315 return createIndex(0, 0, a);
00316 else
00317
00318 return QModelIndex();
00319 }
00320
00321
00322 int row = d->findIndexAsChild(a);
00323 return createIndex(row, 0, a);
00324 }
00325
00326 Album *AbstractAlbumModel::albumForIndex(const QModelIndex &index) const
00327 {
00328 return static_cast<Album*>(index.internalPointer());
00329 }
00330
00331 Album *AbstractAlbumModel::rootAlbum() const
00332 {
00333 return d->rootAlbum;
00334 }
00335
00336 QVariant AbstractAlbumModel::decorationRole(Album *) const
00337 {
00338 return QVariant();
00339 }
00340
00341 QString AbstractAlbumModel::columnHeader() const
00342 {
00343 return i18n("Album");
00344 }
00345
00346 Qt::ItemFlags AbstractAlbumModel::itemFlags(Album *) const
00347 {
00348 return Qt::ItemIsSelectable|Qt::ItemIsEnabled;
00349 }
00350
00351 bool AbstractAlbumModel::filterAlbum(Album *album) const
00352 {
00353 return album && album->type() == d->type;
00354 }
00355
00356 void AbstractAlbumModel::slotAlbumAboutToBeAdded(Album *album, Album *parent, Album *prev)
00357 {
00358 if (!filterAlbum(album))
00359 return;
00360
00361
00362 if (album->isRoot() && !d->rootAlbum)
00363 d->rootAlbum = album;
00364
00365
00366 int row = prev ? d->findIndexAsChild(prev) : 0;
00367 QModelIndex parentIndex = indexForAlbum(parent);
00368 beginInsertRows(parentIndex, row, row);
00369
00370
00371 d->addingAlbum = album;
00372 }
00373
00374 void AbstractAlbumModel::slotAlbumAdded(Album *album)
00375 {
00376 if (d->addingAlbum == album)
00377 {
00378 d->addingAlbum = 0;
00379 endInsertRows();
00380 }
00381 }
00382
00383 void AbstractAlbumModel::slotAlbumAboutToBeDeleted(Album *album)
00384 {
00385 if (!filterAlbum(album))
00386 return;
00387
00388
00389 int row = d->findIndexAsChild(album);
00390 QModelIndex parent = indexForAlbum(album->parent());
00391 beginRemoveRows(parent, row, row);
00392
00393
00394 d->removingAlbum = album;
00395 }
00396
00397 void AbstractAlbumModel::slotAlbumHasBeenDeleted(void *p)
00398 {
00399 if (d->removingAlbum == p)
00400 {
00401 d->removingAlbum = 0;
00402 endRemoveRows();
00403 }
00404 }
00405
00406 void AbstractAlbumModel::slotAlbumsCleared()
00407 {
00408 reset();
00409 }
00410
00411 void AbstractAlbumModel::slotAlbumIconChanged(Album* album)
00412 {
00413 QModelIndex index = indexForAlbum(album);
00414 emit dataChanged(index, index);
00415 }
00416
00417 void AbstractAlbumModel::slotAlbumRenamed(Album *album)
00418 {
00419 QModelIndex index = indexForAlbum(album);
00420 emit dataChanged(index, index);
00421 }
00422
00423
00424
00425 AbstractSpecificAlbumModel::AbstractSpecificAlbumModel(Album::Type albumType,
00426 Album *rootAlbum,
00427 RootAlbumBehavior rootBehavior,
00428 QObject *parent)
00429 : AbstractAlbumModel(albumType, rootAlbum, rootBehavior, parent)
00430 {
00431 AlbumThumbnailLoader *loader = AlbumThumbnailLoader::instance();
00432
00433 connect(loader, SIGNAL(signalThumbnail(Album *, const QPixmap&)),
00434 this, SLOT(slotGotThumbnailFromIcon(Album *, const QPixmap&)));
00435
00436 connect(loader, SIGNAL(signalFailed(Album *)),
00437 this, SLOT(slotThumbnailLost(Album *)));
00438
00439 connect(loader, SIGNAL(signalReloadThumbnails()),
00440 this, SLOT(slotReloadThumbnails()));
00441 }
00442
00443 QString AbstractSpecificAlbumModel::columnHeader() const
00444 {
00445 return m_columnHeader;
00446 }
00447
00448 void AbstractSpecificAlbumModel::slotGotThumbnailFromIcon(Album *album, const QPixmap&)
00449 {
00450
00451
00452 if (!filterAlbum(album))
00453 return;
00454
00455 QModelIndex index = indexForAlbum(album);
00456 emit dataChanged(index, index);
00457 }
00458
00459 void AbstractSpecificAlbumModel::slotThumbnailLost(Album *)
00460 {
00461
00462 }
00463
00464 void AbstractSpecificAlbumModel::slotReloadThumbnails()
00465 {
00466
00467 emitDataChangedForChildren(rootAlbum());
00468 }
00469
00470 void AbstractSpecificAlbumModel::emitDataChangedForChildren(Album *album)
00471 {
00472 for (Album *child = album->firstChild(); child; child = child->next())
00473 {
00474 if (filterAlbum(child))
00475 {
00476
00477 emitDataChangedForChildren(child);
00478
00479
00480 QModelIndex index = indexForAlbum(child);
00481 emit dataChanged(index, index);
00482 }
00483 }
00484 }
00485
00486
00487
00488 AbstractCheckableAlbumModel::AbstractCheckableAlbumModel(Album::Type albumType, Album *rootAlbum,
00489 RootAlbumBehavior rootBehavior,
00490 QObject *parent)
00491 : AbstractSpecificAlbumModel(albumType, rootAlbum, rootBehavior, parent)
00492 {
00493 m_extraFlags = 0;
00494 }
00495
00496 void AbstractCheckableAlbumModel::setCheckable(bool isCheckable)
00497 {
00498 if (isCheckable)
00499 m_extraFlags |= Qt::ItemIsUserCheckable;
00500 else
00501 {
00502 m_extraFlags &= ~Qt::ItemIsUserCheckable;
00503 resetCheckedAlbums();
00504 }
00505 }
00506
00507 bool AbstractCheckableAlbumModel::isCheckable() const
00508 {
00509 return m_extraFlags & Qt::ItemIsUserCheckable;
00510 }
00511
00512 void AbstractCheckableAlbumModel::setTristate(bool isTristate)
00513 {
00514 if (isTristate)
00515 m_extraFlags |= Qt::ItemIsTristate;
00516 else
00517 m_extraFlags &= ~Qt::ItemIsTristate;
00518 }
00519
00520 bool AbstractCheckableAlbumModel::isTristate() const
00521 {
00522 return m_extraFlags & Qt::ItemIsTristate;
00523 }
00524
00525 bool AbstractCheckableAlbumModel::isChecked(Album *album) const
00526 {
00527 return m_checkedAlbums.value(album, Qt::Unchecked) == Qt::Checked;
00528 }
00529
00530 Qt::CheckState AbstractCheckableAlbumModel::checkState(Album *album) const
00531 {
00532 return m_checkedAlbums.value(album, Qt::Unchecked);
00533 }
00534
00535 void AbstractCheckableAlbumModel::setChecked(Album *album, bool isChecked)
00536 {
00537 setData(indexForAlbum(album), isChecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
00538 }
00539
00540 void AbstractCheckableAlbumModel::setCheckState(Album *album, Qt::CheckState state)
00541 {
00542 setData(indexForAlbum(album), state, Qt::CheckStateRole);
00543 }
00544
00545 QList<Album *> AbstractCheckableAlbumModel::checkedAlbums() const
00546 {
00547
00548 return m_checkedAlbums.keys(Qt::Checked);
00549 }
00550
00551 void AbstractCheckableAlbumModel::resetCheckedAlbums()
00552 {
00553 QList<Album *> oldChecked = m_checkedAlbums.keys();
00554 m_checkedAlbums.clear();
00555 foreach(Album *album, oldChecked)
00556 {
00557 QModelIndex index = indexForAlbum(album);
00558 emit dataChanged(index, index);
00559 emit checkStateChanged(album, Qt::Unchecked);
00560 }
00561 }
00562
00563 QVariant AbstractCheckableAlbumModel::data(const QModelIndex &index, int role) const
00564 {
00565 if (role == Qt::CheckStateRole)
00566 {
00567 if (m_extraFlags & Qt::ItemIsUserCheckable)
00568 {
00569
00570
00571 return m_checkedAlbums.value(albumForIndex(index), Qt::Unchecked);
00572 }
00573 }
00574
00575 return AbstractSpecificAlbumModel::data(index, role);
00576 }
00577
00578 Qt::ItemFlags AbstractCheckableAlbumModel::flags(const QModelIndex &index) const
00579 {
00580 return AbstractSpecificAlbumModel::flags(index) | m_extraFlags;
00581 }
00582
00583 bool AbstractCheckableAlbumModel::setData(const QModelIndex &index, const QVariant &value, int role)
00584 {
00585 if (role == Qt::CheckStateRole)
00586 {
00587 Qt::CheckState state = (Qt::CheckState)value.toInt();
00588 Album *album = albumForIndex(index);
00589 if (!album)
00590 return false;
00591 m_checkedAlbums.insert(album, state);
00592 emit dataChanged(index, index);
00593 emit checkStateChanged(album, state);
00594 return true;
00595 }
00596 else
00597 return AbstractSpecificAlbumModel::setData(index, value, role);
00598 }
00599
00600
00601
00602 AlbumModel::AlbumModel(RootAlbumBehavior rootBehavior, QObject *parent)
00603 : AbstractCheckableAlbumModel(Album::PHYSICAL,
00604 AlbumManager::instance()->findPAlbum(0),
00605 rootBehavior, parent)
00606 {
00607 m_columnHeader = i18n("My Albums");
00608 }
00609
00610 QVariant AlbumModel::decorationRole(Album *album) const
00611 {
00612
00613 return AlbumThumbnailLoader::instance()->getAlbumThumbnailDirectly(static_cast<PAlbum *>(album));
00614 }
00615
00616
00617
00618 TagModel::TagModel(RootAlbumBehavior rootBehavior, QObject *parent)
00619 : AbstractCheckableAlbumModel(Album::TAG,
00620 AlbumManager::instance()->findTAlbum(0),
00621 rootBehavior, parent)
00622 {
00623 m_columnHeader = i18n("My Tags");
00624 }
00625
00626 QVariant TagModel::decorationRole(Album *album) const
00627 {
00628 return AlbumThumbnailLoader::instance()->getTagThumbnailDirectly(static_cast<TAlbum *>(album), true);
00629 }
00630
00631 }