001: /*
002: * $Id: BoundAction.java,v 1.4 2005/10/26 11:44:31 kleopatra Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package org.jdesktop.swingx.action;
023:
024: import java.awt.event.ActionEvent;
025: import java.awt.event.ActionListener;
026: import java.awt.event.ItemEvent;
027: import java.awt.event.ItemListener;
028: import java.beans.EventHandler;
029: import java.beans.Statement;
030: import java.util.EventListener;
031: import java.util.logging.Level;
032: import java.util.logging.Logger;
033:
034: import javax.swing.Icon;
035: import javax.swing.event.EventListenerList;
036:
037: /**
038: * A class that represents the many type of actions that this framework supports.
039: * <p>
040: * The command invocation of this action may be delegated to another action or item state
041: * listener. If there isn't an explicit binding then the command is forwarded to
042: * the TargetManager.
043: *
044: * @author Mark Davidson
045: */
046: public class BoundAction extends AbstractActionExt {
047: private static final Logger LOG = Logger
048: .getLogger(BoundAction.class.getName());
049: // Holds the listeners
050: private EventListenerList listeners;
051:
052: public BoundAction() {
053: this ("BoundAction");
054: }
055:
056: public BoundAction(String name) {
057: super (name);
058: }
059:
060: /**
061: * @param name display name of the action
062: * @param command the value of the action command key
063: */
064: public BoundAction(String name, String command) {
065: super (name, command);
066: }
067:
068: public BoundAction(String name, Icon icon) {
069: super (name, icon);
070: }
071:
072: /**
073: * @param name display name of the action
074: * @param command the value of the action command key
075: * @param icon icon to display
076: */
077: public BoundAction(String name, String command, Icon icon) {
078: super (name, command, icon);
079: }
080:
081: /**
082: * The callback string will be called to register the action callback.
083: * Note the toggle property must be set if this is a state action before
084: * this method is called.
085: * For example,
086: * <pre>
087: * <exec>com.sun.foo.FubarHandler#handleBar</exec>
088: * </pre>
089: * will register
090: * <pre>
091: * registerCallback(com.sun.foo.FubarHandler(), "handleBar");
092: * </pre>
093: */
094: public void setCallback(String callback) {
095: String[] elems = callback.split("#", 2);
096: if (elems.length == 2) {
097: try {
098: Class clz = Class.forName(elems[0]);
099:
100: // May throw a security exception in an Applet
101: // context.
102: Object obj = clz.newInstance();
103:
104: registerCallback(obj, elems[1]);
105: } catch (Exception ex) {
106: LOG.fine("ERROR: setCallback(" + callback + ") - "
107: + ex.getMessage());
108: }
109: }
110: }
111:
112: /**
113: * Registers a callback method when the Action corresponding to
114: * the action id is invoked. When a Component that was constructed from the
115: * Action identified by the action id invokes actionPerformed then the method
116: * named will be invoked on the handler Object.
117: * <p>
118: * If the Action represented by the action id is a StateChangeAction, then
119: * the method passed should take an int as an argument. The value of
120: * getStateChange() on the ItemEvent object will be passed as the parameter.
121: *
122: * @param handler the object which will be perform the action
123: * @param method the name of the method on the handler which will be called.
124: */
125: public void registerCallback(Object handler, String method) {
126: if (isStateAction()) {
127: // Create a handler for toogle type actions.
128: addItemListener(new BooleanInvocationHandler(handler,
129: method));
130: } else {
131: // Create a new ActionListener using the dynamic proxy api.
132: addActionListener((ActionListener) EventHandler.create(
133: ActionListener.class, handler, method));
134: }
135: }
136:
137: /**
138: * The callback for the toggle/state changed action that invokes a method
139: * with a boolean argument on a target.
140: *
141: * TODO: should reimplement this class as something that can be persistable.
142: */
143: private class BooleanInvocationHandler implements ItemListener {
144:
145: private Statement falseStatement;
146: private Statement trueStatement;
147:
148: public BooleanInvocationHandler(Object target, String methodName) {
149: // Create the true and false statements.
150: falseStatement = new Statement(target, methodName,
151: new Object[] { Boolean.FALSE });
152:
153: trueStatement = new Statement(target, methodName,
154: new Object[] { Boolean.TRUE });
155: }
156:
157: public void itemStateChanged(ItemEvent evt) {
158: Statement statement = (evt.getStateChange() == ItemEvent.DESELECTED) ? falseStatement
159: : trueStatement;
160:
161: try {
162: statement.execute();
163: } catch (Exception ex) {
164: LOG.log(Level.FINE,
165: "Couldn't execute boolean method via Statement "
166: + statement, ex);
167: }
168: }
169: }
170:
171: // Listener registration...
172:
173: private void addListener(Class clz, EventListener listener) {
174: if (listeners == null) {
175: listeners = new EventListenerList();
176: }
177: listeners.add(clz, listener);
178: }
179:
180: private void removeListener(Class clz, EventListener listener) {
181: if (listeners != null) {
182: listeners.remove(clz, listener);
183: }
184: }
185:
186: private EventListener[] getListeners(Class clz) {
187: if (listeners == null) {
188: return null;
189: }
190: return listeners.getListeners(clz);
191: }
192:
193: /**
194: * Add an action listener which will be invoked when this action is invoked.
195: */
196: public void addActionListener(ActionListener listener) {
197: addListener(ActionListener.class, listener);
198: }
199:
200: public void removeActionListener(ActionListener listener) {
201: removeListener(ActionListener.class, listener);
202: }
203:
204: public ActionListener[] getActionListeners() {
205: return (ActionListener[]) getListeners(ActionListener.class);
206: }
207:
208: /**
209: * Add an item listener which will be invoked for toggle actions.
210: */
211: public void addItemListener(ItemListener listener) {
212: addListener(ItemListener.class, listener);
213: }
214:
215: public void removeItemListener(ItemListener listener) {
216: removeListener(ItemListener.class, listener);
217: }
218:
219: public ItemListener[] getItemListeners() {
220: return (ItemListener[]) getListeners(ItemListener.class);
221: }
222:
223: // Callbacks...
224:
225: /**
226: * Callback for command actions.
227: */
228: public void actionPerformed(ActionEvent evt) {
229: ActionListener[] alist = getActionListeners();
230: if (alist != null) {
231: for (int i = 0; i < alist.length; i++) {
232: alist[i].actionPerformed(evt);
233: }
234: }
235: }
236:
237: /**
238: * Callback for toggle actions.
239: */
240: public void itemStateChanged(ItemEvent evt) {
241: // Update all objects that share this item
242: boolean newValue;
243: boolean oldValue = isSelected();
244:
245: if (evt.getStateChange() == ItemEvent.SELECTED) {
246: newValue = true;
247: } else {
248: newValue = false;
249: }
250:
251: if (oldValue != newValue) {
252: setSelected(newValue);
253:
254: // Forward the event to the delgate for handling.
255: ItemListener[] ilist = getItemListeners();
256: if (ilist != null) {
257: for (int i = 0; i < ilist.length; i++) {
258: ilist[i].itemStateChanged(evt);
259: }
260: }
261: }
262: }
263:
264: }
|