X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLayout.cpp;h=1eaa38aa5fa3b495a590ba70f858bfa736a6eb47;hb=90f7007a2e6c78ffd031e4636ff909ab1bc2ddec;hp=f1d76c6228298a936bc4cc026096680206433465;hpb=9929f8985643696242653fc66388fc532d4eec02;p=lyx.git diff --git a/src/Layout.cpp b/src/Layout.cpp index f1d76c6228..1eaa38aa5f 100644 --- a/src/Layout.cpp +++ b/src/Layout.cpp @@ -13,17 +13,19 @@ #include #include "Layout.h" +#include "Encoding.h" +#include "FontInfo.h" #include "Language.h" -#include "TextClass.h" #include "Lexer.h" -#include "FontInfo.h" +#include "output_xhtml.h" +#include "TextClass.h" -#include "support/Messages.h" #include "support/debug.h" #include "support/lassert.h" #include "support/lstrings.h" +#include "support/Messages.h" +#include "support/textutils.h" -#include using namespace std; using namespace lyx::support; @@ -38,6 +40,7 @@ const int Layout::NOT_IN_TOC = -1000; enum LayoutTags { LT_ALIGN = 1, LT_ALIGNPOSSIBLE, + LT_ARGUMENT, LT_MARGIN, LT_BOTTOMSEP, LT_CATEGORY, @@ -45,17 +48,12 @@ enum LayoutTags { LT_COPYSTYLE, LT_DEPENDSON, LT_OBSOLETEDBY, - //LT_EMPTY, LT_END, - //LT_ENVIRONMENT_DEFAULT, - //LT_FANCYHDR, - LT_FILL_BOTTOM, - LT_FILL_TOP, - //LT_FIRST_COUNTER, LT_FONT, LT_FREE_SPACING, LT_PASS_THRU, - //LT_HEADINGS, + LT_PARBREAK_IS_NEWLINE, + LT_ITEMCOMMAND, LT_ITEMSEP, LT_KEEPEMPTY, LT_LABEL_BOTTOMSEP, @@ -71,8 +69,8 @@ enum LayoutTags { LT_ENDLABELTYPE, LT_LATEXNAME, LT_LATEXPARAM, - LT_OPTARGS, LT_LATEXTYPE, + LT_LEFTDELIM, LT_LEFTMARGIN, LT_NEED_PROTECT, LT_NEWLINE, @@ -80,7 +78,6 @@ enum LayoutTags { LT_PARINDENT, LT_PARSEP, LT_PARSKIP, - //LT_PLAIN, LT_PREAMBLE, LT_LANGPREAMBLE, LT_BABELPREAMBLE, @@ -103,6 +100,11 @@ enum LayoutTags { LT_HTMLSTYLE, LT_HTMLFORCECSS, LT_INPREAMBLE, + LT_HTMLTITLE, + LT_SPELLCHECK, + LT_REFPREFIX, + LT_RESETARGS, + LT_RIGHTDELIM, LT_INTITLE // keep this last! }; @@ -115,7 +117,6 @@ Layout::Layout() latextype = LATEX_PARAGRAPH; intitle = false; inpreamble = false; - optionalargs = 0; needprotect = false; keepempty = false; font = inherit_font; @@ -135,15 +136,17 @@ Layout::Layout() endlabeltype = END_LABEL_NO_LABEL; // Should or should not. That is the question. // spacing.set(Spacing::OneHalf); - fill_top = false; - fill_bottom = false; newline_allowed = true; free_spacing = false; pass_thru = false; + parbreak_is_newline = false; toclevel = NOT_IN_TOC; commanddepth = 0; htmllabelfirst_ = false; htmlforcecss_ = false; + htmltitle_ = false; + spellcheck = true; + itemcommand_ = "item"; } @@ -153,6 +156,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) LexerKeyword layoutTags[] = { { "align", LT_ALIGN }, { "alignpossible", LT_ALIGNPOSSIBLE }, + { "argument", LT_ARGUMENT }, { "babelpreamble", LT_BABELPREAMBLE }, { "bottomsep", LT_BOTTOMSEP }, { "category", LT_CATEGORY }, @@ -162,8 +166,6 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) { "end", LT_END }, { "endlabelstring", LT_ENDLABELSTRING }, { "endlabeltype", LT_ENDLABELTYPE }, - { "fill_bottom", LT_FILL_BOTTOM }, - { "fill_top", LT_FILL_TOP }, { "font", LT_FONT }, { "freespacing", LT_FREE_SPACING }, { "htmlattr", LT_HTMLATTR }, @@ -173,12 +175,14 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) { "htmllabel", LT_HTMLLABEL }, { "htmllabelattr", LT_HTMLLABELATTR }, { "htmllabelfirst", LT_HTMLLABELFIRST }, - { "htmlpremable", LT_HTMLPREAMBLE }, + { "htmlpreamble", LT_HTMLPREAMBLE }, { "htmlstyle", LT_HTMLSTYLE }, { "htmltag", LT_HTMLTAG }, + { "htmltitle", LT_HTMLTITLE }, { "innertag", LT_INNERTAG }, - { "intitle", LT_INTITLE }, { "inpreamble", LT_INPREAMBLE }, + { "intitle", LT_INTITLE }, + { "itemcommand", LT_ITEMCOMMAND }, { "itemsep", LT_ITEMSEP }, { "itemtag", LT_ITEMTAG }, { "keepempty", LT_KEEPEMPTY }, @@ -195,21 +199,26 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) { "latexname", LT_LATEXNAME }, { "latexparam", LT_LATEXPARAM }, { "latextype", LT_LATEXTYPE }, + { "leftdelim", LT_LEFTDELIM }, { "leftmargin", LT_LEFTMARGIN }, { "margin", LT_MARGIN }, { "needprotect", LT_NEED_PROTECT }, { "newline", LT_NEWLINE }, { "nextnoindent", LT_NEXTNOINDENT }, { "obsoletedby", LT_OBSOLETEDBY }, - { "optionalargs", LT_OPTARGS }, + { "parbreakisnewline", LT_PARBREAK_IS_NEWLINE }, { "parindent", LT_PARINDENT }, { "parsep", LT_PARSEP }, { "parskip", LT_PARSKIP }, { "passthru", LT_PASS_THRU }, { "preamble", LT_PREAMBLE }, + { "refprefix", LT_REFPREFIX }, { "requires", LT_REQUIRES }, + { "resetargs", LT_RESETARGS }, + { "rightdelim", LT_RIGHTDELIM }, { "rightmargin", LT_RIGHTMARGIN }, { "spacing", LT_SPACING }, + { "spellcheck", LT_SPELLCHECK }, { "textfont", LT_TEXTFONT }, { "toclevel", LT_TOCLEVEL }, { "topsep", LT_TOPSEP } @@ -218,6 +227,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) bool error = false; bool finished = false; lex.pushTable(layoutTags); + // parse style section while (!finished && lex.isOK() && !error) { int le = lex.lex(); @@ -226,7 +236,8 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) case Lexer::LEX_FEOF: continue; - case Lexer::LEX_UNDEF: // parse error + case Lexer::LEX_UNDEF: + // parse error lex.printError("Unknown layout tag `$$Token'"); error = true; continue; @@ -235,7 +246,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) break; } switch (static_cast(le)) { - case LT_END: // end of structure + case LT_END: finished = true; break; @@ -243,7 +254,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) lex >> category_; break; - case LT_COPYSTYLE: { // initialize with a known style + case LT_COPYSTYLE: { docstring style; lex >> style; style = subst(style, '_', ' '); @@ -264,7 +275,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) break; } - case LT_OBSOLETEDBY: { // replace with a known style + case LT_OBSOLETEDBY: { docstring style; lex >> style; style = subst(style, '_', ' '); @@ -291,11 +302,11 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) depends_on_ = subst(depends_on_, '_', ' '); break; - case LT_MARGIN: // margin style definition. + case LT_MARGIN: readMargin(lex); break; - case LT_LATEXTYPE: // LaTeX style definition. + case LT_LATEXTYPE: readLatexType(lex); break; @@ -311,8 +322,17 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) lex >> toclevel; break; - case LT_OPTARGS: - lex >> optionalargs ; + case LT_RESETARGS: + bool reset; + lex >> reset; + if (reset) { + latexargs_.clear(); + itemargs_.clear(); + } + break; + + case LT_ARGUMENT: + readArgument(lex); break; case LT_NEED_PROTECT: @@ -336,7 +356,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) labelfont = lyxRead(lex, labelfont); break; - case LT_NEXTNOINDENT: // Indent next paragraph? + case LT_NEXTNOINDENT: lex >> nextnoindent; break; @@ -353,6 +373,18 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) latexparam_ = subst(latexparam_, """, "\""); break; + case LT_LEFTDELIM: + lex >> leftdelim_; + leftdelim_ = support::subst(leftdelim_, from_ascii("
"), + from_ascii("\n")); + break; + + case LT_RIGHTDELIM: + lex >> rightdelim_; + rightdelim_ = support::subst(rightdelim_, from_ascii("
"), + from_ascii("\n")); + break; + case LT_INNERTAG: lex >> innertag_; break; @@ -365,6 +397,10 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) lex >> itemtag_; break; + case LT_ITEMCOMMAND: + lex >> itemcommand_; + break; + case LT_PREAMBLE: preamble_ = from_utf8(lex.getLongString("EndPreamble")); break; @@ -385,71 +421,64 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) readEndLabelType(lex); break; - case LT_LEFTMARGIN: // left margin type + case LT_LEFTMARGIN: lex >> leftmargin; break; - case LT_RIGHTMARGIN: // right margin type + case LT_RIGHTMARGIN: lex >> rightmargin; break; - case LT_LABELINDENT: // label indenting flag + case LT_LABELINDENT: lex >> labelindent; break; - case LT_PARINDENT: // paragraph indent. flag + case LT_PARINDENT: lex >> parindent; break; - case LT_PARSKIP: // paragraph skip size + case LT_PARSKIP: lex >> parskip; break; - case LT_ITEMSEP: // item separation size + case LT_ITEMSEP: lex >> itemsep; break; - case LT_TOPSEP: // top separation size + case LT_TOPSEP: lex >> topsep; break; - case LT_BOTTOMSEP: // bottom separation size + case LT_BOTTOMSEP: lex >> bottomsep; break; - case LT_LABEL_BOTTOMSEP: // label bottom separation size + case LT_LABEL_BOTTOMSEP: lex >> labelbottomsep; break; - case LT_LABELSEP: // label separator + case LT_LABELSEP: lex >> labelsep; labelsep = subst(labelsep, 'x', ' '); break; - case LT_PARSEP: // par. separation size + case LT_PARSEP: lex >> parsep; break; - case LT_FILL_TOP: // fill top flag - lex >> fill_top; - break; - - case LT_FILL_BOTTOM: // fill bottom flag - lex >> fill_bottom; - break; - - case LT_NEWLINE: // newlines allowed? + case LT_NEWLINE: lex >> newline_allowed; break; - case LT_ALIGN: // paragraph align + case LT_ALIGN: readAlign(lex); break; - case LT_ALIGNPOSSIBLE: // paragraph allowed align + + case LT_ALIGNPOSSIBLE: readAlignPossible(lex); break; - case LT_LABELSTRING: // label string definition + case LT_LABELSTRING: // FIXME: this means LT_ENDLABELSTRING may only // occur after LT_LABELSTRING lex >> labelstring_; @@ -457,30 +486,34 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) labelstring_appendix_ = labelstring_; break; - case LT_ENDLABELSTRING: // endlabel string definition + case LT_ENDLABELSTRING: lex >> endlabelstring_; endlabelstring_ = trim(endlabelstring_); break; - case LT_LABELSTRING_APPENDIX: // label string appendix definition + case LT_LABELSTRING_APPENDIX: lex >> labelstring_appendix_; labelstring_appendix_ = trim(labelstring_appendix_); break; - case LT_LABELCOUNTER: // name of counter to use + case LT_LABELCOUNTER: lex >> counter; counter = trim(counter); break; - case LT_FREE_SPACING: // Allow for free spacing. + case LT_FREE_SPACING: lex >> free_spacing; break; - case LT_PASS_THRU: // Allow for pass thru. + case LT_PASS_THRU: lex >> pass_thru; break; - case LT_SPACING: // setspace.sty + case LT_PARBREAK_IS_NEWLINE: + lex >> parbreak_is_newline; + break; + + case LT_SPACING: readSpacing(lex); break; @@ -491,6 +524,16 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) requires_.insert(req.begin(), req.end()); break; } + + case LT_REFPREFIX: { + docstring arg; + lex >> arg; + if (arg == "OFF") + refprefix.clear(); + else + refprefix = arg; + break; + } case LT_HTMLTAG: lex >> htmltag_; @@ -526,16 +569,30 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) case LT_HTMLFORCECSS: lex >> htmlforcecss_; + break; case LT_HTMLPREAMBLE: htmlpreamble_ = from_utf8(lex.getLongString("EndPreamble")); break; + + case LT_HTMLTITLE: + lex >> htmltitle_; + break; + case LT_SPELLCHECK: + lex >> spellcheck; + break; } } lex.popTable(); + // make sure we only have inpreamble = true for commands + if (inpreamble && latextype != LATEX_COMMAND && latextype != LATEX_PARAGRAPH) { + LYXERR0("InPreamble not permitted except with command and paragraph layouts."); + LYXERR0("Layout name: " << name()); + inpreamble = false; + } - return !error; + return finished && !error; } @@ -827,52 +884,124 @@ void Layout::readSpacing(Lexer & lex) } -namespace { - -docstring const i18npreamble(Language const * lang, docstring const & templ) +void Layout::readArgument(Lexer & lex) { - if (templ.empty()) - return templ; - - string preamble = subst(to_utf8(templ), "$$lang", lang->babel()); - -#ifdef TEX2LYX - // tex2lyx does not have getMessages() - LASSERT(false, /**/); -#else - // FIXME UNICODE - // boost::regex is not unicode-safe. - // Should use QRegExp or (boost::u32regex, but that requires ICU) - static boost::regex const reg("_\\(([^\\)]+)\\)"); - boost::smatch sub; - while (boost::regex_search(preamble, sub, reg)) { - string const key = sub.str(1); - string translated; - if (isAscii(key)) - translated = to_utf8(getMessages(lang->code()).get(key)); - else { - lyxerr << "Warning: not translating `" << key - << "' because it is not pure ASCII." << endl; - translated = key; + latexarg arg; + arg.mandatory = false; + arg.autoinsert = false; + bool error = false; + bool finished = false; + arg.font = inherit_font; + arg.labelfont = inherit_font; + string id; + lex >> id; + bool const itemarg = prefixIs(id, "item:"); + bool const postcmd = prefixIs(id, "post:"); + + while (!finished && lex.isOK() && !error) { + lex.next(); + string const tok = ascii_lowercase(lex.getString()); + + if (tok.empty()) { + continue; + } else if (tok == "endargument") { + finished = true; + } else if (tok == "labelstring") { + lex.next(); + arg.labelstring = lex.getDocString(); + } else if (tok == "menustring") { + lex.next(); + arg.menustring = lex.getDocString(); + } else if (tok == "mandatory") { + lex.next(); + arg.mandatory = lex.getBool(); + } else if (tok == "autoinsert") { + lex.next(); + arg.autoinsert = lex.getBool(); + } else if (tok == "leftdelim") { + lex.next(); + arg.ldelim = lex.getDocString(); + arg.ldelim = support::subst(arg.ldelim, from_ascii("
"), + from_ascii("\n")); + } else if (tok == "rightdelim") { + lex.next(); + arg.rdelim = lex.getDocString(); + arg.rdelim = support::subst(arg.rdelim, from_ascii("
"), + from_ascii("\n")); + } else if (tok == "presetarg") { + lex.next(); + arg.presetarg = lex.getDocString(); + } else if (tok == "tooltip") { + lex.next(); + arg.tooltip = lex.getDocString(); + } else if (tok == "requires") { + lex.next(); + arg.requires = lex.getString(); + } else if (tok == "decoration") { + lex.next(); + arg.decoration = lex.getString(); + } else if (tok == "font") { + arg.font = lyxRead(lex, arg.font); + } else if (tok == "labelfont") { + arg.labelfont = lyxRead(lex, arg.labelfont); + } else { + lex.printError("Unknown tag"); + error = true; } - preamble = subst(preamble, sub.str(), translated); } -#endif - return from_utf8(preamble); + if (arg.labelstring.empty()) + LYXERR0("Incomplete Argument definition!"); + else if (itemarg) + itemargs_[id] = arg; + else if (postcmd) + postcommandargs_[id] = arg; + else + latexargs_[id] = arg; } + +Layout::LaTeXArgMap Layout::args() const +{ + LaTeXArgMap args = latexargs_; + if (!postcommandargs_.empty()) + args.insert(postcommandargs_.begin(), postcommandargs_.end()); + if (!itemargs_.empty()) + args.insert(itemargs_.begin(), itemargs_.end()); + return args; } -docstring const Layout::langpreamble(Language const * lang) const +int Layout::optArgs() const { - return i18npreamble(lang, langpreamble_); + int nr = 0; + LaTeXArgMap::const_iterator it = latexargs_.begin(); + for (; it != latexargs_.end(); ++it) { + if (!(*it).second.mandatory) + ++nr; + } + LaTeXArgMap::const_iterator iit = postcommandargs_.begin(); + for (; iit != postcommandargs_.end(); ++iit) { + if (!(*iit).second.mandatory) + ++nr; + } + return nr; } -docstring const Layout::babelpreamble(Language const * lang) const +int Layout::requiredArgs() const { - return i18npreamble(lang, babelpreamble_); + int nr = 0; + LaTeXArgMap::const_iterator it = latexargs_.begin(); + for (; it != latexargs_.end(); ++it) { + if ((*it).second.mandatory) + ++nr; + } + LaTeXArgMap::const_iterator iit = postcommandargs_.begin(); + for (; iit != postcommandargs_.end(); ++iit) { + if (!(*iit).second.mandatory) + ++nr; + } + return nr; } @@ -910,8 +1039,13 @@ string const & Layout::htmlitemattr() const string const & Layout::htmllabeltag() const { - if (htmllabeltag_.empty()) - htmllabeltag_ = "span"; + if (htmllabeltag_.empty()) { + if (labeltype != LABEL_TOP_ENVIRONMENT && + labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) + htmllabeltag_ = "span"; + else + htmllabeltag_ = "div"; + } return htmllabeltag_; } @@ -924,7 +1058,8 @@ string const & Layout::htmllabelattr() const } -docstring Layout::htmlstyle() const { +docstring Layout::htmlstyle() const +{ if (!htmlstyle_.empty() && !htmlforcecss_) return htmlstyle_; if (htmldefaultstyle_.empty()) @@ -944,40 +1079,100 @@ string Layout::defaultCSSClass() const docstring::const_iterator it = name().begin(); docstring::const_iterator en = name().end(); for (; it != en; ++it) { - if (!isalpha(*it)) - continue; - if (islower(*it)) - d += *it; - else - d += lowercase(*it); + char_type const c = *it; + if (!isAlphaASCII(c)) { + if (d.empty()) + // make sure we don't start with an underscore, + // as that sometimes causes problems. + d = from_ascii("lyx_"); + else + d += '_'; + } else if (isLower(c)) + d += c; + else + // this is slow, so do it only if necessary + d += lowercase(c); } - // are there other characters we need to remove? defaultcssclass_ = to_utf8(d); return defaultcssclass_; } -// NOTE There is a whole ton of stuff that could go into this. -// Things like bottomsep, topsep, and parsep could become various -// sorts of margins or padding, for example. But for now we are -// going to keep it simple. -void Layout::makeDefaultCSS() const { +namespace { + +string makeMarginValue(char const * side, double d) +{ + ostringstream os; + os << "margin-" << side << ": " << d << "ex;\n"; + return os.str(); +} + +} + + +void Layout::makeDefaultCSS() const +{ // this never needs to be redone, since reloading layouts will // wipe out what we did before. if (!htmldefaultstyle_.empty()) return; - docstring const mainfontCSS = font.asCSS(); - if (!mainfontCSS.empty()) + + // main font + htmldefaultstyle_ = font.asCSS(); + + // bottom margins + string tmp; + if (topsep > 0) + tmp += makeMarginValue("top", topsep); + if (bottomsep > 0) + tmp += makeMarginValue("bottom", bottomsep); + if (!leftmargin.empty()) { + // we can't really do what LyX does with the margin, so + // we'll just figure out how many characters it is + int const len = leftmargin.length(); + tmp += makeMarginValue("left", len); + } + if (!rightmargin.empty()) { + int const len = rightmargin.length(); + tmp += makeMarginValue("right", len); + } + + if (!tmp.empty()) { + if (!htmldefaultstyle_.empty()) + htmldefaultstyle_ += from_ascii("\n"); + htmldefaultstyle_ += from_ascii(tmp); + } + +// tex2lyx does not see output_xhtml.cpp +#ifndef TEX2LYX + // alignment + string where = alignmentToCSS(align); + if (!where.empty()) { + htmldefaultstyle_ += from_ascii("text-align: " + where + ";\n"); + } +#endif + + // wrap up what we have, if anything + if (!htmldefaultstyle_.empty()) htmldefaultstyle_ = from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") + - mainfontCSS + from_ascii("\n}\n"); - if (labelfont == font || htmllabeltag() == "NONE") + htmldefaultstyle_ + from_ascii("\n}\n"); + + if (labeltype == LABEL_NO_LABEL || htmllabeltag() == "NONE") return; - docstring const labelfontCSS = labelfont.asCSS(); - if (!labelfontCSS.empty()) + + docstring labelCSS; + + // label font + if (labelfont != font) + labelCSS = labelfont.asCSS() + from_ascii("\n"); + if (labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) + labelCSS += from_ascii("text-align: center;\n"); + + if (!labelCSS.empty()) htmldefaultstyle_ += from_ascii(htmllabeltag() + "." + defaultCSSLabelClass() + " {\n") + - labelfontCSS + from_ascii("\n}\n"); + labelCSS + from_ascii("\n}\n"); }