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: }