]> git.lyx.org Git - lyx.git/blobdiff - src/BufferParams.cpp
Provide proper fallback if a bibliography processor is not found
[lyx.git] / src / BufferParams.cpp
index 19abefc0dd9706fd872c284aa9f14af470368482..51aab82aeb6f25662cdf71bba84217091be36bd7 100644 (file)
 #include "ColorSet.h"
 #include "Converter.h"
 #include "Encoding.h"
-#include "HSpace.h"
 #include "IndicesList.h"
 #include "Language.h"
 #include "LaTeXFeatures.h"
 #include "LaTeXFonts.h"
+#include "Length.h"
 #include "ModuleList.h"
 #include "Font.h"
 #include "Lexer.h"
@@ -323,7 +323,7 @@ bool inSystemDir(FileName const & document_dir, string & system_dir)
        return false;
 }
 
-} // anon namespace
+} // namespace
 
 
 class BufferParams::Impl
@@ -337,12 +337,12 @@ public:
        Bullet user_defined_bullets[4];
        IndicesList indiceslist;
        Spacing spacing;
+       Length parindent;
+       Length mathindent;
        /** This is the amount of space used for paragraph_separation "skip",
         * and for detached paragraphs in "indented" documents.
         */
-       HSpace indentation;
        VSpace defskip;
-       HSpace math_indentation;
        PDFOptions pdfoptions;
        LayoutFileIndex baseClass_;
        FormatList exportableFormatList;
@@ -385,7 +385,7 @@ BufferParams::BufferParams()
        makeDocumentClass();
        paragraph_separation = ParagraphIndentSeparation;
        is_math_indent = false;
-       math_indentation = "default";
+       math_numbering_side = DEFAULT;
        quotes_style = InsetQuotesParams::EnglishQuotes;
        dynamic_quotes = false;
        fontsize = "default";
@@ -394,7 +394,7 @@ BufferParams::BufferParams()
        papersize = PAPER_DEFAULT;
        orientation = ORIENTATION_PORTRAIT;
        use_geometry = false;
-       biblio_style = "plain";
+       biblio_style = string();
        use_bibtopic = false;
        multibib = string();
        use_indices = false;
@@ -459,8 +459,10 @@ BufferParams::BufferParams()
        html_css_as_file = false;
        display_pixel_ratio = 1.0;
 
+       shell_escape = false;
        output_sync = false;
        use_refstyle = true;
+       use_minted = false;
 
        // map current author
        author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
@@ -629,27 +631,27 @@ PDFOptions const & BufferParams::pdfoptions() const
 }
 
 
-HSpace const & BufferParams::getMathIndentation() const
+Length const & BufferParams::getMathIndent() const
 {
-       return pimpl_->math_indentation;
+       return pimpl_->mathindent;
 }
 
 
-void BufferParams::setMathIndentation(HSpace const & indent)
+void BufferParams::setMathIndent(Length const & indent)
 {
-       pimpl_->math_indentation = indent;
+       pimpl_->mathindent = indent;
 }
 
 
-HSpace const & BufferParams::getIndentation() const
+Length const & BufferParams::getParIndent() const
 {
-       return pimpl_->indentation;
+       return pimpl_->parindent;
 }
 
 
-void BufferParams::setIndentation(HSpace const & indent)
+void BufferParams::setParIndent(Length const & indent)
 {
-       pimpl_->indentation = indent;
+       pimpl_->parindent = indent;
 }
 
 
@@ -667,6 +669,19 @@ void BufferParams::setDefSkip(VSpace const & vs)
 }
 
 
