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
,
104 LT_INTITLE
// keep this last!
107 /////////////////////
112 margintype
= MARGIN_STATIC
;
113 latextype
= LATEX_PARAGRAPH
;
119 labelfont
= inherit_font
;
121 reslabelfont
= sane_font
;
122 nextnoindent
= false;
127 labelbottomsep
= 0.0;
129 align
= LYX_ALIGN_BLOCK
;
130 alignpossible
= LYX_ALIGN_NONE
| LYX_ALIGN_LAYOUT
;
131 labeltype
= LABEL_NO_LABEL
;
132 endlabeltype
= END_LABEL_NO_LABEL
;
133 // Should or should not. That is the question.
134 // spacing.set(Spacing::OneHalf);
137 newline_allowed
= true;
138 free_spacing
= false;
140 toclevel
= NOT_IN_TOC
;
142 htmllabelfirst_
= false;
146 bool Layout::read(Lexer
& lex
, TextClass
const & tclass
)
148 // This table is sorted alphabetically [asierra 30March96]
149 LexerKeyword layoutTags
[] = {
150 { "align", LT_ALIGN
},
151 { "alignpossible", LT_ALIGNPOSSIBLE
},
152 { "babelpreamble", LT_BABELPREAMBLE
},
153 { "bottomsep", LT_BOTTOMSEP
},
154 { "category", LT_CATEGORY
},
155 { "commanddepth", LT_COMMANDDEPTH
},
156 { "copystyle", LT_COPYSTYLE
},
157 { "dependson", LT_DEPENDSON
},
159 { "endlabelstring", LT_ENDLABELSTRING
},
160 { "endlabeltype", LT_ENDLABELTYPE
},
161 { "fill_bottom", LT_FILL_BOTTOM
},
162 { "fill_top", LT_FILL_TOP
},
164 { "freespacing", LT_FREE_SPACING
},
165 { "htmlattr", LT_HTMLATTR
},
166 { "htmlitem", LT_HTMLITEM
},
167 { "htmlitemattr", LT_HTMLITEMATTR
},
168 { "htmllabel", LT_HTMLLABEL
},
169 { "htmllabelattr", LT_HTMLLABELATTR
},
170 { "htmllabelfirst", LT_HTMLLABELFIRST
},
171 { "htmlpremable", LT_HTMLPREAMBLE
},
172 { "htmlstyle", LT_HTMLSTYLE
},
173 { "htmltag", LT_HTMLTAG
},
174 { "innertag", LT_INNERTAG
},
175 { "intitle", LT_INTITLE
},
176 { "itemsep", LT_ITEMSEP
},
177 { "itemtag", LT_ITEMTAG
},
178 { "keepempty", LT_KEEPEMPTY
},
179 { "labelbottomsep", LT_LABEL_BOTTOMSEP
},
180 { "labelcounter", LT_LABELCOUNTER
},
181 { "labelfont", LT_LABELFONT
},
182 { "labelindent", LT_LABELINDENT
},
183 { "labelsep", LT_LABELSEP
},
184 { "labelstring", LT_LABELSTRING
},
185 { "labelstringappendix", LT_LABELSTRING_APPENDIX
},
186 { "labeltag", LT_LABELTAG
},
187 { "labeltype", LT_LABELTYPE
},
188 { "langpreamble", LT_LANGPREAMBLE
},
189 { "latexname", LT_LATEXNAME
},
190 { "latexparam", LT_LATEXPARAM
},
191 { "latextype", LT_LATEXTYPE
},
192 { "leftmargin", LT_LEFTMARGIN
},
193 { "margin", LT_MARGIN
},
194 { "needprotect", LT_NEED_PROTECT
},
195 { "newline", LT_NEWLINE
},
196 { "nextnoindent", LT_NEXTNOINDENT
},
197 { "obsoletedby", LT_OBSOLETEDBY
},
198 { "optionalargs", LT_OPTARGS
},
199 { "parindent", LT_PARINDENT
},
200 { "parsep", LT_PARSEP
},
201 { "parskip", LT_PARSKIP
},
202 { "passthru", LT_PASS_THRU
},
203 { "preamble", LT_PREAMBLE
},
204 { "requires", LT_REQUIRES
},
205 { "rightmargin", LT_RIGHTMARGIN
},
206 { "spacing", LT_SPACING
},
207 { "textfont", LT_TEXTFONT
},
208 { "toclevel", LT_TOCLEVEL
},
209 { "topsep", LT_TOPSEP
}
213 bool finished
= false;
214 lex
.pushTable(layoutTags
);
215 // parse style section
216 while (!finished
&& lex
.isOK() && !error
) {
218 // See comment in LyXRC.cpp.
220 case Lexer::LEX_FEOF
:
223 case Lexer::LEX_UNDEF
: // parse error
224 lex
.printError("Unknown layout tag `$$Token'");
231 switch (static_cast<LayoutTags
>(le
)) {
232 case LT_END
: // end of structure
240 case LT_COPYSTYLE
: { // initialize with a known style
243 style
= subst(style
, '_', ' ');
245 if (tclass
.hasLayout(style
)) {
246 docstring
const tmpname
= name_
;
247 this->operator=(tclass
[style
]);
250 LYXERR0("Cannot copy unknown style `"
252 << "All layouts so far:");
253 DocumentClass::const_iterator lit
= tclass
.begin();
254 DocumentClass::const_iterator len
= tclass
.end();
255 for (; lit
!= len
; ++lit
)
256 LYXERR0(lit
->name());
261 case LT_OBSOLETEDBY
: { // replace with a known style
264 style
= subst(style
, '_', ' ');
266 if (tclass
.hasLayout(style
)) {
267 docstring
const tmpname
= name_
;
268 this->operator=(tclass
[style
]);
270 if (obsoleted_by().empty())
271 obsoleted_by_
= style
;
273 LYXERR0("Cannot replace with unknown style `"
276 //lex.printError("Cannot replace with"
285 depends_on_
= subst(depends_on_
, '_', ' ');
288 case LT_MARGIN
: // margin style definition.
292 case LT_LATEXTYPE
: // LaTeX style definition.
305 lex
>> optionalargs
;
308 case LT_NEED_PROTECT
:
317 font
= lyxRead(lex
, font
);
322 font
= lyxRead(lex
, font
);
326 labelfont
= lyxRead(lex
, labelfont
);
329 case LT_NEXTNOINDENT
: // Indent next paragraph?
333 case LT_COMMANDDEPTH
:
343 latexparam_
= subst(latexparam_
, """, "\"");
359 preamble_
= from_utf8(lex
.getLongString("EndPreamble"));
362 case LT_LANGPREAMBLE
:
363 langpreamble_
= from_utf8(lex
.getLongString("EndLangPreamble"));
366 case LT_BABELPREAMBLE
:
367 babelpreamble_
= from_utf8(lex
.getLongString("EndBabelPreamble"));
374 case LT_ENDLABELTYPE
:
375 readEndLabelType(lex
);
378 case LT_LEFTMARGIN
: // left margin type
382 case LT_RIGHTMARGIN
: // right margin type
386 case LT_LABELINDENT
: // label indenting flag
390 case LT_PARINDENT
: // paragraph indent. flag
394 case LT_PARSKIP
: // paragraph skip size
398 case LT_ITEMSEP
: // item separation size
402 case LT_TOPSEP
: // top separation size
406 case LT_BOTTOMSEP
: // bottom separation size
410 case LT_LABEL_BOTTOMSEP
: // label bottom separation size
411 lex
>> labelbottomsep
;
414 case LT_LABELSEP
: // label separator
416 labelsep
= subst(labelsep
, 'x', ' ');
419 case LT_PARSEP
: // par. separation size
423 case LT_FILL_TOP
: // fill top flag
427 case LT_FILL_BOTTOM
: // fill bottom flag
431 case LT_NEWLINE
: // newlines allowed?
432 lex
>> newline_allowed
;
435 case LT_ALIGN
: // paragraph align
438 case LT_ALIGNPOSSIBLE
: // paragraph allowed align
439 readAlignPossible(lex
);
442 case LT_LABELSTRING
: // label string definition
443 // FIXME: this means LT_ENDLABELSTRING may only
444 // occur after LT_LABELSTRING
446 labelstring_
= trim(labelstring_
);
447 labelstring_appendix_
= labelstring_
;
450 case LT_ENDLABELSTRING
: // endlabel string definition
451 lex
>> endlabelstring_
;
452 endlabelstring_
= trim(endlabelstring_
);
455 case LT_LABELSTRING_APPENDIX
: // label string appendix definition
456 lex
>> labelstring_appendix_
;
457 labelstring_appendix_
= trim(labelstring_appendix_
);
460 case LT_LABELCOUNTER
: // name of counter to use
462 counter
= trim(counter
);
465 case LT_FREE_SPACING
: // Allow for free spacing.
469 case LT_PASS_THRU
: // Allow for pass thru.
473 case LT_SPACING
: // setspace.sty
479 vector
<string
> const req
=
480 getVectorFromString(lex
.getString());
481 requires_
.insert(req
.begin(), req
.end());
497 case LT_HTMLITEMATTR
:
498 lex
>> htmlitemattr_
;
505 case LT_HTMLLABELATTR
:
506 lex
>> htmllabelattr_
;
509 case LT_HTMLLABELFIRST
:
510 lex
>> htmllabelfirst_
;
514 htmlstyle_
= from_utf8(lex
.getLongString("EndHTMLStyle"));
517 case LT_HTMLPREAMBLE
:
518 htmlpreamble_
= from_utf8(lex
.getLongString("EndPreamble"));
538 LexerKeyword alignTags
[] = {
539 { "block", AT_BLOCK
},
540 { "center", AT_CENTER
},
541 { "layout", AT_LAYOUT
},
543 { "right", AT_RIGHT
}
547 void Layout::readAlign(Lexer
& lex
)
549 PushPopHelper
pph(lex
, alignTags
);
552 case Lexer::LEX_UNDEF
:
553 lex
.printError("Unknown alignment `$$Token'");
559 align
= LYX_ALIGN_BLOCK
;
562 align
= LYX_ALIGN_LEFT
;
565 align
= LYX_ALIGN_RIGHT
;
568 align
= LYX_ALIGN_CENTER
;
571 align
= LYX_ALIGN_LAYOUT
;
577 void Layout::readAlignPossible(Lexer
& lex
)
579 lex
.pushTable(alignTags
);
580 alignpossible
= LYX_ALIGN_NONE
| LYX_ALIGN_LAYOUT
;
581 int lineno
= lex
.lineNumber();
585 case Lexer::LEX_UNDEF
:
586 lex
.printError("Unknown alignment `$$Token'");
592 alignpossible
|= LYX_ALIGN_BLOCK
;
595 alignpossible
|= LYX_ALIGN_LEFT
;
598 alignpossible
|= LYX_ALIGN_RIGHT
;
601 alignpossible
|= LYX_ALIGN_CENTER
;
604 alignpossible
|= LYX_ALIGN_LAYOUT
;
607 } while (lineno
== lex
.lineNumber());
612 void Layout::readLabelType(Lexer
& lex
)
618 LA_CENTERED_TOP_ENVIRONMENT
,
628 LexerKeyword labelTypeTags
[] = {
629 { "bibliography", LA_BIBLIO
},
630 { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT
},
631 { "counter", LA_COUNTER
},
632 { "enumerate", LA_ENUMERATE
},
633 { "itemize", LA_ITEMIZE
},
634 { "manual", LA_MANUAL
},
635 { "no_label", LA_NO_LABEL
},
636 { "sensitive", LA_SENSITIVE
},
637 { "static", LA_STATIC
},
638 { "top_environment", LA_TOP_ENVIRONMENT
}
641 PushPopHelper
pph(lex
, labelTypeTags
);
644 case Lexer::LEX_UNDEF
:
645 lex
.printError("Unknown labeltype tag `$$Token'");
651 labeltype
= LABEL_NO_LABEL
;
654 labeltype
= LABEL_MANUAL
;
656 case LA_TOP_ENVIRONMENT
:
657 labeltype
= LABEL_TOP_ENVIRONMENT
;
659 case LA_CENTERED_TOP_ENVIRONMENT
:
660 labeltype
= LABEL_CENTERED_TOP_ENVIRONMENT
;
663 labeltype
= LABEL_STATIC
;
666 labeltype
= LABEL_SENSITIVE
;
669 labeltype
= LABEL_COUNTER
;
672 labeltype
= LABEL_ENUMERATE
;
675 labeltype
= LABEL_ITEMIZE
;
678 labeltype
= LABEL_BIBLIO
;
684 void Layout::readEndLabelType(Lexer
& lex
)
686 static LexerKeyword endlabelTypeTags
[] = {
687 { "box", END_LABEL_BOX
},
688 { "filled_box", END_LABEL_FILLED_BOX
},
689 { "no_label", END_LABEL_NO_LABEL
},
690 { "static", END_LABEL_STATIC
}
693 PushPopHelper
pph(lex
, endlabelTypeTags
);
696 case Lexer::LEX_UNDEF
:
697 lex
.printError("Unknown labeltype tag `$$Token'");
699 case END_LABEL_STATIC
:
701 case END_LABEL_FILLED_BOX
:
702 case END_LABEL_NO_LABEL
:
703 endlabeltype
= static_cast<EndLabelType
>(le
);
706 LYXERR0("Unhandled value " << le
);
712 void Layout::readMargin(Lexer
& lex
)
714 LexerKeyword marginTags
[] = {
715 { "dynamic", MARGIN_DYNAMIC
},
716 { "first_dynamic", MARGIN_FIRST_DYNAMIC
},
717 { "manual", MARGIN_MANUAL
},
718 { "right_address_box", MARGIN_RIGHT_ADDRESS_BOX
},
719 { "static", MARGIN_STATIC
}
722 PushPopHelper
pph(lex
, marginTags
);
726 case Lexer::LEX_UNDEF
:
727 lex
.printError("Unknown margin type tag `$$Token'");
732 case MARGIN_FIRST_DYNAMIC
:
733 case MARGIN_RIGHT_ADDRESS_BOX
:
734 margintype
= static_cast<MarginType
>(le
);
737 LYXERR0("Unhandled value " << le
);
743 void Layout::readLatexType(Lexer
& lex
)
745 LexerKeyword latexTypeTags
[] = {
746 { "bib_environment", LATEX_BIB_ENVIRONMENT
},
747 { "command", LATEX_COMMAND
},
748 { "environment", LATEX_ENVIRONMENT
},
749 { "item_environment", LATEX_ITEM_ENVIRONMENT
},
750 { "list_environment", LATEX_LIST_ENVIRONMENT
},
751 { "paragraph", LATEX_PARAGRAPH
}
754 PushPopHelper
pph(lex
, latexTypeTags
);
757 case Lexer::LEX_UNDEF
:
758 lex
.printError("Unknown latextype tag `$$Token'");
760 case LATEX_PARAGRAPH
:
762 case LATEX_ENVIRONMENT
:
763 case LATEX_ITEM_ENVIRONMENT
:
764 case LATEX_BIB_ENVIRONMENT
:
765 case LATEX_LIST_ENVIRONMENT
:
766 latextype
= static_cast<LatexType
>(le
);
769 LYXERR0("Unhandled value " << le
);
775 void Layout::readSpacing(Lexer
& lex
)
778 ST_SPACING_SINGLE
= 1,
784 LexerKeyword spacingTags
[] = {
785 {"double", ST_SPACING_DOUBLE
},
786 {"onehalf", ST_SPACING_ONEHALF
},
787 {"other", ST_OTHER
},
788 {"single", ST_SPACING_SINGLE
}
791 PushPopHelper
pph(lex
, spacingTags
);
794 case Lexer::LEX_UNDEF
:
795 lex
.printError("Unknown spacing token `$$Token'");
800 case ST_SPACING_SINGLE
:
801 spacing
.set(Spacing::Single
);
803 case ST_SPACING_ONEHALF
:
804 spacing
.set(Spacing::Onehalf
);
806 case ST_SPACING_DOUBLE
:
807 spacing
.set(Spacing::Double
);
811 spacing
.set(Spacing::Other
, lex
.getString());
819 docstring
const i18npreamble(Language
const * lang
, docstring
const & templ
)
824 string preamble
= subst(to_utf8(templ
), "$$lang", lang
->babel());
827 // tex2lyx does not have getMessages()
828 LASSERT(false, /**/);
831 // boost::regex is not unicode-safe.
832 // Should use QRegExp or (boost::u32regex, but that requires ICU)
833 static boost::regex
const reg("_\\(([^\\)]+)\\)");
835 while (boost::regex_search(preamble
, sub
, reg
)) {
836 string
const key
= sub
.str(1);
839 translated
= to_utf8(getMessages(lang
->code()).get(key
));
841 lyxerr
<< "Warning: not translating `" << key
842 << "' because it is not pure ASCII." << endl
;
845 preamble
= subst(preamble
, sub
.str(), translated
);
848 return from_utf8(preamble
);
854 docstring
const Layout::langpreamble(Language
const * lang
) const
856 return i18npreamble(lang
, langpreamble_
);
860 docstring
const Layout::babelpreamble(Language
const * lang
) const
862 return i18npreamble(lang
, babelpreamble_
);
866 bool Layout::operator==(Layout
const & rhs
) const
868 // This is enough for the applications we actually make,
869 // at least at the moment. But we could check more.
870 return name() == rhs
.name()
871 && latexname() == rhs
.latexname()
872 && latextype
== rhs
.latextype
;