3333
3434UBThumbnailScene::UBThumbnailScene (UBDocument* document)
3535 : mDocument{document}
36+ , mThumbnailItems {document->proxy ()->pageCount ()}
3637{
3738}
3839
@@ -82,20 +83,22 @@ void UBThumbnailScene::arrangeThumbnails(int fromIndex, int toIndex)
8283 for (int i = fromIndex; i < toIndex; ++i)
8384 {
8485 auto thumbnail = mThumbnailItems .at (i);
85- thumbnail->setThumbnailSize (thumbnailSize);
86- thumbnail->setFlag (QGraphicsItem::ItemIsSelectable, true );
8786
88- thumbnail->setColumn (columnIndex);
89- thumbnail->setRow (rowIndex);
90-
91- // start with a margin left
92- // step by width + spacing
93- // start with margin top
94- // step by height including label + spacing
95- const auto posX = margins.left () + columnIndex * gridSize.width () + horizontalCenterOffset;
96- const auto posY = margins.top () + rowIndex * gridSize.height ();
97-
98- thumbnail->setPos (posX, posY);
87+ if (thumbnail)
88+ {
89+ thumbnail->setThumbnailSize (thumbnailSize);
90+ thumbnail->setColumn (columnIndex);
91+ thumbnail->setRow (rowIndex);
92+
93+ // start with a margin left
94+ // step by width + spacing
95+ // start with margin top
96+ // step by height including label + spacing
97+ const auto posX = margins.left () + columnIndex * gridSize.width () + horizontalCenterOffset;
98+ const auto posY = margins.top () + rowIndex * gridSize.height ();
99+
100+ thumbnail->setPos (posX, posY);
101+ }
99102
100103 if (++columnIndex >= nbColumns)
101104 {
@@ -130,7 +133,7 @@ void UBThumbnailScene::hightlightItem(int index, bool only)
130133
131134 if (index >= 0 && index < mThumbnailItems .size ())
132135 {
133- mThumbnailItems . at (index)->setSelected (true );
136+ thumbnailAt (index)->setSelected (true );
134137 }
135138}
136139
@@ -139,23 +142,36 @@ int UBThumbnailScene::thumbnailCount() const
139142 return mThumbnailItems .size ();
140143}
141144
142- UBThumbnail* UBThumbnailScene::thumbnailAt (int index) const
145+ UBThumbnail* UBThumbnailScene::thumbnailAt (int index)
143146{
144147 if (index >= 0 && index < mThumbnailItems .size ())
145148 {
149+ if (!mThumbnailItems .at (index))
150+ {
151+ // create the missing thumbnail
152+ auto thumbnailItem = new UBThumbnail;
153+
154+ thumbnailItem->setPixmap (UBThumbnailAdaptor::get (mDocument ->proxy (), index));
155+ thumbnailItem->setSceneIndex (index);
156+
157+ mThumbnailItems [index] = thumbnailItem;
158+ addItem (thumbnailItem);
159+
160+ arrangeThumbnails (index, index + 1 );
161+ }
162+
146163 return mThumbnailItems .at (index);
147164 }
148165
149166 return nullptr ;
150167}
151168
152169/* *
153- * @brief (Re-)create all thumbnails for this scene.
170+ * @brief Create thumbnails for this scene.
154171 *
155- * Already existing thumbnails are first removed from the scene and deleted.
156- * Then all thumbnails for the document pages are asynchronously loaded and
157- * positioned on the scene. The application remains responsive even while
158- * loading thumbnails.
172+ * Thumbnails for the document pages above startIndex are asynchronously
173+ * loaded and positioned on the scene. The application remains responsive
174+ * even while loading thumbnails.
159175 *
160176 * It is even possible to interact with the already loaded thumbnails during
161177 * the loading process. So the already loaded pages can be moved, copied,
@@ -164,13 +180,10 @@ UBThumbnail* UBThumbnailScene::thumbnailAt(int index) const
164180 */
165181void UBThumbnailScene::createThumbnails (int startIndex)
166182{
167- // delete current thumbnails above startIndex
168- for ( int index = mThumbnailItems .size () - 1 ; index >= startIndex; --index )
183+ // skip already loaded thumbnails
184+ while (startIndex < mThumbnailItems .count () && mThumbnailItems . at ( startIndex) )
169185 {
170- auto item = mThumbnailItems .at (index);
171- removeItem (item);
172- mThumbnailItems .removeAt (index);
173- delete item;
186+ ++startIndex;
174187 }
175188
176189 // create the list of all thumbnail paths
@@ -187,6 +200,12 @@ void UBThumbnailScene::createThumbnails(int startIndex)
187200 // abort a running loader
188201 mLoader ->abort ();
189202 delete mLoader ;
203+ mLoader = nullptr ;
204+ }
205+
206+ if (paths.empty ())
207+ {
208+ return ;
190209 }
191210
192211 mLoader = new UBBackgroundLoader{paths, this };
@@ -236,7 +255,7 @@ void UBThumbnailScene::insertThumbnail(int pageIndex, std::shared_ptr<UBGraphics
236255 if (mLoader )
237256 {
238257 // restart loading remaining thumbnails
239- createThumbnails (mThumbnailItems . size () );
258+ createThumbnails (pageIndex );
240259 }
241260}
242261
@@ -259,7 +278,7 @@ void UBThumbnailScene::deleteThumbnail(int pageIndex, bool rearrange)
259278 if (mLoader )
260279 {
261280 // restart loading remaining thumbnails
262- createThumbnails (mThumbnailItems . size () );
281+ createThumbnails (pageIndex );
263282 }
264283
265284 if (mThumbnailItems .size () == 1 )
@@ -288,7 +307,7 @@ void UBThumbnailScene::moveThumbnail(int fromIndex, int toIndex)
288307 if (mLoader )
289308 {
290309 // restart loading remaining thumbnails
291- createThumbnails (mThumbnailItems . size () );
310+ createThumbnails (fromIndex );
292311 }
293312}
294313
@@ -298,7 +317,7 @@ void UBThumbnailScene::reloadThumbnail(int pageIndex)
298317 {
299318 auto thumbnail = mThumbnailItems .at (pageIndex);
300319
301- if (thumbnail && !thumbnail-> isExposed () )
320+ if (thumbnail)
302321 {
303322 thumbnail->setPixmap (UBThumbnailAdaptor::get (mDocument ->proxy (), pageIndex));
304323 }
@@ -334,7 +353,7 @@ void UBThumbnailScene::loadNextThumbnail()
334353 // max number of thumbnails to load in one pass
335354 constexpr int bulkSize{10 };
336355
337- if (mThumbnailItems . size () < mDocument -> proxy ()-> pageCount ())
356+ if (! mLoader -> isIdle ())
338357 {
339358 if (UBApplication::isClosing)
340359 {
@@ -348,7 +367,7 @@ void UBThumbnailScene::loadNextThumbnail()
348367 return ;
349368 }
350369
351- const auto firstIndex = mThumbnailItems . size () ;
370+ int firstIndex = - 1 ;
352371
353372 for (int i = 0 ; i < bulkSize; ++i)
354373 {
@@ -357,31 +376,43 @@ void UBThumbnailScene::loadNextThumbnail()
357376 break ;
358377 }
359378
360- // take next result and determine index from current number of thumbnails and
361- // not from result, because pages may have been added or removed in the meantime
379+ // take and process next result
362380 const auto result = mLoader ->takeResult ();
363- const auto nextIndex = mThumbnailItems . size () ;
364- QPixmap pixmap ;
381+ const auto index = result. first ;
382+ auto thumbnailItem = mThumbnailItems . at (index) ;
365383
366- if (result. second . isEmpty () )
384+ if (!thumbnailItem )
367385 {
368- pixmap = UBThumbnailAdaptor::generateMissingThumbnail (mDocument ->proxy (), nextIndex);
369- }
370- else
371- {
372- pixmap.loadFromData (result.second );
373- }
386+ QPixmap pixmap;
374387
375- auto thumbnailItem = new UBThumbnail;
388+ if (result.second .isEmpty ())
389+ {
390+ pixmap = UBThumbnailAdaptor::generateMissingThumbnail (mDocument ->proxy (), index);
391+ }
392+ else
393+ {
394+ pixmap.loadFromData (result.second );
395+ }
376396
377- thumbnailItem->setPixmap (pixmap);
378- thumbnailItem->setSceneIndex (nextIndex);
397+ thumbnailItem = new UBThumbnail;
379398
380- mThumbnailItems << thumbnailItem;
381- addItem (thumbnailItem);
399+ thumbnailItem->setPixmap (pixmap);
400+ thumbnailItem->setSceneIndex (index);
401+
402+ mThumbnailItems [index] = thumbnailItem;
403+ addItem (thumbnailItem);
404+
405+ if (firstIndex < 0 )
406+ {
407+ firstIndex = index;
408+ }
409+ }
382410 }
383411
384- arrangeThumbnails (firstIndex);
412+ if (firstIndex >= 0 )
413+ {
414+ arrangeThumbnails (firstIndex);
415+ }
385416
386417 // load next thumbnails in a deferred task executed on the main thread when it is idle.
387418 QTimer::singleShot (1 , mLoader , [this ]() { loadNextThumbnail (); });
0 commit comments