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