]> git.lyx.org Git - lyx.git/blobdiff - src/Buffer.cpp
Get default font color and background color working for XHTML export.
[lyx.git] / src / Buffer.cpp
index 07a82c03714fd6f75086387facdaee941cb73160..3df51d7b84a478ac05946d8cac5355450603a2b6 100644 (file)
 #include "mathed/MathMacroTemplate.h"
 #include "mathed/MathSupport.h"
 
+#include "graphics/PreviewLoader.h"
+
 #include "frontends/alert.h"
 #include "frontends/Delegates.h"
 #include "frontends/WorkAreaManager.h"
 
-#include "graphics/Previews.h"
-
 #include "support/lassert.h"
 #include "support/convert.h"
 #include "support/debug.h"
 
 using namespace std;
 using namespace lyx::support;
+using namespace lyx::graphics;
 
 namespace lyx {
 
@@ -127,7 +128,7 @@ namespace {
 
 // Do not remove the comment below, so we get merge conflict in
 // independent branches. Instead add your own.
-int const LYX_FORMAT = 413; // rgh: html_css_as_file
+int const LYX_FORMAT = 416; //uwestoehr : support for horizontal spaces (bug 7728)
 
 typedef map<string, bool> DepClean;
 typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
@@ -150,6 +151,7 @@ public:
 
        ~Impl()
        {
+               delete preview_loader_;
                if (wa_) {
                        wa_->closeAll();
                        delete wa_;
@@ -267,6 +269,9 @@ public:
        /// our Text that should be wrapped in an InsetText
        InsetText * inset;
 
+       ///
+       PreviewLoader * preview_loader_;
+
        /// This is here to force the test to be done whenever parent_buffer
        /// is accessed.
        Buffer const * parent() const { 
@@ -331,10 +336,11 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        Buffer const * cloned_buffer)
        : owner_(owner), lyx_clean(true), bak_clean(true), unnamed(false),
          read_only(readonly_), filename(file), file_fully_loaded(false),
-         toc_backend(owner), macro_lock(false), timestamp_(0),
-         checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
-         bibfile_cache_valid_(false), cite_labels_valid_(false),
-         cloned_buffer_(cloned_buffer), doing_export(false), parent_buffer(0)
+         toc_backend(owner), macro_lock(false), timestamp_(0), checksum_(0),
+         wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false), 
+         bibfile_cache_valid_(false), cite_labels_valid_(false), 
+         preview_loader_(0), cloned_buffer_(cloned_buffer),
+         doing_export(false), parent_buffer(0)
 {
        if (!cloned_buffer_) {
                temppath = createBufferTmpDir();
@@ -427,29 +433,50 @@ Buffer::~Buffer()
 
 Buffer * Buffer::clone() const
 {
+       BufferMap bufmap;
+       masterBuffer()->clone(bufmap);
+       BufferMap::iterator it = bufmap.find(this);
+       LASSERT(it != bufmap.end(), return 0);
+       return it->second;
+}
+
+
+void Buffer::clone(BufferMap & bufmap) const
+{
+       // have we already been cloned?
+       if (bufmap.find(this) != bufmap.end())
+               return;
+
        Buffer * buffer_clone = new Buffer(fileName().absFileName(), false, this);
+       bufmap[this] = buffer_clone;
        buffer_clone->d->macro_lock = true;
        buffer_clone->d->children_positions.clear();
        // FIXME (Abdel 09/01/2010): this is too complicated. The whole children_positions and
        // math macro caches need to be rethought and simplified.
        // I am not sure wether we should handle Buffer cloning here or in BufferList.
        // Right now BufferList knows nothing about buffer clones.
-       Impl::BufferPositionMap::iterator it = d->children_positions.begin();
-       Impl::BufferPositionMap::iterator end = d->children_positions.end();
+       Impl::PositionScopeBufferMap::iterator it = d->position_to_children.begin();
+       Impl::PositionScopeBufferMap::iterator end = d->position_to_children.end();
        for (; it != end; ++it) {
-               DocIterator dit = it->second.clone(buffer_clone);
+               DocIterator dit = it->first.clone(buffer_clone);
                dit.setBuffer(buffer_clone);
-               Buffer * child = const_cast<Buffer *>(it->first);
-               Buffer * child_clone = child->clone();
+               Buffer * child = const_cast<Buffer *>(it->second.second);
+
+               child->clone(bufmap);
+               BufferMap::iterator const bit = bufmap.find(child);
+               LASSERT(bit != bufmap.end(), continue);
+               Buffer * child_clone = bit->second;
+
                Inset * inset = dit.nextInset();
                LASSERT(inset && inset->lyxCode() == INCLUDE_CODE, continue);
                InsetInclude * inset_inc = static_cast<InsetInclude *>(inset);
                inset_inc->setChildBuffer(child_clone);
                child_clone->d->setParent(buffer_clone);
+               // FIXME Do we need to do this now, or can we wait until we run updateMacros()?
                buffer_clone->setChild(dit, child_clone);
        }
        buffer_clone->d->macro_lock = false;
-       return buffer_clone;
+       return;
 }
 
 
@@ -602,7 +629,7 @@ string Buffer::logName(LogType * type) const
        FileName const bname(
                addName(path, onlyFileName(
                        changeExtension(filename,
-                                       formats.extension(bufferFormat()) + ".out"))));
+                                       formats.extension(params().bufferFormat()) + ".out"))));
 
        // Also consider the master buffer log file
        FileName masterfname = fname;
@@ -686,10 +713,10 @@ int Buffer::readHeader(Lexer & lex)
        params().indiceslist().clear();
        params().backgroundcolor = lyx::rgbFromHexName("#ffffff");
        params().isbackgroundcolor = false;
-       params().fontcolor = lyx::rgbFromHexName("#000000");
+       params().fontcolor = RGBColor(0, 0, 0);
        params().isfontcolor = false;
-       params().notefontcolor = lyx::rgbFromHexName("#cccccc");
-       params().boxbgcolor = lyx::rgbFromHexName("#ff0000");
+       params().notefontcolor = RGBColor(0xCC, 0xCC, 0xCC);
+       params().boxbgcolor = RGBColor(0xFF, 0, 0);
        params().html_latex_start.clear();
        params().html_latex_end.clear();
        params().html_math_img_scale = 1.0;
@@ -873,7 +900,12 @@ Buffer::ReadStatus Buffer::readFile(FileName const & fn)
 {
        FileName fname(fn);
        Lexer lex;
-       lex.setFile(fname);
+       if (!lex.setFile(fname)) {
+               Alert::error(_("File Not Found"),
+                       bformat(_("Unable to open file `%1$s'."), 
+                               from_utf8(fn.absFileName())));
+               return ReadFileNotFound;
+       }
 
        int file_format;
        ReadStatus const ret_plf = parseLyXFormat(lex, fn, file_format);
@@ -920,16 +952,35 @@ void Buffer::setFullyLoaded(bool value)
 }
 
 
-void Buffer::updatePreviews() const
+PreviewLoader * Buffer::loader() const
 {
-       if (graphics::Previews::status() != LyXRC::PREVIEW_OFF)
-               thePreviews().generateBufferPreviews(*this);
+       if (lyxrc.preview == LyXRC::PREVIEW_OFF)
+               return 0;
+       if (!d->preview_loader_)
+               d->preview_loader_ = new PreviewLoader(*this);
+       return d->preview_loader_;
 }
 
 
 void Buffer::removePreviews() const
 {
-       thePreviews().removeLoader(*this);
+       delete d->preview_loader_;
+       d->preview_loader_ = 0;
+}
+
+
+void Buffer::updatePreviews() const
+{
+       PreviewLoader * ploader = loader();
+       if (!ploader)
+               return;
+
+       InsetIterator it = inset_iterator_begin(*d->inset);
+       InsetIterator const end = inset_iterator_end(*d->inset);
+       for (; it != end; ++it)
+               it->addPreview(it, *ploader);
+
+       ploader->startLoading();
 }
 
 
@@ -1249,7 +1300,6 @@ bool Buffer::write(ostream & ofs) const
 
 
 bool Buffer::makeLaTeXFile(FileName const & fname,
-                          string const & original_path,
                           OutputParams const & runparams_in,
                           bool output_preamble, bool output_body) const
 {
@@ -1290,8 +1340,7 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
 
        try {
                os.texrow().reset();
-               writeLaTeXSource(os, original_path,
-                     runparams, output_preamble, output_body);
+               writeLaTeXSource(os, runparams, output_preamble, output_body);
        }
        catch (EncodingException & e) {
                odocstringstream ods;
@@ -1334,7 +1383,6 @@ bool Buffer::makeLaTeXFile(FileName const & fname,
 
 
 void Buffer::writeLaTeXSource(otexstream & os,
-                          string const & original_path,
                           OutputParams const & runparams_in,
                           bool const output_preamble, bool const output_body) const
 {
@@ -1361,57 +1409,12 @@ void Buffer::writeLaTeXSource(otexstream & os,
        }
        LYXERR(Debug::INFO, "lyx document header finished");
 
-       // There are a few differences between nice LaTeX and usual files:
-       // usual is \batchmode and has a
-       // special input@path to allow the including of figures
-       // with either \input or \includegraphics (what figinsets do).
-       // input@path is set when the actual parameter
-       // original_path is set. This is done for usual tex-file, but not
-       // for nice-latex-file. (Matthias 250696)
-       // Note that input@path is only needed for something the user does
-       // in the preamble, included .tex files or ERT, files included by
-       // LyX work without it.
+       // With respect to nice LaTeX, usual files have \batchmode
        if (output_preamble) {
                if (!runparams.nice) {
                        // code for usual, NOT nice-latex-file
                        os << "\\batchmode\n"; // changed from \nonstopmode
                }
-               if (!original_path.empty()) {
-                       // FIXME UNICODE
-                       // We don't know the encoding of inputpath
-                       docstring const inputpath = from_utf8(support::latex_path(original_path));
-                       docstring uncodable_glyphs;
-                       Encoding const * const enc = runparams.encoding;
-                       if (enc) {
-                               for (size_t n = 0; n < inputpath.size(); ++n) {
-                                       docstring const glyph =
-                                               docstring(1, inputpath[n]);
-                                       if (enc->latexChar(inputpath[n], true) != glyph) {
-                                               LYXERR0("Uncodable character '"
-                                                       << glyph
-                                                       << "' in input path!");
-                                               uncodable_glyphs += glyph;
-                                       }
-                               }
-                       }
-
-                       // warn user if we found uncodable glyphs.
-                       if (!uncodable_glyphs.empty()) {
-                               frontend::Alert::warning(_("Uncodable character in file path"),
-                                               support::bformat(_("The path of your document\n"
-                                                 "(%1$s)\n"
-                                                 "contains glyphs that are unknown in the\n"
-                                                 "current document encoding (namely %2$s).\n"
-                                                 "This will likely result in incomplete output.\n\n"
-                                                 "Choose an appropriate document encoding (such as utf8)\n"
-                                                 "or change the file path name."), inputpath, uncodable_glyphs));
-                       } else {
-                               os << "\\makeatletter\n"
-                                  << "\\def\\input@path{{"
-                                  << inputpath << "/}}\n"
-                                  << "\\makeatother\n";
-                       }
-               }
 
                // get parent macros (if this buffer has a parent) which will be
                // written at the document begin further down.
@@ -1486,24 +1489,6 @@ void Buffer::writeLaTeXSource(otexstream & os,
 }
 
 
-bool Buffer::isLatex() const
-{
-       return params().documentClass().outputType() == LATEX;
-}
-
-
-bool Buffer::isLiterate() const
-{
-       return params().documentClass().outputType() == LITERATE;
-}
-
-
-bool Buffer::isDocBook() const
-{
-       return params().documentClass().outputType() == DOCBOOK;
-}
-
-
 void Buffer::makeDocBookFile(FileName const & fname,
                              OutputParams const & runparams,
                              bool const body_only) const
@@ -1601,8 +1586,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname,
 
 
 void Buffer::makeLyXHTMLFile(FileName const & fname,
-                             OutputParams const & runparams,
-                             bool const body_only) const
+                             OutputParams const & runparams) const
 {
        LYXERR(Debug::LATEX, "makeLyXHTMLFile...");
 
@@ -1615,7 +1599,7 @@ void Buffer::makeLyXHTMLFile(FileName const & fname,
        updateBuffer(UpdateMaster, OutputUpdate);
        updateMacroInstances(OutputUpdate);
 
-       writeLyXHTMLSource(ofs, runparams, body_only);
+       writeLyXHTMLSource(ofs, runparams);
 
        ofs.close();
        if (ofs.fail())
@@ -1658,6 +1642,21 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
                                << styleinfo
                                << "</style>\n";
                }
+
+               bool const needfg = params().fontcolor != RGBColor(0, 0, 0);
+               bool const needbg = params().backgroundcolor != RGBColor(OxFF, OxFF, OxFF);
+               if (needfg || needbg) {
+                               os << "<style type='text/css'>\nbody {\n";
+                               if (needfg)
+                                  os << "  color: "
+                                           << from_ascii(X11hexname(params().fontcolor))
+                                           << ";\n";
+                               if (needbg)
+                                  os << "  background-color: "
+                                           << from_ascii(X11hexname(params().backgroundcolor))
+                                           << ";\n";
+                               os << "}\n</style>\n";
+               }
                os << "</head>\n<body>\n";
        }
 
@@ -1678,7 +1677,6 @@ int Buffer::runChktex()
        // get LaTeX-Filename
        FileName const path(temppath());
        string const name = addName(path.absFileName(), latexName());
-       string const org_path = filePath();
 
        PathChanger p(path); // path to LaTeX file
        message(_("Running chktex..."));
@@ -1688,7 +1686,7 @@ int Buffer::runChktex()
        runparams.flavor = OutputParams::LATEX;
        runparams.nice = false;
        runparams.linelen = lyxrc.plaintext_linelen;
-       makeLaTeXFile(FileName(name), org_path, runparams);
+       makeLaTeXFile(FileName(name), runparams);
 
        TeXErrors terr;
        Chktex chktex(lyxrc.chktex_command, onlyFileName(name), filePath());
@@ -1917,21 +1915,6 @@ void Buffer::markDepClean(string const & name)
 }
 
 
-bool Buffer::isExportableFormat(string const & format) const
-{
-               typedef vector<Format const *> Formats;
-               Formats formats;
-               formats = exportableFormats(true);
-               Formats::const_iterator fit = formats.begin();
-               Formats::const_iterator end = formats.end();
-               for (; fit != end ; ++fit) {
-                       if ((*fit)->name() == format)
-                               return true;
-               }
-               return false;
-}
-
-
 bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 {
        if (isInternal()) {
@@ -1960,7 +1943,15 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 
                case LFUN_BUFFER_EXPORT: {
                        docstring const arg = cmd.argument();
-                       enable = arg == "custom" || isExportable(to_utf8(arg));
+                       if (arg == "custom") {
+                               enable = true;
+                               break;
+                       }
+                       string format = to_utf8(arg);
+                       size_t pos = format.find(' ');
+                       if (pos != string::npos)
+                               format = format.substr(0, pos);
+                       enable = params().isExportable(format);
                        if (!enable)
                                flag.message(bformat(
                                        _("Don't know how to export to format: %1$s"), arg));
@@ -1968,11 +1959,11 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag)
                }
 
                case LFUN_BUFFER_CHKTEX:
-                       enable = isLatex() && !lyxrc.chktex_command.empty();
+                       enable = params().isLatex() && !lyxrc.chktex_command.empty();
                        break;
 
                case LFUN_BUILD_PROGRAM:
-                       enable = isExportable("program");
+                       enable = params().isExportable("program");
                        break;
 
                case LFUN_BRANCH_ACTIVATE: 
@@ -2083,7 +2074,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
 
                // Execute the command in the background
                Systemcall call;
-               call.startscript(Systemcall::DontWait, command);
+               call.startscript(Systemcall::DontWait, command, filePath());
                break;
        }
 
@@ -2261,7 +2252,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                command2 += quoteName(psname);
                                // First run dvips.
                                // If successful, then spool command
-                               res = one.startscript(Systemcall::Wait, command);
+                               res = one.startscript(Systemcall::Wait, command,
+                                                     filePath());
 
                                if (res == 0) {
                                        // If there's no GUI, we have to wait on this command. Otherwise,
@@ -2269,7 +2261,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                        // file, before it can be printed!!
                                        Systemcall::Starttype stype = use_gui ?
                                                Systemcall::DontWait : Systemcall::Wait;
-                                       res = one.startscript(stype, command2);
+                                       res = one.startscript(stype, command2,
+                                                             filePath());
                                }
                        } else {
                                // case 2: print directly to a printer
@@ -2278,7 +2271,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                                // as above....
                                Systemcall::Starttype stype = use_gui ?
                                        Systemcall::DontWait : Systemcall::Wait;
-                               res = one.startscript(stype, command + quoteName(dviname));
+                               res = one.startscript(stype, command +
+                                               quoteName(dviname), filePath());
                        }
 
                } else {
@@ -2301,7 +2295,7 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                        // as above....
                        Systemcall::Starttype stype = use_gui ?
                                Systemcall::DontWait : Systemcall::Wait;
-                       res = one.startscript(stype, command);
+                       res = one.startscript(stype, command, filePath());
                }
 
                if (res == 0) 
@@ -2313,18 +2307,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr)
                break;
        }
 
