]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/InsetMathNest.C
* InsetMathNest.C (handleFont): avoid crash on undo when
[lyx.git] / src / mathed / InsetMathNest.C
index 787b0b11a53c9b25a5cd1a5c683b3cd5b58742a8..367b4a65b743a143ad3eddb5e0ad90d01d7bbe63 100644 (file)
@@ -22,7 +22,7 @@
 #include "InsetMathDelim.h"
 #include "MathFactory.h"
 #include "InsetMathHull.h"
-#include "MathMLStream.h"
+#include "MathStream.h"
 #include "MathMacroArgument.h"
 //#include "InsetMathMBox.h"
 #include "MathParser.h"
 #include "dispatchresult.h"
 #include "funcrequest.h"
 #include "gettext.h"
+#include "lyxtext.h"
 #include "outputparams.h"
 #include "undo.h"
 
 #include "support/lstrings.h"
 
-#include "frontends/Dialogs.h"
-#include "frontends/Gui.h"
-#include "frontends/LyXView.h"
 #include "frontends/Painter.h"
 #include "frontends/Selection.h"
-#include "frontends/nullpainter.h"
+
+#include "funcrequest.h"
+#include "lyxserver.h"
+#include "lyxsocket.h"
 
 #include <sstream>
 
-using lyx::cap::copySelection;
-using lyx::cap::grabAndEraseSelection;
-using lyx::cap::cutSelection;
-using lyx::cap::replaceSelection;
-using lyx::cap::selClearOrDel;
 
-using lyx::frontend::Gui;
-using lyx::frontend::Clipboard;
+namespace lyx {
+
+using cap::copySelection;
+using cap::grabAndEraseSelection;
+using cap::cutSelection;
+using cap::replaceSelection;
+using cap::selClearOrDel;
 
 using std::endl;
 using std::string;
@@ -95,8 +96,9 @@ MathArray const & InsetMathNest::cell(idx_type i) const
 }
 
 