+BufferParams::MathNumber BufferParams::getMathNumber() const
+{
+       if (math_numbering_side != DEFAULT)
+               return math_numbering_side;
+       // FIXME: do not hardcode language here
+       else if (language->lang() == "arabic_arabi"
+                || documentClass().provides("leqno"))
+               return LEFT;
+       else
+               return RIGHT;
+}
+
+
 string BufferParams::readToken(Lexer & lex, string const & token,
        FileName const & filepath)
 {
@@ -836,8 +851,11 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                paragraph_separation = parseptranslator().find(parsep);
        } else if (token == "\\paragraph_indentation") {
                lex.next();
-               string indentation = lex.getString();
-               pimpl_->indentation = HSpace(indentation);
+               string parindent = lex.getString();
+               if (parindent == "default")
+                       pimpl_->parindent = Length();
+               else
+                       pimpl_->parindent = Length(parindent);
        } else if (token == "\\defskip") {
                lex.next();
                string const defskip = lex.getString();
@@ -849,8 +867,20 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                lex >> is_math_indent;
        } else if (token == "\\math_indentation") {
                lex.next();
-               string math_indentation = lex.getString();
-               pimpl_->math_indentation = HSpace(math_indentation);
+               string mathindent = lex.getString();
+               if (mathindent == "default")
+                       pimpl_->mathindent = Length();
+               else
+                       pimpl_->mathindent = Length(mathindent);
+       } else if (token == "\\math_numbering_side") {
+               string tmp;
+               lex >> tmp;
+               if (tmp == "left")
+                       math_numbering_side = LEFT;
+               else if (tmp == "right")
+                       math_numbering_side = RIGHT;
+               else
+                       math_numbering_side = DEFAULT;
        } else if (token == "\\quotes_style") {
                string qstyle;
                lex >> qstyle;
@@ -1071,6 +1101,8 @@ string BufferParams::readToken(Lexer & lex, string const & token,
                lex >> output_sync_macro;
        } else if (token == "\\use_refstyle") {
                lex >> use_refstyle;
+       } else if (token == "\\use_minted") {
+               lex >> use_minted;
        } else {
                lyxerr << "BufferParams::readToken(): Unknown token: " <<
                        token << endl;
@@ -1088,7 +1120,7 @@ namespace {
                        return "\"" + str + "\"";
                return str;
        }
-}
+} // namespace
 
 
 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
@@ -1278,6 +1310,7 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const
           << "\n\\suppress_date " << convert<string>(suppress_date)
           << "\n\\justification " << convert<string>(justification)
           << "\n\\use_refstyle " << use_refstyle
+          << "\n\\use_minted " << use_minted
           << '\n';
        if (isbackgroundcolor == true)
                os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
@@ -1344,12 +1377,25 @@ void BufferParams::writeFile(ostream & os, Buffer const * buf) const
           << "\n\\paragraph_separation "
           << string_paragraph_separation[paragraph_separation];
        if (!paragraph_separation)
-               os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
+               os << "\n\\paragraph_indentation "
+                  << (getParIndent().empty() ? "default" : getParIndent().asString());
        else
                os << "\n\\defskip " << getDefSkip().asLyXCommand();
        os << "\n\\is_math_indent " << is_math_indent;
        if (is_math_indent)
-               os << "\n\\math_indentation " << getMathIndentation().asLyXCommand();
+               os << "\n\\math_indentation "
+                  << (getMathIndent().empty() ? "default" : getMathIndent().asString());
+       os << "\n\\math_numbering_side ";
+       switch(math_numbering_side) {
+       case LEFT:
+               os << "left";
+               break;
+       case RIGHT:
+               os << "right";
+               break;
+       case DEFAULT:
+               os << "default";
+       }
        os << "\n\\quotes_style "
           << string_quotes_style[quotes_style]
           << "\n\\dynamic_quotes " << dynamic_quotes
@@ -1508,7 +1554,7 @@ void BufferParams::validate(LaTeXFeatures & features) const
 
        if (useNonTeXFonts && fontsMath() != "auto")
                features.require("unicode-math");
-       
+
        if (use_microtype)
                features.require("microtype");
 
@@ -1556,7 +1602,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                && papersize != PAPER_A5
                && papersize != PAPER_B5;
 
