| /******************************************************************************* |
| * Copyright (c) 2004, 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.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.search.SearchDocument; |
| import org.eclipse.jdt.core.search.SearchMatch; |
| import org.eclipse.jdt.core.search.SearchRequestor; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jst.jsp.core.internal.java.search.JSPSearchSupport; |
| import org.eclipse.jst.jsp.core.internal.java.search.JavaSearchDocumentDelegate; |
| import org.eclipse.jst.jsp.ui.internal.JSPUIMessages; |
| import org.eclipse.jst.jsp.ui.internal.Logger; |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.TextChange; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.text.edits.MalformedTreeException; |
| import org.eclipse.text.edits.MultiTextEdit; |
| import org.eclipse.text.edits.ReplaceEdit; |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| /** |
| * <p>After a search is run with this {@link SearchRequestor} {@link #getChanges(RefactoringParticipant)} |
| * can be called to get any new {@link Change}s that need to be created as a result of the search. If |
| * {@link Change}s are already existing for the documents found then new {@link Change}s will not be |
| * created for them, but the needed {@link TextEdit}s will be added to the existing {@link Change}s.</p> |
| */ |
| public class BasicRefactorSearchRequestor extends SearchRequestor { |
| /** The type being renamed (the old type)*/ |
| IJavaElement fElement = null; |
| /** The new name of the type being renamed*/ |
| private String fNewName = ""; //$NON-NLS-1$ |
| /** maps a JSPSearchDocument path -> MultiTextEdit for the java file*/ |
| private HashMap fSearchDocPath2JavaEditMap = null; |
| |
| public BasicRefactorSearchRequestor(IJavaElement element, String newName) { |
| this.fNewName = newName; |
| this.fElement = element; |
| this.fSearchDocPath2JavaEditMap = new HashMap(); |
| } |
| |
| public IJavaElement getElement() { |
| return this.fElement; |
| } |
| |
| /** |
| * @return the new name for the Type |
| */ |
| public String getNewName() { |
| return this.fNewName; |
| } |
| |
| /** |
| * @see org.eclipse.jdt.core.search.SearchRequestor#acceptSearchMatch(org.eclipse.jdt.core.search.SearchMatch) |
| */ |
| public void acceptSearchMatch(SearchMatch javaMatch) throws CoreException { |
| |
| String matchDocumentPath = javaMatch.getResource().getFullPath().toString(); |
| SearchDocument searchDoc = JSPSearchSupport.getInstance().getSearchDocument(matchDocumentPath); |
| |
| if (searchDoc != null && searchDoc instanceof JavaSearchDocumentDelegate) { |
| |
| String renameText = getRenameText((JavaSearchDocumentDelegate)searchDoc, javaMatch); |
| |
| // add it for the correct document |
| addJavaEdit(searchDoc.getPath(), new ReplaceEdit(javaMatch.getOffset(), javaMatch.getLength(), renameText)); |
| } |
| } |
| |
| /** |
| * @param searchDoc |
| * @return |
| */ |
| protected String getRenameText(JavaSearchDocumentDelegate searchDoc, SearchMatch javaMatch) { |
| return getNewName(); |
| } |
| |
| /** |
| * Adds to the multi edit for a give java document. |
| * @param javaDocument |
| * @param javaEdit |
| */ |
| private void addJavaEdit(String searchDocPath, ReplaceEdit javaEdit) { |
| |
| Object o = this.fSearchDocPath2JavaEditMap.get(searchDocPath); |
| if(o != null) { |
| |
| MultiTextEdit multi = (MultiTextEdit)o; |
| multi.addChild(javaEdit); |
| } |
| else { |
| // use a multi edit so doc position offsets get updated automatically |
| // when adding multiple child edits |
| MultiTextEdit multi = new MultiTextEdit(); |
| multi.addChild(javaEdit); |
| this.fSearchDocPath2JavaEditMap.put(searchDocPath, multi); |
| } |
| } |
| |
| /** |
| * <p>This function is not safe because it does not check for existing {@link Change}s that |
| * new {@link Change}s created by this method may conflict with. These conflicts can |
| * cause indeterminate results when applied to documents. Long story short, don't |
| * use this method any more.</p> |
| * |
| * @return all JSP changes for the search matches for the given Type, they may conflict |
| * with already existing {@link Change}s |
| * |
| * @see #getChanges(RefactoringParticipant) |
| * |
| * @deprecated |
| */ |
| public Change[] getChanges() { |
| |
| JSPSearchSupport support = JSPSearchSupport.getInstance(); |
| List changes = new ArrayList(); |
| Iterator keys = fSearchDocPath2JavaEditMap.keySet().iterator(); |
| String searchDocPath = null; |
| SearchDocument delegate = null; |
| |
| while(keys.hasNext()) { |
| // create on the fly |
| searchDocPath = (String)keys.next(); |
| MultiTextEdit javaEdit = (MultiTextEdit)fSearchDocPath2JavaEditMap.get(searchDocPath); |
| delegate = support.getSearchDocument(searchDocPath); |
| |
| if(delegate != null && delegate instanceof JavaSearchDocumentDelegate) { |
| JavaSearchDocumentDelegate javaDelegate = (JavaSearchDocumentDelegate)delegate; |
| changes.add(createChange(javaDelegate, javaDelegate.getJspTranslation().getJspEdit(javaEdit))); |
| } |
| } |
| return (Change[])changes.toArray(new Change[changes.size()]); |
| } |
| |
| /** |
| * Gets new {@link Change}s created as a result of this {@link SearchRequestor}. |
| * Any existing {@link TextChange}s that had new edits added to them will not be |
| * returned. |
| * |
| * @param participant {@link RefactoringParticipant} to determine if there are already existing |
| * {@link TextChange}s for the documents that this {@link SearchRequestor} found. |
| * If existing |
| * {@link TextChange}s are found then they will be used for any new edits, else new {@link TextChange}s |
| * will be created. |
| * |
| * @return Any new {@link TextChange}s created by this {@link SearchRequestor}. If edits were |
| * added to existing {@link TextChange}s then those existing {@link TextChange}s will not be |
| * returned in this array. |
| */ |
| public Change[] getChanges(RefactoringParticipant participant) { |
| |
| JSPSearchSupport support = JSPSearchSupport.getInstance(); |
| List changes = new ArrayList(); |
| Iterator keys = fSearchDocPath2JavaEditMap.keySet().iterator(); |
| String searchDocPath = null; |
| SearchDocument delegate = null; |
| |
| while(keys.hasNext()) { |
| // create on the fly |
| searchDocPath = (String)keys.next(); |
| MultiTextEdit javaEdit = (MultiTextEdit)fSearchDocPath2JavaEditMap.get(searchDocPath); |
| delegate = support.getSearchDocument(searchDocPath); |
| |
| if(delegate != null && delegate instanceof JavaSearchDocumentDelegate) { |
| JavaSearchDocumentDelegate javaDelegate = (JavaSearchDocumentDelegate)delegate; |
| Change change = createChange(javaDelegate, javaDelegate.getJspTranslation().getJspEdit(javaEdit), participant); |
| changes.add(change); |
| } |
| } |
| return (Change[])changes.toArray(new Change[changes.size()]); |
| } |
| |
| /** |
| * <p>This method is not safe because it does not take into consideration already existing |
| * {@link Change}s and thus conflicts could occur that when applied create indeterminate |
| * results in the target documents</p> |
| * |
| * @see #createChange(JavaSearchDocumentDelegate, TextEdit, RefactoringParticipant) |
| * |
| * @deprecated |
| */ |
| private Change createChange(JavaSearchDocumentDelegate searchDoc, TextEdit edit) { |
| |
| IDocument doc = searchDoc.getJspTranslation().getJspDocument(); |
| String file = searchDoc.getFile().getName(); |
| String description = getDescription(); |
| try { |
| // document lines are 0 based |
| String lineNumber = Integer.toString(doc.getLineOfOffset(edit.getOffset()) + 1); |
| description += " " + NLS.bind(JSPUIMessages.BasicRefactorSearchRequestor_1, new String[]{file, lineNumber}); //$NON-NLS-1$ |
| } |
| catch (BadLocationException e) { |
| Logger.logException(e); |
| } |
| return new JSPRenameChange(searchDoc.getFile(), doc, edit, description); |
| } |
| |
| /** |
| * </p>If a {@link TextChange} does not already exist for the given {@link JavaSearchDocumentDelegate} |
| * then a new one will be created with the given {@link TextEdit}. Otherwise the given {@link TextEdit} |
| * will be added to a new group and added to the existing change and <code>null</code> will be returned.</p> |
| * |
| * @param searchDoc the {@link JavaSearchDocumentDelegate} that the <code>edit</code> will be applied to |
| * @param edit the {@link TextEdit} that needs to be added to a new {@link TextChange} or appended to an |
| * existing one |
| * @param participant the {@link RefactoringParticipant} that knows about the existing {@link TextChange}s |
| * @return a new {@link Change} if there was not one already existing for the document in question, |
| * else <code>null</code> |
| */ |
| private Change createChange(JavaSearchDocumentDelegate searchDoc, TextEdit edit, RefactoringParticipant participant) { |
| IDocument doc = searchDoc.getJspTranslation().getJspDocument(); |
| String description = getDescription(); |
| |
| TextChange existingChange = participant.getTextChange(searchDoc.getFile()); |
| TextChange change = null; |
| if(existingChange != null) { |
| try { |
| existingChange.addEdit(edit); |
| }catch (MalformedTreeException e) { |
| Logger.logException("MalformedTreeException while adding edit " + //$NON-NLS-1$ |
| edit + " to existing change " + change, e); //$NON-NLS-1$ |
| } |
| |
| TextEditGroup group = new TextEditGroup(description, edit); |
| existingChange.addTextEditGroup(group); |
| } else { |
| change = new JSPRenameChange(searchDoc.getFile(), doc, edit, searchDoc.getFile().getName()); |
| TextEditGroup group = new TextEditGroup(description, edit); |
| change.addTextEditGroup(group); |
| } |
| |
| return change; |
| } |
| |
| // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3205 |
| // only relevant for IType refactorings |
| protected boolean isFullyQualified(String matchText) { |
| if(getElement() instanceof IType) { |
| String pkg = ((IType)getElement()).getPackageFragment().getElementName(); |
| return matchText.startsWith(pkg); |
| } |
| return false; |
| } |
| |
| /** |
| * Subclasses should override to better describe the change. |
| * @return |
| */ |
| protected String getDescription() { |
| return ""; //$NON-NLS-1$ |
| } |
| } |