-void InsetMathNest::cursorPos(CursorSlice const & sl, bool /*boundary*/,
-       int & x, int & y) const
+void InsetMathNest::cursorPos(BufferView const & bv,
+               CursorSlice const & sl, bool /*boundary*/,
+               int & x, int & y) const
 {
 // FIXME: This is a hack. Ideally, the coord cache should not store
 // absolute positions, but relative ones. This would mean to call
@@ -107,7 +109,8 @@ void InsetMathNest::cursorPos(CursorSlice const & sl, bool /*boundary*/,
 // absolute again when actually drawing the cursor. What a mess.
        BOOST_ASSERT(ptr_cmp(&sl.inset(), this));
        MathArray const & ar = sl.cell();
-       if (!theCoords.getArrays().has(&ar)) {
+       CoordCache const & coord_cache = bv.coordCache();
+       if (!coord_cache.getArrays().has(&ar)) {
                // this can (semi-)legally happen if we just created this cell
                // and it never has been drawn before. So don't ASSERT.
                //lyxerr << "no cached data for array " << &ar << endl;
@@ -115,15 +118,15 @@ void InsetMathNest::cursorPos(CursorSlice const & sl, bool /*boundary*/,
                y = 0;
                return;
        }
-       Point const pt = theCoords.getArrays().xy(&ar);
-       if (!theCoords.getInsets().has(this)) {
+       Point const pt = coord_cache.getArrays().xy(&ar);
+       if (!coord_cache.getInsets().has(this)) {
                // same as above
                //lyxerr << "no cached data for inset " << this << endl;
                x = 0;
                y = 0;
                return;
        }
-       Point const pt2 = theCoords.getInsets().xy(this);
+       Point const pt2 = coord_cache.getInsets().xy(this);
        //lyxerr << "retrieving position cache for MathArray "
        //      << pt.x_ << ' ' << pt.y_ << std::endl;
        x = pt.x_ - pt2.x_ + ar.pos2x(sl.pos());
@@ -203,13 +206,15 @@ bool InsetMathNest::idxLast(LCursor & cur) const
 
 void InsetMathNest::dump() const
 {
-       WriteStream os(lyxerr);
+       odocstringstream oss;
+       WriteStream os(oss);
        os << "---------------------------------------------\n";
        write(os);
        os << "\n";
        for (idx_type i = 0, n = nargs(); i != n; ++i)
                os << cell(i) << "\n";
        os << "---------------------------------------------\n";
+       lyxerr << to_utf8(oss.str());
 }
 
 
@@ -226,29 +231,30 @@ void InsetMathNest::draw(PainterInfo & pi, int x, int y) const
 
 void InsetMathNest::drawSelection(PainterInfo & pi, int x, int y) const
 {
+       BufferView & bv = *pi.base.bv;
        // this should use the x/y values given, not the cached values
-       LCursor & cur = pi.base.bv->cursor();
+       LCursor & cur = bv.cursor();
        if (!cur.selection())
                return;
        if (!ptr_cmp(&cur.inset(), this))
                return;
 
        // FIXME: hack to get position cache warm
-       static lyx::frontend::NullPainter nop;
-       PainterInfo pinop(pi);
-       pinop.pain = nop;
-       draw(pinop, x, y);
+       pi.pain.setDrawingEnabled(false);
+       draw(pi, x, y);
+       pi.pain.setDrawingEnabled(true);
 
        CursorSlice s1 = cur.selBegin();
        CursorSlice s2 = cur.selEnd();
+
        //lyxerr << "InsetMathNest::drawing selection: "
        //      << " s1: " << s1 << " s2: " << s2 << endl;
        if (s1.idx() == s2.idx()) {
                MathArray const & c = cell(s1.idx());
-               int x1 = c.xo() + c.pos2x(s1.pos());
-               int y1 = c.yo() - c.ascent();
-               int x2 = c.xo() + c.pos2x(s2.pos());
-               int y2 = c.yo() + c.descent();
+               int x1 = c.xo(bv) + c.pos2x(s1.pos());
+               int y1 = c.yo(bv) - c.ascent();
+               int x2 = c.xo(bv) + c.pos2x(s2.pos());
+               int y2 = c.yo(bv) + c.descent();
                pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
        //lyxerr << "InsetMathNest::drawing selection 3: "
        //      << " x1: " << x1 << " x2: " << x2
@@ -257,10 +263,10 @@ void InsetMathNest::drawSelection(PainterInfo & pi, int x, int y) const
                for (idx_type i = 0; i < nargs(); ++i) {
                        if (idxBetween(i, s1.idx(), s2.idx())) {
                                MathArray const & c = cell(i);
-                               int x1 = c.xo();
-                               int y1 = c.yo() - c.ascent();
-                               int x2 = c.xo() + c.width();
-                               int y2 = c.yo() + c.descent();
+                               int x1 = c.xo(bv);
+                               int y1 = c.yo(bv) - c.ascent();
+                               int x2 = c.xo(bv) + c.width();
+                               int y2 = c.yo(bv) + c.descent();
                                pi.pain.fillRectangle(x1, y1, x2 - x1, y2 - y1, LColor::selection);
                        }
                }
@@ -341,7 +347,7 @@ void InsetMathNest::normalize(NormalStream & os) const
 }
 
 
-int InsetMathNest::latex(Buffer const &, std::ostream & os,
+int InsetMathNest::latex(Buffer const &, odocstream & os,
                        OutputParams const & runparams) const
 {
        WriteStream wi(os, runparams.moving_arg, true);
@@ -384,27 +390,35 @@ bool InsetMathNest::notifyCursorLeaves(LCursor & /*cur*/)
 
 
 void InsetMathNest::handleFont
-       (LCursor & cur, string const & arg, string const & font)
+       (LCursor & cur, docstring const & arg, char const * const font)
+{
+       handleFont(cur, arg, from_ascii(font));
+}
+
+
+void InsetMathNest::handleFont
+       (LCursor & cur, docstring const & arg, docstring const & font)
 {
        // this whole function is a hack and won't work for incremental font
        // changes...
-       recordUndo(cur, Undo::ATOMIC);
 
-       if (cur.inset().asInsetMath()->name() == font)
-               cur.handleFont(font);
-       else {
+       if (cur.inset().asInsetMath()->name() == font) {
+               recordUndoInset(cur, Undo::ATOMIC);
+               cur.handleFont(to_utf8(font));
+       } else {
+               recordUndo(cur, Undo::ATOMIC);
                cur.handleNest(createInsetMath(font));
                cur.insert(arg);
        }
 }
 
 
-void InsetMathNest::handleFont2(LCursor & cur, string const & arg)
+void InsetMathNest::handleFont2(LCursor & cur, docstring const & arg)
 {
        recordUndo(cur, Undo::ATOMIC);
        LyXFont font;
        bool b;
-       bv_funcs::string2font(arg, font, b);
+       bv_funcs::string2font(to_utf8(arg), font, b);
        if (font.color() != LColor::inherit) {
                MathAtom at = MathAtom(new InsetMathColor(true, font.color()));
                cur.handleNest(at, 0);
@@ -424,9 +438,9 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                cur.message(_("Paste"));
                replaceSelection(cur);
                size_t n = 0;
-               istringstream is(lyx::to_utf8(cmd.argument()));
+               istringstream is(to_utf8(cmd.argument()));
                is >> n;
-               string const selection = lyx::cap::getSelection(cur.buffer(), n);
+               docstring const selection = cap::getSelection(cur.buffer(), n);
                cur.niceInsert(selection);
                cur.clearSelection(); // bug 393
                cur.bv().switchKeyMap();
@@ -479,8 +493,13 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                cur.bv().cursor() = cur;
                break;
 
-       case LFUN_CHAR_FORWARD_SELECT:
        case LFUN_CHAR_FORWARD:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_CHAR_FORWARD_SELECT:
                cur.selHandle(cmd.action == LFUN_CHAR_FORWARD_SELECT);
                cur.autocorrect() = false;
                cur.clearTargetX();
@@ -497,8 +516,13 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                }
                break;
 
-       case LFUN_CHAR_BACKWARD_SELECT:
        case LFUN_CHAR_BACKWARD:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_CHAR_BACKWARD_SELECT:
                cur.selHandle(cmd.action == LFUN_CHAR_BACKWARD_SELECT);
                cur.autocorrect() = false;
                cur.clearTargetX();
@@ -516,8 +540,13 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                }
                break;
 
-       case LFUN_UP_SELECT:
        case LFUN_UP:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_UP_SELECT:
                // FIXME Tried to use clearTargetX and macroModeClose, crashed on cur.up()
                if (cur.inMacroMode()) {
                        // Make Helge happy
@@ -533,8 +562,13 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                cur.normalize();
                break;
 
-       case LFUN_DOWN_SELECT:
        case LFUN_DOWN:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_DOWN_SELECT:
                if (cur.inMacroMode()) {
                        cur.macroModeClose();
                        break;
@@ -559,16 +593,26 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                cur.idx() = cur.lastidx();
                break;
 
-       case LFUN_PARAGRAPH_UP_SELECT:
        case LFUN_PARAGRAPH_UP:
-       case LFUN_PARAGRAPH_DOWN_SELECT:
        case LFUN_PARAGRAPH_DOWN:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_PARAGRAPH_UP_SELECT:
+       case LFUN_PARAGRAPH_DOWN_SELECT:
                break;
 
-       case LFUN_LINE_BEGIN_SELECT:
        case LFUN_LINE_BEGIN:
-       case LFUN_WORD_BACKWARD_SELECT:
        case LFUN_WORD_BACKWARD:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_LINE_BEGIN_SELECT:
+       case LFUN_WORD_BACKWARD_SELECT:
                cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT ||
                                cmd.action == LFUN_LINE_BEGIN_SELECT);
                cur.macroModeClose();
@@ -586,10 +630,15 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                }
                break;
 
-       case LFUN_WORD_FORWARD_SELECT:
        case LFUN_WORD_FORWARD:
-       case LFUN_LINE_END_SELECT:
        case LFUN_LINE_END:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
+       case LFUN_WORD_FORWARD_SELECT:
+       case LFUN_LINE_END_SELECT:
                cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT ||
                                cmd.action == LFUN_LINE_END_SELECT);
                cur.macroModeClose();
@@ -621,10 +670,20 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_CELL_FORWARD:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
                cur.inset().idxNext(cur);
                break;
 
        case LFUN_CELL_BACKWARD:
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset. If we know for
+               // sure that we stay within the same cell we can optimize for
+               // that using:
+               //cur.updateFlags(Update::FitCursor);
                cur.inset().idxPrev(cur);
                break;
 
@@ -635,7 +694,11 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                        recordUndoInset(cur, Undo::ATOMIC);
                else
                        recordUndo(cur, Undo::ATOMIC);
-               cur.backspace();
+               // if the inset can not be removed from within, delete it
+               if (!cur.backspace()) {
+                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
+                       cur.bv().getLyXText()->dispatch(cur, cmd);
+               }
                break;
 
        case LFUN_WORD_DELETE_FORWARD:
@@ -645,7 +708,11 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                        recordUndoInset(cur, Undo::ATOMIC);
                else
                        recordUndo(cur, Undo::ATOMIC);
-               cur.erase();
+               // if the inset can not be removed from within, delete it
+               if (!cur.erase()) {
+                       FuncRequest cmd = FuncRequest(LFUN_CHAR_DELETE_FORWARD);
+                       cur.bv().getLyXText()->dispatch(cur, cmd);
+               }
                break;
 
        case LFUN_ESCAPE:
@@ -666,8 +733,8 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_SELF_INSERT:
                if (cmd.argument().size() != 1) {
                        recordUndo(cur);
-                       string const arg = lyx::to_utf8(cmd.argument());
-                       if (!interpret(cur, arg))
+                       docstring const arg = cmd.argument();
+                       if (!interpretString(cur, arg))
                                cur.insert(arg);
                        break;
                }
@@ -694,10 +761,7 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                                cur.posLeft();
                                cur.pushLeft(*cur.nextInset());
                        }
-               // FIXME: Change to
-               // } else if (!interpret(cur, cmd.argument()[0])) {
-               // when interpret accepts UCS4 characters
-               } else if (!interpret(cur, lyx::to_utf8(cmd.argument()))) {
+               } else if (!interpretChar(cur, cmd.argument()[0])) {
                        cmd = FuncRequest(LFUN_FINISHED_RIGHT);
                        cur.undispatched();
                }
@@ -711,7 +775,7 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                lyxerr << "LFUN_SERVER_SET_XY broken!" << endl;
                int x = 0;
                int y = 0;
-               istringstream is(lyx::to_utf8(cmd.argument()));
+               istringstream is(to_utf8(cmd.argument()));
                is >> x >> y;
                cur.setScreenPos(x, y);
                break;
@@ -747,60 +811,60 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
        //  Math fonts
        case LFUN_FONT_FREE_APPLY:
        case LFUN_FONT_FREE_UPDATE:
-               handleFont2(cur, lyx::to_utf8(cmd.argument()));
+               handleFont2(cur, cmd.argument());
                break;
 
        case LFUN_FONT_BOLD:
                if (currentMode() == TEXT_MODE)
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "textbf");
+                       handleFont(cur, cmd.argument(), "textbf");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathbf");
+                       handleFont(cur, cmd.argument(), "mathbf");
                break;
        case LFUN_FONT_SANS:
                if (currentMode() == TEXT_MODE)
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "textsf");
+                       handleFont(cur, cmd.argument(), "textsf");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathsf");
+                       handleFont(cur, cmd.argument(), "mathsf");
                break;
        case LFUN_FONT_EMPH:
                if (currentMode() == TEXT_MODE)
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "emph");
+                       handleFont(cur, cmd.argument(), "emph");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathcal");
+                       handleFont(cur, cmd.argument(), "mathcal");
                break;
        case LFUN_FONT_ROMAN:
                if (currentMode() == TEXT_MODE)
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "textrm");
+                       handleFont(cur, cmd.argument(), "textrm");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathrm");
+                       handleFont(cur, cmd.argument(), "mathrm");
                break;
        case LFUN_FONT_CODE:
                if (currentMode() == TEXT_MODE)
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "texttt");
+                       handleFont(cur, cmd.argument(), "texttt");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathtt");
+                       handleFont(cur, cmd.argument(), "mathtt");
                break;
        case LFUN_FONT_FRAK:
-               handleFont(cur, lyx::to_utf8(cmd.argument()), "mathfrak");
+               handleFont(cur, cmd.argument(), "mathfrak");
                break;
        case LFUN_FONT_ITAL:
                if (currentMode() == TEXT_MODE)
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "textit");
+                       handleFont(cur, cmd.argument(), "textit");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathit");
+                       handleFont(cur, cmd.argument(), "mathit");
                break;
        case LFUN_FONT_NOUN:
                if (currentMode() == TEXT_MODE)
                        // FIXME: should be "noun"
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "textsc");
+                       handleFont(cur, cmd.argument(), "textsc");
                else
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "mathbb");
+                       handleFont(cur, cmd.argument(), "mathbb");
                break;
        //case LFUN_FONT_FREE_APPLY:
