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