]> git.lyx.org Git - lyx.git/blob - src/insets/insetquotes.C
add lfun 'quote-insert' arguments single/double (ERT fixes not included)
[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 #include "insetquotes.h"
14
15 #include "buffer.h"
16 #include "bufferparams.h"
17 #include "debug.h"
18 #include "language.h"
19 #include "LaTeXFeatures.h"
20 #include "lyxlex.h"
21 #include "lyxrc.h"
22 #include "metricsinfo.h"
23 #include "outputparams.h"
24 #include "paragraph.h"
25 #include "paragraph_funcs.h"
26
27 #include "frontends/font_metrics.h"
28 #include "frontends/Painter.h"
29
30 #include "support/lstrings.h"
31
32
33 using lyx::support::prefixIs;
34
35 using std::endl;
36 using std::string;
37 using std::auto_ptr;
38 using std::ostream;
39
40
41 namespace {
42
43 /* codes used to read/write quotes to LyX files
44  * e    ``english''
45  * s    ''spanish''
46  * g    ,,german``
47  * p    ,,polish''
48  * f    <<french>>
49  * a    >>danish<<
50  */
51
52 char const * const language_char = "esgpfa";
53 char const * const side_char = "lr" ;
54 char const * const times_char = "sd";
55
56 // List of known quote chars
57 char const * const quote_char = ",'`<>";
58
59 // Index of chars used for the quote. Index is [side, language]
60 int quote_index[2][6] = {
61         { 2, 1, 0, 0, 3, 4 },    // "'',,<>"
62         { 1, 1, 2, 1, 4, 3 } };  // "`'`'><"
63
64 // Corresponding LaTeX code, for double and single quotes.
65 char const * const latex_quote_t1[2][5] =
66 { { "\\quotesinglbase ",  "'", "`",
67     "\\guilsinglleft{}", "\\guilsinglright{}" },
68   { ",,", "''", "``", "<<", ">>" } };
69
70 char const * const latex_quote_ot1[2][5] =
71 { { "\\quotesinglbase ",  "'", "`",
72     "\\guilsinglleft{}", "\\guilsinglright{}" },
73   { "\\quotedblbase ", "''", "``",
74     "\\guillemotleft{}", "\\guillemotright{}" } };
75
76 char const * const latex_quote_babel[2][5] =
77 { { "\\glq ",  "'", "`", "\\flq{}", "\\frq{}" },
78   { "\\glqq ", "''", "``", "\\flqq{}", "\\frqq{}" } };
79
80 } // namespace anon
81
82
83 InsetQuotes::InsetQuotes(string const & str)
84 {
85         parseString(str);
86 }
87
88
89 InsetQuotes::InsetQuotes(quote_language l, quote_side s, quote_times t)
90         : language_(l), side_(s), times_(t)
91 {}
92
93
94 InsetQuotes::InsetQuotes(char c, BufferParams const & params)
95         : language_(params.quotes_language), times_(params.quotes_times)
96 {
97         getPosition(c);
98 }
99
100
101 InsetQuotes::InsetQuotes(char c, quote_language l, quote_times t)
102         : language_(l), times_(t)
103 {
104         getPosition(c);
105 }
106
107
108 void InsetQuotes::getPosition(char c)
109 {
110         // Decide whether left or right
111         switch (c) {
112         case ' ': case '(':
113         // FIXME: what about '['? (jspitzm)
114                 side_ = LeftQ;   // left quote
115                 break;
116         default:
117                 side_ = RightQ;  // right quote
118         }
119 }
120
121
122 void InsetQuotes::parseString(string const & s)
123 {
124         string str(s);
125         if (str.length() != 3) {
126                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
127                         " bad string length." << endl;
128                 str = "eld";
129         }
130
131         int i;
132
133         for (i = 0; i < 6; ++i) {
134                 if (str[0] == language_char[i]) {
135                         language_ = quote_language(i);
136                         break;
137                 }
138         }
139         if (i >= 6) {
140                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
141                         " bad language specification." << endl;
142                 language_ = EnglishQ;
143         }
144
145         for (i = 0; i < 2; ++i) {
146                 if (str[1] == side_char[i]) {
147                         side_ = quote_side(i);
148                         break;
149                 }
150         }
151         if (i >= 2) {
152                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
153                         " bad side specification." << endl;
154                 side_ = LeftQ;
155         }
156
157         for (i = 0; i < 2; ++i) {
158                 if (str[2] == times_char[i]) {
159                         times_ = quote_times(i);
160                         break;
161                 }
162         }
163         if (i >= 2) {
164                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
165                         " bad times specification." << endl;
166                 times_ = DoubleQ;
167         }
168 }
169
170
171 string const InsetQuotes::dispString(Language const * loclang) const
172 {
173         string disp;
174         disp += quote_char[quote_index[side_][language_]];
175         if (times_ == DoubleQ)
176                 disp += disp;
177
178         if (lyxrc.font_norm_type == LyXRC::ISO_8859_1
179             || lyxrc.font_norm_type == LyXRC::ISO_8859_9
180             || lyxrc.font_norm_type == LyXRC::ISO_8859_15) {
181                 if (disp == "<<")
182                         disp = '«';
183                 else if (disp == ">>")
184                         disp = '»';
185         }
186
187         // in french, spaces are added inside double quotes
188         if (times_ == DoubleQ && prefixIs(loclang->code(), "fr")) {
189                 if (side_ == LeftQ)
190                         disp += ' ';
191                 else
192                         disp.insert(string::size_type(0), 1, ' ');
193         }
194
195         return disp;
196 }
197
198
199 void InsetQuotes::metrics(MetricsInfo & mi, Dimension & dim) const
200 {
201         LyXFont & font = mi.base.font;
202         dim.asc = font_metrics::maxAscent(font);
203         dim.des = font_metrics::maxDescent(font);
204         dim.wid = 0;
205
206         string const text = dispString(font.language());
207         for (string::size_type i = 0; i < text.length(); ++i) {
208                 if (text[i] == ' ')
209                         dim.wid += font_metrics::width('i', font);
210                 else if (i == 0 || text[i] != text[i - 1])
211                         dim.wid += font_metrics::width(text[i], font);
212                 else
213                         dim.wid += font_metrics::width(',', font);
214         }
215         dim_ = dim;
216 }
217
218
219 #if 0
220 LyXFont const InsetQuotes::convertFont(LyXFont const & f) const
221 {
222 #if 1
223         return f;
224 #else
225         LyXFont font(f);
226         return font;
227 #endif
228 }
229 #endif
230
231
232 void InsetQuotes::draw(PainterInfo & pi, int x, int y) const
233 {
234         string const text = dispString(pi.base.font.language());
235
236         if (text.length() == 2 && text[0] == text[1]) {
237                 pi.pain.text(x, y, text[0], pi.base.font);
238                 int const t = font_metrics::width(',', pi.base.font);
239                 pi.pain.text(x + t, y, text[0], pi.base.font);
240         } else {
241                 pi.pain.text(x, y, text, pi.base.font);
242         }
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 int InsetQuotes::latex(Buffer const & buf, ostream & os,
268                        OutputParams const & runparams) const
269 {
270         // How do we get the local language here??
271         lyx::pos_type curr_pos = ownerPar(buf, this).getPositionOfInset(this);
272         BOOST_ASSERT(curr_pos != -1);
273
274 #warning FIXME. We _must_ find another way to get the language. (Lgb)
275 #if 0
276         // This cannot be used. (Lgb)
277         string const curr_lang =
278                 parOwner()->getFont(buf->params, curr_pos).language()->babel();
279 #else
280         // And this is not the way... (Lgb)
281         string const curr_lang = buf.params().language->lang();
282 #endif
283         const int quoteind = quote_index[side_][language_];
284         string qstr;
285
286         if (language_ == FrenchQ && times_ == DoubleQ
287             && curr_lang == "frenchb") {
288                 if (side_ == LeftQ)
289                         qstr = "\\og "; //the spaces are important here
290                 else
291                         qstr = " \\fg{}"; //and here
292         } else if (language_ == FrenchQ && times_ == DoubleQ
293                    && curr_lang == "french") {
294                 if (side_ == LeftQ)
295                         qstr = "<< "; //the spaces are important here
296                 else
297                         qstr = " >>"; //and here
298         } else if (lyxrc.fontenc == "T1") {
299                 qstr = latex_quote_t1[times_][quoteind];
300 #ifdef DO_USE_DEFAULT_LANGUAGE
301         } else if (doclang == "default") {
302 #else
303         } else if (!runparams.use_babel) {
304 #endif
305                 qstr = latex_quote_ot1[times_][quoteind];
306         } else {
307                 qstr = latex_quote_babel[times_][quoteind];
308         }
309
310         // Always guard against unfortunate ligatures (!` ?`)
311         if (prefixIs(qstr, "`"))
312                 qstr.insert(0, "{}");
313
314         os << qstr;
315         return 0;
316 }
317
318
319 int InsetQuotes::plaintext(Buffer const &, ostream & os,
320                        OutputParams const &) const
321 {
322         os << '"';
323         return 0;
324 }
325
326
327 int InsetQuotes::linuxdoc(Buffer const &, ostream & os,
328                           OutputParams const &) const
329 {
330         os << '"';
331         return 0;
332 }
333
334
335 int InsetQuotes::docbook(Buffer const &, ostream & os,
336                          OutputParams const &) const
337 {
338         if (times_ == DoubleQ) {
339                 if (side_ == LeftQ)
340                         os << "&ldquo;";
341                 else
342                         os << "&rdquo;";
343         } else {
344                 if (side_ == LeftQ)
345                         os << "&lsquo;";
346                 else
347                         os << "&rsquo;";
348         }
349         return 0;
350 }
351
352
353 void InsetQuotes::validate(LaTeXFeatures & features) const
354 {
355         bool const use_babel = features.useBabel();
356         char type = quote_char[quote_index[side_][language_]];
357
358 #ifdef DO_USE_DEFAULT_LANGUAGE
359         if (features.bufferParams().language->lang() == "default"
360 #else
361         if (!use_babel
362 #endif
363             && lyxrc.fontenc != "T1") {
364                 if (times_ == SingleQ)
365                         switch (type) {
366                                 case ',': features.require("quotesinglbase");  break;
367                         case '<': features.require("guilsinglleft");  break;
368                         case '>': features.require("guilsinglright"); break;
369                         default: break;
370                         }
371                 else
372                         switch (type) {
373                         case ',': features.require("quotedblbase");   break;
374                         case '<': features.require("guillemotleft");  break;
375                         case '>': features.require("guillemotright"); break;
376                         default: break;
377                         }
378         }
379 }
380
381
382 auto_ptr<InsetBase> InsetQuotes::clone() const
383 {
384         return auto_ptr<InsetBase>(new InsetQuotes(language_, side_, times_));
385 }
386
387
388 InsetOld::Code InsetQuotes::lyxCode() const
389 {
390   return InsetOld::QUOTE_CODE;
391 }