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 }