]> git.lyx.org Git - lyx.git/blob - src/graphics/GraphicsLoader.C
Point fix, earlier forgotten
[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 #include "GraphicsLoader.h"
14
15 #include "GraphicsCache.h"
16 #include "GraphicsCacheItem.h"
17 #include "GraphicsImage.h"
18 #include "GraphicsParams.h"
19 #include "LoaderQueue.h"
20
21 #include "frontends/LyXView.h"
22
23 #include <boost/bind.hpp>
24 #include <boost/signals/trackable.hpp>
25
26 #include <list>
27
28 namespace lyx {
29 namespace graphics {
30
31 struct Loader::Impl : boost::signals::trackable {
32         ///
33         Impl();
34         ///
35         ~Impl();
36         ///
37         void resetFile(string const &);
38         ///
39         void resetParams(Params const &);
40         ///
41         void createPixmap();
42         ///
43         void startLoading();
44         ///
45         Params const & params() const { return params_; }
46
47         /// The loading status of the image.
48         ImageStatus status_;
49         /** Must store a copy of the cached item to ensure that it is not
50          *  erased unexpectedly by the cache itself.
51          */
52         Cache::ItemPtr cached_item_;
53         /// We modify a local copy of the image once it is loaded.
54         Image::ImagePtr image_;
55         /// This signal is emitted when the image loading status changes.
56         boost::signal0<void> signal_;
57
58 private:
59         ///
60         void statusChanged();
61         ///
62         void checkedLoading();
63
64         ///
65         Params params_;
66
67 };
68
69
70 Loader::Loader()
71         : pimpl_(new Impl)
72 {}
73
74
75 Loader::Loader(string const & file, DisplayType type)
76         : pimpl_(new Impl)
77 {
78         reset(file, type);
79 }
80
81
82 Loader::Loader(string const & file, Params const & params)
83         : pimpl_(new Impl)
84 {
85         reset(file, params);
86 }
87
88
89 Loader::Loader(Loader const & other)
90         : pimpl_(new Impl)
91 {
92         Params const & params = other.pimpl_->params();
93         reset(params.filename, params);
94 }
95
96
97 Loader::~Loader()
98 {}
99
100
101 Loader & Loader::operator=(Loader const & other)
102 {
103         if (this != &other) {
104                 Params const & params = other.pimpl_->params();
105                 reset(params.filename, params);
106         }
107         return *this;
108 }
109
110
111 void Loader::reset(string const & file, DisplayType type) const
112 {
113         Params params;
114         params.display = type;
115         pimpl_->resetParams(params);
116
117         pimpl_->resetFile(file);
118         pimpl_->createPixmap();
119 }
120
121
122 void Loader::reset(string const & file, Params const & params) const
123 {
124         pimpl_->resetParams(params);
125         pimpl_->resetFile(file);
126         pimpl_->createPixmap();
127 }
128
129
130 void Loader::reset(Params const & params) const
131 {
132         pimpl_->resetParams(params);
133         pimpl_->createPixmap();
134 }
135
136
137 void Loader::startLoading() const
138 {
139         if (pimpl_->status_ != WaitingToLoad || !pimpl_->cached_item_.get())
140                 return;
141         pimpl_->startLoading();
142 }
143
144
145 void Loader::startMonitoring() const
146 {
147         if (!pimpl_->cached_item_.get())
148                 return;
149
150         pimpl_->cached_item_->startMonitoring();
151 }
152
153
154 bool Loader::monitoring() const
155 {
156         if (!pimpl_->cached_item_.get())
157                 return false;
158
159         return pimpl_->cached_item_->monitoring();
160 }
161
162
163 unsigned long Loader::checksum() const
164 {
165         if (!pimpl_->cached_item_.get())
166                 return 0;
167
168         return pimpl_->cached_item_->checksum();
169 }
170
171
172 string const & Loader::filename() const
173 {
174         static string const empty;
175         return pimpl_->cached_item_.get() ?
176                 pimpl_->cached_item_->filename() : empty;
177 }
178
179
180 ImageStatus Loader::status() const
181 {
182         return pimpl_->status_;
183 }
184
185
186 boost::signals::connection Loader::connect(slot_type const & slot) const
187 {
188         return pimpl_->signal_.connect(slot);
189 }
190
191
192 Image const * Loader::image() const
193 {
194         return pimpl_->image_.get();
195 }
196
197
198 Loader::Impl::Impl()
199         : status_(WaitingToLoad)
200 {
201 }
202
203
204 Loader::Impl::~Impl()
205 {
206         resetFile(string());
207 }
208
209
210 void Loader::Impl::resetFile(string const & file)
211 {
212         string const old_file = cached_item_.get() ?
213                 cached_item_->filename() : string();
214
215         if (file == old_file)
216                 return;
217
218         // If monitoring() the current file, should continue to monitor the
219         // new file.
220         bool continue_monitoring = false;
221
222         if (!old_file.empty()) {
223                 continue_monitoring = cached_item_->monitoring();
224                 cached_item_.reset();
225                 Cache::get().remove(old_file);
226         }
227
228         status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
229         image_.reset();
230
231         if (cached_item_.get() || file.empty())
232                 return;
233
234         Cache & gc = Cache::get();
235         if (!gc.inCache(file))
236                 gc.add(file);
237
238         // We /must/ make a local copy of this.
239         cached_item_ = gc.item(file);
240         status_ = cached_item_->status();
241
242         if (continue_monitoring && !cached_item_->monitoring())
243                 cached_item_->startMonitoring();
244
245         cached_item_->connect(boost::bind(&Impl::statusChanged, this));
246 }
247
248
249 void Loader::Impl::resetParams(Params const & params)
250 {
251         if (params == params_)
252                 return;
253
254         params_ = params;
255         status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
256         image_.reset();
257 }
258
259
260 void Loader::Impl::statusChanged()
261 {
262         status_ = cached_item_.get() ? cached_item_->status() : WaitingToLoad;
263         createPixmap();
264         signal_();
265 }
266
267
268 void Loader::Impl::createPixmap()
269 {
270         if (!cached_item_.get() ||
271             params_.display == NoDisplay || status_ != Loaded)
272                 return;
273
274         image_.reset(cached_item_->image()->clone());
275
276         // These do nothing if there's nothing to do
277         image_->clip(params_);
278         image_->rotate(params_);
279         image_->scale(params_);
280
281         bool const success = image_->setPixmap(params_);
282
283         if (success) {
284                 status_ = Ready;
285         } else {
286                 image_.reset();
287                 status_ = ErrorGeneratingPixmap;
288         }
289 }
290
291 void Loader::Impl::startLoading()
292 {
293         if (status_ != WaitingToLoad)
294                 return;
295
296         LoaderQueue::get().touch(cached_item_);
297 }
298
299
300 } // namespace graphics
301 } // namespace lyx