]> git.lyx.org Git - lyx.git/blob - src/Layout.cpp
Remove dependency on NO_LAYOUT_CSS #define in Layout.cpp
[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 #include "support/textutils.h"
27
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_ARGUMENT,
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_ITEMCOMMAND,
56         LT_ITEMSEP,
57         LT_KEEPEMPTY,
58         LT_LABEL_BOTTOMSEP,
59         LT_LABELFONT,
60         LT_TEXTFONT,
61         LT_LABELINDENT,
62         LT_LABELSEP,
63         LT_LABELSTRING,
64         LT_LABELSTRING_APPENDIX,
65         LT_LABELCOUNTER,
66         LT_LABELTYPE,
67         LT_ENDLABELSTRING,
68         LT_ENDLABELTYPE,
69         LT_LATEXNAME,
70         LT_LATEXPARAM,
71         LT_LATEXTYPE,
72         LT_LEFTDELIM,
73         LT_LEFTMARGIN,
74         LT_NEED_PROTECT,
75         LT_NEWLINE,
76         LT_NEXTNOINDENT,
77         LT_PARINDENT,
78         LT_PARSEP,
79         LT_PARSKIP,
80         LT_PREAMBLE,
81         LT_LANGPREAMBLE,
82         LT_BABELPREAMBLE,
83         LT_REQUIRES,
84         LT_RIGHTMARGIN,
85         LT_SPACING,
86         LT_TOPSEP,
87         LT_TOCLEVEL,
88         LT_INNERTAG,
89         LT_LABELTAG,
90         LT_ITEMTAG,
91         LT_HTMLTAG,
92         LT_HTMLATTR,
93         LT_HTMLITEM,
94         LT_HTMLITEMATTR,
95         LT_HTMLLABEL,
96         LT_HTMLLABELATTR, 
97         LT_HTMLLABELFIRST,
98         LT_HTMLPREAMBLE,
99         LT_HTMLSTYLE,
100         LT_HTMLFORCECSS,
101         LT_INPREAMBLE,
102         LT_HTMLTITLE,
103         LT_SPELLCHECK,
104         LT_REFPREFIX,
105         LT_RESETARGS,
106         LT_RIGHTDELIM,
107         LT_FORCELOCAL,
108         LT_INTITLE // keep this last!
109 };
110
111 /////////////////////
112
113 Layout::Layout()
114 {
115         unknown_ = false;
116         margintype = MARGIN_STATIC;
117         latextype = LATEX_PARAGRAPH;
118         intitle = false;
119         inpreamble = false;
120         needprotect = false;
121         keepempty = false;
122         font = inherit_font;
123         labelfont = inherit_font;
124         resfont = sane_font;
125         reslabelfont = sane_font;
126         nextnoindent = false;
127         parskip = 0.0;
128         itemsep = 0;
129         topsep = 0.0;
130         bottomsep = 0.0;
131         labelbottomsep = 0.0;
132         parsep = 0;
133         align = LYX_ALIGN_BLOCK;
134         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
135         labeltype = LABEL_NO_LABEL;
136         endlabeltype = END_LABEL_NO_LABEL;
137         // Should or should not. That is the question.
138         // spacing.set(Spacing::OneHalf);
139         newline_allowed = true;
140         free_spacing = false;
141         pass_thru = false;
142         parbreak_is_newline = false;
143         toclevel = NOT_IN_TOC;
144         commanddepth = 0;
145         htmllabelfirst_ = false;
146         htmlforcecss_ = false;
147         htmltitle_ = false;
148         spellcheck = true;
149         forcelocal = 0;
150         itemcommand_ = "item";
151 }
152
153
154 bool Layout::read(Lexer & lex, TextClass const & tclass)
155 {
156         // If this is an empty layout, or if no force local version is set,
157         // we know that we will not discard the stuff to read
158         if (forcelocal == 0)
159                 return readIgnoreForcelocal(lex, tclass);
160         Layout tmp(*this);
161         tmp.forcelocal = 0;
162         bool const ret = tmp.readIgnoreForcelocal(lex, tclass);
163         // Keep the stuff if
164         // - the read version is higher
165         // - both versions are infinity (arbitrary decision)
166         // - the file did not contain any local version (needed for not
167         //   skipping user defined local layouts)
168         if (tmp.forcelocal <= 0 || tmp.forcelocal > forcelocal)
169                 *this = tmp;
170         return ret;
171 }
172
173
174 bool Layout::readIgnoreForcelocal(Lexer & lex, TextClass const & tclass)
175 {
176         // This table is sorted alphabetically [asierra 30March96]
177         LexerKeyword layoutTags[] = {
178                 { "align",          LT_ALIGN },
179                 { "alignpossible",  LT_ALIGNPOSSIBLE },
180                 { "argument",       LT_ARGUMENT },
181                 { "babelpreamble",  LT_BABELPREAMBLE },
182                 { "bottomsep",      LT_BOTTOMSEP },
183                 { "category",       LT_CATEGORY },
184                 { "commanddepth",   LT_COMMANDDEPTH },
185                 { "copystyle",      LT_COPYSTYLE },
186                 { "dependson",      LT_DEPENDSON },
187                 { "end",            LT_END },
188                 { "endlabelstring", LT_ENDLABELSTRING },
189                 { "endlabeltype",   LT_ENDLABELTYPE },
190                 { "font",           LT_FONT },
191                 { "forcelocal",     LT_FORCELOCAL },
192                 { "freespacing",    LT_FREE_SPACING },
193                 { "htmlattr",       LT_HTMLATTR },
194                 { "htmlforcecss",   LT_HTMLFORCECSS },
195                 { "htmlitem",       LT_HTMLITEM },
196                 { "htmlitemattr",   LT_HTMLITEMATTR },
197                 { "htmllabel",      LT_HTMLLABEL },
198                 { "htmllabelattr",  LT_HTMLLABELATTR },
199                 { "htmllabelfirst", LT_HTMLLABELFIRST },
200                 { "htmlpreamble",   LT_HTMLPREAMBLE },
201                 { "htmlstyle",      LT_HTMLSTYLE },
202                 { "htmltag",        LT_HTMLTAG },
203                 { "htmltitle",      LT_HTMLTITLE },
204                 { "innertag",       LT_INNERTAG },
205                 { "inpreamble",     LT_INPREAMBLE },
206                 { "intitle",        LT_INTITLE },
207                 { "itemcommand",    LT_ITEMCOMMAND },
208                 { "itemsep",        LT_ITEMSEP },
209                 { "itemtag",        LT_ITEMTAG },
210                 { "keepempty",      LT_KEEPEMPTY },
211                 { "labelbottomsep", LT_LABEL_BOTTOMSEP },
212                 { "labelcounter",   LT_LABELCOUNTER },
213                 { "labelfont",      LT_LABELFONT },
214                 { "labelindent",    LT_LABELINDENT },
215                 { "labelsep",       LT_LABELSEP },
216                 { "labelstring",    LT_LABELSTRING },
217                 { "labelstringappendix", LT_LABELSTRING_APPENDIX },
218                 { "labeltag",       LT_LABELTAG },
219                 { "labeltype",      LT_LABELTYPE },
220                 { "langpreamble",   LT_LANGPREAMBLE },
221                 { "latexname",      LT_LATEXNAME },
222                 { "latexparam",     LT_LATEXPARAM },
223                 { "latextype",      LT_LATEXTYPE },
224                 { "leftdelim",      LT_LEFTDELIM },
225                 { "leftmargin",     LT_LEFTMARGIN },
226                 { "margin",         LT_MARGIN },
227                 { "needprotect",    LT_NEED_PROTECT },
228                 { "newline",        LT_NEWLINE },
229                 { "nextnoindent",   LT_NEXTNOINDENT },
230                 { "obsoletedby",    LT_OBSOLETEDBY },
231                 { "parbreakisnewline", LT_PARBREAK_IS_NEWLINE },
232                 { "parindent",      LT_PARINDENT },
233                 { "parsep",         LT_PARSEP },
234                 { "parskip",        LT_PARSKIP },
235                 { "passthru",       LT_PASS_THRU },
236                 { "preamble",       LT_PREAMBLE },
237                 { "refprefix",      LT_REFPREFIX },
238                 { "requires",       LT_REQUIRES },
239                 { "resetargs",      LT_RESETARGS },
240                 { "rightdelim",     LT_RIGHTDELIM },
241                 { "rightmargin",    LT_RIGHTMARGIN },
242                 { "spacing",        LT_SPACING },
243                 { "spellcheck",     LT_SPELLCHECK },
244                 { "textfont",       LT_TEXTFONT },
245                 { "toclevel",       LT_TOCLEVEL },
246                 { "topsep",         LT_TOPSEP }
247         };
248
249         bool error = false;
250         bool finished = false;
251         lex.pushTable(layoutTags);
252
253         // parse style section
254         while (!finished && lex.isOK() && !error) {
255                 int le = lex.lex();
256                 // See comment in LyXRC.cpp.
257                 switch (le) {
258                 case Lexer::LEX_FEOF:
259                         continue;
260
261                 case Lexer::LEX_UNDEF:
262                         // parse error
263                         lex.printError("Unknown layout tag `$$Token'");
264                         error = true;
265                         continue;
266
267                 default: 
268                         break;
269                 }
270                 switch (static_cast<LayoutTags>(le)) {
271                 case LT_END:
272                         finished = true;
273                         break;
274
275                 case LT_CATEGORY:
276                         lex >> category_;
277                         break;
278
279                 case LT_COPYSTYLE: {
280                         docstring style;
281                         lex >> style;
282                         style = subst(style, '_', ' ');
283
284                         if (tclass.hasLayout(style)) {
285                                 docstring const tmpname = name_;
286                                 this->operator=(tclass[style]);
287                                 name_ = tmpname;
288                         } else {
289                                 LYXERR0("Cannot copy unknown style `"
290                                         << style << "'\n"
291                                         << "All layouts so far:");
292                                 DocumentClass::const_iterator lit = tclass.begin();
293                                 DocumentClass::const_iterator len = tclass.end();
294                                 for (; lit != len; ++lit)
295                                         LYXERR0(lit->name());
296                         }
297                         break;
298                         }
299
300                 case LT_OBSOLETEDBY: {
301                         docstring style;
302                         lex >> style;
303                         style = subst(style, '_', ' ');
304
305                         if (tclass.hasLayout(style)) {
306                                 docstring const tmpname = name_;
307                                 this->operator=(tclass[style]);
308                                 name_ = tmpname;
309                                 if (obsoleted_by().empty())
310                                         obsoleted_by_ = style;
311                         } else {
312                                 LYXERR0("Cannot replace with unknown style `" 
313                                         << style << '\'');
314
315                                 //lex.printError("Cannot replace with"
316                                 //               " unknown style "
317                                 //               "`$$Token'");
318                         }
319                         break;
320                 }
321
322                 case LT_DEPENDSON:
323                         lex >> depends_on_;
324                         depends_on_ = subst(depends_on_, '_', ' ');
325                         break;
326
327                 case LT_MARGIN:
328                         readMargin(lex);
329                         break;
330
331                 case LT_LATEXTYPE:
332                         readLatexType(lex);
333                         break;
334
335                 case LT_INTITLE:
336                         lex >> intitle;
337                         break;
338
339                 case LT_INPREAMBLE:
340                         lex >> inpreamble;
341                         break;
342
343                 case LT_TOCLEVEL:
344                         lex >> toclevel;
345                         break;
346
347                 case LT_RESETARGS:
348                         bool reset;
349                         lex >> reset;
350                         if (reset) {
351                                 latexargs_.clear();
352                                 itemargs_.clear();
353                                 postcommandargs_.clear();
354                         }
355                         break;
356
357                 case LT_ARGUMENT:
358                         readArgument(lex);
359                         break;
360
361                 case LT_NEED_PROTECT:
362                         lex >> needprotect;
363                         break;
364
365                 case LT_KEEPEMPTY:
366                         lex >> keepempty;
367                         break;
368
369                 case LT_FONT:
370                         font = lyxRead(lex, font);
371                         labelfont = font;
372                         break;
373
374                 case LT_TEXTFONT:
375                         font = lyxRead(lex, font);
376                         break;
377
378                 case LT_LABELFONT:
379                         labelfont = lyxRead(lex, labelfont);
380                         break;
381
382                 case LT_NEXTNOINDENT:
383                         lex >> nextnoindent;
384                         break;
385
386                 case LT_COMMANDDEPTH:
387                         lex >> commanddepth;
388                         break;
389
390                 case LT_LATEXNAME:
391                         lex >> latexname_;
392                         break;
393
394                 case LT_LATEXPARAM:
395                         lex >> latexparam_;
396                         latexparam_ = subst(latexparam_, "&quot;", "\"");
397                         break;
398
399                 case LT_LEFTDELIM:
400                         lex >> leftdelim_;
401                         leftdelim_ = support::subst(leftdelim_, from_ascii("<br/>"),
402                                                     from_ascii("\n"));
403                         break;
404
405                 case LT_RIGHTDELIM:
406                         lex >> rightdelim_;
407                         rightdelim_ = support::subst(rightdelim_, from_ascii("<br/>"),
408                                                      from_ascii("\n"));
409                         break;
410
411                 case LT_INNERTAG:
412                         lex >> innertag_;
413                         break;
414
415                 case LT_LABELTAG:
416                         lex >> labeltag_;
417                         break;
418
419                 case LT_ITEMTAG:
420                         lex >> itemtag_;
421                         break;
422
423                 case LT_ITEMCOMMAND:
424                         lex >> itemcommand_;
425                         break;
426
427                 case LT_PREAMBLE:
428                         preamble_ = from_utf8(lex.getLongString("EndPreamble"));
429                         break;
430
431                 case LT_LANGPREAMBLE:
432                         langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble"));
433                         break;
434
435                 case LT_BABELPREAMBLE:
436                         babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble"));
437                         break;
438
439                 case LT_LABELTYPE:
440                         readLabelType(lex);
441                         break;
442
443                 case LT_ENDLABELTYPE:
444                         readEndLabelType(lex);
445                         break;
446
447                 case LT_LEFTMARGIN:
448                         lex >> leftmargin;
449                         break;
450
451                 case LT_RIGHTMARGIN:
452                         lex >> rightmargin;
453                         break;
454
455                 case LT_LABELINDENT:
456                         lex >> labelindent;
457                         break;
458
459                 case LT_PARINDENT:
460                         lex >> parindent;
461                         break;
462
463                 case LT_PARSKIP:
464                         lex >> parskip;
465                         break;
466
467                 case LT_ITEMSEP:
468                         lex >> itemsep;
469                         break;
470
471                 case LT_TOPSEP:
472                         lex >> topsep;
473                         break;
474
475                 case LT_BOTTOMSEP:
476                         lex >> bottomsep;
477                         break;
478
479                 case LT_LABEL_BOTTOMSEP:
480                         lex >> labelbottomsep;
481                         break;
482
483                 case LT_LABELSEP:
484                         lex >> labelsep;
485                         labelsep = subst(labelsep, 'x', ' ');
486                         break;
487
488                 case LT_PARSEP:
489                         lex >> parsep;
490                         break;
491
492                 case LT_NEWLINE:
493                         lex >> newline_allowed;
494                         break;
495
496                 case LT_ALIGN:
497                         readAlign(lex);
498                         break;
499         
500                 case LT_ALIGNPOSSIBLE:
501                         readAlignPossible(lex);
502                         break;
503
504                 case LT_LABELSTRING:
505                         // FIXME: this means LT_LABELSTRING_APPENDIX may only
506                         // occur after LT_LABELSTRING
507                         lex >> labelstring_;
508                         labelstring_ = trim(labelstring_);
509                         labelstring_appendix_ = labelstring_;
510                         break;
511
512                 case LT_ENDLABELSTRING:
513                         lex >> endlabelstring_; 
514                         endlabelstring_ = trim(endlabelstring_);
515                         break;
516
517                 case LT_LABELSTRING_APPENDIX:
518                         lex >> labelstring_appendix_;   
519                         labelstring_appendix_ = trim(labelstring_appendix_);
520                         break;
521
522                 case LT_LABELCOUNTER:
523                         lex >> counter; 
524                         counter = trim(counter);
525                         break;
526
527                 case LT_FREE_SPACING:
528                         lex >> free_spacing;
529                         break;
530
531                 case LT_PASS_THRU:
532                         lex >> pass_thru;
533                         break;
534
535                 case LT_PARBREAK_IS_NEWLINE:
536                         lex >> parbreak_is_newline;
537                         break;
538
539                 case LT_SPACING:
540                         readSpacing(lex);
541                         break;
542
543                 case LT_REQUIRES: {
544                         lex.eatLine();
545                         vector<string> const req = 
546                                 getVectorFromString(lex.getString());
547                         requires_.insert(req.begin(), req.end());
548                         break;
549                 }
550                         
551                 case LT_REFPREFIX: {
552                         docstring arg;
553                         lex >> arg;
554                         if (arg == "OFF")
555                                 refprefix.clear();
556                         else
557                                 refprefix = arg;
558                         break;
559                 }
560
561                 case LT_HTMLTAG:
562                         lex >> htmltag_;
563                         break;
564         
565                 case LT_HTMLATTR:
566                         lex >> htmlattr_;
567                         break;
568
569                 case LT_HTMLITEM:
570                         lex >> htmlitemtag_;
571                         break;
572         
573                 case LT_HTMLITEMATTR:
574                         lex >> htmlitemattr_;
575                         break;
576         
577                 case LT_HTMLLABEL:
578                         lex >> htmllabeltag_;
579                         break;
580
581                 case LT_HTMLLABELATTR: 
582                         lex >> htmllabelattr_;
583                         break;
584
585                 case LT_HTMLLABELFIRST:
586                         lex >> htmllabelfirst_;
587                         break;
588                         
589                 case LT_HTMLSTYLE:
590                         htmlstyle_ = from_utf8(lex.getLongString("EndHTMLStyle"));
591                         break;
592
593                 case LT_HTMLFORCECSS:
594                         lex >> htmlforcecss_;
595                         break;
596
597                 case LT_HTMLPREAMBLE:
598                         htmlpreamble_ = from_utf8(lex.getLongString("EndPreamble"));
599                         break;
600                 
601                 case LT_HTMLTITLE:
602                         lex >> htmltitle_;
603                         break;
604
605                 case LT_SPELLCHECK:
606                         lex >> spellcheck;
607                         break;
608
609                 case LT_FORCELOCAL:
610                         lex >> forcelocal;
611                         break;
612                 }
613         }
614         lex.popTable();
615         // make sure we only have inpreamble = true for commands
616         if (inpreamble && latextype != LATEX_COMMAND && latextype != LATEX_PARAGRAPH) {
617                 LYXERR0("InPreamble not permitted except with command and paragraph layouts.");
618                 LYXERR0("Layout name: " << name());
619                 inpreamble = false;
620         }
621
622         return finished && !error;
623 }
624
625
626 enum {
627         AT_BLOCK = 1,
628         AT_LEFT,
629         AT_RIGHT,
630         AT_CENTER,
631         AT_LAYOUT
632 };
633
634
635 LexerKeyword alignTags[] = {
636         { "block",  AT_BLOCK },
637         { "center", AT_CENTER },
638         { "layout", AT_LAYOUT },
639         { "left",   AT_LEFT },
640         { "right",  AT_RIGHT }
641 };
642
643
644 void Layout::readAlign(Lexer & lex)
645 {
646         PushPopHelper pph(lex, alignTags);
647         int le = lex.lex();
648         switch (le) {
649         case Lexer::LEX_UNDEF:
650                 lex.printError("Unknown alignment `$$Token'");
651                 return;
652         default: break;
653         };
654         switch (le) {
655         case AT_BLOCK:
656                 align = LYX_ALIGN_BLOCK;
657                 break;
658         case AT_LEFT:
659                 align = LYX_ALIGN_LEFT;
660                 break;
661         case AT_RIGHT:
662                 align = LYX_ALIGN_RIGHT;
663                 break;
664         case AT_CENTER:
665                 align = LYX_ALIGN_CENTER;
666                 break;
667         case AT_LAYOUT:
668                 align = LYX_ALIGN_LAYOUT;
669                 break;
670         }
671 }
672
673
674 void Layout::readAlignPossible(Lexer & lex)
675 {
676         lex.pushTable(alignTags);
677         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
678         int lineno = lex.lineNumber();
679         do {
680                 int le = lex.lex();
681                 switch (le) {
682                 case Lexer::LEX_UNDEF:
683                         lex.printError("Unknown alignment `$$Token'");
684                         continue;
685                 default: break;
686                 };
687                 switch (le) {
688                 case AT_BLOCK:
689                         alignpossible |= LYX_ALIGN_BLOCK;
690                         break;
691                 case AT_LEFT:
692                         alignpossible |= LYX_ALIGN_LEFT;
693                         break;
694                 case AT_RIGHT:
695                         alignpossible |= LYX_ALIGN_RIGHT;
696                         break;
697                 case AT_CENTER:
698                         alignpossible |= LYX_ALIGN_CENTER;
699                         break;
700                 case AT_LAYOUT:
701                         alignpossible |= LYX_ALIGN_LAYOUT;
702                         break;
703                 }
704         } while (lineno == lex.lineNumber());
705         lex.popTable();
706 }
707
708
709 void Layout::readLabelType(Lexer & lex)
710 {
711         enum {
712                 LA_NO_LABEL = 1,
713                 LA_MANUAL,
714                 LA_ABOVE,
715                 LA_CENTERED,
716                 LA_STATIC,
717                 LA_SENSITIVE,
718                 LA_ENUMERATE,
719                 LA_ITEMIZE,
720                 LA_BIBLIO
721         };
722
723
724         LexerKeyword labelTypeTags[] = {
725           { "above",        LA_ABOVE },
726                 { "bibliography", LA_BIBLIO },
727                 { "centered",     LA_CENTERED },
728                 { "enumerate",    LA_ENUMERATE },
729                 { "itemize",      LA_ITEMIZE },
730                 { "manual",       LA_MANUAL },
731                 { "no_label",     LA_NO_LABEL },
732                 { "sensitive",    LA_SENSITIVE },
733                 { "static",       LA_STATIC }
734         };
735
736         PushPopHelper pph(lex, labelTypeTags);
737         int le = lex.lex();
738         switch (le) {
739         case Lexer::LEX_UNDEF:
740                 lex.printError("Unknown labeltype tag `$$Token'");
741                 return;
742         default: break;
743         }
744         switch (le) {
745         case LA_NO_LABEL:
746                 labeltype = LABEL_NO_LABEL;
747                 break;
748         case LA_MANUAL:
749                 labeltype = LABEL_MANUAL;
750                 break;
751         case LA_ABOVE:
752                 labeltype = LABEL_ABOVE;
753                 break;
754         case LA_CENTERED:
755                 labeltype = LABEL_CENTERED;
756                 break;
757         case LA_STATIC:
758                 labeltype = LABEL_STATIC;
759                 break;
760         case LA_SENSITIVE:
761                 labeltype = LABEL_SENSITIVE;
762                 break;
763         case LA_ENUMERATE:
764                 labeltype = LABEL_ENUMERATE;
765                 break;
766         case LA_ITEMIZE:
767                 labeltype = LABEL_ITEMIZE;
768                 break;
769         case LA_BIBLIO:
770                 labeltype = LABEL_BIBLIO;
771                 break;
772         }
773 }
774
775
776 void Layout::readEndLabelType(Lexer & lex)
777 {
778         static LexerKeyword endlabelTypeTags[] = {
779                 { "box",              END_LABEL_BOX },
780                 { "filled_box", END_LABEL_FILLED_BOX },
781                 { "no_label",     END_LABEL_NO_LABEL },
782                 { "static",     END_LABEL_STATIC }
783         };
784
785         PushPopHelper pph(lex, endlabelTypeTags);
786         int le = lex.lex();
787         switch (le) {
788         case Lexer::LEX_UNDEF:
789                 lex.printError("Unknown labeltype tag `$$Token'");
790                 break;
791         case END_LABEL_STATIC:
792         case END_LABEL_BOX:
793         case END_LABEL_FILLED_BOX:
794         case END_LABEL_NO_LABEL:
795                 endlabeltype = static_cast<EndLabelType>(le);
796                 break;
797         default:
798                 LYXERR0("Unhandled value " << le);
799                 break;
800         }
801 }
802
803
804 void Layout::readMargin(Lexer & lex)
805 {
806         LexerKeyword marginTags[] = {
807                 { "dynamic",           MARGIN_DYNAMIC },
808                 { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
809                 { "manual",            MARGIN_MANUAL },
810                 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
811                 { "static",            MARGIN_STATIC }
812         };
813
814         PushPopHelper pph(lex, marginTags);
815
816         int le = lex.lex();
817         switch (le) {
818         case Lexer::LEX_UNDEF:
819                 lex.printError("Unknown margin type tag `$$Token'");
820                 return;
821         case MARGIN_STATIC:
822         case MARGIN_MANUAL:
823         case MARGIN_DYNAMIC:
824         case MARGIN_FIRST_DYNAMIC:
825         case MARGIN_RIGHT_ADDRESS_BOX:
826                 margintype = static_cast<MarginType>(le);
827                 break;
828         default:
829                 LYXERR0("Unhandled value " << le);
830                 break;
831         }
832 }
833
834
835 void Layout::readLatexType(Lexer & lex)
836 {
837         LexerKeyword latexTypeTags[] = {
838                 { "bib_environment",  LATEX_BIB_ENVIRONMENT },
839                 { "command",          LATEX_COMMAND },
840                 { "environment",      LATEX_ENVIRONMENT },
841                 { "item_environment", LATEX_ITEM_ENVIRONMENT },
842                 { "list_environment", LATEX_LIST_ENVIRONMENT },
843                 { "paragraph",        LATEX_PARAGRAPH }
844         };
845
846         PushPopHelper pph(lex, latexTypeTags);
847         int le = lex.lex();
848         switch (le) {
849         case Lexer::LEX_UNDEF:
850                 lex.printError("Unknown latextype tag `$$Token'");
851                 return;
852         case LATEX_PARAGRAPH:
853         case LATEX_COMMAND:
854         case LATEX_ENVIRONMENT:
855         case LATEX_ITEM_ENVIRONMENT:
856         case LATEX_BIB_ENVIRONMENT:
857         case LATEX_LIST_ENVIRONMENT:
858                 latextype = static_cast<LatexType>(le);
859                 break;
860         default:
861                 LYXERR0("Unhandled value " << le);
862                 break;
863         }
864 }
865
866
867 void Layout::readSpacing(Lexer & lex)
868 {
869         enum {
870                 ST_SPACING_SINGLE = 1,
871                 ST_SPACING_ONEHALF,
872                 ST_SPACING_DOUBLE,
873                 ST_OTHER
874         };
875
876         LexerKeyword spacingTags[] = {
877                 {"double",  ST_SPACING_DOUBLE },
878                 {"onehalf", ST_SPACING_ONEHALF },
879                 {"other",   ST_OTHER },
880                 {"single",  ST_SPACING_SINGLE }
881         };
882
883         PushPopHelper pph(lex, spacingTags);
884         int le = lex.lex();
885         switch (le) {
886         case Lexer::LEX_UNDEF:
887                 lex.printError("Unknown spacing token `$$Token'");
888                 return;
889         default: break;
890         }
891         switch (le) {
892         case ST_SPACING_SINGLE:
893                 spacing.set(Spacing::Single);
894                 break;
895         case ST_SPACING_ONEHALF:
896                 spacing.set(Spacing::Onehalf);
897                 break;
898         case ST_SPACING_DOUBLE:
899                 spacing.set(Spacing::Double);
900                 break;
901         case ST_OTHER:
902                 lex.next();
903                 spacing.set(Spacing::Other, lex.getString());
904                 break;
905         }
906 }
907
908
909 void Layout::readArgument(Lexer & lex)
910 {
911         latexarg arg;
912         // writeArgument() makes use of these default values
913         arg.mandatory = false;
914         arg.autoinsert = false;
915         bool error = false;
916         bool finished = false;
917         arg.font = inherit_font;
918         arg.labelfont = inherit_font;
919         string id;
920         lex >> id;
921         bool const itemarg = prefixIs(id, "item:");
922         bool const postcmd = prefixIs(id, "post:");
923
924         while (!finished && lex.isOK() && !error) {
925                 lex.next();
926                 string const tok = ascii_lowercase(lex.getString());
927
928                 if (tok.empty()) {
929                         continue;
930                 } else if (tok == "endargument") {
931                         finished = true;
932                 } else if (tok == "labelstring") {
933                         lex.next();
934                         arg.labelstring = lex.getDocString();
935                 } else if (tok == "menustring") {
936                         lex.next();
937                         arg.menustring = lex.getDocString();
938                 } else if (tok == "mandatory") {
939                         lex.next();
940                         arg.mandatory = lex.getBool();
941                 } else if (tok == "autoinsert") {
942                         lex.next();
943                         arg.autoinsert = lex.getBool();
944                 } else if (tok == "leftdelim") {
945                         lex.next();
946                         arg.ldelim = lex.getDocString();
947                         arg.ldelim = support::subst(arg.ldelim, from_ascii("<br/>"),
948                                                     from_ascii("\n"));
949                 } else if (tok == "rightdelim") {
950                         lex.next();
951                         arg.rdelim = lex.getDocString();
952                         arg.rdelim = support::subst(arg.rdelim, from_ascii("<br/>"),
953                                                     from_ascii("\n"));
954                 } else if (tok == "defaultarg") {
955                         lex.next();
956                         arg.defaultarg = lex.getDocString();
957                 } else if (tok == "presetarg") {
958                         lex.next();
959                         arg.presetarg = lex.getDocString();
960                 } else if (tok == "tooltip") {
961                         lex.next();
962                         arg.tooltip = lex.getDocString();
963                 } else if (tok == "requires") {
964                         lex.next();
965                         arg.requires = lex.getString();
966                 } else if (tok == "decoration") {
967                         lex.next();
968                         arg.decoration = lex.getString();
969                 } else if (tok == "font") {
970                         arg.font = lyxRead(lex, arg.font);
971                 } else if (tok == "labelfont") {
972                         arg.labelfont = lyxRead(lex, arg.labelfont);
973                 } else {
974                         lex.printError("Unknown tag");
975                         error = true;
976                 }
977         }
978         if (arg.labelstring.empty())
979                 LYXERR0("Incomplete Argument definition!");
980         else if (itemarg)
981                 itemargs_[id] = arg;
982         else if (postcmd)
983                 postcommandargs_[id] = arg;
984         else
985                 latexargs_[id] = arg;
986 }
987
988
989 void writeArgument(ostream & os, string const & id, Layout::latexarg const & arg)
990 {
991         os << "\tArgument " << id << '\n';
992         if (!arg.labelstring.empty())
993                 os << "\t\tLabelString \"" << to_utf8(arg.labelstring) << "\"\n";
994         if (!arg.menustring.empty())
995                 os << "\t\tMenuString \"" << to_utf8(arg.menustring) << "\"\n";
996         if (arg.mandatory)
997                 os << "\t\tMandatory " << arg.mandatory << '\n';
998         if (arg.autoinsert)
999                 os << "\t\tAutoinsert " << arg.autoinsert << '\n';
1000         if (!arg.ldelim.empty())
1001                 os << "\t\tLeftDelim \""
1002                    << to_utf8(subst(arg.ldelim, from_ascii("\n"), from_ascii("<br/>")))
1003                    << "\"\n";
1004         if (!arg.rdelim.empty())
1005                 os << "\t\tRightDelim \""
1006                    << to_utf8(subst(arg.rdelim, from_ascii("\n"), from_ascii("<br/>")))
1007                    << "\"\n";
1008         if (!arg.defaultarg.empty())
1009                 os << "\t\tDefaultArg \"" << to_utf8(arg.defaultarg) << "\"\n";
1010         if (!arg.presetarg.empty())
1011                 os << "\t\tPresetArg \"" << to_utf8(arg.presetarg) << "\"\n";
1012         if (!arg.tooltip.empty())
1013                 os << "\t\tToolTip \"" << to_utf8(arg.tooltip) << "\"\n";
1014         if (!arg.requires.empty())
1015                 os << "\t\tRequires \"" << arg.requires << "\"\n";
1016         if (!arg.decoration.empty())
1017                 os << "\t\tDecoration \"" << arg.decoration << "\"\n";
1018         if (arg.font != inherit_font)
1019                 lyxWrite(os, arg.font, "Font", 2);
1020         if (arg.labelfont != inherit_font)
1021                 lyxWrite(os, arg.labelfont, "LabelFont", 2);
1022         os << "\tEndArgument\n";
1023 }
1024
1025
1026 void Layout::write(ostream & os) const
1027 {
1028         os << "Style " << to_utf8(name_) << '\n';
1029         if (!category_.empty() && obsoleted_by_.empty())
1030                 os << "\tCategory \"" << to_utf8(category_) << "\"\n";
1031         // Can't deduce Copystyle here :-(
1032         if (!obsoleted_by_.empty()) {
1033                 os << "\tObsoletedBy \"" << to_utf8(obsoleted_by_)
1034                    << "\"\nEnd\n";
1035                 return;
1036         }
1037         if (!depends_on_.empty())
1038                 os << "\tDependsOn " << to_utf8(depends_on_) << '\n';
1039         switch (margintype) {
1040                 case MARGIN_DYNAMIC:
1041                         os << "\tMargin Dynamic\n";
1042                         break;
1043                 case MARGIN_FIRST_DYNAMIC:
1044                         os << "\tMargin First_Dynamic\n";
1045                         break;
1046                 case MARGIN_MANUAL:
1047                         os << "\tMargin Manual\n";
1048                         break;
1049                 case MARGIN_RIGHT_ADDRESS_BOX:
1050                         os << "\tMargin Right_Address_Box\n";
1051                         break;
1052                 case MARGIN_STATIC:
1053                         os << "\tMargin Static\n";
1054                         break;
1055         }
1056         switch (latextype) {
1057                 case LATEX_BIB_ENVIRONMENT:
1058                         os << "\tLatexType Bib_Environment\n";
1059                         break;
1060                 case LATEX_COMMAND:
1061                         os << "\tLatexType Command\n";
1062                         break;
1063                 case LATEX_ENVIRONMENT:
1064                         os << "\tLatexType Environment\n";
1065                         break;
1066                 case LATEX_ITEM_ENVIRONMENT:
1067                         os << "\tLatexType Item_Environment\n";
1068                         break;
1069                 case LATEX_LIST_ENVIRONMENT:
1070                         os << "\tLatexType List_Environment\n";
1071                         break;
1072                 case LATEX_PARAGRAPH:
1073                         os << "\tLatexType Paragraph\n";
1074                         break;
1075         }
1076         os << "\tInTitle " << intitle << "\n"
1077               "\tInPreamble " << inpreamble << "\n"
1078               "\tTocLevel " << toclevel << '\n';
1079         // ResetArgs does not make sense here
1080         for (LaTeXArgMap::const_iterator it = latexargs_.begin();
1081              it != latexargs_.end(); ++it)
1082                 writeArgument(os, it->first, it->second);
1083         for (LaTeXArgMap::const_iterator it = itemargs_.begin();
1084              it != itemargs_.end(); ++it)
1085                 writeArgument(os, it->first, it->second);
1086         for (LaTeXArgMap::const_iterator it = postcommandargs_.begin();
1087              it != postcommandargs_.end(); ++it)
1088                 writeArgument(os, it->first, it->second);
1089         os << "\tNeedProtect " << needprotect << "\n"
1090               "\tKeepEmpty " << keepempty << '\n';
1091         if (labelfont == font)
1092                 lyxWrite(os, font, "Font", 1);
1093         else {
1094                 lyxWrite(os, font, "TextFont", 1);
1095                 lyxWrite(os, labelfont, "LabelFont", 1);
1096         }
1097         os << "\tNextNoIndent " << nextnoindent << "\n"
1098               "\tCommandDepth " << commanddepth << '\n';
1099         if (!latexname_.empty())
1100                 os << "\tLatexName \"" << latexname_ << "\"\n";
1101         if (!latexparam_.empty())
1102                 os << "\tLatexParam \"" << subst(latexparam_, "\"", "&quot;")
1103                    << "\"\n";
1104         if (!leftdelim_.empty())
1105                 os << "\tLeftDelim "
1106                    << to_utf8(subst(leftdelim_, from_ascii("\n"), from_ascii("<br/>")))
1107                    << '\n';
1108         if (!rightdelim_.empty())
1109                 os << "\tRightDelim "
1110                    << to_utf8(subst(rightdelim_, from_ascii("\n"), from_ascii("<br/>")))
1111                    << '\n';
1112         if (!innertag_.empty())
1113                 os << "\tInnerTag \"" << innertag_ << "\"\n";
1114         if (!labeltag_.empty())
1115                 os << "\tLabelTag \"" << labeltag_ << "\"\n";
1116         if (!itemtag_.empty())
1117                 os << "\tItemTag \"" << itemtag_ << "\"\n";
1118         if (!itemcommand_.empty())
1119                 os << "\tItemCommand " << itemcommand_ << '\n';
1120         if (!preamble_.empty())
1121                 os << "\tPreamble\n\t"
1122                    << to_utf8(subst(rtrim(preamble_, "\n"),
1123                                     from_ascii("\n"), from_ascii("\n\t")))
1124                    << "\n\tEndPreamble\n";
1125         if (!langpreamble_.empty())
1126                 os << "\tLangPreamble\n\t"
1127                    << to_utf8(subst(rtrim(langpreamble_, "\n"),
1128                                     from_ascii("\n"), from_ascii("\n\t")))
1129                    << "\n\tEndLangPreamble\n";
1130         if (!babelpreamble_.empty())
1131                 os << "\tBabelPreamble\n\t"
1132                    << to_utf8(subst(rtrim(babelpreamble_, "\n"),
1133                                     from_ascii("\n"), from_ascii("\n\t")))
1134                    << "\n\tEndBabelPreamble\n";
1135         switch (labeltype) {
1136         case LABEL_ABOVE:
1137                 os << "\tLabelType Above\n";
1138                 break;
1139         case LABEL_BIBLIO:
1140                 os << "\tLabelType Bibliography\n";
1141                 break;
1142         case LABEL_CENTERED:
1143                 os << "\tLabelType Centered\n";
1144                 break;
1145         case LABEL_ENUMERATE:
1146                 os << "\tLabelType Enumerate\n";
1147                 break;
1148         case LABEL_ITEMIZE:
1149                 os << "\tLabelType Itemize\n";
1150                 break;
1151         case LABEL_MANUAL:
1152                 os << "\tLabelType Manual\n";
1153                 break;
1154         case LABEL_NO_LABEL:
1155                 os << "\tLabelType No_Label\n";
1156                 break;
1157         case LABEL_SENSITIVE:
1158                 os << "\tLabelType Sensitive\n";
1159                 break;
1160         case LABEL_STATIC:
1161                 os << "\tLabelType Static\n";
1162                 break;
1163         }
1164         switch (endlabeltype) {
1165         case END_LABEL_BOX:
1166                 os << "\tEndLabelType Box\n";
1167                 break;
1168         case END_LABEL_FILLED_BOX:
1169                 os << "\tEndLabelType Filled_Box\n";
1170                 break;
1171         case END_LABEL_NO_LABEL:
1172                 os << "\tEndLabelType No_Label\n";
1173                 break;
1174         case END_LABEL_STATIC:
1175                 os << "\tEndLabelType Static\n";
1176                 break;
1177         }
1178         if (!leftmargin.empty())
1179                 os << "\tLeftMargin \"" << to_utf8(leftmargin) << "\"\n";
1180         if (!rightmargin.empty())
1181                 os << "\tRightMargin \"" << to_utf8(rightmargin) << "\"\n";
1182         if (!labelindent.empty())
1183                 os << "\tLabelIndent " << to_utf8(labelindent) << '\n';
1184         if (!parindent.empty())
1185                 os << "\tParIndent " << to_utf8(parindent) << '\n';
1186         os << "\tParSkip " << parskip << "\n"
1187               "\tItemSep " << itemsep << "\n"
1188               "\tTopSep " << topsep << "\n"
1189               "\tBottomSep " << bottomsep << "\n"
1190               "\tLabelBottomSep " << labelbottomsep << '\n';
1191         if (!labelsep.empty())
1192                 os << "\tLabelSep " << to_utf8(subst(labelsep, ' ', 'x'))
1193                    << '\n';
1194         os << "\tParSep " << parsep << "\n"
1195               "\tNewLine " << newline_allowed << '\n';
1196         switch (align) {
1197         case LYX_ALIGN_BLOCK:
1198                 os << "\tAlign Block\n";
1199                 break;
1200         case LYX_ALIGN_CENTER:
1201                 os << "\tAlign Center\n";
1202                 break;
1203         case LYX_ALIGN_LAYOUT:
1204                 os << "\tAlign Layout\n";
1205                 break;
1206         case LYX_ALIGN_LEFT:
1207                 os << "\tAlign Left\n";
1208                 break;
1209         case LYX_ALIGN_RIGHT:
1210                 os << "\tAlign Right\n";
1211                 break;
1212         case LYX_ALIGN_DECIMAL:
1213         case LYX_ALIGN_SPECIAL:
1214         case LYX_ALIGN_NONE:
1215                 break;
1216         }
1217         if (alignpossible & (LYX_ALIGN_BLOCK | LYX_ALIGN_CENTER |
1218                              LYX_ALIGN_LAYOUT | LYX_ALIGN_LEFT | LYX_ALIGN_RIGHT)) {
1219                 bool first = true;
1220                 os << "\tAlignPossible";
1221                 if (alignpossible & LYX_ALIGN_BLOCK) {
1222                         if (!first)
1223                                 os << ',';
1224                         os << " Block";
1225                         first = false;
1226                 }
1227                 if (alignpossible & LYX_ALIGN_CENTER) {
1228                         if (!first)
1229                                 os << ',';
1230                         os << " Center";
1231                         first = false;
1232                 }
1233                 if (alignpossible & LYX_ALIGN_LAYOUT) {
1234                         if (!first)
1235                                 os << ',';
1236                         os << " Layout";
1237                         first = false;
1238                 }
1239                 if (alignpossible & LYX_ALIGN_LEFT) {
1240                         if (!first)
1241                                 os << ',';
1242                         os << " Left";
1243                         first = false;
1244                 }
1245                 if (alignpossible & LYX_ALIGN_RIGHT) {
1246                         if (!first)
1247                                 os << ',';
1248                         os << " Right";
1249                         first = false;
1250                 }
1251                 os << '\n';
1252         }
1253         // LabelString must come before LabelStringAppendix
1254         if (!labelstring_.empty())
1255                 os << "\tLabelString \"" << to_utf8(labelstring_) << "\"\n";
1256         if (!endlabelstring_.empty())
1257                 os << "\tEndLabelString \"" << to_utf8(endlabelstring_) << "\"\n";
1258         if (!labelstring_appendix_.empty() && labelstring_appendix_ != labelstring_)
1259                 os << "\tLabelStringAppendix \""
1260                    << to_utf8(labelstring_appendix_) << "\"\n";
1261         if (!counter.empty())
1262                 os << "\tLabelCounter \"" << to_utf8(counter) << "\"\n";
1263         os << "\tFreeSpacing " << free_spacing << '\n';
1264         os << "\tPassThru " << pass_thru << '\n';
1265         os << "\tParbreakIsNewline " << parbreak_is_newline << '\n';
1266         switch (spacing.getSpace()) {
1267         case Spacing::Double:
1268                 os << "\tSpacing Double\n";
1269                 break;
1270         case Spacing::Onehalf:
1271                 os << "\tSpacing Onehalf\n";
1272                 break;
1273         case Spacing::Other:
1274                 os << "\tSpacing Other " << spacing.getValueAsString() << '\n';
1275                 break;
1276         case Spacing::Single:
1277                 os << "\tSpacing Single\n";
1278                 break;
1279         case Spacing::Default:
1280                 break;
1281         }
1282         if (!requires_.empty()) {
1283                 os << "\tRequires ";
1284                 for (set<string>::const_iterator it = requires_.begin();
1285                      it != requires_.end(); ++it) {
1286                         if (it != requires_.begin())
1287                                 os << ',';
1288                         os << *it;
1289                 }
1290                 os << '\n';
1291         }
1292         if (refprefix.empty())
1293                 os << "\tRefPrefix OFF\n";
1294         else
1295                 os << "\tRefPrefix " << to_utf8(refprefix) << '\n';
1296         if (!htmltag_.empty())
1297                 os << "\tHTMLTag " << htmltag_ << '\n';
1298         if (!htmlattr_.empty())
1299                 os << "\tHTMLAttr " << htmlattr_ << '\n';
1300         if (!htmlitemtag_.empty())
1301                 os << "\tHTMLItem " << htmlitemtag_ << '\n';
1302         if (!htmlitemattr_.empty())
1303                 os << "\tHTMLItemAttr " << htmlitemattr_ << '\n';
1304         if (!htmllabeltag_.empty())
1305                 os << "\tHTMLLabel " << htmllabeltag_ << '\n';
1306         if (!htmllabelattr_.empty())
1307                 os << "\tHTMLLabelAttr " << htmllabelattr_ << '\n';
1308         os << "\tHTMLLabelFirst " << htmllabelfirst_ << '\n';
1309         if (!htmlstyle_.empty())
1310                 os << "\tHTMLStyle\n"
1311                    << to_utf8(rtrim(htmlstyle_, "\n"))
1312                    << "\n\tEndHTMLStyle\n";
1313         os << "\tHTMLForceCSS " << htmlforcecss_ << '\n';
1314         if (!htmlpreamble_.empty())
1315                 os << "\tHTMLPreamble\n"
1316                    << to_utf8(rtrim(htmlpreamble_, "\n"))
1317                    << "\n\tEndPreamble\n";
1318         os << "\tHTMLTitle " << htmltitle_ << "\n"
1319               "\tSpellcheck " << spellcheck << "\n"
1320               "\tForceLocal " << forcelocal << "\n"
1321               "End\n";
1322 }
1323
1324
1325 Layout::LaTeXArgMap Layout::args() const
1326 {
1327         LaTeXArgMap args = latexargs_;
1328         if (!postcommandargs_.empty())
1329                 args.insert(postcommandargs_.begin(), postcommandargs_.end());
1330         if (!itemargs_.empty())
1331                 args.insert(itemargs_.begin(), itemargs_.end());
1332         return args;
1333 }
1334
1335
1336 int Layout::optArgs() const
1337 {
1338         int nr = 0;
1339         LaTeXArgMap::const_iterator it = latexargs_.begin();
1340         for (; it != latexargs_.end(); ++it) {
1341                 if (!(*it).second.mandatory)
1342                         ++nr;
1343         }
1344         LaTeXArgMap::const_iterator iit = postcommandargs_.begin();
1345         for (; iit != postcommandargs_.end(); ++iit) {
1346                 if (!(*iit).second.mandatory)
1347                         ++nr;
1348         }
1349         return nr;
1350 }
1351
1352
1353 int Layout::requiredArgs() const
1354 {
1355         int nr = 0;
1356         LaTeXArgMap::const_iterator it = latexargs_.begin();
1357         for (; it != latexargs_.end(); ++it) {
1358                 if ((*it).second.mandatory)
1359                         ++nr;
1360         }
1361         LaTeXArgMap::const_iterator iit = postcommandargs_.begin();
1362         for (; iit != postcommandargs_.end(); ++iit) {
1363                 if (!(*iit).second.mandatory)
1364                         ++nr;
1365         }
1366         return nr;
1367 }
1368
1369
1370 string const & Layout::htmltag() const 
1371
1372         if (htmltag_.empty())
1373                 htmltag_ =  "div";
1374         return htmltag_;
1375 }
1376
1377
1378 string const & Layout::htmlattr() const 
1379
1380         if (htmlattr_.empty())
1381                 htmlattr_ = "class=\"" + defaultCSSClass() + "\"";
1382         return htmlattr_; 
1383 }
1384
1385
1386 string const & Layout::htmlitemtag() const 
1387
1388         if (htmlitemtag_.empty())
1389                 htmlitemtag_ = "div";
1390         return htmlitemtag_; 
1391 }
1392
1393
1394 string const & Layout::htmlitemattr() const 
1395
1396         if (htmlitemattr_.empty())
1397                 htmlitemattr_ = "class=\"" + defaultCSSItemClass() + "\"";
1398         return htmlitemattr_; 
1399 }
1400
1401
1402 string const & Layout::htmllabeltag() const 
1403
1404         if (htmllabeltag_.empty()) {
1405                 if (labeltype != LABEL_ABOVE &&
1406                     labeltype != LABEL_CENTERED)
1407                         htmllabeltag_ = "span";
1408                 else
1409                         htmllabeltag_ = "div";
1410         }
1411         return htmllabeltag_; 
1412 }
1413
1414
1415 string const & Layout::htmllabelattr() const 
1416
1417         if (htmllabelattr_.empty())
1418                 htmllabelattr_ = "class=\"" + defaultCSSLabelClass() + "\"";
1419         return htmllabelattr_; 
1420 }
1421
1422
1423 docstring Layout::htmlstyle() const
1424 {
1425         if (!htmlstyle_.empty() && !htmlforcecss_)
1426                 return htmlstyle_;
1427         if (htmldefaultstyle_.empty()) 
1428                 makeDefaultCSS();
1429         docstring retval = htmldefaultstyle_;
1430         if (!htmlstyle_.empty())
1431                 retval += '\n' + htmlstyle_;
1432         return retval;
1433 }
1434
1435
1436 string Layout::defaultCSSClass() const
1437
1438         if (!defaultcssclass_.empty())
1439                 return defaultcssclass_;
1440         docstring d;
1441         docstring::const_iterator it = name().begin();
1442         docstring::const_iterator en = name().end();
1443         for (; it != en; ++it) {
1444                 char_type const c = *it;
1445                 if (!isAlphaASCII(c)) {
1446                         if (d.empty())
1447                                 // make sure we don't start with an underscore,
1448                                 // as that sometimes causes problems.
1449                                 d = from_ascii("lyx_");
1450                         else
1451                                 d += '_';
1452                 } else if (isLower(c))
1453                         d += c;
1454                 else
1455                         // this is slow, so do it only if necessary
1456                         d += lowercase(c);
1457         }
1458         defaultcssclass_ = to_utf8(d);
1459         return defaultcssclass_;
1460 }
1461
1462
1463 namespace {
1464
1465 string makeMarginValue(char const * side, double d)
1466 {
1467         ostringstream os;
1468         os << "margin-" << side << ": " << d << "ex;\n";
1469         return os.str();
1470 }
1471
1472 }
1473
1474
1475 void Layout::makeDefaultCSS() const
1476 {
1477         // this never needs to be redone, since reloading layouts will
1478         // wipe out what we did before.
1479         if (!htmldefaultstyle_.empty()) 
1480                 return;
1481         
1482         // main font
1483         htmldefaultstyle_ = font.asCSS();
1484         
1485         // bottom margins
1486         string tmp;
1487         if (topsep > 0)
1488                 tmp += makeMarginValue("top", topsep);
1489         if (bottomsep > 0)
1490                 tmp += makeMarginValue("bottom", bottomsep);
1491         if (!leftmargin.empty()) {
1492                 // we can't really do what LyX does with the margin, so 
1493                 // we'll just figure out how many characters it is
1494                 int const len = leftmargin.length();
1495                 tmp += makeMarginValue("left", len);
1496         }
1497         if (!rightmargin.empty()) {
1498                 int const len = rightmargin.length();
1499                 tmp += makeMarginValue("right", len);
1500         }
1501                 
1502         if (!tmp.empty()) {
1503                 if (!htmldefaultstyle_.empty())
1504                         htmldefaultstyle_ += from_ascii("\n");
1505                 htmldefaultstyle_ += from_ascii(tmp);
1506         }
1507
1508         // alignment
1509         string where = alignmentToCSS(align);
1510         if (!where.empty()) {
1511                 htmldefaultstyle_ += from_ascii("text-align: " + where + ";\n");
1512         }
1513
1514         // wrap up what we have, if anything
1515         if (!htmldefaultstyle_.empty())
1516                 htmldefaultstyle_ = 
1517                         from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") +
1518                         htmldefaultstyle_ + from_ascii("\n}\n");
1519         
1520         if (labeltype == LABEL_NO_LABEL || htmllabeltag() == "NONE")
1521                 return;
1522         
1523         docstring labelCSS;
1524         
1525         // label font
1526         if (labelfont != font)
1527                 labelCSS = labelfont.asCSS() + from_ascii("\n");
1528         if (labeltype == LABEL_CENTERED)
1529                 labelCSS += from_ascii("text-align: center;\n");
1530         
1531         if (!labelCSS.empty())
1532                 htmldefaultstyle_ +=
1533                         from_ascii(htmllabeltag() + "." + defaultCSSLabelClass() + " {\n") +
1534                         labelCSS + from_ascii("\n}\n");
1535 }
1536
1537
1538 bool Layout::operator==(Layout const & rhs) const
1539 {
1540         // This is enough for the applications we actually make,
1541         // at least at the moment. But we could check more.
1542         return name() == rhs.name()
1543                 && latexname() == rhs.latexname()
1544                 && latextype == rhs.latextype;
1545 }
1546
1547
1548 } // namespace lyx