]> git.lyx.org Git - lyx.git/blob - src/insets/RenderPreview.cpp
4afbe8d5009c15aeec191fd235c18de8d97e3bcb
[lyx.git] / src / insets / RenderPreview.cpp
1 /**
2  * \file RenderPreview.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 "insets/RenderPreview.h"
14 #include "insets/Inset.h"
15
16 #include "BufferView.h"
17 #include "Color.h"
18 #include "Dimension.h"
19 #include "gettext.h"
20 #include "LyX.h"
21 #include "LyXRC.h"
22 #include "MetricsInfo.h"
23
24 #include "frontends/FontMetrics.h"
25 #include "frontends/Painter.h"
26
27 #include "graphics/PreviewImage.h"
28 #include "graphics/PreviewLoader.h"
29 #include "graphics/Previews.h"
30
31 #include "support/FileName.h"
32 #include "support/lstrings.h"
33
34 #include <boost/bind.hpp>
35
36
37 namespace lyx {
38
39 using support::FileName;
40
41 using std::string;
42 using std::auto_ptr;
43
44
45 LyXRC_PreviewStatus RenderPreview::status()
46 {
47         return graphics::Previews::status();
48 }
49
50
51 RenderPreview::RenderPreview(Inset const * inset)
52         : parent_(inset)
53 {}
54
55
56 RenderPreview::RenderPreview(RenderPreview const & other,
57                              Inset const * inset)
58         : RenderBase(other),
59           boost::signals::trackable(),
60           snippet_(other.snippet_),
61           parent_(inset)
62 {}
63
64
65 RenderPreview::~RenderPreview()
66 {
67        if (ploader_connection_.connected())
68                ploader_connection_.disconnect();
69 }
70
71
72 auto_ptr<RenderBase> RenderPreview::clone(Inset const * inset) const
73 {
74         return auto_ptr<RenderBase>(new RenderPreview(*this, inset));
75 }
76
77
78 namespace {
79
80 graphics::PreviewLoader & getPreviewLoader(Buffer const & buffer)
81 {
82         graphics::Previews const & previews = graphics::Previews::get();
83         return previews.loader(buffer);
84 }
85
86
87 docstring const statusMessage(BufferView const * bv, string const & snippet)
88 {
89         BOOST_ASSERT(bv);
90
91         Buffer const & buffer = bv->buffer();
92         graphics::PreviewLoader const & loader = getPreviewLoader(buffer);
93         graphics::PreviewLoader::Status const status = loader.status(snippet);
94
95         docstring message;
96         switch (status) {
97         case graphics::PreviewLoader::InQueue:
98         case graphics::PreviewLoader::Processing:
99                 message = _("Preview loading");
100                 break;
101         case graphics::PreviewLoader::Ready:
102                 message = _("Preview ready");
103                 break;
104         case graphics::PreviewLoader::NotFound:
105                 message = _("Preview failed");
106                 break;
107         }
108
109         return message;
110 }
111
112 } // namespace anon
113
114
115 graphics::PreviewImage const *
116 RenderPreview::getPreviewImage(Buffer const & buffer) const
117 {
118         graphics::PreviewLoader const & loader = getPreviewLoader(buffer);
119         return loader.preview(snippet_);
120 }
121
122
123 bool RenderPreview::metrics(MetricsInfo & mi, Dimension & dim) const
124 {
125         BOOST_ASSERT(mi.base.bv);
126
127         graphics::PreviewImage const * const pimage =
128                 getPreviewImage(mi.base.bv->buffer());
129
130         if (pimage) {
131                 dim.asc = pimage->ascent();
132                 dim.des = pimage->descent();
133                 dim.wid = pimage->width();
134         } else {
135                 dim.asc = 50;
136                 dim.des = 0;
137
138                 Font font(mi.base.font);
139                 font.setFamily(Font::SANS_FAMILY);
140                 font.setSize(Font::SIZE_FOOTNOTE);
141                 docstring const stat = statusMessage(mi.base.bv, snippet_);
142                 dim.wid = 15 + theFontMetrics(font).width(stat);
143         }
144
145         bool const changed = dim_ != dim;
146         dim_ = dim;
147         return changed;
148 }
149
150
151 void RenderPreview::draw(PainterInfo & pi, int x, int y) const
152 {
153         BOOST_ASSERT(pi.base.bv);
154
155         graphics::PreviewImage const * const pimage =
156                 getPreviewImage(pi.base.bv->buffer());
157         graphics::Image const * const image = pimage ? pimage->image() : 0;
158
159         if (image) {
160                 pi.pain.image(x, y - dim_.asc, dim_.wid, dim_.height(),
161                               *image);
162
163         } else {
164                 int const offset = Inset::TEXT_TO_INSET_OFFSET;
165
166                 pi.pain.rectangle(x + offset,
167                                   y - dim_.asc,
168                                   dim_.wid - 2 * offset,
169                                   dim_.asc + dim_.des,
170                                   Color::foreground);
171
172                 Font font(pi.base.font);
173                 font.setFamily(Font::SANS_FAMILY);
174                 font.setSize(Font::SIZE_FOOTNOTE);
175
176                 docstring const stat = statusMessage(pi.base.bv, snippet_);
177                 pi.pain.text(x + offset + 6,
178                              y - theFontMetrics(font).maxAscent() - 4,
179                              stat, font);
180         }
181 }
182
183
184 void RenderPreview::startLoading(Buffer const & buffer) const
185 {
186         if (status() == LyXRC::PREVIEW_OFF || snippet_.empty())
187                 return;
188
189         graphics::PreviewLoader const & loader = getPreviewLoader(buffer);
190         loader.startLoading();
191 }
192
193
194 void RenderPreview::addPreview(docstring const & latex_snippet,
195                                Buffer const & buffer)
196 {
197         if (status() == LyXRC::PREVIEW_OFF)
198                 return;
199
200         graphics::PreviewLoader & loader = getPreviewLoader(buffer);
201         addPreview(latex_snippet, loader);
202 }
203
204
205 void RenderPreview::addPreview(docstring const & latex_snippet,
206                                graphics::PreviewLoader & ploader)
207 {
208         if (status() == LyXRC::PREVIEW_OFF)
209                 return;
210
211         // FIXME UNICODE
212         // We have to make sure that we call latex with the right encoding
213         snippet_ = support::trim(to_utf8(latex_snippet));
214         if (snippet_.empty())
215                 return;
216
217         if (ploader.preview(snippet_))
218                 return;
219
220         // If this is the first time of calling, connect to the
221         // PreviewLoader signal that'll inform us when the preview image
222         // is ready for loading.
223         if (!ploader_connection_.connected()) {
224                 ploader_connection_ = ploader.connect(
225                         boost::bind(&RenderPreview::imageReady, this, _1));
226         }
227
228         ploader.add(snippet_);
229 }
230
231
232 void RenderPreview::removePreview(Buffer const & buffer)
233 {
234         if (snippet_.empty())
235                 return;
236
237         graphics::PreviewLoader & loader = getPreviewLoader(buffer);
238         loader.remove(snippet_);
239         snippet_.erase();
240 }
241
242
243 void RenderPreview::imageReady(graphics::PreviewImage const & pimage)
244 {
245         // Check the current snippet is the same as that previewed.
246         if (snippet_ == pimage.snippet())
247                 LyX::cref().updateInset(parent_);
248 }
249
250
251 RenderMonitoredPreview::RenderMonitoredPreview(Inset const * inset)
252         : RenderPreview(inset),
253           monitor_(FileName(), 2000)
254 {}
255
256
257 void RenderMonitoredPreview::setAbsFile(FileName const & file)
258 {
259         monitor_.reset(file);
260 }
261
262
263 void RenderMonitoredPreview::draw(PainterInfo & pi, int x, int y) const
264 {
265         RenderPreview::draw(pi, x, y);
266         if (!monitoring())
267                 startMonitoring();
268 }
269
270
271 boost::signals::connection
272 RenderMonitoredPreview::fileChanged(slot_type const & slot)
273 {
274         return monitor_.connect(slot);
275 }
276
277 } // namespace lyx