001: /*
002: * @(#)DelegateAction.java 10/2/2006
003: *
004: * Copyright 2002 - 2006 JIDE Software Inc. All rights reserved.
005: */
006:
007: package com.jidesoft.swing;
008:
009: import javax.swing.*;
010: import java.awt.event.ActionEvent;
011: import java.awt.event.ActionListener;
012:
013: /**
014: * DelegateAction is a special AbstractAction which can do something then delegate to another action depending on
015: * the return value of {@link #delegateActionPerformed(java.awt.event.ActionEvent)}.
016: * There are two usages of it. First, you can use {@link #replaceAction(javax.swing.JComponent,int,javax.swing.KeyStroke,DelegateAction)}
017: * to replace the action associated with the specified keystroke with the DelegateAction. The DelegateAction will be
018: * triggered when the keystroke is pressed. After DelegateAction is done, it can return true or false. If false, the original action
019: * associated with the keystroke will be triggered as well. This solves the problem that {@link JComponent#registerKeyboardAction(java.awt.event.ActionListener,String,javax.swing.KeyStroke,int)}
020: * will replace the original action so that the original actino will never be triggered.
021: * <p/>
022: * The second way to use DelegateAction is to delegate the action from one component to another component using {@link #replaceAction(javax.swing.JComponent,int,javax.swing.JComponent,int,javax.swing.KeyStroke,DelegateAction)}.
023: * In this case, the keystroke on the first component parameter will be triggered the DelegateAction. If DelegateAction returns false, the registered action on the second component parameter will be triggered.
024: * If you pass in {@link PassthroughDelegateAction}, the registered action on the second component
025: * will always be triggered.
026: * <p/>
027: * Please notes, if you call replaceAction several times on the same component with the same keystroke,
028: * it will form a chain of DelegateActions. In this case, the first call will be the first DelegateAction.
029: * In the other words, the first one will have the highest priority and will be triggered first.
030: * Ideally, we should assign a priroty to each DelegateAction. But for the sake of simplicity,
031: * we decided not doing it for now. So because of this, this class is not ready to be used as public API. We have
032: * to make it public because different packages in JIDE need to use it. If you want to use, please use it with caution.
033: * We don't gurantee that we will not change the public methods on this classes.
034: * <p/>
035: */
036: abstract public class DelegateAction extends AbstractAction {
037: private Action _action;
038: private JComponent _target;
039:
040: public DelegateAction() {
041: }
042:
043: public DelegateAction(Action action) {
044: _action = action;
045: }
046:
047: public DelegateAction(Action action, JComponent target) {
048: _action = action;
049: _target = target;
050: }
051:
052: final public void actionPerformed(ActionEvent e) {
053: if (!delegateActionPerformed(e)) {
054: if (_action != null) {
055: if (_target == null) {
056: _action.actionPerformed(e);
057: } else {
058: _action.actionPerformed(new ActionEvent(
059: getTarget(), e.getID(), e
060: .getActionCommand(), e.getWhen(), e
061: .getModifiers()));
062: }
063: }
064: }
065: }
066:
067: protected Action getAction() {
068: return _action;
069: }
070:
071: protected void setAction(Action action) {
072: _action = action;
073: }
074:
075: protected JComponent getTarget() {
076: return _target;
077: }
078:
079: protected void setTarget(JComponent target) {
080: _target = target;
081: }
082:
083: /**
084: * Performs an action. Returns true if no further action should be taken for this keystroke. Otherwise, returns false.
085: *
086: * @param e the action event.
087: * @return true if no further action should be taken for this keystroke. Otherwise, returns false.
088: */
089: abstract public boolean delegateActionPerformed(ActionEvent e);
090:
091: public static class PassthroughDelegateAction extends
092: DelegateAction {
093: @Override
094: public boolean delegateActionPerformed(ActionEvent e) {
095: return false;
096: }
097: }
098:
099: public static void replaceAction(JComponent component,
100: int condition, KeyStroke keyStroke,
101: DelegateAction delegateAction) {
102: replaceAction(component, condition, component, condition,
103: keyStroke, delegateAction);
104: }
105:
106: public static void replaceAction(JComponent component,
107: int condition, KeyStroke keyStroke,
108: DelegateAction delegateAction, boolean first) {
109: replaceAction(component, condition, component, condition,
110: keyStroke, delegateAction, first);
111: }
112:
113: public static void replaceAction(JComponent component,
114: int condition, JComponent target, int targetCondition,
115: KeyStroke keyStroke) {
116: replaceAction(component, condition, target, targetCondition,
117: keyStroke,
118: new DelegateAction.PassthroughDelegateAction(), false);
119: }
120:
121: public static void replaceAction(JComponent component,
122: int condition, JComponent target, int targetCondition,
123: KeyStroke keyStroke, DelegateAction delegateAction) {
124: replaceAction(component, condition, target, targetCondition,
125: keyStroke, delegateAction, false);
126: }
127:
128: public static void replaceAction(JComponent component,
129: int condition, JComponent target, int targetCondition,
130: KeyStroke keyStroke, DelegateAction delegateAction,
131: boolean first) {
132: Object actionCommand = target.getInputMap(targetCondition).get(
133: keyStroke);
134: if (actionCommand != null) {
135: Action action = target.getActionMap().get(actionCommand);
136: if (action != delegateAction) {
137: if (!first && action instanceof DelegateAction) {
138: delegateAction.setAction(((DelegateAction) action)
139: .getAction());
140: ((DelegateAction) action).setAction(delegateAction);
141: delegateAction = (DelegateAction) action;
142: } else {
143: delegateAction.setAction(action);
144: }
145: if (target != component) {
146: delegateAction.setTarget(target);
147: replaceAction(component, condition, keyStroke,
148: delegateAction);
149: } else {
150: component.getActionMap().put(actionCommand,
151: delegateAction);
152: }
153: }
154: } else {
155: if (target != component) {
156: delegateAction.setTarget(target);
157: replaceAction(component, condition, keyStroke,
158: delegateAction);
159: } else {
160: component.registerKeyboardAction(delegateAction,
161: keyStroke, condition);
162: }
163: }
164: }
165:
166: public static void restoreAction(JComponent component,
167: int condition, KeyStroke keyStroke) {
168: ActionListener action = component
169: .getActionForKeyStroke(keyStroke);
170: if (action instanceof DelegateAction) {
171: component.registerKeyboardAction(((DelegateAction) action)
172: .getAction(), keyStroke, condition);
173: }
174: }
175:
176: public static void restoreAction(JComponent component,
177: int condition, KeyStroke keyStroke, Class actionClass) {
178: ActionListener action = component
179: .getActionForKeyStroke(keyStroke);
180: ActionListener parent = action;
181: ActionListener top = action;
182: while (action instanceof DelegateAction) {
183: if (actionClass.isAssignableFrom(action.getClass())) {
184: if (top == action) {
185: component.registerKeyboardAction(
186: ((DelegateAction) action).getAction(),
187: keyStroke, condition);
188: } else {
189: ((DelegateAction) parent)
190: .setAction(((DelegateAction) action)
191: .getAction());
192: }
193: break;
194: }
195: parent = action;
196: action = ((DelegateAction) action).getAction();
197: }
198: }
199:
200: public static void restoreAction(JComponent component,
201: int condition, KeyStroke keyStroke, Action actionToBeRemoved) {
202: ActionListener action = component
203: .getActionForKeyStroke(keyStroke);
204: ActionListener parent = action;
205: ActionListener top = action;
206: while (action instanceof DelegateAction) {
207: if (actionToBeRemoved == action) {
208: if (top == action) {
209: component.registerKeyboardAction(
210: ((DelegateAction) action).getAction(),
211: keyStroke, condition);
212: } else {
213: ((DelegateAction) parent)
214: .setAction(((DelegateAction) action)
215: .getAction());
216: }
217: break;
218: }
219: parent = action;
220: action = ((DelegateAction) action).getAction();
221: }
222: }
223: }
|