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