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.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.jface.text.BadLocationException;
016: import org.eclipse.jface.text.IDocument;
017:
018: /**
019: * A move target edit denotes the target of a move operation. Move
020: * target edits are only valid inside an edit tree if they have a
021: * corresponding source edit. Furthermore a target edit can't
022: * can't be a direct or indirect child of its associated source edit.
023: * Violating one of two requirements will result in a <code>
024: * MalformedTreeException</code> when executing the edit tree.
025: * <p>
026: * Move target edits can't be used as a parent for other edits.
027: * Trying to add an edit to a move target edit results in a <code>
028: * MalformedTreeException</code> as well.
029: *
030: * @see org.eclipse.text.edits.MoveSourceEdit
031: * @see org.eclipse.text.edits.CopyTargetEdit
032: *
033: * @since 3.0
034: */
035: public final class MoveTargetEdit extends TextEdit {
036:
037: private MoveSourceEdit fSource;
038:
039: /**
040: * Constructs a new move target edit
041: *
042: * @param offset the edit's offset
043: */
044: public MoveTargetEdit(int offset) {
045: super (offset, 0);
046: }
047:
048: /**
049: * Constructs an new move target edit
050: *
051: * @param offset the edit's offset
052: * @param source the corresponding source edit
053: */
054: public MoveTargetEdit(int offset, MoveSourceEdit source) {
055: this (offset);
056: setSourceEdit(source);
057: }
058:
059: /*
060: * Copy constructor
061: */
062: private MoveTargetEdit(MoveTargetEdit other) {
063: super (other);
064: }
065:
066: /**
067: * Returns the associated source edit or <code>null</code>
068: * if no source edit is associated yet.
069: *
070: * @return the source edit or <code>null</code>
071: */
072: public MoveSourceEdit getSourceEdit() {
073: return fSource;
074: }
075:
076: /**
077: * Sets the source edit.
078: *
079: * @param edit the source edit
080: *
081: * @exception MalformedTreeException is thrown if the target edit
082: * is a direct or indirect child of the source edit
083: */
084: public void setSourceEdit(MoveSourceEdit edit) {
085: if (fSource != edit) {
086: fSource = edit;
087: fSource.setTargetEdit(this );
088: TextEdit parent = getParent();
089: while (parent != null) {
090: if (parent == fSource)
091: throw new MalformedTreeException(
092: parent,
093: this ,
094: TextEditMessages
095: .getString("MoveTargetEdit.wrong_parent")); //$NON-NLS-1$
096: parent = parent.getParent();
097: }
098: }
099: }
100:
101: /*
102: * @see TextEdit#doCopy
103: */
104: protected TextEdit doCopy() {
105: return new MoveTargetEdit(this );
106: }
107:
108: /*
109: * @see TextEdit#postProcessCopy
110: */
111: protected void postProcessCopy(TextEditCopier copier) {
112: if (fSource != null) {
113: MoveTargetEdit target = (MoveTargetEdit) copier
114: .getCopy(this );
115: MoveSourceEdit source = (MoveSourceEdit) copier
116: .getCopy(fSource);
117: if (target != null && source != null)
118: target.setSourceEdit(source);
119: }
120: }
121:
122: /*
123: * @see TextEdit#accept0
124: */
125: protected void accept0(TextEditVisitor visitor) {
126: boolean visitChildren = visitor.visit(this );
127: if (visitChildren) {
128: acceptChildren(visitor);
129: }
130: }
131:
132: //---- consistency check ----------------------------------------------------------
133:
134: /*
135: * @see TextEdit#traverseConsistencyCheck
136: */
137: int traverseConsistencyCheck(TextEditProcessor processor,
138: IDocument document, List sourceEdits) {
139: return super .traverseConsistencyCheck(processor, document,
140: sourceEdits) + 1;
141: }
142:
143: /*
144: * @see TextEdit#performConsistencyCheck
145: */
146: void performConsistencyCheck(TextEditProcessor processor,
147: IDocument document) throws MalformedTreeException {
148: if (fSource == null)
149: throw new MalformedTreeException(getParent(), this ,
150: TextEditMessages
151: .getString("MoveTargetEdit.no_source")); //$NON-NLS-1$
152: if (fSource.getTargetEdit() != this )
153: throw new MalformedTreeException(
154: getParent(),
155: this ,
156: TextEditMessages
157: .getString("MoveTargetEdit.different_target")); //$NON-NLS-1$
158: }
159:
160: //---- document updating ----------------------------------------------------------------
161:
162: /*
163: * @see TextEdit#performDocumentUpdating
164: */
165: int performDocumentUpdating(IDocument document)
166: throws BadLocationException {
167: String source = fSource.getContent();
168: document.replace(getOffset(), getLength(), source);
169: fDelta = source.length() - getLength();
170:
171: MultiTextEdit sourceRoot = fSource.getSourceRoot();
172: if (sourceRoot != null) {
173: sourceRoot.internalMoveTree(getOffset());
174: TextEdit[] sourceChildren = sourceRoot.removeChildren();
175: List children = new ArrayList(sourceChildren.length);
176: for (int i = 0; i < sourceChildren.length; i++) {
177: TextEdit child = sourceChildren[i];
178: child.internalSetParent(this );
179: children.add(child);
180: }
181: internalSetChildren(children);
182: }
183: fSource.clearContent();
184: return fDelta;
185: }
186:
187: //---- region updating --------------------------------------------------------------
188:
189: /*
190: * @see org.eclipse.text.edits.TextEdit#traversePassThree
191: */
192: int traverseRegionUpdating(TextEditProcessor processor,
193: IDocument document, int accumulatedDelta, boolean delete) {
194: // the children got already updated / normalized while they got removed
195: // from the source edit. So we only have to adjust the offset computed to
196: // far.
197: if (delete) {
198: deleteTree();
199: } else {
200: internalMoveTree(accumulatedDelta);
201: }
202: return accumulatedDelta + fDelta;
203: }
204:
205: boolean deleteChildren() {
206: return false;
207: }
208: }
|