Skip to content
Closed
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
2 changes: 2 additions & 0 deletions ui/org.eclipse.pde.ui/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ 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
delete.package.participant = Manifest Delete Package Participant

queryParticipant.name.0 = PDE Java Search Participant
new.profile.name = Target Definition
Expand Down
32 changes: 32 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,38 @@
</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.deleteParticipants">
<deleteParticipant
class="org.eclipse.pde.internal.ui.refactoring.ManifestPackageDeleteParticipant"
id="org.eclipse.pde.ui.manifestPackageDeleteParticipant"
name="%delete.package.participant">
<enablement>
<with
variable="element">
<instanceof
value="org.eclipse.jdt.core.IPackageFragment">
</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,10 @@ public class PDEUIMessages extends NLS {

public static String ManifestTypeRenameParticipant_composite;

public static String ManifestTypeDeleteParticipant_composite;

public static String ManifestPackageDeleteParticipant_packageDelete;

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,8 @@ 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
ManifestPackageDeleteParticipant_packageDelete=Delete packages 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
Expand Up @@ -101,6 +101,58 @@ public static Change createEmptyPackageChange(IFile file, String packageName, IP
return null;
}

public static Change createMultiplePackageDeleteChange(IFile file, Object[] elements, IProgressMonitor monitor)
throws CoreException {
ArrayList<String> packageNames = new ArrayList<>();
for (Object element : elements) {
if (element instanceof IPackageFragment pkg) {
packageNames.add(pkg.getElementName());
}
}

if (packageNames.isEmpty()) {
return null;
}

if (packageNames.size() == 1) {
return createEmptyPackageChange(file, packageNames.get(0), monitor);
}

try {
Bundle bundle = getBundle(file, monitor);
if (bundle == null) {
return null;
}

BundleModel model = (BundleModel) bundle.getModel();
BundleTextChangeListener listener = new BundleTextChangeListener(model.getDocument());
bundle.getModel().addModelChangedListener(listener);

BasePackageHeader header = (BasePackageHeader) bundle.getManifestHeader(Constants.EXPORT_PACKAGE);
if (header != null) {
for (String packageName : packageNames) {
if (header.hasPackage(packageName)) {
removePackage(header, packageName);
}
}
}

TextEdit[] operations = listener.getTextOperations();
if (operations.length > 0) {
TextFileChange change = new TextFileChange("", file); //$NON-NLS-1$
MultiTextEdit multi = new MultiTextEdit();
multi.addChildren(operations);
change.setEdit(multi);
PDEModelUtility.setChangeTextType(change, file);
return change;
}
} catch (CoreException | MalformedTreeException e) {
} finally {
FileBuffers.getTextFileBufferManager().disconnect(file.getFullPath(), LocationKind.NORMALIZE, monitor);
}
return null;
}

public static MoveFromChange createMovePackageChange(IFile file, Object[] elements, IProgressMonitor monitor) throws CoreException {
try {
Bundle bundle = getBundle(file, monitor);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*******************************************************************************
* 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.IFile;
import org.eclipse.core.resources.IProject;
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.JavaModelException;
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 ManifestPackageDeleteParticipant extends PDEDeleteParticipant {

@Override
protected boolean initialize(Object element) {
try {
if (element instanceof IPackageFragment fragment) {
if (!fragment.containsJavaResources()) {
return false;
}
IJavaProject javaProject = (IJavaProject) fragment.getAncestor(IJavaElement.JAVA_PROJECT);
IProject project = javaProject.getProject();
if (WorkspaceModelManager.isPluginProject(project)) {
fProject = javaProject.getProject();
fElements = new HashMap<>();
fElements.put(fragment, fragment.getElementName());
return true;
}
}
} catch (JavaModelException e) {
// Log error but return false to skip this participant
}
return false;
}

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

@Override
protected void addChange(CompositeChange result, IProgressMonitor pm) throws CoreException {
IFile file = PDEProject.getManifest(fProject);
if (file.exists()) {
Change change = BundleManifestChange.createMultiplePackageDeleteChange(file, fElements.keySet().toArray(), pm);
if (change != null) {
result.add(change);
}
}
}

}
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;
}

}
Loading
Loading