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