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 org.eclipse.core.commands.IHandlerAttributes;
013: import org.eclipse.jface.action.IAction;
014: import org.eclipse.jface.util.IPropertyChangeListener;
015: import org.eclipse.jface.util.PropertyChangeEvent;
016: import org.eclipse.swt.events.HelpEvent;
017: import org.eclipse.swt.events.HelpListener;
018: import org.eclipse.swt.widgets.Event;
019: import org.eclipse.ui.IActionBars;
020: import org.eclipse.ui.IWorkbenchPart;
021: import org.eclipse.ui.IWorkbenchPartSite;
022: import org.eclipse.ui.SubActionBars;
023: import org.eclipse.ui.internal.PartSite;
024:
025: /**
026: * A <code>RetargetAction</code> tracks the active part in the workbench.
027: * Each RetargetAction has an ID. If the active part provides an action
028: * handler for the ID the enable and check state of the RetargetAction
029: * is determined from the enable and check state of the handler. If the
030: * active part does not provide an action handler then this action is
031: * disabled.
032: * </p>
033: * <p>
034: * <b>Note:</b> instances of this class add themselves as listeners to their
035: * action handler. It is important for the creator of a retarget action to call
036: * dispose when the action is no longer needed. This will ensure that the
037: * listener is removed.
038: * </p>
039: * <p>
040: * This class may be instantiated. It is not intented to be subclassed.
041: * </p>
042: *
043: * @since 2.0
044: */
045: public class RetargetAction extends PartEventAction implements
046: ActionFactory.IWorkbenchAction {
047:
048: /**
049: * The help listener assigned to this action, or <code>null</code> if none.
050: */
051: private HelpListener localHelpListener;
052:
053: private boolean enableAccelerator = true;
054:
055: private IAction handler;
056:
057: private IPropertyChangeListener propertyChangeListener = new IPropertyChangeListener() {
058: public void propertyChange(PropertyChangeEvent event) {
059: RetargetAction.this .propagateChange(event);
060: }
061: };
062:
063: /**
064: * Constructs a RetargetAction with the given action id and text.
065: *
066: * @param actionID the retargetable action id
067: * @param text the action's text, or <code>null</code> if there is no text
068: */
069: public RetargetAction(String actionID, String text) {
070: this (actionID, text, IAction.AS_UNSPECIFIED);
071: }
072:
073: /**
074: * Constructs a RetargetAction with the given action id, text and style.
075: *
076: * @param actionID the retargetable action id
077: * @param text the action's text, or <code>null</code> if there is no text
078: * @param style one of <code>AS_PUSH_BUTTON</code>, <code>AS_CHECK_BOX</code>,
079: * <code>AS_DROP_DOWN_MENU</code>, <code>AS_RADIO_BUTTON</code>, and
080: * <code>AS_UNSPECIFIED</code>
081: * @since 3.0
082: */
083: public RetargetAction(String actionID, String text, int style) {
084: super (text, style);
085: setId(actionID);
086: setEnabled(false);
087: super .setHelpListener(new HelpListener() {
088: public void helpRequested(HelpEvent e) {
089: HelpListener listener = null;
090: if (handler != null) {
091: // if we have a handler, see if it has a help listener
092: listener = handler.getHelpListener();
093: if (listener == null) {
094: // use our own help listener
095: listener = localHelpListener;
096: }
097: }
098: if (listener != null) {
099: // pass on the event
100: listener.helpRequested(e);
101: }
102: }
103: });
104: }
105:
106: /**
107: * Disposes of the action and any resources held.
108: */
109: public void dispose() {
110: if (handler != null) {
111: handler
112: .removePropertyChangeListener(propertyChangeListener);
113: handler = null;
114: }
115: IWorkbenchPart part = getActivePart();
116: if (part != null) {
117: IWorkbenchPartSite site = part.getSite();
118: SubActionBars bars = (SubActionBars) ((PartSite) site)
119: .getActionBars();
120: bars.removePropertyChangeListener(propertyChangeListener);
121: }
122: }
123:
124: /**
125: * Enables the accelerator for this action.
126: *
127: * @param b the new enable state
128: */
129: public void enableAccelerator(boolean b) {
130: enableAccelerator = b;
131: }
132:
133: /* (non-Javadoc)
134: * Retaget actions do not have accelerators. It is up to the
135: * part to hook the accelerator.
136: */
137: public int getAccelerator() {
138: if (enableAccelerator) {
139: return super .getAccelerator();
140: }
141: return 0;
142: }
143:
144: /**
145: * A workbench part has been activated. Try to connect
146: * to it.
147: *
148: * @param part the workbench part that has been activated
149: */
150: public void partActivated(IWorkbenchPart part) {
151: super .partActivated(part);
152: IWorkbenchPartSite site = part.getSite();
153: SubActionBars bars = (SubActionBars) ((PartSite) site)
154: .getActionBars();
155: bars.addPropertyChangeListener(propertyChangeListener);
156: setActionHandler(bars.getGlobalActionHandler(getId()));
157: }
158:
159: /**
160: * A workbench part has been closed.
161: *
162: * @param part the workbench part that has been closed
163: */
164: public void partClosed(IWorkbenchPart part) {
165: IWorkbenchPart activePart = part.getSite().getPage()
166: .getActivePart();
167: if (activePart != null) {
168: // We are going to get a part activated message so don't bother setting the
169: // action handler to null. This prevents enablement flash in the toolbar
170: return;
171: }
172: if (part == getActivePart()) {
173: setActionHandler(null);
174: }
175: super .partClosed(part);
176: }
177:
178: /**
179: * A workbench part has been deactivated. Disconnect from it.
180: *
181: * @param part the workbench part that has been deactivated
182: */
183: public void partDeactivated(IWorkbenchPart part) {
184: super .partDeactivated(part);
185: IWorkbenchPartSite site = part.getSite();
186: SubActionBars bars = (SubActionBars) ((PartSite) site)
187: .getActionBars();
188: bars.removePropertyChangeListener(propertyChangeListener);
189:
190: IWorkbenchPart activePart = part.getSite().getPage()
191: .getActivePart();
192: if (activePart != null) {
193: // We are going to get a part activated message so don't bother setting the
194: // action handler to null. This prevents enablement flash in the toolbar
195: return;
196: }
197:
198: setActionHandler(null);
199: }
200:
201: /**
202: * Either the action handler itself has changed, or the configured action
203: * handlers on the action bars have changed. Update self.
204: */
205: protected void propagateChange(PropertyChangeEvent event) {
206: if (event.getProperty().equals(IAction.ENABLED)) {
207: Boolean bool = (Boolean) event.getNewValue();
208: setEnabled(bool.booleanValue());
209: } else if (event.getProperty().equals(IAction.CHECKED)) {
210: Boolean bool = (Boolean) event.getNewValue();
211: setChecked(bool.booleanValue());
212: } else if (event.getProperty().equals(
213: SubActionBars.P_ACTION_HANDLERS)) {
214: if (event.getSource() instanceof IActionBars) {
215: IActionBars bars = (IActionBars) event.getSource();
216: setActionHandler(bars.getGlobalActionHandler(getId()));
217: }
218: }
219: }
220:
221: /**
222: * Invoked when an action occurs.
223: */
224: public void run() {
225: if (handler != null) {
226: handler.run();
227: }
228: }
229:
230: /**
231: * Invoked when an action occurs.
232: */
233: public void runWithEvent(Event event) {
234: if (handler != null) {
235: handler.runWithEvent(event);
236: }
237: }
238:
239: /**
240: * Returns the action handler. This method was made public in 3.0.
241: *
242: * @return The current action handling this retargettable action. This
243: * handler will be <code>null</code> if there is no current
244: * handler.
245: */
246: public IAction getActionHandler() {
247: return handler;
248: }
249:
250: public final boolean isHandled() {
251: return (handler != null);
252: }
253:
254: /**
255: * Sets the action handler.
256: */
257: protected void setActionHandler(IAction newHandler) {
258: // Optimize.
259: if (newHandler == handler) {
260: return;
261: }
262:
263: // Clear old action.
264: if (handler != null) {
265: handler
266: .removePropertyChangeListener(propertyChangeListener);
267: handler = null;
268: }
269:
270: // Set new action.
271: IAction oldHandler = handler;
272: handler = newHandler;
273: if (handler == null) {
274: setEnabled(false);
275: if (getStyle() == AS_CHECK_BOX
276: || getStyle() == AS_RADIO_BUTTON) {
277: setChecked(false);
278: }
279: } else {
280: setEnabled(handler.isEnabled());
281: if (getStyle() == AS_CHECK_BOX
282: || getStyle() == AS_RADIO_BUTTON) {
283: setChecked(handler.isChecked());
284: }
285: handler.addPropertyChangeListener(propertyChangeListener);
286: }
287:
288: // Notify listeners that the handler has changed.
289: firePropertyChange(IHandlerAttributes.ATTRIBUTE_HANDLED,
290: oldHandler, newHandler);
291: }
292:
293: /* (non-Javadoc)
294: * Method declared on IAction.
295: */
296: public void setChecked(boolean checked) {
297: super .setChecked(checked);
298: // This call may come from the SWT control event handler
299: // itself, so notify the handler action to keep things
300: // in sync.
301: if (handler != null) {
302: handler.setChecked(checked);
303: }
304: }
305:
306: /**
307: * The <code>RetargetAction</code> implementation of this method declared on
308: * <code>IAction</code> stores the help listener in a local field. The
309: * supplied listener is only used if there is no hanlder.
310: */
311: public void setHelpListener(HelpListener listener) {
312: localHelpListener = listener;
313: }
314:
315: /**
316: * Returns a string representation of this action.
317: *
318: * @return A string representation of this action.
319: *
320: * @since 3.2
321: */
322: public final String toString() {
323: final StringBuffer buffer = new StringBuffer();
324:
325: buffer.append("RetargetAction("); //$NON-NLS-1$
326: buffer.append(getId());
327: buffer.append(')');
328:
329: return buffer.toString();
330: }
331: }
|