>>>>> "Jean-Marc" == Jean-Marc Lasgouttes <[EMAIL PROTECTED]> writes:

Jean-Marc> Please test, in particular with change tracking.

Since the testing did not show big problems, I committed the patch
bug2882-5-14x (below) to 1.4.4svn. The adaptation of this patch to 1.5
is attached. The changelog says

        * text.C (backspacePos0): rewrite to make it simple and allow
        deleting empty paragraphs even when keepempty is true. Do not rely
        on dEPM, since this was silly (bugs 2587 and 2882)
        (Delete): simplify also and avoid calling backspace.
        (backspace): small tweak.

Could someone test it too? Michael?

JMarc

Index: src/ChangeLog
===================================================================
--- src/ChangeLog	(revision 15546)
+++ src/ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2006-10-25  Jean-Marc Lasgouttes  <[EMAIL PROTECTED]>
+
+	* text.C (backspacePos0): rewrite to make it simple and allow
+	deleting empty paragraphs even when keepempty is true. Do not rely
+	on dEPM, since this was silly (bugs 2587 and 2882)
+	(Delete): simplify also and avoid calling backspace.
+	(backspace): small tweak.
+
 2006-10-09  Jürgen Spitzmüller  <[EMAIL PROTECTED]>
 
 	* buffer.[Ch] (changeRefsIfUnique): extend to handle bibitems 
