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