]> git.lyx.org Git - lyx.git/blob - src/Layout.cpp
Revert unintended commit.
[lyx.git] / src / Layout.cpp
1 /**
2  * \file Layout.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Jean-Marc Lasgouttes
8  * \author André Pönitz
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "Layout.h"
16 #include "Language.h"
17 #include "TextClass.h"
18 #include "Lexer.h"
19 #include "Font.h"
20
21 #include "support/Messages.h"
22 #include "support/debug.h"
23 #include "support/lassert.h"
24 #include "support/lstrings.h"
25
26 #include <boost/regex.hpp>
27
28 using namespace std;
29 using namespace lyx::support;
30
31 namespace lyx {
32
33 /// Special value of toclevel for layouts that to not belong in a TOC
34 const int Layout::NOT_IN_TOC = -1000;
35
36 //  The order of the LayoutTags enum is no more important. [asierra300396]
37 // Tags indexes.
38 enum LayoutTags {
39         LT_ALIGN = 1,
40         LT_ALIGNPOSSIBLE,
41         LT_MARGIN,
42         LT_BOTTOMSEP,
43         LT_CATEGORY,
44         LT_COMMANDDEPTH,
45         LT_COPYSTYLE,
46         LT_DEPENDSON,
47         LT_OBSOLETEDBY,
48         //LT_EMPTY,
49         LT_END,
50         //LT_ENVIRONMENT_DEFAULT,
51         //LT_FANCYHDR,
52         LT_FILL_BOTTOM,
53         LT_FILL_TOP,
54         //LT_FIRST_COUNTER,
55         LT_FONT,
56         LT_FREE_SPACING,
57         LT_PASS_THRU,
58         //LT_HEADINGS,
59         LT_ITEMSEP,
60         LT_KEEPEMPTY,
61         LT_LABEL_BOTTOMSEP,
62         LT_LABELFONT,
63         LT_TEXTFONT,
64         LT_LABELINDENT,
65         LT_LABELSEP,
66         LT_LABELSTRING,
67         LT_LABELSTRING_APPENDIX,
68         LT_LABELCOUNTER,
69         LT_LABELTYPE,
70         LT_ENDLABELSTRING,
71         LT_ENDLABELTYPE,
72         LT_LATEXNAME,
73         LT_LATEXPARAM,
74         LT_OPTARGS,
75         LT_LATEXTYPE,
76         LT_LEFTMARGIN,
77         LT_NEED_PROTECT,
78         LT_NEWLINE,
79         LT_NEXTNOINDENT,
80         LT_PARINDENT,
81         LT_PARSEP,
82         LT_PARSKIP,
83         //LT_PLAIN,
84         LT_PREAMBLE,
85         LT_LANGPREAMBLE,
86         LT_BABELPREAMBLE,
87         LT_REQUIRES,
88         LT_RIGHTMARGIN,
89         LT_SPACING,
90         LT_TOPSEP,
91         LT_TOCLEVEL,
92         LT_INNERTAG,
93         LT_LABELTAG,
94         LT_ITEMTAG,
95         LT_HTMLTAG,
96         LT_HTMLATTR,
97         LT_HTMLITEM,
98         LT_HTMLITEMATTR,
99         LT_HTMLLABEL,
100         LT_HTMLLABELATTR, 
101         LT_HTMLSTYLE,
102         LT_INTITLE // keep this last!
103 };
104
105 /////////////////////
106
107 Layout::Layout()
108 {
109         unknown_ = false;
110         margintype = MARGIN_STATIC;
111         latextype = LATEX_PARAGRAPH;
112         intitle = false;
113         optionalargs = 0;
114         needprotect = false;
115         keepempty = false;
116         font = inherit_font;
117         labelfont = inherit_font;
118         resfont = sane_font;
119         reslabelfont = sane_font;
120         nextnoindent = false;
121         parskip = 0.0;
122         itemsep = 0;
123         topsep = 0.0;
124         bottomsep = 0.0;
125         labelbottomsep = 0.0;
126         parsep = 0;
127         align = LYX_ALIGN_BLOCK;
128         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
129         labeltype = LABEL_NO_LABEL;
130         endlabeltype = END_LABEL_NO_LABEL;
131         // Should or should not. That is the question.
132         // spacing.set(Spacing::OneHalf);
133         fill_top = false;
134         fill_bottom = false;
135         newline_allowed = true;
136         free_spacing = false;
137         pass_thru = false;
138         toclevel = NOT_IN_TOC;
139         commanddepth = 0;
140 }
141
142
143 bool Layout::read(Lexer & lex, TextClass const & tclass)
144 {
145         // This table is sorted alphabetically [asierra 30March96]
146         LexerKeyword layoutTags[] = {
147                 { "align",          LT_ALIGN },
148                 { "alignpossible",  LT_ALIGNPOSSIBLE },
149                 { "babelpreamble",  LT_BABELPREAMBLE },
150                 { "bottomsep",      LT_BOTTOMSEP },
151                 { "category",       LT_CATEGORY },
152                 { "commanddepth",   LT_COMMANDDEPTH },
153                 { "copystyle",      LT_COPYSTYLE },
154                 { "dependson",      LT_DEPENDSON },
155                 { "end",            LT_END },
156                 { "endlabelstring", LT_ENDLABELSTRING },
157                 { "endlabeltype",   LT_ENDLABELTYPE },
158                 { "fill_bottom",    LT_FILL_BOTTOM },
159                 { "fill_top",       LT_FILL_TOP },
160                 { "font",           LT_FONT },
161                 { "freespacing",    LT_FREE_SPACING },
162                 {       "htmlattr",       LT_HTMLATTR },
163                 { "htmlitem",       LT_HTMLITEM },
164                 { "htmlitemattr",   LT_HTMLITEMATTR },
165                 { "htmllabel",      LT_HTMLLABEL },
166                 { "htmllabelattr",  LT_HTMLLABELATTR },
167                 {       "htmlstyle",      LT_HTMLSTYLE },
168                 { "htmltag",        LT_HTMLTAG },
169                 { "innertag",       LT_INNERTAG },
170                 { "intitle",        LT_INTITLE },
171                 { "itemsep",        LT_ITEMSEP },
172                 { "itemtag",        LT_ITEMTAG },
173                 { "keepempty",      LT_KEEPEMPTY },
174                 { "labelbottomsep", LT_LABEL_BOTTOMSEP },
175                 { "labelcounter",   LT_LABELCOUNTER },
176                 { "labelfont",      LT_LABELFONT },
177                 { "labelindent",    LT_LABELINDENT },
178                 { "labelsep",       LT_LABELSEP },
179                 { "labelstring",    LT_LABELSTRING },
180                 { "labelstringappendix", LT_LABELSTRING_APPENDIX },
181                 { "labeltag",       LT_LABELTAG },
182                 { "labeltype",      LT_LABELTYPE },
183                 { "langpreamble",   LT_LANGPREAMBLE },
184                 { "latexname",      LT_LATEXNAME },
185                 { "latexparam",     LT_LATEXPARAM },
186                 { "latextype",      LT_LATEXTYPE },
187                 { "leftmargin",     LT_LEFTMARGIN },
188                 { "margin",         LT_MARGIN },
189                 { "needprotect",    LT_NEED_PROTECT },
190                 { "newline",        LT_NEWLINE },
191                 { "nextnoindent",   LT_NEXTNOINDENT },
192                 { "obsoletedby",    LT_OBSOLETEDBY },
193                 { "optionalargs",   LT_OPTARGS },
194                 { "parindent",      LT_PARINDENT },
195                 { "parsep",         LT_PARSEP },
196                 { "parskip",        LT_PARSKIP },
197                 { "passthru",       LT_PASS_THRU },
198                 { "preamble",       LT_PREAMBLE },
199                 { "requires",       LT_REQUIRES },
200                 { "rightmargin",    LT_RIGHTMARGIN },
201                 { "spacing",        LT_SPACING },
202                 { "textfont",       LT_TEXTFONT },
203                 { "toclevel",       LT_TOCLEVEL },
204                 { "topsep",         LT_TOPSEP }
205         };
206
207         bool error = false;
208         bool finished = false;
209         lex.pushTable(layoutTags);
210         // parse style section
211         while (!finished && lex.isOK() && !error) {
212                 int le = lex.lex();
213                 // See comment in LyXRC.cpp.
214                 switch (le) {
215                 case Lexer::LEX_FEOF:
216                         continue;
217
218                 case Lexer::LEX_UNDEF:          // parse error
219                         lex.printError("Unknown layout tag `$$Token'");
220                         error = true;
221                         continue;
222
223                 default: 
224                         break;
225                 }
226                 switch (static_cast<LayoutTags>(le)) {
227                 case LT_END:            // end of structure
228                         finished = true;
229                         break;
230
231                 case LT_CATEGORY:
232                         lex >> category_;
233                         break;
234
235                 case LT_COPYSTYLE: {     // initialize with a known style
236                         docstring style;
237                         lex >> style;
238                         style = subst(style, '_', ' ');
239
240                         if (tclass.hasLayout(style)) {
241                                 docstring const tmpname = name_;
242                                 this->operator=(tclass[style]);
243                                 name_ = tmpname;
244                         } else {
245                                 LYXERR0("Cannot copy unknown style `"
246                                         << style << "'\n"
247                                         << "All layouts so far:");
248                                 DocumentClass::const_iterator lit = tclass.begin();
249                                 DocumentClass::const_iterator len = tclass.end();
250                                 for (; lit != len; ++lit)
251                                         LYXERR0(lit->name());
252                         }
253                         break;
254                         }
255
256                 case LT_OBSOLETEDBY: {   // replace with a known style
257                         docstring style;
258                         lex >> style;
259                         style = subst(style, '_', ' ');
260
261                         if (tclass.hasLayout(style)) {
262                                 docstring const tmpname = name_;
263                                 this->operator=(tclass[style]);
264                                 name_ = tmpname;
265                                 if (obsoleted_by().empty())
266                                         obsoleted_by_ = style;
267                         } else {
268                                 LYXERR0("Cannot replace with unknown style `" 
269                                         << style << '\'');
270
271                                 //lex.printError("Cannot replace with"
272                                 //               " unknown style "
273                                 //               "`$$Token'");
274                         }
275                         break;
276                 }
277
278                 case LT_DEPENDSON:
279                         lex >> depends_on_;
280                         depends_on_ = subst(depends_on_, '_', ' ');
281                         break;
282
283                 case LT_MARGIN:         // margin style definition.
284                         readMargin(lex);
285                         break;
286
287                 case LT_LATEXTYPE:      // LaTeX style definition.
288                         readLatexType(lex);
289                         break;
290
291                 case LT_INTITLE:
292                         lex >> intitle;
293                         break;
294
295                 case LT_TOCLEVEL:
296                         lex >> toclevel;
297                         break;
298
299                 case LT_OPTARGS:
300                         lex >> optionalargs ;
301                         break;
302
303                 case LT_NEED_PROTECT:
304                         lex >> needprotect;
305                         break;
306
307                 case LT_KEEPEMPTY:
308                         lex >> keepempty;
309                         break;
310
311                 case LT_FONT:
312                         font = lyxRead(lex, font);
313                         labelfont = font;
314                         break;
315
316                 case LT_TEXTFONT:
317                         font = lyxRead(lex, font);
318                         break;
319
320                 case LT_LABELFONT:
321                         labelfont = lyxRead(lex, labelfont);
322                         break;
323
324                 case LT_NEXTNOINDENT:   // Indent next paragraph?
325                         lex >> nextnoindent;
326                         break;
327
328                 case LT_COMMANDDEPTH:
329                         lex >> commanddepth;
330                         break;
331
332                 case LT_LATEXNAME:
333                         lex >> latexname_;
334                         break;
335
336                 case LT_LATEXPARAM:
337                         lex >> latexparam_;
338                         latexparam_ = subst(latexparam_, "&quot;", "\"");
339                         break;
340
341                 case LT_INNERTAG:
342                         lex >> innertag_;
343                         break;
344
345                 case LT_LABELTAG:
346                         lex >> labeltag_;
347                         break;
348
349                 case LT_ITEMTAG:
350                         lex >> itemtag_;
351                         break;
352
353                 case LT_PREAMBLE:
354                         preamble_ = from_utf8(lex.getLongString("EndPreamble"));
355                         break;
356
357                 case LT_LANGPREAMBLE:
358                         langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble"));
359                         break;
360
361                 case LT_BABELPREAMBLE:
362                         babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble"));
363                         break;
364
365                 case LT_LABELTYPE:
366                         readLabelType(lex);
367                         break;
368
369                 case LT_ENDLABELTYPE:
370                         readEndLabelType(lex);
371                         break;
372
373                 case LT_LEFTMARGIN:     // left margin type
374                         lex >> leftmargin;
375                         break;
376
377                 case LT_RIGHTMARGIN:    // right margin type
378                         lex >> rightmargin;
379                         break;
380
381                 case LT_LABELINDENT:    // label indenting flag
382                         lex >> labelindent;
383                         break;
384
385                 case LT_PARINDENT:      // paragraph indent. flag
386                         lex >> parindent;
387                         break;
388
389                 case LT_PARSKIP:        // paragraph skip size
390                         lex >> parskip;
391                         break;
392
393                 case LT_ITEMSEP:        // item separation size
394                         lex >> itemsep;
395                         break;
396
397                 case LT_TOPSEP:         // top separation size
398                         lex >> topsep;
399                         break;
400
401                 case LT_BOTTOMSEP:      // bottom separation size
402                         lex >> bottomsep;
403                         break;
404
405                 case LT_LABEL_BOTTOMSEP: // label bottom separation size
406                         lex >> labelbottomsep;
407                         break;
408
409                 case LT_LABELSEP:       // label separator
410                         lex >> labelsep;
411                         labelsep = subst(labelsep, 'x', ' ');
412                         break;
413
414                 case LT_PARSEP:         // par. separation size
415                         lex >> parsep;
416                         break;
417
418                 case LT_FILL_TOP:       // fill top flag
419                         lex >> fill_top;
420                         break;
421
422                 case LT_FILL_BOTTOM:    // fill bottom flag
423                         lex >> fill_bottom;
424                         break;
425
426                 case LT_NEWLINE:        // newlines allowed?
427                         lex >> newline_allowed;
428                         break;
429
430                 case LT_ALIGN:          // paragraph align
431                         readAlign(lex);
432                         break;
433                 case LT_ALIGNPOSSIBLE:  // paragraph allowed align
434                         readAlignPossible(lex);
435                         break;
436
437                 case LT_LABELSTRING:    // label string definition
438                         // FIXME: this means LT_ENDLABELSTRING may only
439                         // occur after LT_LABELSTRING
440                         lex >> labelstring_;
441                         labelstring_ = trim(labelstring_);
442                         labelstring_appendix_ = labelstring_;
443                         break;
444
445                 case LT_ENDLABELSTRING: // endlabel string definition
446                         lex >> endlabelstring_; 
447                         endlabelstring_ = trim(endlabelstring_);
448                         break;
449
450                 case LT_LABELSTRING_APPENDIX: // label string appendix definition
451                         lex >> labelstring_appendix_;   
452                         labelstring_appendix_ = trim(labelstring_appendix_);
453                         break;
454
455                 case LT_LABELCOUNTER: // name of counter to use
456                         lex >> counter; 
457                         counter = trim(counter);
458                         break;
459
460                 case LT_FREE_SPACING:   // Allow for free spacing.
461                         lex >> free_spacing;
462                         break;
463
464                 case LT_PASS_THRU:      // Allow for pass thru.
465                         lex >> pass_thru;
466                         break;
467
468                 case LT_SPACING: // setspace.sty
469                         readSpacing(lex);
470                         break;
471
472                 case LT_REQUIRES: {
473                         lex.eatLine();
474                         vector<string> const req = 
475                                 getVectorFromString(lex.getString());
476                         requires_.insert(req.begin(), req.end());
477                         break;
478                 }
479
480                 case LT_HTMLTAG:
481                         lex >> htmltag_;
482                         break;
483         
484                 case LT_HTMLATTR:
485                         lex >> htmlattr_;
486                         break;
487
488                 case LT_HTMLITEM:
489                         lex >> htmlitem_;
490                         break;
491         
492                 case LT_HTMLITEMATTR:
493                         lex >> htmlitemattr_;
494                         break;
495         
496                 case LT_HTMLLABEL:
497                         lex >> htmllabel_;
498                         break;
499
500                 case LT_HTMLLABELATTR: 
501                         lex >> htmllabelattr_;
502                         break;
503
504                 case LT_HTMLSTYLE:
505                         htmlstyle_ = from_utf8(lex.getLongString("EndHTMLStyle"));
506                         break;
507
508                 }
509         }
510         lex.popTable();
511
512         return !error;
513 }
514
515
516 enum {
517         AT_BLOCK = 1,
518         AT_LEFT,
519         AT_RIGHT,
520         AT_CENTER,
521         AT_LAYOUT
522 };
523
524
525 LexerKeyword alignTags[] = {
526         { "block",  AT_BLOCK },
527         { "center", AT_CENTER },
528         { "layout", AT_LAYOUT },
529         { "left",   AT_LEFT },
530         { "right",  AT_RIGHT }
531 };
532
533
534 void Layout::readAlign(Lexer & lex)
535 {
536         PushPopHelper pph(lex, alignTags);
537         int le = lex.lex();
538         switch (le) {
539         case Lexer::LEX_UNDEF:
540                 lex.printError("Unknown alignment `$$Token'");
541                 return;
542         default: break;
543         };
544         switch (le) {
545         case AT_BLOCK:
546                 align = LYX_ALIGN_BLOCK;
547                 break;
548         case AT_LEFT:
549                 align = LYX_ALIGN_LEFT;
550                 break;
551         case AT_RIGHT:
552                 align = LYX_ALIGN_RIGHT;
553                 break;
554         case AT_CENTER:
555                 align = LYX_ALIGN_CENTER;
556                 break;
557         case AT_LAYOUT:
558                 align = LYX_ALIGN_LAYOUT;
559                 break;
560         }
561 }
562
563
564 void Layout::readAlignPossible(Lexer & lex)
565 {
566         lex.pushTable(alignTags);
567         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
568         int lineno = lex.lineNumber();
569         do {
570                 int le = lex.lex();
571                 switch (le) {
572                 case Lexer::LEX_UNDEF:
573                         lex.printError("Unknown alignment `$$Token'");
574                         continue;
575                 default: break;
576                 };
577                 switch (le) {
578                 case AT_BLOCK:
579                         alignpossible |= LYX_ALIGN_BLOCK;
580                         break;
581                 case AT_LEFT:
582                         alignpossible |= LYX_ALIGN_LEFT;
583                         break;
584                 case AT_RIGHT:
585                         alignpossible |= LYX_ALIGN_RIGHT;
586                         break;
587                 case AT_CENTER:
588                         alignpossible |= LYX_ALIGN_CENTER;
589                         break;
590                 case AT_LAYOUT:
591                         alignpossible |= LYX_ALIGN_LAYOUT;
592                         break;
593                 }
594         } while (lineno == lex.lineNumber());
595         lex.popTable();
596 }
597
598
599 void Layout::readLabelType(Lexer & lex)
600 {
601         enum {
602                 LA_NO_LABEL = 1,
603                 LA_MANUAL,
604                 LA_TOP_ENVIRONMENT,
605                 LA_CENTERED_TOP_ENVIRONMENT,
606                 LA_STATIC,
607                 LA_SENSITIVE,
608                 LA_COUNTER,
609                 LA_ENUMERATE,
610                 LA_ITEMIZE,
611                 LA_BIBLIO
612         };
613
614
615         LexerKeyword labelTypeTags[] = {
616                 { "bibliography",             LA_BIBLIO },
617                 { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT },
618                 { "counter",                  LA_COUNTER },
619                 { "enumerate",                LA_ENUMERATE },
620                 { "itemize",                  LA_ITEMIZE },
621                 { "manual",                   LA_MANUAL },
622                 { "no_label",                 LA_NO_LABEL },
623                 { "sensitive",                LA_SENSITIVE },
624                 { "static",                   LA_STATIC },
625                 { "top_environment",          LA_TOP_ENVIRONMENT }
626         };
627
628         PushPopHelper pph(lex, labelTypeTags);
629         int le = lex.lex();
630         switch (le) {
631         case Lexer::LEX_UNDEF:
632                 lex.printError("Unknown labeltype tag `$$Token'");
633                 return;
634         default: break;
635         }
636         switch (le) {
637         case LA_NO_LABEL:
638                 labeltype = LABEL_NO_LABEL;
639                 break;
640         case LA_MANUAL:
641                 labeltype = LABEL_MANUAL;
642                 break;
643         case LA_TOP_ENVIRONMENT:
644                 labeltype = LABEL_TOP_ENVIRONMENT;
645                 break;
646         case LA_CENTERED_TOP_ENVIRONMENT:
647                 labeltype = LABEL_CENTERED_TOP_ENVIRONMENT;
648                 break;
649         case LA_STATIC:
650                 labeltype = LABEL_STATIC;
651                 break;
652         case LA_SENSITIVE:
653                 labeltype = LABEL_SENSITIVE;
654                 break;
655         case LA_COUNTER:
656                 labeltype = LABEL_COUNTER;
657                 break;
658         case LA_ENUMERATE:
659                 labeltype = LABEL_ENUMERATE;
660                 break;
661         case LA_ITEMIZE:
662                 labeltype = LABEL_ITEMIZE;
663                 break;
664         case LA_BIBLIO:
665                 labeltype = LABEL_BIBLIO;
666                 break;
667         }
668 }
669
670
671 void Layout::readEndLabelType(Lexer & lex)
672 {
673         static LexerKeyword endlabelTypeTags[] = {
674                 { "box",              END_LABEL_BOX },
675                 { "filled_box", END_LABEL_FILLED_BOX },
676                 { "no_label",     END_LABEL_NO_LABEL },
677                 { "static",     END_LABEL_STATIC }
678         };
679
680         PushPopHelper pph(lex, endlabelTypeTags);
681         int le = lex.lex();
682         switch (le) {
683         case Lexer::LEX_UNDEF:
684                 lex.printError("Unknown labeltype tag `$$Token'");
685                 break;
686         case END_LABEL_STATIC:
687         case END_LABEL_BOX:
688         case END_LABEL_FILLED_BOX:
689         case END_LABEL_NO_LABEL:
690                 endlabeltype = static_cast<EndLabelType>(le);
691                 break;
692         default:
693                 LYXERR0("Unhandled value " << le);
694                 break;
695         }
696 }
697
698
699 void Layout::readMargin(Lexer & lex)
700 {
701         LexerKeyword marginTags[] = {
702                 { "dynamic",           MARGIN_DYNAMIC },
703                 { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
704                 { "manual",            MARGIN_MANUAL },
705                 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
706                 { "static",            MARGIN_STATIC }
707         };
708
709         PushPopHelper pph(lex, marginTags);
710
711         int le = lex.lex();
712         switch (le) {
713         case Lexer::LEX_UNDEF:
714                 lex.printError("Unknown margin type tag `$$Token'");
715                 return;
716         case MARGIN_STATIC:
717         case MARGIN_MANUAL:
718         case MARGIN_DYNAMIC:
719         case MARGIN_FIRST_DYNAMIC:
720         case MARGIN_RIGHT_ADDRESS_BOX:
721                 margintype = static_cast<MarginType>(le);
722                 break;
723         default:
724                 LYXERR0("Unhandled value " << le);
725                 break;
726         }
727 }
728
729
730 void Layout::readLatexType(Lexer & lex)
731 {
732         LexerKeyword latexTypeTags[] = {
733                 { "bib_environment",  LATEX_BIB_ENVIRONMENT },
734                 { "command",          LATEX_COMMAND },
735                 { "environment",      LATEX_ENVIRONMENT },
736                 { "item_environment", LATEX_ITEM_ENVIRONMENT },
737                 { "list_environment", LATEX_LIST_ENVIRONMENT },
738                 { "paragraph",        LATEX_PARAGRAPH }
739         };
740
741         PushPopHelper pph(lex, latexTypeTags);
742         int le = lex.lex();
743         switch (le) {
744         case Lexer::LEX_UNDEF:
745                 lex.printError("Unknown latextype tag `$$Token'");
746                 return;
747         case LATEX_PARAGRAPH:
748         case LATEX_COMMAND:
749         case LATEX_ENVIRONMENT:
750         case LATEX_ITEM_ENVIRONMENT:
751         case LATEX_BIB_ENVIRONMENT:
752         case LATEX_LIST_ENVIRONMENT:
753                 latextype = static_cast<LatexType>(le);
754                 break;
755         default:
756                 LYXERR0("Unhandled value " << le);
757                 break;
758         }
759 }
760
761
762 void Layout::readSpacing(Lexer & lex)
763 {
764         enum {
765                 ST_SPACING_SINGLE = 1,
766                 ST_SPACING_ONEHALF,
767                 ST_SPACING_DOUBLE,
768                 ST_OTHER
769         };
770
771         LexerKeyword spacingTags[] = {
772                 {"double",  ST_SPACING_DOUBLE },
773                 {"onehalf", ST_SPACING_ONEHALF },
774                 {"other",   ST_OTHER },
775                 {"single",  ST_SPACING_SINGLE }
776         };
777
778         PushPopHelper pph(lex, spacingTags);
779         int le = lex.lex();
780         switch (le) {
781         case Lexer::LEX_UNDEF:
782                 lex.printError("Unknown spacing token `$$Token'");
783                 return;
784         default: break;
785         }
786         switch (le) {
787         case ST_SPACING_SINGLE:
788                 spacing.set(Spacing::Single);
789                 break;
790         case ST_SPACING_ONEHALF:
791                 spacing.set(Spacing::Onehalf);
792                 break;
793         case ST_SPACING_DOUBLE:
794                 spacing.set(Spacing::Double);
795                 break;
796         case ST_OTHER:
797                 lex.next();
798                 spacing.set(Spacing::Other, lex.getString());
799                 break;
800         }
801 }
802
803
804 namespace {
805
806 docstring const i18npreamble(Language const * lang, docstring const & templ)
807 {
808         if (templ.empty())
809                 return templ;
810
811         string preamble = subst(to_utf8(templ), "$$lang", lang->babel());
812
813 #ifdef TEX2LYX
814         // tex2lyx does not have getMessages()
815         LASSERT(false, /**/);
816 #else
817         // FIXME UNICODE
818         // boost::regex is not unicode-safe.
819         // Should use QRegExp or (boost::u32regex, but that requires ICU)
820         static boost::regex const reg("_\\(([^\\)]+)\\)");
821         boost::smatch sub;
822         while (boost::regex_search(preamble, sub, reg)) {
823                 string const key = sub.str(1);
824                 string translated;
825                 if (isAscii(key))
826                         translated = to_utf8(getMessages(lang->code()).get(key));
827                 else {
828                         lyxerr << "Warning: not translating `" << key
829                                << "' because it is not pure ASCII." << endl;
830                         translated = key;
831                 }
832                 preamble = subst(preamble, sub.str(), translated);
833         }
834 #endif
835         return from_utf8(preamble);
836 }
837
838 }
839
840
841 docstring const Layout::langpreamble(Language const * lang) const
842 {
843         return i18npreamble(lang, langpreamble_);
844 }
845
846
847 docstring const Layout::babelpreamble(Language const * lang) const
848 {
849         return i18npreamble(lang, babelpreamble_);
850 }
851
852
853 bool Layout::operator==(Layout const & rhs) const
854 {
855         // This is enough for the applications we actually make,
856         // at least at the moment. But we could check more.
857         return name() == rhs.name()
858                 && latexname() == rhs.latexname()
859                 && latextype == rhs.latextype;
860 }
861
862
863 } // namespace lyx