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