blob: 706fe6d961f062fc75259aa7b12b84c611a128d6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ui.actions;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.core.TeamPlugin;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.internal.ui.Utils;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionDelegate;
/**
* The abstract superclass of all Team actions. This class contains some convenience
* methods for getting selected objects and mapping selected objects to their
* providers.
*
* Team providers may subclass this class when creating their actions.
* Team providers may also instantiate or subclass any of the
* subclasses of TeamAction provided in this package.
*/
public abstract class TeamAction extends ActionDelegate implements IObjectActionDelegate, IViewActionDelegate {
// The current selection
protected IStructuredSelection selection;
// The shell, required for the progress dialog
protected Shell shell;
// Constants for determining the type of progress. Subclasses may
// pass one of these values to the run method.
public final static int PROGRESS_DIALOG = 1;
public final static int PROGRESS_BUSYCURSOR = 2;
public final static int PROGRESS_WORKBENCH_WINDOW = 3;
private IWorkbenchPart targetPart;
/**
* Creates an array of the given class type containing all the
* objects in the selection that adapt to the given class.
*
* @param selection
* @param c
* @return
*/
public static Object[] getSelectedAdaptables(ISelection selection, Class c) {
ArrayList result = null;
if (!selection.isEmpty()) {
result = new ArrayList();
Iterator elements = ((IStructuredSelection) selection).iterator();
while (elements.hasNext()) {
Object adapter = getAdapter(elements.next(), c);
if (c.isInstance(adapter)) {
result.add(adapter);
}
}
}
if (result != null && !result.isEmpty()) {
return (Object[])result.toArray((Object[])Array.newInstance(c, result.size()));
}
return (Object[])Array.newInstance(c, 0);
}
/**
* Find the object associated with the given object when it is adapted to
* the provided class. Null is returned if the given object does not adapt
* to the given class
*
* @param selection
* @param c
* @return Object
*/
public static Object getAdapter(Object adaptable, Class c) {
if (c.isInstance(adaptable)) {
return adaptable;
}
if (adaptable instanceof IAdaptable) {
IAdaptable a = (IAdaptable) adaptable;
Object adapter = a.getAdapter(c);
if (c.isInstance(adapter)) {
return adapter;
}
}
return null;
}
/**
* Returns the selected projects.
*
* @return the selected projects
*/
protected IProject[] getSelectedProjects() {
IResource[] selectedResources = getSelectedResources();
if (selectedResources.length == 0) return new IProject[0];
ArrayList projects = new ArrayList();
for (int i = 0; i < selectedResources.length; i++) {
IResource resource = selectedResources[i];
if (resource.getType() == IResource.PROJECT) {
projects.add(resource);
}
}
return (IProject[]) projects.toArray(new IProject[projects.size()]);
}
/**
* Returns an array of the given class type c that contains all
* instances of c that are either contained in the selection or
* are adapted from objects contained in the selection.
*
* @param c
* @return
*/
protected Object[] getSelectedResources(Class c) {
return getSelectedAdaptables(selection, c);
}
/**
* Returns the selected resources.
*
* @return the selected resources
*/
protected IResource[] getSelectedResources() {
return (IResource[])getSelectedResources(IResource.class);
}
/**
* Convenience method for getting the current shell.
*
* @return the shell
*/
protected Shell getShell() {
if (shell != null) {
return shell;
} else {
IWorkbench workbench = TeamUIPlugin.getPlugin().getWorkbench();
if (workbench == null) return null;
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
if (window == null) return null;
return window.getShell();
}
}
/**
* Convenience method for running an operation with progress and
* error feedback.
*
* @param runnable the runnable which executes the operation
* @param problemMessage the message to display in the case of errors
* @param progressKind one of PROGRESS_BUSYCURSOR or PROGRESS_DIALOG
*/
final protected void run(final IRunnableWithProgress runnable, final String problemMessage, int progressKind) {
final Exception[] exceptions = new Exception[] {null};
switch (progressKind) {
case PROGRESS_WORKBENCH_WINDOW :
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().run(true, true, runnable);
} catch (InterruptedException e1) {
exceptions[0] = null;
e1.printStackTrace();
} catch (InvocationTargetException e) {
exceptions[0] = e;
}
break;
case PROGRESS_BUSYCURSOR :
BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
public void run() {
try {
runnable.run(new NullProgressMonitor());
} catch (InvocationTargetException e) {
exceptions[0] = e;
} catch (InterruptedException e) {
exceptions[0] = null;
}
}
});
break;
default :
case PROGRESS_DIALOG :
try {
new ProgressMonitorDialog(getShell()).run(true, true, runnable);
} catch (InvocationTargetException e) {
exceptions[0] = e;
} catch (InterruptedException e) {
exceptions[0] = null;
}
break;
}
if (exceptions[0] != null) {
handle(exceptions[0], null, problemMessage);
}
}
/*
* Method declared on IActionDelegate.
*/
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof IStructuredSelection) {
this.selection = (IStructuredSelection) selection;
if (action != null) {
setActionEnablement(action);
}
}
}
/**
* Method invoked from <code>selectionChanged(IAction, ISelection)</code>
* to set the enablement status of the action. The instance variable
* <code>selection</code> will contain the latest selection so the methods
* <code>getSelectedResources()</code> and <code>getSelectedProjects()</code>
* will provide the proper objects.
*
* This method can be overridden by subclasses but should not be invoked by them.
*/
protected void setActionEnablement(IAction action) {
try {
action.setEnabled(isEnabled());
} catch (TeamException e) {
if (e.getStatus().getCode() == IResourceStatus.OUT_OF_SYNC_LOCAL) {
// Enable the action to allow the user to discover the problem
action.setEnabled(true);
} else {
action.setEnabled(false);
// We should not open a dialog when determining menu enablements so log it instead
TeamPlugin.log(e);
}
}
}
/*
* Method declared on IObjectActionDelegate.
*/
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
if(targetPart != null) {
this.shell = targetPart.getSite().getShell();
this.targetPart = targetPart;
}
}
/**
* Shows the given errors to the user.
*
* @param status the status containing the error
* @param title the title of the error dialog
* @param message the message for the error dialog
* @param shell the shell to open the error dialog in
*/
protected void handle(Exception exception, String title, String message) {
Utils.handleError(getShell(), exception, title, message);
}
/**
* Concrete action enablement code.
* Subclasses must implement.
*
* @return whether the action is enabled
* @throws TeamException if an error occurs during enablement detection
*/
abstract protected boolean isEnabled() throws TeamException;
/**
* Convenience method that maps the selected resources to their providers.
* The returned Hashtable has keys which are ITeamProviders, and values
* which are Lists of IResources that are shared with that provider.
*
* @return a hashtable mapping providers to their selected resources
*/
protected Hashtable getProviderMapping() {
return getProviderMapping(getSelectedResources());
}
/**
* Convenience method that maps the given resources to their providers.
* The returned Hashtable has keys which are ITeamProviders, and values
* which are Lists of IResources that are shared with that provider.
*
* @return a hashtable mapping providers to their resources
*/
protected Hashtable getProviderMapping(IResource[] resources) {
Hashtable result = new Hashtable();
for (int i = 0; i < resources.length; i++) {
RepositoryProvider provider = RepositoryProvider.getProvider(resources[i].getProject());
List list = (List)result.get(provider);
if (list == null) {
list = new ArrayList();
result.put(provider, list);
}
list.add(resources[i]);
}
return result;
}
/**
* @return IWorkbenchPart
*/
protected IWorkbenchPart getTargetPart() {
return targetPart;
}
/**
* Return the path that was active when the menu item was selected.
* @return IWorkbenchPage
*/
protected IWorkbenchPage getTargetPage() {
if (getTargetPart() == null) return TeamUIPlugin.getActivePage();
return getTargetPart().getSite().getPage();
}
/**
* Show the view with the given ID in the perspective from which the action
* was executed. Returns null if the view is not registered.
*
* @param viewId
* @return IViewPart
*/
protected IViewPart showView(String viewId) {
try {
return getTargetPage().showView(viewId);
} catch (PartInitException pe) {
return null;
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
*/
public void init(IViewPart view) {
targetPart = view;
}
}