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