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