/** * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bushe.swing.action; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.awt.event.ActionListener; import javax.swing.Action; /** * Acts as a list or tree for actions or action ids. * <p> * Represents a List of Actions, ActionList elements or Separators. The null element may represent * a separator. Sometimes the list is used as a lazy initialization structure internal to the Action * framework, however, public use will find typically show Action and * ActionLists only. * <p> * The list itself describes it's id, and also the id of the action * that triggers it. * <p> * The list has an associated set of roles that the ActionManager respects. */ public class ActionList implements List { private Object id; private Object triggerActionId; private Number weight; //list of actions private List list = new ArrayList(); //The roles required for the user to see the list private List roles; /** * Supply the id for this list. * @param id the id of the list */ public ActionList(Object id) { this.id = id; } /** * Supply the id for this list and the id for the action that * triggers this list (in XML the actionList's idref attribute). * @param id the id of the list * @param triggerActionId the id of the action that * is fired when a menu is shown, can be null. */ public ActionList(Object id, Object triggerActionId) { this(id); this.triggerActionId = triggerActionId; } /** * Retuns the action-list id that this class represents. */ public Object getId() { return id; } /** * @return the id for the Action that triggers this action list, in * the XML the actionList's idref or id */ public Object getTriggerActionId() { return triggerActionId; } /**@return an unmodifiable list of Strings, each one a role name for the list*/ public List getRoles() { if (roles == null) { return null; } return Collections.unmodifiableList(roles); } /** * @return the weight of this list relative to siblings in another list */ public Number getWeight() { return weight; } /** * @param weight the weight of this list relative to siblings in another list */ public void setWeight(Number weight) { this.weight = weight; } /** * Set the List of roles names (Strings) for the ActionList. The user will * not see the list unless they play in at least one of the roles of the * ActionList. */ public void setRoles(List roles) { this.roles = roles; } /** * Finds the action matching the id in the tree-like list. * @param id the id of the action, should be unique within * the tree, otherwise, first one found is returned (breadth first) * @return an Action whose ActionManager.ID property is .equal() to the * provided id. Null if not found. */ public Action getActionById(Object id) { return findActionInList(id, list); } /** * Calls addActionListener(delegate) on all action in the action * list (even on actions deep in a hierarchy) * @todo needs test */ public void addActionListenerToAll(ActionListener delegate) { BasicAction action = null; Iterator iter = iterator(); while (iter.hasNext()) { Object item = iter.next(); if (item == null) { continue; } if (item instanceof BasicAction) { action = (BasicAction) item; action.addActionListener(delegate); } } //Do submenus too iter = iterator(); while (iter.hasNext()) { Object subList = iter.next(); if (subList == null) { continue; } if (subList instanceof ActionList) { ((ActionList)subList).addActionListenerToAll(delegate); } } } /** * Finds an action in the ActionList (and the ActionLists in the * ActionList, recursively, depth first. * @param id the id of the action * @param actionList the action list to look in (for recursion) * @return the action matching the id or null if not found. */ private Action findActionInList(Object id, List actionList) { Iterator iter = actionList.iterator(); while (iter.hasNext()) { Object item = iter.next(); if (item == null) { continue; } if (item instanceof Action) { Action action = (Action) item; if (id.equals(action.getValue(ActionManager.ID))) { return action; } } } //twice because depth first is probably preferable //since submenus are used less often iter = actionList.iterator(); while (iter.hasNext()) { Object subList = iter.next(); if (subList == null) { continue; } if (subList instanceof ActionList) { Action result = findActionInList(id, (ActionList) subList); if (result != null) { return result; } } } return null; } /** * Sets the context for all the actions in an ActionList if the * Action is ContextAware (BasicAction is ContextAware). * Depending on the action, this will force an updateEnabledState() * (it will by default in BasicAction) * @see ContextAware * @see BasicAction * @param context Map a map of key/value pairs for actions. */ public void setContextForAll(Map context) { for (Iterator iterator = this.iterator(); iterator.hasNext();) { Object action = iterator.next(); if (action instanceof ContextAware) { ContextAware contextAwareAction = (ContextAware)action; contextAwareAction.setContext(context); } } } /** * Sets a context value for all the actions in an ActionList if the Action is ContextAware * (BasicAction is ContextAware). * <p> * Context values are separate from putValue()/getValue() values from javax.swing.Action. * <p> * In action XML, <context name="foo" value="bar"> turns into a context value. * <p> * Depending on the action, this will force an updateEnabledState() (it will by default for any BasicAction). * @see ContextAware * @see BasicAction * @param key key for the context value. * @todo Action XML have name-value-par for action-list, which calls this method (? When if merging?) */ public void putContextValueForAll(Object key, Object contextValue) { for (Iterator iterator = this.iterator(); iterator.hasNext();) { Object action = iterator.next(); if (action instanceof ContextAware) { ContextAware contextAwareAction = (ContextAware)action; contextAwareAction.putContextValue(key, contextValue); } } } /** * Asks all the BasicActions in the list to update their enabled states. * <p> * If setContextForAll() is used, this is usually not necessary, since * contextChanged() in BasicAction calls updateEnabledState by default. * @see BasicAction */ public void updateEnabledForAll() { for (Iterator iterator = this.iterator(); iterator.hasNext();) { Object action = iterator.next(); if (action instanceof EnabledUpdater) { EnabledUpdater updateEnabledAction = (EnabledUpdater)action; updateEnabledAction.updateEnabled(); } } } /** * Sets the enabled state for all the Actions in the list. */ public void setEnabledForAll(boolean enabled) { for (Iterator iterator = this.iterator(); iterator.hasNext();) { Object action = iterator.next(); if (action instanceof Action) { ((Action)action).setEnabled(enabled); } } } //List implementation public int size() { return list.size(); } public boolean isEmpty() { return list.isEmpty(); } public boolean contains(Object o) { return list.contains(o); } public Iterator iterator() { return list.iterator(); } public Object[] toArray() { return list.toArray(); } public Object[] toArray(Object[] a) { return list.toArray(a); } public boolean add(Object o) { return list.add(o); } public boolean remove(Object o) { return list.remove(o); } public boolean containsAll(Collection c) { return list.containsAll(c); } public boolean addAll(Collection c) { return list.addAll(c); } public boolean addAll(int index, Collection c) { return list.addAll(index, c); } public boolean removeAll(Collection c) { return list.removeAll(c); } public boolean retainAll(Collection c) { return list.retainAll(c); } public void clear() { list.clear(); } public Object get(int index) { return list.get(index); } public Object set(int index, Object element) { return list.set(index, element); } public void add(int index, Object element) { list.add(index, element); } public Object remove(int index) { return list.remove(index); } public int indexOf(Object o) { return list.indexOf(o); } public int lastIndexOf(Object o) { return list.lastIndexOf(o); } public ListIterator listIterator() { return list.listIterator(); } public ListIterator listIterator(int index) { return list.listIterator(index); } public List subList(int fromIndex, int toIndex) { return list.subList(fromIndex, toIndex); } }