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