track clean/dirty state in EditStack and IDocumentEditor

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/EditStack.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/EditStack.java
index cdb9143..b373f1e 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/EditStack.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/undo/EditStack.java
@@ -22,6 +22,8 @@
 
 	private final LinkedList<CompoundEdit> pendingEdits = new LinkedList<CompoundEdit>();
 
+	private IUndoableEdit cleanMarker = null;
+
 	public <T extends IUndoableEdit> T apply(final T edit) throws CannotApplyException {
 		edit.redo();
 
@@ -96,4 +98,12 @@
 	public boolean inTransaction() {
 		return !pendingEdits.isEmpty();
 	}
+
+	public boolean isDirty() {
+		return doneEdits.peek() != cleanMarker;
+	}
+
+	public void markClean() {
+		cleanMarker = doneEdits.peek();
+	}
 }
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/BaseVexWidget.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/BaseVexWidget.java
index c6450d7..49a0ff6 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/BaseVexWidget.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/BaseVexWidget.java
@@ -1901,6 +1901,16 @@
 	}
 
 	@Override
+	public boolean isDirty() {
+		return false;
+	}
+
+	@Override
+	public void markClean() {
+		// ignore
+	}
+
+	@Override
 	public ContentPosition viewToModel(final int x, final int y) {
 		final Graphics g = hostComponent.createDefaultGraphics();
 		final LayoutContext context = createLayoutContext(g);
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 a277380..d070683 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
@@ -186,6 +186,14 @@
 		return result;
 	}
 
+	public boolean isDirty() {
+		return editStack.isDirty();
+	}
+
+	public void markClean() {
+		editStack.markClean();
+	}
+
 	/*
 	 * Transaction Handling
 	 */
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 b95590a..2525d89 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
@@ -96,6 +96,10 @@
 	 */
 	void undo() throws CannotUndoException;
 
+	boolean isDirty();
+
+	void markClean();
+
 	/*
 	 * Transaction Handling
 	 */
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 5960c57..5d57144 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
@@ -380,6 +380,14 @@
 		editor.undo();
 	}
 
+	public boolean isDirty() {
+		return editor.isDirty();
+	}
+
+	public void markClean() {
+		editor.markClean();
+	}
+
 	public void doWork(final Runnable runnable) throws CannotApplyException {
 		editor.doWork(runnable);
 	}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/VexWidget.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/VexWidget.java
index 41c6e59..e251613 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/VexWidget.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/widget/swt/VexWidget.java
@@ -612,6 +612,16 @@
 	}
 
 	@Override
+	public boolean isDirty() {
+		return impl.isDirty();
+	}
+
+	@Override
+	public void markClean() {
+		impl.markClean();
+	}
+
+	@Override
 	public ContentPosition viewToModel(final int x, final int y) {
 		return impl.viewToModel(x, y);
 	}