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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* Copyright (c) 2000, 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -12,11 +12,14 @@
* IBM Corporation - initial API and implementation
* Andrey Loskutov <loskutov@gmx.de> - Bug 41431, 462760, 461786
* Lucas Bullen (Red Hat Inc.) - Bug 522096 - "Close Projects" on working set
* Lars Vogel <Lars.Vogel@vogella.com> - ask before closing nested projects
*******************************************************************************/
package org.eclipse.ui.actions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import org.eclipse.core.resources.IFile;
Expand All @@ -31,14 +34,20 @@
import org.eclipse.core.resources.mapping.ResourceChangeValidator;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
Expand All @@ -48,7 +57,9 @@
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
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;

/**
Expand All @@ -71,6 +82,9 @@ public class CloseResourceAction extends WorkspaceAction implements IResourceCha

private String[] modelProviderIds;

/** Projects the last {@link #run()} decided to close, may be wider than the selection. */
private List<? extends IResource> projectsToClose;

/**
* Creates a new action.
*
Expand Down Expand Up @@ -186,6 +200,13 @@ public void run() {
return;
}

projects = promptForProjectsToClose(projects);
if (projects == null) {
// the user cancelled the operation
return;
}
projectsToClose = projects;

final IResource[] projectArray = projects.toArray(new IResource[projects.size()]);

if (!IDE.saveAllEditors(projectArray, true)) {
Expand Down Expand Up @@ -219,6 +240,120 @@ protected boolean shouldPerformResourcePruning() {
return false;
}

@Override
protected List<? extends IResource> getActionResources() {
if (projectsToClose != null) {
return projectsToClose;
}
return super.getActionResources();
}

/**
* Offers to close open projects nested below the selected ones, unless the
* preference already decides.
*
* @return the projects to close, or <code>null</code> if the user cancelled
*/
private List<? extends IResource> promptForProjectsToClose(List<? extends IResource> projects) {
if (!promptForRelatedProjects()) {
return projects;
}
List<IProject> nestedProjects = computeNestedOpenProjects(projects);
if (nestedProjects.isEmpty()) {
return projects;
}
IPreferenceStore store = IDEWorkbenchPlugin.getDefault().getPreferenceStore();
String key = IDEInternalPreferences.CLOSE_NESTED_PROJECTS;
String value = store.getString(key);
if (IDEInternalPreferences.PSPM_NEVER.equals(value)) {
return projects;
}
if (!IDEInternalPreferences.PSPM_ALWAYS.equals(value)) {
// the map fixes the button ids, so the toggle stores ALWAYS or NEVER
LinkedHashMap<String, Integer> buttons = new LinkedHashMap<>();
buttons.put(IDEWorkbenchMessages.CloseResourceAction_closeSelectedOnly,
Integer.valueOf(IDialogConstants.NO_ID));
buttons.put(IDEWorkbenchMessages.CloseResourceAction_closeIncludingNested,
Integer.valueOf(IDialogConstants.YES_ID));
buttons.put(IDialogConstants.CANCEL_LABEL, Integer.valueOf(IDialogConstants.CANCEL_ID));
MessageDialogWithToggle dialog = MessageDialogWithToggle.open(MessageDialog.QUESTION,
getShell(), IDEWorkbenchMessages.CloseResourceAction_nestedTitle,
nestedMessage(projects, nestedProjects), null, false, store, key, SWT.SHEET, buttons);
switch (dialog.getReturnCode()) {
case IDialogConstants.YES_ID:
break;
case IDialogConstants.NO_ID:
return projects;
default:
return null;
}
}
List<IResource> allProjects = new ArrayList<>(projects);
allProjects.addAll(nestedProjects);
return allProjects;
}

/**
* @return the question asked when the selection nests further open projects
*/
private static String nestedMessage(List<? extends IResource> projects, List<IProject> nestedProjects) {
boolean oneProject = projects.size() == 1;
if (nestedProjects.size() == 1) {
return oneProject
? NLS.bind(IDEWorkbenchMessages.CloseResourceAction_closeOneNestedBelowProject,
projects.get(0).getName())
: IDEWorkbenchMessages.CloseResourceAction_closeOneNestedBelowSelection;
}
Integer count = Integer.valueOf(nestedProjects.size());
return oneProject
? NLS.bind(IDEWorkbenchMessages.CloseResourceAction_closeNestedBelowProject, count,
projects.get(0).getName())
: NLS.bind(IDEWorkbenchMessages.CloseResourceAction_closeNestedBelowSelection, count);
}

