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