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

Last change on this file since 8674 was 8540, checked in by Don-vip, 9 years ago

fix remaining checkstyle issues

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