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