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