/* * File : Actions.java * Created : 18-dec-2001 10:48 * By : fbusquets * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2018 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details (see the LICENSE file). */ package edu.xtec.util; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.util.HashMap; import java.util.Map; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.JComponent; /** * Miscellaneous utilities for managing {@link javax.swing.Action} objects. * *

* EXAMPLES: * *

* Creation of a new action, with reference to a original key: * AbstractAction beginAction=new AbstractAction(DefaultEditorKit.beginAction){ * public void actionPerformed(ActionEvent e){ * // ... * } * }; * Creation of a new action, with a new key: * AbstractAction prevTargetAction=new AbstractAction("prev-target"){ * public void actionPerformed(ActionEvent e){ * // ... * } * }; * Action that references an existing one: * Action kitUpAction=null; * AbstractAction upAction=new AbstractAction(DefaultEditorKit.upAction){ * public void actionPerformed(ActionEvent e){ * if(kitUpAction!=null){ * // .... pre-action * kitUpAction.actionPerformed(e); * // .... post-action * } * } * }; * Actions mapping: * protected void setActions(){ * // get existing actions: * kitUpAction=getActionMap().get(DefaultEditorKit.upAction); * * // actionKeys init: * java.util.HashMap actionKeys=Actions.getActionKeys(this); * * // build new ActionMap: * ActionMap am=new ActionMap(); * am.setParent(getActionMap()); * setActionMap(am); * * //Actions derived to trace (only for debug purposes): * Actions.mapTraceAction(this, actionKeys, DefaultEditorKit.readOnlyAction); * Actions.mapTraceAction(this, actionKeys, DefaultEditorKit.writableAction); * Actions.mapTraceAction(this, actionKeys, "requestFocus"); * Actions.mapTraceAction(this, actionKeys, "toggle-componentOrientation"); * * //Actions to disable: * Actions.mapNullAction(this, actionKeys, DefaultEditorKit.beepAction); * * //New actions: * Actions.mapAction(this, actionKeys, beginAction); * Actions.mapAction(this, actionKeys, upAction); * * //Original actions mapped to other methods: * Actions.mapAction(this, actionKeys, beginAction, DefaultEditorKit.previousWordAction); * Actions.mapAction(this, actionKeys, prevTargetAction, DefaultEditorKit.beginParagraphAction); * * //Uncomment this line only if you want to hide all other actions: * //am.setParent(null); * // * * // Assign keystrokes to a new action: * getInputMap().put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_TAB, java.awt.Event.SHIFT_MASK), prevTargetAction.getValue(Action.NAME)); * } * * * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.08.08 */ public abstract class Actions { /** * Collects the keys of all the actions linked to a specific * {@link javax.swing.JComponent} and groups them in arrays by action names. * * @param jc The JComponent with the actions linked to. * @return A HashMap formed by pairs of action names (key) and arrays of action * keys (value). Usually each action name has only one action key * associated to it, and the value of the pair is an object array with * only one string, but this is not an imperative: several actions can * be associated to a single name. */ public static Map getActionKeys(JComponent jc) { Map result = new HashMap(); ActionMap am = jc.getActionMap(); for (Object amk : am.allKeys()) { Action act = am.get(amk); Object o = act.getValue(Action.NAME); if (o == null) o = ""; String name = o.toString(); Object[] keys = result.get(name); if (keys == null) keys = new Object[] { amk }; else { Object[] k2 = new Object[keys.length + 1]; int j; for (j = 0; j < keys.length; j++) k2[j] = keys[j]; k2[j] = amk; keys = k2; } result.put(name, keys); } return result; } /** * This function is for debug purposes only. Prints out the * * @param actionKeys * @param am */ public static void dumpActionKeys(Map actionKeys, ActionMap am) { for (String key : actionKeys.keySet()) { System.out.println(key + ":"); for (Object val : (Object[]) actionKeys.get(key)) System.out.println(" - " + val + " >> " + am.get(val)); } } public static void mapAction(JComponent jc, Map actionKeys, Action act) { if (actionKeys == null) { actionKeys = getActionKeys(jc); } if (jc != null && act != null && actionKeys != null) { ActionMap am = jc.getActionMap(); String name = (String) act.getValue(Action.NAME); Object[] keys = actionKeys.get(name); boolean replaced = false; if (keys != null) { for (Object key : keys) { am.put(key, act); if (key.equals(name)) { replaced = true; } } } if (!replaced) { am.put(name, act); } } } public static void mapAction(JComponent jc, Map actionKeys, Action act, String key) { if (actionKeys == null) { actionKeys = getActionKeys(jc); } if (jc != null && actionKeys != null) { ActionMap am = jc.getActionMap(); Object[] keys = actionKeys.get(key); boolean replaced = false; if (keys != null) { for (Object k : keys) { am.put(k, act); if (k.equals(key)) { replaced = true; } } } if (!replaced) { am.put(key, act); } } } public static class NullAction extends AbstractAction { public NullAction(String name) { super(name); } public void actionPerformed(ActionEvent e) { // do nothing } } public static void mapNullAction(JComponent jc, Map actionKeys, String s) { mapAction(jc, actionKeys, new edu.xtec.util.Actions.NullAction(s)); } public static class TraceAction extends AbstractAction { Action bkAction = null; Object bkKey = null; public TraceAction(Action act, Object key) { super((String) (key instanceof String ? key : "")); bkAction = act; bkKey = key; } public void actionPerformed(ActionEvent e) { System.out.println("TRACE: " + (bkAction != null ? bkAction.getValue(Action.NAME) : "") + " " + bkKey); if (bkAction != null) bkAction.actionPerformed(e); } } public static void mapTraceAction(JComponent jc, Map actionKeys, String s) { mapAction(jc, actionKeys, new edu.xtec.util.Actions.TraceAction(jc.getActionMap().get(s), s)); } public static void traceHierarchy(Component cmp, int level) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; i++) sb.append(" "); sb.append(cmp); System.out.println(sb.substring(0)); if (cmp instanceof Container) { for (Component cmp2 : ((Container) cmp).getComponents()) traceHierarchy(cmp2, level + 1); } } }