]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetBibtex.cpp
Fix trailing whitespace in cpp files.
[lyx.git] / src / insets / InsetBibtex.cpp
index a83068201b430fbb74df4eda0f3039dd4d3658c0..4b9dab5d6513f572ac7b1539031ce1cc52723500 100644 (file)
@@ -5,6 +5,7 @@
  *
  * \author Alejandro Aguilar Sierra
  * \author Richard Heck (BibTeX parser improvements)
+ * \author Jürgen Spitzmüller
  *
  * Full author contact details are available in file CREDITS.
  */
 
 #include "InsetBibtex.h"
 
+#include "BiblioInfo.h"
 #include "Buffer.h"
 #include "BufferParams.h"
+#include "CiteEnginesList.h"
+#include "Cursor.h"
 #include "DispatchResult.h"
 #include "Encoding.h"
+#include "Exporter.h"
 #include "Format.h"
 #include "FuncRequest.h"
 #include "FuncStatus.h"
 #include "LaTeXFeatures.h"
 #include "output_xhtml.h"
 #include "OutputParams.h"
+#include "PDFOptions.h"
+#include "texstream.h"
 #include "TextClass.h"
 
 #include "frontends/alert.h"
 #include "support/debug.h"
 #include "support/docstream.h"
 #include "support/ExceptionMessage.h"
+#include "support/FileNameList.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lstrings.h"
 #include "support/os.h"
-#include "support/Path.h"
+#include "support/PathChanger.h"
 #include "support/textutils.h"
 
 #include <limits>
@@ -50,16 +58,22 @@ namespace os = support::os;
 
 
 InsetBibtex::InsetBibtex(Buffer * buf, InsetCommandParams const & p)
-       : InsetCommand(buf, p, "bibtex")
+       : InsetCommand(buf, p)
 {
-       buffer().invalidateBibinfoCache();
+       buffer().invalidateBibfileCache();
+       buffer().removeBiblioTempFiles();
 }
 
 
 InsetBibtex::~InsetBibtex()
 {
-       if (isBufferLoaded())
-               buffer().invalidateBibfileCache();
+       if (isBufferLoaded()) {
+               /* We do not use buffer() because Coverity believes that this
+                * may throw an exception. Actually this code path is not
+                * taken when buffer_ == 0 */
+               buffer_-> invalidateBibfileCache();
+               buffer_->removeBiblioTempFiles();
+       }
 }
 
 
@@ -70,6 +84,7 @@ ParamInfo const & InsetBibtex::findInfo(string const & /* cmdName */)
                param_info_.add("btprint", ParamInfo::LATEX_OPTIONAL);
                param_info_.add("bibfiles", ParamInfo::LATEX_REQUIRED);
                param_info_.add("options", ParamInfo::LYX_INTERNAL);
+               param_info_.add("biblatexopts", ParamInfo::LATEX_OPTIONAL);
        }
        return param_info_;
 }
@@ -86,8 +101,7 @@ void InsetBibtex::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_INSET_MODIFY: {
                InsetCommandParams p(BIBTEX_CODE);
                try {
-                       if (!InsetCommand::string2params("bibtex", 
-                                       to_utf8(cmd.argument()), p)) {
+                       if (!InsetCommand::string2params(to_utf8(cmd.argument()), p)) {
                                cur.noScreenUpdate();
                                break;
                        }
@@ -95,13 +109,15 @@ void InsetBibtex::doDispatch(Cursor & cur, FuncRequest & cmd)
                        if (message.type_ == WarningException) {
                                Alert::warning(message.title_, message.details_);
                                cur.noScreenUpdate();
-                       } else 
-                               throw message;
+                       } else
+                               throw;
                        break;
                }
-               //
+
+               cur.recordUndo();
                setParams(p);
                buffer().invalidateBibfileCache();
+               buffer().removeBiblioTempFiles();
                cur.forceBufferUpdate();
                break;
        }
