X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetInclude.cpp;h=88153c6d2d35941ad375977036d292062b5f6756;hb=3d4076b598deb18660e50ec9c327efc3b15f15d0;hp=ce325b27930aef68a01bdcd3a45aedb22867390f;hpb=cb9b7406b0ee16b3b445f5a2cafb190cf2659893;p=lyx.git diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index ce325b2793..88153c6d2d 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -18,8 +18,10 @@ #include "BufferList.h" #include "BufferParams.h" #include "BufferView.h" +#include "Converter.h" #include "Cursor.h" #include "DispatchResult.h" +#include "Encoding.h" #include "ErrorList.h" #include "Exporter.h" #include "Format.h" @@ -29,10 +31,11 @@ #include "LayoutFile.h" #include "LayoutModuleList.h" #include "LyX.h" -#include "LyXFunc.h" #include "LyXRC.h" #include "Lexer.h" #include "MetricsInfo.h" +#include "output_plaintext.h" +#include "output_xhtml.h" #include "OutputParams.h" #include "TextClass.h" #include "TocBackend.h" @@ -47,6 +50,8 @@ #include "insets/InsetListingsParams.h" #include "insets/RenderPreview.h" +#include "mathed/MacroTable.h" + #include "support/convert.h" #include "support/debug.h" #include "support/docstream.h" @@ -57,7 +62,7 @@ #include "support/lstrings.h" // contains #include "support/lyxalgo.h" -#include +#include "support/bind.h" using namespace std; using namespace lyx::support; @@ -133,43 +138,44 @@ FileName const masterFileName(Buffer const & buffer) void add_preview(RenderMonitoredPreview &, InsetInclude const &, Buffer const &); -string const parentFilename(Buffer const & buffer) +string const parentFileName(Buffer const & buffer) { return buffer.absFileName(); } -FileName const includedFilename(Buffer const & buffer, +FileName const includedFileName(Buffer const & buffer, InsetCommandParams const & params) { return makeAbsPath(to_utf8(params["filename"]), - onlyPath(parentFilename(buffer))); + onlyPath(parentFileName(buffer))); } -InsetLabel * createLabel(docstring const & label_str) +InsetLabel * createLabel(Buffer * buf, docstring const & label_str) { if (label_str.empty()) return 0; InsetCommandParams icp(LABEL_CODE); icp["name"] = label_str; - return new InsetLabel(icp); + return new InsetLabel(buf, icp); } } // namespace anon -InsetInclude::InsetInclude(InsetCommandParams const & p) - : InsetCommand(p, "include"), include_label(uniqueID()), +InsetInclude::InsetInclude(Buffer * buf, InsetCommandParams const & p) + : InsetCommand(buf, p), include_label(uniqueID()), preview_(new RenderMonitoredPreview(this)), failedtoload_(false), set_label_(false), label_(0), child_buffer_(0) { - preview_->fileChanged(boost::bind(&InsetInclude::fileChanged, this)); + preview_->fileChanged(bind(&InsetInclude::fileChanged, this)); if (isListings(params())) { InsetListingsParams listing_params(to_utf8(p["lstparams"])); - label_ = createLabel(from_utf8(listing_params.getParamValue("label"))); - } + label_ = createLabel(buffer_, from_utf8(listing_params.getParamValue("label"))); + } else if (isInputOrInclude(params()) && buf) + loadIfNeeded(); } @@ -178,7 +184,7 @@ InsetInclude::InsetInclude(InsetInclude const & other) preview_(new RenderMonitoredPreview(this)), failedtoload_(false), set_label_(false), label_(0), child_buffer_(0) { - preview_->fileChanged(boost::bind(&InsetInclude::fileChanged, this)); + preview_->fileChanged(bind(&InsetInclude::fileChanged, this)); if (other.label_) label_ = new InsetLabel(*other.label_); @@ -187,6 +193,8 @@ InsetInclude::InsetInclude(InsetInclude const & other) InsetInclude::~InsetInclude() { + if (isBufferLoaded()) + buffer().invalidateBibfileCache(); delete label_; } @@ -199,6 +207,12 @@ void InsetInclude::setBuffer(Buffer & buffer) } +void InsetInclude::setChildBuffer(Buffer * buffer) +{ + child_buffer_ = buffer; +} + + ParamInfo const & InsetInclude::findInfo(string const & /* cmdName */) { // FIXME @@ -221,8 +235,7 @@ bool InsetInclude::isCompatibleCommand(string const & s) void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) { - LASSERT(cur.buffer() == &buffer(), return); - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_EDIT: { editIncluded(to_utf8(params()["filename"])); @@ -230,15 +243,16 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) } case LFUN_INSET_MODIFY: { - // It should be OK just to invalidate the cache is setParams() + // It should be OK just to invalidate the cache in setParams() // If not.... // child_buffer_ = 0; InsetCommandParams p(INCLUDE_CODE); if (cmd.getArg(0) == "changetype") { + cur.recordUndo(); InsetCommand::doDispatch(cur, cmd); p = params(); } else - InsetCommand::string2params("include", to_utf8(cmd.argument()), p); + InsetCommand::string2params(to_utf8(cmd.argument()), p); if (!p.getCmdName().empty()) { if (isListings(p)){ InsetListingsParams new_params(to_utf8(p["lstparams"])); @@ -253,12 +267,12 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) if (label_) old_label = label_->getParam("name"); else { - label_ = createLabel(new_label); + label_ = createLabel(buffer_, new_label); label_->setBuffer(buffer()); } if (new_label != old_label) { - label_->updateCommand(new_label); + label_->updateLabelAndRefs(new_label, &cur); // the label might have been adapted (duplicate) if (new_label != label_->getParam("name")) { new_params.addParam("label", "{" + @@ -268,9 +282,11 @@ void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd) } } } + cur.recordUndo(); setParams(p); + cur.forceBufferUpdate(); } else - cur.noUpdate(); + cur.noScreenUpdate(); break; } @@ -299,13 +315,19 @@ void InsetInclude::editIncluded(string const & file) bool InsetInclude::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & flag) const { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_EDIT: - case LFUN_INSET_MODIFY: flag.setEnabled(true); return true; + case LFUN_INSET_MODIFY: + if (cmd.getArg(0) == "changetype") + return InsetCommand::getStatus(cur, cmd, flag); + else + flag.setEnabled(true); + return true; + default: return InsetCommand::getStatus(cur, cmd, flag); } @@ -326,7 +348,19 @@ void InsetInclude::setParams(InsetCommandParams const & p) if (type(params()) == INPUT) add_preview(*preview_, *this, buffer()); - buffer().updateBibfilesCache(); + buffer().invalidateBibfileCache(); +} + + +bool InsetInclude::isChildIncluded() const +{ + std::list includeonlys = + buffer().params().getIncludedChildren(); + if (includeonlys.empty()) + return true; + return (std::find(includeonlys.begin(), + includeonlys.end(), + to_utf8(params()["filename"])) != includeonlys.end()); } @@ -345,13 +379,17 @@ docstring InsetInclude::screenLabel() const temp = buffer().B_("Verbatim Input*"); break; case INCLUDE: - temp = buffer().B_("Include"); + if (isChildIncluded()) + temp = buffer().B_("Include"); + else + temp += buffer().B_("Include (excluded)"); break; case LISTINGS: temp = listings_label_; break; case NONE: - LASSERT(false, /**/); + LASSERT(false, temp = buffer().B_("Unknown")); + break; } temp += ": "; @@ -359,7 +397,7 @@ docstring InsetInclude::screenLabel() const if (params()["filename"].empty()) temp += "???"; else - temp += from_utf8(onlyFilename(to_utf8(params()["filename"]))); + temp += from_utf8(onlyFileName(to_utf8(params()["filename"]))); return temp; } @@ -376,27 +414,28 @@ Buffer * InsetInclude::getChildBuffer() const Buffer * InsetInclude::loadIfNeeded() const { + // This is for background export and preview. We don't even want to + // try to load the cloned child document again. + if (buffer().isClone()) + return child_buffer_; + // Don't try to load it again if we failed before. - if (failedtoload_) + if (failedtoload_ || isVerbatim(params()) || isListings(params())) return 0; + FileName const included_file = includedFileName(buffer(), params()); // Use cached Buffer if possible. if (child_buffer_ != 0) { - if (theBufferList().isLoaded(child_buffer_)) + if (theBufferList().isLoaded(child_buffer_) + // additional sanity check: make sure the Buffer really is + // associated with the file we want. + && child_buffer_ == theBufferList().getBuffer(included_file)) return child_buffer_; // Buffer vanished, so invalidate cache and try to reload. child_buffer_ = 0; } - InsetCommandParams const & p = params(); - if (isVerbatim(p) || isListings(p)) - return 0; - - string const parent_filename = buffer().absFileName(); - FileName const included_file = - makeAbsPath(to_utf8(p["filename"]), onlyPath(parent_filename)); - - if (!isLyXFilename(included_file.absFilename())) + if (!isLyXFileName(included_file.absFileName())) return 0; Buffer * child = theBufferList().getBuffer(included_file); @@ -405,50 +444,65 @@ Buffer * InsetInclude::loadIfNeeded() const if (!included_file.exists()) return 0; - child = theBufferList().newBuffer(included_file.absFilename()); + child = theBufferList().newBuffer(included_file.absFileName()); if (!child) // Buffer creation is not possible. return 0; - if (!child->loadLyXFile(included_file)) { + // Set parent before loading, such that macros can be tracked + child->setParent(&buffer()); + + if (child->loadLyXFile() != Buffer::ReadSuccess) { failedtoload_ = true; + child->setParent(0); //close the buffer we just opened theBufferList().release(child); return 0; } - + if (!child->errorList("Parse").empty()) { // FIXME: Do something. } + } else { + // The file was already loaded, so, simply + // inform parent buffer about local macros. + Buffer const * parent = &buffer(); + child->setParent(parent); + MacroNameSet macros; + child->listMacroNames(macros); + MacroNameSet::const_iterator cit = macros.begin(); + MacroNameSet::const_iterator end = macros.end(); + for (; cit != end; ++cit) + parent->usermacros.insert(*cit); } - child->setParent(&buffer()); + // Cache the child buffer. child_buffer_ = child; return child; } -int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const +void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const { string incfile = to_utf8(params()["filename"]); // Do nothing if no file name has been specified if (incfile.empty()) - return 0; + return; - FileName const included_file = includedFilename(buffer(), params()); + FileName const included_file = includedFileName(buffer(), params()); // Check we're not trying to include ourselves. // FIXME RECURSIVE INCLUDE // This isn't sufficient, as the inclusion could be downstream. // But it'll have to do for now. if (isInputOrInclude(params()) && - buffer().absFileName() == included_file.absFilename()) + buffer().absFileName() == included_file.absFileName()) { Alert::error(_("Recursive input"), bformat(_("Attempted to include file %1$s in itself! " "Ignoring inclusion."), from_utf8(incfile))); - return 0; + return; } Buffer const * const masterBuffer = buffer().masterBuffer(); @@ -457,48 +511,128 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const // buffer directory. if (!FileName::isAbsolute(incfile)) { // FIXME UNICODE - incfile = to_utf8(makeRelPath(from_utf8(included_file.absFilename()), + incfile = to_utf8(makeRelPath(from_utf8(included_file.absFileName()), from_utf8(masterBuffer->filePath()))); } + string exppath = incfile; + if (!runparams.export_folder.empty()) { + exppath = makeAbsPath(exppath, runparams.export_folder).realPath(); + FileName(exppath).onlyPath().createPath(); + } + // write it to a file (so far the complete file) string exportfile; string mangled; // bug 5681 if (type(params()) == LISTINGS) { - exportfile = incfile; - mangled = DocFileName(included_file).mangledFilename(); + exportfile = exppath; + mangled = DocFileName(included_file).mangledFileName(); } else { - exportfile = changeExtension(incfile, ".tex"); - mangled = DocFileName(changeExtension(included_file.absFilename(), ".tex")). - mangledFilename(); + exportfile = changeExtension(exppath, ".tex"); + mangled = DocFileName(changeExtension(included_file.absFileName(), ".tex")). + mangledFileName(); } - FileName const writefile(makeAbsPath(mangled, masterBuffer->temppath())); - if (!runparams.nice) incfile = mangled; - else if (!isValidLaTeXFilename(incfile)) { + else if (!isValidLaTeXFileName(incfile)) { frontend::Alert::warning(_("Invalid filename"), - _("The following filename is likely to cause trouble " - "when running the exported file through LaTeX: ") + - from_utf8(incfile)); + _("The following filename will cause troubles " + "when running the exported file through LaTeX: ") + + from_utf8(incfile)); + } else if (!isValidDVIFileName(incfile)) { + frontend::Alert::warning(_("Problematic filename for DVI"), + _("The following filename can cause troubles " + "when running the exported file through LaTeX " + "and opening the resulting DVI: ") + + from_utf8(incfile), true); } + + FileName const writefile(makeAbsPath(mangled, masterBuffer->temppath())); + LYXERR(Debug::LATEX, "incfile:" << incfile); LYXERR(Debug::LATEX, "exportfile:" << exportfile); LYXERR(Debug::LATEX, "writefile:" << writefile); - if (runparams.inComment || runparams.dryrun) { - //Don't try to load or copy the file if we're - //in a comment or doing a dryrun - } else if (isInputOrInclude(params()) && - isLyXFilename(included_file.absFilename())) { - //if it's a LyX file and we're inputting or including, - //try to load it so we can write the associated latex - if (!loadIfNeeded()) - return false; + string const tex_format = flavor2format(runparams.flavor); + + switch (type(params())) { + case VERB: + case VERBAST: { + incfile = latex_path(incfile); + // FIXME UNICODE + os << '\\' << from_ascii(params().getCmdName()) << '{' + << from_utf8(incfile) << '}'; + break; + } + case INPUT: { + runparams.exportdata->addExternalFile(tex_format, writefile, + exportfile); + + // \input wants file with extension (default is .tex) + if (!isLyXFileName(included_file.absFileName())) { + incfile = latex_path(incfile); + // FIXME UNICODE + os << '\\' << from_ascii(params().getCmdName()) + << '{' << from_utf8(incfile) << '}'; + } else { + incfile = changeExtension(incfile, ".tex"); + incfile = latex_path(incfile); + // FIXME UNICODE + os << '\\' << from_ascii(params().getCmdName()) + << '{' << from_utf8(incfile) << '}'; + } + break; + } + case LISTINGS: { + runparams.exportdata->addExternalFile(tex_format, writefile, + exportfile); + os << '\\' << from_ascii(params().getCmdName()); + string const opt = to_utf8(params()["lstparams"]); + // opt is set in QInclude dialog and should have passed validation. + InsetListingsParams params(opt); + if (!params.params().empty()) + os << "[" << from_utf8(params.params()) << "]"; + os << '{' << from_utf8(incfile) << '}'; + break; + } + case INCLUDE: { + runparams.exportdata->addExternalFile(tex_format, writefile, + exportfile); + + // \include don't want extension and demands that the + // file really have .tex + incfile = changeExtension(incfile, string()); + incfile = latex_path(incfile); + // FIXME UNICODE + os << '\\' << from_ascii(params().getCmdName()) << '{' + << from_utf8(incfile) << '}'; + break; + } + case NONE: + break; + } - Buffer * tmp = theBufferList().getBuffer(included_file); + if (runparams.inComment || runparams.dryrun) + // Don't try to load or copy the file if we're + // in a comment or doing a dryrun + return; + + if (isInputOrInclude(params()) && + isLyXFileName(included_file.absFileName())) { + // if it's a LyX file and we're inputting or including, + // try to load it so we can write the associated latex + + Buffer * tmp = loadIfNeeded(); + if (!tmp) { + docstring text = bformat(_("Could not load included " + "file\n`%1$s'\n" + "Please, check whether it actually exists."), + included_file.displayName()); + Alert::warning(_("Missing included file"), text); + return; + } if (tmp->params().baseClass() != masterBuffer->params().baseClass()) { // FIXME UNICODE @@ -533,23 +667,68 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const tmp->markDepClean(masterBuffer->temppath()); + // Don't assume the child's format is latex + string const inc_format = tmp->params().bufferFormat(); + FileName const tmpwritefile(changeExtension(writefile.absFileName(), + formats.extension(inc_format))); + // FIXME: handle non existing files - // FIXME: Second argument is irrelevant! - // since only_body is true, makeLaTeXFile will not look at second - // argument. Should we set it to string(), or should makeLaTeXFile - // make use of it somehow? (JMarc 20031002) // The included file might be written in a different encoding + // and language. Encoding const * const oldEnc = runparams.encoding; - runparams.encoding = &tmp->params().encoding(); - tmp->makeLaTeXFile(writefile, - masterFileName(buffer()).onlyPath().absFilename(), - runparams, false); + Language const * const oldLang = runparams.master_language; + // If the master has full unicode flavor (XeTeX, LuaTeX), + // the children must be encoded in plain utf8! + runparams.encoding = runparams.isFullUnicode() ? + encodings.fromLyXName("utf8-plain") + : &tmp->params().encoding(); + runparams.master_language = buffer().params().language; + runparams.par_begin = 0; + runparams.par_end = tmp->paragraphs().size(); + runparams.is_child = true; + if (!tmp->makeLaTeXFile(tmpwritefile, masterFileName(buffer()). + onlyPath().absFileName(), runparams, Buffer::OnlyBody)) { + docstring msg = bformat(_("Included file `%1$s' " + "was not exported correctly.\nWarning: " + "LaTeX export is probably incomplete."), + included_file.displayName()); + ErrorList const & el = tmp->errorList("Export"); + if (!el.empty()) + msg = bformat(from_ascii("%1$s\n\n%2$s\n\n%3$s"), + msg, el.begin()->error, + el.begin()->description); + Alert::warning(_("Export failure"), msg); + } runparams.encoding = oldEnc; + runparams.master_language = oldLang; + runparams.is_child = false; + + // If needed, use converters to produce a latex file from the child + if (tmpwritefile != writefile) { + ErrorList el; + bool const success = + theConverters().convert(tmp, tmpwritefile, writefile, + included_file, + inc_format, tex_format, el); + + if (!success) { + docstring msg = bformat(_("Included file `%1$s' " + "was not exported correctly.\nWarning: " + "LaTeX export is probably incomplete."), + included_file.displayName()); + if (!el.empty()) + msg = bformat(from_ascii("%1$s\n\n%2$s\n\n%3$s"), + msg, el.begin()->error, + el.begin()->description); + Alert::warning(_("Export failure"), msg); + } + } } else { // In this case, it's not a LyX file, so we copy the file // to the temp dir, so that .aux files etc. are not created // in the original dir. Files included by this file will be - // found via input@path, see ../Buffer.cpp. + // found via either the environment variable TEXINPUTS, or + // input@path, see ../Buffer.cpp. unsigned long const checksum_in = included_file.checksum(); unsigned long const checksum_out = writefile.checksum(); @@ -558,75 +737,107 @@ int InsetInclude::latex(odocstream & os, OutputParams const & runparams) const // FIXME UNICODE LYXERR(Debug::LATEX, to_utf8(bformat(_("Could not copy the file\n%1$s\n" - "into the temporary directory."), - from_utf8(included_file.absFilename())))); - return 0; + "into the temporary directory."), + from_utf8(included_file.absFileName())))); + return; } } } +} - string const tex_format = (runparams.flavor == OutputParams::LATEX) ? - "latex" : "pdflatex"; - if (isVerbatim(params())) { - incfile = latex_path(incfile); - // FIXME UNICODE - os << '\\' << from_ascii(params().getCmdName()) << '{' - << from_utf8(incfile) << '}'; - } else if (type(params()) == INPUT) { - runparams.exportdata->addExternalFile(tex_format, writefile, - exportfile); - // \input wants file with extension (default is .tex) - if (!isLyXFilename(included_file.absFilename())) { - incfile = latex_path(incfile); - // FIXME UNICODE - os << '\\' << from_ascii(params().getCmdName()) - << '{' << from_utf8(incfile) << '}'; - } else { - incfile = changeExtension(incfile, ".tex"); - incfile = latex_path(incfile); - // FIXME UNICODE - os << '\\' << from_ascii(params().getCmdName()) - << '{' << from_utf8(incfile) << '}'; - } - } else if (type(params()) == LISTINGS) { - os << '\\' << from_ascii(params().getCmdName()); - string const opt = to_utf8(params()["lstparams"]); - // opt is set in QInclude dialog and should have passed validation. - InsetListingsParams params(opt); - if (!params.params().empty()) - os << "[" << from_utf8(params.params()) << "]"; - os << '{' << from_utf8(incfile) << '}'; - } else { - runparams.exportdata->addExternalFile(tex_format, writefile, - exportfile); +docstring InsetInclude::xhtml(XHTMLStream & xs, OutputParams const & rp) const +{ + if (rp.inComment) + return docstring(); + + // For verbatim and listings, we just include the contents of the file as-is. + // In the case of listings, we wrap it in
.
+	bool const listing = isListings(params());
+	if (listing || isVerbatim(params())) {
+		if (listing)
+			xs << html::StartTag("pre");
+		// FIXME: We don't know the encoding of the file, default to UTF-8.
+		xs << includedFileName(buffer(), params()).fileContents("UTF-8");
+		if (listing)
+			xs << html::EndTag("pre");
+		return docstring();
+	}
 