/**
* @return <code>true</code> to ask about projects implied by the selection but
* not part of it. Subclasses computing and confirming the projects to
* close themselves answer <code>false</code>.
*/
boolean promptForRelatedProjects() {
return true;
}

/**
* @param projects the projects the user selected
* @return the open projects located inside the given ones, but not among them
*/
private static List<IProject> computeNestedOpenProjects(List<? extends IResource> projects) {
List<IPath> locations = new ArrayList<>(projects.size());
for (IResource project : projects) {
IPath location = project.getLocation();
if (location != null) {
locations.add(location);
}
}
if (locations.isEmpty()) {
return Collections.emptyList();
}
List<IProject> nestedProjects = new ArrayList<>();
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
if (!project.isOpen() || projects.contains(project)) {
continue;
}
IPath location = project.getLocation();
if (location == null) {
continue;
}
for (IPath selected : locations) {
if (!selected.equals(location) && selected.isPrefixOf(location)) {
nestedProjects.add(project);
break;
}
}
}
return nestedProjects;
}

/**
* The <code>CloseResourceAction</code> implementation of this
* <code>SelectionListenerAction</code> method ensures that this action is
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2017 IBM Corporation and others.
* Copyright (c) 2006, 2026 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -14,6 +14,7 @@
* Andrey Loskutov <loskutov@gmx.de> - generified interface, bug 462760
* Mickael Istria (Red Hat Inc.) - Bug 486901
* Lucas Bullen (Red Hat Inc.) - Bug 522096 - "Close Projects" on working set
* Lars Vogel <Lars.Vogel@vogella.com> - ask before closing nested projects
*******************************************************************************/
package org.eclipse.ui.actions;

Expand Down Expand Up @@ -113,6 +114,15 @@ public void run() {
}
}

/**
* The projects to close come from the project graph, not from the selection,
* and {@link #promptForConfirmation()} already confirms them.
*/
@Override
boolean promptForRelatedProjects() {
return false;
}

/**
* Rebuilds the project graph before the projects to close are computed from it.
* Enablement may answer from a stale graph, but closing projects should not. A
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public interface IDEInternalPreferences {
*/
String CLOSE_UNRELATED_PROJECTS = "CLOSE_UNRELATED_PROJECTS"; //$NON-NLS-1$

/**
* (String) Whether to close projects nested below a project that is closed.
*/
String CLOSE_NESTED_PROJECTS = "CLOSE_NESTED_PROJECTS"; //$NON-NLS-1$

String PSPM_PROMPT = MessageDialogWithToggle.PROMPT;

