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