001: /*******************************************************************************
002: * Copyright (c) 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: ******************************************************************************/package org.eclipse.ui.actions;
011:
012: import java.util.ArrayList;
013: import java.util.Collections;
014: import java.util.Iterator;
015: import java.util.List;
016: import org.eclipse.core.resources.IProject;
017: import org.eclipse.core.resources.IResource;
018: import org.eclipse.core.resources.IResourceChangeEvent;
019: import org.eclipse.core.resources.IResourceDelta;
020: import org.eclipse.core.resources.ResourcesPlugin;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.swt.widgets.Shell;
023: import org.eclipse.ui.PlatformUI;
024: import org.eclipse.ui.ide.IDEActionFactory;
025: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
026: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
027: import org.eclipse.ui.internal.ide.misc.DisjointSet;
028:
029: /**
030: * This action closes all projects that are unrelated to the selected projects. A
031: * project is unrelated if it is not directly or transitively referenced by one
032: * of the selected projects, and does not directly or transitively reference
033: * one of the selected projects.
034: * <p>
035: * This class may be instantiated; it is not intended to be subclassed.
036: * </p>
037: *
038: * @see IDEActionFactory#CLOSE_UNRELATED_PROJECTS
039: * @since 3.3
040: */
041: public class CloseUnrelatedProjectsAction extends CloseResourceAction {
042: /**
043: * The id of this action.
044: */
045: public static final String ID = PlatformUI.PLUGIN_ID
046: + ".CloseUnrelatedProjectsAction"; //$NON-NLS-1$
047:
048: private final List projectsToClose = new ArrayList();
049:
050: private boolean selectionDirty = true;
051:
052: private List oldSelection = Collections.EMPTY_LIST;
053:
054: /**
055: * Builds the connected component set for the input projects.
056: * The result is a DisjointSet where all related projects belong
057: * to the same set.
058: */
059: private static DisjointSet buildConnectedComponents(
060: IProject[] projects) {
061: //initially each vertex is in a set by itself
062: DisjointSet set = new DisjointSet();
063: for (int i = 0; i < projects.length; i++) {
064: set.makeSet(projects[i]);
065: }
066: for (int i = 0; i < projects.length; i++) {
067: try {
068: IProject[] references = projects[i]
069: .getReferencedProjects();
070: //each reference represents an edge in the project reference
071: //digraph from projects[i] -> references[j]
072: for (int j = 0; j < references.length; j++) {
073: Object setOne = set.findSet(projects[i]);
074: //note that referenced projects may not exist in the workspace
075: Object setTwo = set.findSet(references[j]);
076: //these two projects are related, so join their sets
077: if (setOne != null && setTwo != null
078: && setOne != setTwo)
079: set.union(setOne, setTwo);
080: }
081: } catch (CoreException e) {
082: //assume inaccessible projects have no references
083: }
084: }
085: return set;
086: }
087:
088: /**
089: * Creates this action.
090: *
091: * @param shell
092: * The shell to use for parenting any dialogs created by this
093: * action.
094: */
095: public CloseUnrelatedProjectsAction(Shell shell) {
096: super (shell,
097: IDEWorkbenchMessages.CloseUnrelatedProjectsAction_text);
098: setId(ID);
099: setToolTipText(IDEWorkbenchMessages.CloseUnrelatedProjectsAction_toolTip);
100: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
101: IIDEHelpContextIds.CLOSE_UNRELATED_PROJECTS_ACTION);
102: }
103:
104: /*
105: * (non-Javadoc)
106: *
107: * @see org.eclipse.ui.actions.SelectionListenerAction#clearCache()
108: */
109: protected void clearCache() {
110: super .clearCache();
111: oldSelection = Collections.EMPTY_LIST;
112: selectionDirty = true;
113: }
114:
115: /**
116: * Computes the related projects of the selection.
117: */
118: private void computeRelated(List selection) {
119: //build the connected component set for all projects in the workspace
120: DisjointSet set = buildConnectedComponents(ResourcesPlugin
121: .getWorkspace().getRoot().getProjects());
122: //remove the connected components that the selected projects are in
123: for (Iterator it = selection.iterator(); it.hasNext();)
124: set.removeSet(it.next());
125: //the remainder of the projects in the disjoint set are unrelated to the selection
126: projectsToClose.clear();
127: set.toList(projectsToClose);
128: }
129:
130: /*
131: * (non-Javadoc)
132: *
133: * @see org.eclipse.ui.actions.SelectionListenerAction#getSelectedResources()
134: */
135: protected List getSelectedResources() {
136: if (selectionDirty) {
137: List newSelection = super .getSelectedResources();
138: if (!oldSelection.equals(newSelection)) {
139: oldSelection = newSelection;
140: computeRelated(newSelection);
141: }
142: selectionDirty = false;
143: }
144: return projectsToClose;
145: }
146:
147: /**
148: * Handles a resource changed event by updating the enablement
149: * when projects change.
150: * <p>
151: * This method overrides the super-type implementation to update
152: * the selection when the open state or description of any project changes.
153: */
154: public void resourceChanged(IResourceChangeEvent event) {
155: // don't bother looking at delta if selection not applicable
156: if (selectionIsOfType(IResource.PROJECT)) {
157: IResourceDelta delta = event.getDelta();
158: if (delta != null) {
159: IResourceDelta[] projDeltas = delta
160: .getAffectedChildren(IResourceDelta.CHANGED);
161: for (int i = 0; i < projDeltas.length; ++i) {
162: IResourceDelta projDelta = projDeltas[i];
163: //changing either the description or the open state can affect enablement
164: if ((projDelta.getFlags() & (IResourceDelta.OPEN | IResourceDelta.DESCRIPTION)) != 0) {
165: selectionChanged(getStructuredSelection());
166: return;
167: }
168: }
169: }
170: }
171: }
172: }
|