]> git.lyx.org Git - lyx.git/blob - src/insets/ExternalTransforms.C
removing update calls
[lyx.git] / src / insets / ExternalTransforms.C
1 /**
2  * \file ExternalTransforms.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 "ExternalTransforms.h"
14
15 #include "debug.h"
16
17 #include "support/lstrings.h"
18 #include "support/lyxlib.h" // float_equal
19 #include "support/translator.h"
20
21 #include <boost/regex.hpp>
22 #include "support/std_sstream.h"
23 #include <cmath> // std::abs
24
25 using lyx::support::float_equal;
26
27 using std::string;
28
29
30 namespace lyx {
31 namespace external {
32
33 string const ExtraData::get(string const & id) const
34 {
35         std::map<string, string>::const_iterator it = data_.find(id);
36         return it == data_.end() ? string() : it->second;
37 }
38
39
40 void ExtraData::set(string const & id, string const & data)
41 {
42         data_[id] = data;
43 }
44
45
46 bool ResizeData::no_resize() const
47 {
48         return float_equal(scale, 0.0, 0.05) &&
49                 width.zero() && height.zero();
50 }
51
52
53 bool RotationData::no_rotation() const
54 {
55         return (std::abs(angle()) < 0.1);
56 }
57
58
59 void RotationData::angle(double a)
60 {
61         // Ensure that angle_ lies in the range -360 < angle_ < 360.
62         int const multiples = int(a) / 360;
63         angle_ = a - (multiples * 360);
64 }
65
66
67 namespace {
68
69 typedef Translator<RotationData::OriginType, string> OriginTranslator;
70 OriginTranslator const & originTranslator();
71
72 } // namespace anon
73
74
75 void RotationData::origin(string const & o)
76 {
77         origin_ = originTranslator().find(o);
78 }
79
80
81 string const RotationData::originString() const
82 {
83         return originTranslator().find(origin_);
84 }
85
86
87 string const ResizeLatexCommand::front_impl() const
88 {
89         if (data.no_resize())
90                 return string();
91
92         std::ostringstream os;
93         if (!float_equal(data.scale, 0.0, 0.05)) {
94                 double const scl = data.scale / 100.0;
95                 os << "\\scalebox{" << scl << "}{" << scl << "}{";
96         } else {
97                 os << "\\resizebox{"
98                    << (data.width.zero()  ?
99                        "!" : data.width.asLatexString()) << "}{"
100                    << (data.height.zero() ?
101                        "!" : data.height.asLatexString()) << "}{";
102         }
103         return os.str();
104 }
105
106
107 string const ResizeLatexCommand::back_impl() const
108 {
109         if (data.no_resize())
110                 return string();
111
112         return "}";
113 }
114
115
116 namespace {
117
118 std::ostream & operator<<(std::ostream & os, RotationData::OriginType type)
119 {
120         switch (type) {
121         case RotationData::DEFAULT:
122         case RotationData::CENTER:
123                 break;
124         case RotationData::TOPLEFT:
125         case RotationData::TOPCENTER:
126         case RotationData::TOPRIGHT:
127                 os << 't';
128                 break;
129         case RotationData::BOTTOMLEFT:
130         case RotationData::BOTTOMCENTER:
131         case RotationData::BOTTOMRIGHT:
132                 os << 'b';
133                 break;
134         case RotationData::BASELINELEFT:
135         case RotationData::BASELINECENTER:
136         case RotationData::BASELINERIGHT:
137                 os << 'B';
138                 break;
139         }
140
141         switch (type) {
142         case RotationData::DEFAULT:
143                 break;
144         case RotationData::TOPLEFT:
145         case RotationData::BOTTOMLEFT:
146         case RotationData::BASELINELEFT:
147                 os << 'l';
148                 break;
149         case RotationData::CENTER:
150         case RotationData::TOPCENTER:
151         case RotationData::BOTTOMCENTER:
152         case RotationData::BASELINECENTER:
153                 os << 'c';
154                 break;
155         case RotationData::TOPRIGHT:
156         case RotationData::BOTTOMRIGHT:
157         case RotationData::BASELINERIGHT:
158                 os << 'r';
159                 break;
160         }
161
162         return os;
163 }
164
165 } // namespace anon
166
167
168 string const RotationLatexCommand::front_impl() const
169 {
170         if (data.no_rotation())
171                 return string();
172
173         std::ostringstream os;
174         os << "\\rotatebox";
175
176         if (data.origin() != RotationData::DEFAULT)
177                 os << "[origin=" << data.origin() << ']';
178
179         os << '{' << data.angle() << "}{";
180         return os.str();
181 }
182
183
184 string const RotationLatexCommand::back_impl() const
185 {
186         if (data.no_rotation())
187                 return string();
188
189         return "}";
190 }
191
192
193 string const  ClipLatexOption::option_impl() const
194 {
195         if (!data.clip || data.bbox.empty())
196                 return string();
197
198         std::ostringstream os;
199         if (!data.bbox.empty())
200                 os << "bb=" << data.bbox << ',';
201         if (data.clip)
202                 os << "clip,";
203         return os.str();
204 }
205
206
207 string const ResizeLatexOption::option_impl() const
208 {
209         if (data.no_resize())
210                 return string();
211
212         std::ostringstream os;
213         if (!float_equal(data.scale, 0.0, 0.05)) {
214                 if (!float_equal(data.scale, 100.0, 0.05))
215                         os << "scale=" << data.scale / 100.0 << ',';
216                 return os.str();
217         }
218
219         if (!data.width.zero())
220                 os << "width=" << data.width.asLatexString() << ',';
221         if (!data.height.zero())
222                 os << "height=" << data.height.asLatexString() << ',';
223         if (data.keepAspectRatio)
224                 os << "keepaspectratio,";
225
226         return os.str();
227 }
228
229
230 string const RotationLatexOption ::option_impl() const
231 {
232         if (data.no_rotation())
233                 return string();
234
235         std::ostringstream os;
236         os << "angle=" << data.angle() << ',';
237
238         if (data.origin() != RotationData::DEFAULT)
239                 os << "origin=" << data.origin() << ',';
240
241         return os.str();
242 }
243
244
245 string const sanitizeDocBookOption(string const & input)
246 {
247         return input;
248 }
249
250
251 string const sanitizeLatexOption(string const & input)
252 {
253         string::const_iterator begin = input.begin();
254         string::const_iterator end   = input.end();
255         string::const_iterator it = begin;
256
257         // Strip any leading commas
258         // "[,,,,foo..." -> "foo..."
259         string output;
260         boost::smatch what;
261         static boost::regex const front("^( *[[],*)(.*)$");
262
263         regex_match(it, end, what, front, boost::match_partial);
264         if (!what[0].matched) {
265                 lyxerr << "Unable to sanitize LaTeX \"Option\": "
266                        << output << '\n';
267                 return string();
268         }
269         it =  what[1].second;
270
271         // Replace any consecutive commas with a single one
272         // "foo,,,,bar" -> "foo,bar"
273         // with iterator now pointing to 'b'
274         static boost::regex const commas("([^,]*)(,,*)(.*)$");
275         for (; it != end;) {
276                 regex_match(it, end, what, commas, boost::match_partial);
277                 if (!what[0].matched) {
278                         output += string(it, end);
279                         break;
280                 }
281                 output += what.str(1) + ",";
282                 it = what[3].first;
283         }
284
285         // Strip any trailing commas
286         // "...foo,,,]" -> "...foo"
287         static boost::regex const back("^(.*[^,])(,*[]] *)$");
288         regex_match(output, what, back);
289         if (!what[0].matched) {
290                 lyxerr << "Unable to sanitize LaTeX \"Option\": "
291                        << output << '\n';
292                 return string();
293         }
294         output = what.str(1);
295
296         // Remove any surrounding whitespace
297         output = lyx::support::trim(output);
298
299         // If the thing is empty, leave it so, else wrap it in square brackets.
300         return output.empty() ? output : "[" + output + "]";
301 }
302
303
304 string const sanitizeLinuxDocOption(string const & input)
305 {
306         return input;
307 }
308
309
310 namespace {
311
312 template <typename Factory, typename Data, typename Transformer>
313 void extractIt(boost::any const & any_factory,
314                Data const & data, Transformer & transformer)
315 {
316         if (any_factory.type() != typeid(Factory))
317                 return;
318
319         Factory factory = boost::any_cast<Factory>(any_factory);
320         if (!factory.empty())
321                 transformer = factory(data);
322 }
323
324 } // namespace anon
325
326
327 TransformCommand::ptr_type
328 TransformStore::getCommandTransformer(RotationData const & data) const
329 {
330         TransformCommand::ptr_type ptr;
331         if (id == Rotate)
332                 extractIt<RotationCommandFactory>(any_factory, data, ptr);
333         return ptr;
334 }
335
336
337 TransformCommand::ptr_type
338 TransformStore::getCommandTransformer(ResizeData const & data) const
339 {
340         TransformCommand::ptr_type ptr;
341         if (id == Resize)
342                 extractIt<ResizeCommandFactory>(any_factory, data, ptr);
343         return ptr;
344 }
345
346
347 TransformOption::ptr_type
348 TransformStore::getOptionTransformer(RotationData const & data) const
349 {
350         TransformOption::ptr_type ptr;
351         if (id == Rotate)
352                 extractIt<RotationOptionFactory>(any_factory, data, ptr);
353         return ptr;
354 }
355
356
357 TransformOption::ptr_type
358 TransformStore::getOptionTransformer(ResizeData const & data) const
359 {
360         TransformOption::ptr_type ptr;
361         if (id == Resize)
362                 extractIt<ResizeOptionFactory>(any_factory, data, ptr);
363         return ptr;
364 }
365
366
367 TransformOption::ptr_type
368 TransformStore::getOptionTransformer(ClipData const & data) const
369 {
370         TransformOption::ptr_type ptr;
371         if (id == Clip)
372                 extractIt<ClipOptionFactory>(any_factory, data, ptr);
373         return ptr;
374 }
375
376
377
378 TransformOption::ptr_type
379 TransformStore::getOptionTransformer(string const & data) const
380 {
381         TransformOption::ptr_type ptr;
382         if (id == Extra)
383                 extractIt<ExtraOptionFactory>(any_factory, data, ptr);
384         return ptr;
385 }
386
387
388 namespace {
389
390 OriginTranslator const initOriginTranslator()
391 {
392         OriginTranslator translator(RotationData::DEFAULT, "default");
393         translator.addPair(RotationData::TOPLEFT,        "topleft");
394         translator.addPair(RotationData::BOTTOMLEFT,     "bottomleft");
395         translator.addPair(RotationData::BASELINELEFT,   "baselineleft");
396         translator.addPair(RotationData::CENTER,         "center");
397         translator.addPair(RotationData::TOPCENTER,      "topcenter");
398         translator.addPair(RotationData::BOTTOMCENTER,   "bottomcenter");
399         translator.addPair(RotationData::BASELINECENTER, "baselinecenter");
400         translator.addPair(RotationData::TOPRIGHT,       "topright");
401         translator.addPair(RotationData::BOTTOMRIGHT,    "bottomright");
402         translator.addPair(RotationData::BASELINERIGHT,  "baselineright");
403         return translator;
404 }
405
406
407 OriginTranslator const & originTranslator()
408 {
409         static OriginTranslator const translator = initOriginTranslator();
410         return translator;
411 }
412
413 } // namespace anon
414
415 } // namespace external
416 } // namespace lyx