-       if (!use_geometry) {
+       if (!use_geometry || features.isProvided("geometry-light")) {
                switch (papersize) {
                case PAPER_A4:
                        clsoptions << "a4paper,";
@@ -1634,6 +1680,18 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        if (is_math_indent)
                clsoptions << "fleqn,";
 
+       switch(math_numbering_side) {
+       case LEFT:
+               clsoptions << "leqno,";
+               break;
+       case RIGHT:
+               clsoptions << "reqno,";
+               features.require("amsmath");
+               break;
+       case DEFAULT:
+               break;
+       }
+
        // language should be a parameter to \documentclass
        if (language->babel() == "hebrew"
            && default_language->babel() != "hebrew")
@@ -1664,17 +1722,60 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        if (!options.empty()) {
                clsoptions << options << ',';
        }
-
-       string strOptions(clsoptions.str());
+       
+       docstring const strOptions = from_utf8(clsoptions.str());
        if (!strOptions.empty()) {
-               strOptions = rtrim(strOptions, ",");
-               // FIXME UNICODE
-               os << '[' << from_utf8(strOptions) << ']';
+               // Check if class options contain uncodable glyphs
+               docstring uncodable_glyphs;
+               docstring options_encodable;
+               Encoding const * const enc = features.runparams().encoding;
+               if (enc) {
+                       for (size_t n = 0; n < strOptions.size(); ++n) {
+                               char_type c = strOptions[n];
+                               if (!enc->encodable(c)) {
+                                       docstring const glyph(1, c);
+                                       LYXERR0("Uncodable character '"
+                                               << glyph
+                                               << "' in class options!");
+                                       uncodable_glyphs += glyph;
+                                       if (features.runparams().dryrun) {
+                                               options_encodable += "<" + _("LyX Warning: ")
+                                                  + _("uncodable character") + " '";
+                                               options_encodable += c;
+                                               options_encodable += "'>";
+                                       }
+                               } else
+                                       options_encodable += c;
+                       }
+               } else
+                       options_encodable = strOptions;
+       
+               // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
+               if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
+                       frontend::Alert::warning(
+                               _("Uncodable character in class options"),
+                               support::bformat(
+                                 _("The class options of your document contain glyphs "
+                                   "that are unknown in the current document encoding "
+                                   "(namely %1$s).\nThese glyphs are omitted "
+                                   " from the output, which may result in "
+                                   "incomplete output."
+                                   "\n\nPlease select an appropriate "
+                                   "document encoding\n"
+                                   "(such as utf8) or change the "
+                                   "class options accordingly."),
+                                 uncodable_glyphs));
+               }
+               options_encodable = rtrim(options_encodable, ",");
+               os << '[' << options_encodable << ']';
        }
 
        os << '{' << from_ascii(tclass.latexname()) << "}\n";
        // end of \documentclass defs
 
+       // The package options (via \PassOptionsToPackage)
+       os << from_ascii(features.getPackageOptions());
+
        // if we use fontspec or newtxmath, we have to load the AMS packages here
        string const ams = features.loadAMSPackages();
        bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
@@ -1746,7 +1847,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        }
 
        if (!features.isProvided("geometry")
-           && (use_geometry || nonstandard_papersize)) {
+            && (use_geometry || nonstandard_papersize)) {
                odocstringstream ods;
                if (!getGraphicsDriver("geometry").empty())
                        ods << getGraphicsDriver("geometry");
@@ -1857,31 +1958,42 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                case PAPER_DEFAULT:
                        break;
                }
-               docstring const g_options = trim(ods.str(), ",");
+               docstring g_options = trim(ods.str(), ",");
                os << "\\usepackage";
-               if (!g_options.empty())
+               // geometry-light means that the class works with geometry, but overwrites
+               // the package options and paper sizes (memoir does this).
+               // In this case, all options need to go to \geometry
+               // and the standard paper sizes need to go to the class options.
+               if (!g_options.empty() && !features.isProvided("geometry-light")) {
                        os << '[' << g_options << ']';
+                       g_options.clear();
+               }
                os << "{geometry}\n";
-               // output this only if use_geometry is true
-               if (use_geometry) {
+               if (use_geometry || features.isProvided("geometry-light")) {
                        os << "\\geometry{verbose";
-                       if (!topmargin.empty())
-                               os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
-                       if (!bottommargin.empty())
-                               os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
-                       if (!leftmargin.empty())
-                               os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
-                       if (!rightmargin.empty())
-                               os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
-                       if (!headheight.empty())
-                               os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
-                       if (!headsep.empty())
-                               os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
-                       if (!footskip.empty())
-                               os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
-                       if (!columnsep.empty())
-                               os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
-                       os << "}\n";
+                       if (!g_options.empty())
+                               // Output general options here with "geometry light".
+                               os << "," << g_options;
+                       // output this only if use_geometry is true
+                       if (use_geometry) {
+                               if (!topmargin.empty())
+                                       os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
+                               if (!bottommargin.empty())
+                                       os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
+                               if (!leftmargin.empty())
+                                       os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
+                               if (!rightmargin.empty())
+                                       os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
+                               if (!headheight.empty())
+                                       os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
+                               if (!headsep.empty())
+                                       os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
+                               if (!footskip.empty())
+                                       os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
+                               if (!columnsep.empty())
+                                       os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
+                       }
+               os << "}\n";
                }
        } else if (orientation == ORIENTATION_LANDSCAPE
                   || papersize != PAPER_DEFAULT) {
@@ -1951,9 +2063,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        } else {
                // when separation by indentation
                // only output something when a width is given
-               if (getIndentation().asLyXCommand() != "default") {
+               if (!getParIndent().empty()) {
                        os << "\\setlength{\\parindent}{"
-                          << from_utf8(getIndentation().asLatexCommand())
+                          << from_utf8(getParIndent().asLatexString())
                           << "}\n";
                }
        }
@@ -1961,9 +2073,9 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        if (is_math_indent) {
                // when formula indentation
                // only output something when it is not the default
-               if (getMathIndentation().asLyXCommand() != "default") {
+               if (!getMathIndent().empty()) {
                        os << "\\setlength{\\mathindent}{"
-                          << from_utf8(getMathIndentation().asLatexCommand())
+                          << from_utf8(getMathIndent().asString())
                           << "}\n";
                }
        }
@@ -1981,9 +2093,6 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                        os << "\\synctex=-1\n";
        }
 
-       // The package options (via \PassOptionsToPackage)
-       os << from_ascii(features.getPackageOptions());
-
        // due to interferences with babel and hyperref, the color package has to
        // be loaded (when it is not already loaded) before babel when hyperref
        // is used with the colorlinks option, see
@@ -1992,13 +2101,12 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
        os << from_ascii(features.getColorOptions());
 
-       // If we use hyperref, jurabib, japanese, varioref or vietnamese,
+       // If we use hyperref, jurabib, japanese or varioref,
        // we have to call babel before
        if (use_babel
            && (features.isRequired("jurabib")
                || features.isRequired("hyperref")
                || features.isRequired("varioref")
-               || features.isRequired("vietnamese")
                || features.isRequired("japanese"))) {
                        os << features.getBabelPresettings();
                        // FIXME UNICODE
@@ -2037,8 +2145,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                OutputParams tmp_params = features.runparams();
                pdfoptions().writeLaTeX(tmp_params, os,
                                        features.isProvided("hyperref"));
-               // correctly break URLs with hyperref and dvi output
-               if (features.runparams().flavor == OutputParams::LATEX
+               // correctly break URLs with hyperref and dvi/ps output
+               if (features.runparams().hyperref_driver == "dvips"
                    && features.isAvailable("breakurl"))
                        os << "\\usepackage{breakurl}\n";
        } else if (features.isRequired("nameref"))
@@ -2190,12 +2298,11 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                   << "\\makeatother\n\n";
 
        // We try to load babel late, in case it interferes with other packages.
-       // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be
-       // called after babel, though.
+       // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
+       // have to be called after babel, though.
        if (use_babel && !features.isRequired("jurabib")
            && !features.isRequired("hyperref")
-               && !features.isRequired("varioref")
-           && !features.isRequired("vietnamese")
+           && !features.isRequired("varioref")
            && !features.isRequired("japanese")) {
                os << features.getBabelPresettings();
                // FIXME UNICODE
@@ -2205,14 +2312,34 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        }
        if (features.isRequired("bicaption"))
                os << "\\usepackage{bicaption}\n";
-       if (!listings_params.empty() || features.mustProvide("listings"))
-               os << "\\usepackage{listings}\n";
-       if (!listings_params.empty()) {
-               os << "\\lstset{";
+       if (!listings_params.empty()
+           || features.mustProvide("listings")
+           || features.mustProvide("minted")) {
+               if (use_minted)
+                       os << "\\usepackage{minted}\n";
+               else
+                       os << "\\usepackage{listings}\n";
+       }
+       string lst_params = listings_params;
+       // If minted, do not output the language option (bug 11203)
+       if (use_minted && contains(lst_params, "language=")) {
+               vector<string> opts =
+                       getVectorFromString(lst_params, ",", false);
+               for (size_t i = 0; i < opts.size(); ++i) {
+                       if (prefixIs(opts[i], "language="))
+                               opts.erase(opts.begin() + i--);
+               }
+               lst_params = getStringFromVector(opts, ",");
+       }
+       if (!lst_params.empty()) {
+               if (use_minted)
+                       os << "\\setminted{";
+               else
+                       os << "\\lstset{";
                // do not test validity because listings_params is
                // supposed to be valid
                string par =
-                       InsetListingsParams(listings_params).separatedParams(true);
+                       InsetListingsParams(lst_params).separatedParams(true);
                os << from_utf8(par);
                os << "}\n";
        }
@@ -2221,7 +2348,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        // (the rest is obsoleted by the new TU encoding).
        // It needs to be loaded at least after amsmath, amssymb,
        // esint and the other packages that provide special glyphs
-       if (features.mustProvide("tipa") && useNonTeXFonts) {
+       if (features.mustProvide("tipa") && useNonTeXFonts
+           && !features.isProvided("xunicode")) {
                // The package officially only supports XeTeX, but also works
                // with LuaTeX. Thus we work around its XeTeX test.
                if (features.runparams().flavor != OutputParams::XETEX) {
@@ -2231,6 +2359,10 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                os << "\\usepackage{xunicode}\n";
        }
 
+       // covington must be loaded after beamerarticle
+       if (features.isRequired("covington"))
+           os << "\\usepackage{covington}\n";
+
        // Polyglossia must be loaded last ...
        if (use_polyglossia) {
                // call the package
@@ -2256,7 +2388,11 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
        }
 
        // ... but before biblatex (see #7065)
-       if (features.mustProvide("biblatex")) {
+       if (features.mustProvide("biblatex")
+           && !features.isProvided("biblatex-natbib")
+           && !features.isProvided("natbib-internal")
+           && !features.isProvided("natbib")
+           && !features.isProvided("jurabib")) {
                string delim = "";
                string opts;
                os << "\\usepackage";
@@ -2304,8 +2440,14 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
                os << '\n';
        }
 
+       // Since menukeys uses catoptions, which does some heavy changes on key-value options,
+       // it is recommended to load menukeys as the last package (even after hyperref)
+       if (features.isRequired("menukeys"))
+               os << "\\usepackage{menukeys}\n";
+
        docstring const i18npreamble =
-               features.getTClassI18nPreamble(use_babel, use_polyglossia);
+               features.getTClassI18nPreamble(use_babel, use_polyglossia,
+                                              use_minted);
        if (!i18npreamble.empty())
                os << i18npreamble + '\n';
 
@@ -2362,7 +2504,7 @@ void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
 }
 
 
-bool BufferParams::setBaseClass(string const & classname)
+bool BufferParams::setBaseClass(string const & classname, string const & path)
 {
        LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
        LayoutFileList & bcl = LayoutFileList::get();
@@ -2378,7 +2520,7 @@ bool BufferParams::setBaseClass(string const & classname)
                bcl.addEmptyClass(classname);
        }
 
-       bool const success = bcl[classname].load();
+       bool const success = bcl[classname].load(path);
        if (!success) {
                docstring s =
                        bformat(_("Due to some error in it, the layout file:\n"
@@ -2511,7 +2653,7 @@ FormatList const & BufferParams::exportableFormats(bool only_viewable) const
 {
        FormatList & cached = only_viewable ?
                        pimpl_->viewableFormatList : pimpl_->exportableFormatList;
-       bool & valid = only_viewable ? 
+       bool & valid = only_viewable ?
                        pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
        if (valid)
                return cached;
@@ -2526,7 +2668,7 @@ FormatList const & BufferParams::exportableFormats(bool only_viewable) const
                theConverters().getReachable(backs[0], only_viewable, true, excludes);
        for (vector<string>::const_iterator it = backs.begin() + 1;
             it != backs.end(); ++it) {
-               FormatList r = theConverters().getReachable(*it, only_viewable, 
+               FormatList r = theConverters().getReachable(*it, only_viewable,
                                false, excludes);
                result.insert(result.end(), r.begin(), r.end());
        }
@@ -2555,8 +2697,16 @@ vector<string> BufferParams::backends() const
                        v.push_back("luatex");
                        v.push_back("dviluatex");
                }
-       } else
-               v.push_back(buffmt);
+       } else {
+               string rbuffmt = buffmt;
+               // If we use an OutputFormat in Japanese docs,
+               // we need special format in order to get the path
+               // via pLaTeX (#8823)
+               if (documentClass().hasOutputFormat()
+                   && encoding().package() == Encoding::japanese)
+                       rbuffmt += "-ja";
+               v.push_back(rbuffmt);
+       }
 
        v.push_back("xhtml");
        v.push_back("text");
@@ -2621,14 +2771,15 @@ string BufferParams::getDefaultOutputFormat() const
        if (!default_output_format.empty()
            && default_output_format != "default")
                return default_output_format;
-       if (isDocBook()
-           || encoding().package() == Encoding::japanese) {
+       if (isDocBook()) {
                FormatList const & formats = exportableFormats(true);
                if (formats.empty())
                        return string();
                // return the first we find
                return formats.front()->name();
        }
+       if (encoding().package() == Encoding::japanese)
+               return lyxrc.default_platex_view_format;
        if (useNonTeXFonts)
                return lyxrc.default_otf_view_format;
        return lyxrc.default_view_format;
@@ -3183,7 +3334,7 @@ void BufferParams::writeEncodingPreamble(otexstream & os,
                // Load the CJK package if needed by a secondary language.
                // If the main encoding is some variant of UTF8, use CJKutf8.
                if (encoding().package() != Encoding::CJK && features.mustProvide("CJK")) {
-                       if (encoding().iconvName() == "UTF-8"
+                       if (language->encoding()->name() == "utf8-cjk"
                            && LaTeXFeatures::isAvailable("CJKutf8"))
                                os << "\\usepackage{CJKutf8}\n";
                        else
@@ -3301,7 +3452,7 @@ string const BufferParams::loadFonts(LaTeXFeatures & features) const
 Encoding const & BufferParams::encoding() const
 {
        // Main encoding for LaTeX output.
-       // 
+       //
        // Exception: XeTeX with 8-bit TeX fonts requires ASCII (see #9740).
        // As the "flavor" is only known once export started, this
        // cannot be handled here. Instead, runparams.encoding is set
@@ -3346,6 +3497,9 @@ bool BufferParams::addCiteEngine(vector<string> const & engine)
 
 string const & BufferParams::defaultBiblioStyle() const
 {
+       if (!biblio_style.empty())
+               return biblio_style;
+
        map<string, string> const & bs = documentClass().defaultBiblioStyle();
        auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
        if (cit != bs.end())
@@ -3411,11 +3565,71 @@ vector<CitationStyle> BufferParams::citeStyles() const
 }
 
 
-string const BufferParams::bibtexCommand() const
+string const BufferParams::getBibtexCommand(string const cmd, bool const warn) const
+{
+       // split from options
+       string command_in;
+       split(cmd, command_in, ' ');
+
+       // Look if the requested command is available. If so, use that.
+       for (auto const & alts : lyxrc.bibtex_alternatives) {
+               string command_prov;
+               split(alts, command_prov, ' ');
+               if (command_in == command_prov)
+                       return cmd;
+       }
+
+       // If not, find the most suitable fallback for the current cite framework,
+       // and warn. Note that we omit options in any such case.
+       string fallback;
+       if (useBiblatex()) {
+               // For Biblatex, we prefer biber (also for Japanese)
+               // and try to fall back to bibtex8
+               if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
+                       fallback = "biber";
+               else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
+                       fallback = "bibtex8";
+       }
+       // For classic BibTeX and as last resort for biblatex, try bibtex
+       if (fallback.empty()) {
+               if (lyxrc.bibtex_alternatives.find("bibtex") != lyxrc.bibtex_alternatives.end())
+                       fallback = "bibtex";
+       }
+
+       if (!warn)
+               return fallback;
+
+       if (fallback.empty()) {
+               frontend::Alert::warning(
+                       _("No bibliography processor found!"),
+                       support::bformat(
+                         _("The bibliography processor requested by this document "
+                           "(%1$s) is not available and no appropriate "
+                           "alternative has been found. "
+                           "No bibliography and references will be generated.\n"
+                           "Please fix your installation!"),
+                         from_utf8(cmd)));
+       } else {
+               frontend::Alert::warning(
+                       _("Requested bibliography processor not found!"),
+                       support::bformat(
+                         _("The bibliography processor requested by this document "
+                           "(%1$s) is not available. "
+                           "As a fallback, '%2$s' will be used, options are omitted. "
+                           "This might result in errors or unwanted changes in "
+                           "the bibliography. Please check carefully!\n"
+                           "It is suggested to install the missing processor."),
+                         from_utf8(cmd), from_utf8(fallback)));
+       }
+       return fallback;
+}
+
+
+string const BufferParams::bibtexCommand(bool const warn) const
 {
        // Return document-specific setting if available
        if (bibtex_command != "default")
-               return bibtex_command;
+               return getBibtexCommand(bibtex_command, warn);
 
        // If we have "default" in document settings, consult the prefs
        // 1. Japanese (uses a specific processor)
@@ -3435,7 +3649,7 @@ string const BufferParams::bibtexCommand() const
        // 2. All other languages
        else if (lyxrc.bibtex_command != "automatic")
                // Return the specified program, if "automatic" is not set
-               return lyxrc.bibtex_command;
+               return getBibtexCommand(lyxrc.bibtex_command, warn);
 
        // 3. Automatic: find the most suitable for the current cite framework
        if (useBiblatex()) {
@@ -3463,4 +3677,16 @@ void BufferParams::invalidateConverterCache() const
        pimpl_->isViewCacheValid = false;
 }
 
+
+// We shouldn't need to reset the params here, since anything
+// we need will be recopied.
+void BufferParams::copyForAdvFR(const BufferParams & bp)
+{
+       string const & lang = bp.language->lang();
+       setLanguage(lang);
+       layout_modules_ = bp.layout_modules_;
+       string const & doc_class = bp.documentClass().name();
+       setBaseClass(doc_class);
+}
+
 } // namespace lyx