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.Image; 007import java.awt.Insets; 008import java.awt.event.ActionListener; 009import java.beans.PropertyChangeEvent; 010import java.beans.PropertyChangeListener; 011 012import javax.swing.Action; 013import javax.swing.BorderFactory; 014import javax.swing.Icon; 015import javax.swing.ImageIcon; 016import javax.swing.JButton; 017import javax.swing.SwingConstants; 018import javax.swing.plaf.basic.BasicArrowButton; 019 020import org.openstreetmap.josm.tools.Destroyable; 021import org.openstreetmap.josm.tools.ImageProvider; 022 023/** 024 * Button that is usually used in toggle dialogs 025 */ 026public class SideButton extends JButton implements Destroyable { 027 private static final int iconHeight = ImageProvider.ImageSizes.SIDEBUTTON.getImageSize(); 028 029 private transient PropertyChangeListener propertyChangeListener; 030 031 public SideButton(Action action) { 032 super(action); 033 fixIcon(action); 034 doStyle(); 035 } 036 037 public SideButton(Action action, boolean usename) { 038 super(action); 039 if (!usename) { 040 setText(null); 041 fixIcon(action); 042 doStyle(); 043 } 044 } 045 046 public SideButton(Action action, String imagename) { 047 super(action); 048 setIcon(makeIcon(imagename)); 049 doStyle(); 050 } 051 052 private void fixIcon(Action action) { 053 // need to listen for changes, so that putValue() that are called after the 054 // SideButton is constructed get the proper icon size 055 if (action != null) { 056 action.addPropertyChangeListener(propertyChangeListener = new PropertyChangeListener() { 057 @Override 058 public void propertyChange(PropertyChangeEvent evt) { 059 if (javax.swing.Action.SMALL_ICON.equals(evt.getPropertyName())) { 060 fixIcon(null); 061 } 062 } 063 }); 064 } 065 Icon i = getIcon(); 066 if (i instanceof ImageIcon && i.getIconHeight() != iconHeight) { 067 setIcon(getScaledImage(((ImageIcon) i).getImage())); 068 } 069 } 070 071 /** 072 * Scales the given image proportionally so that the height is "iconHeight" 073 * @param im original image 074 * @return scaled image 075 */ 076 private static ImageIcon getScaledImage(Image im) { 077 int newWidth = im.getWidth(null) * iconHeight / im.getHeight(null); 078 return new ImageIcon(im.getScaledInstance(newWidth, iconHeight, Image.SCALE_SMOOTH)); 079 } 080 081 public static ImageIcon makeIcon(String imagename) { 082 Image im = ImageProvider.get("dialogs", imagename).getImage(); 083 return getScaledImage(im); 084 } 085 086 private void doStyle() { 087 setLayout(new BorderLayout()); 088 setIconTextGap(2); 089 setMargin(new Insets(0, 0, 0, 0)); 090 } 091 092 public BasicArrowButton createArrow(ActionListener listener) { 093 setMargin(new Insets(0, 0, 0, 0)); 094 BasicArrowButton arrowButton = new BasicArrowButton(SwingConstants.SOUTH, null, null, Color.BLACK, null); 095 arrowButton.setBorder(BorderFactory.createEmptyBorder()); 096 add(arrowButton, BorderLayout.EAST); 097 arrowButton.addActionListener(listener); 098 return arrowButton; 099 } 100 101 @Override 102 public void destroy() { 103 Action action = getAction(); 104 if (action instanceof Destroyable) { 105 ((Destroyable) action).destroy(); 106 } 107 if (action != null) { 108 if (propertyChangeListener != null) { 109 action.removePropertyChangeListener(propertyChangeListener); 110 } 111 setAction(null); 112 } 113 } 114}