]> git.lyx.org Git - lyx.git/blobdiff - src/LaTeXFeatures.cpp
Add babelbib, bibgerm, chscite, and opcit to LaTeXFeatures.
[lyx.git] / src / LaTeXFeatures.cpp
index 347a703ba89ee40e9af85dfbf1755adf62d99ebd..4cbdea6953eee8c10a71152dd55642932edb3d5a 100644 (file)
@@ -24,6 +24,8 @@
 #include "Floating.h"
 #include "FloatList.h"
 #include "Language.h"
+#include "LaTeXFonts.h"
+#include "LaTeXPackages.h"
 #include "Layout.h"
 #include "Lexer.h"
 #include "LyXRC.h"
@@ -37,6 +39,7 @@
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lstrings.h"
+#include "support/regex.h"
 
 #include <algorithm>
 
@@ -160,7 +163,7 @@ static docstring const mathcircumflex_def = from_ascii(
 static docstring const tabularnewline_def = from_ascii(
        "%% Because html converters don't know tabularnewline\n"
        "\\providecommand{\\tabularnewline}{\\\\}\n");
-       
+
 static docstring const lyxgreyedout_def = from_ascii(
        "%% The greyedout annotation environment\n"
        "\\newenvironment{lyxgreyedout}\n"
@@ -181,19 +184,19 @@ static docstring const changetracking_dvipost_def = from_ascii(
        "\\dvipost{osend color pop}\n"
        "\\dvipost{cbstart color push Blue}\n"
        "\\dvipost{cbend color pop}\n"
-       "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
-       "\\newcommand{\\lyxdeleted}[3]{%\n"
+       "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
+       "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n"
        "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
 
 static docstring const changetracking_xcolor_ulem_def = from_ascii(
        "%% Change tracking with ulem\n"
-       "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
-       "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
+       "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
+       "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
 
 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
        "%% Change tracking with ulem\n"
-       "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
-       "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
+       "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
+       "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
 
 static docstring const changetracking_none_def = from_ascii(
        "\\newcommand{\\lyxadded}[3]{#3}\n"
@@ -265,23 +268,76 @@ static docstring const ogonek_def = from_ascii(
 
 static docstring const lyxref_def = from_ascii(
                "\\RS@ifundefined{subref}\n"
-               "  {\\def\\RSsubtxt{section~}\\newref{sub}{name = \\RSsubtxt}}\n" 
+               "  {\\def\\RSsubtxt{section~}\\newref{sub}{name = \\RSsubtxt}}\n"
                "  {}\n"
                "\\RS@ifundefined{thmref}\n"
-               "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n" 
+               "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
                "  {}\n"
                "\\RS@ifundefined{lemref}\n"
                "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n" 
                "  {}\n");
 
+// Make sure the columns are also outputed as rtl
+static docstring const rtloutputdblcol_def = from_ascii(
+       "\\def\\@outputdblcol{%\n"
+       "  \\if@firstcolumn\n"
+       "    \\global \\@firstcolumnfalse\n"
+       "    \\global \\setbox\\@leftcolumn \\box\\@outputbox\n"
+       "  \\else\n"
+       "    \\global \\@firstcolumntrue\n"
+       "    \\setbox\\@outputbox \\vbox {%\n"
+       "      \\hb@xt@\\textwidth {%\n"
+       "      \\kern\\textwidth \\kern-\\columnwidth %**\n"
+       "      \\hb@xt@\\columnwidth {%\n"
+       "         \\box\\@leftcolumn \\hss}%\n"
+       "      \\kern-\\textwidth %**\n"
+       "      \\hfil\n"
+       "      {\\normalcolor\\vrule \\@width\\columnseprule}%\n"
+       "      \\hfil\n"
+       "      \\kern-\\textwidth  %**\n"
+       "      \\hb@xt@\\columnwidth {%\n"
+       "         \\box\\@outputbox \\hss}%\n"
+       "      \\kern-\\columnwidth \\kern\\textwidth %**\n"
+       "    }%\n"
+       "  }%\n"
+       "  \\@combinedblfloats\n"
+       "  \\@outputpage\n"
+       "  \\begingroup\n"
+       "  \\@dblfloatplacement\n"
+       "  \\@startdblcolumn\n"
+       "  \\@whilesw\\if@fcolmade \\fi\n"
+       "  {\\@outputpage\n"
+       "    \\@startdblcolumn}%\n"
+       "  \\endgroup\n"
+       "  \\fi\n"
+       "}\n"
+       "\\@mparswitchtrue\n");
+
 
 /////////////////////////////////////////////////////////////////////
 //
-// LaTeXFeatures
+// LyXHTML strings
 //
 /////////////////////////////////////////////////////////////////////
 
-LaTeXFeatures::Packages LaTeXFeatures::packages_;
+static docstring const lyxnoun_style = from_ascii(
+       "dfn.lyxnoun {\n"
+  "  font-variant: small-caps;\n"
+  "}\n");
+
+
+// this is how it normally renders, but it might not always do so.
+static docstring const lyxstrikeout_style = from_ascii(
+       "del.strikeout {\n"
+  "  text-decoration: line-through;\n"
+  "}\n");
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// LaTeXFeatures
+//
+/////////////////////////////////////////////////////////////////////
 
 
 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
@@ -290,35 +346,70 @@ LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
 {}
 
 
-bool LaTeXFeatures::useBabel() const
+LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
 {
-       if (usePolyglossia())
-               return false;
-       if (bufferParams().lang_package == "default")
-               return (lyxrc.language_package_selection != LyXRC::LP_NONE)
-                       || (bufferParams().language->lang() != lyxrc.default_language
-                           && !bufferParams().language->babel().empty())
-                       || this->hasLanguages();
-       return (bufferParams().lang_package != "none")
-               || (bufferParams().language->lang() != lyxrc.default_language
-                   && !bufferParams().language->babel().empty())
-               || this->hasLanguages();
-}
+       string const local_lp = bufferParams().lang_package;
+
+       // Locally, custom is just stored as a string
+       // in bufferParams().lang_package.
+       if (local_lp != "auto"
+           && local_lp != "babel"
+           && local_lp != "default"
+           && local_lp != "none")
+                return LANG_PACK_CUSTOM;
+
+       if (local_lp == "none")
+               return LANG_PACK_NONE;
+
+       /* If "auto" is selected, we load polyglossia if required,
+        * else we select babel.
+        * If babel is selected (either directly or via the "auto"
+        * mechanism), we really do only require it if we have
+        * a language that needs it.
+        */
+       bool const polyglossia_required =
+               isRequired("polyglossia")
+               && isAvailable("polyglossia")
+               && !isProvided("babel")
+               && this->hasOnlyPolyglossiaLanguages();
+       bool const babel_required = 
+               !bufferParams().language->babel().empty()
+               || !this->getBabelLanguages().empty();
+
+       if (local_lp == "auto") {
+               // polyglossia requirement has priority over babel
+               if (polyglossia_required)
+                       return LANG_PACK_POLYGLOSSIA;
+               else if (babel_required)
+                       return LANG_PACK_BABEL;
+       }
+
+       if (local_lp == "babel") {
+               if (babel_required)
+                       return LANG_PACK_BABEL;
+       }
 
+       if (local_lp == "default") {
+               switch (lyxrc.language_package_selection) {
+               case LyXRC::LP_AUTO:
+                       // polyglossia requirement has priority over babel
+                       if (polyglossia_required)
+                               return LANG_PACK_POLYGLOSSIA;
+                       else if (babel_required)
+                               return LANG_PACK_BABEL;
+                       break;
+               case LyXRC::LP_BABEL:
+                       if (babel_required)
+                               return LANG_PACK_BABEL;
+                       break;
+               case LyXRC::LP_CUSTOM:
+                       return LANG_PACK_CUSTOM;
+               case LyXRC::LP_NONE:
+                       return LANG_PACK_NONE;
+               }
+       }
 
-bool LaTeXFeatures::usePolyglossia() const
-{
-       if (bufferParams().lang_package == "default")
-               return (lyxrc.language_package_selection == LyXRC::LP_AUTO)
-                       && isRequired("polyglossia")
-                       && isAvailable("polyglossia")
-                       && !params_.documentClass().provides("babel")
-                       && this->hasPolyglossiaLanguages();
-       return (bufferParams().lang_package == "auto")
-               && isRequired("polyglossia")
-               && isAvailable("polyglossia")
-               && !params_.documentClass().provides("babel")
-               && this->hasPolyglossiaLanguages();
+       return LANG_PACK_NONE;
 }
 
 
@@ -334,36 +425,6 @@ void LaTeXFeatures::require(set<string> const & names)
 }
 
 
-void LaTeXFeatures::getAvailable()
-{
-       Lexer lex;
-       support::FileName const real_file = libFileSearch("", "packages.lst");
-
-       if (real_file.empty())
-               return;
-
-       lex.setFile(real_file);
-
-       if (!lex.isOK())
-               return;
-
-       // Make sure that we are clean
-       packages_.clear();
-
-       bool finished = false;
-       // Parse config-file
-       while (lex.isOK() && !finished) {
-               switch (lex.lex()) {
-               case Lexer::LEX_FEOF:
-                       finished = true;
-                       break;
-               default:
-                       packages_.insert(lex.getString());
-               }
-       }
-}
-
-
 void LaTeXFeatures::useLayout(docstring const & layoutname)
 {
        // Some code to avoid loops in dependency definition
@@ -379,7 +440,7 @@ void LaTeXFeatures::useLayout(docstring const & layoutname)
        DocumentClass const & tclass = params_.documentClass();
        if (tclass.hasLayout(layoutname)) {
                // Is this layout already in usedLayouts?
-               if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
+               if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
                    != usedLayouts_.end())
                        return;
 
@@ -411,7 +472,7 @@ void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
        if (!tclass.hasInsetLayout(lname))
                return;
        // Is this layout already in usedInsetLayouts?
-       if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname) 
+       if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
                        != usedInsetLayouts_.end())
                return;
 
@@ -426,9 +487,39 @@ bool LaTeXFeatures::isRequired(string const & name) const
 }
 
 
+bool LaTeXFeatures::isProvided(string const & name) const
+{
+       if (params_.useNonTeXFonts)
+               return params_.documentClass().provides(name);
+
+       bool const ot1 = (params_.font_encoding() == "default"
+               || params_.font_encoding() == "OT1");
+       bool const complete = (params_.fonts_sans == "default")
+               && (params_.fonts_typewriter == "default");
+       bool const nomath = (params_.fonts_math == "default");
+       return params_.documentClass().provides(name)
+               || theLaTeXFonts().getLaTeXFont(
+                       from_ascii(params_.fonts_roman)).provides(name, ot1,
+                                                                 complete,
+                                                                 nomath)
+               || theLaTeXFonts().getLaTeXFont(
+                       from_ascii(params_.fonts_sans)).provides(name, ot1,
+                                                                complete,
+                                                                nomath)
+               || theLaTeXFonts().getLaTeXFont(
+                       from_ascii(params_.fonts_typewriter)).provides(name, ot1,
+                                                                      complete,
+                                                                      nomath)
+               || theLaTeXFonts().getLaTeXFont(
+                       from_ascii(params_.fonts_math)).provides(name, ot1,
+                                                                      complete,
+                                                                      nomath);
+}
+
+
 bool LaTeXFeatures::mustProvide(string const & name) const
 {
-       return isRequired(name) && !params_.documentClass().provides(name);
+       return isRequired(name) && !isProvided(name);
 }
 
 
@@ -441,13 +532,7 @@ bool LaTeXFeatures::isAvailable(string const & name)
                //LYXERR0("from=[" << from << "] to=[" << to << "]");
                return theConverters().isReachable(from, to);
        }
-
-       if (packages_.empty())
-               getAvailable();
-       string n = name;
-       if (suffixIs(n, ".sty"))
-               n.erase(name.length() - 4);
-       return packages_.find(n) != packages_.end();
+       return LaTeXPackages::isAvailable(name);
 }
 
 
@@ -460,6 +545,15 @@ void LaTeXFeatures::addPreambleSnippet(string const & preamble)
 }
 
 
