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