allow to insert a line break through a dedicated method in IDocument

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
index 6bad15a..b6df88c 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
@@ -350,6 +350,68 @@
 		return new String(characters);
 	}
 
+	@Override
+	public void insertLineBreak(final int offset) throws DocumentValidationException {
+		Assert.isTrue(offset > getStartOffset() && offset <= getEndOffset(), MessageFormat.format("Offset must be in [{0}, {1}]", getStartOffset() + 1, getEndOffset()));
+
+		final INode insertionNode = getNodeForInsertionAt(offset);
+		insertionNode.accept(new INodeVisitor() {
+			@Override
+			public void visit(final IDocument document) {
+				Assert.isTrue(false, "Cannot insert a line break directly into Document.");
+			}
+
+			@Override
+			public void visit(final IDocumentFragment fragment) {
+				Assert.isTrue(false, "DocumentFragment is never a child of Document.");
+			}
+
+			@Override
+			public void visit(final IElement element) {
+				if (!canInsertAt(element, offset, IValidator.PCDATA)) {
+					throw new DocumentValidationException(MessageFormat.format("Cannot insert a line break into a {0} element at offset {1}.", element.getLocalName(), offset));
+				}
+				insertLineBreak(offset, element);
+			}
+
+			@Override
+			public void visit(final IText text) {
+				insertLineBreak(offset, text.getParent());
+			}
+
+			@Override
+			public void visit(final IComment comment) {
+				insertLineBreak(offset, comment.getParent());
+			}
+
+			@Override
+			public void visit(final IProcessingInstruction pi) {
+				// The target is validated to ensure the instruction is valid after the insertion
+				final String charBefore = pi.getText(new ContentRange(offset - 1, offset - 1));
+				final String charAfter = pi.getText(new ContentRange(offset, offset));
+				final String candidate = charBefore + '\n' + charAfter; // TODO '\n' is an implementation detail that we should not have to rely on at this point!
+
+				final IValidationResult result = XML.validateProcessingInstructionData(candidate);
+				if (!result.isOK()) {
+					throw new DocumentValidationException(result.getMessage());
+				}
+
+				insertLineBreak(offset, pi.getParent());
+			}
+
+			private void insertLineBreak(final int offset, final IParent parent) {
+				fireBeforeContentInserted(new ContentChangeEvent(Document.this, parent, new ContentRange(offset, offset), true));
+				getContent().insertLineBreak(offset);
+				fireContentInserted(new ContentChangeEvent(Document.this, parent, new ContentRange(offset, offset), true));
+			}
+
+			@Override
+			public void visit(final IIncludeNode document) {
+				Assert.isTrue(false, "Cannot insert text into an Include.");
+			}
+		});
+	}
+
 	/**
 	 * Inserts a node at the given offset. There is no check that the insertion is valid.
 	 *
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMController.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMController.java
index 6835ebf..610deb7 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMController.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/DOMController.java
@@ -113,6 +113,11 @@
 		moveCursor(toOffset(cursor.getOffset() + 1));
 	}
 
+	public void insertLineBreak() {
+		document.insertLineBreak(cursor.getOffset());
+		moveCursor(toOffset(cursor.getOffset() + 1));
+	}
+
 	public void insertElement(final QualifiedName elementName) {
 		document.insertElement(cursor.getOffset(), elementName);
 		moveCursor(toOffset(cursor.getOffset() + 1));
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/BoxWidget.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/BoxWidget.java
index 233a724..1a650b0 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/BoxWidget.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/BoxWidget.java
@@ -191,6 +191,8 @@
 		case SWT.HOME:
 			moveOrSelect(event.stateMask, toOffset(0));
 			break;
+		case SWT.CR:
+			controller.insertLineBreak();
 		default:
 			if (event.character > 0 && Character.isDefined(event.character)) {
 				controller.enterChar(event.character);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java
index 376436a..6b72af5 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java
@@ -145,6 +145,8 @@
 	 */

 	void insertText(int offset, String text) throws DocumentValidationException;

 

+	void insertLineBreak(int offset) throws DocumentValidationException;

+

 	/**

 	 * @return true if a comment can be inserted a the given offset

 	 */