• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

digikam

albummodel.cpp

Go to the documentation of this file.
00001 /* ============================================================
00002  *
00003  * This file is a part of digiKam project
00004  * http://www.digikam.org
00005  *
00006  * Date        : 2008-03-22
00007  * Description : Qt Model for Albums
00008  *
00009  * Copyright (C) 2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
00010  *
00011  * This program is free software; you can redistribute it
00012  * and/or modify it under the terms of the GNU General
00013  * Public License as published by the Free Software Foundation;
00014  * either version 2, or (at your option)
00015  * any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * ============================================================ */
00023 
00024 // Qt includes.
00025 
00026 #include <QStringList>
00027 
00028 // KDE includes.
00029 
00030 #include <klocale.h>
00031 
00032 // Local includes.
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         // return the n-th of theh children of parent, or 0
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         // return index of child in the list of children of its parent
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     //connect(AlbumManager::instance(), SIGNAL(signalPAlbumsDirty(const QMap<int, int>&)),
00141       //      this, SLOT(slotRefresh(const QMap<int, int>&)));
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             // reimplement in subclasses
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 &/*parent*/) 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     //TODO
00278     return QAbstractItemModel::setData(index, value, role);
00279 }
00280 
00281 Qt::DropActions AbstractAlbumModel::supportedDropActions() const
00282 {
00283     //TODO
00284     return QAbstractItemModel::supportedDropActions();
00285 }
00286 
00287 QStringList AbstractAlbumModel::mimeTypes() const
00288 {
00289     //TODO
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     //TODO
00296     return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
00297 }
00298 
00299 QMimeData *AbstractAlbumModel::mimeData(const QModelIndexList &indexes) const
00300 {
00301     //TODO
00302     return QAbstractItemModel::mimeData(indexes);
00303 }
00304 
00305 QModelIndex AbstractAlbumModel::indexForAlbum(Album *a) const
00306 {
00307     if (!a)
00308         return QModelIndex();
00309 
00310     // a is root album? Decide on root behavior
00311     if (a == d->rootAlbum)
00312     {
00313         if (d->rootBehavior == IncludeRootAlbum)
00314             // create top-level index
00315             return createIndex(0, 0, a);
00316         else
00317             // with this behavior, root album has no valid index
00318             return QModelIndex();
00319     }
00320 
00321     // Normal album. Get its row.
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     // when the model is instantiated before albums are initialized
00362     if (album->isRoot() && !d->rootAlbum)
00363         d->rootAlbum = album;
00364 
00365     // start inserting operation
00366     int row = prev ? d->findIndexAsChild(prev) : 0;
00367     QModelIndex parentIndex = indexForAlbum(parent);
00368     beginInsertRows(parentIndex, row, row);
00369 
00370     // store album for slotAlbumAdded
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     // begin removing operation
00389     int row = d->findIndexAsChild(album);
00390     QModelIndex parent = indexForAlbum(album->parent());
00391     beginRemoveRows(parent, row, row);
00392 
00393     // store album for slotAlbumHasBeenDeleted
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     // see decorationRole() method of subclasses
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     // ignore, use default thumbnail
00462 }
00463 
00464 void AbstractSpecificAlbumModel::slotReloadThumbnails()
00465 {
00466     // emit dataChanged() for all albums
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             // recurse to children of children
00477             emitDataChangedForChildren(child);
00478 
00479             // emit signal for child
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     // return a list with all keys with value Qt::Checked
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             // with Qt::Unchecked as default, albums not in the hash (initially all)
00570             // are simply regarded as unchecked
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     // asynchronous signals are handled by parent class
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 } // namespace Digikam

digikam

Skip menu "digikam"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members