-       case LFUN_BUFFER_LANGUAGE: {
-               Language const * oldL = params().language;
-               Language const * newL = languages.getLanguage(argument);
-               if (!newL || oldL == newL)
-                       break;
-               if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual()) {
-                       changeLanguage(oldL, newL);
-                       dr.forceBufferUpdate();
-               }
-               break;
-       }
-
        default:
                dispatched = false;
                break;
@@ -2627,6 +2609,12 @@ ListOfBuffers Buffer::getChildren() const
 {
        ListOfBuffers v;
        collectChildren(v, false);
+       // Make sure we have not included ourselves.
+       ListOfBuffers::iterator bit = find(v.begin(), v.end(), this);
+       if (bit != v.end()) {
+               LYXERR0("Recursive include detected in `" << fileName() << "'.");
+               v.erase(bit);
+       }
        return v;
 }
 
@@ -2635,6 +2623,12 @@ ListOfBuffers Buffer::getDescendents() const
 {
        ListOfBuffers v;
        collectChildren(v, true);
+       // Make sure we have not included ourselves.
+       ListOfBuffers::iterator bit = find(v.begin(), v.end(), this);
+       if (bit != v.end()) {
+               LYXERR0("Recursive include detected in `" << fileName() << "'.");
+               v.erase(bit);
+       }
        return v;
 }
 
