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