/* * (c) Copyright IBM Corp. 2000, 2001. * All Rights Reserved. */ package net.sourceforge.phpdt.internal.corext.textmanipulation; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import net.sourceforge.phpdt.internal.corext.textmanipulation.TextEditNode.RootNode; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; //import net.sourceforge.phpdt.core.IJavaModelStatusConstants; //import net.sourceforge.phpdt.core.JavaModelException; // //import net.sourceforge.phpdt.internal.corext.Assert; /** * A TextBufferEditor manages a set of TextEdits and applies * them as a whole to a TextBuffer. Added TextEdits must * not overlap. The only exception from this rule are insertion point. There can be more than * one insert point at the same text position. Clients should use the method * canPerformEdits to validate if all added text edits follow these rules. *

* Clients can attach more than one TextBufferEditor to a single * TextBuffer. If so canPerformEdits validates all text edits from * all text buffer editors working on the same text buffer. */ public class TextBufferEditor { private TextBuffer fBuffer; private List fEdits; private RootNode fRootNode; private int fNumberOfNodes; private int fConnectCount; private int fMode; /* package */ static final int UNDEFINED= 0; /* package */ static final int REDO= 1; /* package */ static final int UNDO= 2; /** * Creates a new TextBufferEditor for the given * TextBuffer. * * @param the text buffer this editor is working on. */ public TextBufferEditor(TextBuffer buffer) { fBuffer= buffer; // Assert.isNotNull(fBuffer); fEdits= new ArrayList(); } /** * Returns the text buffer this editor is working on. * * @return the text buffer this editor is working on */ public TextBuffer getTextBuffer() { return fBuffer; } /** * Adds a TextEdit to this text editor. Adding a TextEdit * to a TextBufferEditor transfers ownership of the edit to the editor. So * after a edit has been added to a editor the creator of that edit must not continue * modifing it. * * @param edit the text edit to be added * @exception CoreException if the text edit can not be added * to this text buffer editor */ public void add(TextEdit edit) throws CoreException { // Assert.isTrue(fMode == UNDEFINED || fMode == REDO); internalAdd(edit); fMode= REDO; } /** * Adds a MultiTextEdit to this text editor. Adding a MultiTextEdit * to a TextBufferEditor transfers ownership of the edit to the editor. So * after a edit has been added to a editor the creator of that edit must not continue * modifing it. * * @param edit the multi text edit to be added * @exception CoreException if the multi text edit can not be added * to this text buffer editor */ public void add(MultiTextEdit edit) throws CoreException { // Assert.isTrue(fMode == UNDEFINED || fMode == REDO); edit.connect(this); fMode= REDO; } /** * Adds a UndoMemento to this text editor. Adding a UndoMemento * to a TextBufferEditor transfers ownership of the memento to the editor. So * after a memento has been added to a editor the creator of that memento must not continue * modifing it. * * @param undo the undo memento to be added * @exception CoreException if the undo memento can not be added * to this text buffer editor */ public void add(UndoMemento undo) throws CoreException { // Assert.isTrue(fMode == UNDEFINED); List list= undo.fEdits; // Add them reverse since we are adding undos. for (int i= list.size() - 1; i >= 0; i--) { internalAdd((TextEdit)list.get(i)); } fMode= undo.fMode; } /** * Checks if the TextEdit added to this text editor can be executed. * * @return true if the edits can be executed. Return false * otherwise. One major reason why text edits cannot be executed * is a wrong offset or length value of a TextEdit. */ public boolean canPerformEdits() { if (fRootNode != null) return true; fRootNode= buildTree(); if (fRootNode == null) return false; if (fRootNode.validate(fBuffer.getLength())) return true; fRootNode= null; return false; } /** * Clears the text buffer editor. */ public void clear() { fRootNode= null; fMode= UNDEFINED; fEdits.clear(); } /** * Executes the text edits added to this text buffer editor and clears all added * text edits. * * @param pm a progress monitor to report progress or null if * no progress is desired. * @return an object representing the undo of the executed TextEdits * @exception CoreException if the edits cannot be executed */ public UndoMemento performEdits(IProgressMonitor pm) throws CoreException { if (pm == null) pm= new NullProgressMonitor(); int size= fEdits.size(); if (size == 0) return new UndoMemento(fMode == UNDO ? REDO : UNDO); if (fRootNode == null) { fRootNode= buildTree(); if (fRootNode == null || !fRootNode.validate(fBuffer.getLength())) { // throw new JavaModelException(null, IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS); } } try { pm.beginTask("", fNumberOfNodes + 10); //$NON-NLS-1$ UndoMemento undo= null; if (fMode == REDO) { undo= fRootNode.performDo(fBuffer, pm); fRootNode.performedDo(); } else { undo= fRootNode.performUndo(fBuffer, pm); fRootNode.performedUndo(); } pm.worked(10); return undo; } finally { pm.done(); clear(); } } //---- Helper methods ------------------------------------------------------------ private RootNode buildTree() { TextEditNode[] nodes= new TextEditNode[fEdits.size()]; for (int i= fEdits.size() - 1; i >= 0; i--) { nodes[i]= TextEditNode.create((TextEdit)fEdits.get(i)); } fNumberOfNodes= nodes.length; Arrays.sort(nodes, new TextEditNodeComparator()); RootNode root= new RootNode(fBuffer.getLength()); for (int i= 0; i < nodes.length; i++) { root.add(nodes[i]); } return root; } private void internalAdd(TextEdit edit) throws CoreException { edit.index= fEdits.size(); edit.isSynthetic= fConnectCount > 0; try { fConnectCount++; edit.connect(this); } finally { fConnectCount--; } fEdits.add(edit); } }