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.jdt.internal.ui.refactoring;
011:
012: import java.util.ArrayList;
013: import java.util.Collections;
014: import java.util.Comparator;
015: import java.util.HashMap;
016: import java.util.List;
017: import java.util.Map;
018:
019: import org.eclipse.text.edits.TextEdit;
020:
021: import org.eclipse.core.runtime.Assert;
022: import org.eclipse.core.runtime.CoreException;
023:
024: import org.eclipse.jface.resource.ImageDescriptor;
025:
026: import org.eclipse.jface.text.IRegion;
027: import org.eclipse.jface.text.Region;
028:
029: import org.eclipse.ltk.ui.refactoring.LanguageElementNode;
030: import org.eclipse.ltk.ui.refactoring.TextEditChangeNode;
031:
032: import org.eclipse.ltk.core.refactoring.TextEditBasedChange;
033: import org.eclipse.ltk.core.refactoring.TextEditBasedChangeGroup;
034:
035: import org.eclipse.jdt.core.ICompilationUnit;
036: import org.eclipse.jdt.core.IJavaElement;
037: import org.eclipse.jdt.core.ISourceRange;
038: import org.eclipse.jdt.core.ISourceReference;
039: import org.eclipse.jdt.core.JavaModelException;
040:
041: import org.eclipse.jdt.ui.JavaElementLabels;
042:
043: import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
044:
045: public class CompilationUnitChangeNode extends TextEditChangeNode {
046:
047: static final ChildNode[] EMPTY_CHILDREN = new ChildNode[0];
048:
049: private static class JavaLanguageNode extends LanguageElementNode {
050:
051: private IJavaElement fJavaElement;
052: private static JavaElementImageProvider fgImageProvider = new JavaElementImageProvider();
053:
054: public JavaLanguageNode(TextEditChangeNode parent,
055: IJavaElement element) {
056: super (parent);
057: fJavaElement = element;
058: Assert.isNotNull(fJavaElement);
059: }
060:
061: public JavaLanguageNode(ChildNode parent, IJavaElement element) {
062: super (parent);
063: fJavaElement = element;
064: Assert.isNotNull(fJavaElement);
065: }
066:
067: public String getText() {
068: return JavaElementLabels.getElementLabel(fJavaElement,
069: JavaElementLabels.ALL_DEFAULT);
070: }
071:
072: public ImageDescriptor getImageDescriptor() {
073: return fgImageProvider.getJavaImageDescriptor(fJavaElement,
074: JavaElementImageProvider.OVERLAY_ICONS
075: | JavaElementImageProvider.SMALL_ICONS);
076: }
077:
078: public IRegion getTextRange() throws CoreException {
079: ISourceRange range = ((ISourceReference) fJavaElement)
080: .getSourceRange();
081: return new Region(range.getOffset(), range.getLength());
082: }
083: }
084:
085: public CompilationUnitChangeNode(TextEditBasedChange change) {
086: super (change);
087: }
088:
089: protected ChildNode[] createChildNodes() {
090: final TextEditBasedChange change = getTextEditBasedChange();
091: ICompilationUnit cunit = (ICompilationUnit) change
092: .getAdapter(ICompilationUnit.class);
093: if (cunit != null) {
094: List children = new ArrayList(5);
095: Map map = new HashMap(20);
096: TextEditBasedChangeGroup[] changes = getSortedChangeGroups(change);
097: for (int i = 0; i < changes.length; i++) {
098: TextEditBasedChangeGroup tec = changes[i];
099: try {
100: IJavaElement element = getModifiedJavaElement(tec,
101: cunit);
102: if (element.equals(cunit)) {
103: children
104: .add(createTextEditGroupNode(this , tec));
105: } else {
106: JavaLanguageNode pjce = getChangeElement(map,
107: element, children, this );
108: pjce
109: .addChild(createTextEditGroupNode(pjce,
110: tec));
111: }
112: } catch (JavaModelException e) {
113: children.add(createTextEditGroupNode(this , tec));
114: }
115: }
116: return (ChildNode[]) children
117: .toArray(new ChildNode[children.size()]);
118: } else {
119: return EMPTY_CHILDREN;
120: }
121: }
122:
123: private static class OffsetComparator implements Comparator {
124: public int compare(Object o1, Object o2) {
125: TextEditBasedChangeGroup c1 = (TextEditBasedChangeGroup) o1;
126: TextEditBasedChangeGroup c2 = (TextEditBasedChangeGroup) o2;
127: int p1 = getOffset(c1);
128: int p2 = getOffset(c2);
129: if (p1 < p2)
130: return -1;
131: if (p1 > p2)
132: return 1;
133: // same offset
134: return 0;
135: }
136:
137: private int getOffset(TextEditBasedChangeGroup edit) {
138: return edit.getRegion().getOffset();
139: }
140: }
141:
142: private TextEditBasedChangeGroup[] getSortedChangeGroups(
143: TextEditBasedChange change) {
144: TextEditBasedChangeGroup[] edits = change.getChangeGroups();
145: List result = new ArrayList(edits.length);
146: for (int i = 0; i < edits.length; i++) {
147: if (!edits[i].getTextEditGroup().isEmpty())
148: result.add(edits[i]);
149: }
150: Comparator comparator = new OffsetComparator();
151: Collections.sort(result, comparator);
152: return (TextEditBasedChangeGroup[]) result
153: .toArray(new TextEditBasedChangeGroup[result.size()]);
154: }
155:
156: private IJavaElement getModifiedJavaElement(
157: TextEditBasedChangeGroup edit, ICompilationUnit cunit)
158: throws JavaModelException {
159: IRegion range = edit.getRegion();
160: if (range.getOffset() == 0 && range.getLength() == 0)
161: return cunit;
162: IJavaElement result = cunit.getElementAt(range.getOffset());
163: if (result == null)
164: return cunit;
165:
166: try {
167: while (true) {
168: ISourceReference ref = (ISourceReference) result;
169: IRegion sRange = new Region(ref.getSourceRange()
170: .getOffset(), ref.getSourceRange().getLength());
171: if (result.getElementType() == IJavaElement.COMPILATION_UNIT
172: || result.getParent() == null
173: || coveredBy(edit, sRange))
174: break;
175: result = result.getParent();
176: }
177: } catch (JavaModelException e) {
178: // Do nothing, use old value.
179: } catch (ClassCastException e) {
180: // Do nothing, use old value.
181: }
182: return result;
183: }
184:
185: private JavaLanguageNode getChangeElement(Map map,
186: IJavaElement element, List children,
187: TextEditChangeNode cunitChange) {
188: JavaLanguageNode result = (JavaLanguageNode) map.get(element);
189: if (result != null)
190: return result;
191: IJavaElement parent = element.getParent();
192: if (parent instanceof ICompilationUnit) {
193: result = new JavaLanguageNode(cunitChange, element);
194: children.add(result);
195: map.put(element, result);
196: } else {
197: JavaLanguageNode parentChange = getChangeElement(map,
198: parent, children, cunitChange);
199: result = new JavaLanguageNode(parentChange, element);
200: parentChange.addChild(result);
201: map.put(element, result);
202: }
203: return result;
204: }
205:
206: private boolean coveredBy(TextEditBasedChangeGroup group,
207: IRegion sourceRegion) {
208: int sLength = sourceRegion.getLength();
209: if (sLength == 0)
210: return false;
211: int sOffset = sourceRegion.getOffset();
212: int sEnd = sOffset + sLength - 1;
213: TextEdit[] edits = group.getTextEdits();
214: for (int i = 0; i < edits.length; i++) {
215: TextEdit edit = edits[i];
216: if (edit.isDeleted())
217: return false;
218: int rOffset = edit.getOffset();
219: int rLength = edit.getLength();
220: int rEnd = rOffset + rLength - 1;
221: if (rLength == 0) {
222: if (!(sOffset < rOffset && rOffset <= sEnd))
223: return false;
224: } else {
225: if (!(sOffset <= rOffset && rEnd <= sEnd))
226: return false;
227: }
228: }
229: return true;
230: }
231: }
|