2 * \file GraphicsLoader.C
3 * Copyright 2002 the LyX Team
4 * Read the file COPYING
6 * \author Angus Leeming <leeming@lyx.org>
12 #pragma implementation
15 #include "GraphicsLoader.h"
17 #include "BufferView.h"
19 #include "GraphicsCache.h"
20 #include "GraphicsCacheItem.h"
21 #include "GraphicsImage.h"
22 #include "GraphicsParams.h"
23 #include "GraphicsSupport.h"
25 #include "frontends/LyXView.h"
26 #include "frontends/Timeout.h"
28 #include <boost/weak_ptr.hpp>
29 #include <boost/bind.hpp>
30 #include <boost/signals/trackable.hpp>
36 struct Loader::Impl : boost::signals::trackable {
42 void resetFile(string const &);
44 void resetParams(Params const &);
49 void startLoading(Inset const &, BufferView const &);
51 /// The loading status of the image.
53 /** Must store a copy of the cached item to ensure that it is not
54 * erased unexpectedly by the cache itself.
56 Cache::ItemPtr cached_item_;
57 /// We modify a local copy of the image once it is loaded.
58 Image::ImagePtr image_;
59 /// This signal is emitted when the image loading status changes.
60 boost::signal0<void> signal_;
66 void checkedLoading();
73 // Multiple Insets can share the same image
74 typedef std::list<Inset const *> InsetList;
78 boost::weak_ptr<BufferView const> view;
83 : pimpl_(new Impl(Params()))
87 Loader::Loader(string const & file, DisplayType type)
88 : pimpl_(new Impl(Params()))
94 Loader::Loader(string const & file, Params const & params)
95 : pimpl_(new Impl(params))
105 void Loader::reset(string const & file, DisplayType type) const
108 params.display = type;
109 pimpl_->resetParams(params);
111 pimpl_->resetFile(file);
112 pimpl_->createPixmap();
116 void Loader::reset(string const & file, Params const & params) const
118 pimpl_->resetParams(params);
119 pimpl_->resetFile(file);
120 pimpl_->createPixmap();
124 void Loader::reset(Params const & params) const
126 pimpl_->resetParams(params);
127 pimpl_->createPixmap();
131 void Loader::startLoading() const
133 if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
135 pimpl_->cached_item_->startLoading();
139 void Loader::startLoading(Inset const & inset, BufferView const & bv) const
141 if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
143 pimpl_->startLoading(inset, bv);
147 void Loader::startMonitoring() const
149 if (!pimpl_->cached_item_.get())
152 pimpl_->cached_item_->startMonitoring();
156 bool Loader::monitoring() const
158 if (!pimpl_->cached_item_.get())
161 return pimpl_->cached_item_->monitoring();
165 unsigned long Loader::checksum() const
167 if (!pimpl_->cached_item_.get())
170 return pimpl_->cached_item_->checksum();
174 string const & Loader::filename() const
176 static string const empty;
177 return pimpl_->cached_item_.get() ?
178 pimpl_->cached_item_->filename() : empty;
182 ImageStatus Loader::status() const
184 return pimpl_->status_;
188 boost::signals::connection Loader::connect(slot_type const & slot) const
190 return pimpl_->signal_.connect(slot);
194 Image const * Loader::image() const
196 return pimpl_->image_.get();
200 Loader::Impl::Impl(Params const & params)
201 : status_(WaitingToLoad), params_(params),
202 timer(2000, Timeout::ONETIME)
204 timer.timeout.connect(boost::bind(&Impl::checkedLoading, this));
208 Loader::Impl::~Impl()
214 void Loader::Impl::resetFile(string const & file)
216 string const old_file = cached_item_.get() ?
217 cached_item_->filename() : string();
219 if (file == old_file)
222 // If monitoring() the current file, should continue to monitor the
224 bool continue_monitoring = false;
226 if (!old_file.empty()) {
227 continue_monitoring = cached_item_->monitoring();
228 cached_item_.reset();
229 Cache::get().remove(old_file);
232 status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
235 if (cached_item_.get() || file.empty())
238 Cache & gc = Cache::get();
239 if (!gc.inCache(file))
242 // We /must/ make a local copy of this.
243 cached_item_ = gc.item(file);
244 status_ = cached_item_->status();
246 if (continue_monitoring && !cached_item_->monitoring())
247 cached_item_->startMonitoring();
249 cached_item_->connect(boost::bind(&Impl::statusChanged, this));
253 void Loader::Impl::resetParams(Params const & params)
255 if (params == params_)
259 status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
264 void Loader::Impl::statusChanged()
266 status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
272 void Loader::Impl::createPixmap()
274 if (!cached_item_.get() ||
275 params_.display == NoDisplay || status_ != Loaded)
278 image_.reset(cached_item_->image()->clone());
280 // These do nothing if there's nothing to do
281 image_->clip(params_);
282 image_->rotate(params_);
283 image_->scale(params_);
285 bool const success = image_->setPixmap(params_);
291 status_ = ErrorGeneratingPixmap;
296 void Loader::Impl::startLoading(Inset const & inset, BufferView const & bv)
298 if (status_ != WaitingToLoad || timer.running())
301 InsetList::const_iterator it = insets.begin();
302 InsetList::const_iterator end = insets.end();
303 it = std::find(it, end, &inset);
305 insets.push_back(&inset);
306 view = bv.owner()->view();
314 struct FindVisibleInset {
316 FindVisibleInset(std::list<VisibleParagraph> const & vps) : vps_(vps) {}
318 bool operator()(Inset const * inset_ptr)
322 return isInsetVisible(*inset_ptr, vps_);
326 std::list<VisibleParagraph> const & vps_;
332 void Loader::Impl::checkedLoading()
334 if (insets.empty() || !view.get())
337 std::list<VisibleParagraph> const vps =
338 getVisibleParagraphs(*view.get());
340 InsetList::const_iterator it = insets.begin();
341 InsetList::const_iterator end = insets.end();
343 it = std::find_if(it, end, FindVisibleInset(vps));
345 // One of the insets is visible, so start loading the image.
347 cached_item_->startLoading();