// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.actions; import java.awt.event.ActionEvent; import java.util.HashSet; import java.util.Set; import javax.swing.ButtonModel; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JRadioButton; import javax.swing.JRadioButtonMenuItem; import javax.swing.JToggleButton; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.tools.ImageProvider; import org.openstreetmap.josm.tools.Shortcut; /** * Abtract class for Toggle Actions. * @since 6220 */ public abstract class ToggleAction extends JosmAction { private final transient Set buttonModels = new HashSet<>(); /** * Constructs a {@code ToggleAction}. * * @param name the action's text as displayed on the menu (if it is added to a menu) * @param icon the icon to use * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note * that html is not supported for menu actions on some platforms. * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always * do want a shortcut, remember you can always register it with group=none, so you * won't be assigned a shortcut unless the user configures one. If you pass null here, * the user CANNOT configure a shortcut for your action. * @param registerInToolbar register this action for the toolbar preferences? * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null * @param installAdapters false, if you don't want to install layer changed and selection changed adapters */ public ToggleAction(String name, ImageProvider icon, String tooltip, Shortcut shortcut, boolean registerInToolbar, String toolbarId, boolean installAdapters) { super(name, icon, tooltip, shortcut, registerInToolbar, toolbarId, installAdapters); // It is required to set the SELECTED_KEY to a non-null value in order to let Swing components update it setSelected(false); } /** * Constructs a {@code ToggleAction}. * * @param name the action's text as displayed on the menu (if it is added to a menu) * @param iconName the name of icon to use * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note * that html is not supported for menu actions on some platforms. * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always * do want a shortcut, remember you can always register it with group=none, so you * won't be assigned a shortcut unless the user configures one. If you pass null here, * the user CANNOT configure a shortcut for your action. * @param registerInToolbar register this action for the toolbar preferences? */ public ToggleAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar) { super(name, iconName, tooltip, shortcut, registerInToolbar); // It is required to set the SELECTED_KEY to a non-null value in order to let Swing components update it setSelected(false); } protected final void setSelected(boolean selected) { putValue(SELECTED_KEY, selected); } /** * Determines if this action is currently being selected. * @return {@code true} if this action is currently being selected, {@code false} otherwise */ public final boolean isSelected() { Object selected = getValue(SELECTED_KEY); if (selected instanceof Boolean) { return (Boolean) selected; } else { Main.warn(getClass().getName() + " does not define a boolean for SELECTED_KEY but " + selected + ". You should report it to JOSM developers."); return false; } } /** * Adds a button model * @param model The button model to add */ public final void addButtonModel(ButtonModel model) { if (model != null && !buttonModels.contains(model)) { buttonModels.add(model); model.setSelected(isSelected()); } } /** * Removes a button model * @param model The button model to remove */ public final void removeButtonModel(ButtonModel model) { if (model != null && buttonModels.contains(model)) { buttonModels.remove(model); } } protected void notifySelectedState() { boolean selected = isSelected(); for (ButtonModel model: buttonModels) { if (model.isSelected() != selected) { model.setSelected(selected); } } } /** * Toggles the selcted action state, if needed according to the ActionEvent that trigerred the action. * This method will do nothing if the action event comes from a Swing component supporting the SELECTED_KEY property because * the component already set the selected state. * This method needs to be called especially if the action is associated with a keyboard shortcut to ensure correct selected state. * @param e ActionEvent that trigerred the action * @see Changes to Actions in 1.6 * @see Interface Action */ protected final void toggleSelectedState(ActionEvent e) { if (e == null || !(e.getSource() instanceof JToggleButton || e.getSource() instanceof JCheckBox || e.getSource() instanceof JRadioButton || e.getSource() instanceof JCheckBoxMenuItem || e.getSource() instanceof JRadioButtonMenuItem )) { setSelected(!isSelected()); } } }