Mercurial > hg > accesspd
comparison java/src/uk/ac/qmul/eecs/ccmi/gui/SpeechOptionPane.java @ 0:78b7fc5391a2
first import, outcome of NIME 2014 hackaton
author | Fiore Martin <f.martin@qmul.ac.uk> |
---|---|
date | Tue, 08 Jul 2014 16:28:59 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78b7fc5391a2 |
---|---|
1 /* | |
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool | |
3 | |
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/) | |
5 | |
6 This program is free software: you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation, either version 3 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 */ | |
19 | |
20 package uk.ac.qmul.eecs.ccmi.gui; | |
21 | |
22 import java.awt.Color; | |
23 import java.awt.Component; | |
24 import java.awt.Frame; | |
25 import java.awt.GridLayout; | |
26 import java.awt.event.ActionEvent; | |
27 import java.awt.event.ActionListener; | |
28 import java.awt.event.InputEvent; | |
29 import java.awt.event.KeyEvent; | |
30 import java.awt.event.WindowAdapter; | |
31 import java.awt.event.WindowEvent; | |
32 import java.text.MessageFormat; | |
33 import java.util.LinkedHashSet; | |
34 import java.util.List; | |
35 import java.util.ResourceBundle; | |
36 import java.util.Set; | |
37 | |
38 import javax.swing.AbstractAction; | |
39 import javax.swing.JButton; | |
40 import javax.swing.JCheckBox; | |
41 import javax.swing.JComponent; | |
42 import javax.swing.JDialog; | |
43 import javax.swing.JFormattedTextField; | |
44 import javax.swing.JLabel; | |
45 import javax.swing.JOptionPane; | |
46 import javax.swing.JPanel; | |
47 import javax.swing.JProgressBar; | |
48 import javax.swing.JScrollPane; | |
49 import javax.swing.JSpinner; | |
50 import javax.swing.JTextArea; | |
51 import javax.swing.JTextField; | |
52 import javax.swing.KeyStroke; | |
53 import javax.swing.SwingWorker; | |
54 import javax.swing.event.ChangeEvent; | |
55 import javax.swing.event.ChangeListener; | |
56 import javax.swing.text.JTextComponent; | |
57 | |
58 import uk.ac.qmul.eecs.ccmi.sound.SoundEvent; | |
59 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory; | |
60 import uk.ac.qmul.eecs.ccmi.speech.Narrator; | |
61 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory; | |
62 import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities; | |
63 | |
64 /** | |
65 * | |
66 * An option panel made out of an {@code Object} being displayed and to buttons: one for accepting and another one for | |
67 * cancelling the option. | |
68 * Furthermore, this class provides one-line calls to display accessible dialog boxes. Input by the user as well | |
69 * as focused components are spoken out through text to speech synthesis performed by a {@link Narrator} instance. | |
70 */ | |
71 public class SpeechOptionPane { | |
72 | |
73 /** | |
74 * Construct a new {@code SpeechOptionPane} with no title. The title is displayed at the top of the dialog | |
75 * that is displayed after a call to {@code showDialog} | |
76 */ | |
77 public SpeechOptionPane(){ | |
78 this(""); | |
79 } | |
80 | |
81 /** | |
82 * Construct a new {@code SpeechOptionPane} with no title. The title is displayed at the top of the dialog | |
83 * that is displayed after a call to {@code showDialog} | |
84 * | |
85 * @param title the String to be displayed | |
86 */ | |
87 public SpeechOptionPane(String title){ | |
88 this.title = title; | |
89 okButton = new JButton("OK"); | |
90 cancelButton = new JButton("Cancel"); | |
91 } | |
92 | |
93 /** | |
94 * Pops the a dialog holding this SpeechOptionPane | |
95 * | |
96 * @param parent the parent component of the dialog | |
97 * @param message the {@code Object} to display | |
98 * @return an integer indicating the option selected by the user | |
99 */ | |
100 @SuppressWarnings("serial") | |
101 public int showDialog(Component parent,final Object message){ | |
102 optPane = new JOptionPane(); | |
103 optPane.setMessage(message); | |
104 /* Enter will entail a unique action, regardless the component that's focused */ | |
105 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "closeDialog"); | |
106 optPane.getActionMap().put("closeDialog", new AbstractAction(){ | |
107 @Override | |
108 public void actionPerformed(ActionEvent evt) { | |
109 okButton.doClick(); | |
110 } | |
111 }); | |
112 optPane.setMessageType(JOptionPane.PLAIN_MESSAGE); | |
113 Object[] options = { | |
114 okButton, | |
115 cancelButton | |
116 }; | |
117 optPane.setOptions(options); | |
118 /* ctrl key will hush the TTS */ | |
119 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
120 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
121 final JDialog dialog = optPane.createDialog(parent, title); | |
122 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); | |
123 SpeechUtilities.changeTabListener(optPane,dialog); | |
124 /* when either button is pressed, dialog is disposed and the button itself becomes the optPane.value */ | |
125 ActionListener buttonListener = new ActionListener(){ | |
126 @Override | |
127 public void actionPerformed(ActionEvent evt) { | |
128 onClose(dialog,(JButton)evt.getSource()); | |
129 } | |
130 }; | |
131 okButton.addActionListener(buttonListener); | |
132 cancelButton.addActionListener(buttonListener); | |
133 | |
134 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
135 dialog.setVisible(true); | |
136 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
137 if(okButton.equals(optPane.getValue())){ | |
138 return OK_OPTION; | |
139 }else{ | |
140 return CANCEL_OPTION; | |
141 } | |
142 } | |
143 | |
144 /** | |
145 * Sets the string appearing at the top of the dialog where this option pane is displayed when {@code showDialog} | |
146 * is called. | |
147 * @param title the title of this option pane | |
148 */ | |
149 public void setDialogTitle(String title){ | |
150 this.title = title; | |
151 } | |
152 | |
153 /** | |
154 * Returns the {@code JButton} that the user has to press (when the option pane is displayed after | |
155 * {@code showDialog} is called) in order to accept the option. | |
156 * | |
157 * @return a reference to the internal {@code JButton} | |
158 */ | |
159 public JButton getOkButton(){ | |
160 return okButton; | |
161 } | |
162 | |
163 /** | |
164 * Returns the {@code JButton} that the user has to press (when the option pane is displayed after | |
165 * {@code showDialog} is called) in order to reject the option. | |
166 * | |
167 * @return a reference to the internal {@code JButton} | |
168 */ | |
169 public JButton getCancelButton(){ | |
170 return cancelButton; | |
171 } | |
172 | |
173 /** | |
174 * This method is called just after the user presses either button of the dialog displayed | |
175 * after {@code showDialog} is called. | |
176 * It assign a value to the return value and it frees the dialog resources. | |
177 * It can be overwritten by subclasses but care should be taken of calling this class method via | |
178 * {@code super} in order to properly close the dialog. | |
179 * | |
180 * @param dialog the dialog displayed after {@code showDialog} is called. | |
181 * @param source the button that triggered the closing of {@code dialog} | |
182 */ | |
183 protected void onClose(JDialog dialog, JButton source){ | |
184 optPane.setValue(source); | |
185 dialog.dispose(); | |
186 } | |
187 | |
188 private String title; | |
189 private JOptionPane optPane; | |
190 private JButton okButton; | |
191 private JButton cancelButton; | |
192 | |
193 | |
194 /* -------- STATIC METHODS ----------- */ | |
195 | |
196 /** | |
197 * Shows a dialog with a text area requesting input for the user. | |
198 * | |
199 * @param parentComponent the parent {@code Component} for the dialog | |
200 * @param message a displayed in the dialog, such text is also uttered by the {@code Narrator} | |
201 * @param text the initial text the text area contains when the dialog is displayed | |
202 * | |
203 * @return the new text entered by the user | |
204 */ | |
205 public static String showTextAreaDialog(Component parentComponent, String message, String text){ | |
206 JTextArea textArea = new JTextArea(NOTES_TEXT_AREA_ROW_SIZE,NOTES_TEXT_AREA_COL_SIZE); | |
207 textArea.setText(text); | |
208 NarratorFactory.getInstance().speak(message); | |
209 return textComponentDialog(parentComponent, message, textArea); | |
210 } | |
211 | |
212 /** | |
213 * Shows a dialog with a text field requesting input from the user | |
214 * | |
215 * @param parentComponent the parent {@code Component} for the dialog | |
216 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
217 * @param initialSelectionValue the initial text the text field contains when the dialog is displayed | |
218 * | |
219 * @return the text entered by the user | |
220 */ | |
221 public static String showInputDialog(Component parentComponent, String message, String initialSelectionValue){ | |
222 final JTextField textField = new JTextField(initialSelectionValue); | |
223 textField.selectAll(); | |
224 NarratorFactory.getInstance().speak(message); | |
225 return textComponentDialog(parentComponent, message, textField); | |
226 } | |
227 | |
228 private static String textComponentDialog(Component parentComponent, String message, final JTextComponent textComponent){ | |
229 Object componentToDisplay = textComponent; | |
230 if(textComponent instanceof JTextArea) | |
231 componentToDisplay = new JScrollPane(textComponent); | |
232 | |
233 Object[] displayObjects = { new JLabel(message), componentToDisplay }; | |
234 final JOptionPane optPane = new JOptionPane(); | |
235 optPane.setMessage(displayObjects); | |
236 optPane.setMessageType(QUESTION_MESSAGE); | |
237 optPane.setOptionType(OK_CANCEL_OPTION); | |
238 /* ctrl key will hush the TTS */ | |
239 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
240 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
241 | |
242 final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.input")); | |
243 if(textComponent instanceof JTextArea) | |
244 dialog.setResizable(true); | |
245 dialog.addWindowFocusListener(new WindowAdapter(){ | |
246 @Override | |
247 public void windowGainedFocus(WindowEvent e) { | |
248 textComponent.requestFocusInWindow(); | |
249 } | |
250 }); | |
251 | |
252 SpeechUtilities.changeTabListener(optPane,dialog); | |
253 textComponent.addKeyListener(SpeechUtilities.getSpeechKeyListener(true)); | |
254 textComponent.setEditable(true); | |
255 // start the editing sound | |
256 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
257 dialog.setVisible(true); | |
258 dialog.dispose(); | |
259 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
260 | |
261 if(optPane.getValue() == null)//window closed | |
262 return null; | |
263 else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel | |
264 return null; | |
265 else{ // pressed on OK | |
266 return textComponent.getText().trim(); | |
267 } | |
268 } | |
269 | |
270 /** | |
271 * Shows a dialog with a {@code JComboBox} requesting selection from the user | |
272 * | |
273 * @param parentComponent the parent {@code Component} for the dialog | |
274 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
275 * @param options options for the {@code JComboBox} | |
276 * @param initialValue the options value selected when the dialog is shown | |
277 * @return the option selected by the user | |
278 */ | |
279 public static Object showSelectionDialog(Component parentComponent, String message, Object[] options, Object initialValue){ | |
280 final LoopComboBox comboBox = new LoopComboBox(options); | |
281 comboBox.setSelectedItem(initialValue); | |
282 Object[] displayObjects = { new JLabel(message), comboBox }; | |
283 JOptionPane optPane = new JOptionPane(); | |
284 optPane.setMessage(displayObjects); | |
285 optPane.setMessageType(QUESTION_MESSAGE); | |
286 optPane.setOptionType(OK_CANCEL_OPTION); | |
287 /* ctrl key will hush the TTS */ | |
288 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
289 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
290 | |
291 NarratorFactory.getInstance().speak(message+", "+SpeechUtilities.getComponentSpeech(comboBox)); | |
292 final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.select")); | |
293 dialog.addWindowFocusListener(new WindowAdapter(){ | |
294 @Override | |
295 public void windowGainedFocus(WindowEvent e) { | |
296 comboBox.requestFocusInWindow(); | |
297 } | |
298 }); | |
299 | |
300 comboBox.addItemListener(SpeechUtilities.getSpeechComboBoxItemListener()); | |
301 | |
302 SpeechUtilities.changeTabListener(optPane,dialog); | |
303 // start the editing sound | |
304 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
305 dialog.setVisible(true); | |
306 dialog.dispose(); | |
307 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
308 if(optPane.getValue() == null)//window closed | |
309 return null; | |
310 else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel )//pressed on cancel | |
311 return null; | |
312 else{ // pressed on OK | |
313 return comboBox.getSelectedItem(); | |
314 } | |
315 } | |
316 | |
317 /** | |
318 * Shows the dialog with a {@code JSpinner} requesting the selection of the speech rate | |
319 * of the main voice of the {@code Narrator} | |
320 * | |
321 * @param parentComponent the parent {@code Component} for the dialog | |
322 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
323 * @param value the initial value | |
324 * @param min the minimum value of the spinner | |
325 * @param max the maximum value of the spinner | |
326 * @return the selected integer value or {@code null} if the user cancels the dialog | |
327 */ | |
328 public static Integer showNarratorRateDialog(Component parentComponent, String message, int value, int min, int max){ | |
329 NarratorFactory.getInstance().speak(message); | |
330 final JSpinner spinner = new JSpinner(new LoopSpinnerNumberModel(value,min,max)); | |
331 JFormattedTextField tf = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField(); | |
332 tf.setEditable(false); | |
333 tf.setFocusable(false); | |
334 tf.setBackground(Color.white); | |
335 | |
336 Object[] displayObjects = { new JLabel(message), spinner}; | |
337 final JOptionPane optPane = new JOptionPane(); | |
338 optPane.setMessage(displayObjects); | |
339 optPane.setMessageType(QUESTION_MESSAGE); | |
340 optPane.setOptionType(OK_CANCEL_OPTION); | |
341 /* ctrl key will hush the TTS */ | |
342 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
343 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
344 | |
345 final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.input")); | |
346 SpeechUtilities.changeTabListener(optPane,dialog); | |
347 | |
348 dialog.addWindowFocusListener(new WindowAdapter(){ | |
349 @Override | |
350 public void windowGainedFocus(WindowEvent e) { | |
351 spinner.requestFocusInWindow(); | |
352 } | |
353 }); | |
354 spinner.addChangeListener(new ChangeListener(){ | |
355 @Override | |
356 public void stateChanged(ChangeEvent evt) { | |
357 JSpinner s = (JSpinner)(evt.getSource()); | |
358 NarratorFactory.getInstance().setRate((Integer)s.getValue()); | |
359 NarratorFactory.getInstance().speak(s.getValue().toString()); | |
360 } | |
361 }); | |
362 // start the editing sound | |
363 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
364 dialog.setVisible(true); | |
365 dialog.dispose(); | |
366 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
367 | |
368 /* set the speech rate back to the value passed as argument */ | |
369 NarratorFactory.getInstance().setRate(value); | |
370 if(optPane.getValue() == null)//window closed | |
371 return null; | |
372 else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel | |
373 return null; | |
374 else{ // pressed on OK | |
375 return (Integer)spinner.getValue(); | |
376 } | |
377 } | |
378 | |
379 /** | |
380 * Brings up a dialog with selected options requesting user to confirmation. | |
381 * | |
382 * @param parentComponent the parent {@code Component} for the dialog | |
383 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
384 * @param optionType an integer designating the options available on the dialog | |
385 * @return an integer indicating the option selected by the user | |
386 */ | |
387 public static int showConfirmDialog(Component parentComponent, String message, int optionType){ | |
388 NarratorFactory.getInstance().speak(message); | |
389 JOptionPane optPane = new JOptionPane(); | |
390 optPane.setMessage(message); | |
391 optPane.setMessageType(QUESTION_MESSAGE); | |
392 optPane.setOptionType(optionType); | |
393 /* ctrl key will hush the TTS */ | |
394 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
395 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
396 | |
397 JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.confirm")); | |
398 SpeechUtilities.changeTabListener(optPane,dialog); | |
399 | |
400 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
401 dialog.setVisible(true); | |
402 dialog.dispose(); | |
403 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
404 | |
405 if(optPane.getValue() == null)//window closed | |
406 return CANCEL_OPTION; | |
407 else | |
408 return ((Integer)optPane.getValue()).intValue(); | |
409 } | |
410 | |
411 /** | |
412 * Displays a message to the user. | |
413 * | |
414 * @param parentComponent the parent {@code Component} for the dialog | |
415 * @param message the message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
416 * @param messageType the type of message to be displayed | |
417 */ | |
418 public static void showMessageDialog(Component parentComponent, String message, int messageType){ | |
419 NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("dialog.speech_option_pane.message"), message)); | |
420 JOptionPane optPane = new JOptionPane(); | |
421 optPane.setMessage(message); | |
422 optPane.setMessageType(messageType); | |
423 /* ctrl key will hush the TTS */ | |
424 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
425 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
426 | |
427 JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.confirm")); | |
428 SpeechUtilities.changeTabListener(optPane,dialog); | |
429 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
430 dialog.setVisible(true); | |
431 dialog.dispose(); | |
432 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
433 } | |
434 | |
435 /** | |
436 * Displays an error message to the user. | |
437 * | |
438 * @param parentComponent the parent {@code Component} for the dialog | |
439 * @param message the message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
440 */ | |
441 public static void showMessageDialog(Component parentComponent, String message){ | |
442 showMessageDialog(parentComponent,message,ERROR_MESSAGE); | |
443 } | |
444 | |
445 /** | |
446 * Execute a ProgressDialogWorker task and | |
447 * shows an indeterminate progress bar dialog if the task is not completed after | |
448 * {@code millisToDecideToPopup}. The user can use the dialog <i>cancel</i> button | |
449 * to cancel the task. | |
450 * | |
451 * @param <T> the result type returned by the worker | |
452 * @param <V> the intermediate result type of the worker | |
453 * @param parentComponent the parent {@code Component} for the dialog | |
454 * @param message message a message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
455 * @param worker a {@code ProgressDialogWorker} that is executed when this method is called | |
456 * @param millisToDecideToPopup the millisecond to let to the worker before popping the dialog up | |
457 * @return an integer indicating whether the task was completed or it was interrupted by the user | |
458 */ | |
459 public static <T,V> int showProgressDialog(Component parentComponent, String message,final ProgressDialogWorker<T,V> worker, int millisToDecideToPopup){ | |
460 JProgressBar progressBar = worker.bar; | |
461 Object displayObjects[] = {message, progressBar}; | |
462 final JOptionPane optPane = new JOptionPane(displayObjects); | |
463 optPane.setOptionType(DEFAULT_OPTION); | |
464 optPane.setOptions(new Object[] {PROGRESS_DIALOG_CANCEL_OPTION}); | |
465 /* ctrl key will hush the TTS */ | |
466 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
467 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
468 | |
469 final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.download")); | |
470 SpeechUtilities.changeTabListener(optPane,dialog); | |
471 | |
472 worker.setDialog(dialog); | |
473 worker.execute(); | |
474 try { | |
475 Thread.sleep(millisToDecideToPopup); | |
476 } catch (InterruptedException ie) { | |
477 throw new RuntimeException(ie); //should never happen | |
478 } | |
479 if(worker.isDone()) | |
480 return OK_OPTION; | |
481 | |
482 NarratorFactory.getInstance().speak(message); | |
483 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
484 dialog.setVisible(true); | |
485 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
486 if( optPane.getValue() == null || | |
487 optPane.getValue() == PROGRESS_DIALOG_CANCEL_OPTION || | |
488 Integer.valueOf(CLOSED_OPTION).equals(optPane.getValue())){ | |
489 worker.cancel(true); | |
490 return CANCEL_OPTION; | |
491 } | |
492 return OK_OPTION; | |
493 } | |
494 | |
495 /** | |
496 * Shows a check box dialog to select the modifiers of a given property | |
497 * | |
498 * @param parentComponent the parent {@code Component} for the dialog | |
499 * @param message message a message displayed in the dialog, such text is also uttered by the {@code Narrator} | |
500 * @param modifierTypes the different types of modifiers that are available for a given property | |
501 * @param modifierIndexes the initial selection of modifiers as the dialog is shown | |
502 * @return a new set with the modifier indexes selected by the user | |
503 */ | |
504 public static Set<Integer> showModifiersDialog(Component parentComponent, String message, List<String> modifierTypes, Set<Integer> modifierIndexes){ | |
505 JOptionPane optPane = new JOptionPane(); | |
506 | |
507 JPanel checkBoxPanel = new JPanel(new GridLayout(0, 1)); | |
508 final JCheckBox[] checkBoxes = new JCheckBox[modifierTypes.size()]; | |
509 for(int i=0;i<checkBoxes.length;i++){ | |
510 checkBoxes[i] = new JCheckBox(modifierTypes.get(i)); | |
511 if(modifierIndexes.contains(i)) | |
512 checkBoxes[i].setSelected(true); | |
513 checkBoxPanel.add(checkBoxes[i]); | |
514 checkBoxes[i].addItemListener(SpeechUtilities.getCheckBoxSpeechItemListener()); | |
515 } | |
516 NarratorFactory.getInstance().speak(message+" "+SpeechUtilities.getComponentSpeech(checkBoxes[0])); | |
517 | |
518 Object[] displayObjects = {new JLabel(message),checkBoxPanel}; | |
519 optPane.setMessage(displayObjects); | |
520 optPane.setMessageType(QUESTION_MESSAGE); | |
521 optPane.setOptionType(OK_CANCEL_OPTION); | |
522 /* ctrl key will hush the TTS */ | |
523 optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up"); | |
524 optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction()); | |
525 JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.modifiers")); | |
526 SpeechUtilities.changeTabListener(optPane,dialog); | |
527 | |
528 dialog.addWindowFocusListener(new WindowAdapter(){ | |
529 @Override | |
530 public void windowGainedFocus(WindowEvent e) { | |
531 checkBoxes[0].requestFocusInWindow(); | |
532 } | |
533 }); | |
534 | |
535 SoundFactory.getInstance().startLoop(SoundEvent.EDITING); | |
536 dialog.setVisible(true); | |
537 dialog.dispose(); | |
538 SoundFactory.getInstance().stopLoop(SoundEvent.EDITING); | |
539 | |
540 if(optPane.getValue() == null)//window closed | |
541 return null; | |
542 else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel | |
543 return null; | |
544 else{ // pressed on OK | |
545 Set<Integer> returnSet = new LinkedHashSet<Integer>(); | |
546 for(int i=0;i<checkBoxes.length;i++) | |
547 if(checkBoxes[i].isSelected()) | |
548 returnSet.add(i); | |
549 return returnSet; | |
550 } | |
551 } | |
552 | |
553 /** | |
554 * Returns the specified component's {code Frame}. | |
555 * | |
556 * @param parentComponent the component for this dialog | |
557 * @return the {@code Frame} that contains the component | |
558 */ | |
559 public static Frame getFrameForComponent(Component parentComponent){ | |
560 return JOptionPane.getFrameForComponent(parentComponent); | |
561 } | |
562 | |
563 private static ResourceBundle resources = ResourceBundle.getBundle(EditorFrame.class.getName()); | |
564 private static final int NOTES_TEXT_AREA_COL_SIZE = 10; | |
565 private static final int NOTES_TEXT_AREA_ROW_SIZE = 10; | |
566 private static final String PROGRESS_DIALOG_CANCEL_OPTION = resources.getString("dialog.speech_option_pane.cancel"); | |
567 | |
568 | |
569 public static final int QUESTION_MESSAGE = JOptionPane.QUESTION_MESSAGE; | |
570 public static final int ERROR_MESSAGE = JOptionPane.ERROR_MESSAGE; | |
571 public static final int INFORMATION_MESSAGE = JOptionPane.INFORMATION_MESSAGE; | |
572 public static final int WARNING_MESSAGE = JOptionPane.WARNING_MESSAGE; | |
573 public static final int OK_CANCEL_OPTION = JOptionPane.OK_CANCEL_OPTION; | |
574 public static final int CANCEL_OPTION = JOptionPane.CANCEL_OPTION; | |
575 public static final int OK_OPTION = JOptionPane.OK_OPTION; | |
576 public static final int CLOSED_OPTION = JOptionPane.CLOSED_OPTION; | |
577 public static final int DEFAULT_OPTION = JOptionPane.DEFAULT_OPTION; | |
578 public static final int YES_NO_OPTION = JOptionPane.YES_NO_OPTION; | |
579 public static final int YES_OPTION = JOptionPane.YES_OPTION; | |
580 public static final int NO_OPTION = JOptionPane.NO_OPTION; | |
581 | |
582 /** | |
583 * A swing worker to be passed as argument to {@code showProgressDialog}. The {@code execute} | |
584 * method can be interrupted by the user by clicking on the {@code cancel} button of the dialog. | |
585 * | |
586 * @param <T> the result type returned by this {@code SwingWorker}'s {@code doInBackground} and {@code get} methods | |
587 * @param <V> the type used for carrying out intermediate results by this {@code SwingWorker}'s {@code publish} and {@code process} methods | |
588 */ | |
589 public static abstract class ProgressDialogWorker<T,V> extends SwingWorker<T,V> { | |
590 /** | |
591 * Creates a new ProgressDialogWorker | |
592 */ | |
593 public ProgressDialogWorker(){ | |
594 bar = new JProgressBar(); | |
595 bar.setIndeterminate(true); | |
596 } | |
597 | |
598 private void setDialog(JDialog dialog){ | |
599 this.dialog = dialog; | |
600 } | |
601 | |
602 @Override | |
603 protected void done() { //executed in EDT when the work is done | |
604 if(dialog != null) | |
605 dialog.dispose(); | |
606 } | |
607 | |
608 private JDialog dialog; | |
609 private JProgressBar bar; | |
610 } | |
611 | |
612 | |
613 } |