001package jmri.implementation.swing;
002
003import java.awt.Component;
004
005import jmri.implementation.AbstractShutDownTask;
006import jmri.util.swing.JmriJOptionPane;
007
008/**
009 * Provides a base for using Swing to ask if shutdown should conditionally
010 * continue.
011 * <p>
012 * Sequence:
013 * <ol>
014 * <li>checkPromptNeeded determines if ready to shutdown. If so, return ready.
015 * <li>Issue a prompt, asking if the user wants to continue or do something else
016 * <li>Recheck until something decided.
017 * </ol>
018 *
019 * <p>
020 * If no "action" name is provided, only the continue and cancel options are
021 * shown.
022 *
023 * @author Bob Jacobsen Copyright (C) 2008
024 */
025public class SwingShutDownTask extends AbstractShutDownTask {
026
027    /**
028     * Constructor specifies the warning message and action to take
029     *
030     * @param name      the name of the task (used in logs)
031     * @param warning   the prompt to display
032     * @param action    the action button to display
033     * @param component the parent component of the dialog
034     */
035    public SwingShutDownTask(String name, String warning, String action, Component component) {
036        super(name);
037        this.component = component;
038        this.warning = warning;
039        this.action = action;
040    }
041
042    String warning;
043    String action;
044    Component component;
045    private boolean didPrompt = false;
046
047    /**
048     * {@inheritDoc}
049     *
050     * This implementation displays a dialog allowing a user continue stopping
051     * the app, abort stopping the app, or take a custom action. Closing the
052     * dialog without choosing any button is treated as aborting stopping the
053     * app.
054     *
055     * @see #didPrompt()
056     * @see #doPrompt()
057     */
058    @Override
059    public final Boolean call() {
060        if (!checkPromptNeeded()) {
061            // issue prompt
062            Object[] possibleValues;
063            if (action != null) {
064                possibleValues = new Object[]{Bundle.getMessage("ButtonContinue"),
065                    Bundle.getMessage("ButtonAbort"),
066                    action};
067            } else {
068                possibleValues = new Object[]{Bundle.getMessage("ButtonContinue"),
069                    Bundle.getMessage("ButtonAbort")};
070            }
071
072            int selectedValue = JmriJOptionPane.showOptionDialog(component,
073                    warning,
074                    Bundle.getMessage("ShutDownWarningTitle"),
075                    JmriJOptionPane.DEFAULT_OPTION,
076                    JmriJOptionPane.WARNING_MESSAGE, null,
077                    possibleValues, possibleValues[possibleValues.length - 1]);
078            switch (selectedValue) {
079                case 1:
080                case -1:
081                    // abort quit
082                    return false;
083                case 0:
084                    // quit anyway
085                    return true;
086                case 2:
087                    // take action and try again
088                    didPrompt = true;
089                    return doPrompt();
090                default:
091                    // unexpected value, log but continue
092                    log.error("unexpected selection: {}", selectedValue);
093                    return true;
094            }
095        }
096        return true;
097    }
098
099    /**
100     * {@inheritDoc}
101     *
102     * This implementation calls {@link #didPrompt()} if the user took the
103     * prompt action.
104     */
105    @Override
106    public void run() {
107        if (didPrompt) {
108            didPrompt();
109        }
110    }
111
112    /**
113     * Provide a subclass-specific check as to whether it's OK to shutdown. If
114     * not, issue a prompt before continuing. Default implementation never
115     * passes, causing message to be emitted.
116     *
117     * @return true if ready to shutdown, and no prompt needed. false to present
118     *         dialog before shutdown proceeds
119     */
120    protected boolean checkPromptNeeded() {
121        return false;
122    }
123
124    /**
125     * Handle the request to address a potential blocker to stopping. This
126     * method is called in {@link #run()} and must not interact with the user.
127     * <p>
128     * This is a dummy implementation, intended to be overloaded.
129     */
130    protected void didPrompt() {
131        // do nothing
132    }
133
134    /**
135     * Handle the request to address a potential blocker to stopping. This
136     * method is called in {@link #call()} and can interact with the user.
137     * <p>
138     * This is a dummy implementation, intended to be overloaded.
139     *
140     * @return true if ready to shutdown, false to end shutdown
141     */
142    protected boolean doPrompt() {
143        return true;
144    }
145
146    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SwingShutDownTask.class);
147
148}