Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Code to Introduce Asynchronous Computation of Connected Compo… #2638

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,24 @@

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDEActionFactory;
import org.eclipse.ui.internal.ide.IDEInternalPreferences;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.internal.ide.misc.DisjointSet;
import org.eclipse.core.runtime.jobs.Job;

/**
* This action closes all projects that are unrelated to the selected projects. A
Expand All @@ -66,37 +67,39 @@ public class CloseUnrelatedProjectsAction extends CloseResourceAction {

private List<? extends IResource> oldSelection = Collections.emptyList();


/**
* Builds the connected component set for the input projects.
* The result is a DisjointSet where all related projects belong
* to the same set.
*/
private static DisjointSet<IProject> buildConnectedComponents(IProject[] projects) {
//initially each vertex is in a set by itself
DisjointSet<IProject> set = new DisjointSet<>();
for (IProject project : projects) {
set.makeSet(project);
}
for (IProject project : projects) {
try {
IProject[] references = project.getReferencedProjects();
//each reference represents an edge in the project reference
//digraph from projects[i] -> references[j]
for (IProject reference : references) {
IProject setOne = set.findSet(project);
//note that referenced projects may not exist in the workspace
IProject setTwo = set.findSet(reference);
//these two projects are related, so join their sets
if (setOne != null && setTwo != null && setOne != setTwo) {
set.union(setOne, setTwo);
private static void buildConnectedComponentsInBackground(IProject[] projects, Runnable onComplete) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private static void buildConnectedComponentsInBackground(IProject[] projects, Runnable onComplete) {
private static CompletableFuture<DisjointSet<IProject>> buildConnectedComponentsInBackground(IProject[] projects) {

Job job = new Job("Compute Connected Components") {
@Override
protected IStatus run(IProgressMonitor monitor) {
DisjointSet<IProject> set = new DisjointSet<>();
for (IProject project : projects) {
set.makeSet(project);
}
for (IProject project : projects) {
try {
IProject[] references = project.getReferencedProjects();
for (IProject reference : references) {
IProject setOne = set.findSet(project);
IProject setTwo = set.findSet(reference);
if (setOne != null && setTwo != null && setOne != setTwo) {
set.union(setOne, setTwo);
}
}
} catch (CoreException e) {
// Assume inaccessible projects have no references
}
}
} catch (CoreException e) {
//assume inaccessible projects have no references
Display.getDefault().asyncExec(onComplete);
return Status.OK_STATUS;
}
}
return set;
};
job.setPriority(Job.LONG);
job.schedule();
}

/**
Expand All @@ -122,7 +125,7 @@ public CloseUnrelatedProjectsAction(Shell shell) {
* action.
* @since 3.4
*/
public CloseUnrelatedProjectsAction(IShellProvider provider){
public CloseUnrelatedProjectsAction(IShellProvider provider) {
super(provider, IDEWorkbenchMessages.CloseUnrelatedProjectsAction_text,
IDEWorkbenchMessages.CloseUnrelatedProjectsAction_toolTip,
IDEWorkbenchMessages.CloseUnrelatedProjectsAction_text_plural,
Expand Down Expand Up @@ -150,39 +153,38 @@ private boolean promptForConfirmation() {
return true;
}

// get first project name
List<? extends IResource> selection = super.getSelectedResources();
int selectionSize = selection.size();
if (selectionSize == 0) {
return true;
}

String message = null;
if (selectionSize == 1) { // if one project is selected then print its name
if (selectionSize == 1) {
IResource firstSelected = selection.get(0);
String projectName = null;
if (firstSelected instanceof IProject) {
projectName = firstSelected.getName();
}
String projectName = (firstSelected instanceof IProject) ? firstSelected.getName() : null;
message = NLS.bind(IDEWorkbenchMessages.CloseUnrelatedProjectsAction_confirmMsg1, projectName);
} else // if more then one project is selected then print there number
} else {
message = NLS.bind(IDEWorkbenchMessages.CloseUnrelatedProjectsAction_confirmMsgN, selectionSize);
}

MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm(
getShell(), IDEWorkbenchMessages.CloseUnrelatedProjectsAction_toolTip,
message, IDEWorkbenchMessages.CloseUnrelatedProjectsAction_AlwaysClose,
false, null, null);

MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm(
getShell(), IDEWorkbenchMessages.CloseUnrelatedProjectsAction_toolTip,
message, IDEWorkbenchMessages.CloseUnrelatedProjectsAction_AlwaysClose,
false, null, null);
if (dialog.getReturnCode() != IDialogConstants.OK_ID) {
return false;
}

store.setValue(IDEInternalPreferences.CLOSE_UNRELATED_PROJECTS, dialog.getToggleState());
return true;
}

/**
* Initializes for the constructor.
*/
private void initAction(){
private void initAction() {
setId(ID);
setToolTipText(IDEWorkbenchMessages.CloseUnrelatedProjectsAction_toolTip);
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IIDEHelpContextIds.CLOSE_UNRELATED_PROJECTS_ACTION);
Expand All @@ -195,28 +197,6 @@ protected void clearCache() {
selectionDirty = true;
}

/**
* Computes the related projects of the selection.
*/
private List<IResource> computeRelated(List<? extends IResource> selection) {
if (selection.contains(ResourcesPlugin.getWorkspace().getRoot())) {
return new ArrayList<>();
}
//build the connected component set for all projects in the workspace
DisjointSet<IProject> set = buildConnectedComponents(ResourcesPlugin.getWorkspace().getRoot().getProjects());
//remove the connected components that the selected projects are in
for (IResource resource : selection) {
IProject project = resource.getProject();
if (project != null) {
set.removeSet(project);
}
}
//the remainder of the projects in the disjoint set are unrelated to the selection
List<IResource> projects = new ArrayList<>();
set.toList(projects);
return projects;
}

@Override
protected List<? extends IResource> getSelectedResources() {
if (selectionDirty) {
Expand All @@ -230,28 +210,21 @@ protected List<? extends IResource> getSelectedResources() {
return projectsToClose;
}

/**
* Handles a resource changed event by updating the enablement
* when projects change.
* <p>
* This method overrides the super-type implementation to update
* the selection when the open state or description of any project changes.
*/
@Override
public void resourceChanged(IResourceChangeEvent event) {
// don't bother looking at delta if selection not applicable
if (selectionIsOfType(IResource.PROJECT)) {
IResourceDelta delta = event.getDelta();
if (delta != null) {
IResourceDelta[] projDeltas = delta.getAffectedChildren(IResourceDelta.CHANGED);
for (IResourceDelta projDelta : projDeltas) {
//changing either the description or the open state can affect enablement
if ((projDelta.getFlags() & (IResourceDelta.OPEN | IResourceDelta.DESCRIPTION)) != 0) {
selectionChanged(getStructuredSelection());
return;
}
private List<IResource> computeRelated(List<? extends IResource> selection) {
if (selection.contains(ResourcesPlugin.getWorkspace().getRoot())) {
return new ArrayList<>();
}
List<IResource> projects = new ArrayList<>();
buildConnectedComponentsInBackground(ResourcesPlugin.getWorkspace().getRoot().getProjects(), () -> {
DisjointSet<IProject> set = buildConnectedComponents(ResourcesPlugin.getWorkspace().getRoot().getProjects());
for (IResource resource : selection) {
IProject project = resource.getProject();
if (project != null) {
set.removeSet(project);
}
}
}
set.toList(projects);
});
return projects;
}
}