001: /*
002: * ActionBuilder.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.underworldlabs.swing.actions;
023:
024: import java.io.CharArrayWriter;
025: import java.io.IOException;
026: import java.io.InputStream;
027:
028: import java.net.URL;
029: import java.util.Enumeration;
030:
031: import java.util.HashMap;
032: import java.util.Iterator;
033: import java.util.Map;
034: import java.util.Properties;
035: import java.util.Set;
036:
037: import javax.swing.Action;
038: import javax.swing.ActionMap;
039: import javax.swing.ImageIcon;
040: import javax.swing.InputMap;
041: import javax.swing.JComponent;
042: import javax.swing.KeyStroke;
043:
044: import javax.xml.parsers.SAXParser;
045: import javax.xml.parsers.SAXParserFactory;
046: import org.underworldlabs.util.MiscUtils;
047:
048: import org.xml.sax.Attributes;
049: import org.xml.sax.SAXException;
050: import org.xml.sax.SAXParseException;
051: import org.xml.sax.helpers.DefaultHandler;
052:
053: // Utilitiy class to build all actions to be
054: // associated with buttons, menu items and key strokes.
055: /* ----------------------------------------------------------
056: * CVS NOTE: Changes to the CVS repository prior to the
057: * release of version 3.0.0beta1 has meant a
058: * resetting of CVS revision numbers.
059: * ----------------------------------------------------------
060: */
061:
062: /**
063: *
064: * @author Takis Diakoumis
065: * @version $Revision: 1.4 $
066: * @date $Date: 2006/05/14 06:56:07 $
067: */
068: public class ActionBuilder {
069:
070: private static final String ACTIONS = "actions";
071: private static final String ACTION = "action";
072: private static final String NAME = "name";
073: private static final String ID = "id";
074: private static final String MNEMONIC = "mnemonic";
075: private static final String SMALL_ICON = "small-icon";
076: private static final String LARGE_ICON = "large-icon";
077: private static final String ACCEL_KEY = "accel-key";
078: private static final String DESCRIPTION = "description";
079: private static final String EXECUTE_CLASS = "execute-class";
080: private static final String ACCEL_EDITABLE = "accel-editable";
081:
082: private static String delimiter = "+";
083:
084: private static HashMap userDefinedActionMap;
085: private static HashMap actionsMap;
086:
087: /**
088: * Builds the action map for the specified action and input maps
089: * using the actions as specified by the XML conf file at path.
090: *
091: * @param actionMap - the action map to bind to
092: * @param inputMap - the input map to bind to
093: * @param path - the path to the action XML conf file
094: */
095: public static void build(ActionMap actionMap, InputMap inputMap,
096: String path) {
097: actionsMap = (HashMap) loadActions(path);
098: build(actionMap, inputMap);
099: }
100:
101: public static void setActionMaps(JComponent component,
102: Properties shortcuts) {
103: ActionMap actionMap = component.getActionMap();
104: InputMap inputMap = component
105: .getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
106: build(actionMap, inputMap);
107:
108: if (shortcuts == null) {
109: return;
110: }
111:
112: buildUserKeymap(shortcuts, inputMap);
113: }
114:
115: public static void build(ActionMap actionMap, InputMap inputMap) {
116: String actionId = null;
117: BaseActionCommand command = null;
118:
119: if (actionMap == null) {
120: return;
121: }
122:
123: Set actionSet = actionsMap.keySet();
124:
125: for (Iterator i = actionSet.iterator(); i.hasNext();) {
126: command = (BaseActionCommand) actionsMap.get(i.next());
127: actionId = command.getActionId();
128: actionMap.put(actionId, command);
129:
130: if (command.hasAccelerator()) {
131: inputMap.put((KeyStroke) command
132: .getValue(Action.ACCELERATOR_KEY), actionId);
133: }
134:
135: }
136:
137: }
138:
139: private static void buildUserKeymap(Properties shortcuts,
140: InputMap inputMap) {
141:
142: String actionId = null;
143: BaseActionCommand command = null;
144:
145: for (Enumeration i = shortcuts.keys(); i.hasMoreElements();) {
146: actionId = (String) i.nextElement();
147: KeyStroke keyStroke = KeyStroke.getKeyStroke(shortcuts
148: .getProperty(actionId));
149:
150: command = (BaseActionCommand) actionsMap.get(actionId);
151: if (command != null) {
152: command.putValue(Action.ACCELERATOR_KEY, keyStroke);
153: }
154:
155: inputMap.put(keyStroke, actionId);
156: }
157:
158: }
159:
160: /**
161: * Reloads the actions from the action conf file at the specified path.
162: */
163: public static Map reloadActions(String path) {
164: return loadActions(path);
165: }
166:
167: /**
168: * Updates the action shortcut keys based on the properties specified.
169: *
170: * @param inputMap - the input map to bind to
171: * @param shortcuts - the new shortcut keys
172: */
173: public static void updateUserDefinedShortcuts(InputMap inputMap,
174: Properties shortcuts) {
175: if (shortcuts == null) {
176: return;
177: }
178: buildUserKeymap(shortcuts, inputMap);
179: }
180:
181: /**
182: * Returns a map containing key/value pairs of all the currently
183: * bound actions.
184: */
185: public static Map getActions() {
186: return actionsMap;
187: }
188:
189: /**
190: * Returns the action with the specified key name.
191: */
192: public static Action get(Object key) {
193: return (Action) actionsMap.get(key);
194: }
195:
196: private static Map loadActions(String path) {
197: InputStream input = null;
198: ClassLoader cl = ActionBuilder.class.getClassLoader();
199:
200: if (cl != null) {
201: input = cl.getResourceAsStream(path);
202: } else {
203: input = ClassLoader.getSystemResourceAsStream(path);
204: }
205:
206: try {
207: SAXParserFactory factory = SAXParserFactory.newInstance();
208: factory.setNamespaceAware(true);
209:
210: SAXParser parser = factory.newSAXParser();
211: ActionHandler handler = new ActionHandler();
212: parser.parse(input, handler);
213: return handler.getActions();
214: } catch (Exception e) {
215: e.printStackTrace();
216: throw new InternalError();
217: } finally {
218: try {
219: if (input != null) {
220: input.close();
221: }
222: } catch (IOException ioExc) {
223: }
224: }
225:
226: }
227:
228: static class ActionHandler extends DefaultHandler {
229:
230: private Map map;
231: private CharArrayWriter contents;
232: private BaseActionCommand actionCommand;
233:
234: public ActionHandler() {
235: contents = new CharArrayWriter();
236: map = new HashMap();
237: }
238:
239: private ImageIcon loadIcon(String path) {
240: URL url = ActionHandler.class.getResource(path);
241:
242: if (url != null) {
243: return new ImageIcon(url);
244: }
245:
246: return null;
247: }
248:
249: public Map getActions() {
250: return map;
251: }
252:
253: public void startElement(String nameSpaceURI, String localName,
254: String qName, Attributes attrs) {
255: String value = null;
256: contents.reset();
257:
258: if (localName.equals(ACTION)) {
259:
260: actionCommand = new BaseActionCommand();
261: actionCommand.setActionId(attrs.getValue(ID));
262: actionCommand.putValue(Action.NAME, attrs
263: .getValue(NAME));
264:
265: value = attrs.getValue(MNEMONIC);
266: if (!MiscUtils.isNull(value)) {
267: actionCommand.putValue(Action.MNEMONIC_KEY,
268: new Integer(value.charAt(0)));
269: }
270:
271: //value = attrs.getValue(LARGE_ICON);
272: value = attrs.getValue(SMALL_ICON);
273: if (!MiscUtils.isNull(value)) {
274: actionCommand.putValue(Action.SMALL_ICON,
275: loadIcon(value));
276: }
277:
278: value = attrs.getValue(ACCEL_KEY);
279: if (!MiscUtils.isNull(value)) {
280: actionCommand.putValue(Action.ACCELERATOR_KEY,
281: KeyStroke.getKeyStroke(value));
282: }
283:
284: value = attrs.getValue(ACCEL_EDITABLE);
285: if (!MiscUtils.isNull(value)) {
286: actionCommand.setAcceleratorEditable(Boolean
287: .valueOf(value).booleanValue());
288: }
289:
290: actionCommand.putValue(Action.SHORT_DESCRIPTION, attrs
291: .getValue(DESCRIPTION));
292: actionCommand.setCommand(attrs.getValue(EXECUTE_CLASS));
293:
294: }
295:
296: }
297:
298: public void endElement(String nameSpaceURI, String localName,
299: String qName) {
300:
301: if (localName.equals(ACTION)) {
302: map.put(actionCommand.getActionId(), actionCommand);
303: }
304:
305: }
306:
307: public void characters(char[] data, int start, int length) {
308: contents.write(data, start, length);
309: }
310:
311: public void ignorableWhitespace(char[] data, int start,
312: int length) {
313: characters(data, start, length);
314: }
315:
316: public void error(SAXParseException spe) throws SAXException {
317: throw new SAXException(spe.getMessage());
318: }
319:
320: } // ActionHandler
321:
322: }
|