X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathHull.cpp;h=cce029f6cedf25f98b3f3293ac45ea8cb8476974;hb=f1a388584fb2c043d17127d7db49c36cb8427cfa;hp=0b8b8a9e3b25e06d63ae169f95965fcb3ca12c1f;hpb=461c973d6213b52cb9ffe72b946f408790b5e7b3;p=lyx.git diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 0b8b8a9e3b..cce029f6ce 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -14,6 +14,10 @@ #include "InsetMathChar.h" #include "InsetMathColor.h" +#include "InsetMathFrac.h" +#include "InsetMathGrid.h" +#include "InsetMathNest.h" +#include "InsetMathScript.h" #include "MathExtern.h" #include "MathFactory.h" #include "MathStream.h" @@ -32,6 +36,8 @@ #include "LaTeXFeatures.h" #include "LyXRC.h" #include "MacroTable.h" +#include "MathMacro.h" +#include "MathMacroTemplate.h" #include "output_xhtml.h" #include "Paragraph.h" #include "ParIterator.h" @@ -44,6 +50,7 @@ #include "insets/InsetRef.h" #include "insets/RenderPreview.h" +#include "graphics/GraphicsImage.h" #include "graphics/PreviewImage.h" #include "graphics/PreviewLoader.h" @@ -53,6 +60,7 @@ #include "support/convert.h" #include "support/lassert.h" #include "support/debug.h" +#include "support/filetools.h" #include "support/gettext.h" #include "support/lstrings.h" @@ -64,6 +72,7 @@ using namespace lyx::support; namespace lyx { using cap::grabAndEraseSelection; +using cap::reduceSelectionToOneCell; namespace { @@ -118,7 +127,7 @@ HullType hullType(docstring const & s) if (s == "gather") return hullGather; if (s == "flalign") return hullFlAlign; if (s == "regexp") return hullRegexp; - lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; + lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl; return HullType(-1); } @@ -138,7 +147,7 @@ docstring hullName(HullType type) case hullGather: return from_ascii("gather"); case hullFlAlign: return from_ascii("flalign"); case hullRegexp: return from_ascii("regexp"); - default: + default: lyxerr << "unknown hull type '" << type << "'" << endl; return from_ascii("none"); } @@ -147,9 +156,9 @@ docstring hullName(HullType type) static InsetLabel * dummy_pointer = 0; InsetMathHull::InsetMathHull(Buffer * buf) - : InsetMathGrid(buf, 1, 1), type_(hullNone), numbered_(1, true), - numbers_(1, empty_docstring()), label_(1, dummy_pointer), - preview_(new RenderPreview(this)) + : InsetMathGrid(buf, 1, 1), type_(hullNone), numbered_(1, NUMBER), + numbers_(1, empty_docstring()), label_(1, dummy_pointer), + preview_(new RenderPreview(this)), use_preview_(false) { //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl; //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl; @@ -162,9 +171,9 @@ InsetMathHull::InsetMathHull(Buffer * buf) InsetMathHull::InsetMathHull(Buffer * buf, HullType type) - : InsetMathGrid(buf, getCols(type), 1), type_(type), numbered_(1, true), - numbers_(1, empty_docstring()), label_(1, dummy_pointer), - preview_(new RenderPreview(this)) + : InsetMathGrid(buf, getCols(type), 1), type_(type), numbered_(1, NUMBER), + numbers_(1, empty_docstring()), label_(1, dummy_pointer), + preview_(new RenderPreview(this)), use_preview_(false) { buffer_ = buf; initMath(); @@ -224,6 +233,8 @@ void InsetMathHull::setBuffer(Buffer & buffer) } +// FIXME This should really be controlled by the TOC level, or +// something of the sort. namespace { const char * counters_to_save[] = {"section", "chapter"}; unsigned int const numcnts = sizeof(counters_to_save)/sizeof(char *); @@ -244,7 +255,8 @@ void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype) if (haveNumbers()) { BufferParams const & bp = buffer_->params(); string const & lang = it->getParLanguage(bp)->code(); - Counters & cnts = bp.documentClass().counters(); + Counters & cnts = + buffer_->masterBuffer()->params().documentClass().counters(); // right now, we only need to do this at export time if (utype == OutputUpdate) { @@ -280,7 +292,8 @@ void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype) } -void InsetMathHull::addToToc(DocIterator const & pit) const +void InsetMathHull::addToToc(DocIterator const & pit, bool output_active, + UpdateType utype) const { if (!buffer_) { //FIXME: buffer_ should be set at creation for this inset! Problem is @@ -289,14 +302,14 @@ void InsetMathHull::addToToc(DocIterator const & pit) const return; } - Toc & toc = buffer().tocBackend().toc("equation"); + shared_ptr toc = buffer().tocBackend().toc("equation"); for (row_type row = 0; row != nrows(); ++row) { - if (!numbered_[row]) + if (!numbered(row)) continue; if (label_[row]) - label_[row]->addToToc(pit); - toc.push_back(TocItem(pit, 0, nicelabel(row))); + label_[row]->addToToc(pit, output_active, utype); + toc->push_back(TocItem(pit, 0, nicelabel(row), output_active)); } } @@ -336,15 +349,36 @@ bool InsetMathHull::idxLast(Cursor & cur) const } +//FIXME: This has probably no effect and can be removed. char InsetMathHull::defaultColAlign(col_type col) { - if (type_ == hullEqnArray) - return "rcl"[col]; - if (type_ == hullGather) - return 'c'; - if (type_ >= hullAlign) - return "rl"[col & 1]; - return 'c'; + return colAlign(type_, col); +} + + +char InsetMathHull::displayColAlign(idx_type idx) const +{ + switch (type_) { + case hullMultline: { + row_type const r = row(idx); + if (r == 0) + return 'l'; + if (r == nrows() - 1) + return 'r'; + return 'c'; + } + case hullEqnArray: + case hullGather: + case hullAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullFlAlign: + return colAlign(type_, col(idx)); + default: + break; + } + return InsetMathGrid::displayColAlign(idx); } @@ -392,9 +426,11 @@ ColorCode InsetMathHull::standardColor() const } -bool InsetMathHull::previewState(BufferView * bv) const +bool InsetMathHull::previewState(const BufferView *const bv) const { - if (!editing(bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) { + if (!editing(bv) && RenderPreview::previewMath() + && type_ != hullRegexp) + { graphics::PreviewImage const * pimage = preview_->getPreviewImage(bv->buffer()); return pimage && pimage->image(); @@ -403,14 +439,24 @@ bool InsetMathHull::previewState(BufferView * bv) const } +namespace { +static const int ERROR_FRAME_WIDTH = 2; +} + void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const { if (previewState(mi.base.bv)) { preview_->metrics(mi, dim); - // insert a one pixel gap in front of the formula - dim.wid += 1; - if (display()) - dim.des += displayMargin(); + if (previewTooSmall(dim)) { + // preview image is too small + dim.wid += 2 * ERROR_FRAME_WIDTH; + dim.asc += 2 * ERROR_FRAME_WIDTH; + } else { + // insert a one pixel gap in front of the formula + dim.wid += 1; + if (display()) + dim.des += displayMargin(); + } // Cache the inset dimension. setDimCache(mi, dim); return; @@ -437,6 +483,8 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const dim.wid += 30 + l; } + if (type_ == hullRegexp) + dim.wid += 2; // make it at least as high as the current font int asc = 0; int des = 0; @@ -449,10 +497,21 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const } +bool InsetMathHull::previewTooSmall(Dimension const & dim) const +{ + return dim.width() <= 10 && dim.height() <= 10; +} + + ColorCode InsetMathHull::backgroundColor(PainterInfo const & pi) const { - if (previewState(pi.base.bv)) + BufferView const * const bv = pi.base.bv; + if (previewState(bv)) { + Dimension const dim = dimension(*pi.base.bv); + if (previewTooSmall(dim)) + return Color_error; return graphics::PreviewLoader::backgroundColor(); + } return Color_mathbg; } @@ -460,23 +519,36 @@ ColorCode InsetMathHull::backgroundColor(PainterInfo const & pi) const void InsetMathHull::drawBackground(PainterInfo & pi, int x, int y) const { Dimension const dim = dimension(*pi.base.bv); + if (previewTooSmall(dim)) { + pi.pain.fillRectangle(x, y - 2 * ERROR_FRAME_WIDTH, + dim.wid, dim.asc + dim.des, backgroundColor(pi)); + return; + } pi.pain.fillRectangle(x + 1, y - dim.asc + 1, dim.wid - 2, - dim.asc + dim.des - 1, pi.backgroundColor(this)); + dim.asc + dim.des - 1, pi.backgroundColor(this)); } void InsetMathHull::draw(PainterInfo & pi, int x, int y) const { - use_preview_ = previewState(pi.base.bv); + BufferView const * const bv = pi.base.bv; + use_preview_ = previewState(bv); if (type_ == hullRegexp) { - Dimension const dim = dimension(*pi.base.bv); + Dimension const dim = dimension(*bv); pi.pain.rectangle(x + 1, y - dim.ascent() + 1, dim.width() - 2, dim.height() - 2, Color_regexpframe); } + if (use_preview_) { - // one pixel gap in front - preview_->draw(pi, x + 1, y); + Dimension const dim = dimension(*bv); + if (previewTooSmall(dim)) { + // we have an extra frame + preview_->draw(pi, x + ERROR_FRAME_WIDTH, y); + } else { + // one pixel gap in front + preview_->draw(pi, x + 1, y); + } setPosCache(pi, x, y); return; } @@ -509,7 +581,9 @@ void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const InsetMathGrid::metricsT(mi, dim); } else { odocstringstream os; - WriteStream wi(os, false, true, WriteStream::wsDefault); + TexRow texrow(false); + otexrowstream ots(os,texrow); + WriteStream wi(ots, false, true, WriteStream::wsDefault); write(wi); dim.wid = os.str().size(); dim.asc = 1; @@ -524,7 +598,9 @@ void InsetMathHull::drawT(TextPainter & pain, int x, int y) const InsetMathGrid::drawT(pain, x, y); } else { odocstringstream os; - WriteStream wi(os, false, true, WriteStream::wsDefault); + TexRow texrow(false); + otexrowstream ots(os,texrow); + WriteStream wi(ots, false, true, WriteStream::wsDefault); write(wi); pain.draw(x, y, os.str().c_str()); } @@ -542,7 +618,9 @@ static docstring latexString(InsetMathHull const & inset) static Encoding const * encoding = 0; if (inset.isBufferValid()) encoding = &(inset.buffer().params().encoding()); - WriteStream wi(ls, false, true, WriteStream::wsPreview, encoding); + TexRow texrow(false); + otexrowstream ots(ls,texrow); + WriteStream wi(ots, false, true, WriteStream::wsPreview, encoding); inset.write(wi); return ls.str(); } @@ -558,35 +636,111 @@ void InsetMathHull::initUnicodeMath() const void InsetMathHull::addPreview(DocIterator const & inset_pos, graphics::PreviewLoader & /*ploader*/) const { - if (RenderPreview::status() == LyXRC::PREVIEW_ON) { + if (RenderPreview::previewMath()) { preparePreview(inset_pos); } } +void InsetMathHull::usedMacros(MathData const & md, DocIterator const & pos, + MacroNameSet & macros, MacroNameSet & defs) const +{ + MacroNameSet::iterator const end = macros.end(); + + for (size_t i = 0; i < md.size(); ++i) { + MathMacro const * mi = md[i].nucleus()->asMacro(); + MathMacroTemplate const * mt = md[i].nucleus()->asMacroTemplate(); + InsetMathScript const * si = md[i].nucleus()->asScriptInset(); + InsetMathFracBase const * fi = md[i].nucleus()->asFracBaseInset(); + InsetMathGrid const * gi = md[i].nucleus()->asGridInset(); + InsetMathNest const * ni = md[i].nucleus()->asNestInset(); + if (mi) { + // Look for macros in the arguments of this macro. + for (idx_type idx = 0; idx < mi->nargs(); ++idx) + usedMacros(mi->cell(idx), pos, macros, defs); + // Make sure this is a macro defined in the document + // (as we also spot the macros in the symbols file) + // or that we have not already accounted for it. + docstring const name = mi->name(); + if (macros.find(name) == end) + continue; + macros.erase(name); + // Look for macros in the definition of this macro. + MathData ar(pos.buffer()); + MacroData const * data = + pos.buffer()->getMacro(name, pos, true); + if (data) { + odocstringstream macro_def; + data->write(macro_def, true); + macro_def << endl; + defs.insert(macro_def.str()); + asArray(data->definition(), ar); + } + usedMacros(ar, pos, macros, defs); + } else if (mt) { + MathData ar(pos.buffer()); + asArray(mt->definition(), ar); + usedMacros(ar, pos, macros, defs); + } else if (si) { + if (!si->nuc().empty()) + usedMacros(si->nuc(), pos, macros, defs); + if (si->hasDown()) + usedMacros(si->down(), pos, macros, defs); + if (si->hasUp()) + usedMacros(si->up(), pos, macros, defs); + } else if (fi || gi) { + idx_type nidx = fi ? fi->nargs() : gi->nargs(); + for (idx_type idx = 0; idx < nidx; ++idx) + usedMacros(fi ? fi->cell(idx) : gi->cell(idx), + pos, macros, defs); + } else if (ni) { + usedMacros(ni->cell(0), pos, macros, defs); + } + } +} + + void InsetMathHull::preparePreview(DocIterator const & pos, - bool forexport) const + bool forexport) const { // there is no need to do all the macro stuff if we're not // actually going to generate the preview. - if (RenderPreview::status() != LyXRC::PREVIEW_ON && !forexport) + if (!RenderPreview::previewMath() && !forexport) return; - + Buffer const * buffer = pos.buffer(); // collect macros at this position MacroNameSet macros; buffer->listMacroNames(macros); - MacroNameSet::iterator it = macros.begin(); - MacroNameSet::iterator end = macros.end(); - odocstringstream macro_preamble; - for (; it != end; ++it) { - MacroData const * data = buffer->getMacro(*it, pos, true); - if (data) { - data->write(macro_preamble, true); - macro_preamble << endl; - } - } + + // collect definitions only for the macros used in this inset + MacroNameSet defs; + for (idx_type idx = 0; idx < nargs(); ++idx) + usedMacros(cell(idx), pos, macros, defs); + + MacroNameSet::iterator it = defs.begin(); + MacroNameSet::iterator end = defs.end(); + docstring macro_preamble; + for (; it != end; ++it) + macro_preamble.append(*it); + + // set the font series and size for this snippet + DocIterator dit = pos; + while (dit.inMathed()) + dit.pop_back(); + Paragraph const & par = dit.paragraph(); + Font font = par.getFontSettings(buffer->params(), dit.pos()); + font.fontInfo().realize(par.layout().font); + string const lsize = font.latexSize(); + docstring setfont; + docstring endfont; + if (font.fontInfo().series() == BOLD_SERIES) { + setfont += from_ascii("\\textbf{"); + endfont += '}'; + } + if (lsize != "normalsize" && !prefixIs(lsize, "error")) + setfont += from_ascii("\\" + lsize + '\n'); docstring setcnt; if (forexport && haveNumbers()) { @@ -609,8 +763,8 @@ void InsetMathHull::preparePreview(DocIterator const & pos, '{' + convert(num) + '}'; } } - docstring const snippet = macro_preamble.str() + - setcnt + latexString(*this); + docstring const snippet = macro_preamble + setfont + setcnt + + latexString(*this) + endfont; LYXERR(Debug::MACROS, "Preview snippet: " << snippet); preview_->addPreview(snippet, *buffer, forexport); } @@ -633,7 +787,7 @@ void InsetMathHull::loadPreview(DocIterator const & pos) const bool InsetMathHull::notifyCursorLeaves(Cursor const & old, Cursor & cur) { - if (RenderPreview::status() == LyXRC::PREVIEW_ON) { + if (RenderPreview::previewMath()) { reloadPreview(old); cur.screenUpdateFlags(Update::Force); } @@ -643,7 +797,7 @@ bool InsetMathHull::notifyCursorLeaves(Cursor const & old, Cursor & cur) docstring InsetMathHull::label(row_type row) const { - LASSERT(row < nrows(), /**/); + LASSERT(row < nrows(), return docstring()); if (InsetLabel * il = label_[row]) return il->screenLabel(); return docstring(); @@ -659,7 +813,7 @@ void InsetMathHull::label(row_type row, docstring const & label) label_[row] = dummy_pointer; } else { if (buffer_) - label_[row]->updateCommand(label); + label_[row]->updateLabelAndRefs(label); else label_[row]->setParam("name", label); } @@ -673,10 +827,10 @@ void InsetMathHull::label(row_type row, docstring const & label) } -void InsetMathHull::numbered(row_type row, bool num) +void InsetMathHull::numbered(row_type row, Numbered num) { numbered_[row] = num; - if (!numbered_[row] && label_[row]) { + if (!numbered(row) && label_[row]) { delete label_[row]; label_[row] = 0; } @@ -685,19 +839,32 @@ void InsetMathHull::numbered(row_type row, bool num) bool InsetMathHull::numbered(row_type row) const { - return numbered_[row]; + return numbered_[row] == NUMBER; } bool InsetMathHull::ams() const { - return type_ == hullAlign - || type_ == hullFlAlign - || type_ == hullMultline - || type_ == hullGather - || type_ == hullAlignAt - || type_ == hullXAlignAt - || type_ == hullXXAlignAt; + switch (type_) { + case hullAlign: + case hullFlAlign: + case hullMultline: + case hullGather: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + return true; + case hullNone: + case hullSimple: + case hullEquation: + case hullEqnArray: + case hullRegexp: + break; + } + for (size_t row = 0; row < numbered_.size(); ++row) + if (numbered_[row] == NOTAG) + return true; + return false; } @@ -719,7 +886,7 @@ bool InsetMathHull::numberedType() const if (type_ == hullRegexp) return false; for (row_type row = 0; row < nrows(); ++row) - if (numbered_[row]) + if (numbered(row)) return true; return false; } @@ -730,7 +897,7 @@ void InsetMathHull::validate(LaTeXFeatures & features) const if (features.runparams().isLaTeX()) { if (ams()) features.require("amsmath"); - + if (type_ == hullRegexp) { features.require("color"); string frcol = lcolor.getLaTeXName(Color_regexpframe); @@ -738,25 +905,26 @@ void InsetMathHull::validate(LaTeXFeatures & features) const features.addPreambleSnippet( string("\\newcommand{\\regexp}[1]{\\fcolorbox{") + frcol + string("}{") - + bgcol + string("}{\\texttt{#1}}}")); + + bgcol + string("}{\\ensuremath{\\mathtt{#1}}}}")); + features.addPreambleSnippet( + string("\\newcommand{\\endregexp}{}")); } - + // Validation is necessary only if not using AMS math. // To be safe, we will always run mathedvalidate. //if (features.amsstyle) // return; - + //features.binom = true; } else if (features.runparams().math_flavor == OutputParams::MathAsHTML) { // it would be better to do this elsewhere, but we can't validate in // InsetMathMatrix and we have no way, outside MathExtern, to know if // we even have any matrices. - features.addPreambleSnippet(""); + "td.rdelim{width: 0.5ex; border: thin solid black; border-left: none;}"); } InsetMathGrid::validate(features); } @@ -772,15 +940,18 @@ void InsetMathHull::header_write(WriteStream & os) const case hullSimple: os << '$'; + os.startOuterRow(); if (cell(0).empty()) os << ' '; break; case hullEquation: + os << "\n"; + os.startOuterRow(); if (n) - os << "\n\\begin{equation" << star(n) << "}\n"; + os << "\\begin{equation" << star(n) << "}\n"; else - os << "\n\\[\n"; + os << "\\[\n"; break; case hullEqnArray: @@ -788,26 +959,34 @@ void InsetMathHull::header_write(WriteStream & os) const case hullFlAlign: case hullGather: case hullMultline: - os << "\n\\begin{" << hullName(type_) << star(n) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\begin{" << hullName(type_) << star(n) << "}\n"; break; case hullAlignAt: case hullXAlignAt: - os << "\n\\begin{" << hullName(type_) << star(n) << '}' + os << "\n"; + os.startOuterRow(); + os << "\\begin{" << hullName(type_) << star(n) << '}' << '{' << static_cast((ncols() + 1)/2) << "}\n"; break; case hullXXAlignAt: - os << "\n\\begin{" << hullName(type_) << '}' + os << "\n"; + os.startOuterRow(); + os << "\\begin{" << hullName(type_) << '}' << '{' << static_cast((ncols() + 1)/2) << "}\n"; break; case hullRegexp: - os << "\\regexp{{{"; + os << "\\regexp{"; break; default: - os << "\n\\begin{unknown" << star(n) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\begin{unknown" << star(n) << "}\n"; break; } } @@ -827,10 +1006,12 @@ void InsetMathHull::footer_write(WriteStream & os) const break; case hullEquation: + os << "\n"; + os.startOuterRow(); if (n) - os << "\n\\end{equation" << star(n) << "}\n"; + os << "\\end{equation" << star(n) << "}\n"; else - os << "\n\\]\n"; + os << "\\]\n"; break; case hullEqnArray: @@ -840,19 +1021,26 @@ void InsetMathHull::footer_write(WriteStream & os) const case hullXAlignAt: case hullGather: case hullMultline: - os << "\n\\end{" << hullName(type_) << star(n) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\end{" << hullName(type_) << star(n) << "}\n"; break; case hullXXAlignAt: - os << "\n\\end{" << hullName(type_) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\end{" << hullName(type_) << "}\n"; break; case hullRegexp: - os << "}}}"; + // Only used as a heuristic to find the regexp termination, when searching in ignore-format mode + os << "\\endregexp{}}"; break; default: - os << "\n\\end{unknown" << star(n) << "}\n"; + os << "\n"; + os.startOuterRow(); + os << "\\end{unknown" << star(n) << "}\n"; break; } } @@ -882,20 +1070,21 @@ void InsetMathHull::addRow(row_type row) return; bool numbered = numberedType(); - docstring lab; + // Move the number and raw pointer, do not call label() (bug 7511) + InsetLabel * label = dummy_pointer; + docstring number = empty_docstring(); if (type_ == hullMultline) { if (row + 1 == nrows()) { - numbered_[row] = false; - lab = label(row); + numbered_[row] = NONUMBER; + swap(label, label_[row]); + swap(number, numbers_[row]); } else numbered = false; } - numbered_.insert(numbered_.begin() + row + 1, numbered); - numbers_.insert(numbers_.begin() + row + 1, empty_docstring()); - label_.insert(label_.begin() + row + 1, dummy_pointer); - if (!lab.empty()) - label(row + 1, lab); + numbered_.insert(numbered_.begin() + row + 1, numbered ? NUMBER : NONUMBER); + numbers_.insert(numbers_.begin() + row + 1, number); + label_.insert(label_.begin() + row + 1, label); InsetMathGrid::addRow(row); } @@ -906,14 +1095,7 @@ void InsetMathHull::swapRow(row_type row) return; if (row + 1 == nrows()) --row; - // gcc implements the standard std::vector which is *not* a container: - // http://www.gotw.ca/publications/N1185.pdf - // As a results, it doesn't like this: - // swap(numbered_[row], numbered_[row + 1]); - // so we do it manually: - bool const b = numbered_[row]; - numbered_[row] = numbered_[row + 1]; - numbered_[row + 1] = b; + swap(numbered_[row], numbered_[row + 1]); swap(numbers_[row], numbers_[row + 1]); swap(label_[row], label_[row + 1]); InsetMathGrid::swapRow(row); @@ -925,9 +1107,7 @@ void InsetMathHull::delRow(row_type row) if (nrows() <= 1 || !rowChangeOK()) return; if (row + 1 == nrows() && type_ == hullMultline) { - bool const b = numbered_[row - 1]; - numbered_[row - 1] = numbered_[row]; - numbered_[row] = b; + swap(numbered_[row - 1], numbered_[row]); swap(numbers_[row - 1], numbers_[row]); swap(label_[row - 1], label_[row]); InsetMathGrid::delRow(row); @@ -963,7 +1143,7 @@ void InsetMathHull::delCol(col_type col) docstring InsetMathHull::nicelabel(row_type row) const { - if (!numbered_[row]) + if (!numbered(row)) return docstring(); docstring const & val = numbers_[row]; if (!label_[row]) @@ -997,7 +1177,7 @@ void InsetMathHull::glueall(HullType type) void InsetMathHull::splitTo2Cols() { - LASSERT(ncols() == 1, /**/); + LASSERT(ncols() == 1, return); InsetMathGrid::addCol(1); for (row_type row = 0; row < nrows(); ++row) { idx_type const i = 2 * row; @@ -1010,13 +1190,13 @@ void InsetMathHull::splitTo2Cols() void InsetMathHull::splitTo3Cols() { - LASSERT(ncols() < 3, /**/); + LASSERT(ncols() < 3, return); if (ncols() < 2) splitTo2Cols(); InsetMathGrid::addCol(2); for (row_type row = 0; row < nrows(); ++row) { idx_type const i = 3 * row + 1; - if (cell(i).size()) { + if (!cell(i).empty()) { cell(i + 1) = MathData(buffer_, cell(i).begin() + 1, cell(i).end()); cell(i).erase(1, cell(i).size()); } @@ -1067,6 +1247,27 @@ void InsetMathHull::setType(HullType type) } +bool InsetMathHull::isMutable(HullType type) +{ + switch (type) { + case hullNone: + case hullSimple: + case hullEquation: + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullMultline: + case hullGather: + return true; + default: + return false; + } +} + + void InsetMathHull::mutate(HullType newtype) { //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl; @@ -1200,21 +1401,24 @@ docstring InsetMathHull::eolString(row_type row, bool fragile, bool latex, { docstring res; if (numberedType()) { - if (label_[row] && numbered_[row]) { + if (label_[row] && numbered(row)) { docstring const name = latex ? escape(label_[row]->getParam("name")) : label_[row]->getParam("name"); res += "\\label{" + name + '}'; } - if (!numbered_[row] && (type_ != hullMultline)) - res += "\\nonumber "; + if (type_ != hullMultline) { + if (numbered_[row] == NONUMBER) + res += "\\nonumber "; + else if (numbered_[row] == NOTAG) + res += "\\notag "; + } } // Never add \\ on the last empty line of eqnarray and friends last_eoln = false; return res + InsetMathGrid::eolString(row, fragile, latex, last_eoln); } - void InsetMathHull::write(WriteStream & os) const { ModeSpecifier specifier(os, MATH_MODE); @@ -1234,15 +1438,15 @@ void InsetMathHull::normalize(NormalStream & os) const void InsetMathHull::infoize(odocstream & os) const { - os << "Type: " << hullName(type_); + os << bformat(_("Type: %1$s"), hullName(type_)); } void InsetMathHull::check() const { - LASSERT(numbered_.size() == nrows(), /**/); - LASSERT(numbers_.size() == nrows(), /**/); - LASSERT(label_.size() == nrows(), /**/); + LATTEST(numbered_.size() == nrows()); + LATTEST(numbers_.size() == nrows()); + LATTEST(label_.size() == nrows()); } @@ -1256,14 +1460,14 @@ void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func) extra = from_ascii("noextra"); string const lang = to_ascii(dlang); - // FIXME: temporarily disabled - //if (cur.selection()) { - // MathData ar; - // selGet(cur.ar); - // lyxerr << "use selection: " << ar << endl; - // insert(pipeThroughExtern(lang, extra, ar)); - // return; - //} + // replace selection with result of computation + if (reduceSelectionToOneCell(cur)) { + MathData ar; + asArray(grabAndEraseSelection(cur), ar); + lyxerr << "use selection: " << ar << endl; + cur.insert(pipeThroughExtern(lang, extra, ar)); + return; + } // only inline, display or eqnarray math is allowed if (getType() > hullEqnArray) { @@ -1284,9 +1488,7 @@ void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func) if (getType() == hullSimple) { size_type pos = cur.cell().find_last(eq); MathData ar; - if (cur.inMathed() && cur.selection()) { - asArray(grabAndEraseSelection(cur), ar); - } else if (pos == cur.cell().size()) { + if (pos == cur.cell().size()) { ar = cur.cell(); lyxerr << "use whole cell: " << ar << endl; } else { @@ -1342,10 +1544,9 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_FINISHED_LEFT: //lyxerr << "action: " << cmd.action() << endl; InsetMathGrid::doDispatch(cur, cmd); - cur.undispatched(); break; - case LFUN_BREAK_PARAGRAPH: + case LFUN_PARAGRAPH_BREAK: // just swallow this break; @@ -1354,7 +1555,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) if (type_ == hullSimple || type_ == hullEquation) { cur.recordUndoInset(); bool const align = - cur.bv().buffer().params().use_amsmath == BufferParams::package_on; + cur.bv().buffer().params().use_package("amsmath") != BufferParams::package_off; mutate(align ? hullAlign : hullEqnArray); // mutate() may change labels and such. cur.forceBufferUpdate(); @@ -1390,7 +1591,6 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) } case LFUN_LABEL_INSERT: { - cur.recordUndoInset(); row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row(); docstring old_label = label(r); docstring const default_label = from_ascii("eq:"); @@ -1410,7 +1610,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) break; } - case LFUN_LABEL_COPY_AS_REF: { + case LFUN_LABEL_COPY_AS_REFERENCE: { row_type row; if (cmd.argument().empty() && &cur.inset() == this) // if there is no argument and we're inside math, we retrieve @@ -1420,7 +1620,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) // if there is an argument, find the corresponding label, else // check whether there is at least one label. for (row = 0; row != nrows(); ++row) - if (numbered_[row] && label_[row] + if (numbered(row) && label_[row] && (cmd.argument().empty() || label(row) == cmd.argument())) break; } @@ -1517,9 +1717,15 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_MATH_DISPLAY: { cur.recordUndoInset(); mutate(type_ == hullSimple ? hullEquation : hullSimple); - cur.idx() = 0; - cur.pos() = cur.lastpos(); - //cur.dispatched(FINISHED); + // if the cursor is in a cell that got merged, move it to + // start of the hull inset. + if (cur.idx() > 0) { + cur.idx() = 0; + cur.pos() = 0; + } + if (cur.pos() > cur.lastpos()) + cur.pos() = cur.lastpos(); + break; } @@ -1548,7 +1754,7 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, // we never allow this in math, and we want to bind enter // to another actions in command-alternatives - case LFUN_BREAK_PARAGRAPH: + case LFUN_PARAGRAPH_BREAK: status.setEnabled(false); return true; case LFUN_MATH_MUTATE: { @@ -1580,6 +1786,7 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, enable = display() != Inline; } status.setEnabled(enable); + status.setOnOff(display() != Inline); return true; } @@ -1606,19 +1813,19 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(type_ != hullSimple); return true; - case LFUN_LABEL_COPY_AS_REF: { + case LFUN_LABEL_COPY_AS_REFERENCE: { bool enabled = false; row_type row; if (cmd.argument().empty() && &cur.inset() == this) { // if there is no argument and we're inside math, we retrieve // the row number from the cursor position. row = (type_ == hullMultline) ? nrows() - 1 : cur.row(); - enabled = numberedType() && label_[row] && numbered_[row]; + enabled = numberedType() && label_[row] && numbered(row); } else { // if there is an argument, find the corresponding label, else // check whether there is at least one label. for (row_type row = 0; row != nrows(); ++row) { - if (numbered_[row] && label_[row] && + if (numbered(row) && label_[row] && (cmd.argument().empty() || label(row) == cmd.argument())) { enabled = true; break; @@ -1848,7 +2055,9 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str, void InsetMathHull::write(ostream & os) const { odocstringstream oss; - WriteStream wi(oss, false, false, WriteStream::wsDefault); + TexRow texrow(false); + otexrowstream ots(oss,texrow); + WriteStream wi(ots, false, false, WriteStream::wsDefault); oss << "Formula "; write(wi); os << to_utf8(oss.str()); @@ -1873,7 +2082,8 @@ bool InsetMathHull::readQuiet(Lexer & lex) } -int InsetMathHull::plaintext(odocstream & os, OutputParams const &) const +int InsetMathHull::plaintext(odocstringstream & os, + OutputParams const & op, size_t max_length) const { // disables ASCII-art for export of equations. See #2275. if (0 && display()) { @@ -1886,19 +2096,32 @@ int InsetMathHull::plaintext(odocstream & os, OutputParams const &) const // reset metrics cache to "real" values //metrics(); return tpain.textheight(); - } else { - odocstringstream oss; - Encoding const * const enc = encodings.fromLyXName("utf8"); - WriteStream wi(oss, false, true, WriteStream::wsDefault, enc); - // Fix Bug #6139 - if (type_ == hullRegexp) - write(wi); - else - wi << cell(0); - docstring const str = oss.str(); - os << str; - return str.size(); } + + odocstringstream oss; + TexRow texrow(false); + otexrowstream ots(oss,texrow); + Encoding const * const enc = encodings.fromLyXName("utf8"); + WriteStream wi(ots, false, true, WriteStream::wsDefault, enc); + + // Fix Bug #6139 + if (type_ == hullRegexp) + write(wi); + else { + for (row_type r = 0; r < nrows(); ++r) { + for (col_type c = 0; c < ncols(); ++c) + wi << (c == 0 ? "" : "\t") << cell(index(r, c)); + // if it's for the TOC, we write just the first line + // and do not include the newline. + if (op.for_toc || op.for_tooltip || oss.str().size() >= max_length) + break; + if (r < nrows() - 1) + wi << "\n"; + } + } + docstring const str = oss.str(); + os << str; + return str.size(); } @@ -1919,12 +2142,14 @@ int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) cons ++ms.tab(); ms.cr(); ms.os() << '<' << bname << '>'; odocstringstream ls; + TexRow texrow; + otexstream ols(ls, texrow); if (runparams.flavor == OutputParams::XML) { ms << MTag("alt role='tex' "); // Workaround for db2latex: db2latex always includes equations with // \ensuremath{} or \begin{display}\end{display} // so we strip LyX' math environment - WriteStream wi(ls, false, false, WriteStream::wsDefault, runparams.encoding); + WriteStream wi(ols, false, false, WriteStream::wsDefault, runparams.encoding); InsetMathGrid::write(wi); ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&"), "<", "<")); ms << ETag("alt"); @@ -1934,9 +2159,6 @@ int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) cons InsetMathGrid::mathmlize(ms); ms << ETag("math"); } else { - TexRow texrow; - texrow.reset(); - otexstream ols(ls, texrow); ms << MTag("alt role='tex'"); latex(ols, runparams); res = texrow.rows(); @@ -1968,7 +2190,7 @@ bool InsetMathHull::haveNumbers() const if (getType() == hullSimple) return havenumbers; for (size_t i = 0; i != numbered_.size(); ++i) { - if (numbered_[i]) { + if (numbered(i)) { havenumbers = true; break; } @@ -2087,8 +2309,8 @@ void InsetMathHull::mathAsLatex(WriteStream & os) const docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const { - BufferParams::MathOutput const mathtype = - buffer().params().html_math_output; + BufferParams::MathOutput const mathtype = + buffer().masterBuffer()->params().html_math_output; bool success = false; @@ -2111,10 +2333,10 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const } catch (MathExportException const &) {} if (success) { if (getType() == hullSimple) - xs << html::StartTag("math", + xs << html::StartTag("math", "xmlns=\"http://www.w3.org/1998/Math/MathML\"", true); - else - xs << html::StartTag("math", + else + xs << html::StartTag("math", "display=\"block\" xmlns=\"http://www.w3.org/1998/Math/MathML\"", true); xs << XHTMLStream::ESCAPE_NONE << os.str() @@ -2135,33 +2357,50 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const << html::EndTag(tag); } } - + // what we actually want is this: // if ( - // ((mathtype == BufferParams::MathML || mathtype == BufferParams::HTML) + // ((mathtype == BufferParams::MathML || mathtype == BufferParams::HTML) // && !success) // || mathtype == BufferParams::Images // ) - // but what follows is equivalent, since we'll enter only if either (a) we + // but what follows is equivalent, since we'll enter only if either (a) we // tried and failed with MathML or HTML or (b) didn't try yet at all but // aren't doing LaTeX, in which case we are doing Images. if (!success && mathtype != BufferParams::LaTeX) { - loadPreview(docit_); - graphics::PreviewImage const * pimage = preview_->getPreviewImage(buffer()); - if (pimage) { + graphics::PreviewImage const * pimage = 0; + if (!op.dryrun) { + loadPreview(docit_); + pimage = preview_->getPreviewImage(buffer()); // FIXME Do we always have png? + } + + if (pimage || op.dryrun) { + string const filename = pimage ? pimage->filename().onlyFileName() + : "previewimage.png"; + if (pimage) { + // if we are not in the master buffer, then we need to see that the + // generated image is copied there; otherwise, preview fails. + Buffer const * mbuf = buffer().masterBuffer(); + if (mbuf != &buffer()) { + string mbtmp = mbuf->temppath(); + FileName const mbufimg(support::addName(mbtmp, filename)); + pimage->filename().copyTo(mbufimg); + } + // add the file to the list of files to be exported + op.exportdata->addExternalFile("xhtml", pimage->filename()); + } + string const tag = (getType() == hullSimple) ? "span" : "div"; - FileName const & mathimg = pimage->filename(); - xs << html::StartTag(tag) - << html::CompTag("img", "src=\"" + mathimg.onlyFileName() + "\"") - << html::EndTag(tag) - << html::CR(); - // add the file to the list of files to be exported - op.exportdata->addExternalFile("xhtml", mathimg); + xs << html::CR() + << html::StartTag(tag) + << html::CompTag("img", "src=\"" + filename + "\" alt=\"Mathematical Equation\"") + << html::EndTag(tag) + << html::CR(); success = true; } } - + // so we'll pass this test if we've failed everything else, or // if mathtype was LaTeX, since we won't have entered any of the // earlier branches @@ -2169,19 +2408,20 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const // Unfortunately, we cannot use latexString() because we do not want // $...$ or whatever. odocstringstream ls; - WriteStream wi(ls, false, true, WriteStream::wsPreview); + TexRow texrow(false); + otexrowstream ots(ls,texrow); + WriteStream wi(ots, false, true, WriteStream::wsPreview); ModeSpecifier specifier(wi, MATH_MODE); mathAsLatex(wi); docstring const latex = ls.str(); - + // class='math' allows for use of jsMath // http://www.math.union.edu/~dpvc/jsMath/ // FIXME XHTML // probably should allow for some kind of customization here string const tag = (getType() == hullSimple) ? "span" : "div"; xs << html::StartTag(tag, "class='math'") - << XHTMLStream::ESCAPE_AND - << latex + << latex << html::EndTag(tag) << html::CR(); } @@ -2191,21 +2431,27 @@ docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const & op) const void InsetMathHull::toString(odocstream & os) const { - plaintext(os, OutputParams(0)); + odocstringstream ods; + plaintext(ods, OutputParams(0)); + os << ods.str(); } -void InsetMathHull::forToc(docstring & os, size_t) const +void InsetMathHull::forOutliner(docstring & os, size_t const, bool const) const { odocstringstream ods; - plaintext(ods, OutputParams(0)); + OutputParams op(0); + op.for_toc = true; + // FIXME: this results in spilling TeX into the LyXHTML output since the + // outliner is used to generate the LyXHTML list of figures/etc. + plaintext(ods, op); os += ods.str(); } -docstring InsetMathHull::contextMenuName() const +string InsetMathHull::contextMenuName() const { - return from_ascii("context-math"); + return "context-math"; }