String PSPM_ALWAYS = MessageDialogWithToggle.ALWAYS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public void initializeDefaultPreferences() {
node.put(IDEInternalPreferences.OPEN_REQUIRED_PROJECTS,
IDEInternalPreferences.PSPM_PROMPT);
node.putBoolean(IDEInternalPreferences.CLOSE_UNRELATED_PROJECTS, false);
node.put(IDEInternalPreferences.CLOSE_NESTED_PROJECTS, IDEInternalPreferences.PSPM_PROMPT);

node.putBoolean(IDEInternalPreferences.WARN_ABOUT_WORKSPACE_INCOMPATIBILITY, true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,13 @@ public class IDEWorkbenchMessages extends NLS {
public static String CloseResourceAction_problemMessage;
public static String CloseResourceAction_operationMessage;
public static String CloseResourceAction_operationMessage_plural;
public static String CloseResourceAction_nestedTitle;
public static String CloseResourceAction_closeOneNestedBelowProject;
public static String CloseResourceAction_closeNestedBelowProject;
public static String CloseResourceAction_closeOneNestedBelowSelection;
public static String CloseResourceAction_closeNestedBelowSelection;
public static String CloseResourceAction_closeIncludingNested;
public static String CloseResourceAction_closeSelectedOnly;

public static String CloseUnrelatedProjectsAction_text;
public static String CloseUnrelatedProjectsAction_text_plural;
Expand Down Expand Up @@ -562,6 +569,7 @@ public class IDEWorkbenchMessages extends NLS {
public static String IDEWorkspacePreference_otherLineDelim;
public static String IDEWorkspacePreference_relatedLink;
public static String IDEWorkspacePreference_openReferencedProjects;
public static String IDEWorkspacePreference_closeNestedProjects;
public static String IDEWorkspacePreference_closeUnrelatedProjectsToolTip;
public static String IDEWorkspacePreference_windowTitleGroupText;
public static String IDEWorkspacePreference_showLocationInWindowTitle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ public class IDEWorkspacePreferencePage extends PreferencePage implements IWorkb

private ComboFieldEditor openReferencesEditor;

private ComboFieldEditor closeNestedEditor;

private StringFieldEditor systemExplorer;

private ComboFieldEditor missingNatureSeverityCombo;
Expand Down Expand Up @@ -144,6 +146,7 @@ protected Control createContents(Composite parent) {
Composite comboParent = new Composite(composite, SWT.NONE);
comboParent.setLayout(new GridLayout(2, false));
createOpenPrefControls(comboParent);
createCloseNestedPrefControls(comboParent);
createMissingNaturePref(comboParent);
createMissingEncodingPref(comboParent);

Expand Down Expand Up @@ -236,6 +239,22 @@ private void createOpenPrefControls(Composite parent) {
openReferencesEditor.load();
}

/**
* Creates controls for the preference to close nested projects.
*/
private void createCloseNestedPrefControls(Composite parent) {
String name = IDEInternalPreferences.CLOSE_NESTED_PROJECTS;
String label = IDEWorkbenchMessages.IDEWorkspacePreference_closeNestedProjects;
String[][] namesAndValues = {
{ Action.removeMnemonics(IDEWorkbenchMessages.Always), IDEInternalPreferences.PSPM_ALWAYS },
{ Action.removeMnemonics(IDEWorkbenchMessages.Never), IDEInternalPreferences.PSPM_NEVER },
{ Action.removeMnemonics(IDEWorkbenchMessages.Prompt), IDEInternalPreferences.PSPM_PROMPT } };
closeNestedEditor = new ComboFieldEditorInGrid(name, label, namesAndValues, parent);
closeNestedEditor.setPreferenceStore(getIDEPreferenceStore());
closeNestedEditor.setPage(this);
closeNestedEditor.load();
}

/**
* Creates controls for the preference to close unrelated projects.
* @param parent The parent control
Expand Down Expand Up @@ -562,6 +581,7 @@ protected void performDefaults() {
encodingEditor.loadDefault();
lineSeparatorEditor.loadDefault();
openReferencesEditor.loadDefault();
closeNestedEditor.loadDefault();
missingNatureSeverityCombo.loadDefault();
missingEncodingSeverityCombo.loadDefault();

Expand Down Expand Up @@ -628,6 +648,7 @@ public boolean performOk() {
encodingEditor.store();
lineSeparatorEditor.store();
openReferencesEditor.store();
closeNestedEditor.store();
missingNatureSeverityCombo.store();
missingEncodingSeverityCombo.store();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@ CloseResourceAction_title = Close Problems
CloseResourceAction_problemMessage = Problems occurred closing the selected resources.
CloseResourceAction_operationMessage = Closing project...
CloseResourceAction_operationMessage_plural = Closing projects...
CloseResourceAction_nestedTitle = Close Nested Projects
CloseResourceAction_closeOneNestedBelowProject = Also close 1 nested project below ''{0}''?
CloseResourceAction_closeNestedBelowProject = Also close {0} nested projects below ''{1}''?
CloseResourceAction_closeOneNestedBelowSelection = Also close 1 nested project below the selected projects?
CloseResourceAction_closeNestedBelowSelection = Also close {0} nested projects below the selected projects?
CloseResourceAction_closeIncludingNested = Close &Including Nested
CloseResourceAction_closeSelectedOnly = Close &Selected Only

CloseUnrelatedProjectsAction_text = Close &Unrelated Project
CloseUnrelatedProjectsAction_text_plural = Close &Unrelated Projects
Expand Down Expand Up @@ -539,6 +546,7 @@ IDEWorkspacePreference_defaultLineDelimProj=Inh&erited from container ({0})
IDEWorkspacePreference_otherLineDelim= Ot&her:
IDEWorkspacePreference_relatedLink = See <a>{0}</a> for workspace startup and shutdown preferences.
IDEWorkspacePreference_openReferencedProjects = Open referenced projects when a project is opened:
IDEWorkspacePreference_closeNestedProjects = Close nested projects when a project is closed:
IDEWorkspacePreference_closeUnrelatedProjectsToolTip = Close unrelated projects without prompt
IDEWorkspacePreference_windowTitleGroupText=Window title
IDEWorkspacePreference_showLocationInWindowTitle=Show &full workspace path:
Expand Down
Loading
Loading