2 * (c) Copyright IBM Corp. 2000, 2001.
5 package net.sourceforge.phpdt.internal.corext.textmanipulation;
7 import java.util.ArrayList;
8 import java.util.Arrays;
11 import net.sourceforge.phpdt.internal.corext.textmanipulation.TextEditNode.RootNode;
13 import org.eclipse.core.runtime.CoreException;
14 import org.eclipse.core.runtime.IProgressMonitor;
15 import org.eclipse.core.runtime.NullProgressMonitor;
17 // import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
18 // import net.sourceforge.phpdt.core.JavaModelException;
20 // import net.sourceforge.phpdt.internal.corext.Assert;
23 * A <code>TextBufferEditor</code> manages a set of <code>TextEdit</code>s
24 * and applies them as a whole to a <code>TextBuffer</code>. Added
25 * <code>TextEdit</code>s must not overlap. The only exception from this rule
26 * are insertion point. There can be more than one insert point at the same text
27 * position. Clients should use the method <code>
28 * canPerformEdits</code> to
29 * validate if all added text edits follow these rules.
31 * Clients can attach more than one <code>TextBufferEditor</code> to a single
33 * TextBuffer</code>. If so <code>canPerformEdits</code> validates
34 * all text edits from all text buffer editors working on the same text buffer.
36 public class TextBufferEditor {
38 private TextBuffer fBuffer;
42 private RootNode fRootNode;
44 private int fNumberOfNodes;
46 private int fConnectCount;
50 /* package */static final int UNDEFINED = 0;
52 /* package */static final int REDO = 1;
54 /* package */static final int UNDO = 2;
57 * Creates a new <code>TextBufferEditor</code> for the given
58 * <code>TextBuffer</code>.
61 * text buffer this editor is working on.
63 public TextBufferEditor(TextBuffer buffer) {
65 // Assert.isNotNull(fBuffer);
66 fEdits = new ArrayList();
70 * Returns the text buffer this editor is working on.
72 * @return the text buffer this editor is working on
74 public TextBuffer getTextBuffer() {
79 * Adds a <code>TextEdit</code> to this text editor. Adding a
80 * <code>TextEdit</code> to a <code>TextBufferEditor</code> transfers
81 * ownership of the edit to the editor. So after a edit has been added to a
82 * editor the creator of that edit <b>must</b> not continue modifing it.
85 * the text edit to be added
86 * @exception CoreException
87 * if the text edit can not be added to this text buffer
90 public void add(TextEdit edit) throws CoreException {
91 // Assert.isTrue(fMode == UNDEFINED || fMode == REDO);
97 * Adds a <code>MultiTextEdit</code> to this text editor. Adding a
98 * <code>MultiTextEdit</code> to a <code>TextBufferEditor</code>
99 * transfers ownership of the edit to the editor. So after a edit has been
100 * added to a editor the creator of that edit <b>must</b> not continue
104 * the multi text edit to be added
105 * @exception CoreException
106 * if the multi text edit can not be added to this text
109 public void add(MultiTextEdit edit) throws CoreException {
110 // Assert.isTrue(fMode == UNDEFINED || fMode == REDO);
116 * Adds a <code>UndoMemento</code> to this text editor. Adding a
117 * <code>UndoMemento</code> to a <code>TextBufferEditor</code> transfers
118 * ownership of the memento to the editor. So after a memento has been added
119 * to a editor the creator of that memento <b>must</b> not continue
123 * the undo memento to be added
124 * @exception CoreException
125 * if the undo memento can not be added to this text buffer
128 public void add(UndoMemento undo) throws CoreException {
129 // Assert.isTrue(fMode == UNDEFINED);
130 List list = undo.fEdits;
131 // Add them reverse since we are adding undos.
132 for (int i = list.size() - 1; i >= 0; i--) {
133 internalAdd((TextEdit) list.get(i));
139 * Checks if the <code>TextEdit</code> added to this text editor can be
142 * @return <code>true</code> if the edits can be executed. Return
144 * </code>otherwise. One major reason why text edits
145 * cannot be executed is a wrong offset or length value of a
146 * <code>TextEdit</code>.
148 public boolean canPerformEdits() {
149 if (fRootNode != null)
151 fRootNode = buildTree();
152 if (fRootNode == null)
154 if (fRootNode.validate(fBuffer.getLength()))
162 * Clears the text buffer editor.
164 public void clear() {
171 * Executes the text edits added to this text buffer editor and clears all
175 * a progress monitor to report progress or <code>null</code>
176 * if no progress is desired.
177 * @return an object representing the undo of the executed
178 * <code>TextEdit</code>s
179 * @exception CoreException
180 * if the edits cannot be executed
182 public UndoMemento performEdits(IProgressMonitor pm) throws CoreException {
184 pm = new NullProgressMonitor();
186 int size = fEdits.size();
188 return new UndoMemento(fMode == UNDO ? REDO : UNDO);
190 if (fRootNode == null) {
191 fRootNode = buildTree();
192 if (fRootNode == null || !fRootNode.validate(fBuffer.getLength())) {
193 // throw new JavaModelException(null,
194 // IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
198 pm.beginTask("", fNumberOfNodes + 10); //$NON-NLS-1$
199 UndoMemento undo = null;
201 undo = fRootNode.performDo(fBuffer, pm);
202 fRootNode.performedDo();
204 undo = fRootNode.performUndo(fBuffer, pm);
205 fRootNode.performedUndo();
215 // ---- Helper methods
216 // ------------------------------------------------------------
218 private RootNode buildTree() {
219 TextEditNode[] nodes = new TextEditNode[fEdits.size()];
220 for (int i = fEdits.size() - 1; i >= 0; i--) {
221 nodes[i] = TextEditNode.create((TextEdit) fEdits.get(i));
223 fNumberOfNodes = nodes.length;
224 Arrays.sort(nodes, new TextEditNodeComparator());
225 RootNode root = new RootNode(fBuffer.getLength());
226 for (int i = 0; i < nodes.length; i++) {
232 private void internalAdd(TextEdit edit) throws CoreException {
233 edit.index = fEdits.size();
234 edit.isSynthetic = fConnectCount > 0;