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