-		// \include don't want extension and demands that the
-		// file really have .tex
-		incfile = changeExtension(incfile, string());
-		incfile = latex_path(incfile);
-		// FIXME UNICODE
-		os << '\\' << from_ascii(params().getCmdName()) << '{'
-		   << from_utf8(incfile) << '}';
+	// We don't (yet) know how to Input or Include non-LyX files.
+	// (If we wanted to get really arcane, we could run some tex2html
+	// converter on the included file. But that's just masochistic.)
+	FileName const included_file = includedFileName(buffer(), params());
+	if (!isLyXFileName(included_file.absFileName())) {
+		frontend::Alert::warning(_("Unsupported Inclusion"),
+					 bformat(_("LyX does not know how to include non-LyX files when "
+					           "generating HTML output. Offending file:\n%1$s"),
+					            params()["filename"]));
+		return docstring();
 	}
 
-	return 0;
+	// In the other cases, we will generate the HTML and include it.
+
+	// Check we're not trying to include ourselves.
+	// FIXME RECURSIVE INCLUDE
+	if (buffer().absFileName() == included_file.absFileName()) {
+		Alert::error(_("Recursive input"),
+			       bformat(_("Attempted to include file %1$s in itself! "
+			       "Ignoring inclusion."), params()["filename"]));
+		return docstring();
+	}
+
+	Buffer const * const ibuf = loadIfNeeded();
+	if (!ibuf)
+		return docstring();
+
+	// are we generating only some paragraphs, or all of them?
+	bool const all_pars = !rp.dryrun || 
+			(rp.par_begin == 0 && 
+			 rp.par_end == (int)buffer().text().paragraphs().size());
+	
+	OutputParams op = rp;
+	if (all_pars) {
+		op.par_begin = 0;
+		op.par_end = 0;
+		ibuf->writeLyXHTMLSource(xs.os(), op, Buffer::IncludedFile);
+	} else
+		xs << XHTMLStream::ESCAPE_NONE 
+		   << "";
+	return docstring();
 }
 
 
