source: josm/trunk/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java@ 12841

Last change on this file since 12841 was 12841, checked in by bastiK, 7 years ago

see #15229 - fix deprecations caused by [12840]

  • Property svn:eol-style set to native
File size: 13.1 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[1838]2package org.openstreetmap.josm.gui;
[626]3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
[1838]6import java.awt.Component;
[9496]7import java.awt.GraphicsEnvironment;
[626]8import java.awt.GridBagLayout;
[6594]9import java.util.HashMap;
10import java.util.HashSet;
11import java.util.Map;
12import java.util.Set;
[626]13
[6594]14import javax.swing.ButtonGroup;
[626]15import javax.swing.JOptionPane;
16import javax.swing.JPanel;
[6594]17import javax.swing.JRadioButton;
[626]18
19import org.openstreetmap.josm.Main;
[6901]20import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
[1838]21import org.openstreetmap.josm.tools.GBC;
[6594]22import org.openstreetmap.josm.tools.Utils;
[626]23
[1838]24/**
25 * ConditionalOptionPaneUtil provides static utility methods for displaying modal message dialogs
26 * which can be enabled/disabled by the user.
[2512]27 *
[5266]28 * They wrap the methods provided by {@link JOptionPane}. Within JOSM you should use these
29 * methods rather than the bare methods from {@link JOptionPane} because the methods provided
[1838]30 * by ConditionalOptionPaneUtil ensure that a dialog window is always on top and isn't hidden by one of the
31 * JOSM windows for detached dialogs, relation editors, history browser and the like.
[2512]32 *
[1838]33 */
[6362]34public final class ConditionalOptionPaneUtil {
[6623]35 public static final int DIALOG_DISABLED_OPTION = Integer.MIN_VALUE;
[1838]36
[6830]37 /** (preference key => return value) mappings valid for the current operation (no, those two maps cannot be combined) */
[8468]38 private static final Map<String, Integer> sessionChoices = new HashMap<>();
[6830]39 /** (preference key =&gt; return value) mappings valid for the current session */
[8468]40 private static final Map<String, Integer> immediateChoices = new HashMap<>();
[6594]41 /** a set indication that (preference key) is or may be stored for the currently active bulk operation */
[8468]42 private static final Set<String> immediateActive = new HashSet<>();
[6594]43
[1838]44 /**
45 * this is a static utility class only
46 */
[11921]47 private ConditionalOptionPaneUtil() {
48 // Hide default constructor for utility classes
49 }
[1838]50
51 /**
[6594]52 * Returns the preference value for the preference key "message." + <code>prefKey</code> + ".value".
53 * The default value if the preference key is missing is -1.
[2512]54 *
[5817]55 * @param prefKey the preference key
[6594]56 * @return the preference value for the preference key "message." + <code>prefKey</code> + ".value"
[1838]57 */
[6594]58 public static int getDialogReturnValue(String prefKey) {
59 return Utils.firstNonNull(
60 immediateChoices.get(prefKey),
61 sessionChoices.get(prefKey),
[12841]62 !Main.pref.getBoolean("message." + prefKey, true) ? Main.pref.getInt("message." + prefKey + ".value", -1) : -1
[6594]63 );
[1169]64 }
[626]65
[1838]66 /**
[6594]67 * Marks the beginning of a bulk operation in order to provide a "Do not show again (this operation)" option.
68 * @param prefKey the preference key
[1838]69 */
[6594]70 public static void startBulkOperation(final String prefKey) {
71 immediateActive.add(prefKey);
[1169]72 }
[745]73
[1841]74 /**
[8540]75 * Determines whether the key has been marked to be part of a bulk operation
76 * (in order to provide a "Do not show again (this operation)" option).
[6595]77 * @param prefKey the preference key
[8958]78 * @return {@code true} if the key has been marked to be part of a bulk operation
[6595]79 */
80 public static boolean isInBulkOperation(final String prefKey) {
81 return immediateActive.contains(prefKey);
82 }
83
84 /**
[6594]85 * Marks the ending of a bulk operation. Removes the "Do not show again (this operation)" result value.
86 * @param prefKey the preference key
[2522]87 */
[6594]88 public static void endBulkOperation(final String prefKey) {
89 immediateActive.remove(prefKey);
90 immediateChoices.remove(prefKey);
[2522]91 }
92
93 /**
[1841]94 * Displays an confirmation dialog with some option buttons given by <code>optionType</code>.
95 * It is always on top even if there are other open windows like detached dialogs,
96 * relation editors, history browsers and the like.
[2512]97 *
[5266]98 * Set <code>optionType</code> to {@link JOptionPane#YES_NO_OPTION} for a dialog with a YES and
[1841]99 * a NO button.
[1838]100
[5266]101 * Set <code>optionType</code> to {@link JOptionPane#YES_NO_CANCEL_OPTION} for a dialog with a YES,
[1841]102 * a NO and a CANCEL button
[2512]103 *
[2929]104 * Returns one of the constants JOptionPane.YES_OPTION, JOptionPane.NO_OPTION,
105 * JOptionPane.CANCEL_OPTION or JOptionPane.CLOSED_OPTION depending on the action chosen by
106 * the user.
[2512]107 *
[1841]108 * @param preferenceKey the preference key
109 * @param parent the parent component
110 * @param message the message
111 * @param title the title
112 * @param optionType the option type
113 * @param messageType the message type
114 * @param options a list of options
[5724]115 * @param defaultOption the default option; only meaningful if options is used; can be null
[2512]116 *
[9496]117 * @return the option selected by user.
118 * {@link JOptionPane#CLOSED_OPTION} if the dialog was closed.
119 * {@link JOptionPane#YES_OPTION} if <code>GraphicsEnvironment.isHeadless</code> returns <code>true</code>
[1841]120 */
[8443]121 public static int showOptionDialog(String preferenceKey, Component parent, Object message, String title, int optionType,
[9496]122 int messageType, Object[] options, Object defaultOption) {
[2929]123 int ret = getDialogReturnValue(preferenceKey);
[6594]124 if (isYesOrNo(ret))
[2929]125 return ret;
[6595]126 MessagePanel pnl = new MessagePanel(message, isInBulkOperation(preferenceKey));
[9496]127 if (GraphicsEnvironment.isHeadless()) {
128 // for unit tests
129 ret = JOptionPane.YES_OPTION;
130 } else {
131 ret = JOptionPane.showOptionDialog(parent, pnl, title, optionType, messageType, null, options, defaultOption);
132 }
[6594]133 if (isYesOrNo(ret)) {
134 pnl.getNotShowAgain().store(preferenceKey, ret);
[2929]135 }
[1841]136 return ret;
137 }
138
[1838]139 /**
[2929]140 * Displays a confirmation dialog with some option buttons given by <code>optionType</code>.
[1838]141 * It is always on top even if there are other open windows like detached dialogs,
142 * relation editors, history browsers and the like.
[2512]143 *
[5266]144 * Set <code>optionType</code> to {@link JOptionPane#YES_NO_OPTION} for a dialog with a YES and
[1838]145 * a NO button.
146
[5266]147 * Set <code>optionType</code> to {@link JOptionPane#YES_NO_CANCEL_OPTION} for a dialog with a YES,
[1838]148 * a NO and a CANCEL button
[2512]149 *
[1838]150 * Replies true, if the selected option is equal to <code>trueOption</code>, otherwise false.
151 * Replies true, if the dialog is not displayed because the respective preference option
[2929]152 * <code>preferenceKey</code> is set to false and the user has previously chosen
153 * <code>trueOption</code>.
[2512]154 *
[1838]155 * @param preferenceKey the preference key
156 * @param parent the parent component
157 * @param message the message
158 * @param title the title
159 * @param optionType the option type
160 * @param messageType the message type
[9496]161 * @param trueOption if this option is selected the method replies true
[2512]162 *
163 *
[1838]164 * @return true, if the selected option is equal to <code>trueOption</code>, otherwise false.
[9496]165 * {@code trueOption} if <code>GraphicsEnvironment.isHeadless</code> returns <code>true</code>
[2512]166 *
[1838]167 * @see JOptionPane#INFORMATION_MESSAGE
168 * @see JOptionPane#WARNING_MESSAGE
169 * @see JOptionPane#ERROR_MESSAGE
170 */
[8509]171 public static boolean showConfirmationDialog(String preferenceKey, Component parent, Object message, String title,
[9496]172 int optionType, int messageType, int trueOption) {
[2929]173 int ret = getDialogReturnValue(preferenceKey);
[6594]174 if (isYesOrNo(ret))
[2929]175 return ret == trueOption;
[6595]176 MessagePanel pnl = new MessagePanel(message, isInBulkOperation(preferenceKey));
[9496]177 if (GraphicsEnvironment.isHeadless()) {
178 // for unit tests
179 ret = trueOption;
180 } else {
181 ret = JOptionPane.showConfirmDialog(parent, pnl, title, optionType, messageType);
182 }
[8345]183 if (isYesOrNo(ret)) {
[6594]184 pnl.getNotShowAgain().store(preferenceKey, ret);
[2522]185 }
[2017]186 return ret == trueOption;
[1169]187 }
[745]188
[6594]189 private static boolean isYesOrNo(int returnCode) {
190 return (returnCode == JOptionPane.YES_OPTION) || (returnCode == JOptionPane.NO_OPTION);
191 }
192
[1838]193 /**
194 * Displays an message in modal dialog with an OK button. Makes sure the dialog
195 * is always on top even if there are other open windows like detached dialogs,
196 * relation editors, history browsers and the like.
[2512]197 *
[1838]198 * If there is a preference with key <code>preferenceKey</code> and value <code>false</code>
199 * the dialog is not show.
[2512]200 *
[1838]201 * @param preferenceKey the preference key
202 * @param parent the parent component
203 * @param message the message
204 * @param title the title
205 * @param messageType the message type
[2512]206 *
[1838]207 * @see JOptionPane#INFORMATION_MESSAGE
208 * @see JOptionPane#WARNING_MESSAGE
209 * @see JOptionPane#ERROR_MESSAGE
210 */
[8510]211 public static void showMessageDialog(String preferenceKey, Component parent, Object message, String title, int messageType) {
[6594]212 if (getDialogReturnValue(preferenceKey) == Integer.MAX_VALUE)
[1838]213 return;
[6595]214 MessagePanel pnl = new MessagePanel(message, isInBulkOperation(preferenceKey));
[2017]215 JOptionPane.showMessageDialog(parent, pnl, title, messageType);
[6594]216 pnl.getNotShowAgain().store(preferenceKey, Integer.MAX_VALUE);
217 }
218
219 /**
220 * An enum designating how long to not show this message again, i.e., for how long to store
221 */
[8836]222 enum NotShowAgain {
[6594]223 NO, OPERATION, SESSION, PERMANENT;
224
225 /**
226 * Stores the dialog result {@code value} at the corresponding place.
227 * @param prefKey the preference key
228 * @param value the dialog result
229 */
230 void store(String prefKey, Integer value) {
231 switch (this) {
232 case NO:
233 break;
234 case OPERATION:
235 immediateChoices.put(prefKey, value);
236 break;
237 case SESSION:
238 sessionChoices.put(prefKey, value);
239 break;
240 case PERMANENT:
[12841]241 Main.pref.putBoolean("message." + prefKey, false);
242 Main.pref.putInt("message." + prefKey + ".value", value);
[6594]243 break;
244 }
[2929]245 }
[6594]246
247 String getLabel() {
248 switch (this) {
249 case NO:
250 return tr("Show this dialog again the next time");
251 case OPERATION:
252 return tr("Do not show again (this operation)");
253 case SESSION:
254 return tr("Do not show again (this session)");
255 case PERMANENT:
256 return tr("Do not show again (remembers choice)");
257 }
258 throw new IllegalStateException();
259 }
[1838]260 }
261
262 /**
[8468]263 * This is a message panel used in dialogs which can be enabled/disabled with a preference setting.
[5266]264 * In addition to the normal message any {@link JOptionPane} would display it includes
[1838]265 * a checkbox for enabling/disabling this particular dialog.
266 *
267 */
[6594]268 static class MessagePanel extends JPanel {
269 private final JRadioButton cbShowPermanentDialog = new JRadioButton(NotShowAgain.PERMANENT.getLabel());
270 private final JRadioButton cbShowSessionDialog = new JRadioButton(NotShowAgain.SESSION.getLabel());
271 private final JRadioButton cbShowImmediateDialog = new JRadioButton(NotShowAgain.OPERATION.getLabel());
272 private final JRadioButton cbStandard = new JRadioButton(NotShowAgain.NO.getLabel());
[1838]273
[6594]274 /**
275 * Constructs a new panel.
[8468]276 * @param message the the message (null to add no message, Component instances are added directly,
277 * otherwise a JLabel with the string representation is added)
[6594]278 * @param displayImmediateOption whether to provide "Do not show again (this session)"
279 */
[8836]280 MessagePanel(Object message, boolean displayImmediateOption) {
[6594]281 cbStandard.setSelected(true);
[8468]282 ButtonGroup group = new ButtonGroup();
[6594]283 group.add(cbShowPermanentDialog);
284 group.add(cbShowSessionDialog);
285 group.add(cbShowImmediateDialog);
286 group.add(cbStandard);
287
[1838]288 setLayout(new GridBagLayout());
289 if (message instanceof Component) {
[6594]290 add((Component) message, GBC.eop());
291 } else if (message != null) {
[6901]292 add(new JMultilineLabel(message.toString()), GBC.eop());
[1838]293 }
[6594]294 add(cbShowPermanentDialog, GBC.eol());
295 add(cbShowSessionDialog, GBC.eol());
296 if (displayImmediateOption) {
297 add(cbShowImmediateDialog, GBC.eol());
298 }
299 add(cbStandard, GBC.eol());
[1169]300 }
[1838]301
[6594]302 NotShowAgain getNotShowAgain() {
303 return cbStandard.isSelected()
304 ? NotShowAgain.NO
305 : cbShowImmediateDialog.isSelected()
306 ? NotShowAgain.OPERATION
307 : cbShowSessionDialog.isSelected()
308 ? NotShowAgain.SESSION
309 : cbShowPermanentDialog.isSelected()
310 ? NotShowAgain.PERMANENT
311 : null;
[1838]312 }
[1169]313 }
[626]314}
Note: See TracBrowser for help on using the repository browser.