From 2e255b1c4f3264571a6bd9ade8651c1657c995c6 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 24 Dec 2016 10:13:51 +0100 Subject: [PATCH] Restructure InsetQuotes for better extensibilty The current char-based implementation gets increasingly unreadable, especially if styles are added that do not follow the strict single-double paradigm. --- src/BufferParams.cpp | 20 +- src/BufferParams.h | 4 +- src/Text3.cpp | 4 +- src/frontends/qt4/GuiDocument.cpp | 20 +- src/frontends/qt4/Menus.cpp | 23 +- src/insets/InsetQuotes.cpp | 571 +++++++++++++++++++++--------- src/insets/InsetQuotes.h | 43 ++- 7 files changed, 462 insertions(+), 223 deletions(-) diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 00cbbedfe8..740bb6bde6 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -128,19 +128,19 @@ ParSepTranslator const & parseptranslator() // Quotes style -typedef Translator QuotesStyleTranslator; +typedef Translator QuotesStyleTranslator; QuotesStyleTranslator const init_quotesstyletranslator() { QuotesStyleTranslator translator - (string_quotes_style[0], InsetQuotes::EnglishQuotes); - translator.addPair(string_quotes_style[1], InsetQuotes::SwedishQuotes); - translator.addPair(string_quotes_style[2], InsetQuotes::GermanQuotes); - translator.addPair(string_quotes_style[3], InsetQuotes::PolishQuotes); - translator.addPair(string_quotes_style[4], InsetQuotes::FrenchQuotes); - translator.addPair(string_quotes_style[5], InsetQuotes::DanishQuotes); - translator.addPair(string_quotes_style[6], InsetQuotes::PlainQuotes); + (string_quotes_style[0], InsetQuotesParams::EnglishQuotes); + translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes); + translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes); + translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes); + translator.addPair(string_quotes_style[4], InsetQuotesParams::FrenchQuotes); + translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes); + translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes); return translator; } @@ -395,7 +395,7 @@ BufferParams::BufferParams() cite_engine_type_ = ENGINE_TYPE_DEFAULT; makeDocumentClass(); paragraph_separation = ParagraphIndentSeparation; - quotes_style = InsetQuotes::EnglishQuotes; + quotes_style = InsetQuotesParams::EnglishQuotes; fontsize = "default"; /* PaperLayout */ @@ -2548,7 +2548,7 @@ Font const BufferParams::getFont() const } -InsetQuotes::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const +InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const { return quotesstyletranslator().find(qs); } diff --git a/src/BufferParams.h b/src/BufferParams.h index d3b6327e31..fec76d06c0 100644 --- a/src/BufferParams.h +++ b/src/BufferParams.h @@ -106,7 +106,7 @@ public: */ ParagraphSeparation paragraph_separation; /// - InsetQuotes::QuoteStyle quotes_style; + InsetQuotesParams::QuoteStyle quotes_style; /// std::string fontsize; /// Get the LayoutFile this document is using. @@ -201,7 +201,7 @@ public: Font const getFont() const; /// translate quote style string to enum value - InsetQuotes::QuoteStyle getQuoteStyle(std::string const & qs) const; + InsetQuotesParams::QuoteStyle getQuoteStyle(std::string const & qs) const; /* these are for the PaperLayout */ /// the papersize diff --git a/src/Text3.cpp b/src/Text3.cpp index 8da40fc7d7..cf90c4d73a 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -1551,8 +1551,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) char_type c = ' '; if (pos > 0 && (!cur.prevInset() || !cur.prevInset()->isSpace())) c = par.getChar(pos - 1); - InsetQuotes::QuoteLevel const quote_level = (cmd.getArg(0) == "single") - ? InsetQuotes::SingleQuotes : InsetQuotes::DoubleQuotes; + InsetQuotesParams::QuoteLevel const quote_level = (cmd.getArg(0) == "single") + ? InsetQuotesParams::SingleQuotes : InsetQuotesParams::DoubleQuotes; cur.insert(new InsetQuotes(cur.buffer(), c, quote_level, cmd.getArg(1), cmd.getArg(2))); cur.buffer()->updateBuffer(); cur.posForward(); diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 33abb3abcc..2e96da4d6e 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -1067,20 +1067,10 @@ GuiDocument::GuiDocument(GuiView & lv) encodinglist.sort(); langModule->encodingCO->addItems(encodinglist); - langModule->quoteStyleCO->addItem( - qt_("``text''"), InsetQuotes::EnglishQuotes); - langModule->quoteStyleCO->addItem( - qt_("''text''"), InsetQuotes::SwedishQuotes); - langModule->quoteStyleCO->addItem - (qt_(",,text``"), InsetQuotes::GermanQuotes); - langModule->quoteStyleCO->addItem( - qt_(",,text''"), InsetQuotes::PolishQuotes); - langModule->quoteStyleCO->addItem( - qt_("<>"), InsetQuotes::FrenchQuotes); - langModule->quoteStyleCO->addItem( - qt_(">>text<<"), InsetQuotes::DanishQuotes); - langModule->quoteStyleCO->addItem( - qt_("\"text\""), InsetQuotes::PlainQuotes); + for (int i = 0; i < quoteparams.stylescount(); ++i) { + InsetQuotesParams::QuoteStyle qs = InsetQuotesParams::QuoteStyle(i); + langModule->quoteStyleCO->addItem(toqstr(quoteparams.getGuiLabel(qs))); + } langModule->languagePackageCO->addItem( qt_("Default"), toqstr("default")); @@ -2660,7 +2650,7 @@ void GuiDocument::applyView() } } - bp_.quotes_style = (InsetQuotes::QuoteStyle) langModule->quoteStyleCO->itemData( + bp_.quotes_style = (InsetQuotesParams::QuoteStyle) langModule->quoteStyleCO->itemData( langModule->quoteStyleCO->currentIndex()).toInt(); QString const langname = langModule->languageCO->itemData( diff --git a/src/frontends/qt4/Menus.cpp b/src/frontends/qt4/Menus.cpp index 25467dbf8f..bca8ea843f 100644 --- a/src/frontends/qt4/Menus.cpp +++ b/src/frontends/qt4/Menus.cpp @@ -1669,7 +1669,7 @@ void MenuDefinition::expandQuotes(BufferView const * bv) InsetQuotes const * qinset = static_cast(inset); - map styles = qinset->getTypes(); + map styles = quoteparams.getTypes(); string const qtype = qinset->getType(); map::const_iterator qq = styles.begin(); @@ -1706,37 +1706,44 @@ void MenuDefinition::expandQuotes(BufferView const * bv) } if (!eqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_("``text''")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::EnglishQuotes))); item.setSubmenu(eqs); add(item); } if (!sqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_("''text''")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::SwedishQuotes))); item.setSubmenu(sqs); add(item); } if (!gqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_(",,text``")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::GermanQuotes))); item.setSubmenu(gqs); add(item); } if (!pqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_(",,text''")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::PolishQuotes))); item.setSubmenu(pqs); add(item); } if (!fqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_("<>")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::FrenchQuotes))); item.setSubmenu(fqs); add(item); } if (!aqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_(">>text<<")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::DanishQuotes))); item.setSubmenu(aqs); add(item); } if (!qqs.empty()) { - MenuItem item(MenuItem::Submenu, qt_("\"text\"")); + MenuItem item(MenuItem::Submenu, + toqstr(quoteparams.getGuiLabel(InsetQuotesParams::PlainQuotes))); item.setSubmenu(qqs); add(item); } diff --git a/src/insets/InsetQuotes.cpp b/src/insets/InsetQuotes.cpp index cc3e3e051e..248d5deab9 100644 --- a/src/insets/InsetQuotes.cpp +++ b/src/insets/InsetQuotes.cpp @@ -4,6 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Jean-Marc Lasgouttes + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -37,8 +38,11 @@ #include "support/debug.h" #include "support/docstring.h" #include "support/docstream.h" +#include "support/gettext.h" #include "support/lstrings.h" +#include + using namespace std; using namespace lyx::support; @@ -47,76 +51,322 @@ namespace lyx { namespace { /* codes used to read/write quotes to LyX files - * e ``english'' - * s ''swedish'' - * g ,,german`` - * p ,,polish'' - * f <> - * a >>danish<< - * q "plain" + * available styles: + * e ``english'' (`inner quotation') + * s ''swedish'' ('inner quotation') + * g ,,german`` (,inner quotation`) + * p ,,polish'' (,inner quotation') + * f <> () + * a >>danish<< (>inner quotation<) + * q "plain" ('inner quotation') */ char const * const style_char = "esgpfaq"; char const * const side_char = "lr" ; char const * const level_char = "sd"; -// List of known quote chars -char const * const quote_char = ",'`<>\""; - -// Unicode characters needed by each quote type -char_type const display_quote_char[2][6] = { - { 0x201a, 0x2019, 0x2018, 0x2039, 0x203a, 0x0027}, - { 0x201e, 0x201d, 0x201c, 0x00ab, 0x00bb, 0x0022} -}; - -// Index of chars used for the quote. Index is [side, style] -int quote_index[2][7] = { - { 2, 1, 0, 0, 3, 4, 5 }, // { ` ' , , < > \" } - { 1, 1, 2, 1, 4, 3, 5 } // { ' ' ` ' > < \" } -}; - -// Corresponding LaTeX code, for double and single quotes. -char const * const latex_quote_t1[2][6] = { - { "\\quotesinglbase", "'", "`", - "\\guilsinglleft", "\\guilsinglright", "\\textquotesingle" }, - { ",,", "''", "``", "<<", ">>", "\\textquotedbl" } -}; - -char const * const latex_quote_ot1[2][6] = { - { "\\quotesinglbase", "'", "`", - "\\guilsinglleft", "\\guilsinglright", "\\textquotesingle" }, - { "\\quotedblbase", "''", "``", - "\\guillemotleft", "\\guillemotright", "\\textquotedbl" } -}; - -char const * const latex_quote_noligatures[2][6] = { - { "\\quotesinglbase", "\\textquoteleft", "\\textquoteright", - "\\guilsinglleft", "\\guilsinglright", "\\textquotesingle" }, - { "\\quotedblbase", "\\textquotedblleft", "\\textquotedblright", - "\\guillemotleft", "\\guillemotright", "\\textquotedbl" } -}; - -char const * const latex_quote_babel[2][6] = { - { "\\glq", "'", "`", "\\flq", "\\frq", "\\textquotesingle" }, - { "\\glqq", "''", "``", "\\flqq", "\\frqq", "\\textquotedbl" } -}; - -char const * const html_quote[2][6] = { - { "‚", "’", "‘", - "‹", "›", "'" }, - { "„", "”", "“", "«", "»", """ } -}; - } // namespace anon +///////////////////////////////////////////////////////////////////// +// +// InsetQuotesParams +// +/////////////////////////////////////////////////////////////////////// + +InsetQuotesParams quoteparams; + + +int InsetQuotesParams::stylescount() const +{ + return strlen(style_char); +} + + +char_type InsetQuotesParams::getQuoteChar(QuoteStyle const & style, QuoteLevel const & level, + QuoteSide const & side) const +{ + // main opening quotation mark + char_type left_primary; + // main closing quotation mark + char_type right_primary; + // secondary (inner, 'single') opening quotation mark + char_type left_secondary; + // secondary (inner, 'single') closing quotation mark + char_type right_secondary; + + switch (style) { + case EnglishQuotes: { + left_primary = 0x201c; // `` + right_primary = 0x201d; // '' + left_secondary = 0x2018; // ` + right_secondary = 0x2019; // ' + break; + } + case SwedishQuotes: { + left_primary = 0x201d; // '' + right_primary = 0x201d; // '' + left_secondary = 0x2019; // ' + right_secondary = 0x2019; // ' + break; + } + case GermanQuotes: { + left_primary = 0x201e; // ,, + right_primary = 0x201c; // `` + left_secondary = 0x201a; // , + right_secondary = 0x2018; // ` + break; + } + case PolishQuotes: { + left_primary = 0x201e; // ,, + right_primary = 0x201d; // '' + left_secondary = 0x201a; // , + right_secondary = 0x2019; // ' + break; + } + case FrenchQuotes: { + left_primary = 0x00ab; // << + right_primary = 0x00bb; // >> + left_secondary = 0x2039; // < + right_secondary = 0x203a; // > + break; + } + case DanishQuotes: { + left_primary = 0x00bb; // >> + right_primary = 0x00ab; // << + left_secondary = 0x203a; // > + right_secondary = 0x2039; // < + break; + } + case PlainQuotes: { + left_primary = 0x0022; // " + right_primary = 0x0022; // " + left_secondary = 0x0027; // ' + right_secondary = 0x0027; // ' + break; + } + default: + // should not happen + left_primary = 0x003f; // ? + right_primary = 0x003f; // ? + left_secondary = 0x003f; // ? + right_secondary = 0x003f; // ? + break; + } + + switch (level) { + case SingleQuotes: + return (side == LeftQuote) ? left_secondary : right_secondary; + case DoubleQuotes: + return (side == LeftQuote) ? left_primary : right_primary; + default: + break; + } + + // should not happen + return 0x003f; +} + + +docstring InsetQuotesParams::getLaTeXQuote(char_type c, string const & op) const +{ + string res; + + switch (c){ + case 0x201a: {// , + if (op == "babel") + res = "\\glq"; + else + res = "\\quotesinglbase"; + break; + } + case 0x2019: {// ' + if (op == "int") + res = "\\textquoteleft"; + else + res = "'"; + break; + } + case 0x2018: {// ` + if (op == "int") + res = "\\textquoteright"; + else + res = "`"; + break; + } + case 0x2039: {// < + if (op == "babel") + res = "\\flq"; + else + res = "\\guilsinglleft"; + break; + } + case 0x203a: {// > + if (op == "babel") + res = "\\frq"; + else + res = "\\guilsinglright"; + break; + } + case 0x0027: {// ' (plain) + res = "\\textquotesingle"; + break; + } + case 0x201e: {// ,, + if (op == "t1") + res = ",,"; + else if (op == "babel") + res = "\\glqq"; + else + res = "\\quotedblbase"; + break; + } + case 0x201d: {// '' + if (op == "int") + res = "\\textquotedblleft"; + else + res = "''"; + break; + } + case 0x201c: {// `` + if (op == "int") + res = "\\textquotedblright"; + else + res = "``"; + break; + } + case 0x00ab: {// << + if (op == "t1") + res = "<<"; + else if (op == "babel") + res = "\\flqq"; + else + res = "\\guillemotleft"; + break; + } + case 0x00bb: {// >> + if (op == "t1") + res = ">>"; + else if (op == "babel") + res = "\\frqq"; + else + res = "\\guillemotright"; + break; + } + case 0x0022: {// " + res = "\\textquotedbl"; + break; + } + default: + break; + } + + return from_ascii(res); +} + + +docstring InsetQuotesParams::getHTMLQuote(char_type c) const +{ + string res; + + switch (c){ + case 0x201a: // , + res = "‚"; + break; + case 0x2019: // ' + res = "’"; + break; + case 0x2018: // ` + res = "‘"; + break; + case 0x2039: // < + res = "‹"; + break; + case 0x203a: // > + res = "›"; + break; + case 0x0027: // ' (plain) + res = "'"; + break; + case 0x201e: // ,, + res = "„"; + break; + case 0x201d: // '' + res = "”"; + break; + case 0x201c: // `` + res = "“"; + break; + case 0x00ab: // << + res = "«"; + break; + case 0x00bb: // >> + res = "»"; + break; + case 0x0022: // " + res = """; + break; + default: + break; + } + + return from_ascii(res); +} + + +map InsetQuotesParams::getTypes() const +{ + map res; + + int sty, sid, lev; + QuoteStyle style; + QuoteSide side; + QuoteLevel level; + string type; + + // get all quote types + for (sty = 0; sty < stylescount(); ++sty) { + style = QuoteStyle(sty); + for (sid = 0; sid < 2; ++sid) { + side = QuoteSide(sid); + for (lev = 0; lev < 2; ++lev) { + type += style_char[style]; + type += side_char[sid]; + level = QuoteLevel(lev); + type += level_char[lev]; + res[type] = docstring(1, getQuoteChar(style, level, side)); + type.clear(); + } + } + } + return res; +} + + +docstring const InsetQuotesParams::getGuiLabel(QuoteStyle const & qs) +{ + return bformat(_("%1$souter%2$s and %3$sinner%4$s[[quotation marks]]"), + docstring(1, quoteparams.getQuoteChar(qs, DoubleQuotes, LeftQuote)), + docstring(1, quoteparams.getQuoteChar(qs, DoubleQuotes, RightQuote)), + docstring(1, quoteparams.getQuoteChar(qs, SingleQuotes, LeftQuote)), + docstring(1, quoteparams.getQuoteChar(qs, SingleQuotes, RightQuote)) + ); +} + + +///////////////////////////////////////////////////////////////////// +// +// InsetQuotes +// +/////////////////////////////////////////////////////////////////////// + InsetQuotes::InsetQuotes(Buffer * buf, string const & str) : Inset(buf) { parseString(str); } -InsetQuotes::InsetQuotes(Buffer * buf, char_type c, QuoteLevel level, +InsetQuotes::InsetQuotes(Buffer * buf, char_type c, InsetQuotesParams::QuoteLevel level, string const & side, string const & style) : Inset(buf), level_(level), pass_thru_(false) { @@ -125,14 +375,14 @@ InsetQuotes::InsetQuotes(Buffer * buf, char_type c, QuoteLevel level, fontenc_ = (buf->params().fontenc == "global") ? lyxrc.fontenc : buf->params().fontenc; } else { - style_ = style.empty() ? EnglishQuotes : getStyle(style); + style_ = style.empty() ? InsetQuotesParams::EnglishQuotes : getStyle(style); fontenc_ = lyxrc.fontenc; } if (side == "left") - side_ = LeftQuote; + side_ = InsetQuotesParams::LeftQuote; else if (side == "right") - side_ = RightQuote; + side_ = InsetQuotesParams::RightQuote; else setSide(c); } @@ -151,10 +401,10 @@ void InsetQuotes::setSide(char_type c) case ' ': case '(': case '[': - side_ = LeftQuote; // left quote + side_ = InsetQuotesParams::LeftQuote; // left quote break; default: - side_ = RightQuote; // right quote + side_ = InsetQuotesParams::RightQuote; // right quote } } @@ -172,16 +422,16 @@ void InsetQuotes::parseString(string const & s, bool const allow_wildcards) // '.' wildcard means: keep current stylee if (!allow_wildcards || str[0] != '.') { - for (i = 0; i < 7; ++i) { + for (i = 0; i < quoteparams.stylescount(); ++i) { if (str[0] == style_char[i]) { - style_ = QuoteStyle(i); + style_ = InsetQuotesParams::QuoteStyle(i); break; } } - if (i >= 7) { - lyxerr << "ERROR (InsetQuotes::InsetQuotes):" - " bad style specification." << endl; - style_ = EnglishQuotes; + if (i >= quoteparams.stylescount()) { + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad style specification."); + style_ = InsetQuotesParams::EnglishQuotes; } } @@ -189,14 +439,14 @@ void InsetQuotes::parseString(string const & s, bool const allow_wildcards) if (!allow_wildcards || str[1] != '.') { for (i = 0; i < 2; ++i) { if (str[1] == side_char[i]) { - side_ = QuoteSide(i); + side_ = InsetQuotesParams::QuoteSide(i); break; } } if (i >= 2) { - lyxerr << "ERROR (InsetQuotes::InsetQuotes):" - " bad side specification." << endl; - side_ = LeftQuote; + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad side specification."); + side_ = InsetQuotesParams::LeftQuote; } } @@ -204,86 +454,58 @@ void InsetQuotes::parseString(string const & s, bool const allow_wildcards) if (!allow_wildcards || str[2] != '.') { for (i = 0; i < 2; ++i) { if (str[2] == level_char[i]) { - level_ = QuoteLevel(i); + level_ = InsetQuotesParams::QuoteLevel(i); break; } } if (i >= 2) { - lyxerr << "ERROR (InsetQuotes::InsetQuotes):" - " bad level specification." << endl; - level_ = DoubleQuotes; + LYXERR0("ERROR (InsetQuotes::InsetQuotes):" + " bad level specification."); + level_ = InsetQuotesParams::DoubleQuotes; } } } -InsetQuotes::QuoteStyle InsetQuotes::getStyle(string const & s) +InsetQuotesParams::QuoteStyle InsetQuotes::getStyle(string const & s) { - QuoteStyle qs = EnglishQuotes; + InsetQuotesParams::QuoteStyle qs = InsetQuotesParams::EnglishQuotes; if (s == "english") - qs = EnglishQuotes; + qs = InsetQuotesParams::EnglishQuotes; else if (s == "swedish") - qs = SwedishQuotes; + qs = InsetQuotesParams::SwedishQuotes; else if (s == "german") - qs = GermanQuotes; + qs = InsetQuotesParams::GermanQuotes; else if (s == "polish") - qs = PolishQuotes; + qs = InsetQuotesParams::PolishQuotes; else if (s == "french") - qs = FrenchQuotes; + qs = InsetQuotesParams::FrenchQuotes; else if (s == "danish") - qs = DanishQuotes; + qs = InsetQuotesParams::DanishQuotes; else if (s == "plain") - qs = PlainQuotes; + qs = InsetQuotesParams::PlainQuotes; return qs; } -map InsetQuotes::getTypes() const -{ - map res; - - int sty, sid, lev; - QuoteStyle style; - QuoteSide side; - QuoteLevel level; - string type; - - // get all quote types - for (sty = 0; sty < 7; ++sty) { - style = QuoteStyle(sty); - for (sid = 0; sid < 2; ++sid) { - side = QuoteSide(sid); - for (lev = 0; lev < 2; ++lev) { - type += style_char[style]; - type += side_char[sid]; - level = QuoteLevel(lev); - type += level_char[lev]; - res[type] = docstring(1, display_quote_char[level][quote_index[side][style]]); - type.clear(); - } - } - } - return res; -} - - docstring InsetQuotes::displayString() const { // In PassThru, we use straight quotes if (pass_thru_) - return (level_ == DoubleQuotes) ? from_ascii("\"") : from_ascii("'"); + return (level_ == InsetQuotesParams::DoubleQuotes) ? + from_ascii("\"") : from_ascii("'"); - int const index = quote_index[side_][style_]; - docstring retdisp = docstring(1, display_quote_char[level_][index]); + docstring retdisp = docstring(1, quoteparams.getQuoteChar(style_, level_, side_)); // in French, thin spaces are added inside double guillemets if (prefixIs(context_lang_, "fr") - && level_ == DoubleQuotes && style_ == FrenchQuotes) { + && level_ == InsetQuotesParams::DoubleQuotes + && style_ == InsetQuotesParams::FrenchQuotes) { // THIN SPACE (U+2009) char_type const thin_space = 0x2009; - if (side_ == LeftQuote) + if (side_ == InsetQuotesParams::LeftQuote) retdisp += thin_space; else retdisp = thin_space + retdisp; @@ -384,28 +606,29 @@ bool InsetQuotes::getStatus(Cursor & cur, FuncRequest const & cmd, void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const { - const int quoteind = quote_index[side_][style_]; + char_type quotechar = quoteparams.getQuoteChar(style_, level_, side_); docstring qstr; // In pass-thru context, we output plain quotes if (runparams.pass_thru) - qstr = (level_ == DoubleQuotes) ? from_ascii("\"") : from_ascii("'"); - else if (style_ == PlainQuotes && runparams.isFullUnicode()) { + qstr = (level_ == InsetQuotesParams::DoubleQuotes) ? from_ascii("\"") : from_ascii("'"); + else if (style_ == InsetQuotesParams::PlainQuotes && runparams.isFullUnicode()) { // For XeTeX and LuaTeX,we need to disable mapping to get straight // quotes. We define our own commands that do this - qstr = (level_ == DoubleQuotes) ? + qstr = (level_ == InsetQuotesParams::DoubleQuotes) ? from_ascii("\\textquotedblplain") : from_ascii("\\textquotesingleplain"); } else if (runparams.use_polyglossia) { // For polyglossia, we directly output the respective unicode chars // (spacing and kerning is then handled respectively) - qstr = docstring(1, display_quote_char[level_][quoteind]); + qstr = docstring(1, quotechar); } - else if (style_ == FrenchQuotes && level_ == DoubleQuotes + else if (style_ == InsetQuotesParams::FrenchQuotes + && level_ == InsetQuotesParams::DoubleQuotes && prefixIs(runparams.local_font->language()->code(), "fr")) { // Specific guillemets of French babel // including correct French spacing - if (side_ == LeftQuote) + if (side_ == InsetQuotesParams::LeftQuote) qstr = from_ascii("\\og"); else qstr = from_ascii("\\fg"); @@ -413,11 +636,11 @@ void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const && !runparams.local_font->language()->internalFontEncoding()) { // Quotation marks for T1 font encoding // (using ligatures) - qstr = from_ascii(latex_quote_t1[level_][quoteind]); + qstr = quoteparams.getLaTeXQuote(quotechar, "t1"); } else if (runparams.local_font->language()->internalFontEncoding()) { // Quotation marks for internal font encodings // (ligatures not featured) - qstr = from_ascii(latex_quote_noligatures[level_][quoteind]); + qstr = quoteparams.getLaTeXQuote(quotechar, "int"); #ifdef DO_USE_DEFAULT_LANGUAGE } else if (doclang == "default") { #else @@ -426,10 +649,10 @@ void InsetQuotes::latex(otexstream & os, OutputParams const & runparams) const // Standard quotation mark macros // These are also used by babel // without fontenc (XeTeX/LuaTeX) - qstr = from_ascii(latex_quote_ot1[level_][quoteind]); + qstr = quoteparams.getLaTeXQuote(quotechar, "ot1"); } else { // Babel shorthand quotation marks (for T1/OT1) - qstr = from_ascii(latex_quote_babel[level_][quoteind]); + qstr = quoteparams.getLaTeXQuote(quotechar, "babel"); } if (!runparams.pass_thru) { @@ -464,14 +687,14 @@ int InsetQuotes::plaintext(odocstringstream & os, docstring InsetQuotes::getQuoteEntity() const { - const int quoteind = quote_index[side_][style_]; - docstring res = from_ascii(html_quote[level_][quoteind]); + docstring res = quoteparams.getHTMLQuote(quoteparams.getQuoteChar(style_, level_, side_)); // in French, thin spaces are added inside double guillemets if (prefixIs(context_lang_, "fr") - && level_ == DoubleQuotes && style_ == FrenchQuotes) { + && level_ == InsetQuotesParams::DoubleQuotes + && style_ == InsetQuotesParams::FrenchQuotes) { // THIN SPACE (U+2009) docstring const thin_space = from_ascii(" "); - if (side_ == LeftQuote) + if (side_ == InsetQuotesParams::LeftQuote) res += thin_space; else res = thin_space + res; @@ -517,62 +740,58 @@ void InsetQuotes::updateBuffer(ParIterator const & it, UpdateType /* utype*/) void InsetQuotes::validate(LaTeXFeatures & features) const { - char type = quote_char[quote_index[side_][style_]]; + char_type type = quoteparams.getQuoteChar(style_, level_, side_); + // Handle characters that are not natively supported by + // specific font encodings (we roll our own definitions) #ifdef DO_USE_DEFAULT_LANGUAGE if (features.bufferParams().language->lang() == "default" #else if (!features.useBabel() #endif && !features.runparams().isFullUnicode() && fontenc_ != "T1") { - if (level_ == SingleQuotes) - switch (type) { - case ',': - features.require("quotesinglbase"); - break; - case '<': - features.require("guilsinglleft"); - break; - case '>': - features.require("guilsinglright"); - break; - default: - break; - } - else - switch (type) { - case ',': - features.require("quotedblbase"); - break; - case '<': - features.require("guillemotleft"); - break; - case '>': - features.require("guillemotright"); - break; - default: - break; - } - } - if (type == '"') { - switch (level_) { - case SingleQuotes: { - if (features.runparams().isFullUnicode()) - features.require("textquotesinglep"); - else - features.require("textcomp"); + switch (type) { + case 0x201a: + features.require("quotesinglbase"); break; - } - case DoubleQuotes: { - if (features.runparams().isFullUnicode()) - features.require("textquotedblp"); - else if (fontenc_ != "T1") - features.require("textquotedbl"); + case 0x2039: + features.require("guilsinglleft"); + break; + case 0x203a: + features.require("guilsinglright"); + break; + case 0x201e: + features.require("quotedblbase"); + break; + case 0x00ab: + features.require("guillemotleft"); + break; + case 0x00bb: + features.require("guillemotright"); break; default: break; } - } + } + // Handle straight quotation marks. These need special care + // in most output formats + switch (type) { + case 0x0027: { + if (features.runparams().isFullUnicode()) + features.require("textquotesinglep"); + else + features.require("textcomp"); + break; + } + case 0x0022: { + if (features.runparams().isFullUnicode()) + features.require("textquotedblp"); + else if (fontenc_ != "T1") + features.require("textquotedbl"); + break; + } + default: + break; } } diff --git a/src/insets/InsetQuotes.h b/src/insets/InsetQuotes.h index 57f3fef1c2..032c111ddb 100644 --- a/src/insets/InsetQuotes.h +++ b/src/insets/InsetQuotes.h @@ -5,6 +5,7 @@ * Licence details can be found in the file COPYING. * * \author Jean-Marc Lasgouttes + * \author Jürgen Spitzmüller * * Full author contact details are available in file CREDITS. */ @@ -22,8 +23,7 @@ namespace lyx { /** Quotes. Used for the various quotes. German, English, French, all either double or single **/ -class InsetQuotes : public Inset -{ +class InsetQuotesParams { public: /// enum QuoteStyle { @@ -56,7 +56,30 @@ public: /// DoubleQuotes }; + /// Returns the unicode character of a given quote + char_type getQuoteChar(QuoteStyle const &, QuoteLevel const &, + QuoteSide const &) const; + /// Returns a map of quotation marks + std::map getTypes() const; + /// + docstring getLaTeXQuote(char_type c, std::string const &) const; + /// + docstring getHTMLQuote(char_type c) const; + /// Returns a label suitable for dialog and menu + docstring const getGuiLabel(QuoteStyle const & qs); + /// + int stylescount() const; +}; +/// +extern InsetQuotesParams quoteparams; + +/** Quotes. + Used for the various quotes. German, English, French, all either + double or single **/ +class InsetQuotes : public Inset +{ +public: /** The constructor works like this: \begin{itemize} \item fls <- french single quote left @@ -66,7 +89,7 @@ public: */ explicit InsetQuotes(Buffer * buf, std::string const & str = "eld"); /// Direct access to inner/outer quotation marks - InsetQuotes(Buffer * buf, char_type c, QuoteLevel level, + InsetQuotes(Buffer * buf, char_type c, InsetQuotesParams::QuoteLevel level, std::string const & side = std::string(), std::string const & style = std::string()); /// @@ -107,11 +130,9 @@ public: InsetCode lyxCode() const { return QUOTE_CODE; } /// should this inset be handled like a normal character bool isChar() const { return true; } - + /// Returns the current quote type std::string getType() const; - /// Returns a map of quotation marks - std::map getTypes() const; private: /// @@ -127,20 +148,22 @@ private: /// docstring getQuoteEntity() const; /// - QuoteStyle getStyle(std::string const &); + InsetQuotesParams::QuoteStyle getStyle(std::string const &); /// - QuoteStyle style_; + InsetQuotesParams::QuoteStyle style_; /// - QuoteSide side_; + InsetQuotesParams::QuoteSide side_; /// - QuoteLevel level_; + InsetQuotesParams::QuoteLevel level_; /// std::string fontenc_; /// Code of the contextual language std::string context_lang_; /// Is this in a pass-thru context? bool pass_thru_; + /// + friend class InsetQuotesParams; protected: /// \name Protected functions inherited from Inset class -- 2.39.2