X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetExternal.cpp;h=f604a1fb9d2e0028005a57524e643037b60e35c9;hb=9176e60b7bcab3e355521a86ddb4c2778cd9b29e;hp=a3a739222f1a3f21821ced19ab93c0854c4bb9a0;hpb=d9f13a9072f5cd09c0ecb49c4b1b8238eefdf0f7;p=lyx.git diff --git a/src/insets/InsetExternal.cpp b/src/insets/InsetExternal.cpp index a3a739222f..f604a1fb9d 100644 --- a/src/insets/InsetExternal.cpp +++ b/src/insets/InsetExternal.cpp @@ -18,6 +18,7 @@ #include "Buffer.h" #include "BufferView.h" +#include "Converter.h" #include "Cursor.h" #include "DispatchResult.h" #include "Exporter.h" @@ -29,6 +30,10 @@ #include "LyXRC.h" #include "MetricsInfo.h" #include "OutputParams.h" +#include "output_latex.h" +#include "output_xhtml.h" +#include "texstream.h" +#include "TocBackend.h" #include "frontends/alert.h" #include "frontends/Application.h" @@ -40,13 +45,13 @@ #include "support/ExceptionMessage.h" #include "support/filetools.h" #include "support/gettext.h" +#include "support/lassert.h" #include "support/lstrings.h" #include "support/lyxlib.h" -#include "support/Translator.h" - -#include +#include "support/TempFile.h" #include +#include using namespace std; using namespace lyx::support; @@ -57,7 +62,7 @@ unsigned int const defaultLyxScale = 100; string defaultTemplateName; -} // namespace anon +} // namespace namespace lyx { @@ -68,15 +73,20 @@ namespace external { TempName::TempName() { - FileName const tempname = FileName::tempName("lyxext"); // must have an extension for the converter code to work correctly. - tempname_ = FileName(tempname.absFilename() + ".tmp"); + support::TempFile f("lyxextXXXXXX.tmp"); + // Let f go out of scope here and delete the file ourselves in + // ~TempName(), since otherwise external processes would not be able + // to use the file on windows (bug 9925). This is not as safe as + // keeping a support::TempFile member would be, but the best we can do. + f.setAutoRemove(false); + tempname_ = f.name(); } -TempName::TempName(TempName const &) +TempName::TempName(TempName const & that) { - tempname_ = TempName()(); + *this = that; } @@ -88,23 +98,36 @@ TempName::~TempName() TempName & TempName::operator=(TempName const & other) { - if (this != &other) - tempname_ = TempName()(); + if (this != &other) { + if (!tempname_.empty()) + tempname_.removeFile(); + support::TempFile f("lyxextXXXXXX.tmp"); + f.setAutoRemove(false); + tempname_ = f.name(); + } return *this; } + +support::FileName TempName::operator()() const +{ + return tempname_; +} + } // namespace external InsetExternalParams::InsetExternalParams() : display(true), + preview_mode(PREVIEW_OFF), lyxscale(defaultLyxScale), draft(false) { if (defaultTemplateName.empty()) { external::TemplateManager const & etm = external::TemplateManager::get(); - templatename_ = etm.getTemplates().begin()->first; + if (!etm.getTemplates().empty()) + templatename_ = etm.getTemplates().begin()->first; } else templatename_ = defaultTemplateName; } @@ -126,7 +149,7 @@ void clearIfNotFound(T & data, external::TransformID value, data = T(); } -} // namespace anon +} // namespace void InsetExternalParams::settemplate(string const & name) @@ -148,7 +171,7 @@ void InsetExternalParams::settemplate(string const & name) clearIfNotFound(resizedata, external::Resize, ids); clearIfNotFound(rotationdata, external::Rotate, ids); - // + // preview_mode = et->preview_mode; } @@ -159,7 +182,7 @@ void InsetExternalParams::write(Buffer const & buf, ostream & os) const << "\ttemplate " << templatename() << '\n'; if (!filename.empty()) - os << "\tfilename " << filename.outputFilename(buf.filePath()) << '\n'; + os << "\tfilename " << filename.outputFileName(buf.filePath()) << '\n'; if (!display) os << "\tdisplay false\n"; @@ -263,20 +286,26 @@ bool InsetExternalParams::read(Buffer const & buffer, Lexer & lex) case EX_FILENAME: { lex.eatLine(); string const name = lex.getString(); - filename.set(name, buffer.filePath()); + filename = buffer.getReferencedFileName(name); break; } - + case EX_DISPLAY: { lex.next(); display = lex.getString() != "false"; break; } - case EX_LYXSCALE: + case EX_LYXSCALE: { lex.next(); - lyxscale = lex.getInteger(); + int const ls = lex.getInteger(); + // negative values are not accepted. + if (ls >= 0) + lyxscale = ls; + else + lex.printError("ExternalInset::read: Wrong lyxscale: $$Token"); break; + } case EX_DRAFT: draft = true; @@ -284,13 +313,13 @@ bool InsetExternalParams::read(Buffer const & buffer, Lexer & lex) case EX_BOUNDINGBOX: lex.next(); - clipdata.bbox.xl = lex.getInteger(); + clipdata.bbox.xl = Length(lex.getString()); lex.next(); - clipdata.bbox.yb = lex.getInteger(); + clipdata.bbox.yb = Length(lex.getString()); lex.next(); - clipdata.bbox.xr = lex.getInteger(); + clipdata.bbox.xr = Length(lex.getString()); lex.next(); - clipdata.bbox.yt = lex.getInteger(); + clipdata.bbox.yt = Length(lex.getString()); break; case EX_CLIP: @@ -363,16 +392,41 @@ bool InsetExternalParams::read(Buffer const & buffer, Lexer & lex) } -InsetExternal::InsetExternal(Buffer & buf) - : renderer_(new RenderButton) +namespace { + +docstring screenLabel(InsetExternalParams const & params, + Buffer const & buffer) +{ + external::Template const * const ptr = + external::getTemplatePtr(params); + if (!ptr) + // FIXME UNICODE + return bformat((_("External template %1$s is not installed")), + from_utf8(params.templatename())); + // FIXME UNICODE + docstring gui = _(ptr->guiName); + gui += ": "; + + if (params.filename.empty()) + gui += "???"; + else + gui += from_utf8(params.filename.relFileName(buffer.filePath())); + + return gui; +} + +} // namespace + + +InsetExternal::InsetExternal(Buffer * buf) + : Inset(buf), renderer_(new RenderButton) { - Inset::setBuffer(buf); } +// Mouse hover is not copied and remains empty InsetExternal::InsetExternal(InsetExternal const & other) : Inset(other), - boost::signals::trackable(), params_(other.params_), renderer_(other.renderer_->clone(this)) {} @@ -381,18 +435,25 @@ InsetExternal::InsetExternal(InsetExternal const & other) InsetExternal::~InsetExternal() { hideDialogs("external", this); + + map::iterator it = mouse_hover_.begin(); + map::iterator end = mouse_hover_.end(); + for (; it != end; ++it) + if (it->second) + it->first->clearLastInset(this); } -void InsetExternal::statusChanged() const +bool InsetExternal::setMouseHover(BufferView const * bv, bool mouse_hover) const { - updateFrontend(); + mouse_hover_[bv] = mouse_hover; + return true; } void InsetExternal::doDispatch(Cursor & cur, FuncRequest & cmd) { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_EDIT: { InsetExternalParams p = params(); @@ -405,6 +466,7 @@ void InsetExternal::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_INSET_MODIFY: { InsetExternalParams p; string2params(to_utf8(cmd.argument()), buffer(), p); + cur.recordUndo(); setParams(p); break; } @@ -414,13 +476,6 @@ void InsetExternal::doDispatch(Cursor & cur, FuncRequest & cmd) params2string(params(), cur.bv().buffer())); break; - case LFUN_MOUSE_RELEASE: - if (!cur.selection() && cmd.button() == mouse_button::button1) - cur.bv().showDialog("external", - params2string(params(), cur.bv().buffer()), - this); - break; - default: Inset::doDispatch(cur, cmd); } @@ -430,7 +485,7 @@ void InsetExternal::doDispatch(Cursor & cur, FuncRequest & cmd) bool InsetExternal::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & flag) const { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_EDIT: case LFUN_INSET_MODIFY: @@ -444,22 +499,40 @@ bool InsetExternal::getStatus(Cursor & cur, FuncRequest const & cmd, } -void InsetExternal::edit(Cursor & cur, bool, EntryDirection) +void InsetExternal::addToToc(DocIterator const & cpit, bool output_active, + UpdateType, TocBackend & backend) const { - cur.bv().showDialog("external", - params2string(params(), cur.bv().buffer()), - this); + docstring str = screenLabel(params_, buffer()); + TocBuilder & b = backend.builder("external"); + b.pushItem(cpit, str, output_active); + b.pop(); +} + + +bool InsetExternal::showInsetDialog(BufferView * bv) const +{ + bv->showDialog("external", params2string(params(), bv->buffer()), + const_cast(this)); + return true; } void InsetExternal::metrics(MetricsInfo & mi, Dimension & dim) const { + if (!isRendererValid()) + updatePreview(); + renderer_->metrics(mi, dim); } void InsetExternal::draw(PainterInfo & pi, int x, int y) const { + if (!isRendererValid()) + updatePreview(); + + if (renderer_->asButton()) + renderer_->setRenderState(mouse_hover_[pi.base.bv]); renderer_->draw(pi, x, y); } @@ -480,23 +553,7 @@ graphics::Params get_grfx_params(InsetExternalParams const & eparams) return gparams; } - -docstring screenLabel(InsetExternalParams const & params, - Buffer const & buffer) -{ - external::Template const * const ptr = - external::getTemplatePtr(params); - if (!ptr) - // FIXME UNICODE - return bformat((_("External template %1$s is not installed")), - from_utf8(params.templatename())); - // FIXME UNICODE - docstring gui = _(ptr->guiName); - return from_utf8(external::doSubstitution(params, buffer, - to_utf8(gui), false)); -} - -} // namespace anon +} // namespace static bool isPreviewWanted(InsetExternalParams const & params) @@ -507,13 +564,14 @@ static bool isPreviewWanted(InsetExternalParams const & params) static docstring latexString(InsetExternal const & inset) { - odocstringstream os; + odocstringstream ods; + otexstream os(ods); // We don't need to set runparams.encoding since it is not used by // latex(). OutputParams runparams(0); runparams.flavor = OutputParams::LATEX; inset.latex(os, runparams); - return os.str(); + return ods.str(); } @@ -523,8 +581,7 @@ static void add_preview_and_start_loading(RenderMonitoredPreview & renderer, { InsetExternalParams const & params = inset.params(); - if (RenderPreview::status() != LyXRC::PREVIEW_OFF && - isPreviewWanted(params)) { + if (RenderPreview::previewText() && isPreviewWanted(params)) { renderer.setAbsFile(params.filename); docstring const snippet = latexString(inset); renderer.addPreview(snippet, buffer); @@ -539,9 +596,22 @@ InsetExternalParams const & InsetExternal::params() const } -void InsetExternal::updatePreview() +bool InsetExternal::isPreviewed() const { - setParams(params_); + return (external::getTemplatePtr(params_) && !params_.filename.empty() + && params_.display + && lyxrc.display_graphics + && params_.preview_mode != PREVIEW_OFF + && (params_.preview_mode != PREVIEW_INSTANT + || RenderPreview::previewText())); +} + + +bool InsetExternal::isRendererValid() const +{ + if (!renderer_->asButton()) + return isPreviewed(); + return !isPreviewed(); } @@ -553,18 +623,19 @@ void InsetExternal::setParams(InsetExternalParams const & p) // will use this. defaultTemplateName = params_.templatename(); - if (!external::getTemplatePtr(params_) || params_.filename.empty() - || !params_.display - || !lyxrc.display_graphics - || params_.preview_mode == PREVIEW_OFF - || (params_.preview_mode == PREVIEW_INSTANT - && RenderPreview::status() == LyXRC::PREVIEW_OFF)) { + updatePreview(); +} + + +void InsetExternal::updatePreview() const +{ + if (!isPreviewed()) { RenderButton * button_ptr = renderer_->asButton(); if (!button_ptr) { renderer_.reset(new RenderButton); button_ptr = renderer_->asButton(); } - button_ptr->update(screenLabel(params_, buffer()), true); + button_ptr->update(screenLabel(params_, buffer()), true, false); return; } @@ -574,15 +645,13 @@ void InsetExternal::setParams(InsetExternalParams const & p) LASSERT(false, return); break; case PREVIEW_INSTANT: { + renderer_ = make_unique(this); RenderMonitoredPreview * preview_ptr = renderer_->asMonitoredPreview(); - renderer_.reset(new RenderMonitoredPreview(this)); - preview_ptr = renderer_->asMonitoredPreview(); - preview_ptr->fileChanged(boost::bind(&InsetExternal::fileChanged, this)); - if (preview_ptr->monitoring()) - preview_ptr->stopMonitoring(); + // This connection is closed at the same time as this is destroyed. + preview_ptr->connect([=]() { fileChanged(); }); add_preview_and_start_loading(*preview_ptr, *this, buffer()); break; - } + } case PREVIEW_GRAPHICS: { RenderGraphic * graphic_ptr = renderer_->asGraphic(); if (!graphic_ptr) { @@ -603,7 +672,7 @@ void InsetExternal::fileChanged() const return; RenderMonitoredPreview * const ptr = renderer_->asMonitoredPreview(); - LASSERT(ptr, /**/); + LASSERT(ptr, return); ptr->removePreview(*buffer); add_preview_and_start_loading(*ptr, *this, *buffer); @@ -624,14 +693,14 @@ void InsetExternal::read(Lexer & lex) } -int InsetExternal::latex(odocstream & os, OutputParams const & runparams) const +void InsetExternal::latex(otexstream & os, OutputParams const & runparams) const { if (params_.draft) { // FIXME UNICODE os << "\\fbox{\\ttfamily{}" - << from_utf8(params_.filename.outputFilename(buffer().filePath())) + << from_utf8(params_.filename.outputFileName(buffer().filePath())) << "}\n"; - return 1; + return; } // "nice" means that the buffer is exported to LaTeX format but not @@ -647,35 +716,55 @@ int InsetExternal::latex(odocstream & os, OutputParams const & runparams) const external::Template const * const et_ptr = external::getTemplatePtr(params_); if (!et_ptr) - return 0; + return; external::Template const & et = *et_ptr; external::Template::Formats::const_iterator cit = et.formats.find("PDFLaTeX"); if (cit != et.formats.end()) { - return external::writeExternal(params_, "PDFLaTeX", - buffer(), os, - *(runparams.exportdata), - external_in_tmpdir, - dryrun); + external::RetVal retval = + external::writeExternal(params_, "PDFLaTeX", buffer(), os, + *(runparams.exportdata), external_in_tmpdir, dryrun); + if (retval == external::KILLED) { + LYXERR0("External template preparation killed."); + if (buffer().isClone() && buffer().isExporting()) + throw ConversionException(); + } + return; } } - return external::writeExternal(params_, "LaTeX", buffer(), os, - *(runparams.exportdata), - external_in_tmpdir, - dryrun); + external::RetVal retval = + external::writeExternal(params_, "LaTeX", buffer(), os, + *(runparams.exportdata), external_in_tmpdir, dryrun); + if (retval == external::KILLED) { + LYXERR0("External template preparation killed."); + if (buffer().isClone() && buffer().isExporting()) + throw ConversionException(); + } } -int InsetExternal::plaintext(odocstream & os, - OutputParams const & runparams) const +int InsetExternal::plaintext(odocstringstream & os, + OutputParams const & runparams, size_t) const { - os << '\n'; // output external material on a new line - external::writeExternal(params_, "Ascii", buffer(), os, - *(runparams.exportdata), false, - runparams.dryrun || runparams.inComment); + // this is too slow for constant use + if (runparams.for_tooltip) + return 0; + + bool const external_in_tmpdir = !runparams.nice; + bool const dryrun = runparams.dryrun || runparams.inComment; + otexstream ots(os); + ots << '\n'; // output external material on a new line + external::RetVal retval = + external::writeExternal(params_, "Ascii", buffer(), ots, + *(runparams.exportdata), external_in_tmpdir, dryrun); + if (retval == external::KILLED) { + LYXERR0("External template preparation killed."); + if (buffer().isClone() && buffer().isExporting()) + throw ConversionException(); + } return PLAINTEXT_NEWLINE; } @@ -683,9 +772,40 @@ int InsetExternal::plaintext(odocstream & os, int InsetExternal::docbook(odocstream & os, OutputParams const & runparams) const { - return external::writeExternal(params_, "DocBook", buffer(), os, - *(runparams.exportdata), false, - runparams.dryrun || runparams.inComment); + bool const external_in_tmpdir = !runparams.nice; + bool const dryrun = runparams.dryrun || runparams.inComment; + odocstringstream ods; + otexstream ots(ods); + external::RetVal retval = + external::writeExternal(params_, "DocBook", buffer(), ots, + *(runparams.exportdata), external_in_tmpdir, dryrun); + if (retval == external::KILLED) { + LYXERR0("External template preparation killed."); + if (buffer().isClone() && buffer().isExporting()) + throw ConversionException(); + } + os << ods.str(); + return int(count(ods.str().begin(), ods.str().end(), '\n')); +} + + +docstring InsetExternal::xhtml(XHTMLStream & xs, + OutputParams const & runparams) const +{ + bool const external_in_tmpdir = !runparams.nice; + bool const dryrun = runparams.dryrun || runparams.inComment; + odocstringstream ods; + otexstream ots(ods); + external::RetVal retval = + external::writeExternal(params_, "XHTML", buffer(), ots, + *(runparams.exportdata), external_in_tmpdir, dryrun); + if (retval == external::KILLED) { + LYXERR0("External template preparation killed."); + if (buffer().isClone() && buffer().isExporting()) + throw ConversionException(); + } + xs << XHTMLStream::ESCAPE_NONE << ods.str(); + return docstring(); } @@ -703,14 +823,26 @@ void InsetExternal::validate(LaTeXFeatures & features) const string format; switch (features.runparams().flavor) { case OutputParams::LATEX: + case OutputParams::DVILUATEX: format = "LaTeX"; break; + case OutputParams::LUATEX: case OutputParams::PDFLATEX: + case OutputParams::XETEX: format = "PDFLaTeX"; break; case OutputParams::XML: format = "DocBook"; break; + case OutputParams::HTML: + format = "html"; + break; + case OutputParams::TEXT: + format = "text"; + break; + case OutputParams::LYX: + format = "lyx"; + break; } external::Template::Formats::const_iterator cit = et.formats.find(format); @@ -726,7 +858,7 @@ void InsetExternal::validate(LaTeXFeatures & features) const return; } - // FIXME: We don't need that always + // FIXME: We don't need that always, see InsetGraphics features.require("lyxdot"); vector::const_iterator it = cit->second.requirements.begin(); @@ -736,17 +868,16 @@ void InsetExternal::validate(LaTeXFeatures & features) const external::TemplateManager & etm = external::TemplateManager::get(); - it = cit->second.preambleNames.begin(); - end = cit->second.preambleNames.end(); - for (; it != end; ++it) { - string const preamble = etm.getPreambleDefByName(*it); + for (string const & name : cit->second.preambleNames) { + docstring const preamble = etm.getPreambleDefByName(name); if (!preamble.empty()) features.addPreambleSnippet(preamble); } } -void InsetExternal::addPreview(graphics::PreviewLoader & ploader) const +void InsetExternal::addPreview(DocIterator const & /*inset_pos*/, + graphics::PreviewLoader & ploader) const { RenderMonitoredPreview * const ptr = renderer_->asMonitoredPreview(); if (!ptr) @@ -760,9 +891,9 @@ void InsetExternal::addPreview(graphics::PreviewLoader & ploader) const } -docstring InsetExternal::contextMenu(BufferView const &, int, int) const +string InsetExternal::contextMenuName() const { - return from_ascii("context-external"); + return "context-external"; }