]> git.lyx.org Git - lyx.git/blob - src/graphics/GraphicsLoader.C
partial framebox support
[lyx.git] / src / graphics / GraphicsLoader.C
1 /*
2  * \file GraphicsLoader.C
3  * Copyright 2002 the LyX Team
4  * Read the file COPYING
5  *
6  * \author Angus Leeming <leeming@lyx.org>
7  */
8
9 #include <config.h>
10
11 #ifdef __GNUG__
12 #pragma implementation
13 #endif
14
15 #include "GraphicsLoader.h"
16
17 #include "BufferView.h"
18
19 #include "GraphicsCache.h"
20 #include "GraphicsCacheItem.h"
21 #include "GraphicsImage.h"
22 #include "GraphicsParams.h"
23 #include "GraphicsSupport.h"
24
25 #include "frontends/LyXView.h"
26 #include "frontends/Timeout.h"
27
28 #include <boost/weak_ptr.hpp>
29 #include <boost/bind.hpp>
30 #include <boost/signals/trackable.hpp>
31
32 #include <list>
33
34 namespace grfx {
35
36 struct Loader::Impl : boost::signals::trackable {
37         ///
38         Impl(Params const &);
39         ///
40         ~Impl();
41         ///
42         void resetFile(string const &);
43         ///
44         void resetParams(Params const &);
45         ///
46         void createPixmap();
47
48         ///
49         void startLoading(Inset const &, BufferView const &);
50
51         /// The loading status of the image.
52         ImageStatus status_;
53         /** Must store a copy of the cached item to ensure that it is not
54          *  erased unexpectedly by the cache itself.
55          */
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_;
61
62 private:
63         ///
64         void statusChanged();
65         ///
66         void checkedLoading();
67
68         ///
69         Params params_;
70
71         ///
72         Timeout timer;
73         // Multiple Insets can share the same image
74         typedef std::list<Inset const *> InsetList;
75         ///
76         InsetList insets;
77         ///
78         boost::weak_ptr<BufferView const> view;
79 };
80
81
82 Loader::Loader()
83         : pimpl_(new Impl(Params()))
84 {}
85
86
87 Loader::Loader(string const & file, DisplayType type)
88         : pimpl_(new Impl(Params()))
89 {
90         reset(file, type);
91 }
92
93
94 Loader::Loader(string const & file, Params const & params)
95         : pimpl_(new Impl(params))
96 {
97         reset(file, params);
98 }
99
100
101 Loader::~Loader()
102 {}
103
104
105 void Loader::reset(string const & file, DisplayType type) const
106 {
107         Params params;
108         params.display = type;
109         pimpl_->resetParams(params);
110
111         pimpl_->resetFile(file);
112         pimpl_->createPixmap();
113 }
114
115
116 void Loader::reset(string const & file, Params const & params) const
117 {
118         pimpl_->resetParams(params);
119         pimpl_->resetFile(file);
120         pimpl_->createPixmap();
121 }
122
123
124 void Loader::reset(Params const & params) const
125 {
126         pimpl_->resetParams(params);
127         pimpl_->createPixmap();
128 }
129
130
131 void Loader::startLoading() const
132 {
133         if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
134                 return;
135         pimpl_->cached_item_->startLoading();
136 }
137
138
139 void Loader::startLoading(Inset const & inset, BufferView const & bv) const
140 {
141         if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
142                 return;
143         pimpl_->startLoading(inset, bv);
144 }
145
146
147 void Loader::startMonitoring() const
148 {
149         if (!pimpl_->cached_item_.get())
150                 return;
151
152         pimpl_->cached_item_->startMonitoring();
153 }
154
155
156 bool Loader::monitoring() const
157 {
158         if (!pimpl_->cached_item_.get())
159                 return false;
160
161         return pimpl_->cached_item_->monitoring();
162 }
163
164
165 unsigned long Loader::checksum() const
166 {
167         if (!pimpl_->cached_item_.get())
168                 return 0;
169
170         return pimpl_->cached_item_->checksum();
171 }
172
173
174 string const & Loader::filename() const
175 {
176         static string const empty;
177         return pimpl_->cached_item_.get() ?
178                 pimpl_->cached_item_->filename() : empty;
179 }
180
181
182 ImageStatus Loader::status() const
183 {
184         return pimpl_->status_;
185 }
186
187
188 boost::signals::connection Loader::connect(slot_type const & slot) const
189 {
190         return pimpl_->signal_.connect(slot);
191 }
192
193
194 Image const * Loader::image() const
195 {
196         return pimpl_->image_.get();
197 }
198
199
200 Loader::Impl::Impl(Params const & params)
201         : status_(WaitingToLoad), params_(params),
202           timer(2000, Timeout::ONETIME)
203 {
204         timer.timeout.connect(boost::bind(&Impl::checkedLoading, this));
205 }
206
207
208 Loader::Impl::~Impl()
209 {
210         resetFile(string());
211 }
212
213
214 void Loader::Impl::resetFile(string const & file)
215 {
216         string const old_file = cached_item_.get() ?
217                 cached_item_->filename() : string();
218
219         if (file == old_file)
220                 return;
221
222         // If monitoring() the current file, should continue to monitor the
223         // new file.
224         bool continue_monitoring = false;
225
226         if (!old_file.empty()) {
227                 continue_monitoring = cached_item_->monitoring();
228                 cached_item_.reset();
229                 Cache::get().remove(old_file);
230         }
231
232         status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
233         image_.reset();
234
235         if (cached_item_.get() || file.empty())
236                 return;
237
238         Cache & gc = Cache::get();
239         if (!gc.inCache(file))
240                 gc.add(file);
241
242         // We /must/ make a local copy of this.
243         cached_item_ = gc.item(file);
244         status_ = cached_item_->status();
245
246         if (continue_monitoring && !cached_item_->monitoring())
247                 cached_item_->startMonitoring();
248
249         cached_item_->connect(boost::bind(&Impl::statusChanged, this));
250 }
251
252
253 void Loader::Impl::resetParams(Params const & params)
254 {
255         if (params == params_)
256                 return;
257
258         params_ = params;
259         status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
260         image_.reset();
261 }
262
263
264 void Loader::Impl::statusChanged()
265 {
266         status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
267         createPixmap();
268         signal_();
269 }
270
271
272 void Loader::Impl::createPixmap()
273 {
274         if (!cached_item_.get() ||
275             params_.display == NoDisplay || status_ != Loaded)
276                 return;
277
278         image_.reset(cached_item_->image()->clone());
279
280         // These do nothing if there's nothing to do
281         image_->clip(params_);
282         image_->rotate(params_);
283         image_->scale(params_);
284
285         bool const success = image_->setPixmap(params_);
286
287         if (success) {
288                 status_ = Ready;
289         } else {
290                 image_.reset();
291                 status_ = ErrorGeneratingPixmap;
292         }
293 }
294
295
296 void Loader::Impl::startLoading(Inset const & inset, BufferView const & bv)
297 {
298         if (status_ != WaitingToLoad || timer.running())
299                 return;
300
301         InsetList::const_iterator it  = insets.begin();
302         InsetList::const_iterator end = insets.end();
303         it = std::find(it, end, &inset);
304         if (it == end)
305                 insets.push_back(&inset);
306         view = bv.owner()->view();
307
308         timer.start();
309 }
310
311
312 namespace {
313
314 struct FindVisibleInset {
315
316         FindVisibleInset(std::list<VisibleParagraph> const & vps) : vps_(vps) {}
317
318         bool operator()(Inset const * inset_ptr)
319         {
320                 if (!inset_ptr)
321                         return false;
322                 return isInsetVisible(*inset_ptr, vps_);
323         }
324
325 private:
326         std::list<VisibleParagraph> const & vps_;
327 };
328
329 } // namespace anon
330
331
332 void Loader::Impl::checkedLoading()
333 {
334         if (insets.empty() || !view.get())
335                 return;
336
337         std::list<VisibleParagraph> const vps =
338                 getVisibleParagraphs(*view.get());
339
340         InsetList::const_iterator it  = insets.begin();
341         InsetList::const_iterator end = insets.end();
342
343         it = std::find_if(it, end, FindVisibleInset(vps));
344
345         // One of the insets is visible, so start loading the image.
346         if (it != end)
347                 cached_item_->startLoading();
348 }
349
350
351 } // namespace grfx