-int InsetInclude::plaintext(odocstream & os, OutputParams const &) const
+int InsetInclude::plaintext(odocstringstream & os,
+        OutputParams const & op, size_t) const
 {
+	// just write the filename if we're making a tooltip or toc entry,
+	// or are generating this for advanced search
+	if (op.for_tooltip || op.for_toc || op.for_search) {
+		os << '[' << screenLabel() << '\n'
+		   << getParam("filename") << "\n]";
+		return PLAINTEXT_NEWLINE + 1; // one char on a separate line
+	}
+
 	if (isVerbatim(params()) || isListings(params())) {
-		os << '[' << screenLabel() << '\n';
-		// FIXME: We don't know the encoding of the file, default to UTF-8.
-		os << includedFilename(buffer(), params()).fileContents("UTF-8");
-		os << "\n]";
+		os << '[' << screenLabel() << '\n'
+		   // FIXME: We don't know the encoding of the file, default to UTF-8.
+		   << includedFileName(buffer(), params()).fileContents("UTF-8")
+		   << "\n]";
 		return PLAINTEXT_NEWLINE + 1; // one char on a separate line
-	} else {
+	}
+
+	Buffer const * const ibuf = loadIfNeeded();
+	if (!ibuf) {
 		docstring const str = '[' + screenLabel() + ']';
 		os << str;
 		return str.size();
 	}
+	writePlaintextFile(*ibuf, os, op);
+	return 0;
 }
 
 
