[LyX/master] Add support for language options (#8034)

Juergen Spitzmueller spitz at lyx.org
Fri Aug 23 13:54:06 UTC 2024


commit 7e49ae7b13180461b1abb956f2c8d3954f4e0fba
Author: Juergen Spitzmueller <spitz at lyx.org>
Date:   Fri Aug 23 15:52:34 2024 +0200

    Add support for language options (#8034)
    
    File format change.
    
    Note that this cannot be properly reverted to LyX 2.4, so any options
    will simply vanish on reversion or roundtrip
---
 development/FORMAT                |   6 ++
 lib/languages                     |   9 ++
 lib/lyx2lyx/lyx_2_5.py            |  18 +++-
 src/BufferParams.cpp              |  77 ++++++++++++++--
 src/BufferParams.h                |  18 +++-
 src/Font.cpp                      |   5 +-
 src/LaTeXFeatures.cpp             |  11 ++-
 src/LaTeXFeatures.h               |   2 +
 src/Language.cpp                  |   6 ++
 src/Language.h                    |   4 +
 src/frontends/qt/GuiDocument.cpp  |  68 ++++++++++++--
 src/frontends/qt/GuiDocument.h    |  13 +++
 src/frontends/qt/ui/LanguageUi.ui | 185 ++++++++++++++++++++------------------
 src/output_latex.cpp              |   8 +-
 src/version.h                     |   4 +-
 15 files changed, 323 insertions(+), 111 deletions(-)

diff --git a/development/FORMAT b/development/FORMAT
index d4015ffa96..79beb356c7 100644
--- a/development/FORMAT
+++ b/development/FORMAT
@@ -7,6 +7,12 @@ changes happened in particular if possible. A good example would be
 
 -----------------------
 
+2024-08-23 Jürgen Spitzmüller <spitz at lyx.org> 
+	* Format incremented to 629: Add support for language options
+	  New buffer params \language_options_babel and
+	  \language_options_polyglossia
+	  These are simply removed on document reversion.
+
 2024-08-21 Jürgen Spitzmüller <spitz at lyx.org> 
 	* Format incremented to 628: Add support for nomentbl-style
 	  nomencl insets:
diff --git a/lib/languages b/lib/languages
index 903bba994b..d62253268d 100644
--- a/lib/languages
+++ b/lib/languages
@@ -8,6 +8,7 @@
 #	GuiName            "<Gui Name>"
 #	HasGuiSupport      <true|false>
 #	BabelName          <babelname>
+#       BabelOptFormat     <format of option specification>
 #	PolyglossiaName    <polyglossianame>
 #	PolyglossiaOpts    "<language-specific options>"
 #	XindyName          <xindyname>
@@ -128,6 +129,10 @@
 #   be de-activated in some contexts (such as - or =).
 # * XindyName holds the value to the (te)xindy -L option. We only give it
 #   if a corresponding language module exists.
+# * BabelOptFormat specifies how the language-specific options shall be
+#   passed with babel (which differs between languages).
+#   Default is \languageattribute{$lang$}{$opts$}
+#   The special value "modifier" indicates to use babel modifiers.
 #
 ##########################################################################
 
@@ -706,6 +711,7 @@ Language french
 	GuiName          "French"
 	HasGuiSupport    true
 	BabelName        french
+	BabelOptFormat   \frenchsetup{$opts§}
 	ActiveChars      ;!?:
 	PolyglossiaName  french
 	XindyName        french
@@ -1038,6 +1044,7 @@ End
 Language latin
 	GuiName          "Latin"
 	BabelName        latin
+	BabelOptFormat   modifier
 	PolyglossiaName  latin
 	XindyName        latin
 	ActiveChars      ^=
@@ -1111,6 +1118,7 @@ Language magyar
 	GuiName          "Hungarian"
 	HasGuiSupport    true
 	BabelName        magyar
+	BabelOptFormat   \magyarOptions{$opts§}
 	PolyglossiaName  magyar
 	XindyName        hungarian
 	QuoteStyle       hungarian
@@ -1420,6 +1428,7 @@ Language spanish
 	GuiName          "Spanish"
 	HasGuiSupport    true
 	BabelName        spanish
+	BabelOptFormat   modifier
 	PolyglossiaName  spanish
 	XindyName        spanish-modern
 	QuoteStyle       french
diff --git a/lib/lyx2lyx/lyx_2_5.py b/lib/lyx2lyx/lyx_2_5.py
index 74a74339c7..67d6519697 100644
--- a/lib/lyx2lyx/lyx_2_5.py
+++ b/lib/lyx2lyx/lyx_2_5.py
@@ -717,7 +717,6 @@ def revert_index_sc(document):
 def revert_nomentbl(document):
     """Revert nomentbl inset to ERT."""
 
-    # intermediate format
     i = find_token(document.header, "\\nomencl_options", 0)
     if i == -1:
         # nothing to do
@@ -860,6 +859,19 @@ def revert_nomentbl(document):
         i += 1
 
 
+def revert_langopts(document):
+    """Remove language options header."""
+
+    i = 0
+    while True:
+        i = find_token(document.header, "\\language_options_", 0)
+        if i == -1:
+            # nothing to do
+            return
+
+        # remove header
+        del document.header[i]
+
 ##
 # Conversion hub
 #
@@ -873,11 +885,13 @@ convert = [
     [625, []],
     [626, []],
     [627, [convert_nomencl, convert_index_sc]],
-    [628, []]
+    [628, []],
+    [629, []]
 ]
 
 
 revert = [
+    [628, [revert_langopts]],
     [627, [revert_nomentbl]],
     [626, [revert_nomencl, revert_index_sc]],
     [625, [revert_nomencl_textwidth]],
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index f14ae84190..9b31218884 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -866,6 +866,18 @@ string BufferParams::readToken(Lexer & lex, string const & token,
 	} else if (token == "\\language_package") {
 		lex.eatLine();
 		lang_package = lex.getString();
+	} else if (token == "\\language_options_babel") {
+		string lang;
+		lex >> lang;
+		lex.eatLine();
+		string const opts = lex.getString();
+		lang_options_babel_[lang] = opts;
+	} else if (token == "\\language_options_polyglossia") {
+		string lang;
+		lex >> lang;
+		lex.eatLine();
+		string const opts = lex.getString();
+		lang_options_polyglossia_[lang] = trim(opts, "\"");
 	} else if (token == "\\inputencoding") {
 		lex >> inputenc;
 	} else if (token == "\\graphics") {
@@ -1358,6 +1370,14 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const
 	// then the text parameters
 	if (language != ignore_language)
 		os << "\\language " << language->lang() << '\n';
+	for (auto const & s : lang_options_babel_)
+		os << "\\language_options_babel " << s.first << " " << s.second << '\n';
+	for (auto const & s : lang_options_polyglossia_) {
+		Language const * l = languages.getLanguage(s.first);
+		if (l && l->polyglossiaOpts() != s.second)
+			// polyglossia options can be empty, so we enquote them
+			os << "\\language_options_polyglossia " << s.first << " \"" << s.second << "\"\n";
+	}
 	os << "\\language_package " << lang_package
 	   << "\n\\inputencoding " << inputenc
 	   << "\n\\fontencoding " << fontenc
@@ -2281,8 +2301,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
 		|| features.isRequired("japanese"))) {
 			os << features.getBabelPresettings();
 			// FIXME UNICODE
-			os << from_utf8(babelCall(language_options.str(),
-									  !lyxrc.language_global_options)) + '\n';
+			os << from_utf8(babelCall(features, language_options.str(),
+						  !lyxrc.language_global_options)) + '\n';
 			os << features.getBabelPostsettings();
 	}
 
@@ -2492,7 +2512,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
 	    && !features.isRequired("japanese")) {
 		os << features.getBabelPresettings();
 		// FIXME UNICODE
-		os << from_utf8(babelCall(language_options.str(),
+		os << from_utf8(babelCall(features, language_options.str(),
 		                          !lyxrc.language_global_options)) + '\n';
 		os << features.getBabelPostsettings();
 	}
@@ -2564,8 +2584,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
 		os << "\\usepackage{polyglossia}\n";
 		// set the main language
 		os << "\\setdefaultlanguage";
-		if (!language->polyglossiaOpts().empty())
-			os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
+		if (!polyglossiaLangOptions(language->lang()).empty())
+			os << "[" << from_ascii(polyglossiaLangOptions(language->lang())) << "]";
 		os << "{" << from_ascii(language->polyglossia()) << "}\n";
 		// now setup the other languages
 		set<string> const polylangs =
@@ -3465,16 +3485,41 @@ vector<string> const BufferParams::font_encodings() const
 }
 
 
-string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
+string BufferParams::babelCall(LaTeXFeatures const & features, string lang_opts,
+			       bool const langoptions) const
 {
 	// suppress the babel call if there is no BabelName defined
 	// for the document language in the lib/languages file and if no
 	// other languages are used (lang_opts is then empty)
 	if (lang_opts.empty())
 		return string();
+	// get language options with modifiers
+	bool have_mods = false;
+	vector<string> blangs;
+	for (auto const & l : features.getLanguages()) {
+		if (l->babel().empty())
+			continue;
+		string blang = l->babel();
+		if (l->babelOptFormat() == "modifier") {
+			vector<string> opts = getVectorFromString(babelLangOptions(l->lang()));
+			bool have_one = false;
+			for (string const & s : opts) {
+				have_mods = true;
+				if (langoptions || have_one)
+					blang += "." + s;
+				else {
+					blang = "modifiers." + blang + "=" + s;
+					have_one = true;
+				}
+			}
+		}
+		blangs.push_back(blang);
+	}
+	if (have_mods)
+		lang_opts = getStringFromVector(blangs);
 	// The prefs may require the languages to
 	// be submitted to babel itself (not the class).
-	if (langoptions)
+	if (langoptions || have_mods)
 		return "\\usepackage[" + lang_opts + "]{babel}";
 	return "\\usepackage{babel}";
 }
@@ -3984,6 +4029,24 @@ string const BufferParams::bibFileEncoding(string const & file) const
 }
 
 
+string const BufferParams::babelLangOptions(string const & lang) const
+{
+	if (lang_options_babel_.find(lang) == lang_options_babel_.end())
+		return string();
+	return lang_options_babel_.find(lang)->second;
+}
+
+
+string const BufferParams::polyglossiaLangOptions(string const & lang) const
+{
+	if (lang_options_polyglossia_.find(lang) == lang_options_polyglossia_.end()) {
+		Language const * l = languages.getLanguage(lang);
+		return l ? l->polyglossiaOpts() : string();
+	}
+	return lang_options_polyglossia_.find(lang)->second;
+}
+
+
 BufferParams const & defaultBufferParams()
 {
 	static BufferParams default_params;
diff --git a/src/BufferParams.h b/src/BufferParams.h
index d7400e2f36..6118688fb0 100644
--- a/src/BufferParams.h
+++ b/src/BufferParams.h
@@ -340,6 +340,20 @@ public:
 	Language const * language;
 	/// language package
 	std::string lang_package;
+	/// babel language options
+	std::map<std::string, std::string> lang_options_babel_;
+	///
+	std::string const babelLangOptions(std::string const & lang) const;
+	///
+	void setBabelLangOptions(std::string const & lang, std::string const & opts)
+		{ lang_options_babel_[lang] = opts; }
+	/// polyglossia language options
+	std::map<std::string, std::string> lang_options_polyglossia_;
+	///
+	std::string const polyglossiaLangOptions(std::string const & lang) const;
+	///
+	void setPolyglossiaLangOptions(std::string const & lang, std::string const & opts)
+		{ lang_options_polyglossia_[lang] = opts; }
 	/// BranchList:
 	BranchList & branchlist();
 	BranchList const & branchlist() const;
@@ -505,7 +519,9 @@ public:
 	std::string paperSizeName(PapersizePurpose purpose,
 				  std::string const & psize = std::string()) const;
 	/// set up if and how babel is called
-	std::string babelCall(std::string const & lang_opts, bool const langoptions) const;
+	std::string babelCall(LaTeXFeatures const & features,
+			      std::string lang_opts,
+			      bool const langoptions) const;
 	/// return supported drivers for specific packages
 	docstring getGraphicsDriver(std::string const & package) const;
 	/// handle inputenc etc.
diff --git a/src/Font.cpp b/src/Font.cpp
index 748a8df92c..5fc47553fb 100644
--- a/src/Font.cpp
+++ b/src/Font.cpp
@@ -242,8 +242,9 @@ int Font::latexWriteStartChanges(otexstream & os, BufferParams const & bparams,
 			if (needs_cprotection)
 				tmp += "\\cprotect";
 			tmp += "\\text" + language()->polyglossia();
-			if (!language()->polyglossiaOpts().empty()) {
-				tmp += "[" + language()->polyglossiaOpts() + "]";
+			string const opts = bparams.polyglossiaLangOptions(language()->lang());
+			if (!opts.empty()) {
+				tmp += "[" + opts + "]";
 				if (runparams.use_hyperref && runparams.moving_arg) {
 					// We need to strip the command for
 					// the pdf string, see #11813
diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp
index a6fc73ecc9..2e1ed4328d 100644
--- a/src/LaTeXFeatures.cpp
+++ b/src/LaTeXFeatures.cpp
@@ -1816,9 +1816,18 @@ docstring const LaTeXFeatures::getBabelPostsettings() const
 {
 	odocstringstream tmp;
 
-	for (auto const & lang : UsedLanguages_)
+	for (auto const & lang : UsedLanguages_) {
 		if (!lang->babel_postsettings().empty())
 			tmp << lang->babel_postsettings() << '\n';
+		if (lang->babelOptFormat() != "modifier") {
+			// user-set options
+			string const opts = bufferParams().babelLangOptions(lang->lang());
+			if (!opts.empty())
+				tmp << from_utf8(subst(subst(lang->babelOptFormat(), "$lang$",
+							     lang->babel()), "$opts$", opts))
+				    << '\n';
+		}
+	}
 	if (!params_.language->babel_postsettings().empty())
 		tmp << params_.language->babel_postsettings() << '\n';
 
diff --git a/src/LaTeXFeatures.h b/src/LaTeXFeatures.h
index 10f7c320f0..50f063909d 100644
--- a/src/LaTeXFeatures.h
+++ b/src/LaTeXFeatures.h
@@ -133,6 +133,8 @@ public:
 	/// A vector of all used languages supported only by babel
 	std::vector<std::string> getBabelExclusiveLanguages() const;
 	///
+	std::set<Language const *> getLanguages() const { return UsedLanguages_; }
+	///
 	std::string getBabelLanguages() const;
 	///
 	std::set<std::string> getPolyglossiaLanguages() const;
diff --git a/src/Language.cpp b/src/Language.cpp
index 60b897c134..5fe1482fa8 100644
--- a/src/Language.cpp
+++ b/src/Language.cpp
@@ -131,6 +131,7 @@ bool Language::readLanguage(Lexer & lex)
 {
 	enum LanguageTags {
 		LA_BABELNAME = 1,
+		LA_BABELOPTFORMAT,
 		LA_DATEFORMATS,
 		LA_ENCODING,
 		LA_END,
@@ -157,6 +158,7 @@ bool Language::readLanguage(Lexer & lex)
 	LexerKeyword languageTags[] = {
 		{ "activechars",          LA_ACTIVECHARS },
 		{ "babelname",            LA_BABELNAME },
+		{ "babeloptformat",       LA_BABELOPTFORMAT },
 		{ "dateformats",          LA_DATEFORMATS },
 		{ "encoding",             LA_ENCODING },
 		{ "end",                  LA_END },
@@ -204,6 +206,9 @@ bool Language::readLanguage(Lexer & lex)
 		case LA_BABELNAME:
 			lex >> babel_;
 			break;
+		case LA_BABELOPTFORMAT:
+			lex >> babeloptformat_;
+			break;
 		case LA_POLYGLOSSIANAME:
 			lex >> polyglossia_name_;
 			break;
@@ -283,6 +288,7 @@ bool Language::read(Lexer & lex)
 	encoding_ = nullptr;
 	internal_enc_ = false;
 	rightToLeft_ = false;
+	babeloptformat_ = "\\languageattribute{$lang$}{$opts$}";
 
 	if (!lex.next()) {
 		lex.printError("No name given for language: `$$Token'.");
diff --git a/src/Language.h b/src/Language.h
index d8ef03a125..1d1b7f0ead 100644
--- a/src/Language.h
+++ b/src/Language.h
@@ -43,6 +43,8 @@ public:
 	std::string const lang() const { return lang_; }
 	/// Babel language name
 	std::string const babel() const { return babel_; }
+	/// Babel option format
+	std::string const babelOptFormat() const { return babeloptformat_; }
 	/// polyglossia language name
 	std::string const polyglossia() const { return polyglossia_name_; }
 	/// polyglossia language options
@@ -116,6 +118,8 @@ private:
 	///
 	trivstring babel_;
 	///
+	trivstring babeloptformat_;
+	///
 	trivstring polyglossia_name_;
 	///
 	trivstring polyglossia_opts_;
diff --git a/src/frontends/qt/GuiDocument.cpp b/src/frontends/qt/GuiDocument.cpp
index 20bacc228a..151d0a5913 100644
--- a/src/frontends/qt/GuiDocument.cpp
+++ b/src/frontends/qt/GuiDocument.cpp
@@ -1008,12 +1008,16 @@ GuiDocument::GuiDocument(GuiView & lv)
 		this, SLOT(change_adaptor()));
 	connect(langModule->languagePackageCO, SIGNAL(activated(int)),
 		this, SLOT(change_adaptor()));
+	connect(langModule->languagePackageCO, SIGNAL(activated(int)),
+		this, SLOT(updateLanguageOptions()));
 	connect(langModule->languagePackageLE, SIGNAL(textChanged(QString)),
 		this, SLOT(change_adaptor()));
 	connect(langModule->languagePackageCO, SIGNAL(currentIndexChanged(int)),
 		this, SLOT(languagePackageChanged(int)));
 	connect(langModule->dynamicQuotesCB, SIGNAL(clicked()),
 		this, SLOT(change_adaptor()));
+	connect(langModule->languageOptionsTW, SIGNAL(itemChanged(QTreeWidgetItem*, int)),
+		this, SLOT(change_adaptor()));
 
 	langModule->languagePackageLE->setValidator(new NoNewLineValidator(
 		langModule->languagePackageLE));
@@ -1074,12 +1078,10 @@ GuiDocument::GuiDocument(GuiView & lv)
 		else
 			encodingmap.insert(qt_(encvar.guiName()), toqstr(encvar.name()));
 	}
-	for (auto const & i : encodingmap_utf8.keys()) {
+	for (auto const & i : encodingmap_utf8.keys())
 		langModule->unicodeEncodingCO->addItem(i, encodingmap_utf8.value(i));
-	}
-	for (auto const & i : encodingmap.keys()) {
+	for (auto const & i : encodingmap.keys())
 		langModule->customEncodingCO->addItem(i, encodingmap.value(i));
-	}
 	// equalise the width of encoding selectors
 	langModule->autoEncodingCO->setMinimumSize(
 		langModule->unicodeEncodingCO->minimumSizeHint());
@@ -1096,7 +1098,7 @@ GuiDocument::GuiDocument(GuiView & lv)
 		qt_("Custom"), toqstr("custom"));
 	langModule->languagePackageCO->addItem(
 		qt_("None[[language package]]"), toqstr("none"));
-
+	langModule->languageOptionsTW->setItemDelegateForColumn(0, new NoEditDelegate(this));
 
 	// fonts
 	fontModule = new FontModule(this);
@@ -1190,6 +1192,8 @@ GuiDocument::GuiDocument(GuiView & lv)
 			qt_("Use OpenType and TrueType fonts directly (requires XeTeX or LuaTeX)\n"
 			    "You need to install the package \"fontspec\" to use this feature"));
 
+	// this requires font to be set
+	updateLanguageOptions();
 
 	// page layout
 	pageLayoutModule = new UiWidget<Ui::PageLayoutUi>(this);
@@ -2623,6 +2627,7 @@ void GuiDocument::osFontsChanged(bool nontexfonts)
 		fontModule->fontencLE->setEnabled(false);
 	else
 		fontencChanged(fontModule->fontencCO->currentIndex());
+	updateLanguageOptions();
 }
 
 
@@ -2839,6 +2844,36 @@ void GuiDocument::updateTexFonts()
 }
 
 
+void GuiDocument::updateLanguageOptions()
+{
+	langModule->languageOptionsTW->clear();
+	QString const langpack = langModule->languagePackageCO->itemData(
+				langModule->languagePackageCO->currentIndex()).toString();
+	if (langpack == "custom")
+		return;
+
+	bool const extern_babel =
+		documentClass().provides("babel");
+	bool const extern_polyglossia =
+		documentClass().provides("polyglossia");
+
+	bool const use_polyglossia = extern_polyglossia
+			|| (langpack != "babel" && !extern_babel
+			    && fontModule->osFontsCB->isChecked());
+	for (auto const & l : buffer().getLanguages()) {
+		QTreeWidgetItem * twi = new QTreeWidgetItem();
+		twi->setData(0, Qt::DisplayRole, qt_(l->display()));
+		twi->setData(0, Qt::UserRole, toqstr(l->lang()));
+		twi->setFlags(twi->flags() | Qt::ItemIsEditable);
+		if (use_polyglossia)
+			twi->setData(1, Qt::EditRole, toqstr(buffer().params().polyglossiaLangOptions(l->lang())));
+		else
+			twi->setData(1, Qt::EditRole, toqstr(buffer().params().babelLangOptions(l->lang())));
+		langModule->languageOptionsTW->addTopLevelItem(twi);
+	}
+}
+
+
 void GuiDocument::updateFontlist()
 {
 	// reset the filters of the CategorizedCombos
@@ -3764,6 +3799,25 @@ void GuiDocument::applyView()
 	else
 		bp_.lang_package = fromqstr(pack);
 
+	bool const extern_babel =
+		documentClass().provides("babel");
+	bool const extern_polyglossia =
+		documentClass().provides("polyglossia");
+
+	bool const use_polyglossia = extern_polyglossia
+			|| (bp_.lang_package != "babel" && !extern_babel
+			    && fontModule->osFontsCB->isChecked());
+
+	QList<QTreeWidgetItem *> langopts = langModule->languageOptionsTW->findItems("*", Qt::MatchWildcard);
+	for (int i = 0; i < langopts.size(); ++i) {
+		if (use_polyglossia)
+			bp_.setPolyglossiaLangOptions(fromqstr(langopts.at(i)->data(0, Qt::UserRole).toString()),
+						      fromqstr(langopts.at(i)->data(1, Qt::EditRole).toString()));
+		else
+			bp_.setBabelLangOptions(fromqstr(langopts.at(i)->data(0, Qt::UserRole).toString()),
+						fromqstr(langopts.at(i)->data(1, Qt::EditRole).toString()));
+	}
+
 	//color
 	bp_.backgroundcolor = set_backgroundcolor;
 	bp_.isbackgroundcolor = is_backgroundcolor;
@@ -4311,7 +4365,7 @@ void GuiDocument::paramsToDialog()
 	if (extern_babel)
 		p = langModule->languagePackageCO->findData(toqstr("babel"));
 	else if (extern_polyglossia)
-		p = langModule->languagePackageCO->findData(toqstr("polyglossia"));
+		p = langModule->languagePackageCO->findData(toqstr("auto"));
 	else
 		p = langModule->languagePackageCO->findData(toqstr(bp_.lang_package));
 
@@ -4325,6 +4379,8 @@ void GuiDocument::paramsToDialog()
 	}
 	langModule->languagePackageCO->setEnabled(!extern_babel && !extern_polyglossia);
 
+	updateLanguageOptions();
+
 	//color
 	if (bp_.isfontcolor) {
 		colorModule->mainTextCF->setStyleSheet(
diff --git a/src/frontends/qt/GuiDocument.h b/src/frontends/qt/GuiDocument.h
index 28d41d777a..3e49fa663d 100644
--- a/src/frontends/qt/GuiDocument.h
+++ b/src/frontends/qt/GuiDocument.h
@@ -43,6 +43,7 @@
 #include "support/unique_ptr.h"
 
 #include <QStandardItemModel>
+#include <QStyledItemDelegate>
 
 namespace lyx {
 
@@ -75,6 +76,17 @@ public:
 	UiWidget(QWidget * parent) : QWidget(parent) { UI::setupUi(this); }
 };
 
+// use to make single QTreeWidget column editable
+// courtesy of https://stackoverflow.com/a/4657065
+class NoEditDelegate : public QStyledItemDelegate {
+public:
+	NoEditDelegate(QObject* parent=0): QStyledItemDelegate(parent) {}
+	virtual QWidget* createEditor(QWidget *, const QStyleOptionViewItem &, const QModelIndex &) const
+	{
+		return 0;
+	}
+};
+
 
 class GuiDocument : public GuiDialog, public Ui::DocumentUi
 {
@@ -173,6 +185,7 @@ private Q_SLOTS:
 	void setOutputSync(bool);
 	void bookmarksopenChanged(bool);
 	void changeTrackingChanged(bool);
+	void updateLanguageOptions();
 private:
 	/// validate listings parameters and return an error message, if any
 	QString validateListingsParameters();
diff --git a/src/frontends/qt/ui/LanguageUi.ui b/src/frontends/qt/ui/LanguageUi.ui
index f1ba383f6e..b5c0aab1ee 100644
--- a/src/frontends/qt/ui/LanguageUi.ui
+++ b/src/frontends/qt/ui/LanguageUi.ui
@@ -7,80 +7,13 @@
     <x>0</x>
     <y>0</y>
     <width>472</width>
-    <height>316</height>
+    <height>413</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string/>
   </property>
   <layout class="QGridLayout" name="gridLayout_4">
-   <item row="0" column="0">
-    <layout class="QGridLayout" name="gridLayout_2">
-     <item row="0" column="0">
-      <widget class="QLabel" name="languageL">
-       <property name="text">
-        <string>&Language:</string>
-       </property>
-       <property name="buddy">
-        <cstring>languageCO</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QComboBox" name="languageCO">
-       <property name="maxVisibleItems">
-        <number>20</number>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QLabel" name="typeL">
-       <property name="text">
-        <string>&Quote style:</string>
-       </property>
-       <property name="buddy">
-        <cstring>quoteStyleCO</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="1">
-      <widget class="QComboBox" name="quoteStyleCO">
-       <property name="toolTip">
-        <string>Select the default quotation marks style</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="0">
-      <layout class="QHBoxLayout" name="horizontalLayout"/>
-     </item>
-     <item row="2" column="1">
-      <widget class="QCheckBox" name="dynamicQuotesCB">
-       <property name="toolTip">
-        <string>Output quotation marks that automatically adapt to the style selected above. If this is not selected, the quotation marks will stick with the style they have been inserted with.</string>
-       </property>
-       <property name="text">
-        <string>Use d&ynamic quotation marks</string>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item row="0" column="1">
-    <spacer>
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="sizeType">
-      <enum>QSizePolicy::MinimumExpanding</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>0</width>
-       <height>23</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
    <item row="1" column="0">
     <widget class="QGroupBox" name="encodingGB">
      <property name="title">
@@ -157,18 +90,56 @@
      </layout>
     </widget>
    </item>
-   <item row="1" column="1">
-    <spacer name="horizontalSpacer">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>0</width>
-       <height>20</height>
-      </size>
-     </property>
-    </spacer>
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout_2">
+     <item row="0" column="0">
+      <widget class="QLabel" name="languageL">
+       <property name="text">
+        <string>&Language:</string>
+       </property>
+       <property name="buddy">
+        <cstring>languageCO</cstring>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QComboBox" name="languageCO">
+       <property name="maxVisibleItems">
+        <number>20</number>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="typeL">
+       <property name="text">
+        <string>&Quote style:</string>
+       </property>
+       <property name="buddy">
+        <cstring>quoteStyleCO</cstring>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QComboBox" name="quoteStyleCO">
+       <property name="toolTip">
+        <string>Select the default quotation marks style</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <layout class="QHBoxLayout" name="horizontalLayout"/>
+     </item>
+     <item row="2" column="1">
+      <widget class="QCheckBox" name="dynamicQuotesCB">
+       <property name="toolTip">
+        <string>Output quotation marks that automatically adapt to the style selected above. If this is not selected, the quotation marks will stick with the style they have been inserted with.</string>
+       </property>
+       <property name="text">
+        <string>Use d&ynamic quotation marks</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
    </item>
    <item row="2" column="0" colspan="2">
     <layout class="QHBoxLayout" name="horizontalLayout_2">
@@ -199,7 +170,7 @@
      <item>
       <spacer name="horizontalSpacer_2">
        <property name="orientation">
-        <enum>Qt::Horizontal</enum>
+        <enum>Qt::Orientation::Horizontal</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
@@ -211,18 +182,60 @@
      </item>
     </layout>
    </item>
-   <item row="3" column="0">
+   <item row="1" column="1">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Orientation::Horizontal</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>0</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QGroupBox" name="langaugeOptsGB">
+     <property name="title">
+      <string>Language &Options</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_5">
+      <item row="0" column="0">
+       <widget class="QTreeWidget" name="languageOptionsTW">
+        <property name="headerHidden">
+         <bool>false</bool>
+        </property>
+        <property name="columnCount">
+         <number>2</number>
+        </property>
+        <column>
+         <property name="text">
+          <string>Language</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Options</string>
+         </property>
+        </column>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="0" column="1">
     <spacer>
      <property name="orientation">
-      <enum>Qt::Vertical</enum>
+      <enum>Qt::Orientation::Horizontal</enum>
      </property>
      <property name="sizeType">
-      <enum>QSizePolicy::Expanding</enum>
+      <enum>QSizePolicy::Policy::MinimumExpanding</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
-       <width>71</width>
-       <height>171</height>
+       <width>0</width>
+       <height>23</height>
       </size>
      </property>
     </spacer>
diff --git a/src/output_latex.cpp b/src/output_latex.cpp
index f6026a6da6..478c99698d 100644
--- a/src/output_latex.cpp
+++ b/src/output_latex.cpp
@@ -255,7 +255,7 @@ static TeXEnvironmentData prepareEnvironment(Buffer const & buf,
 		    !par_lang.empty()) {
 			    string bc = use_polyglossia ?
 					getPolyglossiaBegin(lang_begin_command, par_lang,
-							    data.par_language->polyglossiaOpts())
+							    bparams.polyglossiaLangOptions(data.par_language->lang()))
 				      : subst(lang_begin_command, "$$lang", par_lang);
 			    os << bc;
 			    // the '%' is necessary to prevent unwanted whitespace
@@ -1091,7 +1091,7 @@ void TeXOnePar(Buffer const & buf,
 			    && !par_lang.empty()) {
 				string bc = use_polyglossia ?
 					  getPolyglossiaBegin(lang_begin_command, par_lang,
-					  		      par_language->polyglossiaOpts(),
+							      bparams.polyglossiaLangOptions(par_language->lang()),
 					  		      localswitch)
 					  : subst(lang_begin_command, "$$lang", par_lang);
 				os << bc;
@@ -1357,7 +1357,7 @@ void TeXOnePar(Buffer const & buf,
 				    && current_lang != openLanguageName(state)) {
 					string bc = use_polyglossia ?
 						    getPolyglossiaBegin(lang_begin_command, current_lang,
-									current_language->polyglossiaOpts(),
+									bparams.polyglossiaLangOptions(current_language->lang()),
 									localswitch)
 						  : subst(lang_begin_command, "$$lang", current_lang);
 					os << bc;
@@ -1651,7 +1651,7 @@ void latexParagraphs(Buffer const & buf,
 		// FIXME UNICODE
 		string bc = runparams.use_polyglossia ?
 			    getPolyglossiaBegin(lang_begin_command, mainlang,
-						bparams.language->polyglossiaOpts())
+						bparams.polyglossiaLangOptions(bparams.language->lang()))
 			  : subst(lang_begin_command, "$$lang", mainlang);
 		os << bc;
 		os << '\n';
diff --git a/src/version.h b/src/version.h
index 132b939451..67ff1b79c6 100644
--- a/src/version.h
+++ b/src/version.h
@@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-#define LYX_FORMAT_LYX 628 // spitz: nomentbl
-#define LYX_FORMAT_TEX2LYX 628
+#define LYX_FORMAT_LYX 629 // spitz: language options
+#define LYX_FORMAT_TEX2LYX 629
 
 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
 #ifndef _MSC_VER


More information about the lyx-cvs mailing list