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