]> git.lyx.org Git - lyx.git/blob - src/insets/insetquotes.C
Make it compile when USE_BOOST_FORMAT is unset
[lyx.git] / src / insets / insetquotes.C
1 /**
2  * \file insetquotes.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jean-Marc Lasgouttes
7  *
8  * Full author contact details are available in file CREDITS
9  */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "insetquotes.h"
18
19 #include "support/LAssert.h"
20 #include "support/lstrings.h"
21 #include "BufferView.h"
22 #include "LaTeXFeatures.h"
23 #include "frontends/Painter.h"
24 #include "buffer.h"
25 #include "debug.h"
26 #include "frontends/font_metrics.h"
27 #include "language.h"
28 #include "lyxfont.h"
29 #include "lyxrc.h"
30 #include "paragraph.h"
31 #include "lyxlex.h"
32
33 using std::ostream;
34 using std::endl;
35
36 // Quotes. Used for the various quotes. German, English, French,
37 // Danish, Polish, all either double or single.
38
39 namespace {
40
41 // codes used to read/write quotes to LyX files
42 char const * const language_char = "esgpfa";
43 char const * const side_char = "lr" ;
44 char const * const times_char = "sd";
45
46 // List of known quote chars
47 char const * const quote_char = ",'`<>";
48
49 // Index of chars used for the quote. Index is [side, language]
50 int quote_index[2][6] = {
51         { 2, 1, 0, 0, 3, 4 },    // "'',,<>"
52         { 1, 1, 2, 1, 4, 3 } };  // "`'`'><"
53
54 // Corresponding LaTeX code, for double and single quotes.
55 char const * const latex_quote_t1[2][5] =
56 { { "\\quotesinglbase ",  "'", "`",
57     "\\guilsinglleft{}", "\\guilsinglright{}" },
58   { ",,", "''", "``", "<<", ">>" } };
59
60 char const * const latex_quote_ot1[2][5] =
61 { { "\\quotesinglbase ",  "'", "`",
62     "\\guilsinglleft{}", "\\guilsinglright{}" },
63   { "\\quotedblbase ", "''", "``",
64     "\\guillemotleft{}", "\\guillemotright{}" } };
65
66 char const * const latex_quote_babel[2][5] =
67 { { "\\glq ",  "'", "`", "\\flq{}", "\\frq{}" },
68   { "\\glqq ", "''", "``", "\\flqq{}", "\\frqq{}" } };
69
70 } // namespace anon
71
72
73 InsetQuotes::InsetQuotes(string const & str)
74 {
75         parseString(str);
76 }
77
78
79 InsetQuotes::InsetQuotes(quote_language l,
80                          quote_side s,
81                          quote_times t)
82         : language_(l), side_(s), times_(t)
83 {}
84
85
86 InsetQuotes::InsetQuotes(char c, BufferParams const & params)
87         : language_(params.quotes_language), times_(params.quotes_times)
88 {
89         // Decide whether left or right
90         switch (c) {
91         case ' ': case '(':
92         case Paragraph::META_HFILL:
93         case Paragraph::META_NEWLINE:
94                 side_ = LeftQ;   // left quote
95                 break;
96         default:
97                 side_ = RightQ;  // right quote
98         }
99 }
100
101
102 void InsetQuotes::parseString(string const & s)
103 {
104         string str(s);
105         if (str.length() != 3) {
106                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
107                         " bad string length." << endl;
108                 str = "eld";
109         }
110
111         int i;
112
113         for (i = 0; i < 6; ++i) {
114                 if (str[0] == language_char[i]) {
115                         language_ = quote_language(i);
116                         break;
117                 }
118         }
119         if (i >= 6) {
120                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
121                         " bad language specification." << endl;
122                 language_ = EnglishQ;
123         }
124
125         for (i = 0; i < 2; ++i) {
126                 if (str[1] == side_char[i]) {
127                         side_ = quote_side(i);
128                         break;
129                 }
130         }
131         if (i >= 2) {
132                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
133                         " bad side specification." << endl;
134                 side_ = LeftQ;
135         }
136
137         for (i = 0; i < 2; ++i) {
138                 if (str[2] == times_char[i]) {
139                         times_ = quote_times(i);
140                         break;
141                 }
142         }
143         if (i >= 2) {
144                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
145                         " bad times specification." << endl;
146                 times_ = DoubleQ;
147         }
148 }
149
150
151 string const InsetQuotes::dispString(Language const * loclang) const
152 {
153         string disp;
154         disp += quote_char[quote_index[side_][language_]];
155         if (times_ == DoubleQ)
156                 disp += disp;
157
158         if (lyxrc.font_norm_type == LyXRC::ISO_8859_1
159             || lyxrc.font_norm_type == LyXRC::ISO_8859_3
160             || lyxrc.font_norm_type == LyXRC::ISO_8859_4
161             || lyxrc.font_norm_type == LyXRC::ISO_8859_9) {
162                 if (disp == "'")
163                         disp = "´";
164                 else if (disp == "''")
165                         disp = "´´";
166         }
167         if (lyxrc.font_norm_type == LyXRC::ISO_8859_1
168             || lyxrc.font_norm_type == LyXRC::ISO_8859_9
169             || lyxrc.font_norm_type == LyXRC::ISO_8859_15) {
170                 if (disp == "<<")
171                         disp = '«';
172                 else if (disp == ">>")
173                         disp = '»';
174         }
175
176         // in french, spaces are added inside double quotes
177         if (times_ == DoubleQ && prefixIs(loclang->code(), "fr")) {
178                 if (side_ == LeftQ)
179                         disp += " ";
180                 else
181                         disp = " " + disp;
182         }
183
184         return disp;
185 }
186
187
188 int InsetQuotes::ascent(BufferView *, LyXFont const & font) const
189 {
190         return font_metrics::maxAscent(font);
191 }
192
193
194 int InsetQuotes::descent(BufferView *, LyXFont const & font) const
195 {
196         return font_metrics::maxDescent(font);
197 }
198
199
200 int InsetQuotes::width(BufferView *, LyXFont const & font) const
201 {
202         string const text = dispString(font.language());
203         int w = 0;
204
205         for (string::size_type i = 0; i < text.length(); ++i) {
206                 if (text[i] == ' ')
207                         w += font_metrics::width('i', font);
208                 else if (i == 0 || text[i] != text[i - 1])
209                         w += font_metrics::width(text[i], font);
210                 else
211                         w += font_metrics::width(',', font);
212         }
213
214         return w;
215 }
216
217
218 #if 0
219 LyXFont const InsetQuotes::convertFont(LyXFont const & f) const
220 {
221 #if 1
222         return f;
223 #else
224         LyXFont font(f);
225         return font;
226 #endif
227 }
228 #endif
229
230
231 void InsetQuotes::draw(BufferView * bv, LyXFont const & font,
232                        int baseline, float & x, bool) const
233 {
234         string const text = dispString(font.language());
235
236         if (text.length() == 2 && text[0] == text[1]) {
237                 bv->painter().text(int(x), baseline, text[0], font);
238                 int x2 = int(x + font_metrics::width(',', font));
239                 bv->painter().text(x2, baseline, text[0], font);
240         } else
241                 bv->painter().text(int(x), baseline, text, font);
242         x += width(bv, font);
243 }
244
245
246 void InsetQuotes::write(Buffer const *, ostream & os) const
247 {
248         string text;
249         text += language_char[language_];
250         text += side_char[side_];
251         text += times_char[times_];
252         os << "Quotes " << text;
253 }
254
255
256 void InsetQuotes::read(Buffer const *, LyXLex & lex)
257 {
258         lex.nextToken();
259         parseString(lex.getString());
260         lex.next();
261         if (lex.getString() != "\\end_inset") {
262                 lex.printError("Missing \\end_inset at this point");
263         }
264 }
265
266
267 extern bool use_babel;
268
269 int InsetQuotes::latex(Buffer const * buf, ostream & os,
270                        bool /*fragile*/, bool /* free_spc */) const
271 {
272         // How do we get the local language here??
273         lyx::pos_type curr_pos = parOwner()->getPositionOfInset(this);
274         lyx::Assert(curr_pos != -1);
275         string const curr_lang =
276                 parOwner()->getFont(buf->params,
277                                     curr_pos).language()->babel();
278
279         const int quoteind = quote_index[side_][language_];
280         string qstr;
281
282         if (language_ == FrenchQ && times_ == DoubleQ
283             && curr_lang == "frenchb") {
284                 if (side_ == LeftQ)
285                         qstr = "\\og "; //the spaces are important here
286                 else
287                         qstr = " \\fg{}"; //and here
288         } else if (language_ == FrenchQ && times_ == DoubleQ
289                    && curr_lang == "french") {
290                 if (side_ == LeftQ)
291                         qstr = "<< "; //the spaces are important here
292                 else
293                         qstr = " >>"; //and here
294         } else if (lyxrc.fontenc == "T1") {
295                 qstr = latex_quote_t1[times_][quoteind];
296 #ifdef DO_USE_DEFAULT_LANGUAGE
297         } else if (doclang == "default") {
298 #else
299         } else if (!use_babel) {
300 #endif
301                 qstr = latex_quote_ot1[times_][quoteind];
302         } else {
303                 qstr = latex_quote_babel[times_][quoteind];
304         }
305
306         // Always guard against unfortunate ligatures (!` ?`)
307         if (prefixIs(qstr, "`"))
308                 qstr.insert(0, "{}");
309
310         os << qstr;
311         return 0;
312 }
313
314
315 int InsetQuotes::ascii(Buffer const *, ostream & os, int) const
316 {
317         os << "\"";
318         return 0;
319 }
320
321
322 int InsetQuotes::linuxdoc(Buffer const *, ostream & os) const
323 {
324         os << "\"";
325         return 0;
326 }
327
328
329 int InsetQuotes::docbook(Buffer const *, ostream & os, bool) const
330 {
331         if (times_ == DoubleQ) {
332                 if (side_ == LeftQ)
333                         os << "&ldquo;";
334                 else
335                         os << "&rdquo;";
336         } else {
337                 if (side_ == LeftQ)
338                         os << "&lsquo;";
339                 else
340                         os << "&rsquo;";
341         }
342         return 0;
343 }
344
345
346 void InsetQuotes::validate(LaTeXFeatures & features) const
347 {
348         char type = quote_char[quote_index[side_][language_]];
349
350 #ifdef DO_USE_DEFAULT_LANGUAGE
351         if (features.bufferParams().language->lang() == "default"
352 #else
353         if (!use_babel
354 #endif
355             && lyxrc.fontenc != "T1") {
356                 if (times_ == SingleQ)
357                         switch (type) {
358                         case ',': features.require("quotesinglbase");  break;
359                         case '<': features.require("guilsinglleft");  break;
360                         case '>': features.require("guilsinglright"); break;
361                         default: break;
362                         }
363                 else
364                         switch (type) {
365                         case ',': features.require("quotedblbase");   break;
366                         case '<': features.require("guillemotleft");  break;
367                         case '>': features.require("guillemotright"); break;
368                         default: break;
369                         }
370         }
371 }
372
373
374 Inset * InsetQuotes::clone(Buffer const &, bool) const
375 {
376   return new InsetQuotes(language_, side_, times_);
377 }
378
379
380 Inset::Code InsetQuotes::lyxCode() const
381 {
382   return Inset::QUOTE_CODE;
383 }