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