source: josm/trunk/src/org/openstreetmap/josm/gui/HelpAwareOptionPane.java@ 6041

Last change on this file since 6041 was 6040, checked in by Don-vip, 11 years ago

fix #8827 - HTML rendering differ if run before or after having launched Help Browser

  • Property svn:eol-style set to native
File size: 11.2 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.Dialog.ModalityType;
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.awt.event.WindowAdapter;
11import java.awt.event.WindowEvent;
12import java.util.ArrayList;
13import java.util.List;
14
15import javax.swing.AbstractAction;
16import javax.swing.Action;
17import javax.swing.Icon;
18import javax.swing.JButton;
19import javax.swing.JComponent;
20import javax.swing.JDialog;
21import javax.swing.JOptionPane;
22import javax.swing.KeyStroke;
23
24import org.openstreetmap.josm.gui.help.HelpBrowser;
25import org.openstreetmap.josm.gui.help.HelpUtil;
26import org.openstreetmap.josm.gui.util.GuiHelper;
27import org.openstreetmap.josm.gui.widgets.JosmEditorPane;
28import org.openstreetmap.josm.tools.ImageProvider;
29import org.openstreetmap.josm.tools.InputMapUtils;
30import org.openstreetmap.josm.tools.WindowGeometry;
31
32public class HelpAwareOptionPane {
33
34 public static class ButtonSpec {
35 public final String text;
36 public final Icon icon;
37 public final String tooltipText;
38 public final String helpTopic;
39 public final boolean enabled;
40
41 /**
42 * Constructs a new {@code ButtonSpec}.
43 * @param text the button text
44 * @param icon the icon to display. Can be null
45 * @param tooltipText the tooltip text. Can be null.
46 * @param helpTopic the help topic. Can be null.
47 */
48 public ButtonSpec(String text, Icon icon, String tooltipText, String helpTopic) {
49 this(text, icon, tooltipText, helpTopic, true);
50 }
51
52 /**
53 * Constructs a new {@code ButtonSpec}.
54 * @param text the button text
55 * @param icon the icon to display. Can be null
56 * @param tooltipText the tooltip text. Can be null.
57 * @param helpTopic the help topic. Can be null.
58 * @param enabled the enabled status
59 * @since 5951
60 */
61 public ButtonSpec(String text, Icon icon, String tooltipText, String helpTopic, boolean enabled) {
62 this.text = text;
63 this.icon = icon;
64 this.tooltipText = tooltipText;
65 this.helpTopic = helpTopic;
66 this.enabled = enabled;
67 }
68 }
69
70 static private class DefaultAction extends AbstractAction {
71 private JDialog dialog;
72 private JOptionPane pane;
73 private int value;
74
75 public DefaultAction(JDialog dialog, JOptionPane pane, int value) {
76 this.dialog = dialog;
77 this.pane = pane;
78 this.value = value;
79 }
80
81 public void actionPerformed(ActionEvent e) {
82 pane.setValue(value);
83 dialog.setVisible(false);
84 }
85 }
86
87 /**
88 * Creates the list buttons to be displayed in the option pane dialog.
89 *
90 * @param options the option. If null, just creates an OK button and a help button
91 * @param helpTopic the help topic. The context sensitive help of all buttons is equal
92 * to the context sensitive help of the whole dialog
93 * @return the list of buttons
94 */
95 static private List<JButton> createOptionButtons(ButtonSpec[] options, String helpTopic) {
96 List<JButton> buttons = new ArrayList<JButton>();
97 if (options == null) {
98 JButton b = new JButton(tr("OK"));
99 b.setIcon(ImageProvider.get("ok"));
100 b.setToolTipText(tr("Click to close the dialog"));
101 b.setFocusable(true);
102 buttons.add(b);
103 } else {
104 for (ButtonSpec spec: options) {
105 JButton b = new JButton(spec.text);
106 b.setIcon(spec.icon);
107 b.setToolTipText(spec.tooltipText == null? "" : spec.tooltipText);
108 if (helpTopic != null) {
109 HelpUtil.setHelpContext(b, helpTopic);
110 }
111 b.setFocusable(true);
112 b.setEnabled(spec.enabled);
113 buttons.add(b);
114 }
115 }
116 return buttons;
117 }
118
119 /**
120 * Creates the help button
121 *
122 * @param helpTopic the help topic
123 * @return the help button
124 */
125 static private JButton createHelpButton(final String helpTopic) {
126 JButton b = new JButton(tr("Help"));
127 b.setIcon(ImageProvider.get("help"));
128 b.setToolTipText(tr("Show help information"));
129 HelpUtil.setHelpContext(b, helpTopic);
130 Action a = new AbstractAction() {
131 public void actionPerformed(ActionEvent e) {
132 HelpBrowser.setUrlForHelpTopic(helpTopic);
133 }
134 };
135 b.addActionListener(a);
136 InputMapUtils.enableEnter(b);
137 return b;
138 }
139
140 /**
141 * Displays an option dialog which is aware of a help context. If <code>helpTopic</code> isn't null,
142 * the dialog includes a "Help" button and launches the help browser if the user presses F1. If the
143 * user clicks on the "Help" button the option dialog remains open and JOSM launches the help
144 * browser.
145 *
146 * <code>helpTopic</code> is the trailing part of a JOSM online help URL, i.e. the part after the leading
147 * <code>http://josm.openstreetmap.de/wiki/Help</code>. It should start with a leading '/' and it
148 * may include an anchor after a '#'.
149 *
150 * <strong>Examples</strong>
151 * <ul>
152 * <li>/Dialogs/RelationEditor</li>
153 * <li>/Dialogs/RelationEditor#ConflictInData</li>
154 * </ul>
155 *
156 * In addition, the option buttons display JOSM icons, similar to ExtendedDialog.
157 *
158 * @param parentComponent the parent component
159 * @param msg the message
160 * @param title the title
161 * @param messageType the message type (see {@link JOptionPane})
162 * @param icon the icon to display. Can be null.
163 * @param options the list of options to display. Can be null.
164 * @param defaultOption the default option. Can be null.
165 * @param helpTopic the help topic. Can be null.
166 * @return the index of the selected option or {@link JOptionPane#CLOSED_OPTION}
167 */
168 static public int showOptionDialog(Component parentComponent, Object msg, String title, int messageType, Icon icon, final ButtonSpec[] options, final ButtonSpec defaultOption, final String helpTopic) {
169 final List<JButton> buttons = createOptionButtons(options, helpTopic);
170 if (helpTopic != null) {
171 buttons.add(createHelpButton(helpTopic));
172 }
173
174 JButton defaultButton = null;
175 if (options != null && defaultOption != null) {
176 for (int i=0; i< options.length; i++) {
177 if (options[i] == defaultOption) {
178 defaultButton = buttons.get(i);
179 break;
180 }
181 }
182 }
183
184 if (msg instanceof String) {
185 JosmEditorPane pane = new JosmEditorPane("text/html", (String) msg);
186 pane.setEditable(false);
187 pane.setOpaque(false);
188 msg = pane;
189 }
190
191 final JOptionPane pane = new JOptionPane(
192 msg,
193 messageType,
194 JOptionPane.DEFAULT_OPTION,
195 icon,
196 buttons.toArray(),
197 defaultButton
198 );
199
200 pane.getValue();
201 final JDialog dialog = new JDialog(
202 JOptionPane.getFrameForComponent(parentComponent),
203 title,
204 ModalityType.DOCUMENT_MODAL
205 );
206 dialog.setContentPane(pane);
207 dialog.addWindowListener(new WindowAdapter() {
208 @Override
209 public void windowClosing(WindowEvent e) {
210 pane.setValue(JOptionPane.CLOSED_OPTION);
211 super.windowClosed(e);
212 }
213
214 @Override
215 public void windowOpened(WindowEvent e) {
216 if (defaultOption != null && options != null && options.length > 0) {
217 int i;
218 for (i=0; i<options.length;i++) {
219 if (options[i] == defaultOption) {
220 break;
221 }
222 }
223 if (i >= options.length) {
224 buttons.get(0).requestFocusInWindow();
225 }
226 buttons.get(i).requestFocusInWindow();
227 } else {
228 buttons.get(0).requestFocusInWindow();
229 }
230 }
231 });
232 dialog.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), "close");
233 dialog.getRootPane().getActionMap().put("close", new AbstractAction() {
234 public void actionPerformed(ActionEvent e) {
235 pane.setValue(JOptionPane.CLOSED_OPTION);
236 dialog.setVisible(false);
237 }}
238 );
239
240 if (options != null) {
241 for (int i=0; i < options.length;i++) {
242 final DefaultAction action = new DefaultAction(dialog, pane, i);
243 buttons.get(i).addActionListener(action);
244 buttons.get(i).getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
245 buttons.get(i).getActionMap().put("enter", action);
246 }
247 } else {
248 final DefaultAction action = new DefaultAction(dialog, pane, 0);
249 buttons.get(0).addActionListener(action);
250 buttons.get(0).getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
251 buttons.get(0).getActionMap().put("enter", action);
252 }
253
254 dialog.pack();
255 WindowGeometry.centerOnScreen(dialog.getSize()).applySafe(dialog);
256 if (helpTopic != null) {
257 HelpUtil.setHelpContext(dialog.getRootPane(), helpTopic);
258 }
259 dialog.setVisible(true);
260 return (Integer)pane.getValue();
261 }
262
263 /**
264 * Displays an option dialog which is aware of a help context.
265 *
266 * @param parentComponent the parent component
267 * @param msg the message
268 * @param title the title
269 * @param messageType the message type (see {@link JOptionPane})
270 * @param helpTopic the help topic. Can be null.
271 * @return the index of the selected option or {@link JOptionPane#CLOSED_OPTION}
272 * @see #showOptionDialog(Component, Object, String, int, Icon, ButtonSpec[], ButtonSpec, String)
273 */
274 static public int showOptionDialog(Component parentComponent, Object msg, String title, int messageType,final String helpTopic) {
275 return showOptionDialog(parentComponent, msg, title, messageType, null,null,null, helpTopic);
276 }
277
278 /**
279 * Run it in Event Dispatch Thread.
280 * This version does not return anything, so it is more like showMessageDialog.
281 *
282 * It can be used, when you need to show a message dialog from a worker thread,
283 * e.g. from PleaseWaitRunnable
284 */
285 static public void showMessageDialogInEDT(final Component parentComponent, final Object msg, final String title, final int messageType, final String helpTopic) {
286 GuiHelper.runInEDT(new Runnable() {
287 public void run() {
288 showOptionDialog(parentComponent, msg, title, messageType, null, null, null, helpTopic);
289 }
290 });
291 }
292}
Note: See TracBrowser for help on using the repository browser.