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