001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.actions;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.awt.Component;
007 import java.awt.event.ActionEvent;
008 import java.lang.ref.WeakReference;
009 import java.util.ArrayList;
010 import java.util.Iterator;
011 import java.util.List;
012
013 import javax.swing.ButtonModel;
014
015 import org.openstreetmap.josm.Main;
016
017 public class ExpertToggleAction extends JosmAction {
018
019 private final List<ButtonModel> buttonModels = new ArrayList<ButtonModel>();
020 private boolean selected;
021
022 public interface ExpertModeChangeListener {
023 void expertChanged(boolean isExpert);
024 }
025
026 private static final List<WeakReference<ExpertModeChangeListener>> listeners = new ArrayList<WeakReference<ExpertModeChangeListener>>();
027 private static final List<WeakReference<Component>> visibilityToggleListeners = new ArrayList<WeakReference<Component>>();
028
029 private static ExpertToggleAction INSTANCE = new ExpertToggleAction();
030
031 private synchronized static void fireExpertModeChanged(boolean isExpert) {
032 {
033 Iterator<WeakReference<ExpertModeChangeListener>> it = listeners.iterator();
034 while (it.hasNext()) {
035 WeakReference<ExpertModeChangeListener> wr = it.next();
036 ExpertModeChangeListener listener = wr.get();
037 if (listener == null) {
038 it.remove();
039 continue;
040 }
041 listener.expertChanged(isExpert);
042 }
043 }
044 {
045 Iterator<WeakReference<Component>> it = visibilityToggleListeners.iterator();
046 while (it.hasNext()) {
047 WeakReference<Component> wr = it.next();
048 Component c = wr.get();
049 if (c == null) {
050 it.remove();
051 continue;
052 }
053 c.setVisible(isExpert);
054 }
055 }
056 }
057
058 /**
059 * Register a expert mode change listener
060 *
061 * @param listener the listener. Ignored if null.
062 */
063 public static void addExpertModeChangeListener(ExpertModeChangeListener listener) {
064 addExpertModeChangeListener(listener, false);
065 }
066
067 public synchronized static void addExpertModeChangeListener(ExpertModeChangeListener listener, boolean fireWhenAdding) {
068 if (listener == null) return;
069 for (WeakReference<ExpertModeChangeListener> wr : listeners) {
070 // already registered ? => abort
071 if (wr.get() == listener) return;
072 }
073 listeners.add(new WeakReference<ExpertModeChangeListener>(listener));
074 if (fireWhenAdding) {
075 listener.expertChanged(isExpert());
076 }
077 }
078
079 /**
080 * Removes a expert mode change listener
081 *
082 * @param listener the listener. Ignored if null.
083 */
084 public synchronized static void removeExpertModeChangeListener(ExpertModeChangeListener listener) {
085 if (listener == null) return;
086 Iterator<WeakReference<ExpertModeChangeListener>> it = listeners.iterator();
087 while (it.hasNext()) {
088 WeakReference<ExpertModeChangeListener> wr = it.next();
089 // remove the listener - and any other listener which god garbage
090 // collected in the meantime
091 if (wr.get() == null || wr.get() == listener) {
092 it.remove();
093 }
094 }
095 }
096
097 public synchronized static void addVisibilitySwitcher(Component c) {
098 if (c == null) return;
099 for (WeakReference<Component> wr : visibilityToggleListeners) {
100 // already registered ? => abort
101 if (wr.get() == c) return;
102 }
103 visibilityToggleListeners.add(new WeakReference<Component>(c));
104 c.setVisible(isExpert());
105 }
106
107 public synchronized static void removeVisibilitySwitcher(Component c) {
108 if (c == null) return;
109 Iterator<WeakReference<Component>> it = visibilityToggleListeners.iterator();
110 while (it.hasNext()) {
111 WeakReference<Component> wr = it.next();
112 // remove the listener - and any other listener which god garbage
113 // collected in the meantime
114 if (wr.get() == null || wr.get() == c) {
115 it.remove();
116 }
117 }
118 }
119
120 public ExpertToggleAction() {
121 super(
122 tr("Expert Mode"),
123 "expert",
124 tr("Enable/disable expert mode"),
125 null,
126 false /* register toolbar */
127 );
128 putValue("toolbar", "expertmode");
129 Main.toolbar.register(this);
130 selected = Main.pref.getBoolean("expert", false);
131 notifySelectedState();
132 }
133
134 public void addButtonModel(ButtonModel model) {
135 if (model != null && !buttonModels.contains(model)) {
136 buttonModels.add(model);
137 model.setSelected(selected);
138 }
139 }
140
141 public void removeButtonModel(ButtonModel model) {
142 if (model != null && buttonModels.contains(model)) {
143 buttonModels.remove(model);
144 }
145 }
146
147 protected void notifySelectedState() {
148 for (ButtonModel model: buttonModels) {
149 if (model.isSelected() != selected) {
150 model.setSelected(selected);
151 }
152 }
153 fireExpertModeChanged(selected);
154 }
155
156 protected void toggleSelectedState() {
157 selected = !selected;
158 Main.pref.put("expert", selected);
159 notifySelectedState();
160 }
161
162 public void actionPerformed(ActionEvent e) {
163 toggleSelectedState();
164 }
165
166 public boolean isSelected() {
167 return selected;
168 }
169
170 public static ExpertToggleAction getInstance() {
171 return INSTANCE;
172 }
173
174 public static boolean isExpert() {
175 return INSTANCE.isSelected();
176 }
177 }