001: /*******************************************************************************
002: * Copyright (c) 2000, 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.Iterator;
014: import java.util.List;
015: import org.eclipse.core.resources.IProject;
016: import org.eclipse.core.resources.IResource;
017: import org.eclipse.core.resources.IResourceChangeEvent;
018: import org.eclipse.core.resources.IResourceChangeListener;
019: import org.eclipse.core.resources.IResourceDelta;
020: import org.eclipse.core.resources.IResourceRuleFactory;
021: import org.eclipse.core.resources.ResourcesPlugin;
022: import org.eclipse.core.resources.WorkspaceJob;
023: import org.eclipse.core.runtime.CoreException;
024: import org.eclipse.core.runtime.IProgressMonitor;
025: import org.eclipse.core.runtime.IStatus;
026: import org.eclipse.core.runtime.OperationCanceledException;
027: import org.eclipse.core.runtime.Status;
028: import org.eclipse.core.runtime.SubProgressMonitor;
029: import org.eclipse.core.runtime.jobs.ISchedulingRule;
030: import org.eclipse.core.runtime.jobs.Job;
031: import org.eclipse.core.runtime.jobs.MultiRule;
032: import org.eclipse.jface.dialogs.IDialogConstants;
033: import org.eclipse.jface.dialogs.MessageDialogWithToggle;
034: import org.eclipse.jface.preference.IPreferenceStore;
035: import org.eclipse.jface.viewers.IStructuredSelection;
036: import org.eclipse.jface.window.Window;
037: import org.eclipse.swt.widgets.Shell;
038: import org.eclipse.ui.PlatformUI;
039: import org.eclipse.ui.internal.ide.IDEInternalPreferences;
040: import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
041: import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
042: import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
043:
044: /**
045: * Standard action for opening the currently selected project(s).
046: * <p>
047: * Note that there is a different action for opening an editor on file
048: * resources: <code>OpenFileAction</code>.
049: * </p>
050: * <p>
051: * This class may be instantiated; it is not intended to be subclassed.
052: * </p>
053: */
054: public class OpenResourceAction extends WorkspaceAction implements
055: IResourceChangeListener {
056:
057: /**
058: * The id of this action.
059: */
060: public static final String ID = PlatformUI.PLUGIN_ID
061: + ".OpenResourceAction"; //$NON-NLS-1$
062:
063: /**
064: * Creates a new action.
065: *
066: * @param shell
067: * the shell for any dialogs
068: */
069: public OpenResourceAction(Shell shell) {
070: super (shell, IDEWorkbenchMessages.OpenResourceAction_text);
071: PlatformUI.getWorkbench().getHelpSystem().setHelp(this ,
072: IIDEHelpContextIds.OPEN_RESOURCE_ACTION);
073: setToolTipText(IDEWorkbenchMessages.OpenResourceAction_toolTip);
074: setId(ID);
075: }
076:
077: /**
078: * Returns the total number of closed projects in the workspace.
079: */
080: private int countClosedProjects() {
081: int count = 0;
082: IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
083: .getProjects();
084: for (int i = 0; i < projects.length; i++) {
085: if (!projects[i].isOpen()) {
086: count++;
087: }
088: }
089: return count;
090: }
091:
092: /*
093: * (non-Javadoc) Method declared on WorkspaceAction.
094: */
095: protected String getOperationMessage() {
096: return IDEWorkbenchMessages.OpenResourceAction_operationMessage;
097: }
098:
099: /*
100: * (non-Javadoc) Method declared on WorkspaceAction.
101: */
102: protected String getProblemsMessage() {
103: return IDEWorkbenchMessages.OpenResourceAction_problemMessage;
104: }
105:
106: /*
107: * (non-Javadoc) Method declared on WorkspaceAction.
108: */
109: protected String getProblemsTitle() {
110: return IDEWorkbenchMessages.OpenResourceAction_dialogTitle;
111: }
112:
113: /**
114: * Returns whether there are closed projects in the workspace that are
115: * not part of the current selection.
116: */
117: private boolean hasOtherClosedProjects() {
118: //count the closed projects in the selection
119: int closedInSelection = 0;
120: Iterator resources = getSelectedResources().iterator();
121: while (resources.hasNext()) {
122: IProject project = (IProject) resources.next();
123: if (!project.isOpen())
124: closedInSelection++;
125: }
126: //there are other closed projects if the selection does
127: //not contain all closed projects in the workspace
128: return closedInSelection < countClosedProjects();
129: }
130:
131: protected void invokeOperation(IResource resource,
132: IProgressMonitor monitor) throws CoreException {
133: ((IProject) resource).open(monitor);
134: }
135:
136: /**
137: * Returns the preference for whether to open required projects when opening
138: * a project. Consults the preference and prompts the user if necessary.
139: *
140: * @return <code>true</code> if referenced projects should be opened, and
141: * <code>false</code> otherwise.
142: */
143: private boolean promptToOpenWithReferences() {
144: IPreferenceStore store = IDEWorkbenchPlugin.getDefault()
145: .getPreferenceStore();
146: String key = IDEInternalPreferences.OPEN_REQUIRED_PROJECTS;
147: String value = store.getString(key);
148: if (MessageDialogWithToggle.ALWAYS.equals(value)) {
149: return true;
150: }
151: if (MessageDialogWithToggle.NEVER.equals(value)) {
152: return false;
153: }
154: String message = IDEWorkbenchMessages.OpenResourceAction_openRequiredProjects;
155: MessageDialogWithToggle dialog = MessageDialogWithToggle
156: .openYesNoCancelQuestion(getShell(),
157: IDEWorkbenchMessages.Question, message, null,
158: false, store, key);
159: int result = dialog.getReturnCode();
160: if (result == Window.CANCEL) {
161: throw new OperationCanceledException();
162: }
163: return dialog.getReturnCode() == IDialogConstants.YES_ID;
164: }
165:
166: /**
167: * Handles a resource changed event by updating the enablement if one of the
168: * selected projects is opened or closed.
169: */
170: public void resourceChanged(IResourceChangeEvent event) {
171: // Warning: code duplicated in CloseResourceAction
172: List sel = getSelectedResources();
173: // don't bother looking at delta if selection not applicable
174: if (selectionIsOfType(IResource.PROJECT)) {
175: IResourceDelta delta = event.getDelta();
176: if (delta != null) {
177: IResourceDelta[] projDeltas = delta
178: .getAffectedChildren(IResourceDelta.CHANGED);
179: for (int i = 0; i < projDeltas.length; ++i) {
180: IResourceDelta projDelta = projDeltas[i];
181: if ((projDelta.getFlags() & IResourceDelta.OPEN) != 0) {
182: if (sel.contains(projDelta.getResource())) {
183: selectionChanged(getStructuredSelection());
184: return;
185: }
186: }
187: }
188: }
189: }
190: }
191:
192: /*
193: * (non-Javadoc) Method declared on IAction; overrides method on
194: * WorkspaceAction.
195: */
196: public void run() {
197: try {
198: if (hasOtherClosedProjects()
199: && promptToOpenWithReferences()) {
200: runOpenWithReferences();
201: }
202: ISchedulingRule rule = null;
203: // be conservative and include all projects in the selection - projects
204: // can change state between now and when the job starts
205: IResourceRuleFactory factory = ResourcesPlugin
206: .getWorkspace().getRuleFactory();
207: Iterator resources = getSelectedResources().iterator();
208: while (resources.hasNext()) {
209: IProject project = (IProject) resources.next();
210: rule = MultiRule.combine(rule, factory
211: .modifyRule(project));
212: }
213: runInBackground(rule);
214: } catch (OperationCanceledException e) {
215: //just return when canceled
216: }
217: }
218:
219: /**
220: * Opens the selected projects, and all related projects, in the background.
221: */
222: private void runOpenWithReferences() {
223: final List resources = new ArrayList(getActionResources());
224: Job job = new WorkspaceJob(removeMnemonics(getText())) {
225:
226: /**
227: * Opens a project along with all projects it references
228: */
229: private void doOpenWithReferences(IProject project,
230: IProgressMonitor monitor) throws CoreException {
231: if (!project.exists() || project.isOpen()) {
232: return;
233: }
234: project.open(new SubProgressMonitor(monitor, 1000));
235: IProject[] references = project.getReferencedProjects();
236: for (int i = 0; i < references.length; i++) {
237: doOpenWithReferences(references[i], monitor);
238: }
239: }
240:
241: public IStatus runInWorkspace(IProgressMonitor monitor)
242: throws CoreException {
243: try {
244: // at most we can only open all projects currently closed
245: monitor.beginTask("", countClosedProjects() * 1000); //$NON-NLS-1$
246: monitor.setTaskName(getOperationMessage());
247: for (Iterator it = resources.iterator(); it
248: .hasNext();) {
249: doOpenWithReferences((IProject) it.next(),
250: monitor);
251: }
252: } finally {
253: monitor.done();
254: }
255: return Status.OK_STATUS;
256: }
257: };
258: job.setRule(ResourcesPlugin.getWorkspace().getRoot());
259: job.setUser(true);
260: job.schedule();
261: }
262:
263: /*
264: * (non-Javadoc) Method declared on WorkspaceAction.
265: */
266: protected boolean shouldPerformResourcePruning() {
267: return false;
268: }
269:
270: /**
271: * The <code>OpenResourceAction</code> implementation of this
272: * <code>SelectionListenerAction</code> method ensures that this action is
273: * enabled only if one of the selections is a closed project.
274: */
275: protected boolean updateSelection(IStructuredSelection s) {
276: // don't call super since we want to enable if closed project is
277: // selected.
278:
279: if (!selectionIsOfType(IResource.PROJECT)) {
280: return false;
281: }
282:
283: Iterator resources = getSelectedResources().iterator();
284: while (resources.hasNext()) {
285: IProject currentResource = (IProject) resources.next();
286: if (!currentResource.isOpen()) {
287: return true;
288: }
289: }
290: return false;
291: }
292: }
|