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