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 if (Main.toolbar != null) { 127 Main.toolbar.register(this); 128 } 129 setSelected(Main.pref.getBoolean("expert", false)); 130 notifySelectedState(); 131 } 132 133 @Override 134 protected final void notifySelectedState() { 135 super.notifySelectedState(); 136 fireExpertModeChanged(isSelected()); 137 } 138 139 @Override 140 public void actionPerformed(ActionEvent e) { 141 toggleSelectedState(e); 142 Main.pref.put("expert", isSelected()); 143 notifySelectedState(); 144 } 145 146 /** 147 * Replies the unique instance of this action. 148 * @return The unique instance of this action 149 */ 150 public static ExpertToggleAction getInstance() { 151 return INSTANCE; 152 } 153 154 /** 155 * Determines if expert mode is enabled. 156 * @return {@code true} if expert mode is enabled, {@code false} otherwise. 157 */ 158 public static boolean isExpert() { 159 return INSTANCE.isSelected(); 160 } 161}