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