#include <config.h>
-#include "InsetLayout.h"
#include "InsetText.h"
+#include "mathed/MacroTable.h"
+
#include "insets/InsetArgument.h"
#include "insets/InsetLayout.h"
+#include "insets/InsetPreview.h"
+
+#include "graphics/PreviewImage.h"
+#include "graphics/PreviewLoader.h"
#include "buffer_funcs.h"
#include "Buffer.h"
#include "CutAndPaste.h"
#include "DispatchResult.h"
#include "ErrorList.h"
+#include "Exporter.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
#include "InsetList.h"
#include "support/convert.h"
#include "support/debug.h"
+#include "support/filetools.h"
#include "support/gettext.h"
#include "support/lassert.h"
#include "support/lstrings.h"
#include "support/Changer.h"
+#include "support/FileName.h"
#include <algorithm>
#include <stack>
namespace lyx {
-using graphics::PreviewLoader;
-
-
/////////////////////////////////////////////////////////////////////
InsetText::InsetText(Buffer * buf, UsePlain type)
// environment. Standard collapsible insets should not
// redefine this, non-standard ones may call this.
InsetLayout const & il = getLayout();
+
if (il.forceOwnlines())
os << breakln;
bool needendgroup = false;
}
-
void InsetText::docbook(XMLStream & xs, OutputParams const & rp) const
{
docbook(xs, rp, WriteEverything);
void InsetText::docbook(XMLStream & xs, OutputParams const & rp, XHTMLOptions opts) const
{
- // we will always want to output all our paragraphs when we are
- // called this way.
+ // Always output all the paragraphs.
OutputParams runparams = rp;
runparams.par_begin = 0;
runparams.par_end = text().paragraphs().size();
return;
}
- InsetLayout const & il = getLayout();
+ InsetLayout const &il = getLayout();
- // Maybe this is an <info> paragraph that should not be generated at all (i.e. right now, its place is somewhere
- // else, typically outside the current paragraph).
+ // Maybe this is an <info> paragraph that should not be generated
+ // at all (i.e. right now, its place is somewhere else, typically outside
+ // the current paragraph).
if (!rp.docbook_generate_info && il.docbookininfo() != "never")
return;
+ // Maybe this inset must be rendered before being output.
+ if (il.docbookrenderasimage()) {
+ docbookRenderAsImage(xs, runparams, opts);
+ return;
+ }
+
+ // If none of the special cases before apply, output the inset.
+ docbookText(xs, runparams, opts);
+}
+
+
+void InsetText::docbookRenderAsImage(XMLStream & xs, OutputParams const & rp, XHTMLOptions opts) const
+{
+ LASSERT(getLayout().docbookrenderasimage(), return);
+
+ // Generate the LaTeX code to compile in order to get the image.
+ // This code actually does the same as an InsetPreview, but without
+ // an InsetPreview.
+ // Also, the image must be generated before the DocBook output is finished,
+ // unlike a preview that is not immediately required for display.
+ docstring const latex_snippet = insetToLaTeXSnippet(&buffer(), this);
+ std::string const snippet = support::trim(to_utf8(latex_snippet));
+ // TODO: no real support for Unicode. This code is very similar to RenderPreview::addPreview, the same gotcha applies.
+
+ graphics::PreviewLoader* loader = buffer().loader();
+ // This should be OK because we are exporting
+ LASSERT(loader != nullptr, return);
+ loader->add(snippet);
+ loader->startLoading(true); // Generate the image and wait until done.
+ graphics::PreviewImage const * img = loader->preview(snippet);
+ LASSERT(img != nullptr, return);
+ support::FileName const & filename = img->filename();
+
+ // Use a file name that is only determined by the LaTeX code: the name of
+ // the snippet is more or less random (i.e., if the user generates the file
+ // several times, they will have a clutter of preview files).
+ // Hence: use a cryptographic hash of the snippet. If the snippet changes,
+ // the file name will change a lot; two snippets are unlikely to have the
+ // same hash (by design of cryptographic hash functions). Computing a hash
+ // is typically slow, but extremely fast compared to compilation of the
+ // preview and image rendering.
+ std::string newFileName = "lyx_" + sanitizeFileName(toHexHash(snippet)) + "." + filename.extension();
+
+ // Copy the image into the right folder.
+ rp.exportdata->addExternalFile("docbook5", filename, newFileName);
+
+ // TODO: deal with opts. What exactly is the WriterOuterTag here, for instance?
+ // Start writing the DocBook code for the image.
+ xs << xml::StartTag("mediaobject")
+ << xml::CR();
+
+ // Output the rendered inset.
+ xs << xml::StartTag("imageobject")
+ << xml::CR()
+ << xml::CompTag("imagedata", std::string("fileref='") + newFileName + "'")
+ << xml::CR()
+ << xml::EndTag("imageobject")
+ << xml::CR();
+
+ // Output the raw content.
+ xs << xml::StartTag("textobject")
+ << xml::CR()
+ << xml::StartTag("programlisting", "language='latex' role='" + getLayout().latexname() + "'");
+ docbookText(xs, rp, opts);
+ xs << xml::EndTag("programlisting")
+ << xml::CR()
+ << xml::EndTag("textobject")
+ << xml::CR();
+
+ xs << xml::EndTag("mediaobject");
+}
+
+
+void InsetText::docbookText(XMLStream & xs, OutputParams const & rp, XHTMLOptions opts) const
+{
+ InsetLayout const &il = getLayout();
+ OutputParams runparams = rp;
+
// In some cases, the input parameters must be overridden for outer tags.
bool writeOuterTag = opts & WriteOuterTag;
if (writeOuterTag) {
if (par.getInset(i) && par.getInset(i)->lyxCode() == ARG_CODE) {
InsetArgument const *arg = par.getInset(i)->asInsetArgument();
if (arg->docbookargumentaftermaintag())
- appendedArguments.insert(par.getInset(i)->asInsetArgument());
+ appendedArguments.insert(par.getInset(i)->asInsetArgument());
}
}
}
attrs += from_ascii(" xlink:href=\"") + text_.asString() + from_ascii("\"");
xml::openTag(xs, il.docbooktag(), attrs, il.docbooktagtype());
}
+
+ if (!il.docbookinnertag().empty() && il.docbookinnertag() != "NONE" && il.docbookinnertag() != "IGNORE")
+ xml::openTag(xs, il.docbookinnertag(), il.docbookinnerattr(), il.docbookinnertagtype());
}
// - Think about the arguments before the paragraph.
// No need for labels that are generated from counters. They should be handled by the external DocBook processor.
// With respect to XHTML, paragraphs are still allowed here.
- if (!allowMultiPar())
+ if (runparams.docbook_consider_allow_multi_par && !allowMultiPar())
runparams.docbook_make_pars = false;
if (il.isPassThru())
runparams.pass_thru = true;
if (!il.docbookitemwrappertag().empty() && il.docbookitemwrappertag() != "NONE" && il.docbookitemwrappertag() != "IGNORE")
xml::closeTag(xs, il.docbookitemwrappertag(), il.docbookitemwrappertagtype());
+ if (!il.docbookinnertag().empty() && il.docbookinnertag() != "NONE" && il.docbookinnertag() != "IGNORE")
+ xml::closeTag(xs, il.docbookinnertag(), il.docbookinnertagtype());
+
if (!il.docbooktag().empty() && il.docbooktag() != "NONE" && il.docbooktag() != "IGNORE")
xml::closeTag(xs, il.docbooktag(), il.docbooktagtype());
void InsetText::addPreview(DocIterator const & text_inset_pos,
- PreviewLoader & loader) const
+ graphics::PreviewLoader & loader) const
{
ParagraphList::const_iterator pit = paragraphs().begin();
ParagraphList::const_iterator pend = paragraphs().end();
bool InsetText::insetAllowed(InsetCode code) const
{
switch (code) {
- // Arguments and (plain) quotes are also allowed in PassThru insets
+ // Arguments, (plain) quotes and counter insets
+ // are also allowed in PassThru insets
case ARG_CODE:
case QUOTE_CODE:
+ case COUNTER_CODE:
return true;
+ // These are only allowed in index insets
+ case INDEXMACRO_CODE:
+ case INDEXMACRO_SORTKEY_CODE:
+ return false;
default:
return !isPassThru();
}
tclass.counters().current_float(savecnt.current_float());
tclass.counters().isSubfloat(savecnt.isSubfloat());
buffer().updateBuffer(it2, utype, deleted);
- tclass.counters() = move(savecnt);
+ tclass.counters() = std::move(savecnt);
}
}
}
-bool InsetText::insertCompletion(Cursor & cur, docstring const & s,
- bool finished)
+bool InsetText::insertCompletion(Cursor & cur, docstring const & s, bool /*finished*/)
{
if (!completionSupported(cur))
return false;
- return text_.insertCompletion(cur, s, finished);
+ return text_.insertCompletion(cur, s);
}