@@ -3106,7 +3100,7 @@ void Buffer::getSourceCode(odocstream & os, string const format,
 {
        OutputParams runparams(&params().encoding());
        runparams.nice = true;
-       runparams.flavor = getOutputFlavor(format);
+       runparams.flavor = params().getOutputFlavor(format);
        runparams.linelen = lyxrc.plaintext_linelen;
        // No side effect of file copying and image conversion
        runparams.dryrun = true;
@@ -3116,14 +3110,14 @@ void Buffer::getSourceCode(odocstream & os, string const format,
                d->texrow.reset();
                d->texrow.newline();
                d->texrow.newline();
-               if (isDocBook())
+               if (params().isDocBook())
                        writeDocBookSource(os, absFileName(), runparams, false);
                else if (runparams.flavor == OutputParams::HTML)
                        writeLyXHTMLSource(os, runparams, false);
                else {
                        // latex or literate
                        otexstream ots(os, d->texrow);
-                       writeLaTeXSource(ots, string(), runparams, true, true);
+                       writeLaTeXSource(ots, runparams, true, true);
                }
        } else {
                runparams.par_begin = par_begin;
@@ -3144,7 +3138,7 @@ void Buffer::getSourceCode(odocstream & os, string const format,
                texrow.newline();
                texrow.newline();
                // output paragraphs
-               if (isDocBook())
+               if (params().isDocBook())
                        docbookParagraphs(text(), *this, os, runparams);
                else if (runparams.flavor == OutputParams::HTML) {
                        XHTMLStream xs(os);
@@ -3160,12 +3154,7 @@ void Buffer::getSourceCode(odocstream & os, string const format,
 
 ErrorList & Buffer::errorList(string const & type) const
 {
-       static ErrorList emptyErrorList;
-       map<string, ErrorList>::iterator it = d->errorLists.find(type);
-       if (it == d->errorLists.end())
-               return emptyErrorList;
-
-       return it->second;
+       return d->errorLists[type];
 }
 
 
@@ -3389,74 +3378,6 @@ bool Buffer::autoSave() const
 }
 
 
-string Buffer::bufferFormat() const
-{
-       string format = params().documentClass().outputFormat();
-       if (format == "latex") {
-               if (params().useNonTeXFonts)
-                       return "xetex";
-               if (params().encoding().package() == Encoding::japanese)
-                       return "platex";
-       }
-       return format;
-}
-
-
-string Buffer::getDefaultOutputFormat() const
-{
-       if (!params().default_output_format.empty()
-           && params().default_output_format != "default")
-               return params().default_output_format;
-       if (isDocBook()
-           || params().useNonTeXFonts
-           || params().encoding().package() == Encoding::japanese) {
-               vector<Format const *> const formats = exportableFormats(true);
-               if (formats.empty())
-                       return string();
-               // return the first we find
-               return formats.front()->name();
-       }
-       return lyxrc.default_view_format;
-}
-
-
-OutputParams::FLAVOR Buffer::getOutputFlavor(string const format) const
-{
-       string const dformat = (format.empty() || format == "default") ?
-               getDefaultOutputFormat() : format;
-       DefaultFlavorCache::const_iterator it =
-               default_flavors_.find(dformat);
-
-       if (it != default_flavors_.end())
-               return it->second;
-
-       OutputParams::FLAVOR result = OutputParams::LATEX;
-       
-       if (dformat == "xhtml")
-               result = OutputParams::HTML;
-       else {
-               // Try to determine flavor of default output format
-               vector<string> backs = backends();
-               if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
-                       // Get shortest path to format
-                       Graph::EdgePath path;
-                       for (vector<string>::const_iterator it = backs.begin();
-                           it != backs.end(); ++it) {
-                               Graph::EdgePath p = theConverters().getPath(*it, dformat);
-                               if (!p.empty() && (path.empty() || p.size() < path.size())) {
-                                       path = p;
-                               }
-                       }
-                       if (!path.empty())
-                               result = theConverters().getFlavor(path);
-               }
-       }
-       // cache this flavor
-       default_flavors_[dformat] = result;
-       return result;
-}
-
-
 namespace {
        // helper class, to guarantee this gets reset properly
        class MarkAsExporting   {
@@ -3493,16 +3414,25 @@ bool Buffer::isExporting() const
 }
 
 
-bool Buffer::doExport(string const & format, bool put_in_tempdir,
+bool Buffer::doExport(string const & target, bool put_in_tempdir,
        bool includeall, string & result_file) const
 {
+       OutputParams runparams(&params().encoding());
+       string format = target;
+       string filename;
+       size_t pos = target.find(' ');
+       if (pos != string::npos) {
+               filename = target.substr(pos + 1, target.length() - pos - 1);
+               format = target.substr(0, pos);
+               runparams.export_folder = FileName(filename).onlyPath().realPath();
+               FileName(filename).onlyPath().createPath();
+       }
        MarkAsExporting exporting(this);
        string backend_format;
-       OutputParams runparams(&params().encoding());
        runparams.flavor = OutputParams::LATEX;
        runparams.linelen = lyxrc.plaintext_linelen;
        runparams.includeall = includeall;
-       vector<string> backs = backends();
+       vector<string> backs = params().backends();
        Converters converters = theConverters();
        if (find(backs.begin(), backs.end(), format) == backs.end()) {
                // Get shortest path to format
@@ -3535,14 +3465,18 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                        runparams.flavor = OutputParams::PDFLATEX;
                else if (backend_format == "luatex")
                        runparams.flavor = OutputParams::LUATEX;
+               else if (backend_format == "dviluatex")
+                       runparams.flavor = OutputParams::DVILUATEX;
                else if (backend_format == "xetex")
                        runparams.flavor = OutputParams::XETEX;
        }
 
-       string filename = latexName(false);
-       filename = addName(temppath(), filename);
-       filename = changeExtension(filename,
-                                  formats.extension(backend_format));
+       if (filename.empty()) {
+               filename = latexName(false);
+               filename = addName(temppath(), filename);
+               filename = changeExtension(filename,
+                                          formats.extension(backend_format));
+       }
 
        // Plain text backend
        if (backend_format == "text") {
@@ -3570,14 +3504,14 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        } else if (backend_format == "lyx")
                writeFile(FileName(filename));
        // Docbook backend
-       else if (isDocBook()) {
+       else if (params().isDocBook()) {
                runparams.nice = !put_in_tempdir;
                makeDocBookFile(FileName(filename), runparams);
        }
        // LaTeX backend
        else if (backend_format == format) {
                runparams.nice = true;
-               if (!makeLaTeXFile(FileName(filename), string(), runparams)) {
+               if (!makeLaTeXFile(FileName(filename), runparams)) {
                        if (d->cloned_buffer_) {
                                d->cloned_buffer_->d->errorLists["Export"] =
                                        d->errorLists["Export"];
@@ -3591,7 +3525,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                return false;
        } else {
                runparams.nice = false;
-               if (!makeLaTeXFile(FileName(filename), filePath(), runparams)) {
+               if (!makeLaTeXFile(FileName(filename), runparams)) {
                        if (d->cloned_buffer_) {
                                d->cloned_buffer_->d->errorLists["Export"] =
                                        d->errorLists["Export"];
@@ -3601,7 +3535,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        }
 
        string const error_type = (format == "program")
-               ? "Build" : bufferFormat();
+               ? "Build" : params().bufferFormat();
        ErrorList & error_list = d->errorLists[error_type];
        string const ext = formats.extension(format);
        FileName const tmp_result_file(changeExtension(filename, ext));
@@ -3640,7 +3574,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
                // FIXME: There is a possibility of concurrent access to texrow
                // here from the main GUI thread that should be securized.
                d->cloned_buffer_->d->texrow = d->texrow;
-               string const error_type = bufferFormat();
+               string const error_type = params().bufferFormat();
                d->cloned_buffer_->d->errorLists[error_type] = d->errorLists[error_type];
        }
 
@@ -3657,7 +3591,8 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        // if format == "dvi") to the result dir.
        vector<ExportedFile> const files =
                runparams.exportdata->externalFiles(format);
-       string const dest = onlyPath(result_file);
+       string const dest = runparams.export_folder.empty() ?
+               onlyPath(result_file) : runparams.export_folder;
        bool use_force = use_gui ? lyxrc.export_overwrite == ALL_FILES
                                 : force_overwrite == ALL_FILES;
        CopyStatus status = use_force ? FORCE : SUCCESS;
@@ -3666,9 +3601,19 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
        vector<ExportedFile>::const_iterator const en = files.end();
        for (; it != en && status != CANCEL; ++it) {
                string const fmt = formats.getFormatFromFile(it->sourceName);
+               string fixedName = it->exportName;
+               if (!runparams.export_folder.empty()) {
+                       // Relative pathnames starting with ../ will be sanitized
+                       // if exporting to a different folder
+                       while (fixedName.substr(0, 3) == "../")
+                               fixedName = fixedName.substr(3, fixedName.length() - 3);
+               }
+               FileName fixedFileName = makeAbsPath(fixedName, dest);
+               fixedFileName.onlyPath().createPath();
                status = copyFile(fmt, it->sourceName,
-                       makeAbsPath(it->exportName, dest),
-                       it->exportName, status == FORCE);
+                       fixedFileName,
+                       it->exportName, status == FORCE,
+                       runparams.export_folder.empty());
        }
 
        if (status == CANCEL) {
@@ -3696,15 +3641,15 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir,
 }
 
 
-bool Buffer::doExport(string const & format, bool put_in_tempdir,
-                     bool includeall) const
+bool Buffer::doExport(string const & target, bool put_in_tempdir,
+       bool includeall) const
 {
        string result_file;
        // (1) export with all included children (omit \includeonly)
-       if (includeall && !doExport(format, put_in_tempdir, true, result_file))
+       if (includeall && !doExport(target, put_in_tempdir, true, result_file))
                return false;
        // (2) export with included children only
-       return doExport(format, put_in_tempdir, false, result_file);
+       return doExport(target, put_in_tempdir, false, result_file);
 }
 
 
@@ -3722,55 +3667,6 @@ bool Buffer::preview(string const & format, bool includeall) const
 }
 
 
-bool Buffer::isExportable(string const & format) const
-{
-       vector<string> backs = backends();
-       for (vector<string>::const_iterator it = backs.begin();
-            it != backs.end(); ++it)
-               if (theConverters().isReachable(*it, format))
-                       return true;
-       return false;
-}
-
-
-vector<Format const *> Buffer::exportableFormats(bool only_viewable) const
-{
-       vector<string> const backs = backends();
-       set<string> excludes;
-       if (params().useNonTeXFonts) {
-               excludes.insert("latex");
-               excludes.insert("pdflatex");
-       }
-       vector<Format const *> result =
-               theConverters().getReachable(backs[0], only_viewable, true, excludes);
-       for (vector<string>::const_iterator it = backs.begin() + 1;
-            it != backs.end(); ++it) {
-               vector<Format const *>  r =
-                       theConverters().getReachable(*it, only_viewable, false, excludes);
-               result.insert(result.end(), r.begin(), r.end());
-       }
-       return result;
-}
-
-
-vector<string> Buffer::backends() const
-{
-       vector<string> v;
-       v.push_back(bufferFormat());
-       // FIXME: Don't hardcode format names here, but use a flag
-       if (v.back() == "latex") {
-               v.push_back("pdflatex");
-               v.push_back("luatex");
-               v.push_back("xetex");
-       } else if (v.back() == "xetex")
-               v.push_back("luatex");
-       v.push_back("xhtml");
-       v.push_back("text");
-       v.push_back("lyx");
-       return v;
-}
-
-
 Buffer::ReadStatus Buffer::extractFromVC()
 {
        bool const found = LyXVC::file_not_found_hook(d->filename);
@@ -4126,10 +4022,12 @@ void Buffer::Impl::setLabel(ParIterator & it, UpdateType utype) const
        // Compute the item depth of the paragraph
        par.itemdepth = getItemDepth(it);
 
-       if (layout.margintype == MARGIN_MANUAL
-           || layout.latextype == LATEX_BIB_ENVIRONMENT) {
+       if (layout.margintype == MARGIN_MANUAL) {
                if (par.params().labelWidthString().empty())
                        par.params().labelWidthString(par.expandLabel(layout, bp));
+       } else if (layout.latextype == LATEX_BIB_ENVIRONMENT) {
+               // we do not need to do anything here, since the empty case is
+               // handled during export.
        } else {
                par.params().labelWidthString(docstring());
        }