diff java/src/uk/ac/qmul/eecs/ccmi/simpletemplate/SpeechWizardPanel.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/simpletemplate/SpeechWizardPanel.java	Tue Jul 08 16:28:59 2014 +0100
@@ -0,0 +1,319 @@
+/*  
+ 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.simpletemplate;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.ResourceBundle;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JFormattedTextField;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SpinnerModel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import jwizardcomponent.JWizardComponents;
+import jwizardcomponent.JWizardPanel;
+import uk.ac.qmul.eecs.ccmi.gui.LoopComboBox;
+import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
+import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities;
+
+/*
+ * The abstract class providing basic implementation for the panels displayed when the template
+ * wizard is run in order to build a diagram template. Subclasses will define the central component 
+ * displayed in the panel. The central component is an input component (e.g. a JTextField),
+ * through which the user enters the input required for at that particular step of the wizard.
+ *  
+ *  
+ * @see Wizard
+ */
+@SuppressWarnings("serial")
+abstract class SpeechWizardPanel extends JWizardPanel {
+	public SpeechWizardPanel(JWizardComponents wizardComponents, String title, int next, int previous){
+		super(wizardComponents,title);
+		label = new JLabel(title);
+		this.next = next;
+		this.previous = previous;
+	}
+	
+	@Override
+	public void update(){
+		Component focusOwner = assignFocus();
+		NarratorFactory.getInstance().speak(
+				new StringBuilder(getPanelTitle())
+					.append(' ')
+					.append(SpeechUtilities.getComponentSpeech(focusOwner)).toString());
+		super.update();
+	}
+	
+	@Override
+	public void setPanelTitle(String title){
+		label.setText(title);
+		super.setPanelTitle(title);
+	}
+	
+	protected Component assignFocus(){
+		if(component != null)
+			component.requestFocus();
+		return component;
+	}
+	
+	/**
+	 * Lays out the components according to the layout manager. This method is used by subclasses 
+	 * by passing the component the user use for input (e.g. a text field or a combo-box) as argument.
+	 * such component is placed at the centre of the panel above the buttons.    
+	 * @param centralComponent the component to be laid out at the centre dialog  
+	 */
+	protected void layoutComponents(JComponent centralComponent){
+		component = centralComponent;
+		/* pressing enter on the central component results in a switch to the next panel */
+		component.addKeyListener(new KeyAdapter(){
+			@Override
+			public void keyPressed(KeyEvent evt){
+				pressed = true;
+			}
+			
+			@Override
+			public void keyTyped(KeyEvent evt){
+				/* switch on the next panel only if the press button started on the same window      * 
+				 * this is to avoid keyTyped to be called after the panel switch and therefore refer *
+				 * to a component different that the one the user pressed OK on                      */
+				if(evt.getKeyChar() == '\n' && pressed)
+					getWizardComponents().getNextButton().doClick();
+				pressed = false;
+			}
+			boolean pressed = false;
+		});
+		
+		GridBagConstraints constr = new GridBagConstraints();
+		constr.gridx = 0;
+		constr.gridy = 0;
+		constr.gridwidth = 1;
+		constr.gridheight = 1;
+		constr.weightx = 1.0;
+		constr.weighty = 0.0;
+		constr.anchor = GridBagConstraints.PAGE_START;
+		constr.fill = GridBagConstraints.BOTH;
+		constr.insets = new Insets(5, 5, 5, 5);
+		constr.ipadx = 0;
+		constr.ipady = 0;
+		
+		/* Label */
+		setLayout(new GridBagLayout());
+		JPanel labelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+		label.setHorizontalAlignment(SwingConstants.LEADING);
+		labelPanel.add(label);
+		add(labelPanel,constr);
+		
+		/* JSeparator */
+		constr.gridy = 1;
+		constr.anchor = GridBagConstraints.WEST;
+		constr.fill = GridBagConstraints.BOTH;
+		constr.insets = new Insets(1, 1, 1, 1);
+		add(new JSeparator(), constr);
+		
+		/* central component */
+		Container centralComponentContainer;
+		if(centralComponent instanceof JScrollPane ){
+			centralComponentContainer = centralComponent;
+		}else{
+			centralComponentContainer = new JPanel(new GridBagLayout());
+			centralComponentContainer.add(centralComponent
+	        , new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
+	        , GridBagConstraints.CENTER, GridBagConstraints.BOTH
+	        , new Insets(0, 0, 0, 0), 0, 0));
+		}
+		constr.gridy = 2;
+		constr.weighty = 1.0;
+		constr.anchor = GridBagConstraints.CENTER;
+		constr.insets = new Insets(0, 0, 0, 0); 
+		add(centralComponentContainer,constr);
+	}
+	
+	@Override
+	public void next(){
+		switchPanel(next);
+	}
+
+	@Override
+	public void back(){
+		switchPanel(previous);
+	}
+	
+	private JLabel label;
+	private int next;
+	private int previous;
+	private JComponent component;
+	public static int OWN_SWITCH = -1;
+	public static int DISABLE_SWITCH = -2;
+}
+
+@SuppressWarnings("serial")
+class SelectWizardPanel extends SpeechWizardPanel {
+	SelectWizardPanel(JWizardComponents wizardComponents, String title, Collection<String> options, int next, int previous, Model.Record record){
+		super(wizardComponents,title,next,previous);
+		String[] optionsArray = new String[options.size()];
+		comboBox = new LoopComboBox(new DefaultComboBoxModel(options.toArray(optionsArray)));
+		comboBox.addItemListener(SpeechUtilities.getSpeechComboBoxItemListener());
+		layoutComponents(comboBox);
+		this.record = record;
+	}
+	
+	SelectWizardPanel(JWizardComponents wizardComponents, String title, Collection<String> options, int[] nexts, int previous, Model.Record record){
+		this(wizardComponents, title, options, OWN_SWITCH, previous, record);
+		this.nexts = nexts;
+	}
+	
+	SelectWizardPanel(JWizardComponents wizardComponents, String title, Collection<String> options, int[] nexts, int previous){
+		this(wizardComponents, title, options, nexts, previous,null);
+	}
+
+	@Override
+	public void next(){
+		if(record != null)
+			record.value = (String)comboBox.getSelectedItem();
+		if(nexts != null)
+			switchPanel(nexts[comboBox.getSelectedIndex()]);
+		else
+			super.next();
+	}
+	
+	@Override
+	public void update(){
+		if(record != null)
+			comboBox.setSelectedItem(record.value);
+		super.update();
+	}
+	
+	JComboBox comboBox;
+	int[] nexts;
+	Model.Record record;
+}
+
+@SuppressWarnings("serial")
+class TextWizardPanel extends SpeechWizardPanel {
+	TextWizardPanel(JWizardComponents wizardComponents, String title, Collection<String> existingValues, int next, int previous, Model.Record record){
+		super(wizardComponents,title,next,previous);
+		textField = new JTextField();
+		textField.setColumns(10);
+		textField.addKeyListener(SpeechUtilities.getSpeechKeyListener(true));
+		layoutComponents(textField);
+		this.record = record;
+		this.existingValues = existingValues;
+	}
+	
+	public void next(){
+		String text = textField.getText().trim();
+		/* if the user enters a text he has already entered (that is, it's in the existingValues the don't go on */
+		/* and notify the user they have to chose another text. The only exception is when the record contains   */ 
+		/* the same text the user entered as that means they are going through the editing of an existing element*/
+		if(text.isEmpty()||"\n".equals(text)){
+				NarratorFactory.getInstance().speak(ResourceBundle.getBundle(SpeechWizardDialog.class.getName()).getString("dialog.error.empty_text"));
+				return;
+		}
+		for(String value : existingValues){
+			if(value.equals(text) && !text.equals(record.value)){
+				NarratorFactory.getInstance().speak(MessageFormat.format( 
+								ResourceBundle.getBundle(SpeechWizardDialog.class.getName()).getString("dialog.error.existing_value"),
+								text));
+				return;
+			}
+		}
+		if(record != null)
+			record.value = text;
+		super.next();
+	}
+	
+	@Override
+	public void update(){
+		if(record != null)
+			textField.setText(record.value);
+		super.update();
+	}
+	
+	JTextField textField;
+	Collection<String> existingValues;
+	Model.Record record;
+}
+
+@SuppressWarnings("serial")
+class SpinnerWizardPanel extends SpeechWizardPanel{
+	public SpinnerWizardPanel(JWizardComponents wizardComponents, String title, SpinnerModel spinnerModel, int next, int previous, Model.Record record){
+		super(wizardComponents,title,next,previous);
+		this.record = record;
+		spinner = new JSpinner(spinnerModel);
+		spinner.addChangeListener(new ChangeListener(){
+			@Override
+			public void stateChanged(ChangeEvent evt) {
+				 JSpinner s = (JSpinner)(evt.getSource());
+				 NarratorFactory.getInstance().speak(s.getValue().toString());
+			}
+		});
+		JFormattedTextField tf = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
+		tf.setEditable(false);
+		tf.setFocusable(false);
+		tf.setBackground(Color.white);
+		layoutComponents(spinner);
+	}
+	
+	@Override
+	public void next(){
+		if(record != null)
+			record.value = spinner.getValue().toString();
+		super.next();
+	}
+	
+	@Override
+	public void update(){
+		if(record != null){
+			if(!record.value.isEmpty())
+				spinner.setValue(Integer.parseInt(record.value));
+		}
+		super.update();
+	}
+	
+	Model.Record record;
+	JSpinner spinner;
+}
+
+@SuppressWarnings("serial")
+class DummyWizardPanel extends JWizardPanel{
+	DummyWizardPanel(JWizardComponents wizardComponents){
+		super(wizardComponents);
+	}
+}