blob: a55e1de504389263642296b8e190127d2dd27f67 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.actions;
import org.eclipse.core.commands.IHandlerAttributes;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.SubActionBars;
import org.eclipse.ui.internal.PartSite;
/**
* A <code>RetargetAction</code> tracks the active part in the workbench.
* Each RetargetAction has an ID. If the active part provides an action
* handler for the ID the enable and check state of the RetargetAction
* is determined from the enable and check state of the handler. If the
* active part does not provide an action handler then this action is
* disabled.
* </p>
* <p>
* <b>Note:</b> instances of this class add themselves as listeners to their
* action handler. It is important for the creator of a retarget action to call
* dispose when the action is no longer needed. This will ensure that the
* listener is removed.
* </p>
* <p>
* This class may be instantiated. It is not intented to be subclassed.
* </p>
*
* @since 2.0
*/
public class RetargetAction extends PartEventAction implements
ActionFactory.IWorkbenchAction {
/**
* The help listener assigned to this action, or <code>null</code> if none.
*/
private HelpListener localHelpListener;
private boolean enableAccelerator = true;
private IAction handler;
private IPropertyChangeListener propertyChangeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
RetargetAction.this.propagateChange(event);
}
};
/**
* Constructs a RetargetAction with the given action id and text.
*
* @param actionID the retargetable action id
* @param text the action's text, or <code>null</code> if there is no text
*/
public RetargetAction(String actionID, String text) {
this(actionID, text, IAction.AS_UNSPECIFIED);
}
/**
* Constructs a RetargetAction with the given action id, text and style.
*
* @param actionID the retargetable action id
* @param text the action's text, or <code>null</code> if there is no text
* @param style one of <code>AS_PUSH_BUTTON</code>, <code>AS_CHECK_BOX</code>,
* <code>AS_DROP_DOWN_MENU</code>, <code>AS_RADIO_BUTTON</code>, and
* <code>AS_UNSPECIFIED</code>
* @since 3.0
*/
public RetargetAction(String actionID, String text, int style) {
super(text, style);
setId(actionID);
setEnabled(false);
super.setHelpListener(new HelpListener() {
public void helpRequested(HelpEvent e) {
HelpListener listener = null;
if (handler != null) {
// if we have a handler, see if it has a help listener
listener = handler.getHelpListener();
if (listener == null) {
// use our own help listener
listener = localHelpListener;
}
}
if (listener != null) {
// pass on the event
listener.helpRequested(e);
}
}
});
}
/**
* Disposes of the action and any resources held.
*/
public void dispose() {
if (handler != null) {
handler.removePropertyChangeListener(propertyChangeListener);
handler = null;
}
IWorkbenchPart part = getActivePart();
if (part != null) {
IWorkbenchPartSite site = part.getSite();
SubActionBars bars = (SubActionBars) ((PartSite) site).getActionBars();
bars.removePropertyChangeListener(propertyChangeListener);
}
}
/**
* Enables the accelerator for this action.
*
* @param b the new enable state
*/
public void enableAccelerator(boolean b) {
enableAccelerator = b;
}
/* (non-Javadoc)
* Retaget actions do not have accelerators. It is up to the
* part to hook the accelerator.
*/
public int getAccelerator() {
if (enableAccelerator) {
return super.getAccelerator();
}
return 0;
}
/**
* A workbench part has been activated. Try to connect
* to it.
*
* @param part the workbench part that has been activated
*/
public void partActivated(IWorkbenchPart part) {
super.partActivated(part);
IWorkbenchPartSite site = part.getSite();
SubActionBars bars = (SubActionBars) ((PartSite) site).getActionBars();
bars.addPropertyChangeListener(propertyChangeListener);
setActionHandler(bars.getGlobalActionHandler(getId()));
}
/**
* A workbench part has been closed.
*
* @param part the workbench part that has been closed
*/
public void partClosed(IWorkbenchPart part) {
IWorkbenchPart activePart = part.getSite().getPage().getActivePart();
if (activePart != null) {
// We are going to get a part activated message so don't bother setting the
// action handler to null. This prevents enablement flash in the toolbar
return;
}
if (part == getActivePart()) {
setActionHandler(null);
}
super.partClosed(part);
}
/**
* A workbench part has been deactivated. Disconnect from it.
*
* @param part the workbench part that has been deactivated
*/
public void partDeactivated(IWorkbenchPart part) {
super.partDeactivated(part);
IWorkbenchPartSite site = part.getSite();
SubActionBars bars = (SubActionBars) ((PartSite) site).getActionBars();
bars.removePropertyChangeListener(propertyChangeListener);
IWorkbenchPart activePart = part.getSite().getPage().getActivePart();
if (activePart != null) {
// We are going to get a part activated message so don't bother setting the
// action handler to null. This prevents enablement flash in the toolbar
return;
}
setActionHandler(null);
}
/**
* Either the action handler itself has changed, or the configured action
* handlers on the action bars have changed. Update self.
*/
protected void propagateChange(PropertyChangeEvent event) {
if (event.getProperty().equals(IAction.ENABLED)) {
Boolean bool = (Boolean) event.getNewValue();
setEnabled(bool.booleanValue());
} else if (event.getProperty().equals(IAction.CHECKED)) {
Boolean bool = (Boolean) event.getNewValue();
setChecked(bool.booleanValue());
} else if (event.getProperty().equals(SubActionBars.P_ACTION_HANDLERS)) {
if (event.getSource() instanceof IActionBars) {
IActionBars bars = (IActionBars) event.getSource();
setActionHandler(bars.getGlobalActionHandler(getId()));
}
}
}
/**
* Invoked when an action occurs.
*/
public void run() {
if (handler != null) {
handler.run();
}
}
/**
* Invoked when an action occurs.
*/
public void runWithEvent(Event event) {
if (handler != null) {
handler.runWithEvent(event);
}
}
/**
* Returns the action handler. This method was made public in 3.0.
*
* @return The current action handling this retargettable action. This
* handler will be <code>null</code> if there is no current
* handler.
*/
public IAction getActionHandler() {
return handler;
}
public final boolean isHandled() {
return (handler != null);
}
/**
* Sets the action handler.
*/
protected void setActionHandler(IAction newHandler) {
// Optimize.
if (newHandler == handler) {
return;
}
// Clear old action.
if (handler != null) {
handler.removePropertyChangeListener(propertyChangeListener);
handler = null;
}
// Set new action.
IAction oldHandler = handler;
handler = newHandler;
if (handler == null) {
setEnabled(false);
if (getStyle() == AS_CHECK_BOX || getStyle() == AS_RADIO_BUTTON) {
setChecked(false);
}
} else {
setEnabled(handler.isEnabled());
if (getStyle() == AS_CHECK_BOX || getStyle() == AS_RADIO_BUTTON) {
setChecked(handler.isChecked());
}
handler.addPropertyChangeListener(propertyChangeListener);
}
// Notify listeners that the handler has changed.
firePropertyChange(IHandlerAttributes.ATTRIBUTE_HANDLED, oldHandler,
newHandler);
}
/* (non-Javadoc)
* Method declared on IAction.
*/
public void setChecked(boolean checked) {
super.setChecked(checked);
// This call may come from the SWT control event handler
// itself, so notify the handler action to keep things
// in sync.
if (handler != null) {
handler.setChecked(checked);
}
}
/**
* The <code>RetargetAction</code> implementation of this method declared on
* <code>IAction</code> stores the help listener in a local field. The
* supplied listener is only used if there is no hanlder.
*/
public void setHelpListener(HelpListener listener) {
localHelpListener = listener;
}
/**
* Returns a string representation of this action.
*
* @return A string representation of this action.
*
* @since 3.2
*/
public final String toString() {
final StringBuffer buffer = new StringBuffer();
buffer.append("RetargetAction("); //$NON-NLS-1$
buffer.append(getId());
buffer.append(')');
return buffer.toString();
}
}