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