Kraxy/EBN: missing Q_OBJECT
[kphotoalbum.git] / ThumbnailView / ThumbnailCache.cpp
blobd7a2eb1bb8ef16123be7d054f6671731f0dc4d51
1 /* Copyright (C) 2008-2009 Henner Zeller <h.zeller@acm.org>
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
18 #include "ThumbnailView/ThumbnailCache.h"
20 #include <QPixmapCache>
21 #include <QTimer>
23 #include "DB/ResultId.h"
24 #include "ImageManager/Manager.h"
25 #include "Settings/SettingsData.h"
26 #include "ThumbnailView/ThumbnailRequest.h"
27 #include "DB/ImageInfo.h"
29 ThumbnailView::ThumbnailCache::ThumbnailCache()
30 : _displayList()
31 , _hotFrom(0)
32 , _hotTo(0)
33 , _lastHotFrom(0)
35 _asyncWarmingTimer = new QTimer( this );
36 _asyncWarmingTimer->setSingleShot(true);
37 connect( _asyncWarmingTimer, SIGNAL( timeout() ),
38 this, SLOT( slotAsyncCacheWarming() ) );
41 bool ThumbnailView::ThumbnailCache::find(const DB::ResultId& id,
42 QPixmap *result) const {
43 Q_ASSERT(result != NULL);
44 return QPixmapCache::find( thumbnailPixmapCacheKey(id), *result );
47 void ThumbnailView::ThumbnailCache::insert(const DB::ResultId& id,
48 const QPixmap &pixmap) {
49 QPixmapCache::insert( thumbnailPixmapCacheKey(id), pixmap );
52 void ThumbnailView::ThumbnailCache::clear()
54 QPixmapCache::clear();
57 void ThumbnailView::ThumbnailCache::setDisplayList(const DB::Result& list)
59 _displayList = list;
62 void ThumbnailView::ThumbnailCache::setThumbnailSize(const QSize& thumbSize)
64 if (thumbSize != _thumbSize) {
65 _thumbSize = thumbSize;
66 clear();
70 // Warm the cache around the current hot area. This slot is called
71 // asynchronously after the user has stopped scrolling.
72 void ThumbnailView::ThumbnailCache::slotAsyncCacheWarming()
74 if (!_thumbSize.isValid())
75 return;
77 const bool scrollDown = _hotFrom > _lastHotFrom;
78 _lastHotFrom = _hotFrom;
80 const int page = _hotTo - _hotFrom;
81 const int thumbSize = 4 * _thumbSize.width() * _thumbSize.height();
82 const int totalCacheableThumbs = Settings::SettingsData::instance()->thumbnailCacheBytes() / thumbSize;
83 // lets only use a part of the thumbnail cache because right now we're
84 // using the global QPixmapCache that is used by others as well.
85 const int preloadable = 3 * (totalCacheableThumbs - page) / 4;
86 _requestedImagesLock.lock();
87 _requestedImages.clear();
88 _requestedImagesLock.unlock();
89 ImageManager::Manager::instance()->stop(this);
91 // First, we make sure that the closer areas are covered: next and
92 // previous page.
94 // If we don't have much preload spots to spend, favour the
95 // direction in which we're going.
96 const int likelyDir = ((preloadable < 2*page)
97 ? qMin(preloadable, page)
98 : page);
99 const int unlikelyDir = ((preloadable < 2*page)
100 ? preloadable - likelyDir
101 : page);
103 if (scrollDown) {
104 requestRange(_hotTo, _hotTo + likelyDir);
105 requestRange(_hotFrom - unlikelyDir, _hotFrom);
106 } else {
107 requestRange(_hotFrom - likelyDir, _hotFrom);
108 requestRange(_hotTo, _hotTo + unlikelyDir);
111 // If we still have preload space to spend, load it now.
112 if (preloadable > 2*page) {
113 const int limit = preloadable / 2;
114 requestRange(_hotTo + page, _hotTo + limit);
115 requestRange(_hotFrom - limit, _hotFrom - page);
119 void ThumbnailView::ThumbnailCache::setHotArea(int from, int to)
121 const bool anyChange = (_hotFrom != from) || (_hotTo != to);
122 _hotFrom = from;
123 _hotTo = to;
124 if (anyChange) {
125 // Do the asynchronous warming after we've settled a bit.
126 _asyncWarmingTimer->stop();
127 _asyncWarmingTimer->start( 150 );
130 // TODO(hzeller) to something smart here and determine the scroll speed
131 // and the typical thumbnail generation speed and calculate with it what
132 // to do (e.g. only 1 thumbnail per page on really quick scrolling).
135 void ThumbnailView::ThumbnailCache::requestRange(int from, int to)
137 ImageManager::Manager* imgManager = ImageManager::Manager::instance();
138 if (from < 0) from = 0;
139 if (to > _displayList.size()) to = _displayList.size();
140 for (int i = from; i < to; ++i) {
141 const DB::ResultId id = _displayList.at(i);
142 if (QPixmapCache::find(thumbnailPixmapCacheKey(id)) != NULL)
143 continue;
144 DB::ImageInfoPtr info = id.fetchInfo();
145 const QString fileName = info->fileName(DB::AbsolutePath);
146 _requestedImagesLock.lock();
147 _requestedImages.insert(fileName, id);
148 _requestedImagesLock.unlock();
149 ImageManager::ImageRequest* request
150 = new ThumbnailCacheRequest(fileName, _thumbSize,
151 info->angle(), this);
152 request->setPriority( ImageManager::ThumbnailInvisible );
153 _requestedImagesLock.lock();
154 _requestedImages.insert(fileName, id);
155 _requestedImagesLock.unlock();
156 imgManager->load( request );
160 void ThumbnailView::ThumbnailCache::pixmapLoaded( const QString& fileName,
161 const QSize& size,
162 const QSize& fullSize,
163 int angle, const QImage& image,
164 const bool loadedOK)
166 Q_UNUSED(fullSize);
167 Q_UNUSED(angle);
169 if (!loadedOK || image.isNull())
170 return;
171 QPixmap pixmap( size );
172 pixmap = QPixmap::fromImage( image );
174 QMutexLocker l(&_requestedImagesLock);
175 RequestedMap::iterator found = _requestedImages.find(fileName);
176 if (found != _requestedImages.end()) {
177 insert(found.value(), pixmap);
178 _requestedImages.erase(found);
182 bool ThumbnailView::ThumbnailCache::thumbnailStillNeeded(const QString& fileName) const
184 QMutexLocker l(&_requestedImagesLock);
185 return _requestedImages.contains(fileName);
188 QString ThumbnailView::ThumbnailCache::thumbnailPixmapCacheKey(const DB::ResultId& id)
190 return QString::fromLatin1("thumbnail:%1").arg(toInt(id.rawId()));
193 #include "ThumbnailCache.moc"