fiore@0: /*
fiore@0: CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
fiore@0:
fiore@0: Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
fiore@0:
fiore@0: This program is free software: you can redistribute it and/or modify
fiore@0: it under the terms of the GNU General Public License as published by
fiore@0: the Free Software Foundation, either version 3 of the License, or
fiore@0: (at your option) any later version.
fiore@0:
fiore@0: This program is distributed in the hope that it will be useful,
fiore@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
fiore@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fiore@0: GNU General Public License for more details.
fiore@0:
fiore@0: You should have received a copy of the GNU General Public License
fiore@0: along with this program. If not, see .
fiore@0: */
fiore@0:
fiore@0: package uk.ac.qmul.eecs.ccmi.simpletemplate;
fiore@0:
fiore@0: import java.awt.Color;
fiore@0: import java.awt.Component;
fiore@0: import java.awt.Container;
fiore@0: import java.awt.FlowLayout;
fiore@0: import java.awt.GridBagConstraints;
fiore@0: import java.awt.GridBagLayout;
fiore@0: import java.awt.Insets;
fiore@0: import java.awt.event.KeyAdapter;
fiore@0: import java.awt.event.KeyEvent;
fiore@0: import java.text.MessageFormat;
fiore@0: import java.util.Collection;
fiore@0: import java.util.ResourceBundle;
fiore@0:
fiore@0: import javax.swing.DefaultComboBoxModel;
fiore@0: import javax.swing.JComboBox;
fiore@0: import javax.swing.JComponent;
fiore@0: import javax.swing.JFormattedTextField;
fiore@0: import javax.swing.JLabel;
fiore@0: import javax.swing.JPanel;
fiore@0: import javax.swing.JScrollPane;
fiore@0: import javax.swing.JSeparator;
fiore@0: import javax.swing.JSpinner;
fiore@0: import javax.swing.JTextField;
fiore@0: import javax.swing.SpinnerModel;
fiore@0: import javax.swing.SwingConstants;
fiore@0: import javax.swing.event.ChangeEvent;
fiore@0: import javax.swing.event.ChangeListener;
fiore@0:
fiore@0: import jwizardcomponent.JWizardComponents;
fiore@0: import jwizardcomponent.JWizardPanel;
fiore@0: import uk.ac.qmul.eecs.ccmi.gui.LoopComboBox;
fiore@0: import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
fiore@0: import uk.ac.qmul.eecs.ccmi.speech.SpeechUtilities;
fiore@0:
fiore@0: /*
fiore@0: * The abstract class providing basic implementation for the panels displayed when the template
fiore@0: * wizard is run in order to build a diagram template. Subclasses will define the central component
fiore@0: * displayed in the panel. The central component is an input component (e.g. a JTextField),
fiore@0: * through which the user enters the input required for at that particular step of the wizard.
fiore@0: *
fiore@0: *
fiore@0: * @see Wizard
fiore@0: */
fiore@0: @SuppressWarnings("serial")
fiore@0: abstract class SpeechWizardPanel extends JWizardPanel {
fiore@0: public SpeechWizardPanel(JWizardComponents wizardComponents, String title, int next, int previous){
fiore@0: super(wizardComponents,title);
fiore@0: label = new JLabel(title);
fiore@0: this.next = next;
fiore@0: this.previous = previous;
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void update(){
fiore@0: Component focusOwner = assignFocus();
fiore@0: NarratorFactory.getInstance().speak(
fiore@0: new StringBuilder(getPanelTitle())
fiore@0: .append(' ')
fiore@0: .append(SpeechUtilities.getComponentSpeech(focusOwner)).toString());
fiore@0: super.update();
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void setPanelTitle(String title){
fiore@0: label.setText(title);
fiore@0: super.setPanelTitle(title);
fiore@0: }
fiore@0:
fiore@0: protected Component assignFocus(){
fiore@0: if(component != null)
fiore@0: component.requestFocus();
fiore@0: return component;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Lays out the components according to the layout manager. This method is used by subclasses
fiore@0: * by passing the component the user use for input (e.g. a text field or a combo-box) as argument.
fiore@0: * such component is placed at the centre of the panel above the buttons.
fiore@0: * @param centralComponent the component to be laid out at the centre dialog
fiore@0: */
fiore@0: protected void layoutComponents(JComponent centralComponent){
fiore@0: component = centralComponent;
fiore@0: /* pressing enter on the central component results in a switch to the next panel */
fiore@0: component.addKeyListener(new KeyAdapter(){
fiore@0: @Override
fiore@0: public void keyPressed(KeyEvent evt){
fiore@0: pressed = true;
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void keyTyped(KeyEvent evt){
fiore@0: /* switch on the next panel only if the press button started on the same window *
fiore@0: * this is to avoid keyTyped to be called after the panel switch and therefore refer *
fiore@0: * to a component different that the one the user pressed OK on */
fiore@0: if(evt.getKeyChar() == '\n' && pressed)
fiore@0: getWizardComponents().getNextButton().doClick();
fiore@0: pressed = false;
fiore@0: }
fiore@0: boolean pressed = false;
fiore@0: });
fiore@0:
fiore@0: GridBagConstraints constr = new GridBagConstraints();
fiore@0: constr.gridx = 0;
fiore@0: constr.gridy = 0;
fiore@0: constr.gridwidth = 1;
fiore@0: constr.gridheight = 1;
fiore@0: constr.weightx = 1.0;
fiore@0: constr.weighty = 0.0;
fiore@0: constr.anchor = GridBagConstraints.PAGE_START;
fiore@0: constr.fill = GridBagConstraints.BOTH;
fiore@0: constr.insets = new Insets(5, 5, 5, 5);
fiore@0: constr.ipadx = 0;
fiore@0: constr.ipady = 0;
fiore@0:
fiore@0: /* Label */
fiore@0: setLayout(new GridBagLayout());
fiore@0: JPanel labelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
fiore@0: label.setHorizontalAlignment(SwingConstants.LEADING);
fiore@0: labelPanel.add(label);
fiore@0: add(labelPanel,constr);
fiore@0:
fiore@0: /* JSeparator */
fiore@0: constr.gridy = 1;
fiore@0: constr.anchor = GridBagConstraints.WEST;
fiore@0: constr.fill = GridBagConstraints.BOTH;
fiore@0: constr.insets = new Insets(1, 1, 1, 1);
fiore@0: add(new JSeparator(), constr);
fiore@0:
fiore@0: /* central component */
fiore@0: Container centralComponentContainer;
fiore@0: if(centralComponent instanceof JScrollPane ){
fiore@0: centralComponentContainer = centralComponent;
fiore@0: }else{
fiore@0: centralComponentContainer = new JPanel(new GridBagLayout());
fiore@0: centralComponentContainer.add(centralComponent
fiore@0: , new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
fiore@0: , GridBagConstraints.CENTER, GridBagConstraints.BOTH
fiore@0: , new Insets(0, 0, 0, 0), 0, 0));
fiore@0: }
fiore@0: constr.gridy = 2;
fiore@0: constr.weighty = 1.0;
fiore@0: constr.anchor = GridBagConstraints.CENTER;
fiore@0: constr.insets = new Insets(0, 0, 0, 0);
fiore@0: add(centralComponentContainer,constr);
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void next(){
fiore@0: switchPanel(next);
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void back(){
fiore@0: switchPanel(previous);
fiore@0: }
fiore@0:
fiore@0: private JLabel label;
fiore@0: private int next;
fiore@0: private int previous;
fiore@0: private JComponent component;
fiore@0: public static int OWN_SWITCH = -1;
fiore@0: public static int DISABLE_SWITCH = -2;
fiore@0: }
fiore@0:
fiore@0: @SuppressWarnings("serial")
fiore@0: class SelectWizardPanel extends SpeechWizardPanel {
fiore@0: SelectWizardPanel(JWizardComponents wizardComponents, String title, Collection options, int next, int previous, Model.Record record){
fiore@0: super(wizardComponents,title,next,previous);
fiore@0: String[] optionsArray = new String[options.size()];
fiore@0: comboBox = new LoopComboBox(new DefaultComboBoxModel(options.toArray(optionsArray)));
fiore@0: comboBox.addItemListener(SpeechUtilities.getSpeechComboBoxItemListener());
fiore@0: layoutComponents(comboBox);
fiore@0: this.record = record;
fiore@0: }
fiore@0:
fiore@0: SelectWizardPanel(JWizardComponents wizardComponents, String title, Collection options, int[] nexts, int previous, Model.Record record){
fiore@0: this(wizardComponents, title, options, OWN_SWITCH, previous, record);
fiore@0: this.nexts = nexts;
fiore@0: }
fiore@0:
fiore@0: SelectWizardPanel(JWizardComponents wizardComponents, String title, Collection options, int[] nexts, int previous){
fiore@0: this(wizardComponents, title, options, nexts, previous,null);
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void next(){
fiore@0: if(record != null)
fiore@0: record.value = (String)comboBox.getSelectedItem();
fiore@0: if(nexts != null)
fiore@0: switchPanel(nexts[comboBox.getSelectedIndex()]);
fiore@0: else
fiore@0: super.next();
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void update(){
fiore@0: if(record != null)
fiore@0: comboBox.setSelectedItem(record.value);
fiore@0: super.update();
fiore@0: }
fiore@0:
fiore@0: JComboBox comboBox;
fiore@0: int[] nexts;
fiore@0: Model.Record record;
fiore@0: }
fiore@0:
fiore@0: @SuppressWarnings("serial")
fiore@0: class TextWizardPanel extends SpeechWizardPanel {
fiore@0: TextWizardPanel(JWizardComponents wizardComponents, String title, Collection existingValues, int next, int previous, Model.Record record){
fiore@0: super(wizardComponents,title,next,previous);
fiore@0: textField = new JTextField();
fiore@0: textField.setColumns(10);
fiore@0: textField.addKeyListener(SpeechUtilities.getSpeechKeyListener(true));
fiore@0: layoutComponents(textField);
fiore@0: this.record = record;
fiore@0: this.existingValues = existingValues;
fiore@0: }
fiore@0:
fiore@0: public void next(){
fiore@0: String text = textField.getText().trim();
fiore@0: /* if the user enters a text he has already entered (that is, it's in the existingValues the don't go on */
fiore@0: /* and notify the user they have to chose another text. The only exception is when the record contains */
fiore@0: /* the same text the user entered as that means they are going through the editing of an existing element*/
fiore@0: if(text.isEmpty()||"\n".equals(text)){
fiore@0: NarratorFactory.getInstance().speak(ResourceBundle.getBundle(SpeechWizardDialog.class.getName()).getString("dialog.error.empty_text"));
fiore@0: return;
fiore@0: }
fiore@0: for(String value : existingValues){
fiore@0: if(value.equals(text) && !text.equals(record.value)){
fiore@0: NarratorFactory.getInstance().speak(MessageFormat.format(
fiore@0: ResourceBundle.getBundle(SpeechWizardDialog.class.getName()).getString("dialog.error.existing_value"),
fiore@0: text));
fiore@0: return;
fiore@0: }
fiore@0: }
fiore@0: if(record != null)
fiore@0: record.value = text;
fiore@0: super.next();
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void update(){
fiore@0: if(record != null)
fiore@0: textField.setText(record.value);
fiore@0: super.update();
fiore@0: }
fiore@0:
fiore@0: JTextField textField;
fiore@0: Collection existingValues;
fiore@0: Model.Record record;
fiore@0: }
fiore@0:
fiore@0: @SuppressWarnings("serial")
fiore@0: class SpinnerWizardPanel extends SpeechWizardPanel{
fiore@0: public SpinnerWizardPanel(JWizardComponents wizardComponents, String title, SpinnerModel spinnerModel, int next, int previous, Model.Record record){
fiore@0: super(wizardComponents,title,next,previous);
fiore@0: this.record = record;
fiore@0: spinner = new JSpinner(spinnerModel);
fiore@0: spinner.addChangeListener(new ChangeListener(){
fiore@0: @Override
fiore@0: public void stateChanged(ChangeEvent evt) {
fiore@0: JSpinner s = (JSpinner)(evt.getSource());
fiore@0: NarratorFactory.getInstance().speak(s.getValue().toString());
fiore@0: }
fiore@0: });
fiore@0: JFormattedTextField tf = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
fiore@0: tf.setEditable(false);
fiore@0: tf.setFocusable(false);
fiore@0: tf.setBackground(Color.white);
fiore@0: layoutComponents(spinner);
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void next(){
fiore@0: if(record != null)
fiore@0: record.value = spinner.getValue().toString();
fiore@0: super.next();
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public void update(){
fiore@0: if(record != null){
fiore@0: if(!record.value.isEmpty())
fiore@0: spinner.setValue(Integer.parseInt(record.value));
fiore@0: }
fiore@0: super.update();
fiore@0: }
fiore@0:
fiore@0: Model.Record record;
fiore@0: JSpinner spinner;
fiore@0: }
fiore@0:
fiore@0: @SuppressWarnings("serial")
fiore@0: class DummyWizardPanel extends JWizardPanel{
fiore@0: DummyWizardPanel(JWizardComponents wizardComponents){
fiore@0: super(wizardComponents);
fiore@0: }
fiore@0: }