X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2Finsetexternal.C;h=910d3d071a55a3d2230672a217d987144652de64;hb=e28331ed63062dea10d0a21b9ec12034b4b17b9a;hp=c04fb78434875c4f2bb08bfeaf7aa8eb5f5edb31;hpb=2e57f2ff0ae7cd4a6efbf634ffe6d2f4379d9cfc;p=lyx.git diff --git a/src/insets/insetexternal.C b/src/insets/insetexternal.C index c04fb78434..910d3d071a 100644 --- a/src/insets/insetexternal.C +++ b/src/insets/insetexternal.C @@ -5,334 +5,365 @@ * * \author Asger Alstrup Nielsen * - * Full author contact details are available in file CREDITS + * Full author contact details are available in file CREDITS. */ #include #include "insetexternal.h" -#include "insets/renderers.h" +#include "insets/ExternalSupport.h" +#include "insets/ExternalTemplate.h" +#include "insets/render_button.h" +#include "insets/render_graphic.h" +#include "insets/render_preview.h" #include "buffer.h" -#include "BufferView.h" -#include "converter.h" +#include "cursor.h" #include "debug.h" -#include "ExternalTemplate.h" +#include "dispatchresult.h" +#include "exporter.h" +#include "FuncStatus.h" #include "funcrequest.h" #include "gettext.h" #include "LaTeXFeatures.h" -#include "latexrunparams.h" #include "lyx_main.h" #include "lyxlex.h" #include "lyxrc.h" -#include "Lsstream.h" +#include "metricsinfo.h" +#include "outputparams.h" -#include "frontends/lyx_gui.h" -#include "frontends/LyXView.h" -#include "frontends/Dialogs.h" +#include "graphics/PreviewLoader.h" -#include "support/FileInfo.h" #include "support/filetools.h" -#include "support/forkedcall.h" #include "support/lstrings.h" -#include "support/lyxalgo.h" -#include "support/path.h" -#include "support/tostr.h" +#include "support/lyxlib.h" +#include "support/convert.h" +#include "support/translator.h" #include -#include -#include +#include -using namespace lyx::support; - -using std::ostream; using std::endl; +using std::string; using std::auto_ptr; +using std::istringstream; +using std::ostream; +using std::ostringstream; +using std::vector; -namespace { -lyx::graphics::DisplayType const defaultDisplayType = lyx::graphics::NoDisplay; +namespace { -unsigned int defaultLyxScale = 100; +lyx::external::DisplayType const defaultDisplayType = lyx::external::NoDisplay; -/// Substitute meta-variables in string s, makeing use of params and buffer. -string const doSubstitution(InsetExternal::Params const & params, - Buffer const * buffer, string const & s); +unsigned int const defaultLyxScale = 100; -/// Invoke the external editor. -void editExternal(InsetExternal::Params const & params, Buffer const * buffer); +string defaultTemplateName = "RasterImage"; } // namespace anon -InsetExternal::Params::Params() - : display(defaultDisplayType), - lyxscale(defaultLyxScale) -{ - tempname = tempName(string(), "lyxext"); - unlink(tempname); - // must have an extension for the converter code to work correctly. - tempname += ".tmp"; -} +namespace lyx { +namespace external { -InsetExternal::Params::~Params() +TempName::TempName() { - unlink(tempname); + support::FileName const tempname(support::tempName(support::FileName(), "lyxext")); + // FIXME: This is unsafe + support::unlink(tempname); + // must have an extension for the converter code to work correctly. + tempname_ = support::FileName(tempname.absFilename() + ".tmp"); } -InsetExternal::InsetExternal() - : renderer_(new ButtonRenderer) -{} - - -InsetExternal::InsetExternal(InsetExternal const & other) - : InsetOld(other), - boost::signals::trackable(), - params_(other.params_), - renderer_(other.renderer_->clone()) +TempName::TempName(TempName const &) { - GraphicRenderer * ptr = dynamic_cast(renderer_.get()); - if (ptr) { - ptr->connect(boost::bind(&InsetExternal::statusChanged, this)); - } + tempname_ = TempName()(); } -auto_ptr InsetExternal::clone() const +TempName::~TempName() { - return auto_ptr(new InsetExternal(*this)); + support::unlink(tempname_); } -InsetExternal::~InsetExternal() +TempName & +TempName::operator=(TempName const & other) { - InsetExternalMailer(*this).hideDialog(); + if (this != &other) + tempname_ = TempName()(); + return *this; } -void InsetExternal::statusChanged() -{ - BufferView * bv = renderer_->view(); - if (bv) - bv->updateInset(this); -} - +namespace { -dispatch_result InsetExternal::localDispatch(FuncRequest const & cmd) +/// The translator between the Display enum and corresponding lyx string. +Translator const initTranslator() { - switch (cmd.action) { + Translator translator(DefaultDisplay, "default"); - case LFUN_EXTERNAL_EDIT: { - Assert(cmd.view()); - - Buffer const & buffer = *cmd.view()->buffer(); - InsetExternal::Params p; - InsetExternalMailer::string2params(cmd.argument, buffer, p); - editExternal(p, &buffer); - return DISPATCHED_NOUPDATE; - } - - case LFUN_INSET_MODIFY: { - Assert(cmd.view()); - - Buffer const * buffer = cmd.view()->buffer(); - InsetExternal::Params p; - InsetExternalMailer::string2params(cmd.argument, *buffer, p); - setParams(p, buffer); - cmd.view()->updateInset(this); - return DISPATCHED; - } - - case LFUN_INSET_DIALOG_UPDATE: - InsetExternalMailer(*this).updateDialog(cmd.view()); - return DISPATCHED; - - case LFUN_MOUSE_RELEASE: - case LFUN_INSET_EDIT: - InsetExternalMailer(*this).showDialog(cmd.view()); - return DISPATCHED; + // Fill the display translator + translator.addPair(MonochromeDisplay, "monochrome"); + translator.addPair(GrayscaleDisplay, "grayscale"); + translator.addPair(ColorDisplay, "color"); + translator.addPair(PreviewDisplay, "preview"); + translator.addPair(NoDisplay, "none"); - default: - return UNDISPATCHED; - } + return translator; } - -void InsetExternal::metrics(MetricsInfo & mi, Dimension & dim) const -{ - renderer_->metrics(mi, dim); - dim_ = dim; -} +} // namespace anon -void InsetExternal::draw(PainterInfo & pi, int x, int y) const +Translator const & displayTranslator() { - renderer_->draw(pi, x, y); + static Translator const translator = + initTranslator(); + return translator; } +} // namespace external -namespace { - -lyx::graphics::Params get_grfx_params(InsetExternal::Params const & eparams) -{ - lyx::graphics::Params gparams; - - gparams.filename = eparams.filename.absFilename(); - gparams.scale = eparams.lyxscale; - gparams.display = eparams.display; - - if (gparams.display == lyx::graphics::DefaultDisplay) - gparams.display = lyxrc.display_graphics; - - // Override the above if we're not using a gui - if (!lyx_gui::use_gui) - gparams.display = lyx::graphics::NoDisplay; - - return gparams; -} +InsetExternalParams::InsetExternalParams() + : display(defaultDisplayType), + lyxscale(defaultLyxScale), + draft(false), + templatename_(defaultTemplateName) +{} -ExternalTemplate const * getTemplatePtr(InsetExternal::Params const & params) -{ - ExternalTemplateManager & etm = ExternalTemplateManager::get(); - ExternalTemplate const & templ = etm.getTemplateByName(params.templatename); - if (templ.lyxName.empty()) - return 0; - return &templ; -} +namespace { -string const getScreenLabel(InsetExternal::Params const & params, - Buffer const * buffer) +template +void clearIfNotFound(T & data, external::TransformID value, + vector const & ids) { - ExternalTemplate const * const ptr = getTemplatePtr(params); - if (!ptr) - return bformat(_("External template %1$s is not installed"), - params.templatename); - return doSubstitution(params, buffer, ptr->guiName); + typedef vector::const_iterator + const_iterator; + + const_iterator it = ids.begin(); + const_iterator end = ids.end(); + it = std::find(it, end, value); + if (it == end) + data = T(); } } // namespace anon -InsetExternal::Params const & InsetExternal::params() const +void InsetExternalParams::settemplate(string const & name) { - return params_; -} - - -void InsetExternal::setParams(Params const & p, Buffer const * buffer) -{ - // The stored params; what we would like to happen in an ideal world. - params_.filename = p.filename; - params_.templatename = p.templatename; - params_.display = p.display; - params_.lyxscale = p.lyxscale; - - // We display the inset as a button by default. - bool display_button = (!getTemplatePtr(params_) || - params_.filename.empty() || - params_.display == lyx::graphics::NoDisplay); - - if (display_button) { - ButtonRenderer * button_ptr = - dynamic_cast(renderer_.get()); - if (!button_ptr) { - button_ptr = new ButtonRenderer; - renderer_.reset(button_ptr); - } - - button_ptr->update(getScreenLabel(params_, buffer), true); + templatename_ = name; - } else { - GraphicRenderer * graphic_ptr = - dynamic_cast(renderer_.get()); - if (!graphic_ptr) { - graphic_ptr = new GraphicRenderer; - graphic_ptr->connect( - boost::bind(&InsetExternal::statusChanged, this)); - renderer_.reset(graphic_ptr); - } + external::TemplateManager const & etm = + external::TemplateManager::get(); + external::Template const * const et = etm.getTemplateByName(name); + if (!et) + // Be safe. Don't lose data. + return; - graphic_ptr->update(get_grfx_params(params_)); - } + // Ascertain which transforms the template supports. + // Empty all those that it doesn't. + vector const & ids = et->transformIds; + clearIfNotFound(clipdata, external::Clip, ids); + clearIfNotFound(extradata, external::Extra, ids); + clearIfNotFound(resizedata, external::Resize, ids); + clearIfNotFound(rotationdata, external::Rotate, ids); } -void InsetExternal::write(Buffer const * buffer, ostream & os) const +void InsetExternalParams::write(Buffer const & buffer, ostream & os) const { os << "External\n" - << "\ttemplate " << params_.templatename << '\n'; + << "\ttemplate " << templatename() << '\n'; - if (!params_.filename.empty()) + if (!filename.empty()) os << "\tfilename " - << params_.filename.outputFilename(buffer->filePath()) + << filename.outputFilename(buffer.filePath()) << '\n'; - if (params_.display != defaultDisplayType) - os << "\tdisplay " << lyx::graphics::displayTranslator.find(params_.display) + if (display != defaultDisplayType) + os << "\tdisplay " + << external::displayTranslator().find(display) << '\n'; - if (params_.lyxscale != defaultLyxScale) - os << "\tlyxscale " << tostr(params_.lyxscale) << '\n'; + if (lyxscale != defaultLyxScale) + os << "\tlyxscale " << convert(lyxscale) << '\n'; + + if (draft) + os << "\tdraft\n"; + + if (!clipdata.bbox.empty()) + os << "\tboundingBox " << clipdata.bbox << '\n'; + if (clipdata.clip) + os << "\tclip\n"; + + external::ExtraData::const_iterator it = extradata.begin(); + external::ExtraData::const_iterator end = extradata.end(); + for (; it != end; ++it) { + if (!it->second.empty()) + os << "\textra " << it->first << " \"" + << it->second << "\"\n"; + } + + if (!rotationdata.no_rotation()) { + os << "\trotateAngle " << rotationdata.adjAngle() << '\n'; + if (rotationdata.origin() != external::RotationData::DEFAULT) + os << "\trotateOrigin " + << rotationdata.originString() << '\n'; + } + + if (!resizedata.no_resize()) { + using support::float_equal; + double const scl = convert(resizedata.scale); + if (!float_equal(scl, 0.0, 0.05)) { + if (!float_equal(scl, 100.0, 0.05)) + os << "\tscale " + << resizedata.scale << '\n'; + } else { + if (!resizedata.width.zero()) + os << "\twidth " + << resizedata.width.asString() << '\n'; + if (!resizedata.height.zero()) + os << "\theight " + << resizedata.height.asString() << '\n'; + } + if (resizedata.keepAspectRatio) + os << "\tkeepAspectRatio\n"; + } } -void InsetExternal::read(Buffer const * buffer, LyXLex & lex) +bool InsetExternalParams::read(Buffer const & buffer, LyXLex & lex) { enum ExternalTags { EX_TEMPLATE = 1, EX_FILENAME, EX_DISPLAY, EX_LYXSCALE, + EX_DRAFT, + EX_BOUNDINGBOX, + EX_CLIP, + EX_EXTRA, + EX_HEIGHT, + EX_KEEPASPECTRATIO, + EX_ROTATEANGLE, + EX_ROTATEORIGIN, + EX_SCALE, + EX_WIDTH, EX_END }; keyword_item external_tags[] = { - { "\\end_inset", EX_END }, - { "display", EX_DISPLAY}, - { "filename", EX_FILENAME}, - { "lyxscale", EX_LYXSCALE}, - { "template", EX_TEMPLATE } + { "\\end_inset", EX_END }, + { "boundingBox", EX_BOUNDINGBOX }, + { "clip", EX_CLIP }, + { "display", EX_DISPLAY}, + { "draft", EX_DRAFT}, + { "extra", EX_EXTRA }, + { "filename", EX_FILENAME}, + { "height", EX_HEIGHT }, + { "keepAspectRatio", EX_KEEPASPECTRATIO }, + { "lyxscale", EX_LYXSCALE}, + { "rotateAngle", EX_ROTATEANGLE }, + { "rotateOrigin", EX_ROTATEORIGIN }, + { "scale", EX_SCALE }, + { "template", EX_TEMPLATE }, + { "width", EX_WIDTH } }; - lex.pushTable(external_tags, EX_END); + pushpophelper pph(lex, external_tags, EX_END); bool found_end = false; bool read_error = false; - InsetExternal::Params params; while (lex.isOK()) { switch (lex.lex()) { - case EX_TEMPLATE: { + case EX_TEMPLATE: lex.next(); - params.templatename = lex.getString(); + templatename_ = lex.getString(); break; - } case EX_FILENAME: { - lex.next(); + lex.eatLine(); string const name = lex.getString(); - params.filename.set(name, buffer->filePath()); + filename.set(name, buffer.filePath()); break; } case EX_DISPLAY: { lex.next(); string const name = lex.getString(); - params.display = lyx::graphics::displayTranslator.find(name); + display = external::displayTranslator().find(name); break; } - case EX_LYXSCALE: { + case EX_LYXSCALE: lex.next(); - params.lyxscale = lex.getInteger(); + lyxscale = lex.getInteger(); + break; + + case EX_DRAFT: + draft = true; + break; + + case EX_BOUNDINGBOX: + lex.next(); + clipdata.bbox.xl = lex.getInteger(); + lex.next(); + clipdata.bbox.yb = lex.getInteger(); + lex.next(); + clipdata.bbox.xr = lex.getInteger(); + lex.next(); + clipdata.bbox.yt = lex.getInteger(); + break; + + case EX_CLIP: + clipdata.clip = true; + break; + + case EX_EXTRA: { + lex.next(); + string const name = lex.getString(); + lex.next(); + extradata.set(name, lex.getString()); break; } + case EX_HEIGHT: + lex.next(); + resizedata.height = LyXLength(lex.getString()); + break; + + case EX_KEEPASPECTRATIO: + resizedata.keepAspectRatio = true; + break; + + case EX_ROTATEANGLE: + lex.next(); + rotationdata.angle = lex.getString(); + break; + + case EX_ROTATEORIGIN: + lex.next(); + rotationdata.origin(lex.getString()); + break; + + case EX_SCALE: + lex.next(); + resizedata.scale = lex.getString(); + break; + + case EX_WIDTH: + lex.next(); + resizedata.width = LyXLength(lex.getString()); + break; + case EX_END: found_end = true; break; @@ -348,261 +379,469 @@ void InsetExternal::read(Buffer const * buffer, LyXLex & lex) break; } - if (!found_end) { - lex.printError("ExternalInset::read: " - "Missing \\end_inset."); + if (!found_end) + lex.printError("ExternalInsetParams::read: Missing \\end_inset."); + + // This is a trick to make sure that the data are self-consistent. + settemplate(templatename_); + + if (lyxerr.debugging(Debug::EXTERNAL)) { + lyxerr << "InsetExternalParams::read:\n"; + write(buffer, lyxerr); } - lex.popTable(); + return !read_error; +} + + +InsetExternal::InsetExternal() + : renderer_(new RenderButton) +{} + - // Replace the inset's store - setParams(params, buffer); +InsetExternal::InsetExternal(InsetExternal const & other) + : InsetOld(other), + boost::signals::trackable(), + params_(other.params_), + renderer_(other.renderer_->clone(this)) +{} - lyxerr[Debug::INFO] << "InsetExternal::Read: " - << "template: '" << params_.templatename - << "' filename: '" << params_.filename.absFilename() - << "' display: '" << params_.display - << "' scale: '" << params_.lyxscale - << '\'' << endl; + +auto_ptr InsetExternal::doClone() const +{ + return auto_ptr(new InsetExternal(*this)); } -int InsetExternal::write(string const & format, - Buffer const * buf, ostream & os, - bool external_in_tmpdir) const +InsetExternal::~InsetExternal() { - ExternalTemplate const * const et_ptr = getTemplatePtr(params_); - if (!et_ptr) - return 0; - ExternalTemplate const & et = *et_ptr; + InsetExternalMailer(*this).hideDialog(); +} - ExternalTemplate::Formats::const_iterator cit = - et.formats.find(format); - if (cit == et.formats.end()) { - lyxerr << "External template format '" << format - << "' not specified in template " - << params_.templatename << endl; - return 0; - } - updateExternal(format, buf, external_in_tmpdir); - string const str = doSubstitution(params_, buf, cit->second.product); - os << str; - return int(lyx::count(str.begin(), str.end(),'\n') + 1); +void InsetExternal::statusChanged() const +{ + LyX::cref().updateInset(this); } -int InsetExternal::latex(Buffer const * buf, ostream & os, - LatexRunParams const & runparams) const +void InsetExternal::doDispatch(LCursor & cur, FuncRequest & cmd) { - // "nice" means that the buffer is exported to LaTeX format but not - // run through the LaTeX compiler. - // If we're running through the LaTeX compiler, we should write the - // generated files in the bufer's temporary directory. - bool const external_in_tmpdir = - lyxrc.use_tempdir && !buf->tmppath.empty() && !runparams.nice; + switch (cmd.action) { - // If the template has specified a PDFLaTeX output, then we try and - // use that. - if (runparams.flavor == LatexRunParams::PDFLATEX) { - ExternalTemplate const * const et_ptr = getTemplatePtr(params_); - if (!et_ptr) - return 0; - ExternalTemplate const & et = *et_ptr; + case LFUN_EXTERNAL_EDIT: { + Buffer const & buffer = cur.buffer(); + InsetExternalParams p; + InsetExternalMailer::string2params(to_utf8(cmd.argument()), buffer, p); + external::editExternal(p, buffer); + break; + } - ExternalTemplate::Formats::const_iterator cit = - et.formats.find("PDFLaTeX"); - if (cit != et.formats.end()) - return write("PDFLaTeX", buf, os, external_in_tmpdir); + case LFUN_INSET_MODIFY: { + Buffer const & buffer = cur.buffer(); + InsetExternalParams p; + InsetExternalMailer::string2params(to_utf8(cmd.argument()), buffer, p); + setParams(p, buffer); + break; } - return write("LaTeX", buf, os, external_in_tmpdir); + case LFUN_INSET_DIALOG_UPDATE: + InsetExternalMailer(*this).updateDialog(&cur.bv()); + break; + + case LFUN_MOUSE_RELEASE: + InsetExternalMailer(*this).showDialog(&cur.bv()); + break; + + default: + InsetBase::doDispatch(cur, cmd); + } } -int InsetExternal::ascii(Buffer const * buf, ostream & os, int) const +bool InsetExternal::getStatus(LCursor & cur, FuncRequest const & cmd, + FuncStatus & flag) const { - return write("Ascii", buf, os); + switch (cmd.action) { + + case LFUN_EXTERNAL_EDIT: + case LFUN_INSET_MODIFY: + case LFUN_INSET_DIALOG_UPDATE: + flag.enabled(true); + return true; + + default: + return InsetBase::getStatus(cur, cmd, flag); + } } -int InsetExternal::linuxdoc(Buffer const * buf, ostream & os) const +void InsetExternal::edit(LCursor & cur, bool) { - return write("LinuxDoc", buf, os); + InsetExternalMailer(*this).showDialog(&cur.bv()); } -int InsetExternal::docbook(Buffer const * buf, ostream & os, bool) const +bool InsetExternal::metrics(MetricsInfo & mi, Dimension & dim) const { - return write("DocBook", buf, os); + renderer_->metrics(mi, dim); + bool const changed = dim_ != dim; + dim_ = dim; + return changed; } -void InsetExternal::validate(LaTeXFeatures & features) const +void InsetExternal::draw(PainterInfo & pi, int x, int y) const { - ExternalTemplate const * const et_ptr = getTemplatePtr(params_); - if (!et_ptr) - return; - ExternalTemplate const & et = *et_ptr; + setPosCache(pi, x, y); + renderer_->draw(pi, x, y); +} - ExternalTemplate::Formats::const_iterator cit = - et.formats.find("LaTeX"); - if (cit == et.formats.end()) - return; +namespace { + +enum RenderType { + RENDERBUTTON, + RENDERGRAPHIC, + RENDERPREVIEW +}; + - if (!cit->second.requirement.empty()) { - features.require(cit->second.requirement); +RenderType getRenderType(InsetExternalParams const & p) +{ + if (!external::getTemplatePtr(p) || + p.filename.empty() || + p.display == external::NoDisplay) + return RENDERBUTTON; + + if (p.display == external::PreviewDisplay) { + if (RenderPreview::status() != LyXRC::PREVIEW_OFF) + return RENDERPREVIEW; + return RENDERBUTTON; } - if (!cit->second.preamble.empty()) { - features.addExternalPreamble(cit->second.preamble + "\n"); + + if (p.display == external::DefaultDisplay && + lyxrc.display_graphics == graphics::NoDisplay) + return RENDERBUTTON; + return RENDERGRAPHIC; +} + + +graphics::Params get_grfx_params(InsetExternalParams const & eparams) +{ + graphics::Params gparams; + + gparams.filename = eparams.filename; + gparams.scale = eparams.lyxscale; + if (eparams.clipdata.clip) + gparams.bb = eparams.clipdata.bbox; + gparams.angle = convert(eparams.rotationdata.adjAngle()); + + switch (eparams.display) { + case external::DefaultDisplay: + gparams.display = graphics::DefaultDisplay; + break; + case external::MonochromeDisplay: + gparams.display = graphics::MonochromeDisplay; + break; + case external::GrayscaleDisplay: + gparams.display = graphics::GrayscaleDisplay; + break; + case external::ColorDisplay: + gparams.display = graphics::ColorDisplay; + break; + case external::NoDisplay: + gparams.display = graphics::NoDisplay; + break; + default: + BOOST_ASSERT(false); } + if (gparams.display == graphics::DefaultDisplay) + gparams.display = lyxrc.display_graphics; + // Override the above if we're not using a gui + if (!use_gui) + gparams.display = graphics::NoDisplay; + + return gparams; } -void InsetExternal::updateExternal(string const & format, - Buffer const * buf, - bool external_in_tmpdir) const +docstring const getScreenLabel(InsetExternalParams const & params, + Buffer const & buffer) { - ExternalTemplate const * const et_ptr = getTemplatePtr(params_); - if (!et_ptr) - return; - ExternalTemplate const & et = *et_ptr; + external::Template const * const ptr = + external::getTemplatePtr(params); + if (!ptr) + // FIXME UNICODE + return support::bformat((_("External template %1$s is not installed")), + from_utf8(params.templatename())); + // FIXME UNICODE + return from_utf8(external::doSubstitution(params, buffer, + ptr->guiName, false)); +} - if (!et.automaticProduction) - return; +void add_preview_and_start_loading(RenderMonitoredPreview &, + InsetExternal const &, + Buffer const &); - ExternalTemplate::Formats::const_iterator cit = - et.formats.find(format); - if (cit == et.formats.end()) - return; +} // namespace anon - ExternalTemplate::FormatTemplate const & outputFormat = cit->second; - if (outputFormat.updateResult.empty()) - return; - string from_format = et.inputFormat; - if (from_format.empty()) - return; +InsetExternalParams const & InsetExternal::params() const +{ + return params_; +} + + +void InsetExternal::setParams(InsetExternalParams const & p, + Buffer const & buffer) +{ + params_ = p; + + // Subsequent calls to the InsetExternal::Params default constructor + // will use this. + defaultTemplateName = params_.templatename(); + + switch (getRenderType(params_)) { + case RENDERBUTTON: { + RenderButton * button_ptr = renderer_->asButton(); + if (!button_ptr) { + renderer_.reset(new RenderButton); + button_ptr = renderer_->asButton(); + } + + button_ptr->update(getScreenLabel(params_, buffer), true); + break; + + } case RENDERGRAPHIC: { + RenderGraphic * graphic_ptr = renderer_->asGraphic(); + if (!graphic_ptr) { + renderer_.reset(new RenderGraphic(this)); + graphic_ptr = renderer_->asGraphic(); + } + + graphic_ptr->update(get_grfx_params(params_)); + + break; - string from_file = params_.filename.absFilename(); + } case RENDERPREVIEW: { + RenderMonitoredPreview * preview_ptr = + renderer_->asMonitoredPreview(); + if (!preview_ptr) { + renderer_.reset(new RenderMonitoredPreview(this)); + preview_ptr = renderer_->asMonitoredPreview(); + preview_ptr->fileChanged( + boost::bind(&InsetExternal::fileChanged, this)); + } - if (from_format == "*") { - if (from_file.empty()) - return; + if (preview_ptr->monitoring()) + preview_ptr->stopMonitoring(); + add_preview_and_start_loading(*preview_ptr, *this, buffer); - // Try and ascertain the file format from its contents. - from_format = getExtFromContents(from_file); - if (from_format.empty()) - return; + break; + } } +} - string const to_format = outputFormat.updateFormat; - if (to_format.empty()) - return; - if (!converters.isReachable(from_format, to_format)) { - lyxerr << "InsetExternal::updateExternal. " - "Unable to convert from " - << from_format << " to " << to_format << endl; +void InsetExternal::fileChanged() const +{ + Buffer const * const buffer_ptr = LyX::cref().updateInset(this); + if (!buffer_ptr) return; - } - if (external_in_tmpdir && !from_file.empty()) { - // We are running stuff through LaTeX - from_file = copyFileToDir(buf->tmppath, from_file); - if (from_file.empty()) - return; + RenderMonitoredPreview * const ptr = renderer_->asMonitoredPreview(); + BOOST_ASSERT(ptr); + + Buffer const & buffer = *buffer_ptr; + ptr->removePreview(buffer); + add_preview_and_start_loading(*ptr, *this, buffer); +} + + +void InsetExternal::write(Buffer const & buffer, ostream & os) const +{ + params_.write(buffer, os); +} + + +void InsetExternal::read(Buffer const & buffer, LyXLex & lex) +{ + InsetExternalParams params; + if (params.read(buffer, lex)) + setParams(params, buffer); +} + + +int InsetExternal::latex(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const +{ + if (params_.draft) { + // FIXME UNICODE + os << "\\fbox{\\ttfamily{}" + << from_utf8(params_.filename.outputFilename(buf.filePath())) + << "}\n"; + return 1; } - string const to_file = doSubstitution(params_, buf, - outputFormat.updateResult); - - FileInfo fi(from_file); - string abs_to_file = to_file; - if (!AbsolutePath(to_file)) - abs_to_file = MakeAbsPath(to_file, OnlyPath(from_file)); - FileInfo fi2(abs_to_file); - if (fi2.exist() && fi.exist() && - difftime(fi2.getModificationTime(), - fi.getModificationTime()) >= 0) { - } else { - string const to_filebase = ChangeExtension(to_file, string()); - converters.convert(buf, from_file, to_filebase, - from_format, to_format); + // "nice" means that the buffer is exported to LaTeX format but not + // run through the LaTeX compiler. + // If we're running through the LaTeX compiler, we should write the + // generated files in the bufer's temporary directory. + bool const external_in_tmpdir = !runparams.nice && !runparams.dryrun; + + // If the template has specified a PDFLaTeX output, then we try and + // use that. + if (runparams.flavor == OutputParams::PDFLATEX) { + external::Template const * const et_ptr = + external::getTemplatePtr(params_); + if (!et_ptr) + return 0; + 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", + buf, os, + *(runparams.exportdata), + external_in_tmpdir, + runparams.inComment); + } + } + + return external::writeExternal(params_, "LaTeX", buf, os, + *(runparams.exportdata), + external_in_tmpdir, + runparams.inComment); } -namespace { +int InsetExternal::plaintext(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const +{ + return external::writeExternal(params_, "Ascii", buf, os, + *(runparams.exportdata), false, + runparams.inComment); +} -/// Substitute meta-variables in this string -string const doSubstitution(InsetExternal::Params const & params, - Buffer const * buffer, string const & s) -{ - string result; - string const buffer_path = buffer ? buffer->filePath() : string(); - string const filename = params.filename.outputFilename(buffer_path); - string const basename = ChangeExtension(filename, string()); - string const filepath = OnlyPath(filename); - - result = subst(s, "$$FName", filename); - result = subst(result, "$$Basename", basename); - result = subst(result, "$$FPath", filepath); - result = subst(result, "$$Tempname", params.tempname); - result = subst(result, "$$Sysdir", system_lyxdir); - - // Handle the $$Contents(filename) syntax - if (contains(result, "$$Contents(\"")) { - - string::size_type const pos = result.find("$$Contents(\""); - string::size_type const end = result.find("\")", pos); - string const file = result.substr(pos + 12, end - (pos + 12)); - string contents; - if (buffer) { - Path p(buffer->filePath()); - if (!IsFileReadable(file)) - Path p(buffer->tmppath); - if (IsFileReadable(file)) - contents = GetFileContents(file); - } else { - contents = GetFileContents(file); - } - result = subst(result, - ("$$Contents(\"" + file + "\")").c_str(), - contents); - } - return result; +int InsetExternal::docbook(Buffer const & buf, odocstream & os, + OutputParams const & runparams) const +{ + return external::writeExternal(params_, "DocBook", buf, os, + *(runparams.exportdata), false, + runparams.inComment); } -void editExternal(InsetExternal::Params const & params, Buffer const * buffer) +void InsetExternal::validate(LaTeXFeatures & features) const { - if (!buffer) + if (params_.draft) return; - ExternalTemplate const * const et_ptr = getTemplatePtr(params); + external::Template const * const et_ptr = + external::getTemplatePtr(params_); if (!et_ptr) return; - ExternalTemplate const & et = *et_ptr; - - if (et.editCommand.empty()) + external::Template const & et = *et_ptr; + + string format; + switch (features.runparams().flavor) { + case OutputParams::LATEX: + format = "LaTeX"; + break; + case OutputParams::PDFLATEX: + format = "PDFLaTeX"; + break; + case OutputParams::XML: + format = "DocBook"; + break; + } + external::Template::Formats::const_iterator cit = + et.formats.find(format); + if (cit == et.formats.end()) return; - string const command = doSubstitution(params, buffer, et.editCommand); + // FIXME: We don't need that always + features.require("lyxdot"); + + vector::const_iterator it = cit->second.requirements.begin(); + vector::const_iterator end = cit->second.requirements.end(); + for (; it != end; ++it) + features.require(*it); + + 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); + if (!preamble.empty()) + features.addPreambleSnippet(preamble); + } +} + + +// +// preview stuff +// + +namespace { + +bool preview_wanted(InsetExternalParams const & params) +{ + return params.display == external::PreviewDisplay && + support::isFileReadable(params.filename); +} + + +docstring const latex_string(InsetExternal const & inset, Buffer const & buffer) +{ + odocstringstream os; + OutputParams runparams; + runparams.flavor = OutputParams::LATEX; + inset.latex(buffer, os, runparams); + return os.str(); +} + - Path p(buffer->filePath()); - Forkedcall call; - if (lyxerr.debugging()) { - lyxerr << "Executing '" << command << "' in '" - << buffer->filePath() << '\'' << endl; +void add_preview_and_start_loading(RenderMonitoredPreview & renderer, + InsetExternal const & inset, + Buffer const & buffer) +{ + InsetExternalParams const & params = inset.params(); + + if (RenderPreview::status() != LyXRC::PREVIEW_OFF && + preview_wanted(params)) { + renderer.setAbsFile(params.filename); + docstring const snippet = latex_string(inset, buffer); + renderer.addPreview(snippet, buffer); + renderer.startLoading(buffer); } - call.startscript(Forkedcall::DontWait, command); } } // namespace anon + +void InsetExternal::addPreview(graphics::PreviewLoader & ploader) const +{ + RenderMonitoredPreview * const ptr = renderer_->asMonitoredPreview(); + if (!ptr) + return; + + if (preview_wanted(params())) { + ptr->setAbsFile(params_.filename); + docstring const snippet = latex_string(*this, ploader.buffer()); + ptr->addPreview(snippet, ploader); + } +} + + +/// Mailer stuff + string const InsetExternalMailer::name_("external"); InsetExternalMailer::InsetExternalMailer(InsetExternal & inset) @@ -618,50 +857,41 @@ string const InsetExternalMailer::inset2string(Buffer const & buffer) const void InsetExternalMailer::string2params(string const & in, Buffer const & buffer, - InsetExternal::Params & params) + InsetExternalParams & params) { - params = InsetExternal::Params(); - + params = InsetExternalParams(); if (in.empty()) return; - istringstream data(STRCONV(in)); + istringstream data(in); LyXLex lex(0,0); lex.setStream(data); - if (lex.isOK()) { - lex.next(); - string const token = lex.getString(); - if (token != name_) - return; - } + string name; + lex >> name; + if (!lex || name != name_) + return print_mailer_error("InsetExternalMailer", in, 1, name_); // This is part of the inset proper that is usually swallowed - // by Buffer::readInset - if (lex.isOK()) { - lex.next(); - string const token = lex.getString(); - if (token != "External") - return; - } + // by LyXText::readInset + string id; + lex >> id; + if (!lex || id != "External") + return print_mailer_error("InsetBoxMailer", in, 2, "External"); - if (lex.isOK()) { - InsetExternal inset; - inset.read(&buffer, lex); - params = inset.params(); - } + params.read(buffer, lex); } string const -InsetExternalMailer::params2string(InsetExternal::Params const & params, +InsetExternalMailer::params2string(InsetExternalParams const & params, Buffer const & buffer) { - InsetExternal inset; - inset.setParams(params, &buffer); ostringstream data; data << name_ << ' '; - inset.write(&buffer, data); + params.write(buffer, data); data << "\\end_inset\n"; - return STRCONV(data.str()); + return data.str(); } + +} // namespace lyx