* simplify notifyCursorLeaves logic: We now only call it from strategic

places, i.e.
  - BufferView::setMouseCursor,
  - BufferView::mouseEventDispatch
  - LyXFunc::dispatch
  Before it was called from several dispatch handlers in the middle of the
  dispatch process. Because the cursor might get invalidated, this is
  not a good idea. We had plenty of crashes and odd behaviours because
  of this as nobody really understood those cases.

  This fixes (at least) #2069 and #4163.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@23140 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Stefan Schimanski 2008-02-22 20:45:18 +00:00
parent 90a88ba87d
commit 8527a08903
16 changed files with 58 additions and 73 deletions

View File

@ -1417,6 +1417,7 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
// LFUN_FILE_OPEN generated by drag-and-drop.
FuncRequest cmd = cmd0;
Cursor old = cursor();
Cursor cur(*this);
cur.push(buffer_.inset());
cur.selection() = d->cursor_.selection();
@ -1478,13 +1479,19 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0)
if (!cur.result().dispatched())
cur.dispatch(cmd);
//Do we have a selection?
// Notify left insets
if (cur != old) {
old.fixIfBroken();
bool badcursor = notifyCursorLeaves(old, cur);
if (badcursor)
cursor().fixIfBroken();
}
// Do we have a selection?
theSelection().haveSelection(cursor().selection());
// If the command has been dispatched,
if (cur.result().dispatched()
// an update is asked,
&& cur.result().update())
if (cur.result().dispatched() || cur.result().update())
processUpdateFlags(cur.result().update());
}
@ -1675,8 +1682,12 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select)
// Has the cursor just left the inset?
bool badcursor = false;
bool leftinset = (&d->cursor_.inset() != &cur.inset());
if (leftinset)
if (leftinset) {
d->cursor_.fixIfBroken();
badcursor = notifyCursorLeaves(d->cursor_, cur);
if (badcursor)
cur.fixIfBroken();
}
// FIXME: shift-mouse selection doesn't work well across insets.
bool do_selection = select && &d->cursor_.anchor().inset() == &cur.inset();
@ -1689,24 +1700,7 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select)
if (!do_selection && !badcursor && d->cursor_.inTexted())
update |= checkDepm(cur, d->cursor_);
// if the cursor was in an empty script inset and the new
// position is in the nucleus of the inset, notifyCursorLeaves
// will kill the script inset itself. So we check all the
// elements of the cursor to make sure that they are correct.
// For an example, see bug 2933:
// http://bugzilla.lyx.org/show_bug.cgi?id=2933
// The code below could maybe be moved to a DocIterator method.
//lyxerr << "cur before " << cur << endl;
DocIterator dit = doc_iterator_begin(cur.inset());
dit.bottom() = cur.bottom();
size_t i = 1;
while (i < cur.depth() && dit.nextInset() == &cur[i].inset()) {
dit.push_back(cur[i]);
++i;
}
//lyxerr << "5 cur after" << dit <<endl;
d->cursor_.setCursor(dit);
d->cursor_.setCursor(cur);
d->cursor_.boundary(cur.boundary());
if (do_selection)
d->cursor_.setSelection();

View File

@ -377,8 +377,6 @@ void Cursor::pushBackward(Inset & p)
bool Cursor::popBackward()
{
BOOST_ASSERT(!empty());
//lyxerr << "Leaving inset from in front" << endl;
inset().notifyCursorLeaves(*this);
if (depth() == 1)
return false;
pop();
@ -391,7 +389,6 @@ bool Cursor::popForward()
BOOST_ASSERT(!empty());
//lyxerr << "Leaving inset from in back" << endl;
const pos_type lp = (depth() > 1) ? (*this)[depth() - 2].lastpos() : 0;
inset().notifyCursorLeaves(*this);
if (depth() == 1)
return false;
pop();
@ -1768,7 +1765,7 @@ bool Cursor::fixIfBroken()
}
bool notifyCursorLeaves(DocIterator const & old, Cursor & cur)
bool notifyCursorLeaves(Cursor const & old, Cursor & cur)
{
// find inset in common
size_type i;
@ -1780,7 +1777,9 @@ bool notifyCursorLeaves(DocIterator const & old, Cursor & cur)
// notify everything on top of the common part in old cursor,
// but stop if the inset claims the cursor to be invalid now
for (; i < old.depth(); ++i) {
if (old[i].inset().notifyCursorLeaves(cur))
Cursor insetPos = old;
insetPos.cutOff(i);
if (old[i].inset().notifyCursorLeaves(insetPos, cur))
return true;
}

View File

@ -398,7 +398,7 @@ public:
* Sure that the cursor old is valid, i.e. all inset pointers
* point to valid insets! Use Cursor::fixIfBroken if necessary.
*/
bool notifyCursorLeaves(DocIterator const & old, Cursor & cur);
bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
} // namespace lyx

