diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/java/src/uk/ac/qmul/eecs/ccmi/gui/SpeechOptionPane.java	Tue Jul 08 16:28:59 2014 +0100
@@ -0,0 +1,613 @@
+/*  
+ CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
+  
+ Copyright (C) 2011  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package uk.ac.qmul.eecs.ccmi.gui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.text.MessageFormat;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFormattedTextField;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.SwingWorker;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.text.JTextComponent;
+
+import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
+import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
+import uk.ac.qmul.eecs.ccmi.speech.Narrator;
+import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
+import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities;
+
+/**
+ * 
+ * An option panel made out of an {@code Object} being displayed and to buttons: one for accepting and another one for 
+ * cancelling the option.   
+ * Furthermore, this class provides one-line calls to display accessible dialog boxes. Input by the user as well 
+ * as focused components are spoken out through text to speech synthesis performed by a {@link Narrator} instance.
+ */
+public class SpeechOptionPane {
+	
+	/**
+	 * Construct a new {@code SpeechOptionPane} with no title. The title is displayed at the top of the dialog
+	 * that is displayed after a call to {@code showDialog} 
+	 */
+	public SpeechOptionPane(){
+		this("");
+	}
+	
+	/**
+	 * Construct a new {@code SpeechOptionPane} with no title. The title is displayed at the top of the dialog
+	 * that is displayed after a call to {@code showDialog}
+	 * 
+	 * @param title the String to be displayed
+	 */
+	public SpeechOptionPane(String title){
+		this.title = title; 
+		okButton = new JButton("OK");
+		cancelButton = new JButton("Cancel");
+	}
+	
+	/**
+	 * Pops the a dialog holding this SpeechOptionPane 
+	 *  
+	 * @param parent the parent component of the dialog
+	 * @param message the {@code Object} to display
+	 * @return an integer indicating the option selected by the user
+	 */
+	@SuppressWarnings("serial")
+	public int showDialog(Component parent,final Object message){
+		optPane = new JOptionPane();
+		optPane.setMessage(message);
+		/* Enter will entail a unique action, regardless the component that's focused */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "closeDialog");
+		optPane.getActionMap().put("closeDialog", new AbstractAction(){
+			@Override
+			public void actionPerformed(ActionEvent evt) {
+				okButton.doClick();
+			}
+		});
+		optPane.setMessageType(JOptionPane.PLAIN_MESSAGE);
+		Object[] options = {
+				okButton,
+				cancelButton
+		};
+		optPane.setOptions(options);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		final JDialog dialog = optPane.createDialog(parent, title);
+		dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		/* when either button is pressed, dialog is disposed and the button itself becomes the optPane.value */
+		ActionListener buttonListener = new ActionListener(){
+			@Override
+			public void actionPerformed(ActionEvent evt) {
+				onClose(dialog,(JButton)evt.getSource());
+			}
+		};
+		okButton.addActionListener(buttonListener);
+		cancelButton.addActionListener(buttonListener);
+
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		if(okButton.equals(optPane.getValue())){
+			return OK_OPTION;
+		}else{
+			return CANCEL_OPTION;
+		}
+	}
+	
+	/**
+	 * Sets the string appearing at the top of the dialog where this option pane is displayed when {@code showDialog}
+	 * is called.
+	 * @param title the title of this option pane 
+	 */
+	public void setDialogTitle(String title){
+		this.title = title;
+	}
+	
+	/**
+	 * Returns the {@code JButton} that the user has to press (when the option pane is displayed after 
+	 * {@code showDialog} is called) in order to accept the option.
+	 *    
+	 * @return a reference to the internal {@code JButton} 
+	 */
+	public JButton getOkButton(){
+		return okButton;
+	}
+	
+	/**
+	 * Returns the {@code JButton} that the user has to press (when the option pane is displayed after 
+	 * {@code showDialog} is called) in order to reject the option.
+	 *    
+	 * @return a reference to the internal {@code JButton} 
+	 */
+	public JButton getCancelButton(){
+		return cancelButton;
+	}
+	
+	/**
+	 * This method is called just after the user presses either button of the dialog displayed
+	 * after {@code showDialog} is called.
+	 * It assign a value to the return value and it frees the dialog resources.
+	 * It can be overwritten by subclasses but care should be taken of calling this class method via
+	 * {@code super} in order to properly close the dialog.   
+	 * 
+	 * @param dialog the dialog displayed after {@code showDialog} is called. 
+	 * @param source the button that triggered the closing of {@code dialog}
+	 */
+	protected void onClose(JDialog dialog, JButton source){
+		optPane.setValue(source);
+		dialog.dispose();
+	}
+	
+	private String title;
+	private JOptionPane optPane;
+	private JButton okButton;
+	private JButton cancelButton;
+	
+	
+	/* -------- STATIC METHODS ----------- */
+	
+	/**
+	 * Shows a dialog with a text area requesting input for the user.
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message a displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param text the initial text the text area contains when the dialog is displayed 
+	 *  
+	 * @return the new text entered by the user
+	 */
+	public static String showTextAreaDialog(Component parentComponent, String message, String text){
+		JTextArea textArea = new JTextArea(NOTES_TEXT_AREA_ROW_SIZE,NOTES_TEXT_AREA_COL_SIZE);
+		textArea.setText(text);
+		NarratorFactory.getInstance().speak(message);
+		return textComponentDialog(parentComponent, message, textArea);
+	}
+	
+	/**
+	 * Shows a dialog with a text field requesting input from the user 
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param initialSelectionValue the initial text the text field contains when the dialog is displayed 
+	 * 
+	 * @return the text entered by the user 
+	 */
+	public static String showInputDialog(Component parentComponent, String message, String initialSelectionValue){
+		final JTextField textField = new JTextField(initialSelectionValue);
+		textField.selectAll();
+		NarratorFactory.getInstance().speak(message);
+		return textComponentDialog(parentComponent, message, textField);
+	}
+		
+	private static String textComponentDialog(Component parentComponent, String message, final JTextComponent textComponent){	
+		Object componentToDisplay = textComponent;
+		if(textComponent instanceof JTextArea)
+			componentToDisplay = new JScrollPane(textComponent);
+		
+		Object[] displayObjects = { new JLabel(message), componentToDisplay };
+		final JOptionPane optPane = new JOptionPane();
+		optPane.setMessage(displayObjects);
+		optPane.setMessageType(QUESTION_MESSAGE);	
+		optPane.setOptionType(OK_CANCEL_OPTION);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		
+		final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.input"));
+		if(textComponent instanceof JTextArea)
+			dialog.setResizable(true);
+		dialog.addWindowFocusListener(new WindowAdapter(){
+			@Override
+			public void windowGainedFocus(WindowEvent e) {
+				textComponent.requestFocusInWindow();
+		    }
+		});
+		
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		textComponent.addKeyListener(SpeechUtilities.getSpeechKeyListener(true));
+		textComponent.setEditable(true);
+		// start the editing sound
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		dialog.dispose();
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		
+		if(optPane.getValue() == null)//window closed
+			return null;
+		else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel
+			return null;
+		else{ // pressed on OK
+			return textComponent.getText().trim();
+		}
+	}	
+	
+	/**
+	 * Shows a dialog with a {@code JComboBox} requesting selection from the user 
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param options options for the {@code JComboBox}
+	 * @param initialValue the options value selected when the dialog is shown   
+	 * @return the option selected by the user 
+	 */
+	public static Object showSelectionDialog(Component parentComponent, String message, Object[] options, Object initialValue){
+		final LoopComboBox comboBox = new LoopComboBox(options);
+		comboBox.setSelectedItem(initialValue);
+		Object[] displayObjects = { new JLabel(message), comboBox };
+		JOptionPane optPane = new JOptionPane();
+		optPane.setMessage(displayObjects);
+		optPane.setMessageType(QUESTION_MESSAGE);
+		optPane.setOptionType(OK_CANCEL_OPTION);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		
+		NarratorFactory.getInstance().speak(message+", "+SpeechUtilities.getComponentSpeech(comboBox));
+		final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.select"));
+		dialog.addWindowFocusListener(new WindowAdapter(){
+			@Override
+			public void windowGainedFocus(WindowEvent e) {
+		        comboBox.requestFocusInWindow();
+		    }
+		});
+		
+		comboBox.addItemListener(SpeechUtilities.getSpeechComboBoxItemListener());
+
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		// start the editing sound
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		dialog.dispose();
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		if(optPane.getValue() == null)//window closed
+			return null;
+		else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel )//pressed on cancel
+			return null;
+		else{ // pressed on OK
+			return comboBox.getSelectedItem();
+		}
+	}
+	
+	/**
+	 * Shows the dialog with a {@code JSpinner} requesting the selection of the speech rate 
+	 * of the main voice of the {@code Narrator} 
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param value the initial value 
+	 * @param min the minimum value of the spinner 
+	 * @param max the maximum value of the spinner 
+	 * @return the selected integer value or {@code null} if the user cancels the dialog  
+	 */
+	public static Integer showNarratorRateDialog(Component parentComponent, String message, int value, int min, int max){	
+		NarratorFactory.getInstance().speak(message);
+		final JSpinner spinner = new JSpinner(new LoopSpinnerNumberModel(value,min,max));
+		JFormattedTextField tf = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
+		tf.setEditable(false);
+		tf.setFocusable(false);
+		tf.setBackground(Color.white);
+		
+		Object[] displayObjects = { new JLabel(message), spinner};
+		final JOptionPane optPane = new JOptionPane();
+		optPane.setMessage(displayObjects);
+		optPane.setMessageType(QUESTION_MESSAGE);	
+		optPane.setOptionType(OK_CANCEL_OPTION);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		
+		final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.input"));
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		
+		dialog.addWindowFocusListener(new WindowAdapter(){
+			@Override
+			public void windowGainedFocus(WindowEvent e) {
+				spinner.requestFocusInWindow();
+		    }
+		});
+		spinner.addChangeListener(new ChangeListener(){
+			@Override
+			public void stateChanged(ChangeEvent evt) {
+				 JSpinner s = (JSpinner)(evt.getSource());
+				 NarratorFactory.getInstance().setRate((Integer)s.getValue());
+				 NarratorFactory.getInstance().speak(s.getValue().toString());
+			}
+		});
+		// start the editing sound
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		dialog.dispose();
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		
+		/* set the speech rate back to the value passed as argument */
+		NarratorFactory.getInstance().setRate(value);
+		if(optPane.getValue() == null)//window closed
+			return null;
+		else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel
+			return null;
+		else{ // pressed on OK
+			return (Integer)spinner.getValue();
+		}
+	}
+	
+	/**
+	 * Brings up a dialog with selected options requesting user to confirmation.
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message a message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param optionType  an integer designating the options available on the dialog
+	 * @return an integer indicating the option selected by the user 
+	 */
+	public static int showConfirmDialog(Component parentComponent, String message, int optionType){
+		NarratorFactory.getInstance().speak(message);
+		JOptionPane optPane = new JOptionPane();
+		optPane.setMessage(message);
+		optPane.setMessageType(QUESTION_MESSAGE);
+		optPane.setOptionType(optionType);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		
+		JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.confirm"));
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		dialog.dispose();
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		
+		if(optPane.getValue() == null)//window closed
+			return CANCEL_OPTION;
+		else 
+			return ((Integer)optPane.getValue()).intValue();
+	}
+	
+	/**
+	 * Displays a message to the user.
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message the message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param messageType the type of message to be displayed
+	 */
+	public static void showMessageDialog(Component parentComponent, String message, int messageType){
+		NarratorFactory.getInstance().speak(MessageFormat.format(resources.getString("dialog.speech_option_pane.message"), message));
+		JOptionPane optPane = new JOptionPane();
+		optPane.setMessage(message);
+		optPane.setMessageType(messageType);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		
+		JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.confirm"));
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		dialog.dispose();
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+	}
+	
+	/**
+	 * Displays an error message to the user.
+	 * 
+	 * @param parentComponent the parent {@code Component} for the dialog
+	 * @param message the message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 */
+	public static void showMessageDialog(Component parentComponent, String message){
+		showMessageDialog(parentComponent,message,ERROR_MESSAGE);
+	}
+	
+	/**
+	 * Execute a ProgressDialogWorker task and 
+	 * shows an indeterminate progress bar dialog if the task is not completed after 
+	 * {@code millisToDecideToPopup}. The user can use the dialog <i>cancel</i> button 
+	 * to cancel the task. 
+	 * 
+	 * @param <T>  the result type returned by the worker 
+	 * @param <V>  the intermediate result type of the worker 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message message a message displayed in the dialog, such text is also uttered by the {@code Narrator} 
+	 * @param worker a {@code ProgressDialogWorker} that is executed when this method is called
+	 * @param millisToDecideToPopup the millisecond to let to the worker before popping the dialog up   
+	 * @return an integer indicating whether the task was completed or it was interrupted by the user 
+	 */
+	public static <T,V> int showProgressDialog(Component parentComponent, String message,final ProgressDialogWorker<T,V> worker, int millisToDecideToPopup){
+		JProgressBar progressBar = worker.bar;
+		Object displayObjects[] = {message, progressBar};
+		final JOptionPane optPane = new JOptionPane(displayObjects);
+		optPane.setOptionType(DEFAULT_OPTION);
+		optPane.setOptions(new Object[] {PROGRESS_DIALOG_CANCEL_OPTION});
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		
+		final JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.download"));
+		SpeechUtilities.changeTabListener(optPane,dialog);
+
+		worker.setDialog(dialog);
+		worker.execute();
+		try {
+			Thread.sleep(millisToDecideToPopup);
+		} catch (InterruptedException ie) {
+			throw new RuntimeException(ie); //should never happen
+		}
+		if(worker.isDone())
+			return OK_OPTION;
+		
+		NarratorFactory.getInstance().speak(message);
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		if(	optPane.getValue() == null ||
+			optPane.getValue() == PROGRESS_DIALOG_CANCEL_OPTION || 
+			Integer.valueOf(CLOSED_OPTION).equals(optPane.getValue())){
+				worker.cancel(true);
+				return CANCEL_OPTION;
+		}
+		return OK_OPTION;
+	}
+	
+	/**
+	 * Shows a check box dialog to select the modifiers of a given property 
+	 * 
+	 * @param parentComponent  the parent {@code Component} for the dialog
+	 * @param message message a message displayed in the dialog, such text is also uttered by the {@code Narrator}
+	 * @param modifierTypes the different types of modifiers that are available for a given property
+	 * @param modifierIndexes the initial selection of modifiers as the dialog is shown
+	 * @return a new set with the modifier indexes selected by the user 
+	 */
+	public static Set<Integer> showModifiersDialog(Component parentComponent, String message, List<String> modifierTypes, Set<Integer> modifierIndexes){
+		JOptionPane optPane = new JOptionPane();
+		
+		JPanel checkBoxPanel = new JPanel(new GridLayout(0, 1));
+		final JCheckBox[] checkBoxes = new JCheckBox[modifierTypes.size()]; 
+		for(int i=0;i<checkBoxes.length;i++){
+			checkBoxes[i] = new JCheckBox(modifierTypes.get(i));
+			if(modifierIndexes.contains(i))
+				checkBoxes[i].setSelected(true);
+			checkBoxPanel.add(checkBoxes[i]);
+			checkBoxes[i].addItemListener(SpeechUtilities.getCheckBoxSpeechItemListener());
+		}
+		NarratorFactory.getInstance().speak(message+" "+SpeechUtilities.getComponentSpeech(checkBoxes[0]));
+		
+		Object[] displayObjects = {new JLabel(message),checkBoxPanel};
+		optPane.setMessage(displayObjects);
+		optPane.setMessageType(QUESTION_MESSAGE);
+		optPane.setOptionType(OK_CANCEL_OPTION);
+		/* ctrl key will hush the TTS */
+		optPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL,InputEvent.CTRL_DOWN_MASK),"shut_up");
+		optPane.getActionMap().put("shut_up", SpeechUtilities.getShutUpAction());
+		JDialog dialog = optPane.createDialog(parentComponent, resources.getString("dialog.speech_option_pane.modifiers"));
+		SpeechUtilities.changeTabListener(optPane,dialog);
+		
+		dialog.addWindowFocusListener(new WindowAdapter(){
+			@Override
+			public void windowGainedFocus(WindowEvent e) {
+		        checkBoxes[0].requestFocusInWindow();
+		    }
+		});
+		
+		SoundFactory.getInstance().startLoop(SoundEvent.EDITING);
+		dialog.setVisible(true);
+		dialog.dispose();
+		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
+		
+		if(optPane.getValue() == null)//window closed
+			return null;
+		else if(((Integer)optPane.getValue()).intValue() == CANCEL_OPTION || ((Integer)optPane.getValue()).intValue() == CLOSED_OPTION)//pressed on cancel
+			return null;
+		else{ // pressed on OK
+			Set<Integer> returnSet = new LinkedHashSet<Integer>();
+			for(int i=0;i<checkBoxes.length;i++)
+				if(checkBoxes[i].isSelected()) 
+					returnSet.add(i);
+			return returnSet;
+		}
+	}
+	
+	/**
+	 * Returns the specified component's {code Frame}.
+	 * 
+	 * @param parentComponent the component for this dialog 
+	 * @return the {@code Frame} that contains the component 
+	 */
+	public static Frame getFrameForComponent(Component parentComponent){
+		return JOptionPane.getFrameForComponent(parentComponent);
+	}
+	
+	private static ResourceBundle resources = ResourceBundle.getBundle(EditorFrame.class.getName());
+	private static final int NOTES_TEXT_AREA_COL_SIZE = 10;
+	private static final int NOTES_TEXT_AREA_ROW_SIZE = 10;
+	private static final String PROGRESS_DIALOG_CANCEL_OPTION = resources.getString("dialog.speech_option_pane.cancel"); 
+	
+	
+	public static final int QUESTION_MESSAGE = JOptionPane.QUESTION_MESSAGE;
+	public static final int ERROR_MESSAGE = JOptionPane.ERROR_MESSAGE;
+	public static final int INFORMATION_MESSAGE = JOptionPane.INFORMATION_MESSAGE;
+	public static final int WARNING_MESSAGE = JOptionPane.WARNING_MESSAGE;
+	public static final int OK_CANCEL_OPTION = JOptionPane.OK_CANCEL_OPTION;
+	public static final int CANCEL_OPTION = JOptionPane.CANCEL_OPTION;
+	public static final int OK_OPTION = JOptionPane.OK_OPTION; 
+	public static final int CLOSED_OPTION = JOptionPane.CLOSED_OPTION;
+	public static final int DEFAULT_OPTION = JOptionPane.DEFAULT_OPTION;
+	public static final int YES_NO_OPTION = JOptionPane.YES_NO_OPTION;
+	public static final int YES_OPTION = JOptionPane.YES_OPTION;
+	public static final int NO_OPTION = JOptionPane.NO_OPTION;
+	
+	/**
+	 * A swing worker to be passed as argument to {@code showProgressDialog}. The {@code execute}
+	 * method can be interrupted by the user by clicking on the {@code cancel} button of the dialog. 
+	 *
+	 * @param <T>  the result type returned by this {@code SwingWorker}'s {@code doInBackground} and {@code get} methods
+	 * @param <V>  the type used for carrying out intermediate results by this {@code SwingWorker}'s {@code publish} and {@code process} methods
+	 */
+	public static abstract class ProgressDialogWorker<T,V> extends SwingWorker<T,V> {
+		/**
+		 * Creates a new ProgressDialogWorker 
+		 */
+		public ProgressDialogWorker(){
+			bar = new JProgressBar();
+			bar.setIndeterminate(true);
+		}
+		
+		private void setDialog(JDialog dialog){
+			this.dialog = dialog;
+		}
+		
+		@Override
+	    protected void done() { //executed in EDT when the work is done
+			if(dialog != null)
+				dialog.dispose();
+		}
+		
+		private JDialog dialog;
+		private JProgressBar bar;
+	}
+	
+	
+}