]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/InsetMathHull.cpp
Specify that we are in math mode. This avoids unnecessary \ensuremath
[lyx.git] / src / mathed / InsetMathHull.cpp
index 1f6972fa99f869cddcd2590998378ed00af03792..99d59b00b08a291bc29c97358345562387feaf75 100644 (file)
@@ -13,7 +13,7 @@
 #include "InsetMathArray.h"
 #include "InsetMathChar.h"
 #include "InsetMathColor.h"
-#include "MathArray.h"
+#include "MathData.h"
 #include "InsetMathDelim.h"
 #include "MathExtern.h"
 #include "MathFactory.h"
 #include "MathSupport.h"
 #include "InsetMathRef.h"
 
-#include "bufferview_funcs.h"
-#include "LyXText.h"
-
 #include "Buffer.h"
+#include "buffer_funcs.h"
 #include "BufferParams.h"
 #include "BufferView.h"
 #include "CutAndPaste.h"
 #include "FuncStatus.h"
-#include "LColor.h"
 #include "LaTeXFeatures.h"
-#include "LCursor.h"
-#include "debug.h"
+#include "Cursor.h"
 #include "DispatchResult.h"
 #include "FuncRequest.h"
-#include "gettext.h"
+#include "Language.h"
 #include "LyXRC.h"
 #include "OutputParams.h"
+#include "ParIterator.h"
 #include "sgml.h"
+#include "Text.h"
 #include "TextPainter.h"
-#include "Undo.h"
+#include "TocBackend.h"
 
 #include "insets/RenderPreview.h"
 #include "insets/InsetLabel.h"
 #include "graphics/PreviewImage.h"
 #include "graphics/PreviewLoader.h"
 
-#include "support/lyxlib.h"
-#include "support/lstrings.h"
+#include "frontends/Painter.h"
 
-#include <boost/bind.hpp>
+#include "support/lassert.h"
+#include "support/debug.h"
+#include "support/gettext.h"
+#include "support/lstrings.h"
 
 #include <sstream>
 
