| /******************************************************************************* |
| * Copyright (c) 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jsp.ui.internal.java.refactoring; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.search.SearchRequestor; |
| import org.eclipse.jst.jsp.core.internal.java.search.JSPSearchScope; |
| import org.eclipse.jst.jsp.core.internal.java.search.JSPSearchSupport; |
| import org.eclipse.jst.jsp.ui.internal.JSPUIMessages; |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.CompositeChange; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.TextChange; |
| import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; |
| import org.eclipse.ltk.core.refactoring.participants.ISharableParticipant; |
| import org.eclipse.ltk.core.refactoring.participants.MoveArguments; |
| import org.eclipse.ltk.core.refactoring.participants.MoveParticipant; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; |
| import org.eclipse.text.edits.TextEdit; |
| |
| /** |
| * Abstract {@link ISharableParticipant} {@link MoveParticipant} for editing JSP documents |
| */ |
| public abstract class JSPMoveParticipant extends MoveParticipant implements ISharableParticipant { |
| |
| /** |
| * The name of this participant. |
| * Should be initialized by implementers in {@link #initialize(Object)} |
| */ |
| protected String fName; |
| |
| /** |
| * A map of {@link IJavaElement} names to pairs of {@link IJavaElement}s |
| * and their associated {@link MoveArguments} that have been added to |
| * this {@link ISharableParticipant}. |
| * |
| * key: {@link String} - Element name<br/> |
| * value: {@link ElementAndArgumentsPair} |
| */ |
| private Map fElementAndArgumentPairs; |
| |
| /** |
| * When new changes are being safely created {@link #getTextChange(Object)} |
| * is called first to check for existing {@link TextChange}s, but those |
| * results do not usually include the changes that have been created thus far |
| * locally by this {@link MoveParticipant}. This is to keep track of those |
| * changes so the overridden version of {@link #getTextChange(Object)}s will take |
| * these local {@link TextChange}s into account. |
| */ |
| private Map fLocalTextChanges; |
| |
| /** |
| * Groups an {@link IJavaElement} with its associated {@link MoveArguments} |
| * that have been added to this {@link ISharableParticipant} |
| */ |
| private class ElementAndArgumentsPair { |
| protected IJavaElement fElement; |
| protected MoveArguments fArgs; |
| |
| public ElementAndArgumentsPair(IJavaElement element, MoveArguments args) { |
| this.fElement = element; |
| this.fArgs = args; |
| } |
| } |
| |
| /** |
| * <p>Do local initialization. This is done here instead of in an implementation of |
| * {@link RefactoringParticipant#initialize(java.lang.Object)} because implementers |
| * of this class are not expected to have to call super when they implement |
| * {@link RefactoringParticipant#initialize(java.lang.Object)}</p> |
| * |
| * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#initialize( |
| * org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor, java.lang.Object, |
| * org.eclipse.ltk.core.refactoring.participants.RefactoringArguments) |
| */ |
| public boolean initialize(RefactoringProcessor processor, Object element, |
| RefactoringArguments arguments) { |
| |
| this.fElementAndArgumentPairs = new HashMap(); |
| this.addElement(element, arguments); |
| this.fLocalTextChanges = new HashMap(); |
| this.fName = ""; //$NON-NLS-1$ |
| |
| return super.initialize(processor, element, arguments); |
| } |
| |
| /** |
| * <p>When an element is added to this {@link ISharableParticipant} it must be |
| * a {@link IJavaElement} and be a legal element type ({@link #isLegalElementType(IJavaElement)} |
| * and the given arguments must be {@link MoveArguments}. Also the new <code>element</code> |
| * will not be added if and {@link IJavaElement} of that name has already been added to |
| * this {@link ISharableParticipant}. This protects against elements being added more |
| * then once.</p> |
| * |
| * @see org.eclipse.ltk.core.refactoring.participants.ISharableParticipant#addElement(java.lang.Object, |
| * org.eclipse.ltk.core.refactoring.participants.RefactoringArguments) |
| */ |
| public void addElement(Object element, RefactoringArguments arguments) { |
| if(element instanceof IJavaElement && |
| isLegalElementType((IJavaElement)element) && |
| arguments instanceof MoveArguments) { |
| |
| //don't add elements that have already been added |
| String elementName = ((IJavaElement)element).getElementName(); |
| if(!this.fElementAndArgumentPairs.containsKey(elementName)) { |
| this.fElementAndArgumentPairs.put(elementName, |
| new ElementAndArgumentsPair((IJavaElement)element, (MoveArguments)arguments)); |
| } |
| } |
| } |
| |
| /** |
| * <p>As of now the conditions are always {@link RefactoringStatus#OK}</p> |
| * |
| * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#checkConditions( |
| * org.eclipse.core.runtime.IProgressMonitor, org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext) |
| */ |
| public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) { |
| return new RefactoringStatus(); |
| } |
| |
| /** |
| * |
| * |
| * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#createChange( |
| * org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public Change createChange(IProgressMonitor pm) throws CoreException { |
| this.getTextChange(""); //$NON-NLS-1$ |
| |
| //create one multi change to contain all new created changes |
| CompositeChange multiChange = new CompositeChange(JSPUIMessages.JSP_changes); |
| |
| //for each element get the changes for it and add it to the multi change |
| Iterator iter = fElementAndArgumentPairs.values().iterator(); |
| while(iter.hasNext()) { |
| ElementAndArgumentsPair elemArgsPair = (ElementAndArgumentsPair)iter.next(); |
| |
| Object dest = elemArgsPair.fArgs.getDestination(); |
| |
| if(dest instanceof IPackageFragment) { |
| Change[] changes = createChangesFor(elemArgsPair.fElement, ((IPackageFragment)dest).getElementName(), pm); |
| |
| /* add all new text changes to the local list of text changes so that |
| * future iterations through the while loop will be aware of already |
| * existing changes |
| */ |
| for(int i = 0; i < changes.length; ++i) { |
| if(changes[i] instanceof TextChange) { |
| fLocalTextChanges.put(((TextChange)changes[i]).getModifiedElement(), changes[i]); |
| } |
| } |
| |
| if(changes.length > 0) { |
| multiChange.addAll(changes); |
| } |
| } |
| } |
| |
| //unless there are actually new changes return null |
| Change result = null; |
| if(multiChange.getChildren().length > 0) { |
| result = multiChange; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#getName() |
| */ |
| public String getName() { |
| return fName; |
| } |
| |
| /** |
| * <p>Overridden to include locally created {@link TextChange}s that have not yet be returned by |
| * {@link #createChange(IProgressMonitor)}.</p> |
| * |
| * @see org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant#getTextChange(java.lang.Object) |
| */ |
| public TextChange getTextChange(Object element) { |
| TextChange existingChange = (TextChange)fLocalTextChanges.get(element); |
| if(existingChange == null) { |
| existingChange = super.getTextChange(element); |
| } |
| |
| return existingChange; |
| } |
| |
| /** |
| * Using a {@link SearchRequestor} create new changes. |
| * |
| * @param element the {@link IJavaElement} to create new changes for |
| * @param newName the new name of the given {@link IJavaElement} |
| * |
| * @return any newly created {@link Change}s. It is important to note |
| * that while no NEW {@link Change}s maybe returned it is possible that |
| * new {@link TextEdit}s will still added to existing {@link Change}s. |
| */ |
| protected Change[] createChangesFor(IJavaElement element, String newName, IProgressMonitor monitor) { |
| Change[] changes; |
| BasicRefactorSearchRequestor requestor = getSearchRequestor(element, newName); |
| if(requestor != null) { |
| JSPSearchSupport support = JSPSearchSupport.getInstance(); |
| support.searchRunnable(element, new JSPSearchScope(), requestor, monitor); |
| changes = requestor.getChanges(this); |
| } else { |
| changes = new Change[0]; |
| } |
| |
| return changes; |
| } |
| |
| /** |
| * <p>Should be implemented to return the {@link BasicRefactorSearchRequestor} associated |
| * with the implementers {@link JSPMoveParticipant}.</p> |
| * |
| * @param element the {@link IJavaElement} to create the {@link BasicRefactorSearchRequestor} from |
| * @param newName the new name of the {@link IJavaElement} to use when |
| * creating the {@link BasicRefactorSearchRequestor} |
| * |
| * @return a new {@link BasicRefactorSearchRequestor} based on the given parameters |
| */ |
| protected abstract BasicRefactorSearchRequestor getSearchRequestor(IJavaElement element, String newName); |
| |
| /** |
| * @param element check that this {@link IJavaElement} is of the type the |
| * implementers {@link JSPMoveParticipant} is configured to deal with. |
| * |
| * @return <code>true</code> if the given {@link IJavaElement} is of a type |
| * the implementers {@link JSPMoveParticipant} is configured to deal with, |
| * <code>false</code> otherwise. |
| */ |
| protected abstract boolean isLegalElementType(IJavaElement element); |
| } |