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