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