@@ -638,7 +849,7 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const
 	if (incfile.empty())
 		return 0;
 
-	string const included_file = includedFilename(buffer(), params()).absFilename();
+	string const included_file = includedFileName(buffer(), params()).absFileName();
 
 	// Check we're not trying to include ourselves.
 	// FIXME RECURSIVE INCLUDE
@@ -651,14 +862,19 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const
 		return 0;
 	}
 
+	string exppath = incfile;
+	if (!runparams.export_folder.empty()) {
+		exppath = makeAbsPath(exppath, runparams.export_folder).realPath();
+		FileName(exppath).onlyPath().createPath();
+	}
+
 	// write it to a file (so far the complete file)
-	string const exportfile = changeExtension(incfile, ".sgml");
+	string const exportfile = changeExtension(exppath, ".sgml");
 	DocFileName writefile(changeExtension(included_file, ".sgml"));
 
-	if (loadIfNeeded()) {
-		Buffer * tmp = theBufferList().getBuffer(FileName(included_file));
-
-		string const mangled = writefile.mangledFilename();
+	Buffer * tmp = loadIfNeeded();
+	if (tmp) {
+		string const mangled = writefile.mangledFileName();
 		writefile = makeAbsPath(mangled,
 					buffer().masterBuffer()->temppath());
 		if (!runparams.nice)
@@ -668,7 +884,7 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const
 		LYXERR(Debug::LATEX, "exportfile:" << exportfile);
 		LYXERR(Debug::LATEX, "writefile:" << writefile);
 
-		tmp->makeDocBookFile(writefile, runparams, true);
+		tmp->makeDocBookFile(writefile, runparams, Buffer::OnlyBody);
 	}
 
 	runparams.exportdata->addExternalFile("docbook", writefile,
@@ -689,27 +905,27 @@ int InsetInclude::docbook(odocstream & os, OutputParams const & runparams) const
 
 void InsetInclude::validate(LaTeXFeatures & features) const
 {
-	string incfile = to_utf8(params()["filename"]);
-	string writefile;
-
-	LASSERT(&buffer() == &features.buffer(), /**/);
+	LATTEST(&buffer() == &features.buffer());
 
+	string incfile = to_utf8(params()["filename"]);
 	string const included_file =
-		includedFilename(buffer(), params()).absFilename();
+		includedFileName(buffer(), params()).absFileName();
 
-	if (isLyXFilename(included_file))
+	string writefile;
+	if (isLyXFileName(included_file))
 		writefile = changeExtension(included_file, ".sgml");
 	else
 		writefile = included_file;
 
 	if (!features.runparams().nice && !isVerbatim(params()) && !isListings(params())) {
-		incfile = DocFileName(writefile).mangledFilename();
+		incfile = DocFileName(writefile).mangledFileName();
 		writefile = makeAbsPath(incfile,
-					buffer().masterBuffer()->temppath()).absFilename();
+					buffer().masterBuffer()->temppath()).absFileName();
 	}
 
 	features.includeFile(include_label, writefile);
 
+	features.useInsetLayout(getLayout());
 	if (isVerbatim(params()))
 		features.require("verbatim");
 	else if (isListings(params()))
@@ -718,9 +934,9 @@ void InsetInclude::validate(LaTeXFeatures & features) const
 	// Here we must do the fun stuff...
 	// Load the file in the include if it needs
 	// to be loaded:
-	if (loadIfNeeded()) {
-		// a file got loaded
-		Buffer * const tmp = theBufferList().getBuffer(FileName(included_file));
+	Buffer * const tmp = loadIfNeeded();
+	if (tmp) {
+		// the file is loaded
 		// make sure the buffer isn't us
 		// FIXME RECURSIVE INCLUDES
 		// This is not sufficient, as recursive includes could be
@@ -730,48 +946,27 @@ void InsetInclude::validate(LaTeXFeatures & features) const
 			// otherwise it would always be the master buffer,
 			// and nested includes would not work.
 			features.setBuffer(*tmp);
+			features.runparams().is_child = true;
 			tmp->validate(features);
+			features.runparams().is_child = false;
 			features.setBuffer(buffer());
 		}
 	}
 }
 
 
-void InsetInclude::fillWithBibKeys(BiblioInfo & keys,
-	InsetIterator const & /*di*/) const
+void InsetInclude::collectBibKeys(InsetIterator const & /*di*/) const
 {
-	if (loadIfNeeded()) {
-		string const included_file = includedFilename(buffer(), params()).absFilename();
-		Buffer * tmp = theBufferList().getBuffer(FileName(included_file));
-		BiblioInfo const & newkeys = tmp->localBibInfo();
-		keys.mergeBiblioInfo(newkeys);
-	}
-}
-
-
-void InsetInclude::updateBibfilesCache()
-{
-	Buffer const * const child = getChildBuffer();
-	if (child)
-		child->updateBibfilesCache(Buffer::UpdateChildOnly);
-}
-
-
-support::FileNameList const &
-	InsetInclude::getBibfilesCache() const
-{
-	Buffer const * const child = getChildBuffer();
-	if (child)
-		return child->getBibfilesCache(Buffer::UpdateChildOnly);
-
-	static support::FileNameList const empty;
-	return empty;
+	Buffer * child = loadIfNeeded();
+	if (!child)
+		return;
+	child->collectBibKeys();
 }
 
 
 void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const
 {
-	LASSERT(mi.base.bv, /**/);
+	LBUFERR(mi.base.bv);
 
 	bool use_preview = false;
 	if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
@@ -797,7 +992,7 @@ void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const
 
 void InsetInclude::draw(PainterInfo & pi, int x, int y) const
 {
-	LASSERT(pi.base.bv, /**/);
+	LBUFERR(pi.base.bv);
 
 	bool use_preview = false;
 	if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
@@ -813,9 +1008,9 @@ void InsetInclude::draw(PainterInfo & pi, int x, int y) const
 }
 
 
-docstring InsetInclude::contextMenu(BufferView const &, int, int) const
+string InsetInclude::contextMenuName() const
 {
-	return from_ascii("context-include");
+	return "context-include";
 }
 
 
@@ -825,6 +1020,13 @@ Inset::DisplayType InsetInclude::display() const
 }
 
 
+docstring InsetInclude::layoutName() const
+{
+	if (isListings(params()))
+		return from_ascii("IncludeListings");
+	return InsetCommand::layoutName();
+}
+
 
 //
 // preview stuff
@@ -846,7 +1048,7 @@ namespace {
 
 bool preview_wanted(InsetCommandParams const & params, Buffer const & buffer)
 {
-	FileName const included_file = includedFilename(buffer, params);
+	FileName const included_file = includedFileName(buffer, params);
 
 	return type(params) == INPUT && params.preview() &&
 		included_file.isReadableFile();
@@ -855,14 +1057,16 @@ bool preview_wanted(InsetCommandParams const & params, Buffer const & buffer)
 
 docstring latexString(InsetInclude const & inset)
 {
-	odocstringstream os;
+	TexRow texrow;
+	odocstringstream ods;
+	otexstream os(ods, texrow);
 	// We don't need to set runparams.encoding since this will be done
 	// by latex() anyway.
 	OutputParams runparams(0);
 	runparams.flavor = OutputParams::LATEX;
 	inset.latex(os, runparams);
 
-	return os.str();
+	return ods.str();
 }
 
 
@@ -872,7 +1076,7 @@ void add_preview(RenderMonitoredPreview & renderer, InsetInclude const & inset,
 	InsetCommandParams const & params = inset.params();
 	if (RenderPreview::status() != LyXRC::PREVIEW_OFF &&
 	    preview_wanted(params, buffer)) {
-		renderer.setAbsFile(includedFilename(buffer, params));
+		renderer.setAbsFile(includedFileName(buffer, params));
 		docstring const snippet = latexString(inset);
 		renderer.addPreview(snippet, buffer);
 	}
@@ -881,24 +1085,25 @@ void add_preview(RenderMonitoredPreview & renderer, InsetInclude const & inset,
 } // namespace anon
 
 
-void InsetInclude::addPreview(graphics::PreviewLoader & ploader) const
+void InsetInclude::addPreview(DocIterator const & /*inset_pos*/,
+	graphics::PreviewLoader & ploader) const
 {
 	Buffer const & buffer = ploader.buffer();
 	if (!preview_wanted(params(), buffer))
 		return;
-	preview_->setAbsFile(includedFilename(buffer, params()));
+	preview_->setAbsFile(includedFileName(buffer, params()));
 	docstring const snippet = latexString(*this);
 	preview_->addPreview(snippet, ploader);
 }
 
 
-void InsetInclude::addToToc(DocIterator const & cpit)
+void InsetInclude::addToToc(DocIterator const & cpit, bool output_active) const
 {
 	TocBackend & backend = buffer().tocBackend();
 
 	if (isListings(params())) {
 		if (label_)
-			label_->addToToc(cpit);
+			label_->addToToc(cpit, output_active);
 
 		InsetListingsParams p(to_utf8(params()["lstparams"]));
 		string caption = p.getParamValue("caption");
@@ -908,7 +1113,7 @@ void InsetInclude::addToToc(DocIterator const & cpit)
 		docstring str = convert(toc.size() + 1)
 			+ ". " +  from_utf8(caption);
 		DocIterator pit = cpit;
-		toc.push_back(TocItem(pit, 0, str));
+		toc.push_back(TocItem(pit, 0, str, output_active));
 		return;
 	}
 	Buffer const * const childbuffer = getChildBuffer();
@@ -917,10 +1122,10 @@ void InsetInclude::addToToc(DocIterator const & cpit)
 
 	Toc & toc = backend.toc("child");
 	docstring str = childbuffer->fileName().displayName();
-	toc.push_back(TocItem(cpit, 0, str));
+	toc.push_back(TocItem(cpit, 0, str, output_active));
 
 	TocList & toclist = backend.tocs();
-	childbuffer->tocBackend().update();
+	childbuffer->tocBackend().update(output_active);
 	TocList const & childtoclist = childbuffer->tocBackend().tocs();
 	TocList::const_iterator it = childtoclist.begin();
 	TocList::const_iterator const end = childtoclist.end();
@@ -936,7 +1141,7 @@ void InsetInclude::updateCommand()
 		return;
 
 	docstring old_label = label_->getParam("name");
-	label_->updateCommand(old_label, false);
+	label_->updateLabel(old_label);
 	// the label might have been adapted (duplicate)
 	docstring new_label = label_->getParam("name");
 	if (old_label == new_label)
@@ -951,18 +1156,21 @@ void InsetInclude::updateCommand()
 	setParams(p);	
 }
 
-void InsetInclude::updateLabels(ParIterator const & it)
+
+void InsetInclude::updateBuffer(ParIterator const & it, UpdateType utype)
 {
+	button_.update(screenLabel(), true);
+
 	Buffer const * const childbuffer = getChildBuffer();
 	if (childbuffer) {
-		childbuffer->updateLabels(Buffer::UpdateChildOnly);
+		childbuffer->updateBuffer(Buffer::UpdateChildOnly, utype);
 		return;
 	}
 	if (!isListings(params()))
 		return;
 
 	if (label_)
-		label_->updateLabels(it);
+		label_->updateBuffer(it, utype);
 
 	InsetListingsParams const par(to_utf8(params()["lstparams"]));
 	if (par.getParamValue("caption").empty()) {
@@ -974,7 +1182,7 @@ void InsetInclude::updateLabels(ParIterator const & it)
 	docstring const cnt = from_ascii("listing");
 	listings_label_ = master.B_("Program Listing");
 	if (counters.hasCounter(cnt)) {
-		counters.step(cnt);
+		counters.step(cnt, utype);
 		listings_label_ += " " + convert(counters.value(cnt));
 	}
 }