001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.text.edits;
011:
012: import java.util.List;
013:
014: import org.eclipse.core.runtime.Assert;
015:
016: import org.eclipse.jface.text.BadLocationException;
017: import org.eclipse.jface.text.IDocument;
018: import org.eclipse.jface.text.IRegion;
019:
020: /**
021: * A multi-text edit can be used to aggregate several edits into
022: * one edit. The edit itself doesn't modify a document.
023: * <p>
024: * Clients are allowed to implement subclasses of a multi-text
025: * edit.Subclasses must implement <code>doCopy()</code> to ensure
026: * the a copy of the right type is created. Not implementing
027: * <code>doCopy()</code> in subclasses will result in an assertion
028: * failure during copying.
029: *
030: * @since 3.0
031: */
032: public class MultiTextEdit extends TextEdit {
033:
034: private boolean fDefined;
035:
036: /**
037: * Creates a new <code>MultiTextEdit</code>. The range
038: * of the edit is determined by the range of its children.
039: *
040: * Adding this edit to a parent edit sets its range to the
041: * range covered by its children. If the edit doesn't have
042: * any children its offset is set to the parent's offset
043: * and its length is set to 0.
044: */
045: public MultiTextEdit() {
046: super (0, Integer.MAX_VALUE);
047: fDefined = false;
048: }
049:
050: /**
051: * Creates a new </code>MultiTextEdit</code> for the given
052: * range. Adding a child to this edit which isn't covered
053: * by the given range will result in an exception.
054: *
055: * @param offset the edit's offset
056: * @param length the edit's length.
057: * @see TextEdit#addChild(TextEdit)
058: * @see TextEdit#addChildren(TextEdit[])
059: */
060: public MultiTextEdit(int offset, int length) {
061: super (offset, length);
062: fDefined = true;
063: }
064:
065: /*
066: * Copy constructor.
067: */
068: protected MultiTextEdit(MultiTextEdit other) {
069: super (other);
070: }
071:
072: /**
073: * Checks the edit's integrity.
074: * <p>
075: * Note that this method <b>should only be called</b> by the edit
076: * framework and not by normal clients.</p>
077: *<p>
078: * This default implementation does nothing. Subclasses may override
079: * if needed.</p>
080: *
081: * @exception MalformedTreeException if the edit isn't in a valid state
082: * and can therefore not be executed
083: */
084: protected void checkIntegrity() throws MalformedTreeException {
085: // does nothing
086: }
087:
088: /**
089: * {@inheritDoc}
090: */
091: final boolean isDefined() {
092: if (fDefined)
093: return true;
094: return hasChildren();
095: }
096:
097: /**
098: * {@inheritDoc}
099: */
100: public final int getOffset() {
101: if (fDefined)
102: return super .getOffset();
103:
104: List/*<TextEdit>*/children = internalGetChildren();
105: if (children == null || children.size() == 0)
106: return 0;
107: // the children are already sorted
108: return ((TextEdit) children.get(0)).getOffset();
109: }
110:
111: /**
112: * {@inheritDoc}
113: */
114: public final int getLength() {
115: if (fDefined)
116: return super .getLength();
117:
118: List/*<TextEdit>*/children = internalGetChildren();
119: if (children == null || children.size() == 0)
120: return 0;
121: // the children are already sorted
122: TextEdit first = (TextEdit) children.get(0);
123: TextEdit last = (TextEdit) children.get(children.size() - 1);
124: return last.getOffset() - first.getOffset() + last.getLength();
125: }
126:
127: /**
128: * {@inheritDoc}
129: */
130: public final boolean covers(TextEdit other) {
131: if (fDefined)
132: return super .covers(other);
133: // an undefined multiple text edit covers everything
134: return true;
135: }
136:
137: /*
138: * @see org.eclipse.text.edits.TextEdit#canZeroLengthCover()
139: */
140: protected boolean canZeroLengthCover() {
141: return true;
142: }
143:
144: /*
145: * @see TextEdit#copy
146: */
147: protected TextEdit doCopy() {
148: Assert.isTrue(MultiTextEdit.class == getClass(),
149: "Subclasses must reimplement copy0"); //$NON-NLS-1$
150: return new MultiTextEdit(this );
151: }
152:
153: /*
154: * @see TextEdit#accept0
155: */
156: protected void accept0(TextEditVisitor visitor) {
157: boolean visitChildren = visitor.visit(this );
158: if (visitChildren) {
159: acceptChildren(visitor);
160: }
161: }
162:
163: /*
164: * @see org.eclipse.text.edits.TextEdit#adjustOffset(int)
165: * @since 3.1
166: */
167: void adjustOffset(int delta) {
168: if (fDefined)
169: super .adjustOffset(delta);
170: }
171:
172: /*
173: * @see org.eclipse.text.edits.TextEdit#adjustLength(int)
174: * @since 3.1
175: */
176: void adjustLength(int delta) {
177: if (fDefined)
178: super .adjustLength(delta);
179: }
180:
181: /*
182: * @see TextEdit#performConsistencyCheck
183: */
184: void performConsistencyCheck(TextEditProcessor processor,
185: IDocument document) throws MalformedTreeException {
186: checkIntegrity();
187: }
188:
189: /*
190: * @see TextEdit#performDocumentUpdating
191: */
192: int performDocumentUpdating(IDocument document)
193: throws BadLocationException {
194: fDelta = 0;
195: return fDelta;
196: }
197:
198: /*
199: * @see TextEdit#deleteChildren
200: */
201: boolean deleteChildren() {
202: return false;
203: }
204:
205: void aboutToBeAdded(TextEdit parent) {
206: defineRegion(parent.getOffset());
207: }
208:
209: void defineRegion(int parentOffset) {
210: if (fDefined)
211: return;
212: if (hasChildren()) {
213: IRegion region = getCoverage(getChildren());
214: internalSetOffset(region.getOffset());
215: internalSetLength(region.getLength());
216: } else {
217: internalSetOffset(parentOffset);
218: internalSetLength(0);
219: }
220: fDefined = true;
221: }
222:
223: /*
224: * @see org.eclipse.text.edits.TextEdit#internalToString(java.lang.StringBuffer, int)
225: * @since 3.3
226: */
227: void internalToString(StringBuffer buffer, int indent) {
228: super .internalToString(buffer, indent);
229: if (!fDefined)
230: buffer.append(" [undefined]"); //$NON-NLS-1$
231: }
232: }
|