/******************************************************************************* * Copyright © 2008, 2013 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.edt.ide.ui.internal.refactoring.rename; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ResourceBundle; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.edt.compiler.core.IEGLConstants; import org.eclipse.edt.compiler.internal.core.builder.DefaultProblemRequestor; import org.eclipse.edt.compiler.internal.core.lookup.DefaultCompilerOptions; import org.eclipse.edt.compiler.internal.core.utils.CharOperation; import org.eclipse.edt.compiler.internal.core.validation.name.EGLNameValidator; import org.eclipse.edt.ide.core.internal.model.SourcePart; import org.eclipse.edt.ide.core.model.EGLModelException; import org.eclipse.edt.ide.core.model.IEGLElement; import org.eclipse.edt.ide.core.model.IEGLFile; import org.eclipse.edt.ide.core.model.IPackageFragment; import org.eclipse.edt.ide.core.model.IPart; import org.eclipse.edt.ide.core.search.IEGLSearchConstants; import org.eclipse.edt.ide.core.search.IEGLSearchResultCollector; import org.eclipse.edt.ide.core.search.SearchEngine; import org.eclipse.edt.ide.ui.internal.UINlsStrings; import org.eclipse.edt.ide.ui.internal.refactoring.Checks; import org.eclipse.edt.ide.ui.internal.refactoring.RefactoringScopeFactory; import org.eclipse.edt.ide.ui.internal.refactoring.changes.RenameResourceChange; import org.eclipse.edt.ide.ui.internal.refactoring.changes.TextChangeCompatibility; import org.eclipse.edt.ide.ui.internal.refactoring.tagging.IReferenceUpdating; import org.eclipse.edt.ide.ui.internal.refactoring.util.TextChangeManager; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.CompositeChange; import org.eclipse.ltk.core.refactoring.GroupCategory; import org.eclipse.ltk.core.refactoring.GroupCategorySet; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.ParticipantManager; import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; import org.eclipse.ltk.core.refactoring.participants.RenameArguments; import org.eclipse.ltk.core.refactoring.participants.SharableParticipants; import org.eclipse.text.edits.ReplaceEdit; import com.ibm.icu.text.MessageFormat; public class RenamePartProcessor extends RenameProcessor implements IReferenceUpdating { private static final GroupCategorySet CATEGORY_PART_RENAME= new GroupCategorySet(new GroupCategory("com.ibm.etools.egl.internal.ui..refactoring.rename.renamePart.part", UINlsStrings.RenamePartProcessor_changeCategory_type, UINlsStrings.RenamePartProcessor_changeCategory_type_description)); //$NON-NLS-1$ private IPart part; private boolean fUpdateReferences; private List fReferences; private boolean willUpdateEGLFileName; private TextChangeManager fChangeManager; public RenamePartProcessor(IPart part) { this.part = part; willUpdateEGLFileName = part instanceof SourcePart && ((SourcePart) part).isGeneratable(); } protected RefactoringStatus doCheckFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException, OperationCanceledException { RefactoringStatus result= new RefactoringStatus(); int referenceSearchTicks= fUpdateReferences ? 15 : 0; int createChangeTicks = 5; try{ pm.beginTask("", 12 + referenceSearchTicks + createChangeTicks); //$NON-NLS-1$ pm.setTaskName(UINlsStrings.RefactoringProcessor_precondition_checking); if(pm.isCanceled()) { throw new OperationCanceledException(); } fChangeManager= new TextChangeManager(true); result.merge(checkTypesInPackage()); pm.worked(1); result.merge(checkRenameMainFunction()); pm.worked(1); if(willUpdateEGLFileName) { result.merge(Checks.checkFileNewName(part.getEGLFile(), getNewElementName())); pm.worked(1); } if(result.hasFatalError()) { return result; } if (fUpdateReferences) { pm.setTaskName(UINlsStrings.RefactoringProcessor_searching_references); result.merge(initializeReferences(new SubProgressMonitor(pm, referenceSearchTicks))); } else { fReferences = Collections.EMPTY_LIST; } createChanges(new SubProgressMonitor(pm, createChangeTicks)); } finally { pm.done(); } return result; } public RefactoringStatus initializeReferences(final IProgressMonitor monitor) throws EGLModelException { RefactoringStatus result= new RefactoringStatus(); fReferences = new ArrayList(); String searchString; IPackageFragment packageFragment = (IPackageFragment)part.getAncestor(IEGLElement.PACKAGE_FRAGMENT); if(packageFragment.isDefaultPackage()) { searchString = part.getElementName(); } else { searchString = new String(CharOperation.concat(packageFragment.getElementName().toCharArray(), part.getElementName().toCharArray(), '.')); } new SearchEngine().search(ResourcesPlugin.getWorkspace(), SearchEngine.createSearchPattern(searchString, getSearchFor(part), IEGLSearchConstants.REFERENCES, false), RefactoringScopeFactory.create(part), true,true,new IEGLSearchResultCollector() { public void aboutToStart() { } public void accept(IResource resource, int start, int end, IEGLElement enclosingElement, int accuracy) throws CoreException { if (IEGLSearchResultCollector.EXACT_MATCH == accuracy){ fReferences.add(new Object[] {resource, new Integer(start), new Integer(end), enclosingElement, new Integer(accuracy)}); } } public void done() { } public IProgressMonitor getProgressMonitor() { return monitor; } public void accept(IEGLElement element, int start, int end, IResource resource, int accuracy) throws CoreException { // TODO Auto-generated method stub } }); return result; } private int getSearchFor(IPart part) { int result = IEGLSearchConstants.ALL_ELEMENTS; if(part instanceof SourcePart) { SourcePart sPart = ((SourcePart) part); if (sPart.isDelegate()) { result = IEGLSearchConstants.DELEGATE_PART; } else if (sPart.isExternalType()) { result = IEGLSearchConstants.EXTERNALTYPE_PART; } else if (sPart.isHandler()) { result = IEGLSearchConstants.HANDLER_PART; } else if (sPart.isInterface()) { result = IEGLSearchConstants.INTERFACE_PART; } else if (sPart.isLibrary()) { result = IEGLSearchConstants.LIBRARY_PART; } else if (sPart.isProgram()) { result = IEGLSearchConstants.PROGRAM_PART; } else if (sPart.isRecord()) { result = IEGLSearchConstants.RECORD_PART; } else if (sPart.isService()) { result = IEGLSearchConstants.SERVICE_PART; } else if (sPart.isEnumeration()) { result = IEGLSearchConstants.ENUMERATION_PART; } else if (sPart.isClass()) { result = IEGLSearchConstants.CLASS_PART; } else if (sPart.isFunction()) { result = IEGLSearchConstants.ALL_FUNCTIONS; } } return result; } private void createChanges(IProgressMonitor pm) throws CoreException { try { pm.beginTask("", 3); //$NON-NLS-1$ pm.setTaskName(UINlsStrings.RefactoringProcessor_creating_changes); if (fUpdateReferences) addReferenceUpdates(fChangeManager, new SubProgressMonitor(pm, 3)); pm.worked(1); addPartDeclarationUpdate(fChangeManager); pm.worked(1); } finally { pm.done(); } } private void addRenameEGLFileUpdate(CompositeChange compositeChange) { if(willUpdateEGLFileName) { IEGLFile file = part.getEGLFile(); String filename = file.getElementName(); String ext = null; int lastIndexOfDot = filename.lastIndexOf('.'); if(lastIndexOfDot != -1) { ext = filename.substring(lastIndexOfDot+1); filename = filename.substring(0, lastIndexOfDot); } if(filename.equals(part.getElementName())) { StringBuffer newFilename = new StringBuffer(getNewElementName()); if(ext != null) { newFilename.append('.'); newFilename.append(ext); } compositeChange.add(new RenameResourceChange(null, file.getResource(), newFilename.toString(), null)); } } } private void addPartDeclarationUpdate(TextChangeManager manager) throws EGLModelException { String name= UINlsStrings.RenamePartRefactoring_update; int partNameLength= part.getElementName().length(); IFile file = (IFile) part.getResource(); TextChangeCompatibility.addTextEdit(manager.get(part.getEGLFile()), name, new ReplaceEdit(part.getNameRange().getOffset(), partNameLength, getNewElementName())); } private void addReferenceUpdates(TextChangeManager manager, IProgressMonitor pm) { pm.beginTask("", fReferences.size()); //$NON-NLS-1$ String name= UINlsStrings.RenamePartRefactoring_update_reference; for (Iterator iter = fReferences.iterator(); iter.hasNext();) { Object[] nextRef = (Object[]) iter.next(); if(nextRef[0] instanceof IFile) { int start = ((Integer) nextRef[1]).intValue(); int end = ((Integer) nextRef[2]).intValue(); IEGLElement enclosingElement = (IEGLElement) nextRef[3]; String newElementName = getNewElementName(); start = start + end-start - part.getElementName().length(); // reference may be qualified TextChangeCompatibility.addTextEdit(manager.get(getEGLFile(enclosingElement)), name, new ReplaceEdit(start, part.getElementName().length(), newElementName), CATEGORY_PART_RENAME); } pm.worked(1); } } private IEGLFile getEGLFile(IEGLElement element) { while(!(element instanceof IEGLFile)) { element = element.getParent(); } return (IEGLFile) element; } protected String[] getAffectedProjectNatures() throws CoreException { return new String[]{"com.ibm.etools.egl.model.eglnature"}; //$NON-NLS-1$ } protected IFile[] getChangedFiles() throws CoreException { List result= new ArrayList(); result.addAll(Arrays.asList(toFiles(fChangeManager.getAllCompilationUnits()))); if (willUpdateEGLFileName) result.add((IFile) part.getEGLFile().getResource()); return (IFile[]) result.toArray(new IFile[result.size()]); } private Object[] toFiles(IEGLFile[] allCompilationUnits) { List result = new ArrayList(); for(int i = 0; i < allCompilationUnits.length; i++) { result.add((IFile) allCompilationUnits[i].getResource()); } return (IFile[]) result.toArray(new IFile[result.size()]); } public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { return new RefactoringStatus(); } public Change createChange(IProgressMonitor monitor) throws CoreException, OperationCanceledException { try { CompositeChange result = new CompositeChange(UINlsStrings.RenamePartProcessor_change_name); monitor.beginTask(UINlsStrings.RenamePartRefactoring_creating_change, 4); result.addAll(fChangeManager.getAllChanges()); if (willUpdateEGLFileName) { addRenameEGLFileUpdate(result); } monitor.worked(1); return result; } finally { fChangeManager= null; } } public Object[] getElements() { // TODO Auto-generated method stub return null; } public String getIdentifier() { return this.getClass().getName(); } public String getProcessorName() { return UINlsStrings.RenamePartRefactoring_name; } public boolean isApplicable() throws CoreException { // TODO Auto-generated method stub return false; } public RefactoringParticipant[] loadParticipants(RefactoringStatus status, SharableParticipants shared) throws CoreException { return ParticipantManager.loadRenameParticipants(status, this, part, new RenameArguments(getNewElementName(), getUpdateReferences()), getAffectedProjectNatures(), shared); } public RefactoringStatus checkNewElementName(String newName) throws CoreException { final RefactoringStatus[] result = new RefactoringStatus[] {new RefactoringStatus()}; EGLNameValidator.validate(newName, EGLNameValidator.PART, new DefaultProblemRequestor() { @Override public void acceptProblem(int startOffset, int endOffset, int severity, int problemKind, String[] inserts, ResourceBundle bundle) { if(result[0].isOK()) { result[0] = RefactoringStatus.createFatalErrorStatus(getMessageFromBundle(problemKind, inserts, bundle)); } } }, DefaultCompilerOptions.getInstance()); return result[0]; } public String getCurrentElementName() { return part.getElementName(); } public boolean canEnableUpdateReferences() { return true; } public boolean getUpdateReferences() { return fUpdateReferences; } public void setUpdateReferences(boolean update) { fUpdateReferences = update; } private RefactoringStatus checkTypesInPackage() throws CoreException { IPart existingPart = findPartInPackage(part.getPackageFragment(), getNewElementName()); if (existingPart == null || ! existingPart.exists()) return null; String msg= MessageFormat.format( UINlsStrings.RenamePartRefactoring_exists, new String[]{getNewElementName(), part.getPackageFragment().getElementName()}); return RefactoringStatus.createErrorStatus(msg); } private RefactoringStatus checkRenameMainFunction() throws CoreException { IEGLElement parent = part.getParent(); if(IPart.FUNCTION == part.getElementType() && IEGLConstants.MNEMONIC_MAIN.equalsIgnoreCase(part.getElementName()) && parent instanceof SourcePart && ((SourcePart) parent).isProgram()) { String msg= MessageFormat.format( UINlsStrings.RenamePartRefactoring_rename_main_function, new String[]{parent.getElementName()}); return RefactoringStatus.createErrorStatus(msg); } return null; } public static IPart findPartInPackage(IPackageFragment pack, String name) throws EGLModelException { Assert.isTrue(pack.exists()); Assert.isTrue(!pack.isReadOnly()); /* ICompilationUnit.getType expects simple name*/ if (name.indexOf(".") != -1) //$NON-NLS-1$ name= name.substring(0, name.indexOf(".")); //$NON-NLS-1$ IEGLFile[] cus= pack.getEGLFiles(); for (int i= 0; i < cus.length; i++){ if (cus[i].getPart(name).exists()) return cus[i].getPart(name); } return null; } }