001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui;
003
004import java.awt.BorderLayout;
005import java.awt.Color;
006import java.awt.Insets;
007import java.awt.event.ActionListener;
008import java.beans.PropertyChangeListener;
009
010import javax.swing.AbstractAction;
011import javax.swing.Action;
012import javax.swing.BorderFactory;
013import javax.swing.JButton;
014import javax.swing.SwingConstants;
015import javax.swing.plaf.basic.BasicArrowButton;
016
017import org.openstreetmap.josm.tools.Destroyable;
018import org.openstreetmap.josm.tools.ImageProvider;
019import org.openstreetmap.josm.tools.ImageResource;
020
021/**
022 * Button that is usually used in toggle dialogs.
023 * @since 744
024 */
025public class SideButton extends JButton implements Destroyable {
026
027    private transient PropertyChangeListener propertyChangeListener;
028    private BasicArrowButton arrowButton;
029    private boolean arrowEnabledWithButton;
030
031    /**
032     * Constructs a new {@code SideButton}.
033     * @param action action used to specify the new button
034     * an icon must be provided with {@link ImageResource#attachImageIcon(AbstractAction, boolean)}
035     * @throws IllegalArgumentException if no icon provided
036     * @since 744
037     */
038    public SideButton(Action action) {
039        super(action);
040        ImageResource icon = (ImageResource) action.getValue("ImageResource");
041        if (icon != null) {
042            setIcon(icon.getImageIconBounded(
043                ImageProvider.ImageSizes.SIDEBUTTON.getImageDimension()));
044        } else {
045            throw new IllegalArgumentException("No icon provided");
046        }
047        doStyle();
048    }
049
050    /**
051     * Constructs a new {@code SideButton}.
052     * @param action action used to specify the new button
053     * @param usename use action name
054     * @since 2710
055     */
056    public SideButton(Action action, boolean usename) {
057        this(action);
058        if (!usename) {
059            setText(null);
060        }
061    }
062
063    /**
064     * Constructs a new {@code SideButton}.
065     * @param action action used to specify the new button
066     * @param imagename image name in "dialogs" directory
067     * @since 2747
068     */
069    public SideButton(Action action, String imagename) {
070        super(action);
071        setIcon(ImageProvider.get("dialogs", imagename, ImageProvider.ImageSizes.SIDEBUTTON));
072        doStyle();
073    }
074
075    /**
076     * Do the style settings for the side button layout
077     */
078    private void doStyle() {
079        setLayout(new BorderLayout());
080        setIconTextGap(2);
081        setMargin(new Insets(0, 0, 0, 0));
082    }
083
084    /**
085     * Create the arrow for opening a drop-down menu
086     * @param listener listener to use for button actions (e.g. pressing)
087     * @return the created button
088     * @since 9668
089     */
090    public BasicArrowButton createArrow(ActionListener listener) {
091        return createArrow(listener, false);
092    }
093
094    /**
095     * Create the arrow for opening a drop-down menu
096     * @param listener listener to use for button actions (e.g. pressing)
097     * @param enabledWithButton determines if the button arrow enabled state is the same as main button
098     * @return the created button
099     * @since 13545
100     */
101    public BasicArrowButton createArrow(ActionListener listener, boolean enabledWithButton) {
102        setMargin(new Insets(0, 0, 0, 0));
103        arrowEnabledWithButton = enabledWithButton;
104        arrowButton = new BasicArrowButton(SwingConstants.SOUTH, null, null, Color.BLACK, null);
105        arrowButton.setBorder(BorderFactory.createEmptyBorder());
106        add(arrowButton, BorderLayout.EAST);
107        arrowButton.addActionListener(listener);
108        if (arrowEnabledWithButton) {
109            arrowButton.setEnabled(isEnabled());
110        }
111        return arrowButton;
112    }
113
114    @Override
115    public void setEnabled(boolean b) {
116        super.setEnabled(b);
117        if (arrowButton != null && arrowEnabledWithButton) {
118            arrowButton.setEnabled(b);
119        }
120    }
121
122    @Override
123    public void destroy() {
124        Action action = getAction();
125        if (action instanceof Destroyable) {
126            ((Destroyable) action).destroy();
127        }
128        if (action != null) {
129            if (propertyChangeListener != null) {
130                action.removePropertyChangeListener(propertyChangeListener);
131            }
132            setAction(null);
133        }
134        arrowButton = null;
135    }
136}