2 * \file GraphicsLoader.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS.
13 #include "GraphicsLoader.h"
15 #include "GraphicsCacheItem.h"
16 #include "GraphicsImage.h"
17 #include "GraphicsParams.h"
18 #include "GraphicsCache.h"
20 #include "support/debug.h"
21 #include "support/Timeout.h"
23 #include <boost/bind.hpp>
29 using namespace lyx::support
;
35 /////////////////////////////////////////////////////////////////////
39 /////////////////////////////////////////////////////////////////////
43 /// Use this to request that the item is loaded.
44 void touch(Cache::ItemPtr
const & item
);
45 /// Query whether the clock is ticking.
47 ///get the and only instance of the class
48 static LoaderQueue
& get();
50 /// This class is a singleton class... use LoaderQueue::get() instead
52 /// The in-progress loading queue (elements are unique here).
53 list
<Cache::ItemPtr
> cache_queue_
;
54 /// Used to make the insertion of new elements faster.
55 set
<Cache::ItemPtr
> cache_set_
;
56 /// Newly touched elements go here. loadNext moves them to cache_queue_
57 queue
<Cache::ItemPtr
> bucket_
;
63 /** This is the 'threaded' method, that does the loading in the
74 //static int s_numimages_ = 5;
75 //static int s_millisecs_ = 500;
77 static int s_numimages_
= 10;
78 static int s_millisecs_
= 500;
80 LoaderQueue
& LoaderQueue::get()
82 static LoaderQueue singleton
;
87 void LoaderQueue::loadNext()
89 LYXERR(Debug::GRAPHICS
, "LoaderQueue: "
90 << cache_queue_
.size() << " items in the queue");
91 int counter
= s_numimages_
;
92 while (cache_queue_
.size() && counter
--) {
93 Cache::ItemPtr ptr
= cache_queue_
.front();
94 cache_set_
.erase(ptr
);
95 cache_queue_
.pop_front();
96 if (ptr
->status() == WaitingToLoad
)
99 if (cache_queue_
.size()) {
107 LoaderQueue::LoaderQueue() : timer(s_millisecs_
, Timeout::ONETIME
),
110 timer
.timeout
.connect(boost::bind(&LoaderQueue::loadNext
, this));
114 void LoaderQueue::startLoader()
116 LYXERR(Debug::GRAPHICS
, "LoaderQueue: waking up");
118 timer
.setTimeout(s_millisecs_
);
123 void LoaderQueue::stopLoader()
127 LYXERR(Debug::GRAPHICS
, "LoaderQueue: I'm going to sleep");
131 bool LoaderQueue::running() const
137 void LoaderQueue::touch(Cache::ItemPtr
const & item
)
139 if (! cache_set_
.insert(item
).second
) {
140 list
<Cache::ItemPtr
>::iterator
141 it
= cache_queue_
.begin();
142 list
<Cache::ItemPtr
>::iterator
143 end
= cache_queue_
.end();
145 it
= find(it
, end
, item
);
147 cache_queue_
.erase(it
);
149 cache_queue_
.push_front(item
);
156 /////////////////////////////////////////////////////////////////////
160 /////////////////////////////////////////////////////////////////////
162 typedef boost::shared_ptr
<Image
> ImagePtr
;
164 class Loader::Impl
: public boost::signals::trackable
{
171 void resetFile(FileName
const &);
173 void resetParams(Params
const &);
179 Params
const & params() const { return params_
; }
181 /// The loading status of the image.
183 /** Must store a copy of the cached item to ensure that it is not
184 * erased unexpectedly by the cache itself.
186 Cache::ItemPtr cached_item_
;
187 /// We modify a local copy of the image once it is loaded.
189 /// This signal is emitted when the image loading status changes.
190 boost::signal
<void()> signal_
;
191 /// The connection of the signal StatusChanged
192 boost::signals::connection sc_
;
196 void statusChanged();
198 void checkedLoading();
210 Loader::Loader(FileName
const & file
, bool display
)
213 reset(file
, display
);
217 Loader::Loader(FileName
const & file
, Params
const & params
)
224 Loader::Loader(Loader
const & other
)
227 Params
const & params
= other
.pimpl_
->params();
228 reset(params
.filename
, params
);
238 Loader
& Loader::operator=(Loader
const & other
)
240 if (this != &other
) {
241 Params
const & params
= other
.pimpl_
->params();
242 reset(params
.filename
, params
);
248 void Loader::reset(FileName
const & file
, bool display
) const
251 params
.display
= display
;
252 pimpl_
->resetParams(params
);
254 pimpl_
->resetFile(file
);
255 pimpl_
->createPixmap();
259 void Loader::reset(FileName
const & file
, Params
const & params
) const
261 pimpl_
->resetParams(params
);
262 pimpl_
->resetFile(file
);
263 pimpl_
->createPixmap();
267 void Loader::reset(Params
const & params
) const
269 pimpl_
->resetParams(params
);
270 pimpl_
->createPixmap();
274 void Loader::startLoading() const
276 if (pimpl_
->status_
!= WaitingToLoad
|| !pimpl_
->cached_item_
.get())
278 pimpl_
->startLoading();
282 void Loader::reload() const
284 pimpl_
->cached_item_
->startLoading();
288 void Loader::startMonitoring() const
290 if (!pimpl_
->cached_item_
.get())
293 pimpl_
->cached_item_
->startMonitoring();
297 bool Loader::monitoring() const
299 if (!pimpl_
->cached_item_
.get())
302 return pimpl_
->cached_item_
->monitoring();
306 unsigned long Loader::checksum() const
308 if (!pimpl_
->cached_item_
.get())
311 return pimpl_
->cached_item_
->checksum();
315 FileName
const & Loader::filename() const
317 static FileName
const empty
;
318 return pimpl_
->cached_item_
.get() ?
319 pimpl_
->cached_item_
->filename() : empty
;
323 ImageStatus
Loader::status() const
325 return pimpl_
->status_
;
329 boost::signals::connection
Loader::connect(slot_type
const & slot
) const
331 return pimpl_
->signal_
.connect(slot
);
335 Image
const * Loader::image() const
337 return pimpl_
->image_
.get();
342 : status_(WaitingToLoad
)
347 Loader::Impl::~Impl()
349 resetFile(FileName());
353 void Loader::Impl::resetFile(FileName
const & file
)
355 FileName
const old_file
= cached_item_
.get() ?
356 cached_item_
->filename() : FileName();
358 if (file
== old_file
)
361 // If monitoring() the current file, should continue to monitor the
363 bool continue_monitoring
= false;
365 if (!old_file
.empty()) {
366 continue_monitoring
= cached_item_
->monitoring();
367 // cached_item_ is going to be reset, so the connected
368 // signal needs to be disconnected.
370 cached_item_
.reset();
371 Cache::get().remove(old_file
);
374 status_
= cached_item_
.get() ? cached_item_
->status() : WaitingToLoad
;
377 if (cached_item_
.get() || file
.empty())
380 Cache
& gc
= Cache::get();
381 if (!gc
.inCache(file
))
384 // We /must/ make a local copy of this.
385 cached_item_
= gc
.item(file
);
386 status_
= cached_item_
->status();
388 if (continue_monitoring
&& !cached_item_
->monitoring())
389 cached_item_
->startMonitoring();
391 sc_
= cached_item_
->connect(boost::bind(&Impl::statusChanged
, this));
395 void Loader::Impl::resetParams(Params
const & params
)
397 if (params
== params_
)
401 status_
= cached_item_
.get() ? cached_item_
->status() : WaitingToLoad
;
406 void Loader::Impl::statusChanged()
408 status_
= cached_item_
.get() ? cached_item_
->status() : WaitingToLoad
;
414 void Loader::Impl::createPixmap()
416 if (!params_
.display
|| status_
!= Loaded
)
419 if (!cached_item_
.get()) {
420 LYXERR(Debug::GRAPHICS
, "pixmap not cached yet");
424 if (!cached_item_
->image()) {
425 // There must have been a problem reading the file.
426 LYXERR(Debug::GRAPHICS
, "Graphics file not loaded.");
430 image_
.reset(cached_item_
->image()->clone());
432 bool const success
= image_
->setPixmap(params_
);
438 status_
= ErrorGeneratingPixmap
;
442 void Loader::Impl::startLoading()
444 if (status_
!= WaitingToLoad
)
447 if (cached_item_
->tryDisplayFormat()) {
453 LoaderQueue::get().touch(cached_item_
);
457 } // namespace graphics