remove positions when range is deleted

Change-Id: Ib8d295a7f1dc1b620812646f4a2f808c0ae6bc1f
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
index bcb6406..9a92e9d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
@@ -4,7 +4,7 @@
  * are made available under the terms of the Eclipse Public License v1.0

  * which accompanies this distribution, and is available at

  * http://www.eclipse.org/legal/epl-v10.html

- * 

+ *

  * Contributors:

  * 		Florian Thienel - initial API and implementation

  *******************************************************************************/

@@ -172,20 +172,6 @@
 	}

 

 	@Test

-	public void shouldMovePositionsWithinRemovedRangeToRangeStart() throws Exception {

-		content.insertText(0, "Hello New World");

-		final IPosition nPosition = content.createPosition(6);

-		final IPosition ePosition = content.createPosition(7);

-		final IPosition wPosition = content.createPosition(8);

-

-		content.remove(new ContentRange(6, 8));

-

-		assertEquals(6, nPosition.getOffset());

-		assertEquals(6, ePosition.getOffset());

-		assertEquals(6, wPosition.getOffset());

-	}

-

-	@Test

 	public void canRemovePosition() throws Exception {

 		content.insertTagMarker(0);

 		content.insertTagMarker(0);

@@ -231,4 +217,23 @@
 			assertEquals(content.getRawText().charAt(i), content.charAt(i));

 		}

 	}

+

+	@Test

+	public void whenDeletingRange_shouldInvalidatePosistionsInRange() throws Exception {

+		content.insertTagMarker(0);

+		content.insertText(0, "Hello");

+		content.insertTagMarker(0);

+		final IPosition positionBefore = content.createPosition(0);

+		final IPosition firstDeletedPosition = content.createPosition(1);

+		final IPosition lastDeletedPosition = content.createPosition(5);

+		final IPosition positionAfter = content.createPosition(6);

+

+		content.remove(new ContentRange(1, 5));

+

+		assertTrue("before", positionBefore.isValid());

+		assertFalse("first deleted", firstDeletedPosition.isValid());

+		assertFalse("last deleted", lastDeletedPosition.isValid());

+		assertTrue("after", positionAfter.isValid());

+	}

+

 }

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
index 9ef1ea0..6fd6d6e 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
@@ -4,13 +4,14 @@
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * 
+ *
  * Contributors:
  *     John Krasnay - initial API and implementation
  *******************************************************************************/
 package org.eclipse.vex.core.internal.dom;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
@@ -55,6 +56,22 @@
 	}
 
 	@Test
+	public void whenDeletingRange_shouldRemovePosistionsInRange() throws Exception {
+		final GapContent content = new GapContent(10);
+		content.insertTagMarker(0);
+		content.insertText(0, "Hello");
+		content.insertTagMarker(0);
+		content.createPosition(0);
+		content.createPosition(1);
+		content.createPosition(5);
+		content.createPosition(6);
+
+		content.remove(new ContentRange(1, 5));
+
+		assertEquals(2, content.getPositionCount());
+	}
+
+	@Test
 	public void testGapContent() throws Exception {
 		//
 		// a b (gap) c d
@@ -133,7 +150,7 @@
 		// a b x (gap) y c d
 		// | | | | | | |
 		// 0 1 2 3 4 5 6
-		// 
+		//
 		content.insertText(2, "y");
 		assertEquals(5, content.length());
 		content.insertText(2, "x");
@@ -156,8 +173,10 @@
 
 		assertEquals(0, pa.getOffset());
 		assertEquals(1, pb.getOffset());
-		assertEquals(2, px.getOffset());
-		assertEquals(2, py.getOffset());
+
+		assertFalse(px.isValid());
+		assertFalse(py.isValid());
+
 		assertEquals(2, pc.getOffset());
 		assertEquals(3, pd.getOffset());
 		assertEquals(4, pe.getOffset());
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java
index 3e54a96..9ed6173 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/VexWidgetTest.java
@@ -102,8 +102,7 @@
 		widget.setDocument(createDocument(STRUCTURE_NS, "chapter"), StyleSheet.NULL);
 		widget.insertElement(new QualifiedName(CONTENT_NS, "p"));
 		widget.insertText("1text before comment1");
-		widget.insertComment();
-		final INode comment = widget.getDocument().getChildAt(widget.getCaretOffset());
+		final INode comment = widget.insertComment();
 		widget.insertText("2comment text2");
 		widget.moveBy(1);
 		widget.insertText("3text after comment3");
@@ -112,13 +111,11 @@
 
 		widget.doWork(new Runnable() {
 			public void run() {
-				widget.moveTo(comment.getStartOffset() + 1, false);
-				widget.moveTo(comment.getEndOffset() - 1, true);
+				widget.selectContentOf(comment);
 				final IDocumentFragment fragment = widget.getSelectedFragment();
 				widget.deleteSelection();
 
-				widget.moveBy(-1, false);
-				widget.moveBy(1, true);
+				widget.select(comment);
 				widget.deleteSelection();
 
 				widget.insertFragment(fragment);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
index 00c7daf..159500e 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
@@ -4,7 +4,7 @@
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * 
+ *
  * Contributors:
  *     John Krasnay - initial API and implementation
  *     Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325)
@@ -37,7 +37,7 @@
 	private char[] content;
 	private int gapStart;
 	private int gapEnd;
-	private final SortedSet<GapContentPosition> positions = new TreeSet<GapContentPosition>();
+	private TreeSet<GapContentPosition> positions = new TreeSet<GapContentPosition>();
 
 	/**
 	 * Create a GapContent with the given initial capacity.
@@ -108,18 +108,21 @@
 		gapStart += text.length();
 
 		if (!atEnd) {
-
-			// Update positions
-			final GapContentPosition offsetPosition = new GapContentPosition(offset);
-			for (final GapContentPosition position : positions.tailSet(offsetPosition)) {
-				if (position.getOffset() >= offset) {
-					position.setOffset(position.getOffset() + text.length());
-				}
-			}
-
+			movePositions(offset, text.length());
 		}
 	}
 
+	private void movePositions(final int startOffset, final int delta) {
+		final TreeSet<GapContentPosition> newPositions = new TreeSet<GapContentPosition>();
+		for (final GapContentPosition position : positions) {
+			if (position.getOffset() >= startOffset) {
+				position.setOffset(position.getOffset() + delta);
+			}
+			newPositions.add(position);
+		}
+		positions = newPositions;
+	}
+
 	public void insertTagMarker(final int offset) {
 		assertOffset(offset, 0, length());
 
@@ -152,13 +155,18 @@
 		moveGap(range.getEndOffset() + 1);
 		gapStart -= range.length();
 
+		final TreeSet<GapContentPosition> newPositions = new TreeSet<GapContentPosition>();
 		for (final GapContentPosition position : positions) {
 			if (position.getOffset() > range.getEndOffset()) {
 				position.setOffset(position.getOffset() - range.length());
+				newPositions.add(position);
 			} else if (position.getOffset() >= range.getStartOffset()) {
-				position.setOffset(range.getStartOffset());
+				position.invalidate();
+			} else {
+				newPositions.add(position);
 			}
 		}
+		positions = newPositions;
 	}
 
 	public String getText() {
@@ -317,6 +325,10 @@
 			return useCount > 0;
 		};
 
+		public void invalidate() {
+			useCount = 0;
+		}
+
 		@Override
 		public int hashCode() {
 			final int prime = 31;