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