Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ui/org.eclipse.pde.ui/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ rename.type.participant = Manifest Rename Type Participant
rename.package.participant = Manifest Rename Package Participant
move.type.participant = Manifest Move Type Participant
move.package.participant = Manifest Move Package Participant
delete.type.participant = Manifest Delete Type Participant

queryParticipant.name.0 = PDE Java Search Participant
new.profile.name = Target Definition
Expand Down
16 changes: 16 additions & 0 deletions ui/org.eclipse.pde.ui/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,22 @@
</enablement>
</renameParticipant>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.deleteParticipants">
<deleteParticipant
class="org.eclipse.pde.internal.ui.refactoring.ManifestTypeDeleteParticipant"
id="org.eclipse.pde.ui.manifestTypeDeleteParticipant"
name="%delete.type.participant">
<enablement>
<with
variable="element">
<instanceof
value="org.eclipse.jdt.core.IType">
</instanceof>
</with>
</enablement>
</deleteParticipant>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.moveParticipants">
<moveParticipant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2389,6 +2389,8 @@ public class PDEUIMessages extends NLS {

public static String ManifestTypeRenameParticipant_composite;

public static String ManifestTypeDeleteParticipant_composite;

public static String LauncherPage_title;

public static String WindowImagesSection_16;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ MainPreferencePage_test_plugin_pattern_note=This pattern is matched against the
ManifestEditorContributor_externStringsActionName=Externalize Strings...

ManifestTypeRenameParticipant_composite=Rename classes referenced in plug-in manifest files
ManifestTypeDeleteParticipant_composite=Delete classes referenced in plug-in manifest files

ManifestEditor_MatchSection_optional = Optional
ManifestEditor_MatchSection_reexport = Re-export the dependency
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*******************************************************************************
* Copyright (c) 2026 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.pde.internal.ui.refactoring;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.pde.internal.core.WorkspaceModelManager;
import org.eclipse.pde.internal.core.project.PDEProject;
import org.eclipse.pde.internal.ui.PDEUIMessages;

public class ManifestTypeDeleteParticipant extends PDEDeleteParticipant {

@Override
protected boolean initialize(Object element) {
if (element instanceof IType type) {
IJavaProject javaProject = (IJavaProject) type.getAncestor(IJavaElement.JAVA_PROJECT);
IProject project = javaProject.getProject();
if (WorkspaceModelManager.isPluginProject(project)) {
fProject = javaProject.getProject();
fElements = new HashMap<>();
fElements.put(element, type.getFullyQualifiedName());
return true;
}
}
return false;
}

@Override
public String getName() {
return PDEUIMessages.ManifestTypeDeleteParticipant_composite;
}

@Override
protected void addChange(CompositeChange result, IProgressMonitor pm) throws CoreException {
IFile file = PDEProject.getManifest(fProject);
if (!file.exists()) {
return;
}

Map<IPackageFragment, List<IType>> deletedByPackage = new HashMap<>();
fElements.forEach((element, fullyQualifiedName) -> {
if (element instanceof IType type) {
IPackageFragment pkg = type.getPackageFragment();
deletedByPackage.computeIfAbsent(pkg, k -> new ArrayList<>()).add(type);
}
});
// Check each package to see if it becomes empty after deletion
for (Map.Entry<IPackageFragment, List<IType>> entry : deletedByPackage.entrySet()) {
IPackageFragment pkg = entry.getKey();
List<IType> deletedTypes = entry.getValue();

try {
if (willPackageBeEmpty(pkg, deletedTypes)) {
Change change = BundleManifestChange.createEmptyPackageChange(file, pkg.getElementName(), pm);
if (change != null) {
result.add(change);
}
}
} catch (CoreException e) {
e.printStackTrace();
}
}
}

/**
* Checks if a package will be empty after deleting the specified types.
* @param pkg the package to check
* @param deletedTypes the types being deleted
* @return true if the package will be empty after deletion
* @throws CoreException if an error occurs accessing package contents
*/
private boolean willPackageBeEmpty(IPackageFragment pkg, List<IType> deletedTypes) throws CoreException {
IJavaElement[] javaChildren = pkg.getChildren();
if (javaChildren.length > deletedTypes.size()) {
return false;
}
// Check for non-Java resources (properties files, XML files, etc.)
Object[] nonJavaResources = pkg.getNonJavaResources();
if (nonJavaResources != null && nonJavaResources.length > 0) {
return false;
}

Set<String> deletedJavaFileNames = new HashSet<>();
for (IType type : deletedTypes) {
// Get the compilation unit (the .java file) containing this type
if (type.getCompilationUnit() != null) {
deletedJavaFileNames.add(type.getCompilationUnit().getElementName());
}
}
// Check the underlying folder for any OTHER files
IResource resource = pkg.getCorrespondingResource();
if (resource instanceof IFolder folder) {
IResource[] members = folder.members();
for (IResource member : members) {
if (member instanceof IFile memberFile) {
String fileName = memberFile.getName();
String extension = memberFile.getFileExtension();
if ("class".equals(extension)) { //$NON-NLS-1$
continue;
}
if ("java".equals(extension) && deletedJavaFileNames.contains(fileName)) { //$NON-NLS-1$
continue;
}
return false;
}
}
}
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (c) 2026 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.pde.internal.ui.refactoring;

import java.util.HashMap;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
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.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.DeleteParticipant;
import org.eclipse.ltk.core.refactoring.participants.ISharableParticipant;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;

public abstract class PDEDeleteParticipant extends DeleteParticipant implements ISharableParticipant {

protected IProject fProject;
protected HashMap<Object, String> fElements;

@Override
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
throws OperationCanceledException {
return new RefactoringStatus();
}

@Override
public void addElement(Object element, RefactoringArguments arguments) {
if (element instanceof IType type) {
fElements.put(element, type.getFullyQualifiedName());
} else if (element instanceof IPackageFragment pkg) {
fElements.put(element, pkg.getElementName());
}
}

@Override
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
CompositeChange result = new CompositeChange(getName());
addChange(result, pm);
return (result.getChildren().length == 0) ? null : result;
}

/**
* @throws CoreException may be thrown by overrides
*/
protected abstract void addChange(CompositeChange result, IProgressMonitor pm) throws CoreException;

}
Loading