+using namespace std;
+using namespace lyx::support;
 
 namespace lyx {
 
 using cap::grabAndEraseSelection;
-using support::bformat;
-using support::subst;
-
-using std::endl;
-using std::max;
-using std::ostream;
-using std::auto_ptr;
-using std::istringstream;
-using std::ostringstream;
-using std::pair;
-using std::swap;
-using std::vector;
-
 
 namespace {
 
@@ -98,9 +87,9 @@ namespace {
 
        // returns position of first relation operator in the array
        // used for "intelligent splitting"
-       size_t firstRelOp(MathArray const & ar)
+       size_t firstRelOp(MathData const & ar)
        {
-               for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
+               for (MathData::const_iterator it = ar.begin(); it != ar.end(); ++it)
                        if ((*it)->isRelOp())
                                return it - ar.begin();
                return ar.size();
@@ -154,43 +143,46 @@ docstring hullName(HullType type)
        }
 }
 
+static InsetLabel * dummy_pointer = 0;
 
 InsetMathHull::InsetMathHull()
-       : InsetMathGrid(1, 1), type_(hullNone), nonum_(1), label_(1),
-         preview_(new RenderPreview(this))
+       : InsetMathGrid(1, 1), type_(hullNone), nonum_(1, false),
+         label_(1, dummy_pointer), preview_(new RenderPreview(this))
 {
        //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl;
        //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
        //lyxerr << "sizeof InsetMathChar: " << sizeof(InsetMathChar) << endl;
-       //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl;
+       //lyxerr << "sizeof FontInfo: " << sizeof(FontInfo) << endl;
        initMath();
        setDefaults();
 }
 
 
 InsetMathHull::InsetMathHull(HullType type)
-       : InsetMathGrid(getCols(type), 1), type_(type), nonum_(1), label_(1),
-         preview_(new RenderPreview(this))
+       : InsetMathGrid(getCols(type), 1), type_(type), nonum_(1, false),
+         label_(1, dummy_pointer), preview_(new RenderPreview(this))
 {
        initMath();
        setDefaults();
 }
 
 
-InsetMathHull::InsetMathHull(InsetMathHull const & other)
-       : InsetMathGrid(other),
-         type_(other.type_), nonum_(other.nonum_), label_(other.label_),
-         preview_(new RenderPreview(this))
-{}
+InsetMathHull::InsetMathHull(InsetMathHull const & other) : InsetMathGrid()
+{
+       operator=(other);
+}
 
 
 InsetMathHull::~InsetMathHull()
-{}
+{
+       for (size_t i = 0; i < label_.size(); ++i)
+               delete label_[i];
+}
 
 
-auto_ptr<InsetBase> InsetMathHull::doClone() const
+Inset * InsetMathHull::clone() const
 {
-       return auto_ptr<InsetBase>(new InsetMathHull(*this));
+       return new InsetMathHull(*this);
 }
 
 
@@ -198,17 +190,75 @@ InsetMathHull & InsetMathHull::operator=(InsetMathHull const & other)
 {
        if (this == &other)
                return *this;
-       *static_cast<InsetMathGrid*>(this) = InsetMathGrid(other);
+       InsetMathGrid::operator=(other);
        type_  = other.type_;
        nonum_ = other.nonum_;
+       for (size_t i = 0; i < label_.size(); ++i)
+               delete label_[i];
        label_ = other.label_;
+       for (size_t i = 0; i != label_.size(); ++i) {
+               if (label_[i])
+                       label_[i] = new InsetLabel(*label_[i]);
+       }
        preview_.reset(new RenderPreview(*other.preview_, this));
 
        return *this;
 }
 
 
-InsetBase * InsetMathHull::editXY(LCursor & cur, int x, int y)
+void InsetMathHull::setBuffer(Buffer & buffer)
+{
+       buffer_ = &buffer;
+       for (idx_type i = 0, n = nargs(); i != n; ++i) {
+               MathData & data = cell(i);
+               for (size_t j = 0; j != data.size(); ++j)
+                       data[j].nucleus()->setBuffer(buffer);
+       }
+
+       for (size_t i = 0; i != label_.size(); ++i) {
+               if (label_[i])
+                       label_[i]->setBuffer(buffer);
+       }
+}
+
+
+void InsetMathHull::updateLabels(ParIterator const & it)
+{
+       if (!buffer_) {
+               //FIXME: buffer_ should be set at creation for this inset! Problem is
+               // This inset is created at too many places (see Parser::parse1() in
+               // MathParser.cpp).
+               return;
+       }
+       for (size_t i = 0; i != label_.size(); ++i) {
+               if (label_[i])
+                       label_[i]->updateLabels(it);
+       }
+}
+
+
+void InsetMathHull::addToToc(DocIterator const & pit)
+{
+       if (!buffer_) {
+               //FIXME: buffer_ should be set at creation for this inset! Problem is
+               // This inset is created at too many places (see Parser::parse1() in
+               // MathParser.cpp).
+               return;
+       }
+
+       Toc & toc = buffer().tocBackend().toc("equation");
+
+       for (row_type row = 0; row != nrows(); ++row) {
+               if (nonum_[row])
+                       continue;
+               if (label_[row])
+                       label_[row]->addToToc(pit);
+               toc.push_back(TocItem(pit, 0, nicelabel(row)));
+       }
+}
+
+
+Inset * InsetMathHull::editXY(Cursor & cur, int x, int y)
 {
        if (use_preview_) {
                edit(cur, true);
@@ -227,7 +277,7 @@ InsetMath::mode_type InsetMathHull::currentMode() const
 }
 
 
-bool InsetMathHull::idxFirst(LCursor & cur) const
+bool InsetMathHull::idxFirst(Cursor & cur) const
 {
        cur.idx() = 0;
        cur.pos() = 0;
@@ -235,7 +285,7 @@ bool InsetMathHull::idxFirst(LCursor & cur) const
 }
 
 
-bool InsetMathHull::idxLast(LCursor & cur) const
+bool InsetMathHull::idxLast(Cursor & cur) const
 {
        cur.idx() = nargs() - 1;
        cur.pos() = cur.lastpos();
@@ -247,6 +297,8 @@ 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';
@@ -275,14 +327,14 @@ bool InsetMathHull::previewState(BufferView * bv) const
 {
        if (!editing(bv) && RenderPreview::status() == LyXRC::PREVIEW_ON) {
                graphics::PreviewImage const * pimage =
-                       preview_->getPreviewImage(*bv->buffer());
+                       preview_->getPreviewImage(bv->buffer());
                return pimage && pimage->image();
        }
        return false;
 }
 
 
-bool InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
+void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
 {
        if (previewState(mi.base.bv)) {
                preview_->metrics(mi, dim);
@@ -290,10 +342,9 @@ bool InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
                dim.wid += 1;
                if (display())
                        dim.des += displayMargin();
-               if (dim_ == dim)
-                       return false;
-               dim_ = dim;
-               return true;
+               // Cache the inset dimension. 
+               setDimCache(mi, dim);
+               return;
        }
 
        FontSetChanger dummy1(mi.base, standardFont());
@@ -323,17 +374,22 @@ bool InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
        math_font_max_dim(mi.base.font, asc, des);
        dim.asc = max(dim.asc, asc);
        dim.des = max(dim.des, des);
-
-       if (dim_ == dim)
-               return false;
-       dim_ = dim;
-       return true;
+       // Cache the inset dimension.
+       // FIXME: This will overwrite InsetMathGrid dimension, is that OK?
+       setDimCache(mi, dim);
 }
 
 
 void InsetMathHull::draw(PainterInfo & pi, int x, int y) const
 {
        use_preview_ = previewState(pi.base.bv);
+       Dimension const dim = dimension(*pi.base.bv);
+
+       // background of mathed under focus is not painted because
+       // selection at the top level of nested inset is difficult to handle.
+       if (!editing(pi.base.bv))
+               pi.pain.fillRectangle(x + 1, y - dim.asc + 1, dim.wid - 2,
+                               dim.asc + dim.des - 1, Color_mathbg);
 
        if (use_preview_) {
                // one pixel gap in front
@@ -365,7 +421,7 @@ void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
                InsetMathGrid::metricsT(mi, dim);
        } else {
                odocstringstream os;
-               WriteStream wi(os, false, true);
+               WriteStream wi(os, false, true, false);
                write(wi);
                dim.wid = os.str().size();
                dim.asc = 1;
@@ -380,40 +436,41 @@ void InsetMathHull::drawT(TextPainter & pain, int x, int y) const
                InsetMathGrid::drawT(pain, x, y);
        } else {
                odocstringstream os;
-               WriteStream wi(os, false, true);
+               WriteStream wi(os, false, true, false);
                write(wi);
                pain.draw(x, y, os.str().c_str());
        }
 }
 
 
-namespace {
-
-docstring const latex_string(InsetMathHull const & inset)
+static docstring latexString(InsetMathHull const & inset)
 {
        odocstringstream ls;
-       WriteStream wi(ls, false, false);
+       // This has to be static, because a preview snippet containing math
+       // in text mode (such as $\text{$\phi$}$) gets processed twice. The
+       // first time as a whole, and the second time only the inner math.
+       // In this last case inset.buffer() would be invalid.
+       static Encoding const * encoding = inset.buffer().language()->encoding();
+       WriteStream wi(ls, false, true, false, encoding);
        inset.write(wi);
        return ls.str();
 }
 
-} // namespace anon
-
 
 void InsetMathHull::addPreview(graphics::PreviewLoader & ploader) const
 {
        if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
-               docstring const snippet = latex_string(*this);
+               docstring const snippet = latexString(*this);
                preview_->addPreview(snippet, ploader);
        }
 }
 
 
-bool InsetMathHull::notifyCursorLeaves(LCursor & cur)
+bool InsetMathHull::notifyCursorLeaves(Cursor const & /*old*/, Cursor & cur)
 {
        if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
                Buffer const & buffer = cur.buffer();
-               docstring const snippet = latex_string(*this);
+               docstring const snippet = latexString(*this);
                preview_->addPreview(snippet, buffer);
                preview_->startLoading(buffer);
                cur.updateFlags(Update::Force);
@@ -424,23 +481,45 @@ bool InsetMathHull::notifyCursorLeaves(LCursor & cur)
 
 docstring InsetMathHull::label(row_type row) const
 {
-       BOOST_ASSERT(row < nrows());
-       return label_[row];
+       LASSERT(row < nrows(), /**/);
+       if (InsetLabel * il = label_[row])
+               return il->screenLabel();
+       return docstring();
 }
 
 
 void InsetMathHull::label(row_type row, docstring const & label)
 {
        //lyxerr << "setting label '" << label << "' for row " << row << endl;
-       label_[row] = label;
+       if (label_[row]) {
+               if (label.empty()) {
+                       delete label_[row];
+                       label_[row] = dummy_pointer;
+                       // We need an update of the Buffer reference cache.
+                       // This is achieved by updateLabels().
+                       lyx::updateLabels(buffer());
+               } else
+                       label_[row]->updateCommand(label);
+               return;
+       }
+       InsetCommandParams p(LABEL_CODE);
+       p["name"] = label;
+       label_[row] = new InsetLabel(p);
+       if (buffer_)
+               label_[row]->setBuffer(buffer());
 }
 
 
 void InsetMathHull::numbered(row_type row, bool num)
 {
        nonum_[row] = !num;
-       if (nonum_[row])
-               label_[row].clear();
+       if (nonum_[row] && label_[row]) {
+               delete label_[row];
+               label_[row] = 0;
+               // We need an update of the Buffer reference cache.
+               // This is achieved by updateLabels().
+               lyx::updateLabels(buffer());
+       }
 }
 
 
@@ -463,17 +542,9 @@ bool InsetMathHull::ams() const
 }
 
 
-bool InsetMathHull::display() const
+Inset::DisplayType InsetMathHull::display() const
 {
-       return type_ != hullSimple && type_ != hullNone;
-}
-
-
-void InsetMathHull::getLabelList(Buffer const &, vector<docstring> & labels) const
-{
-       for (row_type row = 0; row < nrows(); ++row)
-               if (!label_[row].empty() && nonum_[row] != 1)
-                       labels.push_back(label_[row]);
+       return (type_ != hullSimple && type_ != hullNone) ? AlignCenter : Inline;
 }
 
 
@@ -497,13 +568,11 @@ void InsetMathHull::validate(LaTeXFeatures & features) const
        if (ams())
                features.require("amsmath");
 
-
        // Validation is necessary only if not using AMS math.
        // To be safe, we will always run mathedvalidate.
        //if (features.amsstyle)
        //  return;
 
-       features.require("boldsymbol");
        //features.binom      = true;
 
        InsetMathGrid::validate(features);
@@ -620,8 +689,21 @@ void InsetMathHull::addRow(row_type row)
 {
        if (!rowChangeOK())
                return;
-       nonum_.insert(nonum_.begin() + row + 1, !numberedType());
-       label_.insert(label_.begin() + row + 1, docstring());
+
+       bool numbered = numberedType();
+       docstring lab;
+       if (type_ == hullMultline) {
+               if (row + 1 == nrows())  {
+                       nonum_[row] = true;
+                       lab = label(row);
+               } else
+                       numbered = false;
+       }
+
+       nonum_.insert(nonum_.begin() + row + 1, !numbered);
+       label_.insert(label_.begin() + row + 1, dummy_pointer);
+       if (!lab.empty())
+               label(row + 1, lab);
        InsetMathGrid::addRow(row);
 }
 
@@ -632,7 +714,14 @@ void InsetMathHull::swapRow(row_type row)
                return;
        if (row + 1 == nrows())
                --row;
-       swap(nonum_[row], nonum_[row + 1]);
+       // gcc implements the standard std::vector<bool> which is *not* a container:
+       //   http://www.gotw.ca/publications/N1185.pdf
+       // As a results, it doesn't like this:
+       //      swap(nonum_[row], nonum_[row + 1]);
+       // so we do it manually:
+       bool const b = nonum_[row];
+       nonum_[row] = nonum_[row + 1];
+       nonum_[row + 1] = b;
        swap(label_[row], label_[row + 1]);
        InsetMathGrid::swapRow(row);
 }
@@ -642,12 +731,21 @@ void InsetMathHull::delRow(row_type row)
 {
        if (nrows() <= 1 || !rowChangeOK())
                return;
+       if (row + 1 == nrows() && type_ == hullMultline) {
+               bool const b = nonum_[row - 1];
+               nonum_[row - 1] = nonum_[row];
+               nonum_[row] = b;
+               swap(label_[row - 1], label_[row]);
+               InsetMathGrid::delRow(row);
+               return;
+       }
        InsetMathGrid::delRow(row);
        // The last dummy row has no number info nor a label.
        // Test nrows() + 1 because we have already erased the row.
        if (row == nrows() + 1)
                row--;
        nonum_.erase(nonum_.begin() + row);
+       delete label_[row];
        label_.erase(label_.begin() + row);
 }
 
@@ -672,15 +770,15 @@ docstring InsetMathHull::nicelabel(row_type row) const
 {
        if (nonum_[row])
                return docstring();
-       if (label_[row].empty())
+       if (!label_[row])
                return from_ascii("(#)");
-       return '(' + label_[row] + ')';
+       return '(' + label_[row]->screenLabel() + from_ascii(", #)");
 }
 
 
 void InsetMathHull::glueall()
 {
-       MathArray ar;
+       MathData ar;
        for (idx_type i = 0; i < nargs(); ++i)
                ar.append(cell(i));
        *this = InsetMathHull(hullSimple);
@@ -691,12 +789,12 @@ void InsetMathHull::glueall()
 
 void InsetMathHull::splitTo2Cols()
 {
-       BOOST_ASSERT(ncols() == 1);
+       LASSERT(ncols() == 1, /**/);
        InsetMathGrid::addCol(1);
        for (row_type row = 0; row < nrows(); ++row) {
                idx_type const i = 2 * row;
                pos_type pos = firstRelOp(cell(i));
-               cell(i + 1) = MathArray(cell(i).begin() + pos, cell(i).end());
+               cell(i + 1) = MathData(cell(i).begin() + pos, cell(i).end());
                cell(i).erase(pos, cell(i).size());
        }
 }
@@ -704,14 +802,14 @@ void InsetMathHull::splitTo2Cols()
 
 void InsetMathHull::splitTo3Cols()
 {
-       BOOST_ASSERT(ncols() < 3);
+       LASSERT(ncols() < 3, /**/);
        if (ncols() < 2)
                splitTo2Cols();
-       InsetMathGrid::addCol(1);
+       InsetMathGrid::addCol(2);
        for (row_type row = 0; row < nrows(); ++row) {
                idx_type const i = 3 * row + 1;
                if (cell(i).size()) {
-                       cell(i + 1) = MathArray(cell(i).begin() + 1, cell(i).end());
+                       cell(i + 1) = MathData(cell(i).begin() + 1, cell(i).end());
                        cell(i).erase(1, cell(i).size());
                }
        }
@@ -729,7 +827,7 @@ void InsetMathHull::changeCols(col_type cols)
                else {
                        splitTo3Cols();
                        while (ncols() < cols)
-                               InsetMathGrid::addCol(ncols() - 1);
+                               InsetMathGrid::addCol(ncols());
                }
                return;
        }
@@ -821,23 +919,23 @@ void InsetMathHull::mutate(HullType newtype)
        else if (type_ == hullEqnArray) {
                if (newtype < type_) {
                        // set correct (no)numbering
-                       bool allnonum = true;
-                       for (row_type row = 0; row < nrows(); ++row)
-                               if (!nonum_[row])
-                                       allnonum = false;
+                       nonum_[0] = true;
+                       for (row_type row = 0; row < nrows(); ++row) {
+                               if (!nonum_[row]) {
+                                       nonum_[0] = false;
+                                       break;
+                               }
+                       }
 
                        // set first non-empty label
-                       docstring label;
                        for (row_type row = 0; row < nrows(); ++row) {
-                               if (!label_[row].empty()) {
-                                       label = label_[row];
+                               if (label_[row]) {
+                                       label_[0] = label_[row];
                                        break;
                                }
                        }
 
                        glueall();
-                       nonum_[0] = allnonum;
-                       label_[0] = label;
                        mutate(newtype);
                } else { // align & Co.
                        changeCols(2);
@@ -910,8 +1008,8 @@ docstring InsetMathHull::eolString(row_type row, bool emptyline, bool fragile) c
 {
        docstring res;
        if (numberedType()) {
-               if (!label_[row].empty() && !nonum_[row])
-                       res += "\\label{" + label_[row] + '}';
+               if (label_[row] && !nonum_[row])
+                       res += "\\label{" + label_[row]->getParam("name") + '}';
                if (nonum_[row] && (type_ != hullMultline))
                        res += "\\nonumber ";
        }
@@ -921,6 +1019,7 @@ docstring InsetMathHull::eolString(row_type row, bool emptyline, bool fragile) c
 
 void InsetMathHull::write(WriteStream & os) const
 {
+       ModeSpecifier specifier(os, MATH_MODE);
        header_write(os);
        InsetMathGrid::write(os);
        footer_write(os);
@@ -949,12 +1048,12 @@ void InsetMathHull::infoize(odocstream & os) const
 
 void InsetMathHull::check() const
 {
-       BOOST_ASSERT(nonum_.size() == nrows());
-       BOOST_ASSERT(label_.size() == nrows());
+       LASSERT(nonum_.size() == nrows(), /**/);
+       LASSERT(label_.size() == nrows(), /**/);
 }
 
 
-void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func)
+void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func)
 {
        docstring dlang;
        docstring extra;
@@ -962,20 +1061,18 @@ void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func)
        iss >> dlang >> extra;
        if (extra.empty())
                extra = from_ascii("noextra");
-       std::string const lang = to_ascii(dlang);
+       string const lang = to_ascii(dlang);
 
-#ifdef WITH_WARNINGS
-#warning temporarily disabled
+       // FIXME: temporarily disabled
        //if (cur.selection()) {
-       //      MathArray ar;
+       //      MathData ar;
        //      selGet(cur.ar);
        //      lyxerr << "use selection: " << ar << endl;
        //      insert(pipeThroughExtern(lang, extra, ar));
        //      return;
        //}
-#endif
 
-       MathArray eq;
+       MathData eq;
        eq.push_back(MathAtom(new InsetMathChar('=')));
 
        // go to first item in line
@@ -984,14 +1081,14 @@ void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func)
 
        if (getType() == hullSimple) {
                size_type pos = cur.cell().find_last(eq);
-               MathArray ar;
+               MathData ar;
                if (cur.inMathed() && cur.selection()) {
                        asArray(grabAndEraseSelection(cur), ar);
                } else if (pos == cur.cell().size()) {
                        ar = cur.cell();
                        lyxerr << "use whole cell: " << ar << endl;
                } else {
-                       ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end());
+                       ar = MathData(cur.cell().begin() + pos + 1, cur.cell().end());
                        lyxerr << "use partial cell form pos: " << pos << endl;
                }
                cur.cell().append(eq);
@@ -1003,7 +1100,7 @@ void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func)
        if (getType() == hullEquation) {
                lyxerr << "use equation inset" << endl;
                mutate(hullEqnArray);
-               MathArray & ar = cur.cell();
+               MathData & ar = cur.cell();
                lyxerr << "use cell: " << ar << endl;
                ++cur.idx();
                cur.cell() = eq;
@@ -1018,11 +1115,9 @@ void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func)
                lyxerr << "use eqnarray" << endl;
                cur.idx() += 2 - cur.idx() % ncols();
                cur.pos() = 0;
-               MathArray ar = cur.cell();
+               MathData ar = cur.cell();
                lyxerr << "use cell: " << ar << endl;
-#ifdef WITH_WARNINGS
-#warning temporarily disabled
-#endif
+               // FIXME: temporarily disabled
                addRow(cur.row());
                ++cur.idx();
                ++cur.idx();
@@ -1034,18 +1129,17 @@ void InsetMathHull::doExtern(LCursor & cur, FuncRequest & func)
 }
 
 
-void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
+void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
 {
        //lyxerr << "action: " << cmd.action << endl;
        switch (cmd.action) {
 
-       case LFUN_FINISHED_LEFT:
+       case LFUN_FINISHED_BACKWARD:
+       case LFUN_FINISHED_FORWARD:
        case LFUN_FINISHED_RIGHT:
-       case LFUN_FINISHED_UP:
-       case LFUN_FINISHED_DOWN:
+       case LFUN_FINISHED_LEFT:
                //lyxerr << "action: " << cmd.action << endl;
                InsetMathGrid::doDispatch(cur, cmd);
-               notifyCursorLeaves(cur);
                cur.undispatched();
                break;
 
@@ -1053,46 +1147,44 @@ void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
                // just swallow this
                break;
 
-       case LFUN_BREAK_LINE:
+       case LFUN_NEWLINE_INSERT:
                // some magic for the common case
                if (type_ == hullSimple || type_ == hullEquation) {
-                       recordUndoInset(cur);
+                       cur.recordUndoInset();
                        bool const align =
-                               cur.bv().buffer()->params().use_amsmath == BufferParams::package_on;
+                               cur.bv().buffer().params().use_amsmath == BufferParams::package_on;
                        mutate(align ? hullAlign : hullEqnArray);
-                       cur.idx() = 0;
+                       cur.idx() = nrows() * ncols() - 1;
                        cur.pos() = cur.lastpos();
                }
                InsetMathGrid::doDispatch(cur, cmd);
                break;
 
-       case LFUN_MATH_NUMBER:
+       case LFUN_MATH_NUMBER_TOGGLE: {
                //lyxerr << "toggling all numbers" << endl;
-               if (display()) {
-                       recordUndoInset(cur);
-                       bool old = numberedType();
-                       if (type_ == hullMultline)
-                               numbered(nrows() - 1, !old);
-                       else
-                               for (row_type row = 0; row < nrows(); ++row)
-                                       numbered(row, !old);
-
-                       cur.message(old ? _("No number") : _("Number"));
-               }
+               cur.recordUndoInset();
+               bool old = numberedType();
+               if (type_ == hullMultline)
+                       numbered(nrows() - 1, !old);
+               else
+                       for (row_type row = 0; row < nrows(); ++row)
+                               numbered(row, !old);
+               
+               cur.message(old ? _("No number") : _("Number"));
                break;
+       }
 
-       case LFUN_MATH_NONUMBER:
-               if (display()) {
-                       recordUndoInset(cur);
-                       row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
-                       bool old = numbered(r);
-                       cur.message(old ? _("No number") : _("Number"));
-                       numbered(r, !old);
-               }
+       case LFUN_MATH_NUMBER_LINE_TOGGLE: {
+               cur.recordUndoInset();
+               row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
+               bool old = numbered(r);
+               cur.message(old ? _("No number") : _("Number"));
+               numbered(r, !old);
                break;
+       }
 
        case LFUN_LABEL_INSERT: {
-               recordUndoInset(cur);
+               cur.recordUndoInset();
                row_type r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
                docstring old_label = label(r);
                docstring const default_label = from_ascii(
@@ -1100,12 +1192,12 @@ void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
                if (old_label.empty())
                        old_label = default_label;
 
-               InsetCommandParams p("label");
+               InsetCommandParams p(LABEL_CODE);
                p["name"] = cmd.argument().empty() ? old_label : cmd.argument();
-               std::string const data = InsetCommandMailer::params2string("label", p);
+               string const data = InsetCommand::params2string("label", p);
 
                if (cmd.argument().empty())
-                       cur.bv().showInsetDialog("label", data, 0);
+                       cur.bv().showDialog("label", data);
                else {
                        FuncRequest fr(LFUN_INSET_INSERT, data);
                        dispatch(cur, fr);
@@ -1113,23 +1205,49 @@ void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
                break;
        }
 
+       case LFUN_WORD_DELETE_FORWARD:
+       case LFUN_CHAR_DELETE_FORWARD:
+               if (col(cur.idx()) + 1 == ncols()
+                   && cur.pos() == cur.lastpos()) {
+                       if (!label(row(cur.idx())).empty()) {
+                               cur.recordUndoInset();
+                               label(row(cur.idx()), docstring());
+                       } else if (numbered(row(cur.idx()))) {
+                               cur.recordUndoInset();
+                               numbered(row(cur.idx()), false);
+                       } else {
+                               InsetMathGrid::doDispatch(cur, cmd);
+                               return;
+                       }
+               } else {
+                       InsetMathGrid::doDispatch(cur, cmd);
+                       return;
+               }
+               break;
+
        case LFUN_INSET_INSERT: {
                //lyxerr << "arg: " << to_utf8(cmd.argument()) << endl;
-               std::string const name = cmd.getArg(0);
+               // FIXME: this should be cleaned up to use InsetLabel methods directly.
+               string const name = cmd.getArg(0);
                if (name == "label") {
-                       InsetCommandParams p("label");
-                       InsetCommandMailer::string2params(name, to_utf8(cmd.argument()), p);
+                       InsetCommandParams p(LABEL_CODE);
+                       InsetCommand::string2params(name, to_utf8(cmd.argument()), p);
                        docstring str = p["name"];
-                       recordUndoInset(cur);
+                       cur.recordUndoInset();
                        row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
-                       str = support::trim(str);
+                       str = trim(str);
                        if (!str.empty())
                                numbered(r, true);
                        docstring old = label(r);
                        if (str != old) {
-                               cur.bv().buffer()->changeRefsIfUnique(old, str,
-                                                       InsetBase::REF_CODE);
-                               label(r, str);
+                               if (label_[r])
+                                       // The label will take care of the reference update.
+                                       label(r, str);
+                               else {
+                                       label(r, str);
+                                       // Newly created inset so initialize it.
+                                       label_[r]->initView();
+                               }
                        }
                        break;
                }
@@ -1138,12 +1256,12 @@ void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_MATH_EXTERN:
-               recordUndoInset(cur);
+               cur.recordUndoInset();
                doExtern(cur, cmd);
                break;
 
        case LFUN_MATH_MUTATE: {
-               recordUndoInset(cur);
+               cur.recordUndoInset();
                row_type row = cur.row();
                col_type col = cur.col();
                mutate(hullType(cmd.argument()));
@@ -1154,12 +1272,16 @@ void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
                }
                if (cur.pos() > cur.lastpos())
                        cur.pos() = cur.lastpos();
+               
+               // FIXME: find some more clever handling of the selection,
+               // i.e. preserve it.
+               cur.clearSelection();
                //cur.dispatched(FINISHED);
                break;
        }
 
        case LFUN_MATH_DISPLAY: {
-               recordUndoInset(cur);
+               cur.recordUndoInset();
                mutate(type_ == hullSimple ? hullEquation : hullSimple);
                cur.idx() = 0;
                cur.pos() = cur.lastpos();
@@ -1174,37 +1296,51 @@ void InsetMathHull::doDispatch(LCursor & cur, FuncRequest & cmd)
 }
 
 
-bool InsetMathHull::getStatus(LCursor & cur, FuncRequest const & cmd,
+bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
                FuncStatus & status) const
 {
        switch (cmd.action) {
-       case LFUN_FINISHED_LEFT:
+       case LFUN_FINISHED_BACKWARD:
+       case LFUN_FINISHED_FORWARD:
        case LFUN_FINISHED_RIGHT:
-       case LFUN_FINISHED_UP:
-       case LFUN_FINISHED_DOWN:
-               status.enabled(true);
-               return true;
-       case LFUN_BREAK_LINE:
-       case LFUN_MATH_NUMBER:
-       case LFUN_MATH_NONUMBER:
+       case LFUN_FINISHED_LEFT:
+       case LFUN_UP:
+       case LFUN_DOWN:
+       case LFUN_NEWLINE_INSERT:
        case LFUN_MATH_EXTERN:
        case LFUN_MATH_MUTATE:
        case LFUN_MATH_DISPLAY:
                // we handle these
-               status.enabled(true);
+               status.setEnabled(true);
+               return true;
+       case LFUN_MATH_NUMBER_TOGGLE:
+               // FIXME: what is the right test, this or the one of
+               // LABEL_INSERT?
+               status.setEnabled(display());
+               status.setOnOff(numberedType());
+               return true;
+       case LFUN_MATH_NUMBER_LINE_TOGGLE: {
+               // FIXME: what is the right test, this or the one of
+               // LABEL_INSERT?
+               bool const enable = (type_ == hullMultline) ?
+                       (nrows() - 1 == cur.row()) : display();
+               row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
+               status.setEnabled(enable);
+               status.setOnOff(numbered(r));
                return true;
+       }
        case LFUN_LABEL_INSERT:
-               status.enabled(type_ != hullSimple);
+               status.setEnabled(type_ != hullSimple);
                return true;
        case LFUN_INSET_INSERT:
                if (cmd.getArg(0) == "label") {
-                       status.enabled(type_ != hullSimple);
+                       status.setEnabled(type_ != hullSimple);
                        return true;
                }
                return InsetMathGrid::getStatus(cur, cmd, status);
        case LFUN_TABULAR_FEATURE: {
                istringstream is(to_utf8(cmd.argument()));
-               std::string s;
+               string s;
                is >> s;
                if (!rowChangeOK()
                    && (s == "append-row"
@@ -1213,7 +1349,7 @@ bool InsetMathHull::getStatus(LCursor & cur, FuncRequest const & cmd,
                        status.message(bformat(
                                from_utf8(N_("Can't change number of rows in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if (!colChangeOK()
@@ -1223,7 +1359,7 @@ bool InsetMathHull::getStatus(LCursor & cur, FuncRequest const & cmd,
                        status.message(bformat(
                                from_utf8(N_("Can't change number of columns in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if ((type_ == hullSimple
@@ -1233,20 +1369,20 @@ bool InsetMathHull::getStatus(LCursor & cur, FuncRequest const & cmd,
                        status.message(bformat(
                                from_utf8(N_("Can't add horizontal grid lines in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if (s == "add-vline-left" || s == "add-vline-right") {
                        status.message(bformat(
                                from_utf8(N_("Can't add vertical grid lines in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if (s == "valign-top" || s == "valign-middle"
                 || s == "valign-bottom" || s == "align-left"
                 || s == "align-center" || s == "align-right") {
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                return InsetMathGrid::getStatus(cur, cmd, status);
@@ -1270,11 +1406,11 @@ void InsetMathHull::mutateToText()
 #if 0
        // translate to latex
        ostringstream os;
-       latex(NULL, os, false, false);
+       latex(os, false, false);
        string str = os.str();
 
        // insert this text
-       LyXText * lt = view_->cursor().innerText();
+       Text * lt = view_->cursor().innerText();
        string::const_iterator cit = str.begin();
        string::const_iterator end = str.end();
        for (; cit != end; ++cit)
@@ -1286,12 +1422,12 @@ void InsetMathHull::mutateToText()
 }
 
 
-void InsetMathHull::handleFont(LCursor & cur, docstring const & arg,
+void InsetMathHull::handleFont(Cursor & cur, docstring const & arg,
        docstring const & font)
 {
        // this whole function is a hack and won't work for incremental font
        // changes...
-       recordUndo(cur);
+       cur.recordUndo();
        if (cur.inset().asInsetMath()->name() == font)
                cur.handleFont(to_utf8(font));
        else {
@@ -1301,37 +1437,39 @@ void InsetMathHull::handleFont(LCursor & cur, docstring const & arg,
 }
 
 
-void InsetMathHull::handleFont2(LCursor & cur, docstring const & arg)
+void InsetMathHull::handleFont2(Cursor & cur, docstring const & arg)
 {
-       recordUndo(cur);
-       LyXFont font;
+       cur.recordUndo();
+       Font font;
        bool b;
-       bv_funcs::string2font(to_utf8(arg), font, b);
-       if (font.color() != LColor::inherit) {
-               MathAtom at = MathAtom(new InsetMathColor(true, font.color()));
+       font.fromString(to_utf8(arg), b);
+       if (font.fontInfo().color() != Color_inherit) {
+               MathAtom at = MathAtom(new InsetMathColor(true, font.fontInfo().color()));
                cur.handleNest(at, 0);
        }
 }
 
 
-void InsetMathHull::edit(LCursor & cur, bool left)
+void InsetMathHull::edit(Cursor & cur, bool front, EntryDirection entry_from)
 {
        cur.push(*this);
-       left ? idxFirst(cur) : idxLast(cur);
+       bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_LEFT || 
+               (entry_from == Inset::ENTRY_DIRECTION_IGNORE && front));
+       enter_front ? idxFirst(cur) : idxLast(cur);
        // The inset formula dimension is not necessarily the same as the
        // one of the instant preview image, so we have to indicate to the
-       // BufferView that a metrics update is needed. 
+       // BufferView that a metrics update is needed.
        cur.updateFlags(Update::Force);
 }
 
 
-docstring const InsetMathHull::editMessage() const
+docstring InsetMathHull::editMessage() const
 {
        return _("Math editor mode");
 }
 
 
-void InsetMathHull::revealCodes(LCursor & cur) const
+void InsetMathHull::revealCodes(Cursor & cur) const
 {
        if (!cur.inMathed())
                return;
@@ -1343,7 +1481,7 @@ void InsetMathHull::revealCodes(LCursor & cur) const
        // translate to latex
        cur.markInsert(bv);
        ostringstream os;
-       write(NULL, os);
+       write(os);
        string str = os.str();
        cur.markErase(bv);
        string::size_type pos = 0;
@@ -1367,7 +1505,7 @@ void InsetMathHull::revealCodes(LCursor & cur) const
 }
 
 
-InsetBase::Code InsetMathHull::lyxCode() const
+InsetCode InsetMathHull::lyxCode() const
 {
        return MATH_CODE;
 }
@@ -1380,12 +1518,10 @@ InsetBase::Code InsetMathHull::lyxCode() const
 bool InsetMathHull::searchForward(BufferView * bv, string const & str,
                                     bool, bool)
 {
-#ifdef WITH_WARNINGS
-#warning completely broken
-#endif
+       // FIXME: completely broken
        static InsetMathHull * lastformula = 0;
        static CursorBase current = DocIterator(ibegin(nucleus()));
-       static MathArray ar;
+       static MathData ar;
        static string laststr;
 
        if (lastformula != this || laststr != str) {
@@ -1402,7 +1538,7 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str,
 
        for (DocIterator it = current; it != iend(nucleus()); increment(it)) {
                CursorSlice & top = it.back();
-               MathArray const & a = top.asInsetMath()->cell(top.idx_);
+               MathData const & a = top.asInsetMath()->cell(top.idx_);
                if (a.matchpart(ar, top.pos_)) {
                        bv->cursor().setSelection(it, ar.size());
                        current = it;
@@ -1419,17 +1555,17 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str,
 #endif
 
 
-void InsetMathHull::write(Buffer const &, std::ostream & os) const
+void InsetMathHull::write(ostream & os) const
 {
        odocstringstream oss;
-       WriteStream wi(oss, false, false);
+       WriteStream wi(oss, false, false, false);
        oss << "Formula ";
        write(wi);
        os << to_utf8(oss.str());
 }
 
 
-void InsetMathHull::read(Buffer const &, LyXLex & lex)
+void InsetMathHull::read(Lexer & lex)
 {
        MathAtom at;
        mathed_parse_normal(at, lex);
@@ -1437,8 +1573,7 @@ void InsetMathHull::read(Buffer const &, LyXLex & lex)
 }
 
 
-int InsetMathHull::plaintext(Buffer const &, odocstream & os,
-                             OutputParams const &) const
+int InsetMathHull::plaintext(odocstream & os, OutputParams const & runparams) const
 {
        if (0 && display()) {
                Dimension dim;
@@ -1452,7 +1587,7 @@ int InsetMathHull::plaintext(Buffer const &, odocstream & os,
                return tpain.textheight();
        } else {
                odocstringstream oss;
-               WriteStream wi(oss, false, true);
+               WriteStream wi(oss, false, true, false, runparams.encoding);
                wi << cell(0);
 
                docstring const str = oss.str();
@@ -1462,8 +1597,7 @@ int InsetMathHull::plaintext(Buffer const &, odocstream & os,
 }
 
 
-int InsetMathHull::docbook(Buffer const & buf, odocstream & os,
-                           OutputParams const & runparams) const
+int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) const
 {
        MathStream ms(os);
        int res = 0;
@@ -1475,34 +1609,35 @@ int InsetMathHull::docbook(Buffer const & buf, odocstream & os,
 
        docstring bname = name;
        if (!label(0).empty())
-               bname += " id='" + sgml::cleanID(buf, runparams, label(0)) + "'";
-       ms << MTag(bname);
+               bname += " id='" + sgml::cleanID(buffer(), runparams, label(0)) + "'";
+
+       ++ms.tab(); ms.cr(); ms.os() << '<' << bname << '>';
 
        odocstringstream ls;
        if (runparams.flavor == OutputParams::XML) {
-               ms << MTag(from_ascii("alt role='tex' "));
+               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 wi(ls, false, false, false, runparams.encoding);
                InsetMathGrid::write(wi);
                ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&amp;"), "<", "&lt;"));
-               ms << ETag(from_ascii("alt"));
-               ms << MTag(from_ascii("math"));
-               ms << ETag(from_ascii("alt"));
-               ms << MTag(from_ascii("math"));
+               ms << ETag("alt");
+               ms << MTag("math");
+               ms << ETag("alt");
+               ms << MTag("math");
                InsetMathGrid::mathmlize(ms);
-               ms << ETag(from_ascii("math"));
+               ms << ETag("math");
        } else {
-               ms << MTag(from_ascii("alt role='tex'"));
-               res = latex(buf, ls, runparams);
+               ms << MTag("alt role='tex'");
+               res = latex(ls, runparams);
                ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&amp;"), "<", "&lt;"));
-               ms << ETag(from_ascii("alt"));
+               ms << ETag("alt");
        }
 
        ms << from_ascii("<graphic fileref=\"eqn/");
        if (!label(0).empty())
-               ms << sgml::cleanID(buf, runparams, label(0));
+               ms << sgml::cleanID(buffer(), runparams, label(0));
        else
                ms << sgml::uniqueID(from_ascii("anon"));
 
@@ -1511,14 +1646,21 @@ int InsetMathHull::docbook(Buffer const & buf, odocstream & os,
        else
                ms << from_ascii("\">");
 
-       ms << ETag(name);
+       ms.cr(); --ms.tab(); ms.os() << "</" << name << '>';
+
        return ms.line() + res;
 }
 
 
-void InsetMathHull::textString(Buffer const & buf, odocstream & os) const
+void InsetMathHull::textString(odocstream & os) const
+{
+       plaintext(os, OutputParams(0));
+}
+
+
+docstring InsetMathHull::contextMenu(BufferView const &, int, int) const
 {
-       plaintext(buf, os, OutputParams(0));
+       return from_ascii("context-math");
 }