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