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 }