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