]> git.lyx.org Git - lyx.git/blob - src/insets/InsetQuotes.cpp
Some new quote styles
[lyx.git] / src / insets / InsetQuotes.cpp
1 /**
2  * \file InsetQuotes.cpp
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  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "InsetQuotes.h"
15
16 #include "Buffer.h"
17 #include "BufferParams.h"
18 #include "BufferView.h"
19 #include "Cursor.h"
20 #include "Dimension.h"
21 #include "Font.h"
22 #include "FuncStatus.h"
23 #include "FuncRequest.h"
24 #include "Language.h"
25 #include "LaTeXFeatures.h"
26 #include "Lexer.h"
27 #include "LyXRC.h"
28 #include "MetricsInfo.h"
29 #include "OutputParams.h"
30 #include "output_xhtml.h"
31 #include "Paragraph.h"
32 #include "ParIterator.h"
33 #include "texstream.h"
34
35 #include "frontends/FontMetrics.h"
36 #include "frontends/Painter.h"
37
38 #include "support/debug.h"
39 #include "support/docstring.h"
40 #include "support/docstream.h"
41 #include "support/gettext.h"
42 #include "support/lstrings.h"
43
44 #include <string.h>
45
46 using namespace std;
47 using namespace lyx::support;
48
49 namespace lyx {
50
51 namespace {
52
53 /* codes used to read/write quotes to LyX files
54  * available styles:
55  * e    ``english''  (`inner quotation')
56  * s    ''swedish''  ('inner quotation')
57  * g    ,,german``   (,inner quotation`)
58  * p    ,,polish''   (,inner quotation')
59  * c    <<swiss>>    (<inner quotation>)
60  * a    >>danish<<   (>inner quotation<)
61  * q    "plain"      ('inner quotation')
62  * b    `british'    (``inner quotation'')
63  * w    >>swedishg>> ('inner quotation') ["g" = Guillemets]
64  * f    <<french>>   (``inner quotation'')
65  * i    <<frenchin>> (<<inner quotation>>) ["in" = Imprimerie Nationale]
66  * r    <<russian>>  (,,inner quotation``)
67  */
68
69 char const * const style_char = "esgpcaqbwfir";
70 char const * const side_char = "lr" ;
71 char const * const level_char = "sd";
72
73 } // namespace anon
74
75
76 /////////////////////////////////////////////////////////////////////
77 //
78 // InsetQuotesParams
79 //
80 ///////////////////////////////////////////////////////////////////////
81
82 InsetQuotesParams quoteparams;
83
84
85 int InsetQuotesParams::stylescount() const
86 {
87         return strlen(style_char);
88 }
89
90
91 char_type InsetQuotesParams::getQuoteChar(QuoteStyle const & style, QuoteLevel const & level,
92                                     QuoteSide const & side) const
93 {
94         // main opening quotation mark
95         char_type left_primary;
96         // main closing quotation mark
97         char_type right_primary;
98         // secondary (inner, 'single') opening quotation mark
99         char_type left_secondary;
100         // secondary (inner, 'single') closing quotation mark
101         char_type right_secondary;
102
103         switch (style) {
104         case EnglishQuotes: {
105                 left_primary = 0x201c; // ``
106                 right_primary = 0x201d; // ''
107                 left_secondary = 0x2018; // `
108                 right_secondary = 0x2019; // '
109                 break;
110         }
111         case SwedishQuotes: {
112                 left_primary = 0x201d; // ''
113                 right_primary = 0x201d; // ''
114                 left_secondary = 0x2019; // '
115                 right_secondary = 0x2019; // '
116                 break;
117         }
118         case GermanQuotes: {
119                 left_primary = 0x201e; // ,,
120                 right_primary = 0x201c; // ``
121                 left_secondary = 0x201a; // ,
122                 right_secondary = 0x2018; // `
123                 break;
124         }
125         case PolishQuotes: {
126                 left_primary =  0x201e; // ,,
127                 right_primary = 0x201d; // ''
128                 left_secondary = 0x201a; // ,
129                 right_secondary = 0x2019; // '
130                 break;
131         }
132         case SwissQuotes: {
133                 left_primary = 0x00ab; // <<
134                 right_primary = 0x00bb; // >>
135                 left_secondary = 0x2039; // <
136                 right_secondary = 0x203a; // >
137                 break;
138         }
139         case DanishQuotes: {
140                 left_primary = 0x00bb; // >>
141                 right_primary = 0x00ab; // <<
142                 left_secondary = 0x203a; // >
143                 right_secondary = 0x2039; // <
144                 break;
145         }
146         case PlainQuotes: {
147                 left_primary = 0x0022; // "
148                 right_primary = 0x0022; // "
149                 left_secondary = 0x0027; // '
150                 right_secondary = 0x0027; // '
151                 break;
152         }
153         case BritishQuotes: {
154                 left_primary = 0x2018; // `
155                 right_primary = 0x2019; // '
156                 left_secondary = 0x201c; // ``
157                 right_secondary = 0x201d; // ''
158                 break;
159         }
160         case SwedishGQuotes: {
161                 left_primary = 0x00bb; // >>
162                 right_primary = 0x00bb; // >>
163                 left_secondary = 0x2019; // '
164                 right_secondary = 0x2019; // '
165                 break;
166         }
167         case FrenchQuotes: {
168                 left_primary = 0x00ab; // <<
169                 right_primary = 0x00bb; // >>
170                 left_secondary = 0x201c; // ``
171                 right_secondary = 0x201d; // ''
172                 break;
173         }
174         case FrenchINQuotes:{
175                 left_primary = 0x00ab; // <<
176                 right_primary = 0x00bb; // >>
177                 left_secondary =  0x00ab; // <<
178                 right_secondary = 0x00bb; // >>
179                 break;
180         }
181         case RussianQuotes:{
182                 left_primary = 0x00ab; // <<
183                 right_primary = 0x00bb; // >>
184                 left_secondary =  0x201e; // ,,
185                 right_secondary = 0x201c; // ``
186                 break;
187         }
188         default:
189                 // should not happen
190                 left_primary = 0x003f; // ?
191                 right_primary = 0x003f; // ?
192                 left_secondary =  0x003f; // ?
193                 right_secondary = 0x003f; // ?
194                 break;
195         }
196
197         switch (level) {
198         case SecondaryQuotes:
199                 return (side == OpeningQuote) ? left_secondary : right_secondary;
200         case PrimaryQuotes:
201                 return (side == OpeningQuote) ? left_primary : right_primary;
202         default:
203                 break;
204         }
205
206         // should not happen
207         return 0x003f;
208 }
209
210
211 docstring InsetQuotesParams::getLaTeXQuote(char_type c, string const & op) const
212 {
213         string res;
214
215         switch (c){
216         case 0x201a: {// ,
217                 if (op == "babel")
218                         res = "\\glq";
219                 else
220                         res = "\\quotesinglbase";
221                 break;
222         }
223         case 0x2019: {// '
224                 if (op == "int")
225                         res = "\\textquoteleft";
226                 else
227                         res = "'";
228                 break;
229         }
230         case 0x2018: {// `
231                 if (op == "int")
232                         res = "\\textquoteright";
233                 else
234                         res = "`";
235                 break;
236         }
237         case 0x2039: {// <
238                 if (op == "babel")
239                         res = "\\flq";
240                 else
241                         res = "\\guilsinglleft";
242                 break;
243         }
244         case 0x203a: {// >
245                 if (op == "babel")
246                         res = "\\frq";
247                 else
248                         res = "\\guilsinglright";
249                 break;
250         }
251         case 0x0027: {// ' (plain)
252                 res = "\\textquotesingle";
253                 break;
254         }
255         case 0x201e: {// ,,
256                 if (op == "t1")
257                         res = ",,";
258                 else if (op == "babel")
259                         res = "\\glqq";
260                 else
261                         res = "\\quotedblbase";
262                 break;
263         }
264         case 0x201d: {// ''
265                 if (op == "int")
266                         res = "\\textquotedblleft";
267                 else
268                         res = "''";
269                 break;
270         }
271         case 0x201c: {// ``
272                 if (op == "int")
273                         res = "\\textquotedblright";
274                 else
275                         res = "``";
276                 break;
277         }
278         case 0x00ab: {// <<
279                 if (op == "t1")
280                         res = "<<";
281                 else if (op == "babel")
282                         res = "\\flqq";
283                 else
284                         res = "\\guillemotleft";
285                 break;
286         }
287         case 0x00bb: {// >>
288                 if (op == "t1")
289                         res = ">>";
290                 else if (op == "babel")
291                         res = "\\frqq";
292                 else
293                         res = "\\guillemotright";
294                 break;
295         }
296         case 0x0022: {// "
297                 res = "\\textquotedbl";
298                 break;
299         }
300         default:
301                 break;
302         }
303         
304         return from_ascii(res);
305 }
306
307
308 docstring InsetQuotesParams::getHTMLQuote(char_type c) const
309 {
310         string res;
311
312         switch (c){
313         case 0x201a: // ,
314                 res = "&sbquo;";
315                 break;
316         case 0x2019: // '
317                 res = "&rsquo;";
318                 break;
319         case 0x2018: // `
320                 res = "&lsquo;";
321                 break;
322         case 0x2039: // <
323                 res = "&lsaquo;";
324                 break;
325         case 0x203a: // >
326                 res = "&rsaquo;";
327                 break;
328         case 0x0027: // ' (plain)
329                 res = "&#x27;";
330                 break;
331         case 0x201e: // ,,
332                 res = "&bdquo;";
333                 break;
334         case 0x201d: // ''
335                 res = "&rdquo;";
336                 break;
337         case 0x201c: // ``
338                 res = "&ldquo;";
339                 break;
340         case 0x00ab: // <<
341                 res = "&laquo;";
342                 break;
343         case 0x00bb: // >>
344                 res = "&raquo;";
345                 break;
346         case 0x0022: // "
347                 res = "&quot;";
348                 break;
349         default:
350                 break;
351         }
352         
353         return from_ascii(res);
354 }
355
356
357 map<string, docstring> InsetQuotesParams::getTypes() const
358 {
359         map<string, docstring> res;
360
361         int sty, sid, lev;
362         QuoteStyle style;
363         QuoteSide side;
364         QuoteLevel level;
365         string type;
366
367         // get all quote types
368         for (sty = 0; sty < stylescount(); ++sty) {
369                 style = QuoteStyle(sty);
370                 for (sid = 0; sid < 2; ++sid) {
371                         side = QuoteSide(sid);
372                         for (lev = 0; lev < 2; ++lev) {
373                                 type += style_char[style];
374                                 type += side_char[sid];
375                                 level = QuoteLevel(lev);
376                                 type += level_char[lev];
377                                 res[type] = docstring(1, getQuoteChar(style, level, side));
378                                 type.clear();
379                         }
380                 }
381         }
382         return res;
383 }
384
385
386 docstring const InsetQuotesParams::getGuiLabel(QuoteStyle const & qs)
387 {
388         return bformat(_("%1$souter%2$s and %3$sinner%4$s[[quotation marks]]"),
389                 docstring(1, quoteparams.getQuoteChar(qs, PrimaryQuotes, OpeningQuote)),
390                 docstring(1, quoteparams.getQuoteChar(qs, PrimaryQuotes, ClosingQuote)),
391                 docstring(1, quoteparams.getQuoteChar(qs, SecondaryQuotes, OpeningQuote)),
392                 docstring(1, quoteparams.getQuoteChar(qs, SecondaryQuotes, ClosingQuote))
393                 );
394 }
395
396
397 /////////////////////////////////////////////////////////////////////
398 //
399 // InsetQuotes
400 //
401 ///////////////////////////////////////////////////////////////////////
402
403 InsetQuotes::InsetQuotes(Buffer * buf, string const & str) : Inset(buf)
404 {
405         parseString(str);
406 }
407
408
409 InsetQuotes::InsetQuotes(Buffer * buf, char_type c, InsetQuotesParams::QuoteLevel level,
410                          string const & side, string const & style)
411         : Inset(buf), level_(level), pass_thru_(false)
412 {
413         if (buf) {
414                 style_ = style.empty() ? buf->params().quotes_style : getStyle(style);
415                 fontenc_ = (buf->params().fontenc == "global")
416                         ? lyxrc.fontenc : buf->params().fontenc;
417         } else {
418                 style_ = style.empty() ? InsetQuotesParams::EnglishQuotes : getStyle(style);
419                 fontenc_ = lyxrc.fontenc;
420         }
421
422         if (side == "left" || side == "opening")
423                 side_ = InsetQuotesParams::OpeningQuote;
424         else if (side == "right" || side == "closing")
425                 side_ = InsetQuotesParams::ClosingQuote;
426         else
427                 setSide(c);
428 }
429
430
431 docstring InsetQuotes::layoutName() const
432 {
433         return from_ascii("Quotes");
434 }
435
436
437 void InsetQuotes::setSide(char_type c)
438 {
439         // Decide whether opening or closing quote
440         switch (c) {
441         case ' ':
442         case '(':
443         case '[':
444                 side_ = InsetQuotesParams::OpeningQuote;// opening quote
445                 break;
446         default:
447                 side_ = InsetQuotesParams::ClosingQuote;// closing quote
448         }
449 }
450
451
452 void InsetQuotes::parseString(string const & s, bool const allow_wildcards)
453 {
454         string str = s;
455         if (str.length() != 3) {
456                 lyxerr << "ERROR (InsetQuotes::InsetQuotes):"
457                         " bad string length." << endl;
458                 str = "eld";
459         }
460
461         int i;
462
463         // '.' wildcard means: keep current stylee
464         if (!allow_wildcards || str[0] != '.') {
465                 for (i = 0; i < quoteparams.stylescount(); ++i) {
466                         if (str[0] == style_char[i]) {
467                                 style_ = InsetQuotesParams::QuoteStyle(i);
468                                 break;
469                         }
470                 }
471                 if (i >= quoteparams.stylescount()) {
472                         LYXERR0("ERROR (InsetQuotes::InsetQuotes):"
473                                 " bad style specification.");
474                         style_ = InsetQuotesParams::EnglishQuotes;
475                 }
476         }
477
478         // '.' wildcard means: keep current side
479         if (!allow_wildcards || str[1] != '.') {
480                 for (i = 0; i < 2; ++i) {
481                         if (str[1] == side_char[i]) {
482                                 side_ = InsetQuotesParams::QuoteSide(i);
483                                 break;
484                         }
485                 }
486                 if (i >= 2) {
487                         LYXERR0("ERROR (InsetQuotes::InsetQuotes):"
488                                 " bad side specification.");
489                         side_ = InsetQuotesParams::OpeningQuote;
490                 }
491         }
492
493         // '.' wildcard means: keep current level
494         if (!allow_wildcards || str[2] != '.') {
495                 for (i = 0; i < 2; ++i) {
496                         if (str[2] == level_char[i]) {
497                                 level_ = InsetQuotesParams::QuoteLevel(i);
498                                 break;
499                         }
500                 }
501                 if (i >= 2) {
502                         LYXERR0("ERROR (InsetQuotes::InsetQuotes):"
503                                 " bad level specification.");
504                         level_ = InsetQuotesParams::PrimaryQuotes;
505                 }
506         }
507 }
508
509
510 InsetQuotesParams::QuoteStyle InsetQuotes::getStyle(string const & s)
511 {
512         InsetQuotesParams::QuoteStyle qs = InsetQuotesParams::EnglishQuotes;
513         
514         if (s == "english")
515                 qs = InsetQuotesParams::EnglishQuotes;
516         else if (s == "swedish")
517                 qs = InsetQuotesParams::SwedishQuotes;
518         else if (s == "german")
519                 qs = InsetQuotesParams::GermanQuotes;
520         else if (s == "polish")
521                 qs = InsetQuotesParams::PolishQuotes;
522         else if (s == "swiss")
523                 qs = InsetQuotesParams::SwissQuotes;
524         else if (s == "danish")
525                 qs = InsetQuotesParams::DanishQuotes;
526         else if (s == "plain")
527                 qs = InsetQuotesParams::PlainQuotes;
528         else if (s == "british")
529                 qs = InsetQuotesParams::BritishQuotes;
530         else if (s == "swedishg")
531                 qs = InsetQuotesParams::SwedishGQuotes;
532         else if (s == "french")
533                 qs = InsetQuotesParams::FrenchQuotes;
534         else if (s == "frenchin")
535                 qs = InsetQuotesParams::FrenchINQuotes;
536
537         return qs;
538 }
539
540
541 docstring InsetQuotes::displayString() const
542 {
543         // In PassThru, we use straight quotes
544         if (pass_thru_)
545                 return (level_ == InsetQuotesParams::PrimaryQuotes) ?
546                                         from_ascii("\"") : from_ascii("'");
547
548         docstring retdisp = docstring(1, quoteparams.getQuoteChar(style_, level_, side_));
549
550         // in French, thin spaces are added inside double guillemets
551         if (prefixIs(context_lang_, "fr")
552             && level_ == InsetQuotesParams::PrimaryQuotes
553             && (style_ == InsetQuotesParams::SwissQuotes
554                 || style_ == InsetQuotesParams::FrenchQuotes
555                 || style_ == InsetQuotesParams::FrenchINQuotes)) {
556                 // THIN SPACE (U+2009)
557                 char_type const thin_space = 0x2009;
558                 if (side_ == InsetQuotesParams::OpeningQuote)
559                         retdisp += thin_space;
560                 else
561                         retdisp = thin_space + retdisp;
562         }
563
564         return retdisp;
565 }
566
567
568 void InsetQuotes::metrics(MetricsInfo & mi, Dimension & dim) const
569 {
570         FontInfo & font = mi.base.font;
571         frontend::FontMetrics const & fm = theFontMetrics(font);
572         dim.asc = fm.maxAscent();
573         dim.des = fm.maxDescent();
574         dim.wid = fm.width(displayString());
575 }
576
577
578 void InsetQuotes::draw(PainterInfo & pi, int x, int y) const
579 {
580         FontInfo font = pi.base.font;
581         font.setPaintColor(pi.textColor(font.realColor()));
582         pi.pain.text(x, y, displayString(), font);
583 }
584
585
586 string InsetQuotes::getType() const
587 {
588         string text;
589         text += style_char[style_];
590         text += side_char[side_];
591         text += level_char[level_];
592         return text;
593 }
594
595
596 void InsetQuotes::write(ostream & os) const
597 {
598         os << "Quotes " << getType();
599 }
600
601
602 void InsetQuotes::read(Lexer & lex)
603 {
604         lex.setContext("InsetQuotes::read");
605         lex.next();
606         parseString(lex.getString());
607         lex >> "\\end_inset";
608 }
609
610
611 void InsetQuotes::doDispatch(Cursor & cur, FuncRequest & cmd)
612 {
613         switch (cmd.action()) {
614         case LFUN_INSET_MODIFY: {
615                 string const first_arg = cmd.getArg(0);
616                 bool const change_type = first_arg == "changetype";
617                 if (!change_type) {
618                         // not for us
619                         // this will not be handled higher up
620                         cur.undispatched();
621                         return;
622                 }
623                 cur.recordUndoInset(this);
624                 parseString(cmd.getArg(1), true);
625                 cur.buffer()->updateBuffer();
626                 break;
627         }
628         default:
629                 Inset::doDispatch(cur, cmd);
630                 break;
631         }
632 }
633
634
635 bool InsetQuotes::getStatus(Cursor & cur, FuncRequest const & cmd,
636                 FuncStatus & flag) const
637 {
638         switch (cmd.action()) {
639
640         case LFUN_INSET_MODIFY: {
641                 string const first_arg = cmd.getArg(0);
642                 if (first_arg == "changetype") {
643                         string const type = cmd.getArg(1);
644                         flag.setOnOff(type == getType());
645                         flag.setEnabled(!pass_thru_);
646                         return true;
647                 }
648                 return Inset::getStatus(cur, cmd, flag);
649         }
650
651         default:
652                 return Inset::getStatus(cur, cmd, flag);
653         }
654 }
655
656
657 void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const
658 {
659         char_type quotechar = quoteparams.getQuoteChar(style_, level_, side_);
660         docstring qstr;
661
662         // In pass-thru context, we output plain quotes
663         if (runparams.pass_thru)
664                 qstr = (level_ == InsetQuotesParams::PrimaryQuotes) ? from_ascii("\"") : from_ascii("'");
665         else if (style_ == InsetQuotesParams::PlainQuotes && runparams.isFullUnicode()) {
666                 // For XeTeX and LuaTeX,we need to disable mapping to get straight
667                 // quotes. We define our own commands that do this
668                 qstr = (level_ == InsetQuotesParams::PrimaryQuotes) ?
669                         from_ascii("\\textquotedblplain") : from_ascii("\\textquotesingleplain");
670         }
671         else if (runparams.use_polyglossia) {
672                 // For polyglossia, we directly output the respective unicode chars 
673                 // (spacing and kerning is then handled respectively)
674                 qstr = docstring(1, quotechar);
675         }
676         else if (style_ == InsetQuotesParams::FrenchQuotes
677                  && level_ == InsetQuotesParams::PrimaryQuotes
678                  && prefixIs(runparams.local_font->language()->code(), "fr")) {
679                 // Specific guillemets of French babel
680                 // including correct French spacing
681                 if (side_ == InsetQuotesParams::OpeningQuote)
682                         qstr = from_ascii("\\og");
683                 else
684                         qstr = from_ascii("\\fg");
685         } else if (fontenc_ == "T1"
686                    && !runparams.local_font->language()->internalFontEncoding()) {
687                 // Quotation marks for T1 font encoding
688                 // (using ligatures)
689                 qstr = quoteparams.getLaTeXQuote(quotechar, "t1");
690         } else if (runparams.local_font->language()->internalFontEncoding()) {
691                 // Quotation marks for internal font encodings
692                 // (ligatures not featured)
693                 qstr = quoteparams.getLaTeXQuote(quotechar, "int");
694 #ifdef DO_USE_DEFAULT_LANGUAGE
695         } else if (doclang == "default") {
696 #else
697         } else if (!runparams.use_babel || runparams.isFullUnicode()) {
698 #endif
699                 // Standard quotation mark macros
700                 // These are also used by babel
701                 // without fontenc (XeTeX/LuaTeX)
702                 qstr = quoteparams.getLaTeXQuote(quotechar, "ot1");
703         } else {
704                 // Babel shorthand quotation marks (for T1/OT1)
705                 qstr = quoteparams.getLaTeXQuote(quotechar, "babel");
706         }
707
708         if (!runparams.pass_thru) {
709                 // Guard against unwanted ligatures with preceding text
710                 char_type const lastchar = os.lastChar();
711                 // !` ?` => !{}` ?{}`
712                 if (prefixIs(qstr, from_ascii("`"))
713                     && (lastchar == '!' || lastchar == '?'))
714                         os << "{}";
715                 // ``` ''' ,,, <<< >>>
716                 // => `{}`` '{}'' ,{},, <{}<< >{}>>
717                 if (contains(from_ascii(",'`<>"), lastchar)
718                     && prefixIs(qstr, lastchar))
719                         os << "{}";
720         }
721
722         os << qstr;
723
724         if (prefixIs(qstr, from_ascii("\\")))
725                 // properly terminate the command depending on the context
726                 os << termcmd;
727 }
728
729
730 int InsetQuotes::plaintext(odocstringstream & os, 
731         OutputParams const &, size_t) const
732 {
733         docstring const str = displayString();
734         os << str;
735         return str.size();
736 }
737
738
739 docstring InsetQuotes::getQuoteEntity() const {
740         docstring res = quoteparams.getHTMLQuote(quoteparams.getQuoteChar(style_, level_, side_));
741         // in French, thin spaces are added inside double guillemets
742         if (prefixIs(context_lang_, "fr")
743             && level_ == InsetQuotesParams::PrimaryQuotes
744             && style_ == InsetQuotesParams::FrenchQuotes) {
745                 // THIN SPACE (U+2009)
746                 docstring const thin_space = from_ascii("&#x2009;");
747                 if (side_ == InsetQuotesParams::OpeningQuote)
748                         res += thin_space;
749                 else
750                         res = thin_space + res;
751         }
752         return res;
753 }
754
755
756 int InsetQuotes::docbook(odocstream & os, OutputParams const &) const
757 {
758         os << getQuoteEntity();
759         return 0;
760 }
761
762
763 docstring InsetQuotes::xhtml(XHTMLStream & xs, OutputParams const &) const
764 {
765         xs << XHTMLStream::ESCAPE_NONE << getQuoteEntity();
766         return docstring();
767 }
768
769
770 void InsetQuotes::toString(odocstream & os) const
771 {
772         os << displayString();
773 }
774
775
776 void InsetQuotes::forOutliner(docstring & os, size_t const, bool const) const
777 {
778         os += displayString();
779 }
780
781
782 void InsetQuotes::updateBuffer(ParIterator const & it, UpdateType /* utype*/)
783 {
784         BufferParams const & bp = buffer().masterBuffer()->params();
785         pass_thru_ = it.paragraph().isPassThru();
786         context_lang_ = it.paragraph().getFontSettings(bp, it.pos()).language()->code();
787         fontenc_ = (bp.fontenc == "global") ? lyxrc.fontenc : bp.fontenc;
788 }
789
790
791 void InsetQuotes::validate(LaTeXFeatures & features) const
792 {
793         char_type type = quoteparams.getQuoteChar(style_, level_, side_);
794
795         // Handle characters that are not natively supported by
796         // specific font encodings (we roll our own definitions)
797 #ifdef DO_USE_DEFAULT_LANGUAGE
798         if (features.bufferParams().language->lang() == "default"
799 #else
800         if (!features.useBabel()
801 #endif
802             && !features.runparams().isFullUnicode() && fontenc_ != "T1") {
803                 switch (type) {
804                 case 0x201a:
805                         features.require("quotesinglbase");
806                         break;
807                 case 0x2039:
808                         features.require("guilsinglleft");
809                         break;
810                 case 0x203a:
811                         features.require("guilsinglright");
812                         break;
813                 case 0x201e:
814                         features.require("quotedblbase");
815                         break;
816                 case 0x00ab:
817                         features.require("guillemotleft");
818                         break;
819                 case 0x00bb:
820                         features.require("guillemotright");
821                         break;
822                 default:
823                         break;
824                 }
825         }
826         // Handle straight quotation marks. These need special care
827         // in most output formats
828         switch (type) {
829         case 0x0027: {
830                 if (features.runparams().isFullUnicode())
831                                 features.require("textquotesinglep");
832                         else
833                                 features.require("textcomp");
834                         break;
835         }
836         case 0x0022: {
837                 if (features.runparams().isFullUnicode())
838                         features.require("textquotedblp");
839                 else if (fontenc_ != "T1")
840                         features.require("textquotedbl");
841                 break;
842         }
843         default:
844                 break;
845         }
846 }
847
848
849 string InsetQuotes::contextMenuName() const
850 {
851         return "context-quote";
852 }
853
854 } // namespace lyx