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