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