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