// License: GPL. For details, see LICENSE file. package at.dallermassl.josm.plugin.surveyor; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.ComponentInputMap; import javax.swing.Icon; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JToggleButton; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.plaf.ActionMapUIResource; import org.openstreetmap.josm.tools.ImageProvider; /** * this class represents a button as it is described in the xml file. * @author cdaller * */ public class ButtonDescription { private String label; private String hotkey; private String iconName; private ButtonType type; private List<SurveyorActionDescription> actions; private GpsDataSource gpsDataSource; /** * Default Constructor */ public ButtonDescription() { super(); } /** * @param actions a list of actions to be performed. * @param type if <code>null</code> {@link ButtonType#SINGLE} is used. */ public ButtonDescription(String label, String hotkey, String iconName, String buttonAction, ButtonType type) { this(label, hotkey, iconName, createFromOneElement(new SurveyorActionDescription(buttonAction)), type); } /** * @param actions a list of actions to be performed. * @param type if <code>null</code> {@link ButtonType#SINGLE} is used. */ public ButtonDescription(String label, String hotkey, String iconName, SurveyorActionDescription actionDescription, ButtonType type) { this(label, hotkey, iconName, createFromOneElement(actionDescription), type); } /** * Helper method to create a list from one element. * @param buttonActionClassName the action's class name. * @return a list holding one ButtonActionDescription element. */ private static List<SurveyorActionDescription> createFromOneElement(SurveyorActionDescription actionDescription) { List<SurveyorActionDescription> list = new ArrayList<>(); list.add(actionDescription); return list; } /** * @param actions a list of actions to be performed. * @param type if <code>null</code> {@link ButtonType#SINGLE} is used. */ public ButtonDescription(String label, String hotkey, String iconName, List<SurveyorActionDescription> actions, ButtonType type) { super(); this.label = label; this.hotkey = hotkey; this.iconName = iconName; if (type == null) { this.type = ButtonType.SINGLE; } else { this.type = type; } this.actions = actions; } /** * @return the actions */ public List<SurveyorActionDescription> getActions() { return this.actions; } /** * @param actions the actions to set */ public void setActions(List<SurveyorActionDescription> actions) { this.actions = actions; } /** * @return the hotkey */ public String getHotkey() { return this.hotkey; } /** * @param hotkey the hotkey to set */ public void setHotkey(String hotkey) { this.hotkey = hotkey; } /** * @return the label */ public String getLabel() { return this.label; } /** * @param label the label to set */ public void setLabel(String label) { this.label = label; } /** * @return the type */ public ButtonType getButtonType() { return this.type; } /** * Set the button type as a string. * @param type the type of the button * @see ButtonType */ public void setType(String type) { try { this.type = ButtonType.valueOf(type.toUpperCase()); } catch (IllegalArgumentException e) { System.err.println("Unknown button type '" + type + "' given. Allowed values are " + Arrays.toString(ButtonType.values())); } } /** * @param type the type to set */ public void setButtonType(ButtonType type) { this.type = type; } /** * Sets the name of the icon. */ public void setIcon(String icon) { this.iconName = icon; } /** * Creates the button. * @return the button. */ public JComponent createComponent() { String actionName = tr(getLabel()) + " (" + hotkey + ")"; Icon icon = ImageProvider.getIfAvailable(null, iconName); if (icon == null) icon = ImageProvider.getIfAvailable("markers", iconName); if (icon == null) icon = ImageProvider.getIfAvailable("symbols", iconName); if (icon == null) icon = ImageProvider.getIfAvailable("nodes", iconName); MetaAction action = new MetaAction(actionName, icon); action.setActions(actions); action.setGpsDataSource(gpsDataSource); AbstractButton button; if (type == ButtonType.TOGGLE) { button = new JToggleButton(action); connectActionAndButton(action, button); } else { button = new JButton(action); } button.setActionCommand(label); // connect component keyboard map with buttons: ActionMap actionMap = new ActionMapUIResource(); actionMap.put(actionName, action); InputMap keyMap = new ComponentInputMap(button); keyMap.put(KeyStroke.getKeyStroke(hotkey), actionName); SwingUtilities.replaceUIActionMap(button, actionMap); SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_IN_FOCUSED_WINDOW, keyMap); return button; } private static void connectActionAndButton(Action action, AbstractButton button) { SelectionStateAdapter adapter = new SelectionStateAdapter(action, button); adapter.configure(); } /** * Class that connects the selection state of the action * to the selection state of the button. * * @author R.J. Lorimer */ private static class SelectionStateAdapter implements PropertyChangeListener, ItemListener { private Action action; private AbstractButton button; SelectionStateAdapter(Action theAction, AbstractButton theButton) { action = theAction; button = theButton; } protected void configure() { action.addPropertyChangeListener(this); button.addItemListener(this); } public void itemStateChanged(ItemEvent e) { boolean value = e.getStateChange() == ItemEvent.SELECTED; Boolean valueObj = Boolean.valueOf(value); action.putValue(ActionConstants.SELECTED_KEY, valueObj); } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(ActionConstants.SELECTED_KEY)) { Boolean newSelectedState = (Boolean) evt.getNewValue(); button.setSelected(newSelectedState.booleanValue()); } } } /** * Set the source of gps data. * @param gpsDataSource the source from where gps data can be obtained. */ public void setGpsDataSource(GpsDataSource gpsDataSource) { this.gpsDataSource = gpsDataSource; } }