View File

@ -1705,15 +1705,20 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
}
// Let the current Cursor dispatch its own actions.
Cursor old = view()->cursor();
view()->cursor().getPos(cursorPosBeforeDispatchX_,
cursorPosBeforeDispatchY_);
view()->cursor().dispatch(cmd);
updateFlags = view()->cursor().result().update();
if (!view()->cursor().result().dispatched()) {
// No update needed in this case (e.g. when reaching
// top of document.
updateFlags = Update::None;
// notify insets we just left
if (view()->cursor() != old) {
old.fixIfBroken();
bool badcursor = notifyCursorLeaves(old, view()->cursor());
if (badcursor)
view()->cursor().fixIfBroken();
}
updateFlags = view()->cursor().result().update();
}
if (lyx_view_ && lyx_view_->buffer()) {

View File

@ -590,10 +590,6 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
bool up = cmd.action == LFUN_UP_SELECT || cmd.action == LFUN_UP;
bool const successful = cur.upDownInText(up, needsUpdate);
if (successful) {
// notify insets which were left and get their update flags
notifyCursorLeaves(cur.beforeDispatchCursor(), cur);
cur.fixIfBroken();
// redraw if you leave mathed (for the decorations)
needsUpdate |= cur.beforeDispatchCursor().inMathed();
} else

View File

@ -34,6 +34,7 @@ class Change;
class Cursor;
class CursorSlice;
class Dimension;
class DocIterator;
class FuncRequest;
class FuncStatus;
class InsetCollapsable;
@ -221,9 +222,8 @@ public:
/// number of columns in gridlike structures
virtual size_t ncols() const { return 0; }
/// is called when the cursor leaves this inset
/// returns true if cursor is now invalid. The cursor parameter
/// is _not_ necessarily pointing to the inset.
virtual bool notifyCursorLeaves(Cursor &) { return false; }
/// returns true if cursor is now invalid.
virtual bool notifyCursorLeaves(Cursor const &, Cursor &) { return false; }
/// is called when the mouse enter or leave this inset
/// return true if this inset needs repaint
virtual bool setMouseHover(bool) { return false; }

View File

@ -414,7 +414,7 @@ void InsetMathHull::addPreview(graphics::PreviewLoader & ploader) const
}
bool InsetMathHull::notifyCursorLeaves(Cursor & cur)
bool InsetMathHull::notifyCursorLeaves(Cursor const & /*old*/, Cursor & cur)
{
if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
Buffer const & buffer = cur.buffer();
@ -1046,7 +1046,6 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
case LFUN_FINISHED_LEFT:
//lyxerr << "action: " << cmd.action << endl;
InsetMathGrid::doDispatch(cur, cmd);
notifyCursorLeaves(cur);
cur.undispatched();
break;

View File

@ -116,7 +116,7 @@ public:
virtual void textString(Buffer const &, odocstream &) const;
/// get notification when the cursor leaves this inset
bool notifyCursorLeaves(Cursor & cur);
bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
///
//bool insetAllowed(InsetCode code) const;
///

View File

@ -371,7 +371,7 @@ bool InsetMathNest::setMouseHover(bool mouse_hover)
}
bool InsetMathNest::notifyCursorLeaves(Cursor & /*cur*/)
bool InsetMathNest::notifyCursorLeaves(Cursor const & /*old*/, Cursor & /*cur*/)
{
// FIXME: look here
#if 0
@ -584,12 +584,8 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
// go up/down
bool up = cmd.action == LFUN_UP || cmd.action == LFUN_UP_SELECT;
bool successful = cur.upDownInMath(up);
if (successful) {
// notify left insets and give them chance to set update flags
lyx::notifyCursorLeaves(cur.beforeDispatchCursor(), cur);
cur.fixIfBroken();
if (successful)
break;
}
if (cur.fixIfBroken())
// FIXME: Something bad happened. We pass the corrected Cursor

View File

@ -97,7 +97,7 @@ public:
/// access to the lock
void lock(bool);
/// get notification when the cursor leaves this inset
bool notifyCursorLeaves(Cursor & cur);
bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
/// direct access to the cell.
/// inlined because shows in profile.

View File

@ -660,9 +660,9 @@ void InsetMathScript::infoize2(odocstream & os) const
}
bool InsetMathScript::notifyCursorLeaves(Cursor & cur)
bool InsetMathScript::notifyCursorLeaves(Cursor const & old, Cursor & cur)
{
InsetMathNest::notifyCursorLeaves(cur);
InsetMathNest::notifyCursorLeaves(old, cur);
//LYXERR0("InsetMathScript::notifyCursorLeaves: 1 " << cur);
@ -690,14 +690,13 @@ bool InsetMathScript::notifyCursorLeaves(Cursor & cur)
if ((nargs() == 2 && cell(1).empty())
|| (nargs() == 3 && cell(1).empty() && cell(2).empty())) {
// Make undo step. We cannot use cur for this because
// it does not necessarily point to us. The BufferView
// cursor though should do.
int scriptSlice
= cur.bv().cursor().find(this);
// it does not necessarily point to us anymore. But we
// should be on top of the cursor old.
Cursor insetCur = old;
int scriptSlice = insetCur.find(this);
BOOST_ASSERT(scriptSlice != -1);
Cursor & bvCur = cur.bv().cursor();
bvCur.cutOff(scriptSlice);
bvCur.recordUndoInset();
insetCur.cutOff(scriptSlice);
insetCur.recordUndoInset();
// Let the script inset commit suicide. This is
// modelled on Cursor.pullArg(), but tries not to
@ -705,12 +704,9 @@ bool InsetMathScript::notifyCursorLeaves(Cursor & cur)
// cur (since the top slice will be deleted
// afterwards)
MathData ar = cell(0);
bvCur.pop();
bvCur.cell().erase(bvCur.pos());
bvCur.cell().insert(bvCur.pos(), ar);
// put cursor behind
bvCur.pos() += ar.size();
insetCur.pop();
insetCur.cell().erase(insetCur.pos());
insetCur.cell().insert(insetCur.pos(), ar);
// redraw
cur.updateFlags(cur.disp_.update() | Update::SinglePar);

View File

@ -129,7 +129,7 @@ private:
/// where do we have to draw the scripts?
bool hasLimits() const;
/// clean up empty cells and return true if a cell has been deleted.
bool notifyCursorLeaves(Cursor & cur);
bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
/// possible subscript (index 0) and superscript (index 1)
bool cell_1_is_up_;

View File

@ -606,10 +606,10 @@ bool MathMacro::idxLast(Cursor & cur) const
}
bool MathMacro::notifyCursorLeaves(Cursor & cur)
bool MathMacro::notifyCursorLeaves(Cursor const & old, Cursor & cur)
{
cur.updateFlags(Update::Force);
return InsetMathNest::notifyCursorLeaves(cur);
return InsetMathNest::notifyCursorLeaves(old, cur);
}

View File

@ -56,7 +56,7 @@ public:
bool idxLast(Cursor &) const;
///
virtual bool notifyCursorLeaves(Cursor &);
virtual bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
/// Remove cell (starting from 0)
void removeArgument(pos_type pos);

View File

@ -538,11 +538,11 @@ void MathMacroTemplate::edit(Cursor & cur, bool front, EntryDirection entry_from
}
bool MathMacroTemplate::notifyCursorLeaves(Cursor & cur)
bool MathMacroTemplate::notifyCursorLeaves(Cursor const & old, Cursor & cur)
{
updateLook();
cur.updateFlags(Update::Force);
return InsetMathNest::notifyCursorLeaves(cur);
return InsetMathNest::notifyCursorLeaves(old, cur);
}

View File

@ -40,7 +40,7 @@ public:
///
void edit(Cursor & cur, bool front, EntryDirection entry_from);
///
bool notifyCursorLeaves(Cursor & cur);
bool notifyCursorLeaves(Cursor const & old, Cursor & cur);
///
void read(Buffer const &, Lexer & lex);
///