http://bugzilla.lyx.org/show_bug.cgi?id=4566
Attached is a backport of Stefan's fixes for this bug. It works for me, and Uwe tested it as well, but since it entails a range of changes, please have a look before I commit. Jürgen
Index: src/mathed/InsetMathNest.cpp =================================================================== --- src/mathed/InsetMathNest.cpp (Revision 24068) +++ src/mathed/InsetMathNest.cpp (Arbeitskopie) @@ -413,66 +413,78 @@ // this whole function is a hack and won't work for incremental font // changes... - if (cur.inset().asInsetMath()->name() == font) { - recordUndoInset(cur, Undo::ATOMIC); + recordUndoSelection(cur); + + if (cur.inset().asInsetMath()->name() == font) cur.handleFont(to_utf8(font)); - } else { - CursorSlice i1 = cur.selBegin(); - CursorSlice i2 = cur.selEnd(); - if (!i1.inset().asInsetMath()) - return; - if (i1.idx() == i2.idx()) { - // the easy case where only one cell is selected - recordUndo(cur, Undo::ATOMIC); - cur.handleNest(createInsetMath(font)); + else + handleNest(cur, createInsetMath(font), arg); +} + + +void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest) +{ + handleNest(cur, nest, docstring()); +} + + +void InsetMathNest::handleNest(Cursor & cur, MathAtom const & nest, + docstring const & arg) +{ + CursorSlice i1 = cur.selBegin(); + CursorSlice i2 = cur.selEnd(); + if (!i1.inset().asInsetMath()) + return; + if (i1.idx() == i2.idx()) { + // the easy case where only one cell is selected + cur.handleNest(nest); + cur.insert(arg); + return; + } + + // multiple selected cells in a simple non-grid inset + if (i1.asInsetMath()->nrows() == 0 || i1.asInsetMath()->ncols() == 0) { + for (idx_type i = i1.idx(); i <= i2.idx(); ++i) { + // select cell + cur.idx() = i; + cur.pos() = 0; + cur.resetAnchor(); + cur.pos() = cur.lastpos(); + cur.setSelection(); + + // change font of cell + cur.handleNest(nest); cur.insert(arg); - return; + + // cur is in the font inset now. If the loop continues, + // we need to get outside again for the next cell + if (i + 1 <= i2.idx()) + cur.pop_back(); } - // multiple selected cells in a simple non-grid inset - if (i1.asInsetMath()->nrows() == 0 || i1.asInsetMath()->ncols() == 0) { - recordUndoInset(cur); - for (idx_type i = i1.idx(); i <= i2.idx(); ++i) { - // select cell - cur.idx() = i; - cur.pos() = 0; - cur.resetAnchor(); - cur.pos() = cur.lastpos(); - cur.setSelection(); - - // change font of cell - cur.handleNest(createInsetMath(font)); - cur.insert(arg); - - // cur is in the font inset now. If the loop continues, - // we need to get outside again for the next cell - if (i + 1 <= i2.idx()) - cur.pop_back(); - } - return; - } - // the complicated case with multiple selected cells in a grid - recordUndoInset(cur); - Inset::row_type r1, r2; - Inset::col_type c1, c2; - cap::region(i1, i2, r1, r2, c1, c2); - for (Inset::row_type row = r1; row <= r2; ++row) { - for (Inset::col_type col = c1; col <= c2; ++col) { - // select cell - cur.idx() = i1.asInsetMath()->index(row, col); - cur.pos() = 0; - cur.resetAnchor(); - cur.pos() = cur.lastpos(); - cur.setSelection(); + return; + } - // change font of cell - cur.handleNest(createInsetMath(font)); - cur.insert(arg); + // the complicated case with multiple selected cells in a grid + Inset::row_type r1, r2; + Inset::col_type c1, c2; + cap::region(i1, i2, r1, r2, c1, c2); + for (Inset::row_type row = r1; row <= r2; ++row) { + for (Inset::col_type col = c1; col <= c2; ++col) { + // select cell + cur.idx() = i1.asInsetMath()->index(row, col); + cur.pos() = 0; + cur.resetAnchor(); + cur.pos() = cur.lastpos(); + cur.setSelection(); - // cur is in the font inset now. If the loop continues, - // we need to get outside again for the next cell - if (col + 1 <= c2 || row + 1 <= r2) - cur.pop_back(); - } + // change font of cell + cur.handleNest(nest); + cur.insert(arg); + + // cur is in the font inset now. If the loop continues, + // we need to get outside again for the next cell + if (col + 1 <= c2 || row + 1 <= r2) + cur.pop_back(); } } } @@ -480,14 +492,12 @@ void InsetMathNest::handleFont2(Cursor & cur, docstring const & arg) { - recordUndo(cur, Undo::ATOMIC); + recordUndoSelection(cur); Font font; bool b; bv_funcs::string2font(to_utf8(arg), font, b); - if (font.color() != Color::inherit && font.color() != Color::ignore) { - MathAtom at = MathAtom(new InsetMathColor(true, font.color())); - cur.handleNest(at, 0); - } + if (font.color() != Color::inherit && font.color() != Color::ignore) + handleNest(cur, MathAtom(new InsetMathColor(true, font.color()))); } @@ -1029,11 +1039,17 @@ // handling such that "self-insert" works on "arbitrary stuff" too, and // math-insert only handles special math things like "matrix". case LFUN_MATH_INSERT: { - recordUndo(cur, Undo::ATOMIC); - if (cmd.argument() == "^" || cmd.argument() == "_") { + recordUndoSelection(cur); + if (cmd.argument() == "^" || cmd.argument() == "_") interpretChar(cur, cmd.argument()[0]); - } else - cur.niceInsert(cmd.argument()); + else { + MathData ar; + asArray(cmd.argument(), ar); + if (ar.size() == 1 && ar[0]->asNestInset()) + handleNest(cur, ar[0]); + else + cur.niceInsert(cmd.argument()); + } break; } Index: src/mathed/InsetMathNest.h =================================================================== --- src/mathed/InsetMathNest.h (Revision 24068) +++ src/mathed/InsetMathNest.h (Arbeitskopie) @@ -128,6 +128,11 @@ docstring const & arg, char const * const font); /// void handleFont2(Cursor & cur, docstring const & arg); + /// Grab and erase selection and insert the InsetMathNest atom in every + /// previously selected cell, insert the grabbed former data and \c arg + /// in the first cell of the inserted atom. + void handleNest(Cursor & cur, MathAtom const & nest); + void handleNest(Cursor & cur, MathAtom const & nest, docstring const & arg); /// interpret \p c and insert the result at the current position of /// of \p cur. Return whether the cursor should stay in the formula. Index: src/CutAndPaste.h =================================================================== --- src/CutAndPaste.h (Revision 24068) +++ src/CutAndPaste.h (Arbeitskopie) @@ -106,6 +106,8 @@ void region(CursorSlice const & i1, CursorSlice const & i2, Inset::row_type & r1, Inset::row_type & r2, Inset::col_type & c1, Inset::col_type & c2); +/// Returns true if multiple cells are selected in mathed. +bool multipleCellsSelected(Cursor const & cur); /// Get the current selection as a string. Does not change the selection. /// Does only work if the whole selection is in mathed. docstring grabSelection(Cursor const & cur); Index: src/CutAndPaste.cpp =================================================================== --- src/CutAndPaste.cpp (Revision 24068) +++ src/CutAndPaste.cpp (Arbeitskopie) @@ -404,6 +404,23 @@ } +bool multipleCellsSelected(Cursor const & cur) +{ + if (!cur.selection() || !cur.inMathed()) + return false; + + CursorSlice i1 = cur.selBegin(); + CursorSlice i2 = cur.selEnd(); + if (!i1.inset().asInsetMath()) + return false; + + if (i1.idx() == i2.idx()) + return false; + + return true; +} + + void switchBetweenClasses(textclass_type c1, textclass_type c2, InsetText & in, ErrorList & errorlist) { Index: src/Undo.cpp =================================================================== --- src/Undo.cpp (Revision 24068) +++ src/Undo.cpp (Arbeitskopie) @@ -19,6 +19,7 @@ #include "Buffer.h" #include "buffer_funcs.h" #include "Cursor.h" +#include "CutAndPaste.h" #include "debug.h" #include "BufferView.h" #include "Text.h" @@ -282,7 +283,14 @@ void recordUndoSelection(Cursor & cur, Undo::undo_kind kind) { - recordUndo(kind, cur, cur.selBegin().pit(), cur.selEnd().pit()); + if (cur.inMathed()) { + if (cap::multipleCellsSelected(cur)) + recordUndoInset(cur, kind); + else + recordUndo(cur, kind); + } else + recordUndo(kind, cur, cur.selBegin().pit(), + cur.selEnd().pit()); }