diff options
author | Kai Maetzel | 2003-09-17 13:07:41 +0000 |
---|---|---|
committer | Kai Maetzel | 2003-09-17 13:07:41 +0000 |
commit | 80f6ceec422cb0eb3e0e36e8733341c0ce22752d (patch) | |
tree | e00135fa3d3c4c7371f0dd3d24dc97b1e579a968 | |
parent | dc529584a725a395734649dd02c88075ec244525 (diff) | |
download | eclipse.platform.text-80f6ceec422cb0eb3e0e36e8733341c0ce22752d.tar.gz eclipse.platform.text-80f6ceec422cb0eb3e0e36e8733341c0ce22752d.tar.xz eclipse.platform.text-80f6ceec422cb0eb3e0e36e8733341c0ce22752d.zip |
updated edits
7 files changed, 248 insertions, 203 deletions
diff --git a/org.eclipse.text/src/org/eclipse/text/edits/Messages.properties b/org.eclipse.text/src/org/eclipse/text/edits/Messages.properties index 5438395c346..486880f2fbc 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/Messages.properties +++ b/org.eclipse.text/src/org/eclipse/text/edits/Messages.properties @@ -28,4 +28,6 @@ MoveTargetEdit.different_target= Source edit has different target edit. MoveTargetEdit.wrong_parent=Source edit must not be the parent of the target. TextEditProcessor.invalid_length=End position lies outside of document range -UndoMemento.invalid_length=End position lies outside of document range + +UndoEdit.no_children=Can\'t add children to an undo edit +UndoEdit.can_not_be_added=Can\'t add an undo edit to another edit diff --git a/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java index bf720bb15b3..f09faf456b7 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java @@ -58,21 +58,14 @@ public class MultiTextEdit extends TextEdit { fDefined= true; } - /** + /* * Copy constructor. */ - private MultiTextEdit(MultiTextEdit other) { + protected MultiTextEdit(MultiTextEdit other) { super(other); } /* non Java-doc - * @see TextEdit#perform - */ - /* package */ final void perform(IDocument document) { - // do nothing. - } - - /* non Java-doc * @see TextEdit#copy */ protected TextEdit doCopy() { @@ -80,16 +73,28 @@ public class MultiTextEdit extends TextEdit { return new MultiTextEdit(this); } + /* non Java-doc + * @see TextEdit#perform + */ + /* package */ final void perform(IDocument document) { + // do nothing. + } + /* package */ void aboutToBeAdded(TextEdit parent) { - if (!fDefined) { - if (hasChildren()) { - IRegion region= getCoverage(getChildren()); - internalSetOffset(region.getOffset()); - internalSetLength(region.getLength()); - } else { - internalSetOffset(parent.getOffset()); - internalSetLength(0); - } + defineRegion(parent.getOffset()); + } + + /* package */ void defineRegion(int parentOffset) { + if (fDefined) + return; + if (hasChildren()) { + IRegion region= getCoverage(getChildren()); + internalSetOffset(region.getOffset()); + internalSetLength(region.getLength()); + } else { + internalSetOffset(parentOffset); + internalSetLength(0); } - } + fDefined= true; + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java index 5cc91929b17..87f899d1e5a 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java @@ -102,6 +102,9 @@ public abstract class TextEdit { * the point in time when this call is made. Any subsequent changes * to the edit's offset and length aren't reflected in the returned * region object. + * <p> + * Creating a region for a deleted edit will result in an assertion + * failure. * * @return the manipulated region */ @@ -111,7 +114,8 @@ public abstract class TextEdit { /** * Returns the offset of the edit. An offset is a 0-based - * character index. + * character index. Returns <code>-1</code> if the edit + * is marked as deleted * * @return the offset of the edit */ @@ -120,7 +124,8 @@ public abstract class TextEdit { } /** - * Returns the length of the edit. + * Returns the length of the edit. Returns <code>-1</code> + * if the edit is marked as deleted. * * @return the length of the edit */ @@ -313,6 +318,17 @@ public abstract class TextEdit { } /** + * Returns the size of the managed children. + * + * @return the size of the children + */ + public final int getChildrenSize() { + if (fChildren == null) + return 0; + return fChildren.size(); + } + + /** * Returns the text range spawned by the given array of text edits. * The method requires that the given array contains at least one * edit. If all edits passed are deleted the method returns <code> @@ -457,26 +473,10 @@ public abstract class TextEdit { //---- Execution ------------------------------------------------------- /** - * Returns whether the edit tree can be applied to the - * given document or not. - * - * @return <code>true</code> if the edit tree can be - * applied to the given document. Otherwise <code>false - * </code> is returned. - */ - public boolean canBeApplied(IDocument document) { - try { - TextEditProcessor processor= new TextEditProcessor(document); - processor.add(this); - return processor.canPerformEdits(); - } finally { - // unconnect from text edit processor - fParent= null; - } - } - - /** - * Applies the edit tree rooted by this edit to the given document. + * Applies the edit tree rooted by this edit to the given document. To check + * if the edit tree can be applied to the document either catch <code> + * MalformedTreeException</code> or use <code>TextEditProcessor</code> to + * execute an edit tree. * * @param document the document to be manipulated * @exception MalformedTreeException is thrown if the tree isn't @@ -485,14 +485,14 @@ public abstract class TextEdit { * @exception BadLocationException is thrown if one of the edits * in the tree can't be executed. The state of the document is * undefined if this exception is thrown. + * * @see #checkIntegrity() * @see #perform(IDocument) + * @see TextEditProcessor#performEdits() */ - public final UndoMemento apply(IDocument document) throws MalformedTreeException, BadLocationException { + public final UndoEdit apply(IDocument document) throws MalformedTreeException, BadLocationException { try { - TextEditProcessor processor= new TextEditProcessor(document); - processor.add(this); - processor.checkIntegrity(); + TextEditProcessor processor= new TextEditProcessor(document, this); return processor.performEdits(); } finally { // unconnect from text edit processor @@ -529,6 +529,14 @@ public abstract class TextEdit { /* package */ abstract void perform(IDocument document) throws BadLocationException; + /* package */ UndoEdit dispatchPerformEdits(TextEditProcessor processor) throws BadLocationException { + return processor.executeDo(); + } + + /* package */ void dispatchCheckIntegrity(TextEditProcessor processor) throws MalformedTreeException { + processor.checkIntegrityDo(); + } + //---- internal state accessors ---------------------------------------------------------- /* package */ void internalSetParent(TextEdit parent) { @@ -697,7 +705,7 @@ public abstract class TextEdit { } } - private static int getDelta(DocumentEvent event) { + /* package */ static int getDelta(DocumentEvent event) { String text= event.getText(); return (text == null ? -event.getLength() : text.length()) - event.getLength(); } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java b/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java index c50cb2f9bc6..b6218a7c43d 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java @@ -30,18 +30,29 @@ import org.eclipse.jface.text.IDocument; public class TextEditProcessor { private IDocument fDocument; - private MultiTextEdit fRoot; + private TextEdit fRoot; + + private boolean fChecked; + private MalformedTreeException fException; /** * Constructs a new edit processor for the given * document. * * @param document the document to manipulate + * @param root the root of the text edit tree describing + * the modifications. By passing a text edit a a text edit + * processor the ownership of the edit is transfered to the + * text edit processors. Clients must not modify the edit + * (e.g adding new children) any longer. */ - public TextEditProcessor(IDocument document) { + public TextEditProcessor(IDocument document, TextEdit root) { Assert.isNotNull(document); + Assert.isNotNull(root); fDocument= document; - fRoot= new MultiTextEdit(0, fDocument.getLength()); + fRoot= root; + if (fRoot instanceof MultiTextEdit) + ((MultiTextEdit)fRoot).defineRegion(0); } /** @@ -63,23 +74,6 @@ public class TextEditProcessor { } /** - * Adds an <code>Edit</code> to this edit processor. Adding an edit - * to an edit processor transfers ownership of the edit to the - * processor. So after an edit has been added to a processor the - * creator of the edit <b>must</b> not continue modifying the edit. - * - * @param edit the edit to add - * @exception MalformedTreeException if the text edit can not be - * added to this edit processor. - * - * @see TextEdit#addChild(TextEdit) - */ - public void add(TextEdit edit) throws MalformedTreeException { - checkIntegrity(edit, fDocument); - fRoot.addChild(edit); - } - - /** * Checks if the processor can execute all its edits. * * @return <code>true</code> if the edits can be executed. Return <code>false @@ -88,7 +82,14 @@ public class TextEditProcessor { * likely end in a <code>BadLocationException</code>. */ public boolean canPerformEdits() { - return checkBufferLength(fRoot, fDocument.getLength()) == null; + try { + fRoot.dispatchCheckIntegrity(this); + fChecked= true; + } catch (MalformedTreeException e) { + fException= e; + return false; + } + return true; } /** @@ -102,8 +103,14 @@ public class TextEditProcessor { * tree can't be executed. The state of the document is undefined if this * exception is thrown. */ - public UndoMemento performEdits() throws MalformedTreeException, BadLocationException { - return execute(); + public UndoEdit performEdits() throws MalformedTreeException, BadLocationException { + if (!fChecked) { + fRoot.dispatchCheckIntegrity(this); + } else { + if (fException != null) + throw fException; + } + return fRoot.dispatchPerformEdits(this); } /* non Java-doc @@ -113,49 +120,41 @@ public class TextEditProcessor { return true; } - /* protected */ void checkIntegrity() throws MalformedTreeException { - TextEdit failure= checkBufferLength(fRoot, fDocument.getLength()); - if (failure != null) { - throw new MalformedTreeException(failure.getParent(), failure, TextEditMessages.getString("TextEditProcessor.invalid_length")); //$NON-NLS-1$ - } - } + //---- checking -------------------------------------------------------------------- - //---- Helper methods ------------------------------------------------------------------------ - - private static TextEdit checkBufferLength(TextEdit root, int bufferLength) { - if (root.getExclusiveEnd() > bufferLength) - return root; - List children= root.internalGetChildren(); - if (children != null) { - for (Iterator iter= children.iterator(); iter.hasNext();) { - TextEdit edit= (TextEdit)iter.next(); - TextEdit failure= null; - if ((failure= checkBufferLength(edit, bufferLength)) != null) - return failure; - } - } - return null; + /* package */ void checkIntegrityDo() throws MalformedTreeException { + checkIntegrity(fRoot); + if (fRoot.getExclusiveEnd() > fDocument.getLength()) + throw new MalformedTreeException(null, fRoot, TextEditMessages.getString("TextEditProcessor.invalid_length")); //$NON-NLS-1$ } - private static void checkIntegrity(TextEdit root, IDocument document) { + private static void checkIntegrity(TextEdit root) throws MalformedTreeException { root.checkIntegrity(); List children= root.internalGetChildren(); if (children != null) { for (Iterator iter= children.iterator(); iter.hasNext();) { TextEdit edit= (TextEdit)iter.next(); - checkIntegrity(edit, document); + checkIntegrity(edit); } } } - private UndoMemento execute() throws BadLocationException { + /* package */ void checkIntegrityUndo() { + if (fRoot.getExclusiveEnd() > fDocument.getLength()) + throw new MalformedTreeException(null, fRoot, TextEditMessages.getString("TextEditProcessor.invalid_length")); //$NON-NLS-1$ + } + + //---- execution -------------------------------------------------------------------- + + /* package */ UndoEdit executeDo() throws BadLocationException { Updater.DoUpdater updater= null; try { - updater= Updater.createDoUpdater(); + updater= Updater.createDoUpdater(fRoot); fDocument.addDocumentListener(updater); updater.push(new TextEdit[] { fRoot }); updater.setIndex(0); execute(fRoot, updater); + updater.storeRegion(); return updater.undo; } finally { if (updater != null) @@ -178,4 +177,21 @@ public class TextEditProcessor { edit.perform(fDocument); } } + + /* package */ UndoEdit executeUndo() throws BadLocationException { + Updater updater= null; + try { + updater= Updater.createUndoUpdater(fRoot); + fDocument.addDocumentListener(updater); + TextEdit[] edits= fRoot.getChildren(); + for (int i= edits.length - 1; i >= 0; i--) { + edits[i].perform(fDocument); + } + updater.storeRegion(); + return updater.undo; + } finally { + if (updater != null) + fDocument.removeDocumentListener(updater); + } + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java new file mode 100644 index 00000000000..ee5f0575648 --- /dev/null +++ b/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.text.edits; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; + +/** + * This class encapsulates the reverse changes of an executed text + * edit tree. To apply an undo memento to a document use method + * <code>apply(IDocument)</code>. + * <p> + * Clients can add additional children to an undo edit nor can they + * add an undo edit as a child to another edit. Doing so results in + * both cases in a <code>MalformedTreeException<code>. + * + * @since 3.0 + */ +public final class UndoEdit extends TextEdit { + + /* package */ UndoEdit() { + super(0, Integer.MAX_VALUE); + } + + private UndoEdit(UndoEdit other) { + super(other); + } + + /* (non-Javadoc) + * @see org.eclipse.text.edits.TextEdit#internalAdd(org.eclipse.text.edits.TextEdit) + */ + /* package */ void internalAdd(TextEdit child) throws MalformedTreeException { + throw new MalformedTreeException(null, this, TextEditMessages.getString("UndoEdit.no_children")); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.text.edits.MultiTextEdit#aboutToBeAdded(org.eclipse.text.edits.TextEdit) + */ + /* package */ void aboutToBeAdded(TextEdit parent) { + throw new MalformedTreeException(parent, this, TextEditMessages.getString("UndoEdit.can_not_be_added")); //$NON-NLS-1$ + } + + /* package */ UndoEdit dispatchPerformEdits(TextEditProcessor processor) throws BadLocationException { + return processor.executeUndo(); + } + + /* package */ void dispatchCheckIntegrity(TextEditProcessor processor) throws MalformedTreeException { + processor.checkIntegrityUndo(); + } + + /* (non-Javadoc) + * @see org.eclipse.text.edits.TextEdit#doCopy() + */ + protected TextEdit doCopy() { + return new UndoEdit(this); + } + + /* (non-Javadoc) + * @see org.eclipse.text.edits.TextEdit#perform(org.eclipse.jface.text.IDocument) + */ + void perform(IDocument document) throws BadLocationException { + // do nothing. Only the children modify the + // document + } + + /* package */ void add(ReplaceEdit edit) { + List children= internalGetChildren(); + if (children == null) { + children= new ArrayList(2); + internalSetChildren(children); + } + children.add(edit); + } + + /* package */ void defineRegion(int offset, int length) { + internalSetOffset(offset); + internalSetLength(length); + } +} + diff --git a/org.eclipse.text/src/org/eclipse/text/edits/UndoMemento.java b/org.eclipse.text/src/org/eclipse/text/edits/UndoMemento.java deleted file mode 100644 index d9de7b6db5e..00000000000 --- a/org.eclipse.text/src/org/eclipse/text/edits/UndoMemento.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.text.edits; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jface.text.Assert; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.IDocument; - -/** - * This class encapsulates the reverse changes of an executed text - * edit tree. To apply an undo memento to a document use method - * <code>apply(IDocument)</code>. - */ -public final class UndoMemento { - - private List fEdits; - - /** - * Returns whether this undo memento can be applied to the - * given document or not. - * - * @return <code>true</code> if the undo memento can be - * applied to the given document. Otherwise <code>false - * </code> is returned. - */ - public boolean canBeApplied(IDocument document) { - Assert.isNotNull(document); - return checkBufferLength(document.getLength()) != null; - } - - /** - * Applies this undo memento to the given document. - * - * @param document the document to be manipulated - * - * @exception MalformedTreeException is thrown if the undo isn't - * in a valid state. This exception is thrown before any edit - * is executed. So the document is still in its original state. - * @exception BadLocationException is thrown if one of the edits - * of the undo can't be executed. The state of the document is - * undefined if this exception is thrown. - * - * @see TextEdit#apply(IDocument) - */ - public UndoMemento apply(IDocument document) throws MalformedTreeException, BadLocationException { - Assert.isNotNull(document); - TextEdit failure= checkBufferLength(document.getLength()); - if (failure != null) - throw new MalformedTreeException(failure.getParent(), failure, TextEditMessages.getString("UndoMemento.invalid_length")); //$NON-NLS-1$ - return perform(document); - } - - /* package */ UndoMemento() { - fEdits= new ArrayList(5); - } - - /* package */ void add(ReplaceEdit edit) { - fEdits.add(edit); - } - - private TextEdit checkBufferLength(int bufferLength) { - for (int i= fEdits.size() - 1; i >= 0; i--) { - ReplaceEdit edit= (ReplaceEdit)fEdits.get(i); - if (edit.getExclusiveEnd() > bufferLength) - return edit; - bufferLength+= getDelta(edit); - } - return null; - } - - private UndoMemento perform(IDocument document) throws BadLocationException { - Updater updater= null; - try { - updater= Updater.createUndoUpdater(); - document.addDocumentListener(updater); - for (int i= fEdits.size() - 1; i >= 0; i--) { - ((TextEdit)fEdits.get(i)).perform(document); - } - return updater.undo; - } finally { - if (updater != null) - document.removeDocumentListener(updater); - } - } - - private int getDelta(ReplaceEdit edit) { - return edit.getText().length() - edit.getLength(); - } -} - diff --git a/org.eclipse.text/src/org/eclipse/text/edits/Updater.java b/org.eclipse.text/src/org/eclipse/text/edits/Updater.java index 2ad0ed80a3b..45887593d86 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/Updater.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/Updater.java @@ -16,22 +16,26 @@ import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocumentListener; -/* package */ class Updater implements IDocumentListener { +/* package */ abstract class Updater implements IDocumentListener { - protected UndoMemento undo= new UndoMemento(); + protected UndoEdit undo= new UndoEdit(); - public static Updater createUndoUpdater() { - return new Updater(); + public static Updater createUndoUpdater(TextEdit root) { + return new UndoUpdater(root); } - public static DoUpdater createDoUpdater() { - return new DoUpdater(); + public static DoUpdater createDoUpdater(TextEdit root) { + return new DoUpdater(root); } public static class DoUpdater extends Updater { + private TextEdit fRoot; private TextEdit fActiveEdit; private TreeIterationInfo fIterationInfo= new TreeIterationInfo(); + public DoUpdater(TextEdit root) { + fRoot= root; + } public void push(TextEdit[] edits) { fIterationInfo.push(edits); } @@ -47,6 +51,24 @@ import org.eclipse.jface.text.IDocumentListener; public void documentChanged(DocumentEvent event) { fActiveEdit.update(event, fIterationInfo); } + public void storeRegion() { + undo.defineRegion(fRoot.getOffset(), fRoot.getLength()); + } + } + + public static class UndoUpdater extends Updater { + private int fOffset; + private int fLength; + private UndoUpdater(TextEdit root) { + fOffset= root.getOffset(); + fLength= root.getLength(); + } + public void documentChanged(DocumentEvent event) { + fLength+= TextEdit.getDelta(event); + } + public void storeRegion() { + undo.defineRegion(fOffset, fLength); + } } protected Updater() { @@ -66,5 +88,7 @@ import org.eclipse.jface.text.IDocumentListener; } public void documentChanged(DocumentEvent event) { - } + } + + public abstract void storeRegion(); } |