| /******************************************************************************* |
| * Copyright (c) 2000, 2011 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.refactoring.reorg; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SubMonitor; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory; |
| |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.participants.DeleteArguments; |
| import org.eclipse.ltk.core.refactoring.participants.ParticipantManager; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor; |
| import org.eclipse.ltk.core.refactoring.participants.SharableParticipants; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaCore; |
| |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; |
| |
| /** |
| * A modification collector for Java element delete operations. |
| */ |
| public class DeleteModifications extends RefactoringModifications { |
| |
| private List<IJavaElement> fDelete; |
| |
| /** |
| * Contains the actual packages when executing |
| * <code>handlePackageFragmentDelete</code>. This is part of the |
| * algorithm to check if a parent folder can be deleted. |
| */ |
| private Set<IPackageFragment> fPackagesToDelete; |
| |
| public DeleteModifications() { |
| fDelete= new ArrayList<>(); |
| fPackagesToDelete= new LinkedHashSet<>(); |
| } |
| |
| public void delete(IResource resource) { |
| getResourceModifications().addDelete(resource); |
| } |
| |
| public void delete(IResource[] resources) { |
| for (IResource resource : resources) { |
| delete(resource); |
| } |
| } |
| |
| public void delete(IJavaElement[] elements) throws CoreException { |
| for (IJavaElement element : elements) { |
| delete(element); |
| } |
| } |
| |
| public void delete(IJavaElement element) throws CoreException { |
| switch(element.getElementType()) { |
| case IJavaElement.JAVA_MODEL: |
| return; |
| case IJavaElement.JAVA_PROJECT: |
| fDelete.add(element); |
| if (element.getResource() != null) |
| getResourceModifications().addDelete(element.getResource()); |
| return; |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
| fDelete.add(element); |
| IResource resource= element.getResource(); |
| // Flag an resource change even if we have an archive. If it is |
| // internal (we have a underlying resource then we have a resource |
| // change. |
| if (resource != null) |
| getResourceModifications().addDelete(resource); |
| for (IJavaProject referencingProject : JavaElementUtil.getReferencingProjects((IPackageFragmentRoot) element)) { |
| IFile classpath= referencingProject.getProject().getFile(".classpath"); //$NON-NLS-1$ |
| getResourceModifications().addChanged(classpath); |
| } |
| return; |
| case IJavaElement.PACKAGE_FRAGMENT: |
| fDelete.add(element); |
| fPackagesToDelete.add((IPackageFragment) element); |
| return; |
| case IJavaElement.COMPILATION_UNIT: |
| fDelete.add(element); |
| IType[] types= ((ICompilationUnit)element).getTypes(); |
| fDelete.addAll(Arrays.asList(types)); |
| if (element.getResource() != null) |
| getResourceModifications().addDelete(element.getResource()); |
| return; |
| default: |
| fDelete.add(element); |
| } |
| |
| } |
| |
| /** |
| * @return a List of IResources that are removed by package deletes |
| * @throws CoreException if accessing package structure of packages to delete fails |
| */ |
| public List<IResource> postProcess() throws CoreException { |
| return postProcess(new NullProgressMonitor()); |
| } |
| |
| /** |
| * @param monitor may be null |
| * @return a List of IResources that are removed by package deletes |
| * @throws CoreException if accessing package structure of packages to delete fails |
| */ |
| public List<IResource> postProcess(IProgressMonitor monitor) throws CoreException { |
| String taskName= RefactoringCoreMessages.DeleteRefactoring_progress_collecting_resources; |
| SubMonitor subMonitor= SubMonitor.convert(monitor, taskName, fPackagesToDelete.size()); |
| |
| IsCompletelySelected isCompletelySelected = new IsCompletelySelected(fPackagesToDelete, subMonitor); |
| |
| ArrayList<IResource> resourcesCollector= new ArrayList<>(); |
| for (IPackageFragment pack : fPackagesToDelete) { |
| subMonitor.checkCanceled(); |
| handlePackageFragmentDelete(pack, resourcesCollector, isCompletelySelected); |
| subMonitor.worked(1); |
| } |
| return resourcesCollector; |
| } |
| |
| @Override |
| public void buildDelta(IResourceChangeDescriptionFactory deltaFactory) { |
| getResourceModifications().buildDelta(deltaFactory); |
| } |
| |
| @Override |
| public RefactoringParticipant[] loadParticipants(RefactoringStatus status, RefactoringProcessor owner, String[] natures, SharableParticipants shared) { |
| List<RefactoringParticipant> result= new ArrayList<>(); |
| for (IJavaElement javaElement : fDelete) { |
| result.addAll(Arrays.asList(ParticipantManager.loadDeleteParticipants(status, |
| owner, javaElement, |
| new DeleteArguments(), natures, shared))); |
| } |
| result.addAll(Arrays.asList(getResourceModifications().getParticipants(status, owner, natures, shared))); |
| return result.toArray(new RefactoringParticipant[result.size()]); |
| } |
| |
| /** |
| * This method collects file and folder deletion for notifying |
| * participants. Participants will get notified of |
| * |
| * * deletion of the package (in any case) |
| * * deletion of files within the package if only the files are deleted without |
| * the package folder ("package cleaning") |
| * * deletion of the package folder if it is not only cleared and if its parent |
| * is not removed as well. |
| * |
| * All deleted resources are added to <code>resourcesCollector</code> |
| * @param pack the package |
| * @param isCompletelySelected predicate which states whether all sub-packages of a package are to be deleted |
| * |
| * @param resourcesCollector a collector for IResources to be deleted |
| * @throws CoreException if accessing package structure of {@code pack} fails |
| */ |
| private void handlePackageFragmentDelete(IPackageFragment pack, ArrayList<IResource> resourcesCollector, IsCompletelySelected isCompletelySelected) throws CoreException { |
| final IContainer container= (IContainer)pack.getResource(); |
| if (container == null) |
| return; |
| |
| final IResource[] members= container.members(); |
| |
| /* |
| * Check whether this package is removed completely or only cleared. |
| * The default package can never be removed completely. |
| */ |
| if (!pack.isDefaultPackage() && isCompletelySelected.test(pack)) { |
| // This package is removed completely, which means its folder will be |
| // deleted as well. We only notify participants of the folder deletion |
| // if the parent folder of this folder will not be deleted as well: |
| boolean parentIsMarked= false; |
| final IPackageFragment parent= JavaElementUtil.getParentSubpackage(pack); |
| if (parent == null) { |
| // "Parent" is the default package which will never be |
| // deleted physically |
| parentIsMarked= false; |
| } else { |
| // Parent is marked if it is in the list |
| parentIsMarked= fPackagesToDelete.contains(parent); |
| } |
| |
| if (parentIsMarked) { |
| // Parent is marked, but is it really deleted or only cleared? |
| if (isCompletelySelected.test(parent)) { |
| // Parent can be removed completely, so we do not add |
| // this folder to the list. |
| } else { |
| // Parent cannot be removed completely, but as this folder |
| // can be removed, we notify the participant |
| resourcesCollector.add(container); |
| getResourceModifications().addDelete(container); |
| } |
| } else { |
| // Parent will not be removed, but we will |
| resourcesCollector.add(container); |
| getResourceModifications().addDelete(container); |
| } |
| } else { |
| // This package is only cleared because it has subpackages (=subfolders) |
| // which are not deleted. As the package is only cleared, its folder |
| // will not be removed and so we must notify the participant of the deleted children. |
| for (IResource member : members) { |
| if (member instanceof IFile) { |
| IFile file= (IFile)member; |
| if ("class".equals(file.getFileExtension()) && file.isDerived()) //$NON-NLS-1$ |
| continue; |
| if (pack.isDefaultPackage() && ! JavaCore.isJavaLikeFileName(file.getName())) |
| continue; |
| resourcesCollector.add(member); |
| getResourceModifications().addDelete(member); |
| } |
| if (!pack.isDefaultPackage() && member instanceof IFolder) { |
| // Normally, folder children of packages are packages |
| // as well, but in case they have been removed from the build |
| // path, notify the participant |
| IPackageFragment frag= (IPackageFragment) JavaCore.create(member); |
| if (frag == null) { |
| resourcesCollector.add(member); |
| getResourceModifications().addDelete(member); |
| } |
| } |
| } |
| } |
| } |
| } |