#include "graphics/PreviewLoader.h"
#include "insets/RenderPreview.h"
+#include "insets/InsetListingsParams.h"
#include "support/filetools.h"
#include "support/lstrings.h" // contains
namespace lyx {
+
+// Implementation is in LyX.cpp
+extern void dispatch(FuncRequest const & action);
using support::addName;
using support::absolutePath;
using support::DocFileName;
using support::FileName;
using support::getFileContents;
+using support::getVectorFromString;
using support::isFileReadable;
using support::isLyXFilename;
+using support::isValidLaTeXFilename;
using support::latex_path;
using support::makeAbsPath;
using support::makeDisplayPath;
using support::makeRelPath;
using support::onlyFilename;
using support::onlyPath;
+using support::prefixIs;
using support::subst;
using support::sum;
using std::endl;
using std::string;
-using std::auto_ptr;
using std::istringstream;
using std::ostream;
using std::ostringstream;
+using std::vector;
namespace Alert = frontend::Alert;
namespace fs = boost::filesystem;
return "file" + convert<docstring>(++seed);
}
+
+bool isListings(InsetCommandParams const & params)
+{
+ return params.getCmdName() == "lstinputlisting";
+}
+
} // namespace anon
InsetCommandParams p("include");
InsetIncludeMailer::string2params(to_utf8(cmd.argument()), p);
if (!p.getCmdName().empty()) {
+ if (isListings(p)){
+ InsetListingsParams par_old(params().getOptions());
+ InsetListingsParams par_new(p.getOptions());
+ if (par_old.getParamValue("label") !=
+ par_new.getParamValue("label")
+ && !par_new.getParamValue("label").empty())
+ cur.bv().buffer().changeRefsIfUnique(
+ from_utf8(par_old.getParamValue("label")),
+ from_utf8(par_new.getParamValue("label")),
+ Inset::REF_CODE);
+ }
set(p, cur.buffer());
cur.buffer().updateBibfilesCache();
} else
break;
case LFUN_MOUSE_RELEASE:
- InsetIncludeMailer(*this).showDialog(&cur.bv());
+ if (!cur.selection())
+ InsetIncludeMailer(*this).showDialog(&cur.bv());
break;
default:
INCLUDE = 0,
VERB = 1,
INPUT = 2,
- VERBAST = 3
+ VERBAST = 3,
+ LISTINGS = 4,
};
return VERB;
if (command_name == "verbatiminput*")
return VERBAST;
+ if (command_name == "lstinputlisting")
+ return LISTINGS;
return INCLUDE;
}
}
+bool isInputOrInclude(InsetCommandParams const & params)
+{
+ Types const t = type(params);
+ return (t == INPUT) || (t == INCLUDE);
+}
+
+
string const masterFilename(Buffer const & buffer)
{
return buffer.getMasterBuffer()->fileName();
}
-auto_ptr<Inset> InsetInclude::doClone() const
+Inset * InsetInclude::clone() const
{
- return auto_ptr<Inset>(new InsetInclude(*this));
+ return new InsetInclude(*this);
}
}
if (token != "\\end_inset") {
lex.printError("Missing \\end_inset at this point. "
- "Read: `$$Token'");
+ "Read: `$$Token'");
}
}
-docstring const InsetInclude::getScreenLabel(Buffer const &) const
+docstring const InsetInclude::getScreenLabel(Buffer const & buf) const
{
docstring temp;
switch (type(params_)) {
case INPUT:
- temp += _("Input");
+ temp = buf.B_("Input");
break;
case VERB:
- temp += _("Verbatim Input");
+ temp = buf.B_("Verbatim Input");
break;
case VERBAST:
- temp += _("Verbatim Input*");
+ temp = buf.B_("Verbatim Input*");
break;
case INCLUDE:
- temp += _("Include");
+ temp = buf.B_("Include");
break;
+ case LISTINGS: {
+ temp = listings_label_;
+ }
}
temp += ": ";
/// return the child buffer if the file is a LyX doc and is loaded
Buffer * getChildBuffer(Buffer const & buffer, InsetCommandParams const & params)
{
- if (isVerbatim(params))
+ if (isVerbatim(params) || isListings(params))
return 0;
string const included_file = includedFilename(buffer, params).absFilename();
if (!isLyXFilename(included_file))
return 0;
- return theBufferList().getBuffer(included_file);
+ Buffer * childBuffer = theBufferList().getBuffer(included_file);
+
+ //FIXME RECURSIVE INCLUDES
+ if (childBuffer == & buffer)
+ return 0;
+ else
+ return childBuffer;
}
+} // namespace anon
/// return true if the file is or got loaded.
-bool loadIfNeeded(Buffer const & buffer, InsetCommandParams const & params)
+Buffer * loadIfNeeded(Buffer const & parent, InsetCommandParams const & params)
{
- if (isVerbatim(params))
- return false;
+ if (isVerbatim(params) || isListings(params))
+ return 0;
+
+ string const parent_filename = parent.fileName();
+ FileName const included_file = makeAbsPath(to_utf8(params["filename"]),
+ onlyPath(parent_filename));
- FileName const included_file = includedFilename(buffer, params);
if (!isLyXFilename(included_file.absFilename()))
- return false;
+ return 0;
- Buffer * buf = theBufferList().getBuffer(included_file.absFilename());
- if (!buf) {
+ Buffer * child = theBufferList().getBuffer(included_file.absFilename());
+ if (!child) {
// the readonly flag can/will be wrong, not anymore I think.
if (!fs::exists(included_file.toFilesystemEncoding()))
- return false;
- buf = theBufferList().newBuffer(included_file.absFilename());
- if (!loadLyXFile(buf, included_file))
- return false;
+ return 0;
+
+ child = theBufferList().newBuffer(included_file.absFilename());
+ if (!loadLyXFile(child, included_file)) {
+ //close the buffer we just opened
+ theBufferList().close(child, false);
+ return 0;
+ }
}
- if (buf)
- buf->setParentName(parentFilename(buffer));
- return buf != 0;
+ child->setParentName(parent_filename);
+ return child;
}
-} // namespace anon
-
-
int InsetInclude::latex(Buffer const & buffer, odocstream & os,
- OutputParams const & runparams) const
+ OutputParams const & runparams) const
{
string incfile(to_utf8(params_["filename"]));
return 0;
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.fileName() == included_file.absFilename())
+ {
+ Alert::error(_("Recursive input"),
+ bformat(_("Attempted to include file %1$s in itself! "
+ "Ignoring inclusion."), from_utf8(incfile)));
+ return 0;
+ }
+
Buffer const * const m_buffer = buffer.getMasterBuffer();
// if incfile is relative, make it relative to the master
if (!absolutePath(incfile)) {
// FIXME UNICODE
incfile = to_utf8(makeRelPath(from_utf8(included_file.absFilename()),
- from_utf8(m_buffer->filePath())));
+ from_utf8(m_buffer->filePath())));
}
// write it to a file (so far the complete file)
string const exportfile = changeExtension(incfile, ".tex");
- string const mangled = DocFileName(changeExtension(included_file.absFilename(),
- ".tex")).mangledFilename();
+ string const mangled =
+ DocFileName(changeExtension(included_file.absFilename(),".tex")).
+ mangledFilename();
FileName const writefile(makeAbsPath(mangled, m_buffer->temppath()));
if (!runparams.nice)
incfile = mangled;
+ 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));
+ }
LYXERR(Debug::LATEX) << "incfile:" << incfile << endl;
LYXERR(Debug::LATEX) << "exportfile:" << exportfile << endl;
LYXERR(Debug::LATEX) << "writefile:" << writefile << endl;
- if (runparams.inComment || runparams.dryrun)
- // Don't try to load or copy the file
- ;
- else if (loadIfNeeded(buffer, params_)) {
+ 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(buffer, params_))
+ return false;
+
Buffer * tmp = theBufferList().getBuffer(included_file.absFilename());
- if (tmp->params().textclass != m_buffer->params().textclass) {
+ if (tmp->params().getBaseClass() != m_buffer->params().getBaseClass()) {
// FIXME UNICODE
docstring text = bformat(_("Included file `%1$s'\n"
"has textclass `%2$s'\n"
Alert::warning(_("Different textclasses"), text);
//return 0;
}
+
+ // Make sure modules used in child are all included in master
+ //FIXME It might be worth loading the children's modules into the master
+ //over in BufferParams rather than doing this check.
+ vector<string> const masterModules = m_buffer->params().getModules();
+ vector<string> const childModules = tmp->params().getModules();
+ vector<string>::const_iterator it = childModules.begin();
+ vector<string>::const_iterator end = childModules.end();
+ for (; it != end; ++it) {
+ string const module = *it;
+ vector<string>::const_iterator found =
+ find(masterModules.begin(), masterModules.end(), module);
+ if (found != masterModules.end()) {
+ docstring text = bformat(_("Included file `%1$s'\n"
+ "uses module `%2$s'\n"
+ "which is not used in parent file."),
+ makeDisplayPath(included_file.absFilename()), from_utf8(module));
+ Alert::warning(_("Module not found"), text);
+ }
+ }
tmp->markDepClean(m_buffer->temppath());
-#ifdef WITH_WARNINGS
-#warning handle non existing files
-#warning Second argument is irrelevant!
+// 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)
-#endif
// The included file might be written in a different encoding
Encoding const * const oldEnc = runparams.encoding;
runparams.encoding = &tmp->params().encoding();
runparams, false);
runparams.encoding = oldEnc;
} else {
- // 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.
+ // 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.
unsigned long const checksum_in = sum(included_file);
unsigned long const checksum_out = sum(writefile);
os << '\\' << from_ascii(params_.getCmdName())
<< '{' << from_utf8(incfile) << '}';
}
+ } else if (type(params_) == LISTINGS) {
+ os << '\\' << from_ascii(params_.getCmdName());
+ string opt = params_.getOptions();
+ // 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);
int InsetInclude::plaintext(Buffer const & buffer, odocstream & os,
- OutputParams const &) const
+ OutputParams const &) const
{
- if (isVerbatim(params_)) {
+ if (isVerbatim(params_) || isListings(params_)) {
os << '[' << getScreenLabel(buffer) << '\n';
// FIXME: We don't know the encoding of the file
docstring const str =
int InsetInclude::docbook(Buffer const & buffer, odocstream & os,
- OutputParams const & runparams) const
+ OutputParams const & runparams) const
{
string incfile = to_utf8(params_["filename"]);
string const included_file = includedFilename(buffer, params_).absFilename();
+ //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 (buffer.fileName() == included_file) {
+ Alert::error(_("Recursive input"),
+ bformat(_("Attempted to include file %1$s in itself! "
+ "Ignoring inclusion."), from_utf8(incfile)));
+ return 0;
+ }
+
// write it to a file (so far the complete file)
string const exportfile = changeExtension(incfile, ".sgml");
DocFileName writefile(changeExtension(included_file, ".sgml"));
runparams.exportdata->addExternalFile("docbook-xml", writefile,
exportfile);
- if (isVerbatim(params_)) {
+ if (isVerbatim(params_) || isListings(params_)) {
os << "<inlinegraphic fileref=\""
<< '&' << include_label << ';'
<< "\" format=\"linespecific\">";
} else
- os << '&' << include_label << ';';
+ os << '&' << include_label << ';';
return 0;
}
else
writefile = included_file;
- if (!features.runparams().nice && !isVerbatim(params_)) {
+ if (!features.runparams().nice && !isVerbatim(params_) && !isListings(params_)) {
incfile = DocFileName(writefile).mangledFilename();
writefile = makeAbsPath(incfile,
buffer.getMasterBuffer()->temppath()).absFilename();
if (isVerbatim(params_))
features.require("verbatim");
+ else if (isListings(params_))
+ features.require("listings");
// Here we must do the fun stuff...
// Load the file in the include if it needs
if (loadIfNeeded(buffer, params_)) {
// a file got loaded
Buffer * const tmp = theBufferList().getBuffer(included_file);
- if (tmp) {
+ // make sure the buffer isn't us
+ // FIXME RECURSIVE INCLUDES
+ // This is not sufficient, as recursive includes could be
+ // more than a file away. But it will do for now.
+ if (tmp && tmp != & buffer) {
// We must temporarily change features.buffer,
// otherwise it would always be the master buffer,
// and nested includes would not work.
void InsetInclude::getLabelList(Buffer const & buffer,
std::vector<docstring> & list) const
{
- if (loadIfNeeded(buffer, params_)) {
+ if (isListings(params_)) {
+ InsetListingsParams params(params_.getOptions());
+ string label = params.getParamValue("label");
+ if (!label.empty())
+ list.push_back(from_utf8(label));
+ }
+ else if (loadIfNeeded(buffer, params_)) {
string const included_file = includedFilename(buffer, params_).absFilename();
Buffer * tmp = theBufferList().getBuffer(included_file);
tmp->setParentName("");
void InsetInclude::fillWithBibKeys(Buffer const & buffer,
- std::vector<std::pair<string, docstring> > & keys) const
+ BiblioInfo & keys, InsetIterator const & /*di*/) const
{
if (loadIfNeeded(buffer, params_)) {
string const included_file = includedFilename(buffer, params_).absFilename();
Buffer * tmp = theBufferList().getBuffer(included_file);
+ //FIXME This is kind of a dirty hack and should be made reasonable.
tmp->setParentName("");
- tmp->fillWithBibKeys(keys);
+ keys.fillWithBibKeys(tmp);
tmp->setParentName(parentFilename(buffer));
}
}
bool InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const
{
- BOOST_ASSERT(mi.base.bv && mi.base.bv->buffer());
+ BOOST_ASSERT(mi.base.bv);
bool use_preview = false;
if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
graphics::PreviewImage const * pimage =
- preview_->getPreviewImage(*mi.base.bv->buffer());
+ preview_->getPreviewImage(mi.base.bv->buffer());
use_preview = pimage && pimage->image();
}
} else {
if (!set_label_) {
set_label_ = true;
- button_.update(getScreenLabel(*mi.base.bv->buffer()),
+ button_.update(getScreenLabel(mi.base.bv->buffer()),
true);
}
button_.metrics(mi, dim);
{
setPosCache(pi, x, y);
- BOOST_ASSERT(pi.base.bv && pi.base.bv->buffer());
+ BOOST_ASSERT(pi.base.bv);
bool use_preview = false;
if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
graphics::PreviewImage const * pimage =
- preview_->getPreviewImage(*pi.base.bv->buffer());
+ preview_->getPreviewImage(pi.base.bv->buffer());
use_preview = pimage && pimage->image();
}
button_.draw(pi, x, y);
}
-bool InsetInclude::display() const
+
+Inset::DisplayType InsetInclude::display() const
{
- return type(params_) != INPUT;
+ return type(params_) == INPUT ? Inline : AlignCenter;
}
}
-void InsetInclude::addToToc(TocList & toclist, Buffer const & buffer) const
+void InsetInclude::addToToc(TocList & toclist, Buffer const & buffer, ParConstIterator const & pit) const
{
+ if (isListings(params_)) {
+ InsetListingsParams params(params_.getOptions());
+ string caption = params.getParamValue("caption");
+ if (!caption.empty()) {
+ Toc & toc = toclist["listing"];
+ docstring const str = convert<docstring>(toc.size() + 1)
+ + ". " + from_utf8(caption);
+ // This inset does not have a valid ParConstIterator
+ // so it has to use the iterator of its parent paragraph
+ toc.push_back(TocItem(pit, 0, str));
+ }
+ return;
+ }
Buffer const * const childbuffer = getChildBuffer(buffer, params_);
if (!childbuffer)
return;
}
-void InsetInclude::updateLabels(Buffer const & buffer) const
+void InsetInclude::updateLabels(Buffer const & buffer,
+ ParIterator const &)
{
Buffer const * const childbuffer = getChildBuffer(buffer, params_);
- if (!childbuffer)
- return;
+ if (childbuffer)
+ lyx::updateLabels(*childbuffer, true);
+ else if (isListings(params_)) {
+ InsetListingsParams const par = params_.getOptions();
+ if (par.getParamValue("caption").empty())
+ listings_label_.clear();
+ else {
+ Counters & counters = buffer.params().getTextClass().counters();
+ docstring const cnt = from_ascii("listing");
+ if (counters.hasCounter(cnt)) {
+ counters.step(cnt);
+ listings_label_ = buffer.B_("Program Listing ") + convert<docstring>(counters.value(cnt));
+ } else
+ listings_label_ = buffer.B_("Program Listing");
+ }
+ }
+}
+
- lyx::updateLabels(*childbuffer, true);
+void InsetInclude::registerEmbeddedFiles(Buffer const & buffer,
+ EmbeddedFiles & files, ParConstIterator const & pit) const
+{
+ // include and input are temprarily not considered.
+ if (isVerbatim(params_) || isListings(params_))
+ files.registerFile(includedFilename(buffer, params_).absFilename(),
+ EmbeddedFile::AUTO, pit);
}
return print_mailer_error("InsetIncludeMailer", in, 1, name_);
// This is part of the inset proper that is usually swallowed
- // by LyXText::readInset
+ // by Text::readInset
string id;
lex >> id;
if (!lex || id != "Include")