Index: src/text.C
===================================================================
--- src/text.C	(revision 15546)
+++ src/text.C	(working copy)
@@ -1589,31 +1589,35 @@ bool LyXText::Delete(LCursor & cur)
 {
 	BOOST_ASSERT(this == cur.text());
 	bool needsUpdate = false;
+	Paragraph & par = cur.paragraph();
 
 	if (cur.pos() != cur.lastpos()) {
-		recordUndo(cur, Undo::DELETE, cur.pit());
-		setCursorIntern(cur, cur.pit(), cur.pos() + 1, false, cur.boundary());
-		needsUpdate = backspace(cur);
-		if (cur.paragraph().lookupChange(cur.pos()) == Change::DELETED)
-			cur.posRight();
+		// this is the code for a normal delete, not pasting
+		// any paragraphs
+		recordUndo(cur, Undo::DELETE);
+		par.erase(cur.pos());
+		if (par.lookupChange(cur.pos()) == Change::DELETED)
+			cur.forwardPos();
+		needsUpdate = true;
 	} else if (cur.pit() != cur.lastpit()) {
-		LCursor scur = cur;
-
-		setCursorIntern(cur, cur.pit() + 1, 0, false, false);
-		if (pars_[cur.pit()].layout() == pars_[scur.pit()].layout()) {
-			recordUndo(scur, Undo::DELETE, scur.pit());
-			needsUpdate = backspace(cur);
-			if (cur.buffer().params().tracking_changes) {
-				// move forward after the paragraph break is DELETED
-				Paragraph & par = cur.paragraph();
-				if (par.lookupChange(par.size()) == Change::DELETED)
-					setCursorIntern(cur, cur.pit() + 1, 0);
-				}
+		if (cur.buffer().params().tracking_changes
+		    && par.lookupChange(cur.pos()) != Change::INSERTED) {
+			// mark "carriage return" as deleted:
+			par.setChange(cur.pos(), Change::DELETED);
+			cur.forwardPos();
+			needsUpdate = true;
 		} else {
-			setCursorIntern(scur, scur.pit(), scur.pos(), false, scur.boundary());
+			setCursorIntern(cur, cur.pit() + 1, 0);
+			needsUpdate = backspacePos0(cur);
+			if (cur.paragraph().lookupChange(cur.pos()) == Change::DELETED)
+				cur.forwardPos();
 		}
 	} else
 		needsUpdate = dissolveInset(cur);
+
+	// Make sure the cursor is correct. Is this really needed?
+	if (needsUpdate)
+		setCursorIntern(cur, cur.pit(), cur.pos());
 	
 	return needsUpdate;
 }
@@ -1622,73 +1626,50 @@ bool LyXText::Delete(LCursor & cur)
 bool LyXText::backspacePos0(LCursor & cur)
 {
 	BOOST_ASSERT(this == cur.text());
+	if (cur.pit() == 0)
+		return false;
+
 	bool needsUpdate = false;
 
-	Paragraph & par = cur.paragraph();
+	BufferParams const & bufparams = cur.buffer().params();
+	LyXTextClass const & tclass = bufparams.getLyXTextClass();
+	ParagraphList & plist = cur.text()->paragraphs();
+	Paragraph const & par = cur.paragraph();
+	LCursor prevcur = cur;
+	--prevcur.pit();
+	prevcur.pos() = prevcur.lastpos();
+	Paragraph const & prevpar = prevcur.paragraph();
+
 	// is it an empty paragraph?
-	pos_type lastpos = cur.lastpos();
-	if (lastpos == 0 || (lastpos == 1 && par.isSeparator(0))) {
-		// This is an empty paragraph and we delete it just
-		// by moving the cursor one step
-		// left and let the DeleteEmptyParagraphMechanism
-		// handle the actual deletion of the paragraph.
-
-		if (cur.pit() != 0) {
-			// For KeepEmpty layouts we need to get
-			// rid of the keepEmpty setting first.
-			// And the only way to do this is to
-			// reset the layout to something
-			// else: f.ex. the default layout.
-			if (par.allowEmpty()) {
-				Buffer & buf = cur.buffer();
-				BufferParams const & bparams = buf.params();
-				par.layout(bparams.getLyXTextClass().defaultLayout());
-			}
-                                
-			cursorLeft(cur);
-			return true;
-		}
+	if (cur.lastpos() == 0 
+	    || (cur.lastpos() == 1 && par.isSeparator(0))) {
+		recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+		plist.erase(boost::next(plist.begin(), cur.pit()));
+		needsUpdate = true;
 	}
-
-	if (cur.pit() != 0)
-		recordUndo(cur, Undo::DELETE, cur.pit() - 1);
-
-	pit_type tmppit = cur.pit();
-	// We used to do cursorLeftIntern() here, but it is
-	// not a good idea since it triggers the auto-delete
-	// mechanism. So we do a cursorLeftIntern()-lite,
-	// without the dreaded mechanism. (JMarc)
-	if (cur.pit() != 0) {
-		// steps into the above paragraph.
-		setCursorIntern(cur, cur.pit() - 1,
-				pars_[cur.pit() - 1].size(),
-				false);
+	// is previous par empty?
+	else if (prevcur.lastpos() == 0 
+		 || (prevcur.lastpos() == 1 && prevpar.isSeparator(0))) {
+		recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+		plist.erase(boost::next(plist.begin(), prevcur.pit()));
+		needsUpdate = true;
 	}
-
 	// Pasting is not allowed, if the paragraphs have different
 	// layout. I think it is a real bug of all other
 	// word processors to allow it. It confuses the user.
 	// Correction: Pasting is always allowed with standard-layout
-	// Correction (Jug 20050717): Remove check about alignment!
-	Buffer & buf = cur.buffer();
-	BufferParams const & bufparams = buf.params();
-	LyXTextClass const & tclass = bufparams.getLyXTextClass();
-	pit_type const cpit = cur.pit();
-
-	if (cpit != tmppit
-	    && (pars_[cpit].layout() == pars_[tmppit].layout()
-	        || pars_[tmppit].layout() == tclass.defaultLayout()))
-	{
-		mergeParagraph(bufparams, pars_, cpit);
+	else if (par.layout() == prevpar.layout()
+		 || par.layout() == tclass.defaultLayout()) {
+		recordUndo(cur, Undo::ATOMIC, prevcur.pit());
+		mergeParagraph(bufparams, plist, prevcur.pit());
 		needsUpdate = true;
+	}
 
-		if (cur.pos() != 0 && pars_[cpit].isSeparator(cur.pos() - 1))
-				--cur.pos();
-
-		// the counters may have changed
+	if (needsUpdate) {
 		updateCounters(cur.buffer());
-		setCursor(cur, cur.pit(), cur.pos(), false);
+		setCursorIntern(cur, prevcur.pit(), prevcur.pos());
 	}
+
 	return needsUpdate;
 }
 
@@ -1701,11 +1682,7 @@ bool LyXText::backspace(LCursor & cur)
 		if (cur.pit() == 0)
 			return dissolveInset(cur);
 
-		// The cursor is at the beginning of a paragraph, so
-		// the the backspace will collapse two paragraphs into
-		// one.
-
-		if (cur.pit() != 0 && cur.buffer().params().tracking_changes) {
+		if (cur.buffer().params().tracking_changes) {
 			// Previous paragraph, mark "carriage return" as
 			// deleted:
 			Paragraph & par = pars_[cur.pit() - 1];
@@ -1717,6 +1694,8 @@ bool LyXText::backspace(LCursor & cur)
 			}
 		}
 
+		// The cursor is at the beginning of a paragraph, so
+		// the backspace will collapse two paragraphs into one.
 		needsUpdate = backspacePos0(cur);
 
 	} else {
@@ -1727,8 +1706,7 @@ bool LyXText::backspace(LCursor & cur)
 		// not a good idea since it triggers the auto-delete
 		// mechanism. So we do a cursorLeftIntern()-lite,
 		// without the dreaded mechanism. (JMarc)
-		setCursorIntern(cur, cur.pit(), cur.pos() - 1,
-				false, cur.boundary());
+		setCursorIntern(cur, cur.pit(), cur.pos() - 1);
 		cur.paragraph().erase(cur.pos());
 	}
 
Index: status.14x
===================================================================
--- status.14x	(revision 15546)
+++ status.14x	(working copy)
@@ -54,6 +54,10 @@ What's new
   windows). This fix was already used by the official windows installer for
   1.4.3.
 
+- Fix deletion of empty paragraph in various situations: paragraphs
+  with different layouts, layouts with KeepEmpty property, ERT insets
+  (bugs 2587 and 2882)
+
 - Fix cursor positioning when opening the VSpace dialog (bug 2869).
 
 - Give a better error message for missing layout include files
Index: src/text.C
===================================================================
--- src/text.C	(revision 15543)
+++ src/text.C	(working copy)
@@ -1630,35 +1630,36 @@ bool LyXText::erase(LCursor & cur)
 {
 	BOOST_ASSERT(this == cur.text());
 	bool needsUpdate = false;
+	Paragraph & par = cur.paragraph();
 
 	if (cur.pos() != cur.lastpos()) {
-		recordUndo(cur, Undo::DELETE, cur.pit());
-		setCursorIntern(cur, cur.pit(), cur.pos() + 1, false, cur.boundary());
-		needsUpdate = backspace(cur);
-		// FIXME: change tracking (MG)
-		if (cur.paragraph().isDeleted(cur.pos()))
-			cur.posRight();
+		// this is the code for a normal delete, not pasting
+		// any paragraphs
+		recordUndo(cur, Undo::DELETE);
+		par.eraseChar(cur.pos(), cur.buffer().params().trackChanges);
+		if (par.isDeleted(cur.pos()))
+			cur.forwardPos();
+		needsUpdate = true;
 	} else if (cur.pit() != cur.lastpit()) {
-		LCursor scur = cur;
-
-		setCursorIntern(cur, cur.pit() + 1, 0, false, false);
-		if (pars_[cur.pit()].layout() == pars_[scur.pit()].layout()) {
-			recordUndo(scur, Undo::DELETE, scur.pit());
-			needsUpdate = backspace(cur);
-			if (cur.buffer().params().trackChanges) {
-				// FIXME: Change tracking (MG)
-				// move forward after the paragraph break is DELETED
-				Paragraph & par = cur.paragraph();
-				// FIXME: change tracking (MG)
-				if (par.isDeleted(par.size()))
-					setCursorIntern(cur, cur.pit() + 1, 0);
-				}
+		if (cur.buffer().params().trackChanges
+		    && par.isInserted(cur.pos())) {
+			// mark "carriage return" as deleted:
+			par.setChange(cur.pos(), Change(Change::DELETED));
+			cur.forwardPos();
+			needsUpdate = true;
 		} else {
-			setCursorIntern(scur, scur.pit(), scur.pos(), false, scur.boundary());
+			setCursorIntern(cur, cur.pit() + 1, 0);
+			needsUpdate = backspacePos0(cur);
+			if (cur.paragraph().isDeleted(cur.pos()))
+				cur.forwardPos();
 		}
 	} else
 		needsUpdate = dissolveInset(cur);
 
+	// Make sure the cursor is correct. Is this really needed?
+	if (needsUpdate)
+		setCursorIntern(cur, cur.pit(), cur.pos());
+	
 	return needsUpdate;
 }
 
@@ -1666,79 +1667,56 @@ bool LyXText::erase(LCursor & cur)
 bool LyXText::backspacePos0(LCursor & cur)
 {
 	BOOST_ASSERT(this == cur.text());
+	if (cur.pit() == 0)
+		return false;
+
 	bool needsUpdate = false;
 
-	Paragraph & par = cur.paragraph();
-	// is it an empty paragraph?
-	pos_type lastpos = cur.lastpos();
-	if (lastpos == 0 || (lastpos == 1 && par.isSeparator(0))) {
-		// This is an empty paragraph and we delete it just
-		// by moving the cursor one step
-		// left and let the DeleteEmptyParagraphMechanism
-		// handle the actual deletion of the paragraph.
-
-		if (cur.pit() != 0) {
-			// For KeepEmpty layouts we need to get
-			// rid of the keepEmpty setting first.
-			// And the only way to do this is to
-			// reset the layout to something
-			// else: f.ex. the default layout.
-			if (par.allowEmpty()) {
-				Buffer & buf = cur.buffer();
-				BufferParams const & bparams = buf.params();
-				par.layout(bparams.getLyXTextClass().defaultLayout());
-			}
+	BufferParams const & bufparams = cur.buffer().params();
+	LyXTextClass const & tclass = bufparams.getLyXTextClass();
+	ParagraphList & plist = cur.text()->paragraphs();
+	Paragraph const & par = cur.paragraph();
+	LCursor prevcur = cur;
+	--prevcur.pit();
+	prevcur.pos() = prevcur.lastpos();
+	Paragraph const & prevpar = prevcur.paragraph();
 
-			cursorLeft(cur);
-			return true;
-		}
+	// is it an empty paragraph?
+	if (cur.lastpos() == 0 
+	    || (cur.lastpos() == 1 && par.isSeparator(0))) {
+		recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+		plist.erase(boost::next(plist.begin(), cur.pit()));
+		needsUpdate = true;
 	}
-
-	if (cur.pit() != 0)
-		recordUndo(cur, Undo::DELETE, cur.pit() - 1);
-
-	pit_type tmppit = cur.pit();
-	// We used to do cursorLeftIntern() here, but it is
-	// not a good idea since it triggers the auto-delete
-	// mechanism. So we do a cursorLeftIntern()-lite,
-	// without the dreaded mechanism. (JMarc)
-	if (cur.pit() != 0) {
-		// steps into the above paragraph.
-		setCursorIntern(cur, cur.pit() - 1,
-				pars_[cur.pit() - 1].size(),
-				false);
+	// is previous par empty?
+	else if (prevcur.lastpos() == 0 
+		 || (prevcur.lastpos() == 1 && prevpar.isSeparator(0))) {
+		recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+		plist.erase(boost::next(plist.begin(), prevcur.pit()));
+		needsUpdate = true;
 	}
-
 	// Pasting is not allowed, if the paragraphs have different
 	// layout. I think it is a real bug of all other
 	// word processors to allow it. It confuses the user.
 	// Correction: Pasting is always allowed with standard-layout
-	// Correction (Jug 20050717): Remove check about alignment!
-	Buffer & buf = cur.buffer();
-	BufferParams const & bufparams = buf.params();
-	LyXTextClass const & tclass = bufparams.getLyXTextClass();
-	pit_type const cpit = cur.pit();
-
-	if (cpit != tmppit
-	    && (pars_[cpit].layout() == pars_[tmppit].layout()
-		|| pars_[tmppit].layout() == tclass.defaultLayout()))
-	{
-		mergeParagraph(bufparams, pars_, cpit);
+	else if (par.layout() == prevpar.layout()
+		 || par.layout() == tclass.defaultLayout()) {
+		recordUndo(cur, Undo::ATOMIC, prevcur.pit());
+		mergeParagraph(bufparams, plist, prevcur.pit());
 		needsUpdate = true;
+	}
 
-		if (cur.pos() != 0 && pars_[cpit].isSeparator(cur.pos() - 1))
-				--cur.pos();
-
-		// the counters may have changed
-		ParIterator par_it(cur);
-		updateLabels(cur.buffer(), par_it);
-
-		setCursor(cur, cur.pit(), cur.pos(), false);
+	if (needsUpdate) {
+		updateLabels(cur.buffer());
+		setCursorIntern(cur, prevcur.pit(), prevcur.pos());
 	}
+
 	return needsUpdate;
 }
 
 
+
+
 bool LyXText::backspace(LCursor & cur)
 {
 	BOOST_ASSERT(this == cur.text());
@@ -1747,11 +1725,7 @@ bool LyXText::backspace(LCursor & cur)
 		if (cur.pit() == 0)
 			return dissolveInset(cur);
 
-		// The cursor is at the beginning of a paragraph, so
-		// the the backspace will collapse two paragraphs into
-		// one.
-
-		if (cur.pit() != 0 && cur.buffer().params().trackChanges) {
+		if (cur.buffer().params().trackChanges) {
 			// FIXME: Change tracking (MG)
 			// Previous paragraph, mark "carriage return" as
 			// deleted:
@@ -1766,6 +1740,8 @@ bool LyXText::backspace(LCursor & cur)
 			}
 		}
 
+		// The cursor is at the beginning of a paragraph, so
+		// the backspace will collapse two paragraphs into one.
 		needsUpdate = backspacePos0(cur);
 
 	} else {

Reply via email to