+void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
+{
+       SnippetList::const_iterator begin = css_snippets_.begin();
+       SnippetList::const_iterator end   = css_snippets_.end();
+       if (find(begin, end, snippet) == end)
+               css_snippets_.push_back(snippet);
+}
+
+
 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
 {
        if (!usedFloats_[name])
@@ -478,10 +572,10 @@ void LaTeXFeatures::useFloat(string const & name, bool subfloat)
 
 void LaTeXFeatures::useLanguage(Language const * lang)
 {
-       if (!lang->babel().empty())
+       if (!lang->babel().empty() || !lang->polyglossia().empty())
                UsedLanguages_.insert(lang);
-       if (lang->lang() == "vietnamese")
-               require("vietnamese");
+       if (!lang->requires().empty())
+               require(lang->requires());
        // CJK languages do not have a babel name.
        // They use the CJK package
        if (lang->encoding()->package() == Encoding::CJK)
@@ -504,7 +598,7 @@ bool LaTeXFeatures::hasLanguages() const
 }
 
 
-bool LaTeXFeatures::hasPolyglossiaLanguages() const
+bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
 {
        LanguageList::const_iterator const begin = UsedLanguages_.begin();
        for (LanguageList::const_iterator cit = begin;
@@ -517,16 +611,34 @@ bool LaTeXFeatures::hasPolyglossiaLanguages() const
 }
 
 
-string LaTeXFeatures::getLanguages() const
+bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
+{
+       LanguageList::const_iterator const begin = UsedLanguages_.begin();
+       for (LanguageList::const_iterator cit = begin;
+            cit != UsedLanguages_.end();
+            ++cit) {
+               if ((*cit)->isPolyglossiaExclusive())
+                       return true;
+       }
+       return false;
+}
+
+
+string LaTeXFeatures::getBabelLanguages() const
 {
        ostringstream languages;
 
+       bool first = true;
        LanguageList::const_iterator const begin = UsedLanguages_.begin();
        for (LanguageList::const_iterator cit = begin;
             cit != UsedLanguages_.end();
             ++cit) {
-               if (cit != begin)
+               if ((*cit)->babel().empty())
+                       continue;
+               if (!first)
                        languages << ',';
+               else
+                       first = false;
                languages << (*cit)->babel();
        }
        return languages.str();
@@ -591,6 +703,7 @@ char const * simplefeatures[] = {
        "units",
        "tipa",
        "tipx",
+       "tone",
        "framed",
        "soul",
        "textcomp",
@@ -599,7 +712,12 @@ char const * simplefeatures[] = {
        "ifsym",
        "marvosym",
        "txfonts",
+       "pxfonts",
+       "mathdesign",
        "mathrsfs",
+       "mathabx",
+       "mathtools",
+       // "cancel",
        "ascii",
        "url",
        "covington",
@@ -617,6 +735,24 @@ char const * simplefeatures[] = {
        "tfrupee"
 };
 
+char const * bibliofeatures[] = {
+       // Known bibliography packages (will be loaded before natbib)
+       "achicago",
+       "apacite",
+       "apalike",
+       "astron",
+       "authordate1-4",
+       "babelbib",
+       "bibgerm",
+       "chicago",
+       "chscite",
+       "harvard",
+       "mslapa",
+       "named"
+};
+
+int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
+
 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
 
 }
@@ -685,7 +821,6 @@ string const LaTeXFeatures::getColorOptions() const
 string const LaTeXFeatures::getPackages() const
 {
        ostringstream packages;
-       DocumentClass const & tclass = params_.documentClass();
 
        // FIXME: currently, we can only load packages and macros known
        // to LyX.
@@ -693,32 +828,41 @@ string const LaTeXFeatures::getPackages() const
        // also unknown packages can be requested. They are silently
        // swallowed now. We should change this eventually.
 
-       //
+       // Output all the package option stuff we have been asked to do.
+       map<string, string>::const_iterator it =
+           params_.documentClass().packageOptions().begin();
+       map<string, string>::const_iterator en =
+           params_.documentClass().packageOptions().end();
+       for (; it != en; ++it)
+               if (mustProvide(it->first))
+                       packages << "\\PassOptionsToPackage{" << it->second << "}"
+                                << "{" << it->first << "}\n";
+
        //  These are all the 'simple' includes.  i.e
        //  packages which we just \usepackage{package}
-       //
        for (int i = 0; i < nb_simplefeatures; ++i) {
                if (mustProvide(simplefeatures[i]))
-                       packages << "\\usepackage{"
-                                << simplefeatures[i] << "}\n";
+                       packages << "\\usepackage{" << simplefeatures[i] << "}\n";
        }
 
-       //
        // The rest of these packages are somewhat more complicated
        // than those above.
-       //
 
        // if fontspec is used, AMS packages have to be loaded before
        // fontspec (in BufferParams)
-       if (!params_.useNonTeXFonts && !loadAMSPackages().empty())
-               packages << loadAMSPackages();
+       string const amsPackages = loadAMSPackages();
+       if (!params_.useNonTeXFonts && !amsPackages.empty())
+               packages << amsPackages;
 
        // fixltx2e must be loaded after amsthm, since amsthm produces an error with
-       // the redefined \[ command (bug 7233). Load is as early as possible, since
+       // the redefined \[ command (bug 7233). Load it as early as possible, since
        // other packages might profit from it.
        if (mustProvide("fixltx2e"))
                packages << "\\usepackage{fixltx2e}\n";
 
+        if (mustProvide("cancel") &&
+            params_.use_package("cancel") != BufferParams::package_off)
+                packages << "\\usepackage{cancel}\n";
        // wasysym is a simple feature, but it must be after amsmath if both
        // are used
        // wasysym redefines some integrals (e.g. iint) from amsmath. That
@@ -728,33 +872,45 @@ string const LaTeXFeatures::getPackages() const
        // integral symbols from wasysym and amsmath.
        // See http://www.lyx.org/trac/ticket/1942
        if (mustProvide("wasysym") &&
-           (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
+           params_.use_package("wasysym") != BufferParams::package_off &&
+           (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
                packages << "\\usepackage{wasysym}\n";
 
        // accents must be loaded after amsmath
-       if (mustProvide("accents"))
+       if (mustProvide("accents") &&
+           params_.use_package("accents") != BufferParams::package_off)
                packages << "\\usepackage{accents}\n";
 
        // mathdots must be loaded after amsmath
        if (mustProvide("mathdots") &&
-               params_.use_mathdots != BufferParams::package_off)
+               params_.use_package("mathdots") != BufferParams::package_off)
                packages << "\\usepackage{mathdots}\n";
 
        // yhmath must be loaded after amsmath
-       if (mustProvide("yhmath"))
+       if (mustProvide("yhmath") &&
+           params_.use_package("yhmath") != BufferParams::package_off)
                packages << "\\usepackage{yhmath}\n";
 
+       // stmaryrd must be loaded after amsmath
+       if (mustProvide("stmaryrd") &&
+           params_.use_package("stmaryrd") != BufferParams::package_off)
+               packages << "\\usepackage{stmaryrd}\n";
+
+       if (mustProvide("stackrel") &&
+           params_.use_package("stackrel") != BufferParams::package_off)
+               packages << "\\usepackage{stackrel}\n";
+
        if (mustProvide("undertilde") &&
-               params_.use_undertilde != BufferParams::package_off)
+               params_.use_package("undertilde") != BufferParams::package_off)
                packages << "\\usepackage{undertilde}\n";
 
        // [x]color and pdfcolmk are handled in getColorOptions() above
-       
+
        // makeidx.sty
        if (isRequired("makeidx") || isRequired("splitidx")) {
-               if (!tclass.provides("makeidx") && !isRequired("splitidx"))
+               if (!isProvided("makeidx") && !isRequired("splitidx"))
                        packages << "\\usepackage{makeidx}\n";
-               if (!tclass.provides("splitidx") && isRequired("splitidx"))
+               if (mustProvide("splitidx"))
                        packages << "\\usepackage{splitidx}\n";
                packages << "\\makeindex\n";
        }
@@ -768,47 +924,68 @@ string const LaTeXFeatures::getPackages() const
                                 << params_.graphics_driver
                                 << "]{graphicx}\n";
        }
-       
+
        // lyxskak.sty --- newer chess support based on skak.sty
        if (mustProvide("chess"))
                packages << "\\usepackage[ps,mover]{lyxskak}\n";
 
        // setspace.sty
-       if (mustProvide("setspace") && !tclass.provides("SetSpace"))
+       if (mustProvide("setspace") && !isProvided("SetSpace"))
                packages << "\\usepackage{setspace}\n";
 
        // esint must be after amsmath and wasysym, since it will redeclare
        // inconsistent integral symbols
-       if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
-           params_.use_esint != BufferParams::package_off)
+       if (mustProvide("esint") &&
+           params_.use_package("esint") != BufferParams::package_off)
                packages << "\\usepackage{esint}\n";
 
+       // Known bibliography packages (simple \usepackage{package})
+       for (int i = 0; i < nb_bibliofeatures; ++i) {
+               if (mustProvide(bibliofeatures[i]))
+                       packages << "\\usepackage{"
+                                << bibliofeatures[i] << "}\n";
+       }
+
+       // Compatibility between achicago and natbib
+       if (mustProvide("achicago") && mustProvide("natbib"))
+               packages << "\\let\\achicagobib\\thebibliography\n";
+
        // natbib.sty
        // Some classes load natbib themselves, but still allow (or even require)
        // plain numeric citations (ReVTeX is such a case, see bug 5182).
        // This special case is indicated by the "natbib-internal" key.
-       if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
+       if (mustProvide("natbib") && !isProvided("natbib-internal")) {
                packages << "\\usepackage[";
-               if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
+               if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
                        packages << "numbers";
                else
                        packages << "authoryear";
                packages << "]{natbib}\n";
        }
 
+       // Compatibility between achicago and natbib
+       if (mustProvide("achicago") && mustProvide("natbib")) {
+               packages << "\\let\\thebibliography\\achicagobib\n";
+               packages << "\\let\\SCcite\\astroncite\n";
+               packages << "\\let\\UnexpandableProtect\\protect\n";
+       }
+
        // jurabib -- we need version 0.6 at least.
        if (mustProvide("jurabib"))
                packages << "\\usepackage{jurabib}[2004/01/25]\n";
-       
+
+       // opcit -- we pass custombst as we output \bibliographystyle ourselves
+       if (mustProvide("opcit")) {
+               if (isRequired("hyperref"))
+                       packages << "\\usepackage[custombst,hyperref]{opcit}\n";
+               else
+                       packages << "\\usepackage[custombst]{opcit}\n";
+       }
+
        // xargs -- we need version 1.09 at least
        if (mustProvide("xargs"))
                packages << "\\usepackage{xargs}[2008/03/08]\n";
 
-       // bibtopic -- the dot provides the aux file naming which
-       // LyX can detect.
-       if (mustProvide("bibtopic"))
-               packages << "\\usepackage[dot]{bibtopic}\n";
-
        if (mustProvide("xy"))
                packages << "\\usepackage[all]{xy}\n";
 
@@ -819,9 +996,8 @@ string const LaTeXFeatures::getPackages() const
                packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
                            "\\usepackage{ulem}\n";
 
-       if (params_.use_mhchem == BufferParams::package_on ||
-           (mustProvide("mhchem") &&
-            params_.use_mhchem != BufferParams::package_off))
+       if (mustProvide("mhchem") &&
+           params_.use_package("mhchem") != BufferParams::package_off)
                packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
                            "\\usepackage{mhchem}\n";
 
@@ -844,7 +1020,7 @@ string const LaTeXFeatures::getPackages() const
 }
 
 
-string LaTeXFeatures::getPreambleSnippets() const 
+string LaTeXFeatures::getPreambleSnippets() const
 {
        ostringstream snip;
        SnippetList::const_iterator pit  = preamble_snippets_.begin();
@@ -855,6 +1031,17 @@ string LaTeXFeatures::getPreambleSnippets() const
 }
 
 
+std::string LaTeXFeatures::getCSSSnippets() const
+{
+       ostringstream snip;
+       SnippetList::const_iterator pit  = css_snippets_.begin();
+       SnippetList::const_iterator pend = css_snippets_.end();
+       for (; pit != pend; ++pit)
+               snip << *pit << '\n';
+       return snip.str();
+}
+
+
 docstring const LaTeXFeatures::getMacros() const
 {
        odocstringstream macros;
@@ -975,17 +1162,17 @@ docstring const LaTeXFeatures::getMacros() const
 
        // floats
        getFloatDefinitions(macros);
-       
-       if (mustProvide("refstyle")) 
-               macros << lyxref_def << '\n';   
-       
+
+       if (mustProvide("refstyle"))
+               macros << lyxref_def << '\n';
+
        // change tracking
        if (mustProvide("ct-dvipost"))
                macros << changetracking_dvipost_def;
-       
+
        if (mustProvide("ct-xcolor-ulem")) {
                streamsize const prec = macros.precision(2);
-       
+
                RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
                macros << "\\providecolor{lyxadded}{rgb}{"
                       << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
@@ -995,7 +1182,7 @@ docstring const LaTeXFeatures::getMacros() const
                       << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
 
                macros.precision(prec);
-               
+
                if (isRequired("hyperref"))
                        macros << changetracking_xcolor_ulem_hyperref_def;
                else
@@ -1005,6 +1192,9 @@ docstring const LaTeXFeatures::getMacros() const
        if (mustProvide("ct-none"))
                macros << changetracking_none_def;
 
+       if (mustProvide("rtloutputdblcol"))
+               macros << rtloutputdblcol_def;
+
        return macros.str();
 }
 
@@ -1021,7 +1211,10 @@ string const LaTeXFeatures::getBabelPresettings() const
        if (!params_.language->babel_presettings().empty())
                tmp << params_.language->babel_presettings() << '\n';
 
-       return tmp.str();
+       if (!contains(tmp.str(), '@'))
+               return tmp.str();
+
+       return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
 }
 
 
@@ -1037,7 +1230,10 @@ string const LaTeXFeatures::getBabelPostsettings() const
        if (!params_.language->babel_postsettings().empty())
                tmp << params_.language->babel_postsettings() << '\n';
 
-       return tmp.str();
+       if (!contains(tmp.str(), '@'))
+               return tmp.str();
+
+       return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
 }
 
 
@@ -1062,12 +1258,8 @@ string const LaTeXFeatures::loadAMSPackages() const
        if (mustProvide("amsthm"))
                tmp << "\\usepackage{amsthm}\n";
 
-       // esint is preferred for esintoramsmath
-       if ((mustProvide("amsmath")
-            && params_.use_amsmath != BufferParams::package_off)
-           || (mustProvide("esintoramsmath")
-               && params_.use_esint == BufferParams::package_off
-               && params_.use_amsmath != BufferParams::package_off)) {
+       if (mustProvide("amsmath")
+           && params_.use_package("amsmath") != BufferParams::package_off) {
                tmp << "\\usepackage{amsmath}\n";
        } else {
                // amsbsy and amstext are already provided by amsmath
@@ -1076,9 +1268,9 @@ string const LaTeXFeatures::loadAMSPackages() const
                if (mustProvide("amstext"))
                        tmp << "\\usepackage{amstext}\n";
        }
-       
+
        if (mustProvide("amssymb")
-           || params_.use_amsmath == BufferParams::package_on)
+           && params_.use_package("amssymb") != BufferParams::package_off)
                tmp << "\\usepackage{amssymb}\n";
 
        return tmp.str();
@@ -1112,7 +1304,7 @@ docstring const LaTeXFeatures::getTClassPreamble() const
 }
 
 
-docstring const LaTeXFeatures::getTClassHTMLPreamble() const 
+docstring const LaTeXFeatures::getTClassHTMLPreamble() const
 {
        DocumentClass const & tclass = params_.documentClass();
        odocstringstream tcpreamble;
@@ -1138,10 +1330,20 @@ docstring const LaTeXFeatures::getTClassHTMLPreamble() const
 }
 
 
-docstring const LaTeXFeatures::getTClassHTMLStyles() const {
+docstring const LaTeXFeatures::getTClassHTMLStyles() const
+{
        DocumentClass const & tclass = params_.documentClass();
        odocstringstream tcpreamble;
 
+       if (mustProvide("noun"))
+               tcpreamble << lyxnoun_style;
+       // this isn't exact, but it won't hurt that much if it
+       // wasn't for this.
+       if (mustProvide("ulem"))
+               tcpreamble << lyxstrikeout_style;
+
+       tcpreamble << tclass.htmlstyles();
+
        list<docstring>::const_iterator cit = usedLayouts_.begin();
        list<docstring>::const_iterator end = usedLayouts_.end();
        for (; cit != end; ++cit)
@@ -1162,10 +1364,20 @@ docstring const LaTeXFeatures::getTClassHTMLStyles() const {
 
 
 namespace {
+
 docstring const getFloatI18nPreamble(docstring const & type,
                        docstring const & name, Language const * lang,
                        Encoding const & enc, bool const polyglossia)
 {
+       // Check whether name can be encoded in the buffer encoding
+       bool encodable = true;
+       for (size_t i = 0; i < name.size(); ++i) {
+               if (!enc.encodable(name[i])) {
+                       encodable = false;
+                       break;
+               }
+       }
+
        docstring const language = polyglossia ? from_ascii(lang->polyglossia())
                                               : from_ascii(lang->babel());
        docstring const langenc = from_ascii(lang->encoding()->iconvName());
@@ -1173,15 +1385,58 @@ docstring const getFloatI18nPreamble(docstring const & type,
        docstring const bufenc = from_ascii(enc.iconvName());
        docstring const s1 = docstring(1, 0xF0000);
        docstring const s2 = docstring(1, 0xF0001);
-       docstring const translated = (langenc == bufenc) ? name
+       docstring const translated = encodable ? name
                : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
-                       + s1 + langenc + s2 + translated + s1 + bufenc + s2;
+                       + s1 + langenc + s2 + name + s1 + bufenc + s2;
 
        odocstringstream os;
        os << "\\addto\\captions" << language
           << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
        return os.str();
 }
+
+
+docstring const i18npreamble(docstring const & templ, Language const * lang,
+               Encoding const & enc, bool const polyglossia)
+{
+       if (templ.empty())
+               return templ;
+
+       string preamble = polyglossia ?
+               subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
+               subst(to_utf8(templ), "$$lang", lang->babel());
+
+       string const langenc = lang->encoding()->iconvName();
+       string const texenc = lang->encoding()->latexName();
+       string const bufenc = enc.iconvName();
+       // First and second character of plane 15 (Private Use Area)
+       string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
+       string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
+       // FIXME UNICODE
+       // lyx::regex is not unicode-safe.
+       // Should use QRegExp or (boost::u32regex, but that requires ICU)
+       static regex const reg("_\\(([^\\)]+)\\)");
+       smatch sub;
+       while (regex_search(preamble, sub, reg)) {
+               string const key = sub.str(1);
+               docstring const name = lang->translateLayout(key);
+               // Check whether name can be encoded in the buffer encoding
+               bool encodable = true;
+               for (size_t i = 0; i < name.size(); ++i) {
+                       if (!enc.encodable(name[i])) {
+                               encodable = false;
+                               break;
+                       }
+               }
+               string const translated = encodable ? to_utf8(name)
+                       : "\\inputencoding{" + texenc + "}"
+                       + s1 + langenc + s2 + to_utf8(name)
+                       + s1 + bufenc + s2;
+               preamble = subst(preamble, sub.str(), translated);
+       }
+       return from_utf8(preamble);
+}
+
 }
 
 
@@ -1198,17 +1453,20 @@ docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_po
        list<docstring>::const_iterator end = usedLayouts_.end();
        for (; cit != end; ++cit) {
                // language dependent commands (once per document)
-               snippets.insert(tclass[*cit].langpreamble(buffer().language(),
+               snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
+                                               buffer().language(),
                                                buffer().params().encoding(),
                                                use_polyglossia));
                // commands for language changing (for multilanguage documents)
                if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
-                       snippets.insert(tclass[*cit].babelpreamble(
+                       snippets.insert(i18npreamble(
+                                               tclass[*cit].babelpreamble(),
                                                buffer().language(),
                                                buffer().params().encoding(),
                                                use_polyglossia));
                        for (lang_it lit = lbeg; lit != lend; ++lit)
-                               snippets.insert(tclass[*cit].babelpreamble(
+                               snippets.insert(i18npreamble(
+                                               tclass[*cit].babelpreamble(),
                                                *lit,
                                                buffer().params().encoding(),
                                                use_polyglossia));
@@ -1220,7 +1478,7 @@ docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_po
                UsedFloats::const_iterator fend = usedFloats_.end();
                for (; fit != fend; ++fit) {
                        Floating const & fl = floats.getType(fit->first);
-                       // we assume builtin floats are translated 
+                       // we assume builtin floats are translated
                        if (fl.isPredefined())
                                continue;
                        docstring const type = from_ascii(fl.floattype());
@@ -1252,6 +1510,34 @@ docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_po
                }
        }
 
+       cit = usedInsetLayouts_.begin();
+       end = usedInsetLayouts_.end();
+       TextClass::InsetLayouts const & ils = tclass.insetLayouts();
+       for (; cit != end; ++cit) {
+               TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
+               if (it == ils.end())
+                       continue;
+               // language dependent commands (once per document)
+               snippets.insert(i18npreamble(it->second.langpreamble(),
+                                               buffer().language(),
+                                               buffer().params().encoding(),
+                                               use_polyglossia));
+               // commands for language changing (for multilanguage documents)
+               if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
+                       snippets.insert(i18npreamble(
+                                               it->second.babelpreamble(),
+                                               buffer().language(),
+                                               buffer().params().encoding(),
+                                               use_polyglossia));
+                       for (lang_it lit = lbeg; lit != lend; ++lit)
+                               snippets.insert(i18npreamble(
+                                               it->second.babelpreamble(),
+                                               *lit,
+                                               buffer().params().encoding(),
+                                               use_polyglossia));
+               }
+       }
+
        odocstringstream tcpreamble;
        set<docstring>::const_iterator const send = snippets.end();
        set<docstring>::const_iterator it = snippets.begin();
@@ -1388,4 +1674,25 @@ void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
 }
 
 
+void LaTeXFeatures::resolveAlternatives()
+{
+       for (Features::iterator it = features_.begin(); it != features_.end();) {
+               if (contains(*it, '|')) {
+                       vector<string> const alternatives = getVectorFromString(*it, "|");
+                       vector<string>::const_iterator const end = alternatives.end();
+                       vector<string>::const_iterator ita = alternatives.begin();
+                       for (; ita != end; ++ita) {
+                               if (isRequired(*ita))
+                                       break;
+                       }
+                       if (ita == end)
+                               require(alternatives.front());
+                       features_.erase(it);
+                       it = features_.begin();
+               } else
+                       ++it;
+       }
+}
+
+
 } // namespace lyx