view java/src/uk/ac/qmul/eecs/ccmi/gui/SpeechOptionPane.java @ 0:9418ab7b7f3f

Initial import
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Fri, 16 Dec 2011 17:35:51 +0000
parents
children 9e67171477bc
line wrap: on
line source
/*  
 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.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.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.NarratorFactory;
import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities;

/**
 * 
 * TheSpeechOptionPane 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 the {@link Narrator} instance. 
 *  
 */
public abstract class SpeechOptionPane {
	
	public static String showTextAreaDialog(Component parentComponent, String message, String initialSelectionValue){
		JTextArea textArea = new JTextArea(NOTES_TEXT_AREA_ROW_SIZE,NOTES_TEXT_AREA_COL_SIZE);
		textArea.setText(initialSelectionValue);
		NarratorFactory.getInstance().speak(message);
		return textComponentDialog(parentComponent, message, textArea);
	}
	
	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);
		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();
		}
	}	
	
	public static String showInputDialog(Component parentComponent, String message){
		return showInputDialog(parentComponent, message, "");
	}
	
	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);
		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();
		}
	}
	
	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);
		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();
		}
	}
	
	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);
		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
		
		if(optPane.getValue() == null)//window closed
			return CANCEL_OPTION;
		else 
			return ((Integer)optPane.getValue()).intValue();
	}
	
	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);
		SoundFactory.getInstance().stopLoop(SoundEvent.EDITING);
	}
	
	public static void showMessageDialog(Component parentComponent, String message){
		showMessageDialog(parentComponent,message,ERROR_MESSAGE);
	}
	
	public static <T,V> int showProgressDialog(Component parentComponent, String message,final ProgressDialogWorker<T,V> worker, int millisToDecideToPopup){
		JProgressBar progressBar = new JProgressBar();
		progressBar.setIndeterminate(true);
		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;
	}
	
	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);
		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;
		}
	}
	
	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;
	
	
	public static abstract class ProgressDialogWorker<T,V> extends SwingWorker<T,V> {
		private void setDialog(JDialog dialog){
			this.dialog = dialog;
		}
		
		@Override
	    protected void done() {
			if(dialog != null)
				dialog.dispose();
		}
		
		private JDialog dialog;
	}
	
	
}