// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.actions;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Component;
import java.awt.event.ActionEvent;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.preferences.BooleanProperty;
import org.openstreetmap.josm.tools.ListenerList;
/**
* This action toggles the Expert mode.
* @since 4840
*/
public class ExpertToggleAction extends ToggleAction {
/**
* This listener is notified whenever the expert mode setting changed.
*/
@FunctionalInterface
public interface ExpertModeChangeListener {
/**
* The expert mode changed.
* @param isExpert true
if expert mode was enabled, false otherwise.
*/
void expertChanged(boolean isExpert);
}
// TODO: Switch to checked list. We can do this as soon as we do not see any more warnings.
private static final ListenerList listeners = ListenerList.createUnchecked();
private static final ListenerList visibilityToggleListeners = ListenerList.createUnchecked();
private static final BooleanProperty PREF_EXPERT = new BooleanProperty("expert", false);
private static final ExpertToggleAction INSTANCE = new ExpertToggleAction();
private static synchronized void fireExpertModeChanged(boolean isExpert) {
listeners.fireEvent(listener -> listener.expertChanged(isExpert));
visibilityToggleListeners.fireEvent(c -> c.setVisible(isExpert));
}
/**
* Register a expert mode change listener
*
* @param listener the listener. Ignored if null.
*/
public static void addExpertModeChangeListener(ExpertModeChangeListener listener) {
addExpertModeChangeListener(listener, false);
}
public static synchronized void addExpertModeChangeListener(ExpertModeChangeListener listener, boolean fireWhenAdding) {
if (listener == null) return;
listeners.addWeakListener(listener);
if (fireWhenAdding) {
listener.expertChanged(isExpert());
}
}
/**
* Removes a expert mode change listener
*
* @param listener the listener. Ignored if null.
*/
public static synchronized void removeExpertModeChangeListener(ExpertModeChangeListener listener) {
if (listener == null) return;
listeners.removeListener(listener);
}
/**
* Marks a component to be only visible when expert mode is enabled. The visibility of the component is changed automatically.
* @param c The component.
*/
public static synchronized void addVisibilitySwitcher(Component c) {
if (c == null) return;
visibilityToggleListeners.addWeakListener(c);
c.setVisible(isExpert());
}
/**
* Stops tracking visibility changes for the given component.
* @param c The component.
* @see #addVisibilitySwitcher(Component)
*/
public static synchronized void removeVisibilitySwitcher(Component c) {
if (c == null) return;
visibilityToggleListeners.removeListener(c);
}
/**
* Constructs a new {@code ExpertToggleAction}.
*/
public ExpertToggleAction() {
super(tr("Expert Mode"),
"expert",
tr("Enable/disable expert mode"),
null,
false /* register toolbar */
);
putValue("toolbar", "expertmode");
if (Main.toolbar != null) {
Main.toolbar.register(this);
}
setSelected(PREF_EXPERT.get());
notifySelectedState();
}
@Override
protected final void notifySelectedState() {
super.notifySelectedState();
PREF_EXPERT.put(isSelected());
fireExpertModeChanged(isSelected());
}
/**
* Forces the expert mode state to the given state.
* @param isExpert if expert mode should be used.
* @since 11224
*/
public void setExpert(boolean isExpert) {
if (isSelected() != isExpert) {
setSelected(isExpert);
notifySelectedState();
}
}
@Override
public void actionPerformed(ActionEvent e) {
toggleSelectedState(e);
notifySelectedState();
}
/**
* Replies the unique instance of this action.
* @return The unique instance of this action
*/
public static ExpertToggleAction getInstance() {
return INSTANCE;
}
/**
* Determines if expert mode is enabled.
* @return {@code true} if expert mode is enabled, {@code false} otherwise.
*/
public static boolean isExpert() {
return INSTANCE.isSelected();
}
}