@@ -136,9 +152,10 @@ void InsetBibtex::editDatabases() const
 
        int nr_databases = bibfilelist.size();
        if (nr_databases > 1) {
-                       docstring message = bformat(_("The BibTeX inset includes %1$s databases.\n"
+                       docstring const engine = usingBiblatex() ? _("Biblatex") : _("BibTeX");
+                       docstring message = bformat(_("The %1$s[[BibTeX/Biblatex]] inset includes %2$s databases.\n"
                                                       "If you proceed, all of them will be opened."),
-                                                       convert<docstring>(nr_databases));
+                                                       engine, convert<docstring>(nr_databases));
                        int const ret = Alert::prompt(_("Open Databases?"),
                                message, 0, 1, _("&Cancel"), _("&Proceed"));
 
@@ -149,36 +166,38 @@ void InsetBibtex::editDatabases() const
        vector<docstring>::const_iterator it = bibfilelist.begin();
        vector<docstring>::const_iterator en = bibfilelist.end();
        for (; it != en; ++it) {
-               FileName bibfile = getBibTeXPath(*it, buffer());
-               formats.edit(buffer(), bibfile,
-                    formats.getFormatFromFile(bibfile));
+               FileName const bibfile = getBibTeXPath(*it, buffer());
+               theFormats().edit(buffer(), bibfile,
+                    theFormats().getFormatFromFile(bibfile));
        }
 }
 
 
+bool InsetBibtex::usingBiblatex() const
+{
+       return buffer().masterParams().useBiblatex();
+}
+
+
 docstring InsetBibtex::screenLabel() const
 {
-       return _("BibTeX Generated Bibliography");
+       return usingBiblatex() ? _("Biblatex Generated Bibliography")
+                              : _("BibTeX Generated Bibliography");
 }
 
 
 docstring InsetBibtex::toolTip(BufferView const & /*bv*/, int /*x*/, int /*y*/) const
 {
-       docstring item = from_ascii("* ");
-       docstring tip = _("Databases:") + "\n";
+       docstring tip = _("Databases:");
        vector<docstring> bibfilelist = getVectorFromString(getParam("bibfiles"));
 
-       if (bibfilelist.empty()) {
-               tip += item;
-               tip += _("none");
-       } else {
-               vector<docstring>::const_iterator it = bibfilelist.begin();
-               vector<docstring>::const_iterator en = bibfilelist.end();
-               for (; it != en; ++it) {
-                       tip += item;
-                       tip += *it + "\n";
-               }
-       }
+       tip += "<ul>";
+       if (bibfilelist.empty())
+               tip += "<li>" + _("none") + "</li>";
+       else
+               for (docstring const & bibfile : bibfilelist)
+                       tip += "<li>" + bibfile + "</li>";
+       tip += "</ul>";
 
        // Style-Options
        bool toc = false;
@@ -190,123 +209,73 @@ docstring InsetBibtex::toolTip(BufferView const & /*bv*/, int /*x*/, int /*y*/)
                        style = split(style, bibtotoc, char_type(','));
        }
 
-       tip += _("Style File:") +"\n";
-       tip += item;
-       if (!style.empty())
-               tip += style;
-       else
-               tip += _("none");
+       docstring const btprint = getParam("btprint");
+       if (!usingBiblatex()) {
+               tip += _("Style File:");
+               tip += "<ul><li>" + (style.empty() ? _("none") : style) + "</li></ul>";
 
-       tip += "\n" + _("Lists:") + " ";
-       docstring btprint = getParam("btprint");
+               tip += _("Lists:") + " ";
                if (btprint == "btPrintAll")
                        tip += _("all references");
                else if (btprint == "btPrintNotCited")
                        tip += _("all uncited references");
                else
                        tip += _("all cited references");
-       
-       if (toc) {
-               tip += ", ";
-               tip += _("included in TOC");
+               if (toc) {
+                       tip += ", ";
+                       tip += _("included in TOC");
+               }
+               if (!buffer().parent()
+                   && buffer().params().multibib == "child") {
+                       tip += "<br />";
+                       tip += _("Note: This bibliography is not output, since bibliographies in the master file "
+                                "are not allowed with the setting 'Multiple bibliographies per child document'");
+               }
+       } else {
+               tip += _("Lists:") + " ";
+               if (btprint == "bibbysection")
+                       tip += _("all reference units");
+               else if (btprint == "btPrintAll")
+                       tip += _("all references");
+               else
+                       tip += _("all cited references");
+               if (toc) {
+                       tip += ", ";
+                       tip += _("included in TOC");
+               }
+               if (!getParam("biblatexopts").empty()) {
+                       if (toc)
+                               tip += "<br />";
+                       tip += _("Options: ") + getParam("biblatexopts");
+               }
        }
 
        return tip;
 }
 
 
-static string normalizeName(Buffer const & buffer,
-       OutputParams const & runparams, string const & name, string const & ext)
+void InsetBibtex::latex(otexstream & os, OutputParams const & runparams) const
 {
-       string const fname = makeAbsPath(name, buffer.filePath()).absFileName();
-       if (FileName::isAbsolute(name) || !FileName(fname + ext).isReadableFile())
-               return name;
-       if (!runparams.nice)
-               return fname;
-
-       // FIXME UNICODE
-       return to_utf8(makeRelPath(from_utf8(fname),
-                                        from_utf8(buffer.masterBuffer()->filePath())));
-}
-
-
-int InsetBibtex::latex(odocstream & os, OutputParams const & runparams) const
-{
-       // the sequence of the commands:
+       // The sequence of the commands:
+       // With normal BibTeX:
        // 1. \bibliographystyle{style}
        // 2. \addcontentsline{...} - if option bibtotoc set
        // 3. \bibliography{database}
-       // and with bibtopic:
+       // With bibtopic:
        // 1. \bibliographystyle{style}
        // 2. \begin{btSect}{database}
        // 3. \btPrint{Cited|NotCited|All}
        // 4. \end{btSect}
+       // With Biblatex:
+       // \printbibliography[biblatexopts]
+       // or
+       // \bibbysection[biblatexopts] - if btprint is "bibbysection"
+
+       // chapterbib does not allow bibliographies in the master
+       if (!usingBiblatex() && !runparams.is_child
+           && buffer().params().multibib == "child")
+               return;
 
-       // Database(s)
-       // If we are processing the LaTeX file in a temp directory then
-       // copy the .bib databases to this temp directory, mangling their
-       // names in the process. Store this mangled name in the list of
-       // all databases.
-       // (We need to do all this because BibTeX *really*, *really*
-       // can't handle "files with spaces" and Windows users tend to
-       // use such filenames.)
-       // Otherwise, store the (maybe absolute) path to the original,
-       // unmangled database name.
-       vector<docstring> bibfilelist = getVectorFromString(getParam("bibfiles"));
-       vector<docstring>::const_iterator it = bibfilelist.begin();
-       vector<docstring>::const_iterator en = bibfilelist.end();
-       odocstringstream dbs;
-       bool didone = false;
-
-       for (; it != en; ++it) {
-               string utf8input = to_utf8(*it);
-               string database =
-                       normalizeName(buffer(), runparams, utf8input, ".bib");
-               FileName const try_in_file =
-                       makeAbsPath(database + ".bib", buffer().filePath());
-               bool const not_from_texmf = try_in_file.isReadableFile();
-
-               if (!runparams.inComment && !runparams.dryrun && !runparams.nice &&
-                   not_from_texmf) {
-                       // mangledFileName() needs the extension
-                       DocFileName const in_file = DocFileName(try_in_file);
-                       database = removeExtension(in_file.mangledFileName());
-                       FileName const out_file = makeAbsPath(database + ".bib",
-                                       buffer().masterBuffer()->temppath());
-
-                       bool const success = in_file.copyTo(out_file);
-                       if (!success) {
-                               lyxerr << "Failed to copy '" << in_file
-                                      << "' to '" << out_file << "'"
-                                      << endl;
-                       }
-               } else if (!runparams.inComment && runparams.nice && not_from_texmf &&
-                          !isValidLaTeXFileName(database)) {
-                               frontend::Alert::warning(_("Invalid filename"),
-                                                        _("The following filename is likely to cause trouble "
-                                                          "when running the exported file through LaTeX: ") +
-                                                           from_utf8(database));
-               }
-
-               if (didone)
-                       dbs << ',';
-               else 
-                       didone = true;
-               // FIXME UNICODE
-               dbs << from_utf8(latex_path(database));
-       }
-       docstring const db_out = dbs.str();
-
-       // Post this warning only once.
-       static bool warned_about_spaces = false;
-       if (!warned_about_spaces &&
-           runparams.nice && db_out.find(' ') != docstring::npos) {
-               warned_about_spaces = true;
-               Alert::warning(_("Export Warning!"),
-                              _("There are spaces in the paths to your BibTeX databases.\n"
-                                             "BibTeX will be unable to find them."));
-       }
-       // Style-Options
        string style = to_utf8(getParam("options")); // maybe empty! and with bibtotoc
        string bibtotoc;
        if (prefixIs(style, "bibtotoc")) {
@@ -315,95 +284,110 @@ int InsetBibtex::latex(odocstream & os, OutputParams const & runparams) const
                        style = split(style, bibtotoc, ',');
        }
 
-       // line count
-       int nlines = 0;
-
-       if (!style.empty()) {
-               string base = normalizeName(buffer(), runparams, style, ".bst");
-               FileName const try_in_file = 
-                       makeAbsPath(base + ".bst", buffer().filePath());
-               bool const not_from_texmf = try_in_file.isReadableFile();
-               // If this style does not come from texmf and we are not
-               // exporting to .tex copy it to the tmp directory.
-               // This prevents problems with spaces and 8bit charcaters
-               // in the file name.
-               if (!runparams.inComment && !runparams.dryrun && !runparams.nice &&
-                   not_from_texmf) {
-                       // use new style name
-                       DocFileName const in_file = DocFileName(try_in_file);
-                       base = removeExtension(in_file.mangledFileName());
-                       FileName const out_file = makeAbsPath(base + ".bst",
-                                       buffer().masterBuffer()->temppath());
-                       bool const success = in_file.copyTo(out_file);
-                       if (!success) {
-                               lyxerr << "Failed to copy '" << in_file
-                                      << "' to '" << out_file << "'"
-                                      << endl;
+       if (usingBiblatex()) {
+               // Options
+               string opts = to_utf8(getParam("biblatexopts"));
+               // bibtotoc-Option
+               if (!bibtotoc.empty())
+                       opts = opts.empty() ? "heading=bibintoc" : "heading=bibintoc," + opts;
+               // The bibliography command
+               docstring btprint = getParam("btprint");
+               if (btprint == "btPrintAll")
+                       os << "\\nocite{*}\n";
+               if (btprint == "bibbysection" && !buffer().masterParams().multibib.empty())
+                       os << "\\bibbysection";
+               else
+                       os << "\\printbibliography";
+               if (!opts.empty())
+                       os << "[" << opts << "]";
+               os << "\n";
+       } else {// using BibTeX
+               // Database(s)
+               vector<docstring> const db_out =
+                       buffer().prepareBibFilePaths(runparams, getBibFiles(), false);
+               // Style options
+               if (style == "default")
+                       style = buffer().masterParams().defaultBiblioStyle();
+               if (!style.empty() && !buffer().masterParams().useBibtopic()) {
+                       string base = buffer().masterBuffer()->prepareFileNameForLaTeX(style, ".bst", runparams.nice);
+                       FileName const try_in_file =
+                               makeAbsPath(base + ".bst", buffer().filePath());
+                       bool const not_from_texmf = try_in_file.isReadableFile();
+                       // If this style does not come from texmf and we are not
+                       // exporting to .tex copy it to the tmp directory.
+                       // This prevents problems with spaces and 8bit characters
+                       // in the file name.
+                       if (!runparams.inComment && !runparams.dryrun && !runparams.nice &&
+                           not_from_texmf) {
+                               // use new style name
+                               DocFileName const in_file = DocFileName(try_in_file);
+                               base = removeExtension(in_file.mangledFileName());
+                               FileName const out_file = makeAbsPath(base + ".bst",
+                                               buffer().masterBuffer()->temppath());
+                               bool const success = in_file.copyTo(out_file);
+                               if (!success) {
+                                       LYXERR0("Failed to copy '" << in_file
+                                              << "' to '" << out_file << "'");
+                               }
                        }
+                       // FIXME UNICODE
+                       os << "\\bibliographystyle{"
+                          << from_utf8(latex_path(buffer().prepareFileNameForLaTeX(base, ".bst", runparams.nice)))
+                          << "}\n";
                }
-               // FIXME UNICODE
-               os << "\\bibliographystyle{"
-                  << from_utf8(latex_path(normalizeName(buffer(), runparams, base, ".bst")))
-                  << "}\n";
-               nlines += 1;
-       }
-
-       // Post this warning only once.
-       static bool warned_about_bst_spaces = false;
-       if (!warned_about_bst_spaces && runparams.nice && contains(style, ' ')) {
-               warned_about_bst_spaces = true;
-               Alert::warning(_("Export Warning!"),
-                              _("There are spaces in the path to your BibTeX style file.\n"
-                                             "BibTeX will be unable to find it."));
-       }
-
-       if (!db_out.empty() && buffer().params().use_bibtopic) {
-               os << "\\begin{btSect}{" << db_out << "}\n";
-               docstring btprint = getParam("btprint");
-               if (btprint.empty())
-                       // default
-                       btprint = from_ascii("btPrintCited");
-               os << "\\" << btprint << "\n"
-                  << "\\end{btSect}\n";
-               nlines += 3;
-       }
-
-       // bibtotoc-Option
-       if (!bibtotoc.empty() && !buffer().params().use_bibtopic) {
-               if (buffer().params().documentClass().hasLaTeXLayout("chapter")) {
-                       if (buffer().params().sides == OneSide) {
-                               // oneside
-                               os << "\\clearpage";
-                       } else {
-                               // twoside
-                               os << "\\cleardoublepage";
+               // Warn about spaces in bst path. Warn only once.
+               static bool warned_about_bst_spaces = false;
+               if (!warned_about_bst_spaces && runparams.nice && contains(style, ' ')) {
+                       warned_about_bst_spaces = true;
+                       Alert::warning(_("Export Warning!"),
+                                      _("There are spaces in the path to your BibTeX style file.\n"
+                                                     "BibTeX will be unable to find it."));
+               }
+               // Handle the bibtopic case
+               if (!db_out.empty() && buffer().masterParams().useBibtopic()) {
+                       os << "\\begin{btSect}";
+                       if (!style.empty())
+                               os << "[" << style << "]";
+                       os << "{" << getStringFromVector(db_out) << "}\n";
+                       docstring btprint = getParam("btprint");
+                       if (btprint.empty())
+                               // default
+                               btprint = from_ascii("btPrintCited");
+                       os << "\\" << btprint << "\n"
+                          << "\\end{btSect}\n";
+               }
+               // bibtotoc option
+               if (!bibtotoc.empty() && !buffer().masterParams().useBibtopic()) {
+                       // set label for hyperref, see http://www.lyx.org/trac/ticket/6470
+                       if (buffer().masterParams().pdfoptions().use_hyperref)
+                                       os << "\\phantomsection";
+                       if (buffer().masterParams().documentClass().hasLaTeXLayout("chapter"))
+                               os << "\\addcontentsline{toc}{chapter}{\\bibname}";
+                       else if (buffer().masterParams().documentClass().hasLaTeXLayout("section"))
+                               os << "\\addcontentsline{toc}{section}{\\refname}";
+               }
+               // The bibliography command
+               if (!db_out.empty() && !buffer().masterParams().useBibtopic()) {
+                       docstring btprint = getParam("btprint");
+                       if (btprint == "btPrintAll") {
+                               os << "\\nocite{*}\n";
                        }
-                       os << "\\addcontentsline{toc}{chapter}{\\bibname}";
-               } else if (buffer().params().documentClass().hasLaTeXLayout("section"))
-                       os << "\\addcontentsline{toc}{section}{\\refname}";
-       }
-
-       if (!db_out.empty() && !buffer().params().use_bibtopic) {
-               docstring btprint = getParam("btprint");
-               if (btprint == "btPrintAll") {
-                       os << "\\nocite{*}\n";
-                       nlines += 1;
+                       os << "\\bibliography{" << getStringFromVector(db_out) << "}\n";
                }
-               os << "\\bibliography{" << db_out << "}\n";
-               nlines += 1;
        }
-
-       return nlines;
 }
 
 
-support::FileNameList InsetBibtex::getBibFiles() const
+support::FileNamePairList InsetBibtex::getBibFiles() const
 {
        FileName path(buffer().filePath());
        support::PathChanger p(path);
-       
-       support::FileNameList vec;
-       
+
+       // We need to store both the real FileName and the way it is entered
+       // (with full path, rel path or as a single file name).
+       // The latter is needed for biblatex's central bibfile macro.
+       support::FileNamePairList vec;
+
        vector<docstring> bibfilelist = getVectorFromString(getParam("bibfiles"));
        vector<docstring>::const_iterator it = bibfilelist.begin();
        vector<docstring>::const_iterator en = bibfilelist.end();
@@ -411,11 +395,11 @@ support::FileNameList InsetBibtex::getBibFiles() const
                FileName const file = getBibTeXPath(*it, buffer());
 
                if (!file.empty())
-                       vec.push_back(file);
+                       vec.push_back(make_pair(*it, file));
                else
                        LYXERR0("Couldn't find " + to_utf8(*it) + " in InsetBibtex::getBibFiles()!");
        }
-       
+
        return vec;
 
 }
@@ -474,7 +458,7 @@ namespace {
        /// @return true if a string of length > 0 could be read.
        ///
        bool readTypeOrKey(docstring & val, ifdocstream & ifs,
-               docstring const & delimChars, docstring const & illegalChars, 
+               docstring const & delimChars, docstring const & illegalChars,
                charCase chCase) {
 
                char_type ch;
@@ -494,10 +478,10 @@ namespace {
 
                // read value
                bool legalChar = true;
-               while (ifs && !isSpace(ch) && 
+               while (ifs && !isSpace(ch) &&
                                                 delimChars.find(ch) == docstring::npos &&
                                                 (legalChar = (illegalChars.find(ch) == docstring::npos))
-                                       ) 
+                                       )
                {
                        if (chCase == makeLowerCase)
                                val += lowercase(ch);
@@ -505,7 +489,7 @@ namespace {
                                val += ch;
                        ifs.get(ch);
                }
-               
+
                if (!legalChar) {
                        ifs.putback(ch);
                        return false;
@@ -547,13 +531,13 @@ namespace {
                                return false;
 
                        // check for field type
-                       if (isDigit(ch)) {
+                       if (isDigitASCII(ch)) {
 
                                // read integer value
                                do {
                                        val += ch;
                                        ifs.get(ch);
-                               } while (ifs && isDigit(ch));
+                               } while (ifs && isDigitASCII(ch));
 
                                if (!ifs)
                                        return false;
@@ -566,33 +550,33 @@ namespace {
                                do {
                                        ifs.get(ch);
                                } while (ifs && isSpace(ch));
-                               
+
                                if (!ifs)
                                        return false;
-                               
+
                                // We now have the first non-whitespace character
                                // We'll collapse adjacent whitespace.
                                bool lastWasWhiteSpace = false;
-                               
+
                                // inside this delimited text braces must match.
                                // Thus we can have a closing delimiter only
                                // when nestLevel == 0
                                int nestLevel = 0;
+
                                while (ifs && (nestLevel > 0 || ch != delim)) {
                                        if (isSpace(ch)) {
                                                lastWasWhiteSpace = true;
                                                ifs.get(ch);
                                                continue;
                                        }
-                                       // We output the space only after we stop getting 
+                                       // We output the space only after we stop getting
                                        // whitespace so as not to output any whitespace
                                        // at the end of the value.
                                        if (lastWasWhiteSpace) {
                                                lastWasWhiteSpace = false;
                                                val += ' ';
                                        }
-                                       
+
                                        val += ch;
 
                                        // update nesting level
@@ -602,7 +586,7 @@ namespace {
                                                        break;
                                                case '}':
                                                        --nestLevel;
-                                                       if (nestLevel < 0) 
+                                                       if (nestLevel < 0)
                                                                return false;
                                                        break;
                                        }
@@ -661,9 +645,13 @@ namespace {
 }
 
 
-// This method returns a comma separated list of Bibtex entries
-void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
-       InsetIterator const & /*di*/) const
+void InsetBibtex::collectBibKeys(InsetIterator const & /*di*/) const
+{
+       parseBibTeXFiles();
+}
+
+
+void InsetBibtex::parseBibTeXFiles() const
 {
        // This bibtex parser is a first step to parse bibtex files
        // more precisely.
@@ -683,12 +671,15 @@ void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
        // We don't restrict keys to ASCII in LyX, since our own
        // InsetBibitem can generate non-ASCII keys, and nonstandard
        // 8bit clean bibtex forks exist.
-       support::FileNameList const files = getBibFiles();
-       support::FileNameList::const_iterator it = files.begin();
-       support::FileNameList::const_iterator en = files.end();
+
+       BiblioInfo keylist;
+
+       support::FileNamePairList const files = getBibFiles();
+       support::FileNamePairList::const_iterator it = files.begin();
+       support::FileNamePairList::const_iterator en = files.end();
        for (; it != en; ++ it) {
-               ifdocstream ifs(it->toFilesystemEncoding().c_str(),
-                       ios_base::in, buffer().params().encoding().iconvName());
+               ifdocstream ifs(it->second.toFilesystemEncoding().c_str(),
+                       ios_base::in, buffer().masterParams().encoding().iconvName());
 
                char_type ch;
                VarMap strings;
@@ -752,13 +743,13 @@ void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
                                // next char must be an equal sign
                                ifs.get(ch);
                                if (!ifs || ch != '=') {
-                                       lyxerr << "BibTeX Parser: No `=' after string name: " << 
+                                       lyxerr << "BibTeX Parser: No `=' after string name: " <<
                                                        name << "." << std::endl;
                                        continue;
                                }
 
                                if (!readValue(value, ifs, strings)) {
-                                       lyxerr << "BibTeX Parser: Unable to read value for string: " << 
+                                       lyxerr << "BibTeX Parser: Unable to read value for string: " <<
                                                        name << "." << std::endl;
                                        continue;
                                }
@@ -782,7 +773,7 @@ void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
                                docstring key;
 
                                if (!readTypeOrKey(key, ifs, from_ascii(","), from_ascii("}"), keepCase)) {
-                                       lyxerr << "BibTeX Parser: Unable to read key for entry type:" << 
+                                       lyxerr << "BibTeX Parser: Unable to read key for entry type:" <<
                                                        entryType << "." << std::endl;
                                        continue;
                                }
@@ -793,7 +784,7 @@ void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
                                }
 
                                /////////////////////////////////////////////
-                               // now we have a key, so we will add an entry 
+                               // now we have a key, so we will add an entry
                                // (even if it's empty, as bibtex does)
                                //
                                // we now read the field = value pairs.
@@ -804,13 +795,13 @@ void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
                                docstring value;
                                docstring data;
                                BibTeXInfo keyvalmap(key, entryType);
-                               
+
                                bool readNext = removeWSAndComma(ifs);
+
                                while (ifs && readNext) {
 
                                        // read field name
-                                       if (!readTypeOrKey(name, ifs, from_ascii("="), 
+                                       if (!readTypeOrKey(name, ifs, from_ascii("="),
                                                           from_ascii("{}(),"), makeLowerCase) || !ifs)
                                                break;
 
@@ -848,20 +839,22 @@ void InsetBibtex::fillWithBibKeys(BiblioInfo & keylist,
                        } //< else (citation entry)
                } //< searching '@'
        } //< for loop over files
+
+       buffer().addBiblioInfo(keylist);
 }
 
 
 FileName InsetBibtex::getBibTeXPath(docstring const & filename, Buffer const & buf)
 {
        string texfile = changeExtension(to_utf8(filename), "bib");
-       // note that, if the filename can be found directly from the path, 
+       // note that, if the filename can be found directly from the path,
        // findtexfile will just return a FileName object for that path.
        FileName file(findtexfile(texfile, "bib"));
        if (file.empty())
                file = FileName(makeAbsPath(texfile, buf.filePath()));
        return file;
 }
+
 
 bool InsetBibtex::addDatabase(docstring const & db)
 {
@@ -897,33 +890,87 @@ bool InsetBibtex::delDatabase(docstring const & db)
 
 void InsetBibtex::validate(LaTeXFeatures & features) const
 {
-       if (features.bufferParams().use_bibtopic)
+       BufferParams const & mparams = features.buffer().masterParams();
+       if (mparams.useBibtopic())
                features.require("bibtopic");
+       else if (!mparams.useBiblatex() && mparams.multibib == "child")
+               features.require("chapterbib");
        // FIXME XHTML
        // It'd be better to be able to get this from an InsetLayout, but at present
        // InsetLayouts do not seem really to work for things that aren't InsetTexts.
        if (features.runparams().flavor == OutputParams::HTML)
-               features.addPreambleSnippet("<style type=\"text/css\">\n"
-                       "div.bibtexentry { margin-left: 2em; text-indent: -2em; }\n"
+               features.addCSSSnippet("div.bibtexentry { margin-left: 2em; text-indent: -2em; }\n"
                        "span.bibtexlabel:before{ content: \"[\"; }\n"
-                       "span.bibtexlabel:after{ content: \"] \"; }\n"
-                       "</style>");
+                       "span.bibtexlabel:after{ content: \"] \"; }");
 }
 
 
-// FIXME 
+int InsetBibtex::plaintext(odocstringstream & os,
+       OutputParams const & op, size_t max_length) const
+{
+       docstring const reflabel = buffer().B_("References");
+
+       // We could output more information here, e.g., what databases are included
+       // and information about options. But I don't necessarily see any reason to
+       // do this right now.
+       if (op.for_tooltip || op.for_toc || op.for_search) {
+               os << '[' << reflabel << ']' << '\n';
+               return PLAINTEXT_NEWLINE;
+       }
+
+       BiblioInfo bibinfo = buffer().masterBibInfo();
+       bibinfo.makeCitationLabels(buffer());
+       vector<docstring> const & cites = bibinfo.citedEntries();
+
+       size_t start_size = os.str().size();
+       docstring refoutput;
+       refoutput += reflabel + "\n\n";
+
+       // Tell BiblioInfo our purpose
+       CiteItem ci;
+       ci.context = CiteItem::Export;
+
+       // Now we loop over the entries
+       vector<docstring>::const_iterator vit = cites.begin();
+       vector<docstring>::const_iterator const ven = cites.end();
+       for (; vit != ven; ++vit) {
+               if (start_size + refoutput.size() >= max_length)
+                       break;
+               BiblioInfo::const_iterator const biit = bibinfo.find(*vit);
+               if (biit == bibinfo.end())
+                       continue;
+               BibTeXInfo const & entry = biit->second;
+               refoutput += "[" + entry.label() + "] ";
+               // FIXME Right now, we are calling BibInfo::getInfo on the key,
+               // which will give us all the cross-referenced info. But for every
+               // entry, so there's a lot of repitition. This should be fixed.
+               refoutput += bibinfo.getInfo(entry.key(), buffer(), ci) + "\n\n";
+       }
+       os << refoutput;
+       return refoutput.size();
+}
+
+
+// FIXME
 // docstring InsetBibtex::entriesAsXHTML(vector<docstring> const & entries)
 // And then here just: entriesAsXHTML(buffer().masterBibInfo().citedEntries())
 docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const
 {
        BiblioInfo const & bibinfo = buffer().masterBibInfo();
-       vector<docstring> const & cites = bibinfo.citedEntries();
-       CiteEngine const engine = buffer().params().citeEngine();
-       bool const numbers = 
-               (engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL);
+       bool const all_entries = getParam("btprint") == "btPrintAll";
+       vector<docstring> const & cites =
+           all_entries ? bibinfo.getKeys() : bibinfo.citedEntries();
+
+       docstring const reflabel = buffer().B_("References");
+
+       // tell BiblioInfo our purpose
+       CiteItem ci;
+       ci.context = CiteItem::Export;
+       ci.richtext = true;
+       ci.max_key_size = UINT_MAX;
 
        xs << html::StartTag("h2", "class='bibtex'")
-               << _("References")
+               << reflabel
                << html::EndTag("h2")
                << html::StartTag("div", "class='bibtex'");
 
@@ -934,48 +981,43 @@ docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const
                BiblioInfo::const_iterator const biit = bibinfo.find(*vit);
                if (biit == bibinfo.end())
                        continue;
+
                BibTeXInfo const & entry = biit->second;
-               xs << html::StartTag("div", "class='bibtexentry'");
-               // FIXME XHTML
-               // The same name/id problem we have elsewhere.
-               string const attr = "id='" + to_utf8(entry.key()) + "'";
-               xs << html::CompTag("a", attr);
-               docstring citekey;
-               if (numbers)
-                       citekey = entry.citeNumber();
-               else {
-                       docstring const auth = entry.getAbbreviatedAuthor();
-                       // we do it this way so as to access the xref, if necessary
-                       // note that this also gives us the modifier
-                       docstring const year = bibinfo.getYear(*vit, true);
-                       if (!auth.empty() && !year.empty())
-                               citekey = auth + ' ' + year;
+               string const attr = "class='bibtexentry' id='LyXCite-"
+                   + to_utf8(html::cleanAttr(entry.key())) + "'";
+               xs << html::StartTag("div", attr);
+
+               // don't print labels if we're outputting all entries
+               if (!all_entries) {
+                       xs << html::StartTag("span", "class='bibtexlabel'")
+                               << entry.label()
+                               << html::EndTag("span");
                }
-               if (citekey.empty()) {
-                       citekey = entry.label();
-                       if (citekey.empty())
-                               citekey = entry.key();
-               }
-               xs << html::StartTag("span", "class='bibtexlabel'")
-                       << citekey
-                       << html::EndTag("span");
+
                // FIXME Right now, we are calling BibInfo::getInfo on the key,
                // which will give us all the cross-referenced info. But for every
                // entry, so there's a lot of repitition. This should be fixed.
-               xs << html::StartTag("span", "class='bibtexinfo'") 
-                       << bibinfo.getInfo(entry.key(), buffer(), true)
-                       << html::EndTag("span")
-                       << html::EndTag("div");
-               xs.cr();
+               xs << html::StartTag("span", "class='bibtexinfo'")
+                  << XHTMLStream::ESCAPE_AND
+                  << bibinfo.getInfo(entry.key(), buffer(), ci)
+                  << html::EndTag("span")
+                  << html::EndTag("div")
+                  << html::CR();
        }
        xs << html::EndTag("div");
        return docstring();
 }
 
 
-docstring InsetBibtex::contextMenu(BufferView const &, int, int) const
+void InsetBibtex::write(ostream & os) const
+{
+       params().Write(os, &buffer());
+}
+
+
+string InsetBibtex::contextMenuName() const
 {
-       return from_ascii("context-bibtex");
+       return "context-bibtex";
 }