test and fix the editing editing functionality
Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/FakeCursor.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/FakeCursor.java
index 9060e9f..e1f574d 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/FakeCursor.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/FakeCursor.java
@@ -16,37 +16,43 @@
private final LinkedList<ICursorPositionListener> cursorPositionListeners = new LinkedList<ICursorPositionListener>();
private final Graphics graphics = new FakeGraphics();
private final ContentTopology contentTopology;
+ private final BalancingSelector selector;
- private int offset;
- private boolean hasSelection;
- private int selectionStartOffset;
- private int selectionEndOffset;
+ private IDocument document;
public FakeCursor(final IDocument document) {
+ this.document = document;
contentTopology = new ContentTopology() {
@Override
public int getLastOffset() {
- return document.getEndOffset();
+ return FakeCursor.this.document.getEndOffset();
}
};
+ selector = new BalancingSelector();
+ selector.setDocument(document);
+ }
+
+ public void setDocument(final IDocument document) {
+ this.document = document;
+ selector.setDocument(document);
}
@Override
public int getOffset() {
- return offset;
+ return selector.getCaretOffset();
}
@Override
public boolean hasSelection() {
- return hasSelection;
+ return selector.isActive();
}
@Override
public ContentRange getSelectedRange() {
- if (hasSelection) {
- return new ContentRange(selectionStartOffset, selectionEndOffset);
+ if (selector.isActive()) {
+ return selector.getRange();
} else {
- return new ContentRange(offset, offset);
+ return new ContentRange(selector.getCaretOffset(), selector.getCaretOffset());
}
}
@@ -75,21 +81,20 @@
@Override
public void move(final ICursorMove move) {
firePositionAboutToChange();
- offset = move.calculateNewOffset(graphics, contentTopology, offset, null, null, 0);
- hasSelection = false;
- firePositionChanged(offset);
+ selector.setMark(move.calculateNewOffset(graphics, contentTopology, selector.getCaretOffset(), null, null, 0));
+ firePositionChanged(selector.getCaretOffset());
}
@Override
public void select(final ICursorMove move) {
firePositionAboutToChange();
- if (!hasSelection) {
- selectionStartOffset = offset;
+ final int newOffset = move.calculateNewOffset(graphics, contentTopology, selector.getCaretOffset(), null, null, 0);
+ if (move.isAbsolute()) {
+ selector.setEndAbsoluteTo(newOffset);
+ } else {
+ selector.moveEndTo(newOffset);
}
- offset = move.calculateNewOffset(graphics, contentTopology, offset, null, null, 0);
- hasSelection = true;
- selectionEndOffset = offset;
- firePositionChanged(offset);
+ firePositionChanged(selector.getCaretOffset());
}
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java
index 7cb6e51..cb7f1d2 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SelectionTest.java
@@ -44,7 +44,7 @@
editor.selectContentOf(title);
- assertEquals(title.getRange().resizeBy(1, -1), editor.getSelectedRange());
+ assertEquals(title.getRange().resizeBy(1, 0), editor.getSelectedRange());
assertTrue(editor.hasSelection());
}
@@ -65,7 +65,7 @@
editor.select(title);
- assertEquals(title.getRange(), editor.getSelectedRange());
+ assertEquals(title.getRange().resizeBy(0, 1), editor.getSelectedRange());
assertTrue(editor.hasSelection());
}
}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SimpleEditingTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SimpleEditingTest.java
index ff20a75..008c29c 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SimpleEditingTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/widget/L2SimpleEditingTest.java
@@ -35,6 +35,7 @@
import org.eclipse.vex.core.internal.undo.CannotApplyException;
import org.eclipse.vex.core.provisional.dom.DocumentValidationException;
import org.eclipse.vex.core.provisional.dom.IComment;
+import org.eclipse.vex.core.provisional.dom.IDocument;
import org.eclipse.vex.core.provisional.dom.IDocumentFragment;
import org.eclipse.vex.core.provisional.dom.IElement;
import org.eclipse.vex.core.provisional.dom.INode;
@@ -49,15 +50,22 @@
*/
public class L2SimpleEditingTest {
+ private FakeCursor cursor;
private IDocumentEditor editor;
private IElement rootElement;
@Before
public void setUp() throws Exception {
- editor = new BaseVexWidget(new MockHostComponent());
- editor.setDocument(createDocumentWithDTD(TEST_DTD, "section"));
- // TODO move dependency to whitespace policy into a BaseVexWidget specific set-up method
- ((BaseVexWidget) editor).setWhitespacePolicy(new CssWhitespacePolicy(readTestStyleSheet()));
+ final IDocument document = createDocumentWithDTD(TEST_DTD, "section");
+ cursor = new FakeCursor(document);
+ editor = new DocumentEditor(cursor, new CssWhitespacePolicy(readTestStyleSheet()));
+ editor.setDocument(document);
+ rootElement = editor.getDocument().getRootElement();
+ }
+
+ private void useDocument(final IDocument document) {
+ cursor.setDocument(document);
+ editor.setDocument(document);
rootElement = editor.getDocument().getRootElement();
}
@@ -77,7 +85,7 @@
public void shouldProvideInsertionElementAsCurrentElement() throws Exception {
final IElement titleElement = editor.insertElement(TITLE);
editor.moveBy(-1);
- assertEquals(titleElement.getStartPosition(), editor.getCaretPosition());
+ assertEquals(titleElement.getStartPosition().getOffset(), editor.getCaretPosition().getOffset());
assertSame(rootElement, editor.getCurrentElement());
}
@@ -874,8 +882,7 @@
@Test
public void givenMultipleElementsOfSameKindSelected_whenStructureAfterJoinWouldBeInvalid_cannotJoin() throws Exception {
- editor.setDocument(createDocumentWithDTD(TEST_DTD, "one-kind-of-child"));
- rootElement = editor.getDocument().getRootElement();
+ useDocument(createDocumentWithDTD(TEST_DTD, "one-kind-of-child"));
final IElement firstSection = editor.insertElement(SECTION);
editor.insertElement(TITLE);
@@ -894,8 +901,7 @@
@Test(expected = CannotApplyException.class)
public void givenMultipleElementsOfSameKindSelected_whenStructureAfterJoinWouldBeInvalid_shouldJoin() throws Exception {
- editor.setDocument(createDocumentWithDTD(TEST_DTD, "one-kind-of-child"));
- rootElement = editor.getDocument().getRootElement();
+ useDocument(createDocumentWithDTD(TEST_DTD, "one-kind-of-child"));
final IElement firstSection = editor.insertElement(SECTION);
editor.insertElement(TITLE);
@@ -1093,7 +1099,7 @@
editor.insertText("Hello World");
editor.moveTo(title.getStartPosition().moveBy(1));
editor.moveBy(5, true);
- final int expectedCaretPosition = editor.getSelectedRange().getEndOffset() + 1;
+ final int expectedCaretPosition = editor.getSelectedRange().getEndOffset();
editor.deleteSelection();
editor.undo();
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 84ffc04..dfc23f6 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
@@ -77,7 +77,7 @@
@Override
public void removePosition(final IPosition position) {
- if (positions.contains(position)) {
+ if (position.isValid() && positions.contains(position)) {
/*
* This cast is save: if the position can be removed, this instance must have created it, hence it is a
* GapContentPosition.
@@ -505,4 +505,9 @@
}
}
+ @Override
+ public String toString() {
+ return getRawText();
+ }
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DocumentEditor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DocumentEditor.java
index c6c83f2..9850e2e 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DocumentEditor.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DocumentEditor.java
@@ -176,25 +176,29 @@
*/
@Override
- public void doWork(final Runnable runnable) throws DocumentValidationException {
+ public void doWork(final Runnable runnable) throws CannotApplyException {
doWork(runnable, false);
}
@Override
- public void doWork(final Runnable runnable, final boolean savePosition) throws DocumentValidationException {
+ public void doWork(final Runnable runnable, final boolean savePosition) throws CannotApplyException {
final IPosition position = document.createPosition(cursor.getOffset());
editStack.beginWork();
try {
runnable.run();
final IUndoableEdit work = editStack.commitWork();
cursor.move(toOffset(work.getOffsetAfter()));
- } catch (final DocumentValidationException e) {
+ } catch (final CannotApplyException e) {
final IUndoableEdit work = editStack.rollbackWork();
- cursor.move(toOffset(work.getOffsetBefore()));
+ if (work.getOffsetBefore() > 0) {
+ cursor.move(toOffset(work.getOffsetBefore()));
+ }
throw e;
} catch (final Throwable t) {
final IUndoableEdit work = editStack.rollbackWork();
- cursor.move(toOffset(work.getOffsetBefore()));
+ if (work.getOffsetBefore() > 0) {
+ cursor.move(toOffset(work.getOffsetBefore()));
+ }
// TODO throw exception? at least log error?
} finally {
if (savePosition) {
@@ -335,8 +339,8 @@
@Override
public void selectAll() {
- cursor.move(toOffset(document.getStartOffset()));
- cursor.select(toOffset(document.getEndOffset()));
+ cursor.move(toOffset(document.getStartOffset() + 1));
+ cursor.select(toOffset(document.getEndOffset() - 1));
}
@Override
@@ -351,7 +355,7 @@
cursor.move(toOffset(node.getEndOffset()));
} else {
cursor.move(toOffset(node.getStartOffset() + 1));
- cursor.select(toOffset(node.getEndOffset() - 1));
+ cursor.select(toOffset(node.getEndOffset()));
}
}
@@ -369,7 +373,7 @@
if (!hasSelection()) {
return false;
}
- return document.canDelete(getSelectedRange());
+ return document.canDelete(getSelectedRange().resizeBy(0, -1));
}
@Override
@@ -381,7 +385,7 @@
return;
}
- apply(new DeleteEdit(document, getSelectedRange(), cursor.getOffset()));
+ apply(new DeleteEdit(document, getSelectedRange().resizeBy(0, -1), cursor.getOffset()));
}
/*
@@ -688,7 +692,7 @@
@Override
public void deleteBackward() throws DocumentValidationException {
- if (readOnly) {
+ if (isReadOnly()) {
throw new ReadOnlyException("Cannot delete, because the editor is read-only.");
}
@@ -706,7 +710,7 @@
final ContentRange range = document.getNodeForInsertionAt(offset).getRange();
edit = new DeleteEdit(document, range, offset);
} else if (document.getNodeForInsertionAt(offset - 1).isEmpty()) {
- final ContentRange range = document.getNodeForInsertionAt(offset + 1).getRange();
+ final ContentRange range = document.getNodeForInsertionAt(offset - 1).getRange();
edit = new DeleteEdit(document, range, offset);
} else if (!document.isTagAt(offset - 1)) {
edit = new DeletePreviousCharEdit(document, offset);
@@ -1171,7 +1175,12 @@
}
final ContentRange elementRange = currentElement.getRange();
- final IDocumentFragment elementContent = document.getFragment(elementRange.resizeBy(1, -1));
+ final IDocumentFragment elementContent;
+ if (currentElement.isEmpty()) {
+ elementContent = null;
+ } else {
+ elementContent = document.getFragment(elementRange.resizeBy(1, -1));
+ }
doWork(new Runnable() {
@Override
@@ -1216,7 +1225,12 @@
}
final ContentRange elementRange = currentElement.getRange();
- final IDocumentFragment elementContent = document.getFragment(elementRange.resizeBy(1, -1));
+ final IDocumentFragment elementContent;
+ if (currentElement.isEmpty()) {
+ elementContent = null;
+ } else {
+ elementContent = document.getFragment(elementRange.resizeBy(1, -1));
+ }
doWork(new Runnable() {
@Override
@@ -1239,8 +1253,9 @@
return false;
}
- final IElement parent = document.getElementForInsertionAt(cursor.getOffset());
- final IAxis<? extends INode> selectedNodes = parent.children().in(getSelectedRange());
+ final ContentRange selectedRange = getSelectedRange();
+ final IElement parent = document.getElementForInsertionAt(selectedRange.getStartOffset());
+ final IAxis<? extends INode> selectedNodes = parent.children().in(selectedRange);
if (selectedNodes.isEmpty()) {
return false;
}
@@ -1288,8 +1303,8 @@
return;
}
- final IElement parent = document.getElementForInsertionAt(cursor.getOffset());
final ContentRange selectedRange = getSelectedRange();
+ final IElement parent = document.getElementForInsertionAt(selectedRange.getStartOffset());
final IAxis<? extends INode> selectedNodes = parent.children().in(selectedRange);
if (selectedNodes.isEmpty()) {
return;
@@ -1313,8 +1328,11 @@
doWork(new Runnable() {
@Override
public void run() {
- final DeleteEdit deletePreservedContent = editStack.apply(new DeleteEdit(document, new ContentRange(firstNode.getEndOffset() + 1, selectedRange.getEndOffset()), cursor.getOffset()));
- editStack.apply(new DeleteEdit(document, firstNode.getRange().resizeBy(1, -1), deletePreservedContent.getOffsetAfter()));
+ final DeleteEdit deletePreservedContent = editStack
+ .apply(new DeleteEdit(document, new ContentRange(firstNode.getEndOffset() + 1, selectedRange.getEndOffset() - 1), cursor.getOffset()));
+ if (!firstNode.isEmpty()) {
+ editStack.apply(new DeleteEdit(document, firstNode.getRange().resizeBy(1, -1), deletePreservedContent.getOffsetAfter()));
+ }
for (final IDocumentFragment contentPart : contentToJoin) {
editStack.apply(new InsertFragmentEdit(document, firstNode.getEndOffset(), contentPart));
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IDocumentEditor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IDocumentEditor.java
index 0c21da1..e2a3eaa 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IDocumentEditor.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/IDocumentEditor.java
@@ -99,7 +99,7 @@
* @param runnable
* Runnable implementing the work to be done.
*/
- void doWork(Runnable runnable) throws DocumentValidationException;
+ void doWork(Runnable runnable) throws CannotApplyException;
/**
* Perform the runnable's run method within a transaction. All operations in the runnable are treated as a single
@@ -111,7 +111,7 @@
* @param savePosition
* If true, the current caret position is saved and restored once the operation is complete.
*/
- void doWork(Runnable runnable, boolean savePosition) throws DocumentValidationException;
+ void doWork(Runnable runnable, boolean savePosition) throws CannotApplyException;
/**
* Execute a Runnable, restoring the caret position to its original position afterward.