-               handleFont(cur, lyx::to_utf8(cmd.argument()), "textrm");
+               handleFont(cur, cmd.argument(), "textrm");
                break;
        case LFUN_FONT_DEFAULT:
-               handleFont(cur, lyx::to_utf8(cmd.argument()), "textnormal");
+               handleFont(cur, cmd.argument(), "textnormal");
                break;
 
        case LFUN_MATH_MODE: {
@@ -809,10 +873,10 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                if (currentMode() == InsetBase::MATH_MODE && cmd.argument() == "on")
                        break;
                cur.macroModeClose();
-               string const save_selection = grabAndEraseSelection(cur);
+               docstring const save_selection = grabAndEraseSelection(cur);
                selClearOrDel(cur);
                //cur.plainInsert(MathAtom(new InsetMathMBox(cur.bv())));
-               cur.plainInsert(MathAtom(new InsetMathBox("mbox")));
+               cur.plainInsert(MathAtom(new InsetMathBox(from_ascii("mbox"))));
                cur.posLeft();
                cur.pushLeft(*cur.nextInset());
                cur.niceInsert(save_selection);
@@ -821,7 +885,7 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                        cur.niceInsert(MathAtom(new InsetMathHull("simple")));
                        cur.message(_("create new math text environment ($...$)"));
                } else {
-                       handleFont(cur, lyx::to_utf8(cmd.argument()), "textrm");
+                       handleFont(cur, cmd.argument(), "textrm");
                        cur.message(_("entered math text mode (textrm)"));
                }
 #endif
