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