+bool Undo::undoAction(CursorData & cur)
+{
+ return d->undoRedoAction(cur, true);
+}
+
+
+bool Undo::redoAction(CursorData & cur)
+{
+ return d->undoRedoAction(cur, false);
+}
+
+
+void Undo::beginUndoGroup()
+{
+ if (d->group_level_ == 0) {
+ // create a new group
+ ++d->group_id_;
+ LYXERR(Debug::UNDO, "+++++++ Creating new group " << d->group_id_
+ << " for buffer " << &d->buffer_);
+ }
+ ++d->group_level_;
+}
+
+
+void Undo::beginUndoGroup(CursorData const & cur_before)
+{
+ beginUndoGroup();
+ if (d->group_cur_before_.empty())
+ d->group_cur_before_ = cur_before;
+}
+
+
+void Undo::endUndoGroup()
+{
+ if (d->group_level_ == 0) {
+ LYXERR0("There is no undo group to end here");
+ return;
+ }
+ --d->group_level_;
+ if (d->group_level_ == 0) {
+ // real end of the group
+ d->group_cur_before_ = CursorData();
+ LYXERR(Debug::UNDO, "------- End of group " << d->group_id_
+ << " of buffer " << &d->buffer_);
+ }
+}
+
+
+void Undo::endUndoGroup(CursorData const & cur_after)
+{
+ endUndoGroup();
+ if (!d->undostack_.empty() && d->undostack_.top().cur_after.empty())
+ d->undostack_.top().cur_after = cur_after;
+}
+
+
+void Undo::splitUndoGroup(CursorData const & cur)