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 <math.h>
00027
00028
00029
00030 #include <QList>
00031 #include <QMap>
00032 #include <QPainter>
00033 #include <QEvent>
00034 #include <QPixmap>
00035 #include <QEvent>
00036
00037
00038
00039 #include <kapplication.h>
00040 #include <kiconloader.h>
00041 #include <kdebug.h>
00042
00043
00044
00045 #include "thumbnailloadthread.h"
00046 #include "thumbnailsize.h"
00047 #include "album.h"
00048 #include "albummanager.h"
00049 #include "albumsettings.h"
00050 #include "albumthumbnailloader.h"
00051 #include "albumthumbnailloader.moc"
00052
00053 namespace Digikam
00054 {
00055
00056 typedef QMap<QString, QList<int> > PathAlbumMap;
00057 typedef QMap<int, QPixmap> AlbumThumbnailMap;
00058
00059 class AlbumThumbnailLoaderPrivate
00060 {
00061 public:
00062 AlbumThumbnailLoaderPrivate()
00063 {
00064 iconSize = AlbumSettings::instance()->getDefaultTreeIconSize();
00065 minBlendSize = 20;
00066 iconAlbumThumbThread = 0;
00067 iconTagThumbThread = 0;
00068 }
00069
00070 int iconSize;
00071 int minBlendSize;
00072
00073 ThumbnailLoadThread *iconTagThumbThread;
00074 ThumbnailLoadThread *iconAlbumThumbThread;
00075
00076 PathAlbumMap pathAlbumMap;
00077
00078 AlbumThumbnailMap thumbnailMap;
00079 };
00080
00081 class AlbumThumbnailLoaderCreator { public: AlbumThumbnailLoader object; };
00082 K_GLOBAL_STATIC(AlbumThumbnailLoaderCreator, creator)
00083
00084 AlbumThumbnailLoader *AlbumThumbnailLoader::instance()
00085 {
00086 return &creator->object;
00087 }
00088
00089 AlbumThumbnailLoader::AlbumThumbnailLoader()
00090 {
00091 d = new AlbumThumbnailLoaderPrivate;
00092
00093 connect(this, SIGNAL(signalDispatchThumbnailInternal(int, const QPixmap &)),
00094 this, SLOT(slotDispatchThumbnailInternal(int, const QPixmap &)));
00095
00096 connect(AlbumManager::instance(), SIGNAL(signalAlbumIconChanged(Album*)),
00097 this, SLOT(slotIconChanged(Album*)));
00098
00099 connect(AlbumManager::instance(), SIGNAL(signalAlbumDeleted(Album*)),
00100 this, SLOT(slotIconChanged(Album*)));
00101 }
00102
00103 AlbumThumbnailLoader::~AlbumThumbnailLoader()
00104 {
00105 delete d->iconTagThumbThread;
00106 delete d->iconAlbumThumbThread;
00107
00108 delete d;
00109 }
00110
00111 QPixmap AlbumThumbnailLoader::getStandardTagIcon(RelativeSize relativeSize)
00112 {
00113 return loadIcon("tag", computeIconSize(relativeSize));
00114 }
00115
00116 QPixmap AlbumThumbnailLoader::getStandardTagRootIcon(RelativeSize relativeSize)
00117 {
00118 return loadIcon("tag-folder", computeIconSize(relativeSize));
00119 }
00120
00121 QPixmap AlbumThumbnailLoader::getStandardTagIcon(TAlbum *album, RelativeSize relativeSize)
00122 {
00123 if (album->isRoot())
00124 return getStandardTagRootIcon(relativeSize);
00125 else
00126 return getStandardTagIcon(relativeSize);
00127 }
00128
00129 QPixmap AlbumThumbnailLoader::getStandardAlbumIcon(RelativeSize relativeSize)
00130 {
00131 return loadIcon("folder", computeIconSize(relativeSize));
00132 }
00133
00134 QPixmap AlbumThumbnailLoader::getStandardAlbumRootIcon(RelativeSize relativeSize)
00135 {
00136 return loadIcon("folder-image", computeIconSize(relativeSize));
00137 }
00138
00139 QPixmap AlbumThumbnailLoader::getStandardAlbumIcon(PAlbum *album, RelativeSize relativeSize)
00140 {
00141 if (album->isRoot() || album->isAlbumRoot())
00142 return getStandardAlbumRootIcon(relativeSize);
00143 else
00144 return getStandardAlbumIcon(relativeSize);
00145 }
00146
00147 int AlbumThumbnailLoader::computeIconSize(RelativeSize relativeSize)
00148 {
00149 if (relativeSize == SmallerSize)
00150 {
00151
00152 return lround(20.0 / 32.0 * (double)d->iconSize);
00153 }
00154 return d->iconSize;
00155 }
00156
00157 QRect AlbumThumbnailLoader::computeBlendRect(int iconSize)
00158 {
00159
00160 double largerSize = iconSize;
00161 double x = 6.0 / 32.0 * largerSize;
00162 double y = 9.0 / 32.0 * largerSize;
00163 double size = 20.0 / 32.0 * largerSize;
00164 return QRect(lround(x), lround(y), lround(size), lround(size));
00165 }
00166
00167 QPixmap AlbumThumbnailLoader::loadIcon(const QString &name, int size)
00168 {
00169 KIconLoader *iconLoader = KIconLoader::global();
00170 return iconLoader->loadIcon(name, KIconLoader::NoGroup, size);
00171 }
00172
00173 bool AlbumThumbnailLoader::getTagThumbnail(TAlbum *album, QPixmap &icon)
00174 {
00175 int size = computeIconSize(SmallerSize);
00176
00177
00178
00179
00180
00181
00182
00183
00184 if(!album->icon().isEmpty())
00185 {
00186 if(album->icon().startsWith('/'))
00187 {
00188 KUrl iconKURL;
00189 iconKURL.setPath(album->icon());
00190 addUrl(album, iconKURL);
00191 icon = QPixmap();
00192 return true;
00193 }
00194 else
00195 {
00196 icon = loadIcon(album->icon(), size);
00197 return false;
00198 }
00199 }
00200 else
00201 {
00202 icon = QPixmap();
00203 return false;
00204 }
00205 }
00206
00207 QPixmap AlbumThumbnailLoader::getTagThumbnailDirectly(TAlbum *album, bool blendIcon)
00208 {
00209 int size = computeIconSize(SmallerSize);
00210
00211 if(!album->icon().isEmpty())
00212 {
00213
00214 AlbumThumbnailMap::iterator it = d->thumbnailMap.find(album->globalID());
00215 if (it != d->thumbnailMap.end())
00216 {
00217 if (blendIcon)
00218 return blendIcons(getStandardTagIcon(), *it);
00219 else
00220 return *it;
00221 }
00222
00223 if(album->icon().startsWith('/'))
00224 {
00225 KUrl iconKURL;
00226 iconKURL.setPath(album->icon());
00227 addUrl(album, iconKURL);
00228 }
00229 else
00230 {
00231 return loadIcon(album->icon(), size);
00232 }
00233 }
00234
00235 return getStandardTagIcon(album);
00236 }
00237
00238 bool AlbumThumbnailLoader::getAlbumThumbnail(PAlbum *album)
00239 {
00240 if(!album->icon().isEmpty() && d->iconSize > d->minBlendSize)
00241 {
00242 addUrl(album, album->iconKURL());
00243 }
00244 else
00245 {
00246 return false;
00247 }
00248
00249 return true;
00250 }
00251
00252 QPixmap AlbumThumbnailLoader::getAlbumThumbnailDirectly(PAlbum *album)
00253 {
00254 if(!album->icon().isEmpty() && d->iconSize > d->minBlendSize)
00255 {
00256
00257 AlbumThumbnailMap::iterator it = d->thumbnailMap.find(album->globalID());
00258 if (it != d->thumbnailMap.end())
00259 return *it;
00260
00261
00262 addUrl(album, album->iconKURL());
00263 }
00264
00265 return getStandardAlbumIcon(album);
00266 }
00267
00268 void AlbumThumbnailLoader::addUrl(Album *album, const KUrl &url)
00269 {
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 AlbumThumbnailMap::iterator ttit = d->thumbnailMap.find(album->globalID());
00281 if (ttit != d->thumbnailMap.end())
00282 {
00283
00284
00285
00286 emit signalDispatchThumbnailInternal(album->globalID(), *ttit);
00287 return;
00288 }
00289
00290
00291 PathAlbumMap::iterator it = d->pathAlbumMap.find(url.path());
00292
00293 if (it == d->pathAlbumMap.end())
00294 {
00295
00296
00297 if (album->type() == Album::TAG)
00298 {
00299 if(!d->iconTagThumbThread)
00300 {
00301 d->iconTagThumbThread = new ThumbnailLoadThread();
00302 d->iconTagThumbThread->setThumbnailSize(d->iconSize);
00303 d->iconTagThumbThread->setSendSurrogatePixmap(false);
00304 d->iconTagThumbThread->setExifRotate(AlbumSettings::instance()->getExifRotate());
00305 connect(d->iconTagThumbThread,
00306 SIGNAL(signalThumbnailLoaded(const LoadingDescription &, const QPixmap&)),
00307 SLOT(slotGotThumbnailFromIcon(const LoadingDescription &, const QPixmap&)),
00308 Qt::QueuedConnection);
00309 }
00310
00311
00312 d->iconTagThumbThread->find(url.path());
00313 }
00314 else
00315 {
00316 if(!d->iconAlbumThumbThread)
00317 {
00318 d->iconAlbumThumbThread = new ThumbnailLoadThread();
00319 d->iconAlbumThumbThread->setThumbnailSize(d->iconSize);
00320 d->iconAlbumThumbThread->setSendSurrogatePixmap(false);
00321 d->iconAlbumThumbThread->setExifRotate(AlbumSettings::instance()->getExifRotate());
00322 connect(d->iconAlbumThumbThread,
00323 SIGNAL(signalThumbnailLoaded(const LoadingDescription &, const QPixmap&)),
00324 SLOT(slotGotThumbnailFromIcon(const LoadingDescription &, const QPixmap&)),
00325 Qt::QueuedConnection);
00326 }
00327
00328 d->iconAlbumThumbThread->find(url.path());
00329 }
00330
00331
00332 QList<int> &list = d->pathAlbumMap[url.path()];
00333 list.removeAll(album->globalID());
00334 list.push_back(album->globalID());
00335 }
00336 else
00337 {
00338
00339 (*it).removeAll(album->globalID());
00340 (*it).push_back(album->globalID());
00341 }
00342 }
00343
00344 void AlbumThumbnailLoader::setThumbnailSize(int size)
00345 {
00346 if (d->iconSize == size)
00347 return;
00348
00349 d->iconSize = size;
00350
00351
00352 d->pathAlbumMap.clear();
00353
00354 d->thumbnailMap.clear();
00355
00356 if (d->iconAlbumThumbThread)
00357 {
00358 d->iconAlbumThumbThread->stopLoading();
00359 }
00360 if (d->iconTagThumbThread)
00361 {
00362 d->iconTagThumbThread->stopLoading();
00363 }
00364
00365 emit signalReloadThumbnails();
00366 }
00367
00368 int AlbumThumbnailLoader::thumbnailSize() const
00369 {
00370 return d->iconSize;
00371 }
00372
00373 void AlbumThumbnailLoader::slotGotThumbnailFromIcon(const LoadingDescription &loadingDescription, const QPixmap &thumbnail)
00374 {
00375
00376
00377
00378 PathAlbumMap::iterator it = d->pathAlbumMap.find(loadingDescription.filePath);
00379
00380 if (it != d->pathAlbumMap.end())
00381 {
00382 AlbumManager *manager = AlbumManager::instance();
00383
00384 if (thumbnail.isNull())
00385 {
00386
00387 for (QList<int>::iterator vit = (*it).begin(); vit != (*it).end(); ++vit)
00388 {
00389 Album *album = manager->findAlbum(*vit);
00390 if (album)
00391 emit signalFailed(album);
00392 }
00393 }
00394 else
00395 {
00396
00397
00398 QPixmap tagThumbnail;
00399
00400 for (QList<int>::iterator vit = (*it).begin(); vit != (*it).end(); ++vit)
00401 {
00402
00403 Album *album = manager->findAlbum(*vit);
00404 if (album)
00405 {
00406 if (album->type() == Album::TAG)
00407 {
00408
00409 if (tagThumbnail.isNull())
00410 {
00411 tagThumbnail = createTagThumbnail(thumbnail);
00412 d->thumbnailMap.insert(album->globalID(), tagThumbnail);
00413 }
00414
00415 emit signalThumbnail(album, tagThumbnail);
00416 }
00417 else
00418 {
00419 d->thumbnailMap.insert(album->globalID(), thumbnail);
00420 emit signalThumbnail(album, thumbnail);
00421 }
00422 }
00423 }
00424 }
00425
00426 d->pathAlbumMap.erase(it);
00427 }
00428 }
00429
00430 void AlbumThumbnailLoader::slotDispatchThumbnailInternal(int albumID, const QPixmap &thumbnail)
00431 {
00432
00433
00434 AlbumManager *manager = AlbumManager::instance();
00435 Album *album = manager->findAlbum(albumID);
00436 if (album)
00437 {
00438 if (thumbnail.isNull())
00439 emit signalFailed(album);
00440 else
00441 emit signalThumbnail(album, thumbnail);
00442 }
00443 }
00444
00445 void AlbumThumbnailLoader::slotIconChanged(Album* album)
00446 {
00447 if(!album || album->type() != Album::TAG)
00448 return;
00449
00450 d->thumbnailMap.remove(album->globalID());
00451 }
00452
00453 QPixmap AlbumThumbnailLoader::createTagThumbnail(const QPixmap &albumThumbnail)
00454 {
00455
00456
00457 QPixmap tagThumbnail;
00458 int thumbSize = qMax(albumThumbnail.width(), albumThumbnail.height());
00459
00460 if(!albumThumbnail.isNull() && thumbSize >= d->minBlendSize)
00461 {
00462 QRect rect = computeBlendRect(thumbSize);
00463 int w1 = albumThumbnail.width();
00464 int w2 = rect.width();
00465 int h1 = albumThumbnail.height();
00466 int h2 = rect.height();
00467 tagThumbnail = QPixmap(w2, h2);
00468 QPainter p(&tagThumbnail);
00469 p.drawPixmap(0, 0, albumThumbnail, (w1-w2)/2, (h1-h2)/2, w2, h2);
00470 p.end();
00471 }
00472 else
00473 {
00474 tagThumbnail = albumThumbnail;
00475 }
00476
00477 return tagThumbnail;
00478 }
00479
00480 QPixmap AlbumThumbnailLoader::blendIcons(QPixmap dstIcon, const QPixmap &tagIcon)
00481 {
00482 int dstIconSize = qMax(dstIcon.width(), dstIcon.height());
00483
00484 if (dstIconSize >= d->minBlendSize)
00485 {
00486 if(!tagIcon.isNull())
00487 {
00488 QRect rect = computeBlendRect(dstIconSize);
00489 QPainter p(&dstIcon);
00490 p.drawPixmap(rect.x(), rect.y(), tagIcon, 0, 0, rect.width(), rect.height());
00491 p.end();
00492 }
00493 return dstIcon;
00494 }
00495 else
00496 {
00497 return tagIcon;
00498 }
00499 }
00500
00501 }