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