3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
10 * Full author contact details are available in file CREDITS.
17 #include "TextClass.h"
21 #include "support/Messages.h"
22 #include "support/debug.h"
23 #include "support/lassert.h"
24 #include "support/lstrings.h"
26 #include <boost/regex.hpp>
29 using namespace lyx::support;
33 /// Special value of toclevel for layouts that to not belong in a TOC
34 const int Layout::NOT_IN_TOC = -1000;
36 // The order of the LayoutTags enum is no more important. [asierra300396]
50 //LT_ENVIRONMENT_DEFAULT,
67 LT_LABELSTRING_APPENDIX,
95 LT_INTITLE // keep this last!
103 margintype = MARGIN_STATIC;
104 latextype = LATEX_PARAGRAPH;
110 labelfont = inherit_font;
112 reslabelfont = sane_font;
113 nextnoindent = false;
118 labelbottomsep = 0.0;
120 align = LYX_ALIGN_BLOCK;
121 alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
122 labeltype = LABEL_NO_LABEL;
123 endlabeltype = END_LABEL_NO_LABEL;
124 // Should or should not. That is the question.
125 // spacing.set(Spacing::OneHalf);
128 newline_allowed = true;
129 free_spacing = false;
131 toclevel = NOT_IN_TOC;
136 bool Layout::read(Lexer & lex, TextClass const & tclass)
138 // This table is sorted alphabetically [asierra 30March96]
139 LexerKeyword layoutTags[] = {
140 { "align", LT_ALIGN },
141 { "alignpossible", LT_ALIGNPOSSIBLE },
142 { "babelpreamble", LT_BABELPREAMBLE },
143 { "bottomsep", LT_BOTTOMSEP },
144 { "category", LT_CATEGORY },
145 { "commanddepth", LT_COMMANDDEPTH },
146 { "copystyle", LT_COPYSTYLE },
147 { "dependson", LT_DEPENDSON },
149 { "endlabelstring", LT_ENDLABELSTRING },
150 { "endlabeltype", LT_ENDLABELTYPE },
151 { "fill_bottom", LT_FILL_BOTTOM },
152 { "fill_top", LT_FILL_TOP },
154 { "freespacing", LT_FREE_SPACING },
155 { "innertag", LT_INNERTAG },
156 { "intitle", LT_INTITLE },
157 { "itemsep", LT_ITEMSEP },
158 { "itemtag", LT_ITEMTAG },
159 { "keepempty", LT_KEEPEMPTY },
160 { "labelbottomsep", LT_LABEL_BOTTOMSEP },
161 { "labelcounter", LT_LABELCOUNTER },
162 { "labelfont", LT_LABELFONT },
163 { "labelindent", LT_LABELINDENT },
164 { "labelsep", LT_LABELSEP },
165 { "labelstring", LT_LABELSTRING },
166 { "labelstringappendix", LT_LABELSTRING_APPENDIX },
167 { "labeltag", LT_LABELTAG },
168 { "labeltype", LT_LABELTYPE },
169 { "langpreamble", LT_LANGPREAMBLE },
170 { "latexname", LT_LATEXNAME },
171 { "latexparam", LT_LATEXPARAM },
172 { "latextype", LT_LATEXTYPE },
173 { "leftmargin", LT_LEFTMARGIN },
174 { "margin", LT_MARGIN },
175 { "needprotect", LT_NEED_PROTECT },
176 { "newline", LT_NEWLINE },
177 { "nextnoindent", LT_NEXTNOINDENT },
178 { "obsoletedby", LT_OBSOLETEDBY },
179 { "optionalargs", LT_OPTARGS },
180 { "parindent", LT_PARINDENT },
181 { "parsep", LT_PARSEP },
182 { "parskip", LT_PARSKIP },
183 { "passthru", LT_PASS_THRU },
184 { "preamble", LT_PREAMBLE },
185 { "requires", LT_REQUIRES },
186 { "rightmargin", LT_RIGHTMARGIN },
187 { "spacing", LT_SPACING },
188 { "textfont", LT_TEXTFONT },
189 { "toclevel", LT_TOCLEVEL },
190 { "topsep", LT_TOPSEP }
194 bool finished = false;
195 lex.pushTable(layoutTags);
196 // parse style section
197 while (!finished && lex.isOK() && !error) {
199 // See comment in LyXRC.cpp.
201 case Lexer::LEX_FEOF:
204 case Lexer::LEX_UNDEF: // parse error
205 lex.printError("Unknown layout tag `$$Token'");
212 switch (static_cast<LayoutTags>(le)) {
213 case LT_END: // end of structure
221 case LT_COPYSTYLE: { // initialize with a known style
224 style = subst(style, '_', ' ');
226 if (tclass.hasLayout(style)) {
227 docstring const tmpname = name_;
228 this->operator=(tclass[style]);
231 LYXERR0("Cannot copy unknown style `"
233 << "All layouts so far:");
234 DocumentClass::const_iterator lit = tclass.begin();
235 DocumentClass::const_iterator len = tclass.end();
236 for (; lit != len; ++lit)
237 LYXERR0(lit->name());
242 case LT_OBSOLETEDBY: { // replace with a known style
245 style = subst(style, '_', ' ');
247 if (tclass.hasLayout(style)) {
248 docstring const tmpname = name_;
249 this->operator=(tclass[style]);
251 if (obsoleted_by().empty())
252 obsoleted_by_ = style;
254 LYXERR0("Cannot replace with unknown style `"
257 //lex.printError("Cannot replace with"
266 depends_on_ = subst(depends_on_, '_', ' ');
269 case LT_MARGIN: // margin style definition.
273 case LT_LATEXTYPE: // LaTeX style definition.
286 lex >> optionalargs ;
289 case LT_NEED_PROTECT:
298 font = lyxRead(lex, font);
303 font = lyxRead(lex, font);
307 labelfont = lyxRead(lex, labelfont);
310 case LT_NEXTNOINDENT: // Indent next paragraph?
314 case LT_COMMANDDEPTH:
324 latexparam_ = subst(latexparam_, """, "\"");
340 preamble_ = from_utf8(lex.getLongString("EndPreamble"));
343 case LT_LANGPREAMBLE:
344 langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble"));
347 case LT_BABELPREAMBLE:
348 babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble"));
355 case LT_ENDLABELTYPE:
356 readEndLabelType(lex);
359 case LT_LEFTMARGIN: // left margin type
363 case LT_RIGHTMARGIN: // right margin type
367 case LT_LABELINDENT: // label indenting flag
371 case LT_PARINDENT: // paragraph indent. flag
375 case LT_PARSKIP: // paragraph skip size
379 case LT_ITEMSEP: // item separation size
383 case LT_TOPSEP: // top separation size
387 case LT_BOTTOMSEP: // bottom separation size
391 case LT_LABEL_BOTTOMSEP: // label bottom separation size
392 lex >> labelbottomsep;
395 case LT_LABELSEP: // label separator
397 labelsep = subst(labelsep, 'x', ' ');
400 case LT_PARSEP: // par. separation size
404 case LT_FILL_TOP: // fill top flag
408 case LT_FILL_BOTTOM: // fill bottom flag
412 case LT_NEWLINE: // newlines allowed?
413 lex >> newline_allowed;
416 case LT_ALIGN: // paragraph align
419 case LT_ALIGNPOSSIBLE: // paragraph allowed align
420 readAlignPossible(lex);
423 case LT_LABELSTRING: // label string definition
424 // FIXME: this means LT_ENDLABELSTRING may only
425 // occur after LT_LABELSTRING
427 labelstring_ = trim(labelstring_);
428 labelstring_appendix_ = labelstring_;
431 case LT_ENDLABELSTRING: // endlabel string definition
432 lex >> endlabelstring_;
433 endlabelstring_ = trim(endlabelstring_);
436 case LT_LABELSTRING_APPENDIX: // label string appendix definition
437 lex >> labelstring_appendix_;
438 labelstring_appendix_ = trim(labelstring_appendix_);
441 case LT_LABELCOUNTER: // name of counter to use
443 counter = trim(counter);
446 case LT_FREE_SPACING: // Allow for free spacing.
450 case LT_PASS_THRU: // Allow for pass thru.
454 case LT_SPACING: // setspace.sty
460 vector<string> const req =
461 getVectorFromString(lex.getString());
462 requires_.insert(req.begin(), req.end());
482 LexerKeyword alignTags[] = {
483 { "block", AT_BLOCK },
484 { "center", AT_CENTER },
485 { "layout", AT_LAYOUT },
487 { "right", AT_RIGHT }
491 void Layout::readAlign(Lexer & lex)
493 PushPopHelper pph(lex, alignTags);
496 case Lexer::LEX_UNDEF:
497 lex.printError("Unknown alignment `$$Token'");
503 align = LYX_ALIGN_BLOCK;
506 align = LYX_ALIGN_LEFT;
509 align = LYX_ALIGN_RIGHT;
512 align = LYX_ALIGN_CENTER;
515 align = LYX_ALIGN_LAYOUT;
521 void Layout::readAlignPossible(Lexer & lex)
523 lex.pushTable(alignTags);
524 alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT;
525 int lineno = lex.lineNumber();
529 case Lexer::LEX_UNDEF:
530 lex.printError("Unknown alignment `$$Token'");
536 alignpossible |= LYX_ALIGN_BLOCK;
539 alignpossible |= LYX_ALIGN_LEFT;
542 alignpossible |= LYX_ALIGN_RIGHT;
545 alignpossible |= LYX_ALIGN_CENTER;
548 alignpossible |= LYX_ALIGN_LAYOUT;
551 } while (lineno == lex.lineNumber());
556 void Layout::readLabelType(Lexer & lex)
562 LA_CENTERED_TOP_ENVIRONMENT,
572 LexerKeyword labelTypeTags[] = {
573 { "bibliography", LA_BIBLIO },
574 { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT },
575 { "counter", LA_COUNTER },
576 { "enumerate", LA_ENUMERATE },
577 { "itemize", LA_ITEMIZE },
578 { "manual", LA_MANUAL },
579 { "no_label", LA_NO_LABEL },
580 { "sensitive", LA_SENSITIVE },
581 { "static", LA_STATIC },
582 { "top_environment", LA_TOP_ENVIRONMENT }
585 PushPopHelper pph(lex, labelTypeTags);
588 case Lexer::LEX_UNDEF:
589 lex.printError("Unknown labeltype tag `$$Token'");
595 labeltype = LABEL_NO_LABEL;
598 labeltype = LABEL_MANUAL;
600 case LA_TOP_ENVIRONMENT:
601 labeltype = LABEL_TOP_ENVIRONMENT;
603 case LA_CENTERED_TOP_ENVIRONMENT:
604 labeltype = LABEL_CENTERED_TOP_ENVIRONMENT;
607 labeltype = LABEL_STATIC;
610 labeltype = LABEL_SENSITIVE;
613 labeltype = LABEL_COUNTER;
616 labeltype = LABEL_ENUMERATE;
619 labeltype = LABEL_ITEMIZE;
622 labeltype = LABEL_BIBLIO;
628 void Layout::readEndLabelType(Lexer & lex)
630 static LexerKeyword endlabelTypeTags[] = {
631 { "box", END_LABEL_BOX },
632 { "filled_box", END_LABEL_FILLED_BOX },
633 { "no_label", END_LABEL_NO_LABEL },
634 { "static", END_LABEL_STATIC }
637 PushPopHelper pph(lex, endlabelTypeTags);
640 case Lexer::LEX_UNDEF:
641 lex.printError("Unknown labeltype tag `$$Token'");
643 case END_LABEL_STATIC:
645 case END_LABEL_FILLED_BOX:
646 case END_LABEL_NO_LABEL:
647 endlabeltype = static_cast<EndLabelType>(le);
650 LYXERR0("Unhandled value " << le);
656 void Layout::readMargin(Lexer & lex)
658 LexerKeyword marginTags[] = {
659 { "dynamic", MARGIN_DYNAMIC },
660 { "first_dynamic", MARGIN_FIRST_DYNAMIC },
661 { "manual", MARGIN_MANUAL },
662 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX },
663 { "static", MARGIN_STATIC }
666 PushPopHelper pph(lex, marginTags);
670 case Lexer::LEX_UNDEF:
671 lex.printError("Unknown margin type tag `$$Token'");
676 case MARGIN_FIRST_DYNAMIC:
677 case MARGIN_RIGHT_ADDRESS_BOX:
678 margintype = static_cast<MarginType>(le);
681 LYXERR0("Unhandled value " << le);
687 void Layout::readLatexType(Lexer & lex)
689 LexerKeyword latexTypeTags[] = {
690 { "bib_environment", LATEX_BIB_ENVIRONMENT },
691 { "command", LATEX_COMMAND },
692 { "environment", LATEX_ENVIRONMENT },
693 { "item_environment", LATEX_ITEM_ENVIRONMENT },
694 { "list_environment", LATEX_LIST_ENVIRONMENT },
695 { "paragraph", LATEX_PARAGRAPH }
698 PushPopHelper pph(lex, latexTypeTags);
701 case Lexer::LEX_UNDEF:
702 lex.printError("Unknown latextype tag `$$Token'");
704 case LATEX_PARAGRAPH:
706 case LATEX_ENVIRONMENT:
707 case LATEX_ITEM_ENVIRONMENT:
708 case LATEX_BIB_ENVIRONMENT:
709 case LATEX_LIST_ENVIRONMENT:
710 latextype = static_cast<LatexType>(le);
713 LYXERR0("Unhandled value " << le);
719 void Layout::readSpacing(Lexer & lex)
722 ST_SPACING_SINGLE = 1,
728 LexerKeyword spacingTags[] = {
729 {"double", ST_SPACING_DOUBLE },
730 {"onehalf", ST_SPACING_ONEHALF },
731 {"other", ST_OTHER },
732 {"single", ST_SPACING_SINGLE }
735 PushPopHelper pph(lex, spacingTags);
738 case Lexer::LEX_UNDEF:
739 lex.printError("Unknown spacing token `$$Token'");
744 case ST_SPACING_SINGLE:
745 spacing.set(Spacing::Single);
747 case ST_SPACING_ONEHALF:
748 spacing.set(Spacing::Onehalf);
750 case ST_SPACING_DOUBLE:
751 spacing.set(Spacing::Double);
755 spacing.set(Spacing::Other, lex.getString());
761 docstring const & Layout::name() const
767 void Layout::setName(docstring const & name)
773 docstring const & Layout::obsoleted_by() const
775 return obsoleted_by_;
779 docstring const & Layout::depends_on() const
787 docstring const i18npreamble(Language const * lang, docstring const & templ)
792 string preamble = subst(to_utf8(templ), "$$lang", lang->babel());
795 // tex2lyx does not have getMessages()
796 LASSERT(false, /**/);
799 // boost::regex is not unicode-safe.
800 // Should use QRegExp or (boost::u32regex, but that requires ICU)
801 static boost::regex const reg("_\\(([^\\)]+)\\)");
803 while (boost::regex_search(preamble, sub, reg)) {
804 string const key = sub.str(1);
807 translated = to_utf8(getMessages(lang->code()).get(key));
809 lyxerr << "Warning: not translating `" << key
810 << "' because it is not pure ASCII." << endl;
813 preamble = subst(preamble, sub.str(), translated);
816 return from_utf8(preamble);
822 docstring const Layout::langpreamble(Language const * lang) const
824 return i18npreamble(lang, langpreamble_);
828 docstring const Layout::babelpreamble(Language const * lang) const
830 return i18npreamble(lang, babelpreamble_);
834 bool Layout::operator==(Layout const & rhs) const
836 // This is enough for the applications we actually make,
837 // at least at the moment. But we could check more.
838 return name() == rhs.name()
839 && latexname() == rhs.latexname()
840 && latextype == rhs.latextype;