001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.gui; 003 004 import java.awt.event.MouseAdapter; 005 import java.awt.event.MouseEvent; 006 import java.beans.PropertyChangeEvent; 007 import java.beans.PropertyChangeListener; 008 009 import javax.swing.AbstractAction; 010 import javax.swing.Action; 011 import javax.swing.Icon; 012 import javax.swing.JToggleButton; 013 014 import org.openstreetmap.josm.Main; 015 import org.openstreetmap.josm.actions.ExpertToggleAction; 016 import org.openstreetmap.josm.actions.ExpertToggleAction.ExpertModeChangeListener; 017 import org.openstreetmap.josm.tools.Destroyable; 018 019 /** 020 * Just a toggle button, with smaller border and icon only to display in 021 * MapFrame toolbars. 022 * Also provides methods for storing hidden state in preferences 023 * @author imi, akks 024 */ 025 public class IconToggleButton extends JToggleButton implements HideableButton, PropertyChangeListener, Destroyable, ExpertModeChangeListener { 026 027 public boolean groupbutton; 028 private ShowHideButtonListener listener; 029 private boolean hideIfDisabled = false; 030 private boolean isExpert; 031 032 /** 033 * Construct the toggle button with the given action. 034 */ 035 public IconToggleButton(Action action) { 036 this(action, false); 037 } 038 039 /** 040 * Construct the toggle button with the given action. 041 */ 042 public IconToggleButton(Action action, boolean isExpert) { 043 super(action); 044 this.isExpert = isExpert; 045 setText(null); 046 047 Object o = action.getValue(Action.SHORT_DESCRIPTION); 048 if (o != null) { 049 setToolTipText(o.toString()); 050 } 051 052 action.addPropertyChangeListener(this); 053 054 addMouseListener(new MouseAdapter(){ 055 @Override public void mousePressed(MouseEvent e) { 056 groupbutton = e.getX() > getWidth()/2 && e.getY() > getHeight()/2; 057 } 058 }); 059 060 ExpertToggleAction.addExpertModeChangeListener(this); 061 } 062 063 public void propertyChange(PropertyChangeEvent evt) { 064 if (evt.getPropertyName().equals("active")) { 065 setSelected((Boolean)evt.getNewValue()); 066 requestFocusInWindow(); 067 } else if (evt.getPropertyName().equals("selected")) { 068 setSelected((Boolean)evt.getNewValue()); 069 } 070 } 071 072 public void destroy() { 073 Action action = getAction(); 074 if (action instanceof Destroyable) { 075 ((Destroyable) action).destroy(); 076 } 077 if (action != null) { 078 action.removePropertyChangeListener(this); 079 } 080 } 081 082 String getPreferenceKey() { 083 String s = (String) getSafeActionValue("toolbar"); 084 if (s == null) { 085 if (getAction()!=null) { 086 s = getAction().getClass().getName(); 087 } 088 } 089 return "sidetoolbar.hidden."+s; 090 091 } 092 093 @Override 094 public void expertChanged(boolean isExpert) { 095 applyButtonHiddenPreferences(); 096 } 097 098 @Override 099 public void applyButtonHiddenPreferences() { 100 boolean alwaysHideDisabled = Main.pref.getBoolean("sidetoolbar.hideDisabledButtons", false); 101 if (!isEnabled() && (hideIfDisabled || alwaysHideDisabled)) { 102 setVisible(false); // hide because of disabled button 103 } else { 104 boolean hiddenFlag = false; 105 String hiddenFlagStr = Main.pref.get(getPreferenceKey(), null); 106 if (hiddenFlagStr == null) { 107 if (isExpert && !ExpertToggleAction.isExpert()) { 108 hiddenFlag = true; 109 } 110 } else { 111 hiddenFlag = Boolean.parseBoolean(hiddenFlagStr); 112 } 113 setVisible( !hiddenFlag ); // show or hide, do what preferences say 114 } 115 } 116 117 @Override 118 public void setButtonHidden(boolean b) { 119 setVisible(!b); 120 if (listener!=null) { // if someone wants to know about changes of visibility 121 if (!b) listener.buttonShown(); else listener.buttonHidden(); 122 } 123 if ((b && isExpert && !ExpertToggleAction.isExpert()) || 124 (!b && isExpert && ExpertToggleAction.isExpert())) { 125 Main.pref.put(getPreferenceKey(), null); 126 } else { 127 Main.pref.put(getPreferenceKey(), b); 128 } 129 } 130 131 /* 132 * This fuction should be called for plugins that want to enable auto-hiding 133 * custom buttons when they are disabled (because of incorrect layer, for example) 134 */ 135 public void setAutoHideDisabledButton(boolean b) { 136 hideIfDisabled = b; 137 if (b && !isEnabled()) { 138 setVisible(false); 139 } 140 } 141 142 @Override 143 public void showButton() { 144 setButtonHidden(false); 145 } 146 147 @Override 148 public void hideButton() { 149 setButtonHidden(true); 150 } 151 152 @Override 153 public String getActionName() { 154 return (String) getSafeActionValue(Action.NAME); 155 } 156 157 @Override 158 public Icon getIcon() { 159 return (Icon) getSafeActionValue(Action.SMALL_ICON); 160 } 161 162 @Override 163 public boolean isButtonVisible() { 164 return isVisible(); 165 } 166 167 @Override 168 public void setShowHideButtonListener(ShowHideButtonListener l) { 169 listener = l; 170 } 171 172 protected final Object getSafeActionValue(String key) { 173 // Mac OS X Aqua L&F can call accessors from constructor, so getAction() can be null in those cases 174 return getAction() != null ? getAction().getValue(key) : null; 175 } 176 }