]> git.lyx.org Git - lyx.git/blob - src/Layout.cpp
Add test for Layout::write()
[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/textutils.h"
27
28
29 using namespace std;
30 using namespace lyx::support;
31
32 namespace lyx {
33
34 /// Special value of toclevel for layouts that to not belong in a TOC
35 const int Layout::NOT_IN_TOC = -1000;
36
37 //  The order of the LayoutTags enum is no more important. [asierra300396]
38 // Tags indexes.
39 enum LayoutTags {
40         LT_ALIGN = 1,
41         LT_ALIGNPOSSIBLE,
42         LT_ARGUMENT,
43         LT_MARGIN,
44         LT_BOTTOMSEP,
45         LT_CATEGORY,
46         LT_COMMANDDEPTH,
47         LT_COPYSTYLE,
48         LT_DEPENDSON,
49         LT_OBSOLETEDBY,
50         LT_END,
51         LT_FONT,
52         LT_FREE_SPACING,
53         LT_PASS_THRU,
54         LT_PARBREAK_IS_NEWLINE,
55         LT_ITEMCOMMAND,
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_LATEXTYPE,
72         LT_LEFTDELIM,
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_RESETARGS,
106         LT_RIGHTDELIM,
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         needprotect = false;
120         keepempty = false;
121         font = inherit_font;
122         labelfont = inherit_font;
123         resfont = sane_font;
124         reslabelfont = sane_font;
125         nextnoindent = false;
126         parskip = 0.0;
127         itemsep = 0;
128         topsep = 0.0;
129         bottomsep = 0.0;
130         labelbottomsep = 0.0;
131         parsep = 0;
132         align = LYX_ALIGN_BLOCK;
133         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
134         labeltype = LABEL_NO_LABEL;
135         endlabeltype = END_LABEL_NO_LABEL;
136         // Should or should not. That is the question.
137         // spacing.set(Spacing::OneHalf);
138         newline_allowed = true;
139         free_spacing = false;
140         pass_thru = false;
141         parbreak_is_newline = false;
142         toclevel = NOT_IN_TOC;
143         commanddepth = 0;
144         htmllabelfirst_ = false;
145         htmlforcecss_ = false;
146         htmltitle_ = false;
147         spellcheck = true;
148         itemcommand_ = "item";
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                 { "argument",       LT_ARGUMENT },
159                 { "babelpreamble",  LT_BABELPREAMBLE },
160                 { "bottomsep",      LT_BOTTOMSEP },
161                 { "category",       LT_CATEGORY },
162                 { "commanddepth",   LT_COMMANDDEPTH },
163                 { "copystyle",      LT_COPYSTYLE },
164                 { "dependson",      LT_DEPENDSON },
165                 { "end",            LT_END },
166                 { "endlabelstring", LT_ENDLABELSTRING },
167                 { "endlabeltype",   LT_ENDLABELTYPE },
168                 { "font",           LT_FONT },
169                 { "freespacing",    LT_FREE_SPACING },
170                 { "htmlattr",       LT_HTMLATTR },
171                 { "htmlforcecss",   LT_HTMLFORCECSS },
172                 { "htmlitem",       LT_HTMLITEM },
173                 { "htmlitemattr",   LT_HTMLITEMATTR },
174                 { "htmllabel",      LT_HTMLLABEL },
175                 { "htmllabelattr",  LT_HTMLLABELATTR },
176                 { "htmllabelfirst", LT_HTMLLABELFIRST },
177                 { "htmlpreamble",   LT_HTMLPREAMBLE },
178                 { "htmlstyle",      LT_HTMLSTYLE },
179                 { "htmltag",        LT_HTMLTAG },
180                 { "htmltitle",      LT_HTMLTITLE },
181                 { "innertag",       LT_INNERTAG },
182                 { "inpreamble",     LT_INPREAMBLE },
183                 { "intitle",        LT_INTITLE },
184                 { "itemcommand",    LT_ITEMCOMMAND },
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                 { "leftdelim",      LT_LEFTDELIM },
202                 { "leftmargin",     LT_LEFTMARGIN },
203                 { "margin",         LT_MARGIN },
204                 { "needprotect",    LT_NEED_PROTECT },
205                 { "newline",        LT_NEWLINE },
206                 { "nextnoindent",   LT_NEXTNOINDENT },
207                 { "obsoletedby",    LT_OBSOLETEDBY },
208                 { "parbreakisnewline", LT_PARBREAK_IS_NEWLINE },
209                 { "parindent",      LT_PARINDENT },
210                 { "parsep",         LT_PARSEP },
211                 { "parskip",        LT_PARSKIP },
212                 { "passthru",       LT_PASS_THRU },
213                 { "preamble",       LT_PREAMBLE },
214                 { "refprefix",      LT_REFPREFIX },
215                 { "requires",       LT_REQUIRES },
216                 { "resetargs",      LT_RESETARGS },
217                 { "rightdelim",     LT_RIGHTDELIM },
218                 { "rightmargin",    LT_RIGHTMARGIN },
219                 { "spacing",        LT_SPACING },
220                 { "spellcheck",     LT_SPELLCHECK },
221                 { "textfont",       LT_TEXTFONT },
222                 { "toclevel",       LT_TOCLEVEL },
223                 { "topsep",         LT_TOPSEP }
224         };
225
226         bool error = false;
227         bool finished = false;
228         lex.pushTable(layoutTags);
229
230         // parse style section
231         while (!finished && lex.isOK() && !error) {
232                 int le = lex.lex();
233                 // See comment in LyXRC.cpp.
234                 switch (le) {
235                 case Lexer::LEX_FEOF:
236                         continue;
237
238                 case Lexer::LEX_UNDEF:
239                         // parse error
240                         lex.printError("Unknown layout tag `$$Token'");
241                         error = true;
242                         continue;
243
244                 default: 
245                         break;
246                 }
247                 switch (static_cast<LayoutTags>(le)) {
248                 case LT_END:
249                         finished = true;
250                         break;
251
252                 case LT_CATEGORY:
253                         lex >> category_;
254                         break;
255
256                 case LT_COPYSTYLE: {
257                         docstring style;
258                         lex >> style;
259                         style = subst(style, '_', ' ');
260
261                         if (tclass.hasLayout(style)) {
262                                 docstring const tmpname = name_;
263                                 this->operator=(tclass[style]);
264                                 name_ = tmpname;
265                         } else {
266                                 LYXERR0("Cannot copy unknown style `"
267                                         << style << "'\n"
268                                         << "All layouts so far:");
269                                 DocumentClass::const_iterator lit = tclass.begin();
270                                 DocumentClass::const_iterator len = tclass.end();
271                                 for (; lit != len; ++lit)
272                                         LYXERR0(lit->name());
273                         }
274                         break;
275                         }
276
277                 case LT_OBSOLETEDBY: {
278                         docstring style;
279                         lex >> style;
280                         style = subst(style, '_', ' ');
281
282                         if (tclass.hasLayout(style)) {
283                                 docstring const tmpname = name_;
284                                 this->operator=(tclass[style]);
285                                 name_ = tmpname;
286                                 if (obsoleted_by().empty())
287                                         obsoleted_by_ = style;
288                         } else {
289                                 LYXERR0("Cannot replace with unknown style `" 
290                                         << style << '\'');
291
292                                 //lex.printError("Cannot replace with"
293                                 //               " unknown style "
294                                 //               "`$$Token'");
295                         }
296                         break;
297                 }
298
299                 case LT_DEPENDSON:
300                         lex >> depends_on_;
301                         depends_on_ = subst(depends_on_, '_', ' ');
302                         break;
303
304                 case LT_MARGIN:
305                         readMargin(lex);
306                         break;
307
308                 case LT_LATEXTYPE:
309                         readLatexType(lex);
310                         break;
311
312                 case LT_INTITLE:
313                         lex >> intitle;
314                         break;
315
316                 case LT_INPREAMBLE:
317                         lex >> inpreamble;
318                         break;
319
320                 case LT_TOCLEVEL:
321                         lex >> toclevel;
322                         break;
323
324                 case LT_RESETARGS:
325                         bool reset;
326                         lex >> reset;
327                         if (reset) {
328                                 latexargs_.clear();
329                                 itemargs_.clear();
330                                 postcommandargs_.clear();
331                         }
332                         break;
333
334                 case LT_ARGUMENT:
335                         readArgument(lex);
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:
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_LEFTDELIM:
377                         lex >> leftdelim_;
378                         leftdelim_ = support::subst(leftdelim_, from_ascii("<br/>"),
379                                                     from_ascii("\n"));
380                         break;
381
382                 case LT_RIGHTDELIM:
383                         lex >> rightdelim_;
384                         rightdelim_ = support::subst(rightdelim_, from_ascii("<br/>"),
385                                                      from_ascii("\n"));
386                         break;
387
388                 case LT_INNERTAG:
389                         lex >> innertag_;
390                         break;
391
392                 case LT_LABELTAG:
393                         lex >> labeltag_;
394                         break;
395
396                 case LT_ITEMTAG:
397                         lex >> itemtag_;
398                         break;
399
400                 case LT_ITEMCOMMAND:
401                         lex >> itemcommand_;
402                         break;
403
404                 case LT_PREAMBLE:
405                         preamble_ = from_utf8(lex.getLongString("EndPreamble"));
406                         break;
407
408                 case LT_LANGPREAMBLE:
409                         langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble"));
410                         break;
411
412                 case LT_BABELPREAMBLE:
413                         babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble"));
414                         break;
415
416                 case LT_LABELTYPE:
417                         readLabelType(lex);
418                         break;
419
420                 case LT_ENDLABELTYPE:
421                         readEndLabelType(lex);
422                         break;
423
424                 case LT_LEFTMARGIN:
425                         lex >> leftmargin;
426                         break;
427
428                 case LT_RIGHTMARGIN:
429                         lex >> rightmargin;
430                         break;
431
432                 case LT_LABELINDENT:
433                         lex >> labelindent;
434                         break;
435
436                 case LT_PARINDENT:
437                         lex >> parindent;
438                         break;
439
440                 case LT_PARSKIP:
441                         lex >> parskip;
442                         break;
443
444                 case LT_ITEMSEP:
445                         lex >> itemsep;
446                         break;
447
448                 case LT_TOPSEP:
449                         lex >> topsep;
450                         break;
451
452                 case LT_BOTTOMSEP:
453                         lex >> bottomsep;
454                         break;
455
456                 case LT_LABEL_BOTTOMSEP:
457                         lex >> labelbottomsep;
458                         break;
459
460                 case LT_LABELSEP:
461                         lex >> labelsep;
462                         labelsep = subst(labelsep, 'x', ' ');
463                         break;
464
465                 case LT_PARSEP:
466                         lex >> parsep;
467                         break;
468
469                 case LT_NEWLINE:
470                         lex >> newline_allowed;
471                         break;
472
473                 case LT_ALIGN:
474                         readAlign(lex);
475                         break;
476         
477                 case LT_ALIGNPOSSIBLE:
478                         readAlignPossible(lex);
479                         break;
480
481                 case LT_LABELSTRING:
482                         // FIXME: this means LT_LABELSTRING_APPENDIX may only
483                         // occur after LT_LABELSTRING
484                         lex >> labelstring_;
485                         labelstring_ = trim(labelstring_);
486                         labelstring_appendix_ = labelstring_;
487                         break;
488
489                 case LT_ENDLABELSTRING:
490                         lex >> endlabelstring_; 
491                         endlabelstring_ = trim(endlabelstring_);
492                         break;
493
494                 case LT_LABELSTRING_APPENDIX:
495                         lex >> labelstring_appendix_;   
496                         labelstring_appendix_ = trim(labelstring_appendix_);
497                         break;
498
499                 case LT_LABELCOUNTER:
500                         lex >> counter; 
501                         counter = trim(counter);
502                         break;
503
504                 case LT_FREE_SPACING:
505                         lex >> free_spacing;
506                         break;
507
508                 case LT_PASS_THRU:
509                         lex >> pass_thru;
510                         break;
511
512                 case LT_PARBREAK_IS_NEWLINE:
513                         lex >> parbreak_is_newline;
514                         break;
515
516                 case LT_SPACING:
517                         readSpacing(lex);
518                         break;
519
520                 case LT_REQUIRES: {
521                         lex.eatLine();
522                         vector<string> const req = 
523                                 getVectorFromString(lex.getString());
524                         requires_.insert(req.begin(), req.end());
525                         break;
526                 }
527                         
528                 case LT_REFPREFIX: {
529                         docstring arg;
530                         lex >> arg;
531                         if (arg == "OFF")
532                                 refprefix.clear();
533                         else
534                                 refprefix = arg;
535                         break;
536                 }
537
538                 case LT_HTMLTAG:
539                         lex >> htmltag_;
540                         break;
541         
542                 case LT_HTMLATTR:
543                         lex >> htmlattr_;
544                         break;
545
546                 case LT_HTMLITEM:
547                         lex >> htmlitemtag_;
548                         break;
549         
550                 case LT_HTMLITEMATTR:
551                         lex >> htmlitemattr_;
552                         break;
553         
554                 case LT_HTMLLABEL:
555                         lex >> htmllabeltag_;
556                         break;
557
558                 case LT_HTMLLABELATTR: 
559                         lex >> htmllabelattr_;
560                         break;
561
562                 case LT_HTMLLABELFIRST:
563                         lex >> htmllabelfirst_;
564                         break;
565                         
566                 case LT_HTMLSTYLE:
567                         htmlstyle_ = from_utf8(lex.getLongString("EndHTMLStyle"));
568                         break;
569
570                 case LT_HTMLFORCECSS:
571                         lex >> htmlforcecss_;
572                         break;
573
574                 case LT_HTMLPREAMBLE:
575                         htmlpreamble_ = from_utf8(lex.getLongString("EndPreamble"));
576                         break;
577                 
578                 case LT_HTMLTITLE:
579                         lex >> htmltitle_;
580                         break;
581
582                 case LT_SPELLCHECK:
583                         lex >> spellcheck;
584                         break;
585                 }
586         }
587         lex.popTable();
588         // make sure we only have inpreamble = true for commands
589         if (inpreamble && latextype != LATEX_COMMAND && latextype != LATEX_PARAGRAPH) {
590                 LYXERR0("InPreamble not permitted except with command and paragraph layouts.");
591                 LYXERR0("Layout name: " << name());
592                 inpreamble = false;
593         }
594
595         return finished && !error;
596 }
597
598
599 enum {
600         AT_BLOCK = 1,
601         AT_LEFT,
602         AT_RIGHT,
603         AT_CENTER,
604         AT_LAYOUT
605 };
606
607
608 LexerKeyword alignTags[] = {
609         { "block",  AT_BLOCK },
610         { "center", AT_CENTER },
611         { "layout", AT_LAYOUT },
612         { "left",   AT_LEFT },
613         { "right",  AT_RIGHT }
614 };
615
616
617 void Layout::readAlign(Lexer & lex)
618 {
619         PushPopHelper pph(lex, alignTags);
620         int le = lex.lex();
621         switch (le) {
622         case Lexer::LEX_UNDEF:
623                 lex.printError("Unknown alignment `$$Token'");
624                 return;
625         default: break;
626         };
627         switch (le) {
628         case AT_BLOCK:
629                 align = LYX_ALIGN_BLOCK;
630                 break;
631         case AT_LEFT:
632                 align = LYX_ALIGN_LEFT;
633                 break;
634         case AT_RIGHT:
635                 align = LYX_ALIGN_RIGHT;
636                 break;
637         case AT_CENTER:
638                 align = LYX_ALIGN_CENTER;
639                 break;
640         case AT_LAYOUT:
641                 align = LYX_ALIGN_LAYOUT;
642                 break;
643         }
644 }
645
646
647 void Layout::readAlignPossible(Lexer & lex)
648 {
649         lex.pushTable(alignTags);
650         alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
651         int lineno = lex.lineNumber();
652         do {
653                 int le = lex.lex();
654                 switch (le) {
655                 case Lexer::LEX_UNDEF:
656                         lex.printError("Unknown alignment `$$Token'");
657                         continue;
658                 default: break;
659                 };
660                 switch (le) {
661                 case AT_BLOCK:
662                         alignpossible |= LYX_ALIGN_BLOCK;
663                         break;
664                 case AT_LEFT:
665                         alignpossible |= LYX_ALIGN_LEFT;
666                         break;
667                 case AT_RIGHT:
668                         alignpossible |= LYX_ALIGN_RIGHT;
669                         break;
670                 case AT_CENTER:
671                         alignpossible |= LYX_ALIGN_CENTER;
672                         break;
673                 case AT_LAYOUT:
674                         alignpossible |= LYX_ALIGN_LAYOUT;
675                         break;
676                 }
677         } while (lineno == lex.lineNumber());
678         lex.popTable();
679 }
680
681
682 void Layout::readLabelType(Lexer & lex)
683 {
684         enum {
685                 LA_NO_LABEL = 1,
686                 LA_MANUAL,
687                 LA_ABOVE,
688                 LA_CENTERED,
689                 LA_STATIC,
690                 LA_SENSITIVE,
691                 LA_ENUMERATE,
692                 LA_ITEMIZE,
693                 LA_BIBLIO
694         };
695
696
697         LexerKeyword labelTypeTags[] = {
698           { "above",        LA_ABOVE },
699                 { "bibliography", LA_BIBLIO },
700                 { "centered",     LA_CENTERED },
701                 { "enumerate",    LA_ENUMERATE },
702                 { "itemize",      LA_ITEMIZE },
703                 { "manual",       LA_MANUAL },
704                 { "no_label",     LA_NO_LABEL },
705                 { "sensitive",    LA_SENSITIVE },
706                 { "static",       LA_STATIC }
707         };
708
709         PushPopHelper pph(lex, labelTypeTags);
710         int le = lex.lex();
711         switch (le) {
712         case Lexer::LEX_UNDEF:
713                 lex.printError("Unknown labeltype tag `$$Token'");
714                 return;
715         default: break;
716         }
717         switch (le) {
718         case LA_NO_LABEL:
719                 labeltype = LABEL_NO_LABEL;
720                 break;
721         case LA_MANUAL:
722                 labeltype = LABEL_MANUAL;
723                 break;
724         case LA_ABOVE:
725                 labeltype = LABEL_ABOVE;
726                 break;
727         case LA_CENTERED:
728                 labeltype = LABEL_CENTERED;
729                 break;
730         case LA_STATIC:
731                 labeltype = LABEL_STATIC;
732                 break;
733         case LA_SENSITIVE:
734                 labeltype = LABEL_SENSITIVE;
735                 break;
736         case LA_ENUMERATE:
737                 labeltype = LABEL_ENUMERATE;
738                 break;
739         case LA_ITEMIZE:
740                 labeltype = LABEL_ITEMIZE;
741                 break;
742         case LA_BIBLIO:
743                 labeltype = LABEL_BIBLIO;
744                 break;
745         }
746 }
747
748
749 void Layout::readEndLabelType(Lexer & lex)
750 {
751         static LexerKeyword endlabelTypeTags[] = {
752                 { "box",              END_LABEL_BOX },
753                 { "filled_box", END_LABEL_FILLED_BOX },
754                 { "no_label",     END_LABEL_NO_LABEL },
755                 { "static",     END_LABEL_STATIC }
756         };
757
758         PushPopHelper pph(lex, endlabelTypeTags);
759         int le = lex.lex();
760         switch (le) {
761         case Lexer::LEX_UNDEF:
762                 lex.printError("Unknown labeltype tag `$$Token'");
763                 break;
764         case END_LABEL_STATIC:
765         case END_LABEL_BOX:
766         case END_LABEL_FILLED_BOX:
767         case END_LABEL_NO_LABEL:
768                 endlabeltype = static_cast<EndLabelType>(le);
769                 break;
770         default:
771                 LYXERR0("Unhandled value " << le);
772                 break;
773         }
774 }
775
776
777 void Layout::readMargin(Lexer & lex)
778 {
779         LexerKeyword marginTags[] = {
780                 { "dynamic",           MARGIN_DYNAMIC },
781                 { "first_dynamic",     MARGIN_FIRST_DYNAMIC },
782                 { "manual",            MARGIN_MANUAL },
783                 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
784                 { "static",            MARGIN_STATIC }
785         };
786
787         PushPopHelper pph(lex, marginTags);
788
789         int le = lex.lex();
790         switch (le) {
791         case Lexer::LEX_UNDEF:
792                 lex.printError("Unknown margin type tag `$$Token'");
793                 return;
794         case MARGIN_STATIC:
795         case MARGIN_MANUAL:
796         case MARGIN_DYNAMIC:
797         case MARGIN_FIRST_DYNAMIC:
798         case MARGIN_RIGHT_ADDRESS_BOX:
799                 margintype = static_cast<MarginType>(le);
800                 break;
801         default:
802                 LYXERR0("Unhandled value " << le);
803                 break;
804         }
805 }
806
807
808 void Layout::readLatexType(Lexer & lex)
809 {
810         LexerKeyword latexTypeTags[] = {
811                 { "bib_environment",  LATEX_BIB_ENVIRONMENT },
812                 { "command",          LATEX_COMMAND },
813                 { "environment",      LATEX_ENVIRONMENT },
814                 { "item_environment", LATEX_ITEM_ENVIRONMENT },
815                 { "list_environment", LATEX_LIST_ENVIRONMENT },
816                 { "paragraph",        LATEX_PARAGRAPH }
817         };
818
819         PushPopHelper pph(lex, latexTypeTags);
820         int le = lex.lex();
821         switch (le) {
822         case Lexer::LEX_UNDEF:
823                 lex.printError("Unknown latextype tag `$$Token'");
824                 return;
825         case LATEX_PARAGRAPH:
826         case LATEX_COMMAND:
827         case LATEX_ENVIRONMENT:
828         case LATEX_ITEM_ENVIRONMENT:
829         case LATEX_BIB_ENVIRONMENT:
830         case LATEX_LIST_ENVIRONMENT:
831                 latextype = static_cast<LatexType>(le);
832                 break;
833         default:
834                 LYXERR0("Unhandled value " << le);
835                 break;
836         }
837 }
838
839
840 void Layout::readSpacing(Lexer & lex)
841 {
842         enum {
843                 ST_SPACING_SINGLE = 1,
844                 ST_SPACING_ONEHALF,
845                 ST_SPACING_DOUBLE,
846                 ST_OTHER
847         };
848
849         LexerKeyword spacingTags[] = {
850                 {"double",  ST_SPACING_DOUBLE },
851                 {"onehalf", ST_SPACING_ONEHALF },
852                 {"other",   ST_OTHER },
853                 {"single",  ST_SPACING_SINGLE }
854         };
855
856         PushPopHelper pph(lex, spacingTags);
857         int le = lex.lex();
858         switch (le) {
859         case Lexer::LEX_UNDEF:
860                 lex.printError("Unknown spacing token `$$Token'");
861                 return;
862         default: break;
863         }
864         switch (le) {
865         case ST_SPACING_SINGLE:
866                 spacing.set(Spacing::Single);
867                 break;
868         case ST_SPACING_ONEHALF:
869                 spacing.set(Spacing::Onehalf);
870                 break;
871         case ST_SPACING_DOUBLE:
872                 spacing.set(Spacing::Double);
873                 break;
874         case ST_OTHER:
875                 lex.next();
876                 spacing.set(Spacing::Other, lex.getString());
877                 break;
878         }
879 }
880
881
882 void Layout::readArgument(Lexer & lex)
883 {
884         latexarg arg;
885         // writeArgument() makes use of these default values
886         arg.mandatory = false;
887         arg.autoinsert = false;
888         bool error = false;
889         bool finished = false;
890         arg.font = inherit_font;
891         arg.labelfont = inherit_font;
892         string id;
893         lex >> id;
894         bool const itemarg = prefixIs(id, "item:");
895         bool const postcmd = prefixIs(id, "post:");
896
897         while (!finished && lex.isOK() && !error) {
898                 lex.next();
899                 string const tok = ascii_lowercase(lex.getString());
900
901                 if (tok.empty()) {
902                         continue;
903                 } else if (tok == "endargument") {
904                         finished = true;
905                 } else if (tok == "labelstring") {
906                         lex.next();
907                         arg.labelstring = lex.getDocString();
908                 } else if (tok == "menustring") {
909                         lex.next();
910                         arg.menustring = lex.getDocString();
911                 } else if (tok == "mandatory") {
912                         lex.next();
913                         arg.mandatory = lex.getBool();
914                 } else if (tok == "autoinsert") {
915                         lex.next();
916                         arg.autoinsert = lex.getBool();
917                 } else if (tok == "leftdelim") {
918                         lex.next();
919                         arg.ldelim = lex.getDocString();
920                         arg.ldelim = support::subst(arg.ldelim, from_ascii("<br/>"),
921                                                     from_ascii("\n"));
922                 } else if (tok == "rightdelim") {
923                         lex.next();
924                         arg.rdelim = lex.getDocString();
925                         arg.rdelim = support::subst(arg.rdelim, from_ascii("<br/>"),
926                                                     from_ascii("\n"));
927                 } else if (tok == "defaultarg") {
928                         lex.next();
929                         arg.defaultarg = lex.getDocString();
930                 } else if (tok == "presetarg") {
931                         lex.next();
932                         arg.presetarg = lex.getDocString();
933                 } else if (tok == "tooltip") {
934                         lex.next();
935                         arg.tooltip = lex.getDocString();
936                 } else if (tok == "requires") {
937                         lex.next();
938                         arg.requires = lex.getString();
939                 } else if (tok == "decoration") {
940                         lex.next();
941                         arg.decoration = lex.getString();
942                 } else if (tok == "font") {
943                         arg.font = lyxRead(lex, arg.font);
944                 } else if (tok == "labelfont") {
945                         arg.labelfont = lyxRead(lex, arg.labelfont);
946                 } else {
947                         lex.printError("Unknown tag");
948                         error = true;
949                 }
950         }
951         if (arg.labelstring.empty())
952                 LYXERR0("Incomplete Argument definition!");
953         else if (itemarg)
954                 itemargs_[id] = arg;
955         else if (postcmd)
956                 postcommandargs_[id] = arg;
957         else
958                 latexargs_[id] = arg;
959 }
960
961
962 void writeArgument(ostream & os, string const & id, Layout::latexarg const & arg)
963 {
964         os << "\tArgument " << id << '\n';
965         if (!arg.labelstring.empty())
966                 os << "\t\tLabelString \"" << to_utf8(arg.labelstring) << "\"\n";
967         if (!arg.menustring.empty())
968                 os << "\t\tMenuString \"" << to_utf8(arg.menustring) << "\"\n";
969         if (arg.mandatory)
970                 os << "\t\tMandatory " << arg.mandatory << '\n';
971         if (arg.autoinsert)
972                 os << "\t\tAutoinsert " << arg.autoinsert << '\n';
973         if (!arg.ldelim.empty())
974                 os << "\t\tLeftDelim \""
975                    << to_utf8(subst(arg.ldelim, from_ascii("\n"), from_ascii("<br/>")))
976                    << "\"\n";
977         if (!arg.rdelim.empty())
978                 os << "\t\tRightDelim \""
979                    << to_utf8(subst(arg.rdelim, from_ascii("\n"), from_ascii("<br/>")))
980                    << "\"\n";
981         if (!arg.defaultarg.empty())
982                 os << "\t\tDefaultArg \"" << to_utf8(arg.defaultarg) << "\"\n";
983         if (!arg.presetarg.empty())
984                 os << "\t\tPresetArg \"" << to_utf8(arg.presetarg) << "\"\n";
985         if (!arg.tooltip.empty())
986                 os << "\t\tToolTip \"" << to_utf8(arg.tooltip) << "\"\n";
987         if (!arg.requires.empty())
988                 os << "\t\tRequires \"" << arg.requires << "\"\n";
989         if (!arg.decoration.empty())
990                 os << "\t\tDecoration \"" << arg.decoration << "\"\n";
991         if (arg.font != inherit_font)
992                 lyxWrite(os, arg.font, "Font", 2);
993         if (arg.labelfont != inherit_font)
994                 lyxWrite(os, arg.labelfont, "LabelFont", 2);
995         os << "\tEndArgument\n";
996 }
997
998
999 void Layout::write(ostream & os) const
1000 {
1001         os << "Style " << to_utf8(name_) << '\n';
1002         if (!category_.empty() && obsoleted_by_.empty())
1003                 os << "\tCategory \"" << to_utf8(category_) << "\"\n";
1004         // Can't deduce Copystyle here :-(
1005         if (!obsoleted_by_.empty()) {
1006                 os << "\tObsoletedBy \"" << to_utf8(obsoleted_by_)
1007                    << "\"\nEnd\n";
1008                 return;
1009         }
1010         if (!depends_on_.empty())
1011                 os << "\tDependsOn " << to_utf8(depends_on_) << '\n';
1012         switch (margintype) {
1013                 case MARGIN_DYNAMIC:
1014                         os << "\tMargin Dynamic\n";
1015                         break;
1016                 case MARGIN_FIRST_DYNAMIC:
1017                         os << "\tMargin First_Dynamic\n";
1018                         break;
1019                 case MARGIN_MANUAL:
1020                         os << "\tMargin Manual\n";
1021                         break;
1022                 case MARGIN_RIGHT_ADDRESS_BOX:
1023                         os << "\tMargin Right_Address_Box\n";
1024                         break;
1025                 case MARGIN_STATIC:
1026                         os << "\tMargin Static\n";
1027                         break;
1028         }
1029         switch (latextype) {
1030                 case LATEX_BIB_ENVIRONMENT:
1031                         os << "\tLatexType Bib_Environment\n";
1032                         break;
1033                 case LATEX_COMMAND:
1034                         os << "\tLatexType Command\n";
1035                         break;
1036                 case LATEX_ENVIRONMENT:
1037                         os << "\tLatexType Environment\n";
1038                         break;
1039                 case LATEX_ITEM_ENVIRONMENT:
1040                         os << "\tLatexType Item_Environment\n";
1041                         break;
1042                 case LATEX_LIST_ENVIRONMENT:
1043                         os << "\tLatexType List_Environment\n";
1044                         break;
1045                 case LATEX_PARAGRAPH:
1046                         os << "\tLatexType Paragraph\n";
1047                         break;
1048         }
1049         os << "\tInTitle " << intitle << "\n"
1050               "\tInPreamble " << inpreamble << "\n"
1051               "\tTocLevel " << toclevel << '\n';
1052         // ResetArgs does not make sense here
1053         for (LaTeXArgMap::const_iterator it = latexargs_.begin();
1054              it != latexargs_.end(); ++it)
1055                 writeArgument(os, it->first, it->second);
1056         for (LaTeXArgMap::const_iterator it = itemargs_.begin();
1057              it != itemargs_.end(); ++it)
1058                 writeArgument(os, it->first, it->second);
1059         for (LaTeXArgMap::const_iterator it = postcommandargs_.begin();
1060              it != postcommandargs_.end(); ++it)
1061                 writeArgument(os, it->first, it->second);
1062         os << "\tNeedProtect " << needprotect << "\n"
1063               "\tKeepEmpty " << keepempty << '\n';
1064         if (labelfont == font)
1065                 lyxWrite(os, font, "Font", 1);
1066         else {
1067                 lyxWrite(os, font, "TextFont", 1);
1068                 lyxWrite(os, labelfont, "LabelFont", 1);
1069         }
1070         os << "\tNextNoIndent " << nextnoindent << "\n"
1071               "\tCommandDepth " << commanddepth << '\n';
1072         if (!latexname_.empty())
1073                 os << "\tLatexName \"" << latexname_ << "\"\n";
1074         if (!latexparam_.empty())
1075                 os << "\tLatexParam \"" << subst(latexparam_, "\"", "&quot;")
1076                    << "\"\n";
1077         if (!leftdelim_.empty())
1078                 os << "\tLeftDelim "
1079                    << to_utf8(subst(leftdelim_, from_ascii("\n"), from_ascii("<br/>")))
1080                    << '\n';
1081         if (!rightdelim_.empty())
1082                 os << "\tRightDelim "
1083                    << to_utf8(subst(rightdelim_, from_ascii("\n"), from_ascii("<br/>")))
1084                    << '\n';
1085         if (!innertag_.empty())
1086                 os << "\tInnerTag \"" << innertag_ << "\"\n";
1087         if (!labeltag_.empty())
1088                 os << "\tLabelTag \"" << labeltag_ << "\"\n";
1089         if (!itemtag_.empty())
1090                 os << "\tItemTag \"" << itemtag_ << "\"\n";
1091         if (!itemcommand_.empty())
1092                 os << "\tItemCommand " << itemcommand_ << '\n';
1093         if (!preamble_.empty())
1094                 os << "\tPreamble\n\t"
1095                    << to_utf8(subst(rtrim(preamble_, "\n"),
1096                                           from_ascii("\n"), from_ascii("\n\t")))
1097                    << "\n\tEndPreamble\n";
1098         if (!langpreamble_.empty())
1099                 os << "\tLangPreamble\n\t"
1100                    << to_utf8(subst(rtrim(langpreamble_, "\n"),
1101                                           from_ascii("\n"), from_ascii("\n\t")))
1102                    << "\n\tEndLangPreamble\n";
1103         if (!babelpreamble_.empty())
1104                 os << "\tBabelPreamble\n\t"
1105                    << to_utf8(subst(rtrim(babelpreamble_, "\n"),
1106                                           from_ascii("\n"), from_ascii("\n\t")))
1107                    << "\n\tEndBabelPreamble\n";
1108         switch (labeltype) {
1109         case LABEL_ABOVE:
1110                 os << "\tLabelType Above\n";
1111                 break;
1112         case LABEL_BIBLIO:
1113                 os << "\tLabelType Bibliography\n";
1114                 break;
1115         case LABEL_CENTERED:
1116                 os << "\tLabelType Centered\n";
1117                 break;
1118         case LABEL_ENUMERATE:
1119                 os << "\tLabelType Enumerate\n";
1120                 break;
1121         case LABEL_ITEMIZE:
1122                 os << "\tLabelType Itemize\n";
1123                 break;
1124         case LABEL_MANUAL:
1125                 os << "\tLabelType Manual\n";
1126                 break;
1127         case LABEL_NO_LABEL:
1128                 os << "\tLabelType No_Label\n";
1129                 break;
1130         case LABEL_SENSITIVE:
1131                 os << "\tLabelType Sensitive\n";
1132                 break;
1133         case LABEL_STATIC:
1134                 os << "\tLabelType Static\n";
1135                 break;
1136         }
1137         switch (endlabeltype) {
1138         case END_LABEL_BOX:
1139                 os << "\tEndLabelType Box\n";
1140                 break;
1141         case END_LABEL_FILLED_BOX:
1142                 os << "\tEndLabelType Filled_Box\n";
1143                 break;
1144         case END_LABEL_NO_LABEL:
1145                 os << "\tEndLabelType No_Label\n";
1146                 break;
1147         case END_LABEL_STATIC:
1148                 os << "\tEndLabelType Static\n";
1149                 break;
1150         }
1151         if (!leftmargin.empty())
1152                 os << "\tLeftMargin \"" << to_utf8(leftmargin) << "\"\n";
1153         if (!rightmargin.empty())
1154                 os << "\tRightMargin \"" << to_utf8(rightmargin) << "\"\n";
1155         if (!labelindent.empty())
1156                 os << "\tLabelIndent " << to_utf8(labelindent) << '\n';
1157         if (!parindent.empty())
1158                 os << "\tParIndent " << to_utf8(parindent) << '\n';
1159         os << "\tParSkip " << parskip << "\n"
1160               "\tItemSep " << itemsep << "\n"
1161               "\tTopSep " << topsep << "\n"
1162               "\tBottomSep " << bottomsep << "\n"
1163               "\tLabelBottomSep " << labelbottomsep << '\n';
1164         if (!labelsep.empty())
1165                 os << "\tLabelSep " << to_utf8(subst(labelsep, ' ', 'x'))
1166                    << '\n';
1167         os << "\tParSep " << parsep << "\n"
1168               "\tNewLine " << newline_allowed << '\n';
1169         switch (align) {
1170         case LYX_ALIGN_BLOCK:
1171                 os << "\tAlign Block\n";
1172                 break;
1173         case LYX_ALIGN_CENTER:
1174                 os << "\tAlign Center\n";
1175                 break;
1176         case LYX_ALIGN_LAYOUT:
1177                 os << "\tAlign Layout\n";
1178                 break;
1179         case LYX_ALIGN_LEFT:
1180                 os << "\tAlign Left\n";
1181                 break;
1182         case LYX_ALIGN_RIGHT:
1183                 os << "\tAlign Right\n";
1184                 break;
1185         case LYX_ALIGN_DECIMAL:
1186         case LYX_ALIGN_SPECIAL:
1187         case LYX_ALIGN_NONE:
1188                 break;
1189         }
1190         if (alignpossible & (LYX_ALIGN_BLOCK | LYX_ALIGN_CENTER |
1191                              LYX_ALIGN_LAYOUT | LYX_ALIGN_LEFT | LYX_ALIGN_RIGHT)) {
1192                 bool first = true;
1193                 os << "\tAlignPossible";
1194                 if (alignpossible & LYX_ALIGN_BLOCK) {
1195                         if (!first)
1196                                 os << ',';
1197                         os << " Block";
1198                         first = false;
1199                 }
1200                 if (alignpossible & LYX_ALIGN_CENTER) {
1201                         if (!first)
1202                                 os << ',';
1203                         os << " Center";
1204                         first = false;
1205                 }
1206                 if (alignpossible & LYX_ALIGN_LAYOUT) {
1207                         if (!first)
1208                                 os << ',';
1209                         os << " Layout";
1210                         first = false;
1211                 }
1212                 if (alignpossible & LYX_ALIGN_LEFT) {
1213                         if (!first)
1214                                 os << ',';
1215                         os << " Left";
1216                         first = false;
1217                 }
1218                 if (alignpossible & LYX_ALIGN_RIGHT) {
1219                         if (!first)
1220                                 os << ',';
1221                         os << " Right";
1222                         first = false;
1223                 }
1224                 os << '\n';
1225         }
1226         // LabelString must come before LabelStringAppendix
1227         if (!labelstring_.empty())
1228                 os << "\tLabelString \"" << to_utf8(labelstring_) << "\"\n";
1229         if (!endlabelstring_.empty())
1230                 os << "\tEndLabelString \"" << to_utf8(endlabelstring_) << "\"\n";
1231         if (!labelstring_appendix_.empty() && labelstring_appendix_ != labelstring_)
1232                 os << "\tLabelStringAppendix \""
1233                    << to_utf8(labelstring_appendix_) << "\"\n";
1234         if (!counter.empty())
1235                 os << "\tLabelCounter \"" << to_utf8(counter) << "\"\n";
1236         os << "\tFreeSpacing " << free_spacing << '\n';
1237         os << "\tPassThru " << pass_thru << '\n';
1238         os << "\tParbreakIsNewline " << parbreak_is_newline << '\n';
1239         switch (spacing.getSpace()) {
1240         case Spacing::Double:
1241                 os << "\tSpacing Double\n";
1242                 break;
1243         case Spacing::Onehalf:
1244                 os << "\tSpacing Onehalf\n";
1245                 break;
1246         case Spacing::Other:
1247                 os << "\tSpacing Other " << spacing.getValueAsString() << '\n';
1248                 break;
1249         case Spacing::Single:
1250                 os << "\tSpacing Single\n";
1251                 break;
1252         case Spacing::Default:
1253                 break;
1254         }
1255         if (!requires_.empty()) {
1256                 os << "\tRequires ";
1257                 for (set<string>::const_iterator it = requires_.begin();
1258                      it != requires_.end(); ++it) {
1259                         if (it != requires_.begin())
1260                                 os << ',';
1261                         os << *it;
1262                 }
1263                 os << '\n';
1264         }
1265         if (refprefix.empty())
1266                 os << "\tRefPrefix OFF\n";
1267         else
1268                 os << "\tRefPrefix " << to_utf8(refprefix) << '\n';
1269         if (!htmltag_.empty())
1270                 os << "\tHTMLTag " << htmltag_ << '\n';
1271         if (!htmlattr_.empty())
1272                 os << "\tHTMLAttr " << htmlattr_ << '\n';
1273         if (!htmlitemtag_.empty())
1274                 os << "\tHTMLItem " << htmlitemtag_ << '\n';
1275         if (!htmlitemattr_.empty())
1276                 os << "\tHTMLItemAttr " << htmlitemattr_ << '\n';
1277         if (!htmllabeltag_.empty())
1278                 os << "\tHTMLLabel " << htmllabeltag_ << '\n';
1279         if (!htmllabelattr_.empty())
1280                 os << "\tHTMLLabelAttr " << htmllabelattr_ << '\n';
1281         os << "\tHTMLLabelFirst " << htmllabelfirst_ << '\n';
1282         if (!htmlstyle_.empty())
1283                 os << "\tHTMLStyle\n"
1284                    << to_utf8(rtrim(htmlstyle_, "\n"))
1285                    << "\n\tEndHTMLStyle\n";
1286         os << "\tHTMLForceCSS " << htmlforcecss_ << '\n';
1287         if (!htmlpreamble_.empty())
1288                 os << "\tHTMLPreamble\n"
1289                    << to_utf8(rtrim(htmlpreamble_, "\n"))
1290                    << "\n\tEndPreamble\n";
1291         os << "\tHTMLTitle " << htmltitle_ << "\n"
1292               "\tSpellcheck " << spellcheck << "\n"
1293               "End\n";
1294 }
1295
1296
1297 Layout::LaTeXArgMap Layout::args() const
1298 {
1299         LaTeXArgMap args = latexargs_;
1300         if (!postcommandargs_.empty())
1301                 args.insert(postcommandargs_.begin(), postcommandargs_.end());
1302         if (!itemargs_.empty())
1303                 args.insert(itemargs_.begin(), itemargs_.end());
1304         return args;
1305 }
1306
1307
1308 int Layout::optArgs() const
1309 {
1310         int nr = 0;
1311         LaTeXArgMap::const_iterator it = latexargs_.begin();
1312         for (; it != latexargs_.end(); ++it) {
1313                 if (!(*it).second.mandatory)
1314                         ++nr;
1315         }
1316         LaTeXArgMap::const_iterator iit = postcommandargs_.begin();
1317         for (; iit != postcommandargs_.end(); ++iit) {
1318                 if (!(*iit).second.mandatory)
1319                         ++nr;
1320         }
1321         return nr;
1322 }
1323
1324
1325 int Layout::requiredArgs() const
1326 {
1327         int nr = 0;
1328         LaTeXArgMap::const_iterator it = latexargs_.begin();
1329         for (; it != latexargs_.end(); ++it) {
1330                 if ((*it).second.mandatory)
1331                         ++nr;
1332         }
1333         LaTeXArgMap::const_iterator iit = postcommandargs_.begin();
1334         for (; iit != postcommandargs_.end(); ++iit) {
1335                 if (!(*iit).second.mandatory)
1336                         ++nr;
1337         }
1338         return nr;
1339 }
1340
1341
1342 string const & Layout::htmltag() const 
1343
1344         if (htmltag_.empty())
1345                 htmltag_ =  "div";
1346         return htmltag_;
1347 }
1348
1349
1350 string const & Layout::htmlattr() const 
1351
1352         if (htmlattr_.empty())
1353                 htmlattr_ = "class=\"" + defaultCSSClass() + "\"";
1354         return htmlattr_; 
1355 }
1356
1357
1358 string const & Layout::htmlitemtag() const 
1359
1360         if (htmlitemtag_.empty())
1361                 htmlitemtag_ = "div";
1362         return htmlitemtag_; 
1363 }
1364
1365
1366 string const & Layout::htmlitemattr() const 
1367
1368         if (htmlitemattr_.empty())
1369                 htmlitemattr_ = "class=\"" + defaultCSSItemClass() + "\"";
1370         return htmlitemattr_; 
1371 }
1372
1373
1374 string const & Layout::htmllabeltag() const 
1375
1376         if (htmllabeltag_.empty()) {
1377                 if (labeltype != LABEL_ABOVE &&
1378                     labeltype != LABEL_CENTERED)
1379                         htmllabeltag_ = "span";
1380                 else
1381                         htmllabeltag_ = "div";
1382         }
1383         return htmllabeltag_; 
1384 }
1385
1386
1387 string const & Layout::htmllabelattr() const 
1388
1389         if (htmllabelattr_.empty())
1390                 htmllabelattr_ = "class=\"" + defaultCSSLabelClass() + "\"";
1391         return htmllabelattr_; 
1392 }
1393
1394
1395 docstring Layout::htmlstyle() const
1396 {
1397         if (!htmlstyle_.empty() && !htmlforcecss_)
1398                 return htmlstyle_;
1399         if (htmldefaultstyle_.empty()) 
1400                 makeDefaultCSS();
1401         docstring retval = htmldefaultstyle_;
1402         if (!htmlstyle_.empty())
1403                 retval += '\n' + htmlstyle_;
1404         return retval;
1405 }
1406
1407
1408 string Layout::defaultCSSClass() const
1409
1410         if (!defaultcssclass_.empty())
1411                 return defaultcssclass_;
1412         docstring d;
1413         docstring::const_iterator it = name().begin();
1414         docstring::const_iterator en = name().end();
1415         for (; it != en; ++it) {
1416                 char_type const c = *it;
1417                 if (!isAlphaASCII(c)) {
1418                         if (d.empty())
1419                                 // make sure we don't start with an underscore,
1420                                 // as that sometimes causes problems.
1421                                 d = from_ascii("lyx_");
1422                         else
1423                                 d += '_';
1424                 } else if (isLower(c))
1425                         d += c;
1426                 else
1427                         // this is slow, so do it only if necessary
1428                         d += lowercase(c);
1429         }
1430         defaultcssclass_ = to_utf8(d);
1431         return defaultcssclass_;
1432 }
1433
1434
1435 namespace {
1436
1437 string makeMarginValue(char const * side, double d)
1438 {
1439         ostringstream os;
1440         os << "margin-" << side << ": " << d << "ex;\n";
1441         return os.str();
1442 }
1443
1444 }
1445
1446
1447 void Layout::makeDefaultCSS() const
1448 {
1449         // this never needs to be redone, since reloading layouts will
1450         // wipe out what we did before.
1451         if (!htmldefaultstyle_.empty()) 
1452                 return;
1453         
1454         // main font
1455         htmldefaultstyle_ = font.asCSS();
1456         
1457         // bottom margins
1458         string tmp;
1459         if (topsep > 0)
1460                 tmp += makeMarginValue("top", topsep);
1461         if (bottomsep > 0)
1462                 tmp += makeMarginValue("bottom", bottomsep);
1463         if (!leftmargin.empty()) {
1464                 // we can't really do what LyX does with the margin, so 
1465                 // we'll just figure out how many characters it is
1466                 int const len = leftmargin.length();
1467                 tmp += makeMarginValue("left", len);
1468         }
1469         if (!rightmargin.empty()) {
1470                 int const len = rightmargin.length();
1471                 tmp += makeMarginValue("right", len);
1472         }
1473                 
1474         if (!tmp.empty()) {
1475                 if (!htmldefaultstyle_.empty())
1476                         htmldefaultstyle_ += from_ascii("\n");
1477                 htmldefaultstyle_ += from_ascii(tmp);
1478         }
1479
1480 // tex2lyx does not see output_xhtml.cpp
1481 #ifndef NO_LAYOUT_CSS
1482         // alignment
1483         string where = alignmentToCSS(align);
1484         if (!where.empty()) {
1485                 htmldefaultstyle_ += from_ascii("text-align: " + where + ";\n");
1486         }
1487 #endif
1488
1489         // wrap up what we have, if anything
1490         if (!htmldefaultstyle_.empty())
1491                 htmldefaultstyle_ = 
1492                         from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") +
1493                         htmldefaultstyle_ + from_ascii("\n}\n");
1494         
1495         if (labeltype == LABEL_NO_LABEL || htmllabeltag() == "NONE")
1496                 return;
1497         
1498         docstring labelCSS;
1499         
1500         // label font
1501         if (labelfont != font)
1502                 labelCSS = labelfont.asCSS() + from_ascii("\n");
1503         if (labeltype == LABEL_CENTERED)
1504                 labelCSS += from_ascii("text-align: center;\n");
1505         
1506         if (!labelCSS.empty())
1507                 htmldefaultstyle_ +=
1508                         from_ascii(htmllabeltag() + "." + defaultCSSLabelClass() + " {\n") +
1509                         labelCSS + from_ascii("\n}\n");
1510 }
1511
1512
1513 bool Layout::operator==(Layout const & rhs) const
1514 {
1515         // This is enough for the applications we actually make,
1516         // at least at the moment. But we could check more.
1517         return name() == rhs.name()
1518                 && latexname() == rhs.latexname()
1519                 && latextype == rhs.latextype;
1520 }
1521
1522
1523 } // namespace lyx