]> git.lyx.org Git - lyx.git/blob - src/Layout.cpp
Workaround for #6865: smarter FontList::setMisspelled implementation
[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 "Language.h"
17 #include "TextClass.h"
18 #include "Lexer.h"
19 #include "FontInfo.h"
20
21 #include "support/Messages.h"
22 #include "support/debug.h"
23 #include "support/lassert.h"
24 #include "support/lstrings.h"
25
26 #include "support/regex.h"
27
28 using namespace std;
29 using namespace lyx::support;
30
31 namespace lyx {
32
33 /// Special value of toclevel for layouts that to not belong in a TOC
34 const int Layout::NOT_IN_TOC = -1000;
35
36 //  The order of the LayoutTags enum is no more important. [asierra300396]
37 // Tags indexes.
38 enum LayoutTags {
39         LT_ALIGN = 1,
40         LT_ALIGNPOSSIBLE,
41         LT_MARGIN,
42         LT_BOTTOMSEP,
43         LT_CATEGORY,
44         LT_COMMANDDEPTH,
45         LT_COPYSTYLE,
46         LT_DEPENDSON,
47         LT_OBSOLETEDBY,
48         //LT_EMPTY,
49         LT_END,
50         //LT_ENVIRONMENT_DEFAULT,
51         //LT_FANCYHDR,
52         LT_FILL_BOTTOM,
53         LT_FILL_TOP,
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         fill_top = false;
143         fill_bottom = false;
144         newline_allowed = true;
145         free_spacing = false;
146         pass_thru = false;
147         parbreak_is_newline = false;
148         toclevel = NOT_IN_TOC;
149         commanddepth = 0;
150         htmllabelfirst_ = false;
151         htmlforcecss_ = false;
152         htmltitle_ = false;
153         spellcheck = true;
154         optargs = 0;
155         reqargs = 0;
156 }
157
158
159 bool Layout::read(Lexer & lex, TextClass const & tclass)
160 {
161         // This table is sorted alphabetically [asierra 30March96]
162         LexerKeyword layoutTags[] = {
163                 { "align",          LT_ALIGN },
164                 { "alignpossible",  LT_ALIGNPOSSIBLE },
165                 { "babelpreamble",  LT_BABELPREAMBLE },
166                 { "bottomsep",      LT_BOTTOMSEP },
167                 { "category",       LT_CATEGORY },
168                 { "commanddepth",   LT_COMMANDDEPTH },
169                 { "copystyle",      LT_COPYSTYLE },
170                 { "dependson",      LT_DEPENDSON },
171                 { "end",            LT_END },
172                 { "endlabelstring", LT_ENDLABELSTRING },
173                 { "endlabeltype",   LT_ENDLABELTYPE },
174                 { "fill_bottom",    LT_FILL_BOTTOM },
175                 { "fill_top",       LT_FILL_TOP },
176                 { "font",           LT_FONT },
177                 { "freespacing",    LT_FREE_SPACING },
178                 { "htmlattr",       LT_HTMLATTR },
179                 { "htmlforcecss",   LT_HTMLFORCECSS },
180                 { "htmlitem",       LT_HTMLITEM },
181                 { "htmlitemattr",   LT_HTMLITEMATTR },
182                 { "htmllabel",      LT_HTMLLABEL },
183                 { "htmllabelattr",  LT_HTMLLABELATTR },
184                 { "htmllabelfirst", LT_HTMLLABELFIRST },
185                 { "htmlpremable",   LT_HTMLPREAMBLE },
186                 { "htmlstyle",      LT_HTMLSTYLE },
187                 { "htmltag",        LT_HTMLTAG },
188                 { "htmltitle",      LT_HTMLTITLE },
189                 { "innertag",       LT_INNERTAG },
190                 { "inpreamble",     LT_INPREAMBLE },
191                 { "intitle",        LT_INTITLE },
192                 { "itemsep",        LT_ITEMSEP },
193                 { "itemtag",        LT_ITEMTAG },
194                 { "keepempty",      LT_KEEPEMPTY },
195                 { "labelbottomsep", LT_LABEL_BOTTOMSEP },
196                 { "labelcounter",   LT_LABELCOUNTER },
197                 { "labelfont",      LT_LABELFONT },
198                 { "labelindent",    LT_LABELINDENT },
199                 { "labelsep",       LT_LABELSEP },
200                 { "labelstring",    LT_LABELSTRING },
201                 { "labelstringappendix", LT_LABELSTRING_APPENDIX },
202                 { "labeltag",       LT_LABELTAG },
203                 { "labeltype",      LT_LABELTYPE },
204                 { "langpreamble",   LT_LANGPREAMBLE },
205                 { "latexname",      LT_LATEXNAME },
206                 { "latexparam",     LT_LATEXPARAM },
207                 { "latextype",      LT_LATEXTYPE },
208                 { "leftmargin",     LT_LEFTMARGIN },
209                 { "margin",         LT_MARGIN },
210                 { "needprotect",    LT_NEED_PROTECT },
211                 { "newline",        LT_NEWLINE },
212                 { "nextnoindent",   LT_NEXTNOINDENT },
213                 { "obsoletedby",    LT_OBSOLETEDBY },
214                 { "optionalargs",   LT_OPTARGS },
215                 { "parbreakisnewline", LT_PARBREAK_IS_NEWLINE },
216                 { "parindent",      LT_PARINDENT },
217                 { "parsep",         LT_PARSEP },
218                 { "parskip",        LT_PARSKIP },
219                 { "passthru",       LT_PASS_THRU },
220                 { "preamble",       LT_PREAMBLE },
221                 { "refprefix",      LT_REFPREFIX },
222                 { "requiredargs",   LT_REQARGS },
223                 { "requires",       LT_REQUIRES },
224                 { "rightmargin",    LT_RIGHTMARGIN },
225                 { "spacing",        LT_SPACING },
226                 { "spellcheck",     LT_SPELLCHECK },
227                 { "textfont",       LT_TEXTFONT },
228                 { "toclevel",       LT_TOCLEVEL },
229                 { "topsep",         LT_TOPSEP }
230         };
231
232         bool error = false;
233         bool finished = false;
234         lex.pushTable(layoutTags);
235         // parse style section
236         while (!finished && lex.isOK() && !error) {
237                 int le = lex.lex();
238                 // See comment in LyXRC.cpp.
239                 switch (le) {
240                 case Lexer::LEX_FEOF:
241                         continue;
242
243                 case Lexer::LEX_UNDEF:          // parse error
244                         lex.printError("Unknown layout tag `$$Token'");
245                         error = true;
246                         continue;
247
248                 default: 
249                         break;
250                 }
251                 switch (static_cast<LayoutTags>(le)) {
252                 case LT_END:            // end of structure
253                         finished = true;
254                         break;
255
256                 case LT_CATEGORY:
257                         lex >> category_;
258                         break;
259
260                 case LT_COPYSTYLE: {     // initialize with a known style
261                         docstring style;
262                         lex >> style;
263                         style = subst(style, '_', ' ');
264
265                         if (tclass.hasLayout(style)) {
266                                 docstring const tmpname = name_;
267                                 this->operator=(tclass[style]);
268                                 name_ = tmpname;
269                         } else {
270                                 LYXERR0("Cannot copy unknown style `"
271                                         << style << "'\n"
272                                         << "All layouts so far:");
273                                 DocumentClass::const_iterator lit = tclass.begin();
274                                 DocumentClass::const_iterator len = tclass.end();
275                                 for (; lit != len; ++lit)
276                                         LYXERR0(lit->name());
277                         }
278                         break;
279                         }
280
281                 case LT_OBSOLETEDBY: {   // replace with a known style
282                         docstring style;
283                         lex >> style;
284                         style = subst(style, '_', ' ');
285
286                         if (tclass.hasLayout(style)) {
287                                 docstring const tmpname = name_;
288                                 this->operator=(tclass[style]);
289                                 name_ = tmpname;
290                                 if (obsoleted_by().empty())
291                                         obsoleted_by_ = style;
292                         } else {
293                                 LYXERR0("Cannot replace with unknown style `" 
294                                         << style << '\'');
295
296                                 //lex.printError("Cannot replace with"
297                                 //               " unknown style "
298                                 //               "`$$Token'");
299                         }
300                         break;
301                 }
302
303                 case LT_DEPENDSON:
304                         lex >> depends_on_;
305                         depends_on_ = subst(depends_on_, '_', ' ');
306                         break;
307
308                 case LT_MARGIN:         // margin style definition.
309                         readMargin(lex);
310                         break;
311
312                 case LT_LATEXTYPE:      // LaTeX style definition.
313                         readLatexType(lex);
314                         break;
315
316                 case LT_INTITLE:
317                         lex >> intitle;
318                         break;
319
320                 case LT_INPREAMBLE:
321                         lex >> inpreamble;
322                         break;
323
324                 case LT_TOCLEVEL:
325                         lex >> toclevel;
326                         break;
327
328                 case LT_OPTARGS:
329                         lex >> optargs;
330                         break;
331
332                 case LT_REQARGS:
333                         lex >> reqargs;
334                         break;
335
336                 case LT_NEED_PROTECT:
337                         lex >> needprotect;
338                         break;
339
340                 case LT_KEEPEMPTY:
341                         lex >> keepempty;
342                         break;
343
344                 case LT_FONT:
345                         font = lyxRead(lex, font);
346                         labelfont = font;
347                         break;
348
349                 case LT_TEXTFONT:
350                         font = lyxRead(lex, font);
351                         break;
352
353                 case LT_LABELFONT:
354                         labelfont = lyxRead(lex, labelfont);
355                         break;
356
357                 case LT_NEXTNOINDENT:   // Indent next paragraph?
358                         lex >> nextnoindent;
359                         break;
360
361                 case LT_COMMANDDEPTH:
362                         lex >> commanddepth;
363                         break;
364
365                 case LT_LATEXNAME:
366                         lex >> latexname_;
367                         break;
368
369                 case LT_LATEXPARAM:
370                         lex >> latexparam_;
371                         latexparam_ = subst(latexparam_, "&quot;", "\"");
372                         break;
373
374                 case LT_INNERTAG:
375                         lex >> innertag_;
376                         break;
377
378                 case LT_LABELTAG:
379                         lex >> labeltag_;
380                         break;
381
382                 case LT_ITEMTAG:
383                         lex >> itemtag_;
384                         break;
385
386                 case LT_PREAMBLE:
387                         preamble_ = from_utf8(lex.getLongString("EndPreamble"));
388                         break;
389
390                 case LT_LANGPREAMBLE:
391                         langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble"));
392                         break;
393
394                 case LT_BABELPREAMBLE:
395                         babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble"));
396                         break;
397
398                 case LT_LABELTYPE:
399                         readLabelType(lex);
400                         break;
401
402                 case LT_ENDLABELTYPE:
403                         readEndLabelType(lex);
404                         break;
405
406                 case LT_LEFTMARGIN:     // left margin type
407                         lex >> leftmargin;
408                         break;
409
410                 case LT_RIGHTMARGIN:    // right margin type
411                         lex >> rightmargin;
412                         break;
413
414                 case LT_LABELINDENT:    // label indenting flag
415                         lex >> labelindent;
416                         break;
417
418                 case LT_PARINDENT:      // paragraph indent. flag
419                         lex >> parindent;
420                         break;
421
422                 case LT_PARSKIP:        // paragraph skip size
423                         lex >> parskip;
424                         break;
425
426                 case LT_ITEMSEP:        // item separation size
427                         lex >> itemsep;
428                         break;
429
430                 case LT_TOPSEP:         // top separation size
431                         lex >> topsep;
432                         break;
433
434                 case LT_BOTTOMSEP:      // bottom separation size
435                         lex >> bottomsep;
436                         break;
437
438                 case LT_LABEL_BOTTOMSEP: // label bottom separation size
439                         lex >> labelbottomsep;
440                         break;
441
442                 case LT_LABELSEP:       // label separator
443                         lex >> labelsep;
444                         labelsep = subst(labelsep, 'x', ' ');
445                         break;
446
447                 case LT_PARSEP:         // par. separation size
448                         lex >> parsep;
449                         break;
450
451                 case LT_FILL_TOP:       // fill top flag
452                         lex >> fill_top;
453                         break;
454
455                 case LT_FILL_BOTTOM:    // fill bottom flag
456                         lex >> fill_bottom;
457                         break;
458
459                 case LT_NEWLINE:        // newlines allowed?
460                         lex >> newline_allowed;
461                         break;
462
463                 case LT_ALIGN:          // paragraph align
464                         readAlign(lex);
465                         break;
466                 case LT_ALIGNPOSSIBLE:  // paragraph allowed align
467                         readAlignPossible(lex);
468                         break;
469
470                 case LT_LABELSTRING:    // label string definition
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: // endlabel string definition
479                         lex >> endlabelstring_; 
480                         endlabelstring_ = trim(endlabelstring_);
481                         break;
482
483                 case LT_LABELSTRING_APPENDIX: // label string appendix definition
484                         lex >> labelstring_appendix_;   
485                         labelstring_appendix_ = trim(labelstring_appendix_);
486                         break;
487
488                 case LT_LABELCOUNTER: // name of counter to use
489                         lex >> counter; 
490                         counter = trim(counter);
491                         break;
492
493                 case LT_FREE_SPACING:   // Allow for free spacing.
494                         lex >> free_spacing;
495                         break;
496
497                 case LT_PASS_THRU:      // Allow for 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: // setspace.sty
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
562                 case LT_HTMLPREAMBLE:
563                         htmlpreamble_ = from_utf8(lex.getLongString("EndPreamble"));
564                         break;
565                 
566                 case LT_HTMLTITLE:
567                         lex >> htmltitle_;
568                         break;
569
570                 case LT_SPELLCHECK:
571                         lex >> spellcheck;
572                         break;
573                 }
574         }
575         lex.popTable();
576         // make sure we only have inpreamble = true for commands
577         if (inpreamble && latextype != LATEX_COMMAND) {
578                 LYXERR0("InPreamble not permitted except with Command-type layouts.");
579                 LYXERR0("Layout name: " << name());
580                 inpreamble = false;
581         }
582
583         return finished && !error;
584 }
585
586
587 enum {
588         AT_BLOCK = 1,
589         AT_LEFT,
590         AT_RIGHT,
591         AT_CENTER,
592         AT_LAYOUT
593 };
594
595
596 LexerKeyword alignTags[] = {
597         { "block",  AT_BLOCK },
598         { "center", AT_CENTER },
599         { "layout", AT_LAYOUT },
600         { "left",   AT_LEFT },
601         { "right",  AT_RIGHT }
602 };
603
604
605 void Layout::readAlign(Lexer & lex)
606 {
607         PushPopHelper pph(lex, alignTags);
608         int le = lex.lex();
609         switch (le) {
610         case Lexer::LEX_UNDEF:
611                 lex.printError("Unknown alignment `$$Token'");
612                 return;
613         default: break;
614         };
615         switch (le) {
616         case AT_BLOCK:
617                 align = LYX_ALIGN_BLOCK;
618                 break;
619         case AT_LEFT:
620                 align = LYX_ALIGN_LEFT;
621                 break;
622         case AT_RIGHT:
623                 align = LYX_ALIGN_RIGHT;
624                 break;
625         case AT_CENTER:
626                 align = LYX_ALIGN_CENTER;
627                 break;
628         case AT_LAYOUT:
629                 align = LYX_ALIGN_LAYOUT;
630                 break;
631         }
632 }
633
634
635 void Layout::readAlignPossible(Lexer & lex)
636 {
637         lex.pushTable(alignTags);
638         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
639         int lineno = lex.lineNumber();
640         do {
641                 int le = lex.lex();
642                 switch (le) {
643                 case Lexer::LEX_UNDEF:
644                         lex.printError("Unknown alignment `$$Token'");
645                         continue;
646                 default: break;
647                 };
648                 switch (le) {
649                 case AT_BLOCK:
650                         alignpossible |= LYX_ALIGN_BLOCK;
651                         break;
652                 case AT_LEFT:
653                         alignpossible |= LYX_ALIGN_LEFT;
654                         break;
655                 case AT_RIGHT:
656                         alignpossible |= LYX_ALIGN_RIGHT;
657                         break;
658                 case AT_CENTER:
659                         alignpossible |= LYX_ALIGN_CENTER;
660                         break;
661                 case AT_LAYOUT:
662                         alignpossible |= LYX_ALIGN_LAYOUT;
663                         break;
664                 }
665         } while (lineno == lex.lineNumber());
666         lex.popTable();
667 }
668
669
670 void Layout::readLabelType(Lexer & lex)
671 {
672         enum {
673                 LA_NO_LABEL = 1,
674                 LA_MANUAL,
675                 LA_TOP_ENVIRONMENT,
676                 LA_CENTERED_TOP_ENVIRONMENT,
677                 LA_STATIC,
678                 LA_SENSITIVE,
679                 LA_COUNTER,
680                 LA_ENUMERATE,
681                 LA_ITEMIZE,
682                 LA_BIBLIO
683         };
684
685
686         LexerKeyword labelTypeTags[] = {
687                 { "bibliography",             LA_BIBLIO },
688                 { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT },
689                 { "counter",                  LA_COUNTER },
690                 { "enumerate",                LA_ENUMERATE },
691                 { "itemize",                  LA_ITEMIZE },
692                 { "manual",                   LA_MANUAL },
693                 { "no_label",                 LA_NO_LABEL },
694                 { "sensitive",                LA_SENSITIVE },
695                 { "static",                   LA_STATIC },
696                 { "top_environment",          LA_TOP_ENVIRONMENT }
697         };
698
699         PushPopHelper pph(lex, labelTypeTags);
700         int le = lex.lex();
701         switch (le) {
702         case Lexer::LEX_UNDEF:
703                 lex.printError("Unknown labeltype tag `$$Token'");
704                 return;
705         default: break;
706         }
707         switch (le) {
708         case LA_NO_LABEL:
709                 labeltype = LABEL_NO_LABEL;
710                 break;
711         case LA_MANUAL:
712                 labeltype = LABEL_MANUAL;
713                 break;
714         case LA_TOP_ENVIRONMENT:
715                 labeltype = LABEL_TOP_ENVIRONMENT;
716                 break;
717         case LA_CENTERED_TOP_ENVIRONMENT:
718                 labeltype = LABEL_CENTERED_TOP_ENVIRONMENT;
719                 break;
720         case LA_STATIC:
721                 labeltype = LABEL_STATIC;
722                 break;
723         case LA_SENSITIVE:
724                 labeltype = LABEL_SENSITIVE;
725                 break;
726         case LA_COUNTER:
727                 labeltype = LABEL_COUNTER;
728                 break;
729         case LA_ENUMERATE:
730                 labeltype = LABEL_ENUMERATE;
731                 break;
732         case LA_ITEMIZE:
733                 labeltype = LABEL_ITEMIZE;
734                 break;
735         case LA_BIBLIO:
736                 labeltype = LABEL_BIBLIO;
737                 break;
738         }
739 }
740
741
742 void Layout::readEndLabelType(Lexer & lex)
743 {
744         static LexerKeyword endlabelTypeTags[] = {
745                 { "box",              END_LABEL_BOX },
746                 { "filled_box", END_LABEL_FILLED_BOX },
747                 { "no_label",     END_LABEL_NO_LABEL },
748                 { "static",     END_LABEL_STATIC }
749         };
750
751         PushPopHelper pph(lex, endlabelTypeTags);
752         int le = lex.lex();
753         switch (le) {
754         case Lexer::LEX_UNDEF:
755                 lex.printError("Unknown labeltype tag `$$Token'");
756                 break;
757         case END_LABEL_STATIC:
758         case END_LABEL_BOX:
759         case END_LABEL_FILLED_BOX:
760         case END_LABEL_NO_LABEL:
761                 endlabeltype = static_cast<EndLabelType>(le);
762                 break;
763         default:
764                 LYXERR0("Unhandled value " << le);
765                 break;
766         }
767 }
768
769
770 void Layout::readMargin(Lexer & lex)
771 {
772         LexerKeyword marginTags[] = {
773                 { "dynamic",           MARGIN_DYNAMIC },
774                 { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
775                 { "manual",            MARGIN_MANUAL },
776                 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
777                 { "static",            MARGIN_STATIC }
778         };
779
780         PushPopHelper pph(lex, marginTags);
781
782         int le = lex.lex();
783         switch (le) {
784         case Lexer::LEX_UNDEF:
785                 lex.printError("Unknown margin type tag `$$Token'");
786                 return;
787         case MARGIN_STATIC:
788         case MARGIN_MANUAL:
789         case MARGIN_DYNAMIC:
790         case MARGIN_FIRST_DYNAMIC:
791         case MARGIN_RIGHT_ADDRESS_BOX:
792                 margintype = static_cast<MarginType>(le);
793                 break;
794         default:
795                 LYXERR0("Unhandled value " << le);
796                 break;
797         }
798 }
799
800
801 void Layout::readLatexType(Lexer & lex)
802 {
803         LexerKeyword latexTypeTags[] = {
804                 { "bib_environment",  LATEX_BIB_ENVIRONMENT },
805                 { "command",          LATEX_COMMAND },
806                 { "environment",      LATEX_ENVIRONMENT },
807                 { "item_environment", LATEX_ITEM_ENVIRONMENT },
808                 { "list_environment", LATEX_LIST_ENVIRONMENT },
809                 { "paragraph",        LATEX_PARAGRAPH }
810         };
811
812         PushPopHelper pph(lex, latexTypeTags);
813         int le = lex.lex();
814         switch (le) {
815         case Lexer::LEX_UNDEF:
816                 lex.printError("Unknown latextype tag `$$Token'");
817                 return;
818         case LATEX_PARAGRAPH:
819         case LATEX_COMMAND:
820         case LATEX_ENVIRONMENT:
821         case LATEX_ITEM_ENVIRONMENT:
822         case LATEX_BIB_ENVIRONMENT:
823         case LATEX_LIST_ENVIRONMENT:
824                 latextype = static_cast<LatexType>(le);
825                 break;
826         default:
827                 LYXERR0("Unhandled value " << le);
828                 break;
829         }
830 }
831
832
833 void Layout::readSpacing(Lexer & lex)
834 {
835         enum {
836                 ST_SPACING_SINGLE = 1,
837                 ST_SPACING_ONEHALF,
838                 ST_SPACING_DOUBLE,
839                 ST_OTHER
840         };
841
842         LexerKeyword spacingTags[] = {
843                 {"double",  ST_SPACING_DOUBLE },
844                 {"onehalf", ST_SPACING_ONEHALF },
845                 {"other",   ST_OTHER },
846                 {"single",  ST_SPACING_SINGLE }
847         };
848
849         PushPopHelper pph(lex, spacingTags);
850         int le = lex.lex();
851         switch (le) {
852         case Lexer::LEX_UNDEF:
853                 lex.printError("Unknown spacing token `$$Token'");
854                 return;
855         default: break;
856         }
857         switch (le) {
858         case ST_SPACING_SINGLE:
859                 spacing.set(Spacing::Single);
860                 break;
861         case ST_SPACING_ONEHALF:
862                 spacing.set(Spacing::Onehalf);
863                 break;
864         case ST_SPACING_DOUBLE:
865                 spacing.set(Spacing::Double);
866                 break;
867         case ST_OTHER:
868                 lex.next();
869                 spacing.set(Spacing::Other, lex.getString());
870                 break;
871         }
872 }
873
874
875 namespace {
876
877 docstring const i18npreamble(Language const * lang, docstring const & templ)
878 {
879         if (templ.empty())
880                 return templ;
881
882         string preamble = subst(to_utf8(templ), "$$lang", lang->babel());
883
884 #ifdef TEX2LYX
885         // tex2lyx does not have getMessages()
886         LASSERT(false, /**/);
887 #else
888         // FIXME UNICODE
889         // lyx::regex is not unicode-safe.
890         // Should use QRegExp or (boost::u32regex, but that requires ICU)
891         static regex const reg("_\\(([^\\)]+)\\)");
892         smatch sub;
893         while (regex_search(preamble, sub, reg)) {
894                 string const key = sub.str(1);
895                 string translated;
896                 if (isAscii(key))
897                         translated = to_utf8(getMessages(lang->code()).get(key));
898                 else {
899                         lyxerr << "Warning: not translating `" << key
900                                << "' because it is not pure ASCII." << endl;
901                         translated = key;
902                 }
903                 preamble = subst(preamble, sub.str(), translated);
904         }
905 #endif
906         return from_utf8(preamble);
907 }
908
909 }
910
911
912 docstring const Layout::langpreamble(Language const * lang) const
913 {
914         return i18npreamble(lang, langpreamble_);
915 }
916
917
918 docstring const Layout::babelpreamble(Language const * lang) const
919 {
920         return i18npreamble(lang, babelpreamble_);
921 }
922
923
924 string const & Layout::htmltag() const 
925
926         if (htmltag_.empty())
927                 htmltag_ =  "div";
928         return htmltag_;
929 }
930
931
932 string const & Layout::htmlattr() const 
933
934         if (htmlattr_.empty())
935                 htmlattr_ = "class=\"" + defaultCSSClass() + "\"";
936         return htmlattr_; 
937 }
938
939
940 string const & Layout::htmlitemtag() const 
941
942         if (htmlitemtag_.empty())
943                 htmlitemtag_ = "div";
944         return htmlitemtag_; 
945 }
946
947
948 string const & Layout::htmlitemattr() const 
949
950         if (htmlitemattr_.empty())
951                 htmlitemattr_ = "class=\"" + defaultCSSItemClass() + "\"";
952         return htmlitemattr_; 
953 }
954
955
956 string const & Layout::htmllabeltag() const 
957
958         if (htmllabeltag_.empty())
959                 htmllabeltag_ = "span";
960         return htmllabeltag_; 
961 }
962
963
964 string const & Layout::htmllabelattr() const 
965
966         if (htmllabelattr_.empty())
967                 htmllabelattr_ = "class=\"" + defaultCSSLabelClass() + "\"";
968         return htmllabelattr_; 
969 }
970
971
972 docstring Layout::htmlstyle() const {
973         if (!htmlstyle_.empty() && !htmlforcecss_)
974                 return htmlstyle_;
975         if (htmldefaultstyle_.empty()) 
976                 makeDefaultCSS();
977         docstring retval = htmldefaultstyle_;
978         if (!htmlstyle_.empty())
979                 retval += '\n' + htmlstyle_;
980         return retval;
981 }
982
983
984 string Layout::defaultCSSClass() const
985
986         if (!defaultcssclass_.empty())
987                 return defaultcssclass_;
988         docstring d;
989         docstring::const_iterator it = name().begin();
990         docstring::const_iterator en = name().end();
991         for (; it != en; ++it) {
992                 if (!isalpha(*it))
993                         continue;
994                 if (islower(*it))
995                         d += *it;
996                 else 
997                         d += lowercase(*it);
998         }
999         // are there other characters we need to remove?
1000         defaultcssclass_ = to_utf8(d);
1001         return defaultcssclass_;
1002 }
1003
1004
1005 // NOTE There is a whole ton of stuff that could go into this.
1006 // Things like bottomsep, topsep, and parsep could become various
1007 // sorts of margins or padding, for example. But for now we are
1008 // going to keep it simple.
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         docstring const mainfontCSS = font.asCSS();
1015         if (!mainfontCSS.empty())
1016                 htmldefaultstyle_ = 
1017                         from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") +
1018                         mainfontCSS + from_ascii("\n}\n");
1019         if (labelfont == font || htmllabeltag() == "NONE")
1020                 return;
1021         docstring const labelfontCSS = labelfont.asCSS();
1022         if (!labelfontCSS.empty())
1023                 htmldefaultstyle_ +=
1024                         from_ascii(htmllabeltag() + "." + defaultCSSLabelClass() + " {\n") +
1025                         labelfontCSS + from_ascii("\n}\n");
1026 }
1027
1028
1029 bool Layout::operator==(Layout const & rhs) const
1030 {
1031         // This is enough for the applications we actually make,
1032         // at least at the moment. But we could check more.
1033         return name() == rhs.name()
1034                 && latexname() == rhs.latexname()
1035                 && latextype == rhs.latextype;
1036 }
1037
1038
1039 } // namespace lyx