@@ -839,9 +903,9 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                recordUndo(cur, Undo::ATOMIC);
                unsigned int m = 1;
                unsigned int n = 1;
-               string v_align;
-               string h_align;
-               istringstream is(lyx::to_utf8(cmd.argument()));
+               docstring v_align;
+               docstring h_align;
+               idocstringstream is(cmd.argument());
                is >> m >> n >> v_align >> h_align;
                if (m < 1)
                        m = 1;
@@ -849,13 +913,13 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                        n = 1;
                v_align += 'c';
                cur.niceInsert(
-                       MathAtom(new InsetMathArray("array", m, n, v_align[0], h_align)));
+                       MathAtom(new InsetMathArray(from_ascii("array"), m, n, (char)v_align[0], h_align)));
                break;
        }
 
        case LFUN_MATH_DELIM: {
-               string ls;
-               string rs = lyx::support::split(lyx::to_utf8(cmd.argument()), ls, ' ');
+               docstring ls;
+               docstring rs = support::split(cmd.argument(), ls, ' ');
                // Reasonable default values
                if (ls.empty())
                        ls = '(';
@@ -867,10 +931,10 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_MATH_BIGDELIM: {
-               string const lname = cmd.getArg(0);
-               string const ldelim = cmd.getArg(1);
-               string const rname = cmd.getArg(2);
-               string const rdelim = cmd.getArg(3);
+               docstring const lname  = from_utf8(cmd.getArg(0));
+               docstring const ldelim = from_utf8(cmd.getArg(1));
+               docstring const rname  = from_utf8(cmd.getArg(2));
+               docstring const rdelim = from_utf8(cmd.getArg(3));
                latexkeys const * l = in_word_set(lname);
                bool const have_l = l && l->inset == "big" &&
                                    InsetMathBig::isBigInsetDelim(ldelim);
@@ -881,7 +945,7 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
                // or right delimiter.
                if (have_l || have_r) {
                        recordUndo(cur, Undo::ATOMIC);
-                       string const selection = grabAndEraseSelection(cur);
+                       docstring const selection = grabAndEraseSelection(cur);
                        selClearOrDel(cur);
                        if (have_l)
                                cur.insert(MathAtom(new InsetMathBig(lname,
@@ -899,25 +963,31 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_SPACE_INSERT:
        case LFUN_MATH_SPACE:
                recordUndo(cur, Undo::ATOMIC);
-               cur.insert(MathAtom(new InsetMathSpace(",")));
+               cur.insert(MathAtom(new InsetMathSpace(from_ascii(","))));
                break;
 
        case LFUN_ERT_INSERT:
                // interpret this as if a backslash was typed
                recordUndo(cur, Undo::ATOMIC);
-               interpret(cur, '\\');
+               interpretChar(cur, '\\');
                break;
 
        case LFUN_MATH_SUBSCRIPT:
                // interpret this as if a _ was typed
                recordUndo(cur, Undo::ATOMIC);
-               interpret(cur, '_');
+               interpretChar(cur, '_');
                break;
 
        case LFUN_MATH_SUPERSCRIPT:
                // interpret this as if a ^ was typed
                recordUndo(cur, Undo::ATOMIC);
-               interpret(cur, '^');
+               interpretChar(cur, '^');
+               break;
+
+       case LFUN_QUOTE_INSERT:
+               // interpret this as if a straight " was typed
+               recordUndo(cur, Undo::ATOMIC);
+               interpretChar(cur, '\"');
                break;
 
 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
@@ -925,21 +995,31 @@ void InsetMathNest::doDispatch(LCursor & cur, FuncRequest & cmd)
 // math-insert only handles special math things like "matrix".
        case LFUN_MATH_INSERT: {
                recordUndo(cur, Undo::ATOMIC);
-               if (cmd.argument() == "^" || cmd.argument() == "_")
-                       interpret(cur, cmd.argument()[0]);
-               else
-                       cur.niceInsert(lyx::to_utf8(cmd.argument()));
+               if (cmd.argument() == "^" || cmd.argument() == "_") {
+                       interpretChar(cur, cmd.argument()[0]);
+               else
+                       cur.niceInsert(cmd.argument());
                break;
                }
 
        case LFUN_DIALOG_SHOW_NEW_INSET: {
-               string const & name = lyx::to_utf8(cmd.argument());
+               docstring const & name = cmd.argument();
                string data;
                if (name == "ref") {
                        RefInset tmp(name);
-                       data = tmp.createDialogStr(name);
+                       data = tmp.createDialogStr(to_utf8(name));
                }
-               cur.bv().owner()->getDialogs().show(name, data, 0);
+               cur.bv().showInsetDialog(to_utf8(name), data, 0);
+               break;
+       }
+
+       case LFUN_INSET_INSERT: {
+               MathArray ar;
+               if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
+                       recordUndo(cur);
+                       cur.insert(ar);
+               } else
+                       cur.undispatched();
                break;
        }
 
@@ -956,7 +1036,7 @@ bool InsetMathNest::getStatus(LCursor & cur, FuncRequest const & cmd,
        // the font related toggles
        //string tc = "mathnormal";
        bool ret = true;
-       string const arg = lyx::to_utf8(cmd.argument());
+       string const arg = to_utf8(cmd.argument());
        switch (cmd.action) {
        case LFUN_TABULAR_FEATURE:
                flag.enabled(false);
@@ -993,7 +1073,7 @@ bool InsetMathNest::getStatus(LCursor & cur, FuncRequest const & cmd,
                flag.enabled(true);
                break;
        case LFUN_MATH_MUTATE:
-               //flag.setOnOff(mathcursor::formula()->hullType() == lyx::to_utf8(cmd.argument()));
+               //flag.setOnOff(mathcursor::formula()->hullType() == to_utf8(cmd.argument()));
                flag.setOnOff(false);
                break;
 
@@ -1027,6 +1107,15 @@ bool InsetMathNest::getStatus(LCursor & cur, FuncRequest const & cmd,
                flag.enabled(currentMode() == MATH_MODE);
                break;
 
+       case LFUN_INSET_INSERT: {
+               // Don't test createMathInset_fromDialogStr(), since
+               // getStatus is not called with a valid reference and the
+               // dialog would not be applyable.
+               string const name = cmd.getArg(0);
+               flag.enabled(name == "ref");
+               break;
+       }
+
        case LFUN_MATH_DELIM:
        case LFUN_MATH_BIGDELIM:
                // Don't do this with multi-cell selections
@@ -1056,7 +1145,7 @@ InsetBase * InsetMathNest::editXY(LCursor & cur, int x, int y)
        int idx_min = 0;
        int dist_min = 1000000;
        for (idx_type i = 0, n = nargs(); i != n; ++i) {
-               int const d = cell(i).dist(x, y);
+               int const d = cell(i).dist(cur.bv(), x, y);
                if (d < dist_min) {
                        dist_min = d;
                        idx_min = i;
@@ -1065,12 +1154,13 @@ InsetBase * InsetMathNest::editXY(LCursor & cur, int x, int y)
        MathArray & ar = cell(idx_min);
        cur.push(*this);
        cur.idx() = idx_min;
-       cur.pos() = ar.x2pos(x - ar.xo());
+       cur.pos() = ar.x2pos(x - ar.xo(cur.bv()));
+
        //lyxerr << "found cell : " << idx_min << " pos: " << cur.pos() << endl;
        if (dist_min == 0) {
                // hit inside cell
                for (pos_type i = 0, n = ar.size(); i < n; ++i)
-                       if (ar[i]->covers(x, y))
+                       if (ar[i]->covers(cur.bv(), x, y))
                                return ar[i].nucleus()->editXY(cur, x, y);
        }
        return this;
@@ -1084,12 +1174,15 @@ void InsetMathNest::lfunMousePress(LCursor & cur, FuncRequest & cmd)
        if (cmd.button() == mouse_button::button1) {
                //lyxerr << "## lfunMousePress: setting cursor to: " << cur << endl;
                bv.mouseSetCursor(cur);
+               // FIXME: we have to enable full redraw here because of the
+               // visual box corners that define the inset.
+               //cur.noUpdate();
        } else if (cmd.button() == mouse_button::button2) {
                MathArray ar;
                if (cur.selection())
-                       asArray(lyx::to_utf8(bv.cursor().selectionAsString(false)), ar);
+                       asArray(bv.cursor().selectionAsString(false), ar);
                else
-                       asArray(lyx::to_utf8(bv.owner()->gui().selection().get()), ar);
+                       asArray(theSelection().get(), ar);
 
                cur.insert(ar);
                bv.mouseSetCursor(cur);
@@ -1120,13 +1213,15 @@ void InsetMathNest::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
        //lyxerr << "## lfunMouseRelease: buttons: " << cmd.button() << endl;
 
        if (cmd.button() == mouse_button::button1) {
-               //cur.bv().owner()->gui().selection().put(cur.grabSelection());
+               //theSelection().put(cur.grabSelection());
+               if (!cur.selection())
+                       cur.noUpdate();
                return;
        }
 
        if (cmd.button() == mouse_button::button3) {
                // try to dispatch to enclosed insets first
-               cur.bv().owner()->getDialogs().show("mathpanel");
+               cur.bv().showDialog("mathpanel");
                return;
        }
 
@@ -1134,10 +1229,10 @@ void InsetMathNest::lfunMouseRelease(LCursor & cur, FuncRequest & cmd)
 }
 
 
-bool InsetMathNest::interpret(LCursor & cur, char c)
+bool InsetMathNest::interpretChar(LCursor & cur, char_type c)
 {
        //lyxerr << "interpret 2: '" << c << "'" << endl;
-       string save_selection;
+       docstring save_selection;
        if (c == '^' || c == '_')
                save_selection = grabAndEraseSelection(cur);
 
@@ -1145,7 +1240,7 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
 
        // handle macroMode
        if (cur.inMacroMode()) {
-               string name = cur.macroName();
+               docstring name = cur.macroName();
 
                /// are we currently typing '#1' or '#2' or...?
                if (name == "\\#") {
@@ -1157,7 +1252,7 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
                }
 
                if (isalpha(c)) {
-                       cur.activeMacro()->setName(name + c);
+                       cur.activeMacro()->setName(name + docstring(1, c));
                        return true;
                }
 
@@ -1178,28 +1273,28 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
                                cur.niceInsert(MathAtom(new InsetMathComment));
                        } else if (c == '#') {
                                BOOST_ASSERT(cur.activeMacro());
-                               cur.activeMacro()->setName(name + c);
+                               cur.activeMacro()->setName(name + docstring(1, c));
                        } else {
                                cur.backspace();
-                               cur.niceInsert(createInsetMath(string(1, c)));
+                               cur.niceInsert(createInsetMath(docstring(1, c)));
                        }
                        return true;
                }
 
                // One character big delimiters. The others are handled in
-               // the other interpret() method.
+               // interpretString().
                latexkeys const * l = in_word_set(name.substr(1));
                if (name[0] == '\\' && l && l->inset == "big") {
-                       string delim;
+                       docstring delim;
                        switch (c) {
                        case '{':
-                               delim = "\\{";
+                               delim = from_ascii("\\{");
                                break;
                        case '}':
-                               delim = "\\}";
+                               delim = from_ascii("\\}");
                                break;
                        default:
-                               delim = string(1, c);
+                               delim = docstring(1, c);
                                break;
                        }
                        if (InsetMathBig::isBigInsetDelim(delim)) {
@@ -1221,7 +1316,7 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
                if (c == '{')
                        cur.niceInsert(MathAtom(new InsetMathBrace));
                else if (c != ' ')
-                       interpret(cur, c);
+                       interpretChar(cur, c);
                return true;
        }
 
@@ -1246,7 +1341,7 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
 
        if (c == '\\') {
                //lyxerr << "starting with macro" << endl;
-               cur.insert(MathAtom(new InsetMathUnknown("\\", false)));
+               cur.insert(MathAtom(new InsetMathUnknown(from_ascii("\\"), false)));
                return true;
        }
 
@@ -1262,17 +1357,36 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
                        // but suppress direct insertion of two spaces in a row
                        // the still allows typing  '<space>a<space>' and deleting the 'a', but
                        // it is better than nothing...
-                       if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
+                       if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ') {
                                cur.insert(c);
+                               // FIXME: we have to enable full redraw here because of the
+                               // visual box corners that define the inset. If we know for
+                               // sure that we stay within the same cell we can optimize for
+                               // that using:
+                               //cur.updateFlags(Update::SinglePar | Update::FitCursor);
+                       }
                        return true;
                }
                if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
                        cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
+                       // FIXME: we have to enable full redraw here because of the
+                       // visual box corners that define the inset. If we know for
+                       // sure that we stay within the same cell we can optimize for
+                       // that using:
+                       //cur.updateFlags(Update::SinglePar | Update::FitCursor);
                        return true;
                }
-               if (cur.popRight())
+
+               if (cur.popRight()) {
+                       // FIXME: we have to enable full redraw here because of the
+                       // visual box corners that define the inset. If we know for
+                       // sure that we stay within the same cell we can optimize for
+                       // that using:
+                       //cur.updateFlags(Update::FitCursor);
                        return true;
-               // if are at the very end, leave the formula
+               }
+
+               // if we are at the very end, leave the formula
                return cur.pos() != cur.lastpos();
        }
 
@@ -1294,7 +1408,7 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
 
        if (c == '{' || c == '}' || c == '&' || c == '$' || c == '#' ||
            c == '%' || c == '_' || c == '^') {
-               cur.niceInsert(createInsetMath(string(1, c)));
+               cur.niceInsert(createInsetMath(docstring(1, c)));
                return true;
        }
 
@@ -1310,14 +1424,14 @@ bool InsetMathNest::interpret(LCursor & cur, char c)
 }
 
 
-bool InsetMathNest::interpret(LCursor & cur, string const & str)
+bool InsetMathNest::interpretString(LCursor & cur, docstring const & str)
 {
        // Create a InsetMathBig from cur.cell()[cur.pos() - 1] and t if
        // possible
        if (!cur.empty() && cur.pos() > 0 &&
            cur.cell()[cur.pos() - 1]->asUnknownInset()) {
                if (InsetMathBig::isBigInsetDelim(str)) {
-                       string prev = asString(cur.cell()[cur.pos() - 1]);
+                       docstring prev = asString(cur.cell()[cur.pos() - 1]);
                        if (prev[0] == '\\') {
                                prev = prev.substr(1);
                                latexkeys const * l = in_word_set(prev);
@@ -1333,8 +1447,8 @@ bool InsetMathNest::interpret(LCursor & cur, string const & str)
 }
 
 
-bool InsetMathNest::script(LCursor & cur, bool up, string const &
-               save_selection)
+bool InsetMathNest::script(LCursor & cur, bool up, 
+               docstring const & save_selection)
 {
        // Hack to get \^ and \_ working
        //lyxerr << "handling script: up: " << up << endl;
@@ -1342,7 +1456,7 @@ bool InsetMathNest::script(LCursor & cur, bool up, string const &
                if (up)
                        cur.niceInsert(createInsetMath("mathcircumflex"));
                else
-                       interpret(cur, '_');
+                       interpretChar(cur, '_');
                return true;
        }
 
@@ -1373,11 +1487,7 @@ bool InsetMathNest::script(LCursor & cur, bool up, string const &
                }
                --cur.pos();
                InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset();
-               // special handling of {}-bases
-               // is this always correct?
-               if (inset->nuc().size() == 1
-                   && inset->nuc().back()->asBraceInset())
-                       inset->nuc() = inset->nuc().back()->asNestInset()->cell(0);
+               // See comment in MathParser.C for special handling of {}-bases
 
                cur.push(*inset);
                cur.idx() = 1;
@@ -1389,3 +1499,6 @@ bool InsetMathNest::script(LCursor & cur, bool up, string const &
        //lyxerr << "inserting selection 2:\n" << save_selection << endl;
        return true;
 }
+
+
+} // namespace lyx