]> git.lyx.org Git - lyx.git/blob - src/Layout.cpp
Support for command argument placement after the workarea 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_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                         }
332                         break;
333
334                 case LT_ARGUMENT:
335                         readArgument(lex);
336                         break;
337
338                 case LT_NEED_PROTECT:
339                         lex >> needprotect;
340                         break;
341
342                 case LT_KEEPEMPTY:
343                         lex >> keepempty;
344                         break;
345
346                 case LT_FONT:
347                         font = lyxRead(lex, font);
348                         labelfont = font;
349                         break;
350
351                 case LT_TEXTFONT:
352                         font = lyxRead(lex, font);
353                         break;
354
355                 case LT_LABELFONT:
356                         labelfont = lyxRead(lex, labelfont);
357                         break;
358
359                 case LT_NEXTNOINDENT:
360                         lex >> nextnoindent;
361                         break;
362
363                 case LT_COMMANDDEPTH:
364                         lex >> commanddepth;
365                         break;
366
367                 case LT_LATEXNAME:
368                         lex >> latexname_;
369                         break;
370
371                 case LT_LATEXPARAM:
372                         lex >> latexparam_;
373                         latexparam_ = subst(latexparam_, "&quot;", "\"");
374                         break;
375
376                 case LT_LEFTDELIM:
377                         lex >> leftdelim_;
378                         leftdelim_ = support::subst(leftdelim_, from_ascii("<br/>"),
379                                                     from_ascii("\n"));
380                         break;
381
382                 case LT_RIGHTDELIM:
383                         lex >> rightdelim_;
384                         rightdelim_ = support::subst(rightdelim_, from_ascii("<br/>"),
385                                                      from_ascii("\n"));
386                         break;
387
388                 case LT_INNERTAG:
389                         lex >> innertag_;
390                         break;
391
392                 case LT_LABELTAG:
393                         lex >> labeltag_;
394                         break;
395
396                 case LT_ITEMTAG:
397                         lex >> itemtag_;
398                         break;
399
400                 case LT_ITEMCOMMAND:
401                         lex >> itemcommand_;
402                         break;
403
404                 case LT_PREAMBLE:
405                         preamble_ = from_utf8(lex.getLongString("EndPreamble"));
406                         break;
407
408                 case LT_LANGPREAMBLE:
409                         langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble"));
410                         break;
411
412                 case LT_BABELPREAMBLE:
413                         babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble"));
414                         break;
415
416                 case LT_LABELTYPE:
417                         readLabelType(lex);
418                         break;
419
420                 case LT_ENDLABELTYPE:
421                         readEndLabelType(lex);
422                         break;
423
424                 case LT_LEFTMARGIN:
425                         lex >> leftmargin;
426                         break;
427
428                 case LT_RIGHTMARGIN:
429                         lex >> rightmargin;
430                         break;
431
432                 case LT_LABELINDENT:
433                         lex >> labelindent;
434                         break;
435
436                 case LT_PARINDENT:
437                         lex >> parindent;
438                         break;
439
440                 case LT_PARSKIP:
441                         lex >> parskip;
442                         break;
443
444                 case LT_ITEMSEP:
445                         lex >> itemsep;
446                         break;
447
448                 case LT_TOPSEP:
449                         lex >> topsep;
450                         break;
451
452                 case LT_BOTTOMSEP:
453                         lex >> bottomsep;
454                         break;
455
456                 case LT_LABEL_BOTTOMSEP:
457                         lex >> labelbottomsep;
458                         break;
459
460                 case LT_LABELSEP:
461                         lex >> labelsep;
462                         labelsep = subst(labelsep, 'x', ' ');
463                         break;
464
465                 case LT_PARSEP:
466                         lex >> parsep;
467                         break;
468
469                 case LT_NEWLINE:
470                         lex >> newline_allowed;
471                         break;
472
473                 case LT_ALIGN:
474                         readAlign(lex);
475                         break;
476         
477                 case LT_ALIGNPOSSIBLE:
478                         readAlignPossible(lex);
479                         break;
480
481                 case LT_LABELSTRING:
482                         // FIXME: this means LT_ENDLABELSTRING may only
483                         // occur after LT_LABELSTRING
484                         lex >> labelstring_;
485                         labelstring_ = trim(labelstring_);
486                         labelstring_appendix_ = labelstring_;
487                         break;
488
489                 case LT_ENDLABELSTRING:
490                         lex >> endlabelstring_; 
491                         endlabelstring_ = trim(endlabelstring_);
492                         break;
493
494                 case LT_LABELSTRING_APPENDIX:
495                         lex >> labelstring_appendix_;   
496                         labelstring_appendix_ = trim(labelstring_appendix_);
497                         break;
498
499                 case LT_LABELCOUNTER:
500                         lex >> counter; 
501                         counter = trim(counter);
502                         break;
503
504                 case LT_FREE_SPACING:
505                         lex >> free_spacing;
506                         break;
507
508                 case LT_PASS_THRU:
509                         lex >> pass_thru;
510                         break;
511
512                 case LT_PARBREAK_IS_NEWLINE:
513                         lex >> parbreak_is_newline;
514                         break;
515
516                 case LT_SPACING:
517                         readSpacing(lex);
518                         break;
519
520                 case LT_REQUIRES: {
521                         lex.eatLine();
522                         vector<string> const req = 
523                                 getVectorFromString(lex.getString());
524                         requires_.insert(req.begin(), req.end());
525                         break;
526                 }
527                         
528                 case LT_REFPREFIX: {
529                         docstring arg;
530                         lex >> arg;
531                         if (arg == "OFF")
532                                 refprefix.clear();
533                         else
534                                 refprefix = arg;
535                         break;
536                 }
537
538                 case LT_HTMLTAG:
539                         lex >> htmltag_;
540                         break;
541         
542                 case LT_HTMLATTR:
543                         lex >> htmlattr_;
544                         break;
545
546                 case LT_HTMLITEM:
547                         lex >> htmlitemtag_;
548                         break;
549         
550                 case LT_HTMLITEMATTR:
551                         lex >> htmlitemattr_;
552                         break;
553         
554                 case LT_HTMLLABEL:
555                         lex >> htmllabeltag_;
556                         break;
557
558                 case LT_HTMLLABELATTR: 
559                         lex >> htmllabelattr_;
560                         break;
561
562                 case LT_HTMLLABELFIRST:
563                         lex >> htmllabelfirst_;
564                         break;
565                         
566                 case LT_HTMLSTYLE:
567                         htmlstyle_ = from_utf8(lex.getLongString("EndHTMLStyle"));
568                         break;
569
570                 case LT_HTMLFORCECSS:
571                         lex >> htmlforcecss_;
572                         break;
573
574                 case LT_HTMLPREAMBLE:
575                         htmlpreamble_ = from_utf8(lex.getLongString("EndPreamble"));
576                         break;
577                 
578                 case LT_HTMLTITLE:
579                         lex >> htmltitle_;
580                         break;
581
582                 case LT_SPELLCHECK:
583                         lex >> spellcheck;
584                         break;
585                 }
586         }
587         lex.popTable();
588         // make sure we only have inpreamble = true for commands
589         if (inpreamble && latextype != LATEX_COMMAND && latextype != LATEX_PARAGRAPH) {
590                 LYXERR0("InPreamble not permitted except with command and paragraph layouts.");
591                 LYXERR0("Layout name: " << name());
592                 inpreamble = false;
593         }
594
595         return finished && !error;
596 }
597
598
599 enum {
600         AT_BLOCK = 1,
601         AT_LEFT,
602         AT_RIGHT,
603         AT_CENTER,
604         AT_LAYOUT
605 };
606
607
608 LexerKeyword alignTags[] = {
609         { "block",  AT_BLOCK },
610         { "center", AT_CENTER },
611         { "layout", AT_LAYOUT },
612         { "left",   AT_LEFT },
613         { "right",  AT_RIGHT }
614 };
615
616
617 void Layout::readAlign(Lexer & lex)
618 {
619         PushPopHelper pph(lex, alignTags);
620         int le = lex.lex();
621         switch (le) {
622         case Lexer::LEX_UNDEF:
623                 lex.printError("Unknown alignment `$$Token'");
624                 return;
625         default: break;
626         };
627         switch (le) {
628         case AT_BLOCK:
629                 align = LYX_ALIGN_BLOCK;
630                 break;
631         case AT_LEFT:
632                 align = LYX_ALIGN_LEFT;
633                 break;
634         case AT_RIGHT:
635                 align = LYX_ALIGN_RIGHT;
636                 break;
637         case AT_CENTER:
638                 align = LYX_ALIGN_CENTER;
639                 break;
640         case AT_LAYOUT:
641                 align = LYX_ALIGN_LAYOUT;
642                 break;
643         }
644 }
645
646
647 void Layout::readAlignPossible(Lexer & lex)
648 {
649         lex.pushTable(alignTags);
650         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
651         int lineno = lex.lineNumber();
652         do {
653                 int le = lex.lex();
654                 switch (le) {
655                 case Lexer::LEX_UNDEF:
656                         lex.printError("Unknown alignment `$$Token'");
657                         continue;
658                 default: break;
659                 };
660                 switch (le) {
661                 case AT_BLOCK:
662                         alignpossible |= LYX_ALIGN_BLOCK;
663                         break;
664                 case AT_LEFT:
665                         alignpossible |= LYX_ALIGN_LEFT;
666                         break;
667                 case AT_RIGHT:
668                         alignpossible |= LYX_ALIGN_RIGHT;
669                         break;
670                 case AT_CENTER:
671                         alignpossible |= LYX_ALIGN_CENTER;
672                         break;
673                 case AT_LAYOUT:
674                         alignpossible |= LYX_ALIGN_LAYOUT;
675                         break;
676                 }
677         } while (lineno == lex.lineNumber());
678         lex.popTable();
679 }
680
681
682 void Layout::readLabelType(Lexer & lex)
683 {
684         enum {
685                 LA_NO_LABEL = 1,
686                 LA_MANUAL,
687                 LA_TOP_ENVIRONMENT,
688                 LA_CENTERED_TOP_ENVIRONMENT,
689                 LA_STATIC,
690                 LA_SENSITIVE,
691                 LA_COUNTER,
692                 LA_ENUMERATE,
693                 LA_ITEMIZE,
694                 LA_BIBLIO
695         };
696
697
698         LexerKeyword labelTypeTags[] = {
699                 { "bibliography",             LA_BIBLIO },
700                 { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT },
701                 { "counter",                  LA_COUNTER },
702                 { "enumerate",                LA_ENUMERATE },
703                 { "itemize",                  LA_ITEMIZE },
704                 { "manual",                   LA_MANUAL },
705                 { "no_label",                 LA_NO_LABEL },
706                 { "sensitive",                LA_SENSITIVE },
707                 { "static",                   LA_STATIC },
708                 { "top_environment",          LA_TOP_ENVIRONMENT }
709         };
710
711         PushPopHelper pph(lex, labelTypeTags);
712         int le = lex.lex();
713         switch (le) {
714         case Lexer::LEX_UNDEF:
715                 lex.printError("Unknown labeltype tag `$$Token'");
716                 return;
717         default: break;
718         }
719         switch (le) {
720         case LA_NO_LABEL:
721                 labeltype = LABEL_NO_LABEL;
722                 break;
723         case LA_MANUAL:
724                 labeltype = LABEL_MANUAL;
725                 break;
726         case LA_TOP_ENVIRONMENT:
727                 labeltype = LABEL_TOP_ENVIRONMENT;
728                 break;
729         case LA_CENTERED_TOP_ENVIRONMENT:
730                 labeltype = LABEL_CENTERED_TOP_ENVIRONMENT;
731                 break;
732         case LA_STATIC:
733                 labeltype = LABEL_STATIC;
734                 break;
735         case LA_SENSITIVE:
736                 labeltype = LABEL_SENSITIVE;
737                 break;
738         case LA_COUNTER:
739                 labeltype = LABEL_COUNTER;
740                 break;
741         case LA_ENUMERATE:
742                 labeltype = LABEL_ENUMERATE;
743                 break;
744         case LA_ITEMIZE:
745                 labeltype = LABEL_ITEMIZE;
746                 break;
747         case LA_BIBLIO:
748                 labeltype = LABEL_BIBLIO;
749                 break;
750         }
751 }
752
753
754 void Layout::readEndLabelType(Lexer & lex)
755 {
756         static LexerKeyword endlabelTypeTags[] = {
757                 { "box",              END_LABEL_BOX },
758                 { "filled_box", END_LABEL_FILLED_BOX },
759                 { "no_label",     END_LABEL_NO_LABEL },
760                 { "static",     END_LABEL_STATIC }
761         };
762
763         PushPopHelper pph(lex, endlabelTypeTags);
764         int le = lex.lex();
765         switch (le) {
766         case Lexer::LEX_UNDEF:
767                 lex.printError("Unknown labeltype tag `$$Token'");
768                 break;
769         case END_LABEL_STATIC:
770         case END_LABEL_BOX:
771         case END_LABEL_FILLED_BOX:
772         case END_LABEL_NO_LABEL:
773                 endlabeltype = static_cast<EndLabelType>(le);
774                 break;
775         default:
776                 LYXERR0("Unhandled value " << le);
777                 break;
778         }
779 }
780
781
782 void Layout::readMargin(Lexer & lex)
783 {
784         LexerKeyword marginTags[] = {
785                 { "dynamic",           MARGIN_DYNAMIC },
786                 { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
787                 { "manual",            MARGIN_MANUAL },
788                 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
789                 { "static",            MARGIN_STATIC }
790         };
791
792         PushPopHelper pph(lex, marginTags);
793
794         int le = lex.lex();
795         switch (le) {
796         case Lexer::LEX_UNDEF:
797                 lex.printError("Unknown margin type tag `$$Token'");
798                 return;
799         case MARGIN_STATIC:
800         case MARGIN_MANUAL:
801         case MARGIN_DYNAMIC:
802         case MARGIN_FIRST_DYNAMIC:
803         case MARGIN_RIGHT_ADDRESS_BOX:
804                 margintype = static_cast<MarginType>(le);
805                 break;
806         default:
807                 LYXERR0("Unhandled value " << le);
808                 break;
809         }
810 }
811
812
813 void Layout::readLatexType(Lexer & lex)
814 {
815         LexerKeyword latexTypeTags[] = {
816                 { "bib_environment",  LATEX_BIB_ENVIRONMENT },
817                 { "command",          LATEX_COMMAND },
818                 { "environment",      LATEX_ENVIRONMENT },
819                 { "item_environment", LATEX_ITEM_ENVIRONMENT },
820                 { "list_environment", LATEX_LIST_ENVIRONMENT },
821                 { "paragraph",        LATEX_PARAGRAPH }
822         };
823
824         PushPopHelper pph(lex, latexTypeTags);
825         int le = lex.lex();
826         switch (le) {
827         case Lexer::LEX_UNDEF:
828                 lex.printError("Unknown latextype tag `$$Token'");
829                 return;
830         case LATEX_PARAGRAPH:
831         case LATEX_COMMAND:
832         case LATEX_ENVIRONMENT:
833         case LATEX_ITEM_ENVIRONMENT:
834         case LATEX_BIB_ENVIRONMENT:
835         case LATEX_LIST_ENVIRONMENT:
836                 latextype = static_cast<LatexType>(le);
837                 break;
838         default:
839                 LYXERR0("Unhandled value " << le);
840                 break;
841         }
842 }
843
844
845 void Layout::readSpacing(Lexer & lex)
846 {
847         enum {
848                 ST_SPACING_SINGLE = 1,
849                 ST_SPACING_ONEHALF,
850                 ST_SPACING_DOUBLE,
851                 ST_OTHER
852         };
853
854         LexerKeyword spacingTags[] = {
855                 {"double",  ST_SPACING_DOUBLE },
856                 {"onehalf", ST_SPACING_ONEHALF },
857                 {"other",   ST_OTHER },
858                 {"single",  ST_SPACING_SINGLE }
859         };
860
861         PushPopHelper pph(lex, spacingTags);
862         int le = lex.lex();
863         switch (le) {
864         case Lexer::LEX_UNDEF:
865                 lex.printError("Unknown spacing token `$$Token'");
866                 return;
867         default: break;
868         }
869         switch (le) {
870         case ST_SPACING_SINGLE:
871                 spacing.set(Spacing::Single);
872                 break;
873         case ST_SPACING_ONEHALF:
874                 spacing.set(Spacing::Onehalf);
875                 break;
876         case ST_SPACING_DOUBLE:
877                 spacing.set(Spacing::Double);
878                 break;
879         case ST_OTHER:
880                 lex.next();
881                 spacing.set(Spacing::Other, lex.getString());
882                 break;
883         }
884 }
885
886
887 void Layout::readArgument(Lexer & lex)
888 {
889         latexarg arg;
890         arg.mandatory = false;
891         arg.autoinsert = false;
892         bool error = false;
893         bool finished = false;
894         arg.font = inherit_font;
895         arg.labelfont = inherit_font;
896         string id;
897         lex >> id;
898         bool const itemarg = prefixIs(id, "item:");
899         bool const postcmd = prefixIs(id, "post:");
900
901         while (!finished && lex.isOK() && !error) {
902                 lex.next();
903                 string const tok = ascii_lowercase(lex.getString());
904
905                 if (tok.empty()) {
906                         continue;
907                 } else if (tok == "endargument") {
908                         finished = true;
909                 } else if (tok == "labelstring") {
910                         lex.next();
911                         arg.labelstring = lex.getDocString();
912                 } else if (tok == "menustring") {
913                         lex.next();
914                         arg.menustring = lex.getDocString();
915                 } else if (tok == "mandatory") {
916                         lex.next();
917                         arg.mandatory = lex.getBool();
918                 } else if (tok == "autoinsert") {
919                         lex.next();
920                         arg.autoinsert = lex.getBool();
921                 } else if (tok == "leftdelim") {
922                         lex.next();
923                         arg.ldelim = lex.getDocString();
924                         arg.ldelim = support::subst(arg.ldelim, from_ascii("<br/>"),
925                                                     from_ascii("\n"));
926                 } else if (tok == "rightdelim") {
927                         lex.next();
928                         arg.rdelim = lex.getDocString();
929                         arg.rdelim = support::subst(arg.rdelim, from_ascii("<br/>"),
930                                                     from_ascii("\n"));
931                 } else if (tok == "presetarg") {
932                         lex.next();
933                         arg.presetarg = lex.getDocString();
934                 } else if (tok == "tooltip") {
935                         lex.next();
936                         arg.tooltip = lex.getDocString();
937                 } else if (tok == "requires") {
938                         lex.next();
939                         arg.requires = lex.getString();
940                 } else if (tok == "decoration") {
941                         lex.next();
942                         arg.decoration = lex.getString();
943                 } else if (tok == "font") {
944                         arg.font = lyxRead(lex, arg.font);
945                 } else if (tok == "labelfont") {
946                         arg.labelfont = lyxRead(lex, arg.labelfont);
947                 } else {
948                         lex.printError("Unknown tag");
949                         error = true;
950                 }
951         }
952         if (arg.labelstring.empty())
953                 LYXERR0("Incomplete Argument definition!");
954         else if (itemarg)
955                 itemargs_[id] = arg;
956         else if (postcmd)
957                 postcommandargs_[id] = arg;
958         else
959                 latexargs_[id] = arg;
960 }
961
962
963 Layout::LaTeXArgMap Layout::args() const
964 {
965         LaTeXArgMap args = latexargs_;
966         if (!postcommandargs_.empty())
967                 args.insert(postcommandargs_.begin(), postcommandargs_.end());
968         if (!itemargs_.empty())
969                 args.insert(itemargs_.begin(), itemargs_.end());
970         return args;
971 }
972
973
974 int Layout::optArgs() const
975 {
976         int nr = 0;
977         LaTeXArgMap::const_iterator it = latexargs_.begin();
978         for (; it != latexargs_.end(); ++it) {
979                 if (!(*it).second.mandatory)
980                         ++nr;
981         }
982         LaTeXArgMap::const_iterator iit = postcommandargs_.begin();
983         for (; iit != postcommandargs_.end(); ++iit) {
984                 if (!(*iit).second.mandatory)
985                         ++nr;
986         }
987         return nr;
988 }
989
990
991 int Layout::requiredArgs() const
992 {
993         int nr = 0;
994         LaTeXArgMap::const_iterator it = latexargs_.begin();
995         for (; it != latexargs_.end(); ++it) {
996                 if ((*it).second.mandatory)
997                         ++nr;
998         }
999         LaTeXArgMap::const_iterator iit = postcommandargs_.begin();
1000         for (; iit != postcommandargs_.end(); ++iit) {
1001                 if (!(*iit).second.mandatory)
1002                         ++nr;
1003         }
1004         return nr;
1005 }
1006
1007
1008 string const & Layout::htmltag() const 
1009
1010         if (htmltag_.empty())
1011                 htmltag_ =  "div";
1012         return htmltag_;
1013 }
1014
1015
1016 string const & Layout::htmlattr() const 
1017
1018         if (htmlattr_.empty())
1019                 htmlattr_ = "class=\"" + defaultCSSClass() + "\"";
1020         return htmlattr_; 
1021 }
1022
1023
1024 string const & Layout::htmlitemtag() const 
1025
1026         if (htmlitemtag_.empty())
1027                 htmlitemtag_ = "div";
1028         return htmlitemtag_; 
1029 }
1030
1031
1032 string const & Layout::htmlitemattr() const 
1033
1034         if (htmlitemattr_.empty())
1035                 htmlitemattr_ = "class=\"" + defaultCSSItemClass() + "\"";
1036         return htmlitemattr_; 
1037 }
1038
1039
1040 string const & Layout::htmllabeltag() const 
1041
1042         if (htmllabeltag_.empty()) {
1043                 if (labeltype != LABEL_TOP_ENVIRONMENT &&
1044                     labeltype != LABEL_CENTERED_TOP_ENVIRONMENT)
1045                         htmllabeltag_ = "span";
1046                 else
1047                         htmllabeltag_ = "div";
1048         }
1049         return htmllabeltag_; 
1050 }
1051
1052
1053 string const & Layout::htmllabelattr() const 
1054
1055         if (htmllabelattr_.empty())
1056                 htmllabelattr_ = "class=\"" + defaultCSSLabelClass() + "\"";
1057         return htmllabelattr_; 
1058 }
1059
1060
1061 docstring Layout::htmlstyle() const
1062 {
1063         if (!htmlstyle_.empty() && !htmlforcecss_)
1064                 return htmlstyle_;
1065         if (htmldefaultstyle_.empty()) 
1066                 makeDefaultCSS();
1067         docstring retval = htmldefaultstyle_;
1068         if (!htmlstyle_.empty())
1069                 retval += '\n' + htmlstyle_;
1070         return retval;
1071 }
1072
1073
1074 string Layout::defaultCSSClass() const
1075
1076         if (!defaultcssclass_.empty())
1077                 return defaultcssclass_;
1078         docstring d;
1079         docstring::const_iterator it = name().begin();
1080         docstring::const_iterator en = name().end();
1081         for (; it != en; ++it) {
1082                 char_type const c = *it;
1083                 if (!isAlphaASCII(c)) {
1084                         if (d.empty())
1085                                 // make sure we don't start with an underscore,
1086                                 // as that sometimes causes problems.
1087                                 d = from_ascii("lyx_");
1088                         else
1089                                 d += '_';
1090                 } else if (isLower(c))
1091                         d += c;
1092                 else
1093                         // this is slow, so do it only if necessary
1094                         d += lowercase(c);
1095         }
1096         defaultcssclass_ = to_utf8(d);
1097         return defaultcssclass_;
1098 }
1099
1100
1101 namespace {
1102
1103 string makeMarginValue(char const * side, double d)
1104 {
1105         ostringstream os;
1106         os << "margin-" << side << ": " << d << "ex;\n";
1107         return os.str();
1108 }
1109
1110 }
1111
1112
1113 void Layout::makeDefaultCSS() const
1114 {
1115         // this never needs to be redone, since reloading layouts will
1116         // wipe out what we did before.
1117         if (!htmldefaultstyle_.empty()) 
1118                 return;
1119         
1120         // main font
1121         htmldefaultstyle_ = font.asCSS();
1122         
1123         // bottom margins
1124         string tmp;
1125         if (topsep > 0)
1126                 tmp += makeMarginValue("top", topsep);
1127         if (bottomsep > 0)
1128                 tmp += makeMarginValue("bottom", bottomsep);
1129         if (!leftmargin.empty()) {
1130                 // we can't really do what LyX does with the margin, so 
1131                 // we'll just figure out how many characters it is
1132                 int const len = leftmargin.length();
1133                 tmp += makeMarginValue("left", len);
1134         }
1135         if (!rightmargin.empty()) {
1136                 int const len = rightmargin.length();
1137                 tmp += makeMarginValue("right", len);
1138         }
1139                 
1140         if (!tmp.empty()) {
1141                 if (!htmldefaultstyle_.empty())
1142                         htmldefaultstyle_ += from_ascii("\n");
1143                 htmldefaultstyle_ += from_ascii(tmp);
1144         }
1145
1146 // tex2lyx does not see output_xhtml.cpp
1147 #ifndef TEX2LYX
1148         // alignment
1149         string where = alignmentToCSS(align);
1150         if (!where.empty()) {
1151                 htmldefaultstyle_ += from_ascii("text-align: " + where + ";\n");
1152         }
1153 #endif
1154         
1155         // wrap up what we have, if anything
1156         if (!htmldefaultstyle_.empty())
1157                 htmldefaultstyle_ = 
1158                         from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") +
1159                         htmldefaultstyle_ + from_ascii("\n}\n");
1160         
1161         if (labeltype == LABEL_NO_LABEL || htmllabeltag() == "NONE")
1162                 return;
1163         
1164         docstring labelCSS;
1165         
1166         // label font
1167         if (labelfont != font)
1168                 labelCSS = labelfont.asCSS() + from_ascii("\n");
1169         if (labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1170                 labelCSS += from_ascii("text-align: center;\n");
1171         
1172         if (!labelCSS.empty())
1173                 htmldefaultstyle_ +=
1174                         from_ascii(htmllabeltag() + "." + defaultCSSLabelClass() + " {\n") +
1175                         labelCSS + from_ascii("\n}\n");
1176 }
1177
1178
1179 bool Layout::operator==(Layout const & rhs) const
1180 {
1181         // This is enough for the applications we actually make,
1182         // at least at the moment. But we could check more.
1183         return name() == rhs.name()
1184                 && latexname() == rhs.latexname()
1185                 && latextype == rhs.latextype;
1186 }
1187
1188
1189 } // namespace lyx