2 * Copyright 2001 Sun Microsystems, Inc.
4 * See the file "license.terms" for information on usage and
5 * redistribution of this file, and for a DISCLAIMER OF ALL
9 import java.awt.Component;
10 import java.awt.Container;
11 import java.awt.Cursor;
12 import java.awt.BorderLayout;
13 import java.awt.Dimension;
14 import java.awt.FlowLayout;
15 import java.awt.GridLayout;
16 import java.awt.GridBagLayout;
17 import java.awt.GridBagConstraints;
18 import java.awt.Insets;
19 import java.awt.event.ActionListener;
20 import java.awt.event.ActionEvent;
21 import java.awt.event.WindowAdapter;
22 import java.awt.event.WindowEvent;
24 import javax.swing.BorderFactory;
25 import javax.swing.ComboBoxModel;
26 import javax.swing.ListModel;
27 import javax.swing.ListSelectionModel;
28 import javax.swing.JButton;
29 import javax.swing.JComboBox;
30 import javax.swing.JComponent;
31 import javax.swing.JFrame;
32 import javax.swing.JLabel;
33 import javax.swing.JList;
34 import javax.swing.JPanel;
35 import javax.swing.JTextArea;
36 import javax.swing.JToggleButton;
37 import javax.swing.JScrollPane;
38 import javax.swing.JSlider;
39 import javax.swing.SwingUtilities;
40 import javax.swing.UIManager;
41 import javax.swing.UnsupportedLookAndFeelException;
43 import javax.swing.border.Border;
44 import javax.swing.border.EtchedBorder;
45 import javax.swing.border.TitledBorder;
47 import javax.swing.event.ChangeListener;
48 import javax.swing.event.ChangeEvent;
50 import javax.swing.plaf.basic.BasicArrowButton;
51 import javax.swing.plaf.metal.MetalLookAndFeel;
54 * Defines and contains all the user-interface Swing objects of the Player.
55 * In terms of the model-view-controller (MVC) architecture, this implements
56 * the "view" and "control" elements. Its interacts with the PlayerModel
57 * class, the "model" element.
59 public class PlayerPanel extends JPanel {
61 private PlayerModel playerModel;
63 private int width = 600;
64 private int height = 450;
65 private int border = 30;
67 private Color backgroundColor = Color.LIGHT_GRAY;
68 private Color foregroundColor = Color.BLACK;
69 private Color controlColor = new Color(250, 250, 250);
71 private JComboBox synthesizerComboBox;
72 private JComboBox waveSynthesisComboBox;
73 private JComboBox voiceComboBox;
75 private JTextArea speakingTextArea;
76 private JList speakablesList;
77 private int speakablesListVisibleRows = 5;
79 private JToggleButton pauseButton;
80 private JButton playButton;
81 private JButton cancelButton;
82 private JButton stopButton;
83 private JButton deleteButton;
85 private int initialVolume = 10;
86 private JSlider volumeSlider;
87 private JSlider speedSlider;
88 private JSlider pitchSlider;
89 private JSlider rangeSlider;
91 private JButton fileButton;
92 private JTextArea textArea;
93 private int textAreaRows = 2;
94 private int textAreaColumns = 20;
95 private JButton clearTextButton;
96 private JButton speakTextButton;
97 private JButton speakJSMLButton;
99 private static char cancelMnemonic = 'A';
100 private static char clearMnemonic = 'C';
101 private static char deleteMnemonic = 'D';
102 private static char pauseMnemonic = 'U';
103 private static char pitchMnemonic = 'H';
104 private static char playMnemonic = 'P';
105 private static char playListMnemonic = 'L';
106 private static char rangeMnemonic = 'R';
107 private static char resumeMnemonic = 'E';
108 private static char stopMnemonic = 'T';
109 private static char speakMnemonic = 'S';
110 private static char speakJSMLMnemonic = 'J';
111 private static char synthesizerMnemonic = 'Y';
112 private static char textMnemonic = 'X';
113 private static char voiceMnemonic = 'O';
114 private static char volumeMnemonic = 'V';
115 private static char wordsPerMinMnemonic = 'W';
119 * Constructs a PlayerPanel that interacts with the given PlayerModel.
121 * @param playerModel the PlayerModel that this PlayerPanel interacts
124 public PlayerPanel(PlayerModel playerModel) {
126 this.playerModel = playerModel;
128 setSize(width, height);
129 setAlignmentY((float) 0.5);
130 setAlignmentX((float) 0.5);
132 setLayout(new BorderLayout());
133 add(createMainPanel(), BorderLayout.NORTH);
134 add(createTextPanel(), BorderLayout.CENTER);
139 * Creates the main JPanel that is the upper JPanel of the
140 * user interface. It contains:
142 * <li> (on the left) volume and speaking rate control slides
143 * <li> (center) the synthesizer/voice selection combo boxes,
144 * the play list, and the buttons
145 * <li> (on the right) pitch and range control slides
148 * @return the upper JPanel of the application with all the controls
151 private JPanel createMainPanel() {
152 JPanel centerPanel = new JPanel();
154 centerPanel.setLayout(new BorderLayout());
155 centerPanel.add(createLeftSliderPanel(), BorderLayout.WEST);
156 centerPanel.add(createSpeakablesPanel(), BorderLayout.CENTER);
157 centerPanel.add(createRightSliderPanel(), BorderLayout.EAST);
164 * Creates the TitledBordered JPanel and the play list it contains.
165 * This Panel is at the center of the Main Panel. The play list is
166 * contained within a JScrollPane.
168 * @return a JPanel that containts the play list
170 private JPanel createSpeakablesPanel() {
172 ListModel playList = playerModel.getPlayList();
173 speakablesList = new JList(playList);
174 speakablesList.setVisibleRowCount(speakablesListVisibleRows);
175 speakablesList.setSelectionMode
176 (ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
177 speakablesList.setSelectedIndex(0);
178 speakablesList.setDragEnabled(true);
180 JLabel listTitle = new JLabel("Play List");
181 listTitle.setDisplayedMnemonic(playListMnemonic);
182 listTitle.setLabelFor(speakablesList);
184 JScrollPane scrollPane = new JScrollPane(speakablesList);
185 scrollPane.add(listTitle);
187 JPanel centerPanel = new JPanel(new BorderLayout());
188 centerPanel.add(listTitle, BorderLayout.NORTH);
189 centerPanel.add(scrollPane, BorderLayout.CENTER);
190 centerPanel.add(createControlsPanel(), BorderLayout.SOUTH);
192 TitledBorder titledBorder = new TitledBorder("");
193 titledBorder.setTitleColor(foregroundColor);
194 titledBorder.setTitleJustification(TitledBorder.CENTER);
195 titledBorder.setBorder(new EtchedBorder(Color.WHITE, Color.BLACK));
196 centerPanel.setBorder(titledBorder);
198 JPanel speakablesPanel = new JPanel(new BorderLayout());
199 speakablesPanel.add(createSettingsPanel(), BorderLayout.NORTH);
200 speakablesPanel.add(centerPanel, BorderLayout.CENTER);
202 return speakablesPanel;
207 * Creates the settings JPanel and the synthesizer and voice
208 * JComboBoxes it contains. This JPanel is inside the speakables Panel.
210 * @return the JPanel of synthesizer and voice JComboBoxes
212 private JPanel createSettingsPanel() {
213 synthesizerComboBox = createComboBox
214 ((ComboBoxModel) playerModel.getSynthesizerList(),
215 "Synthesizer", "FreeTTS Synthesizer");
217 voiceComboBox = createComboBox
218 ((ComboBoxModel) playerModel.getVoiceList(),
221 JLabel synthesizerLabel = new JLabel("Synthesizer:");
222 synthesizerLabel.setDisplayedMnemonic(synthesizerMnemonic);
223 synthesizerLabel.setLabelFor(synthesizerComboBox);
225 JLabel voiceLabel = new JLabel("Voice:");
226 voiceLabel.setDisplayedMnemonic(voiceMnemonic);
227 voiceLabel.setLabelFor(voiceComboBox);
229 JPanel leftPanel = new JPanel(new BorderLayout());
230 leftPanel.add(synthesizerLabel, BorderLayout.NORTH);
231 leftPanel.add(synthesizerComboBox, BorderLayout.CENTER);
233 JPanel rightPanel = new JPanel(new BorderLayout());
234 rightPanel.add(voiceLabel, BorderLayout.NORTH);
235 rightPanel.add(voiceComboBox, BorderLayout.CENTER);
237 JPanel settingsPanel = new JPanel();
239 FlowLayout flowLayout = new FlowLayout();
240 flowLayout.setAlignment(FlowLayout.CENTER);
241 settingsPanel.setLayout(flowLayout);
242 settingsPanel.add(leftPanel);
243 settingsPanel.add(rightPanel);
245 addComboBoxListeners();
247 return settingsPanel;
252 * Creates a non-editable ComboBox with the given attributes.
254 * @param model the ComboBoxModel this ComboBox is based on
255 * @param toolTipText the tooltip text
256 * @param prototypeDisplayValue the String used to calculate the
257 * width of the ComboBox
259 public JComboBox createComboBox(ComboBoxModel model, String toolTipText,
260 String prototypeDisplayValue) {
261 JComboBox comboBox = new JComboBox(model);
262 comboBox.setToolTipText(toolTipText);
263 comboBox.setPrototypeDisplayValue(prototypeDisplayValue);
264 comboBox.setEditable(false);
270 * Adds listeners for the synthesizer and voices JComboBoxes
272 private void addComboBoxListeners() {
273 synthesizerComboBox.addActionListener(new ActionListener()
275 public void actionPerformed(ActionEvent e) {
276 int selectedIndex = synthesizerComboBox.getSelectedIndex();
277 Monitor monitor = playerModel.getMonitor();
278 if (monitor != playerModel.getMonitor(selectedIndex)) {
279 if (monitor != null) {
280 monitor.setVisible(false);
282 if (playerModel.isMonitorVisible()) {
283 monitor = playerModel.getMonitor(selectedIndex);
284 monitor.setVisible(true);
285 add(monitor, BorderLayout.SOUTH);
287 playerModel.setSynthesizer(selectedIndex);
291 voiceComboBox.addActionListener(new ActionListener() {
292 public void actionPerformed(ActionEvent e) {
293 Cursor oldCursor = getCursor();
294 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
295 playerModel.setVoice(voiceComboBox.getSelectedIndex());
296 setCursor(oldCursor);
304 * Creates the JPanel and the buttons it contains.
306 * @return a JPanel that contains the buttons.
308 private JPanel createControlsPanel() {
310 // create the buttons
311 playButton = createJButton("Play", playMnemonic);
312 cancelButton = createJButton("Cancel", cancelMnemonic);
313 stopButton = createJButton("Stop", stopMnemonic);
315 pauseButton = new JToggleButton("Pause");
316 pauseButton.setToolTipText("Pause");
317 pauseButton.setMnemonic(pauseMnemonic);
318 setControlColors(pauseButton);
320 JPanel buttonsPanel = new JPanel();
321 buttonsPanel.add(pauseButton);
322 buttonsPanel.add(playButton);
323 buttonsPanel.add(cancelButton);
324 buttonsPanel.add(stopButton);
326 JPanel controlsPanel = new JPanel(new BorderLayout());
327 controlsPanel.add(buttonsPanel, BorderLayout.CENTER);
329 addControlsPanelActionListeners();
331 return controlsPanel;
336 * Creates a JButton with the given label, which is also the tooltip
337 * text, and the given mnemonic.
339 * @param label the button label, which is also the tooltip text
340 * @param mnemonic mnemonic for the button
344 private JButton createJButton(String label, int mnemonic) {
345 JButton button = new JButton(label);
346 button.setToolTipText(label);
347 button.setMnemonic(mnemonic);
348 setControlColors(button);
355 * Creates the JPanel where the volume and speaking rate JSliders are.
357 private JPanel createLeftSliderPanel() {
358 // create the sliders
359 playerModel.setVolume(initialVolume);
361 volumeSlider = new JSlider(JSlider.VERTICAL, 0, 10, initialVolume);
362 int speakingRate = (int) playerModel.getSpeakingRate();
363 if (speakingRate == -1) {
366 speedSlider = new JSlider(JSlider.VERTICAL, 0, 400, 0);
368 JPanel volumePanel = createSliderPanel
369 (volumeSlider, "Volume Control", 1, 5,
370 "Volume", volumeMnemonic);
371 JPanel speedPanel = createSliderPanel
372 (speedSlider, "Speed Control", 50, 100,
373 "Words/min", wordsPerMinMnemonic);
375 JPanel sliderPanel = new JPanel(new FlowLayout());
376 sliderPanel.add(volumePanel);
377 sliderPanel.add(speedPanel);
378 addLeftSliderPanelListeners();
385 * Creates the JPanel where the pitch and range JSliders are.
387 private JPanel createRightSliderPanel() {
388 // create the sliders
389 pitchSlider = new JSlider(JSlider.VERTICAL, 50, 200, 50);
390 rangeSlider = new JSlider(JSlider.VERTICAL, 0, 50, 0);
392 JPanel pitchPanel = createSliderPanel
393 (pitchSlider, "Pitch Control", 25, 50, "Pitch/Hz", pitchMnemonic);
394 JPanel rangePanel = createSliderPanel
395 (rangeSlider, "Range Control", 5, 10, "Range", rangeMnemonic);
397 JPanel sliderPanel = new JPanel();
398 sliderPanel.setLayout(new FlowLayout());
399 sliderPanel.add(pitchPanel);
400 sliderPanel.add(rangePanel);
402 addRightSliderPanelListeners();
409 * Adds ActionListeners for the JSliders.
411 private void addLeftSliderPanelListeners() {
412 volumeSlider.addChangeListener(new ChangeListener() {
413 public void stateChanged(ChangeEvent ce) {
414 if (playerModel.setVolume
415 ((float) volumeSlider.getValue()) == false) {
416 volumeSlider.setValue((int) playerModel.getVolume());
420 speedSlider.addChangeListener(new ChangeListener() {
421 public void stateChanged(ChangeEvent ce) {
422 if (playerModel.setSpeakingRate
423 ((float) speedSlider.getValue()) == false) {
424 speedSlider.setValue((int) playerModel.getSpeakingRate());
432 * Adds ActionListeners for the JSliders.
434 private void addRightSliderPanelListeners() {
435 pitchSlider.addChangeListener(new ChangeListener() {
436 public void stateChanged(ChangeEvent e) {
437 if (playerModel.setPitch
438 ((float) pitchSlider.getValue()) == false) {
439 pitchSlider.setValue((int) playerModel.getPitch());
443 rangeSlider.addChangeListener(new ChangeListener() {
444 public void stateChanged(ChangeEvent e) {
445 if (playerModel.setRange
446 ((float) rangeSlider.getValue()) == false) {
447 rangeSlider.setValue((int) playerModel.getRange());
455 * Updates all the Sliders with values from the PlayerModel.
457 private void updateSliders() {
458 int volume = (int) playerModel.getVolume();
460 volumeSlider.setValue(volume);
462 int rate = (int) playerModel.getSpeakingRate();
464 speedSlider.setValue(rate);
466 int pitch = (int) playerModel.getPitch();
468 pitchSlider.setValue(pitch);
470 int range = (int) playerModel.getRange();
472 rangeSlider.setValue(range);
478 * Creates a JPanel that contains the given JSlider, with the
481 * @param slider the JSlider
482 * @param toolTipText the text for the tooltip
483 * @param minorTickSpacing the spacing between minor ticks
484 * @param majorTickSpacing the spacing between major ticks
485 * @param title the title of the JSlider
487 private JPanel createSliderPanel(JSlider slider, String toolTipText,
488 int minorTickSpacing,
489 int majorTickSpacing,
490 String title, char mnemonic) {
491 JPanel sliderPanel = new JPanel(new BorderLayout());
493 slider.setSize(getSize().width/2 - border,
494 slider.getSize().height);
496 slider.putClientProperty("JSlider.isFilled", Boolean.TRUE);
497 slider.setMinorTickSpacing(minorTickSpacing);
498 slider.setMajorTickSpacing(majorTickSpacing);
499 slider.setPaintTicks(true);
500 slider.setPaintLabels(true);
501 slider.setToolTipText(toolTipText);
503 JLabel leftLabel = new JLabel(title);
504 leftLabel.setForeground(foregroundColor);
505 leftLabel.setDisplayedMnemonic(mnemonic);
506 leftLabel.setLabelFor(slider);
508 sliderPanel.add(leftLabel, BorderLayout.NORTH);
509 sliderPanel.add(slider, BorderLayout.CENTER);
516 * Adds ActionListeners to all the buttons
518 private void addControlsPanelActionListeners() {
519 playButton.addActionListener(new ActionListener() {
520 public void actionPerformed(ActionEvent e) {
521 int[] selectedIndices =
522 speakablesList.getSelectedIndices();
523 for (int i = 0; i < selectedIndices.length; i++) {
524 if (selectedIndices[i] != -1) {
525 playerModel.play(selectedIndices[i]);
530 pauseButton.addActionListener(new ActionListener() {
531 public void actionPerformed(ActionEvent e) {
532 if (playerModel.isPaused()) {
533 playerModel.resume();
539 cancelButton.addActionListener(new ActionListener() {
540 public void actionPerformed(ActionEvent e) {
541 playerModel.cancel();
544 stopButton.addActionListener(new ActionListener() {
545 public void actionPerformed(ActionEvent e) {
547 pauseButton.setEnabled(true);
554 * Creates the text JPanel is where the user enters text to be read.
556 * @return the JPanel with the textArea for text input
558 private JPanel createTextPanel() {
559 textArea = new JTextArea();
560 textArea.requestFocusInWindow();
561 textArea.setLineWrap(true);
562 textArea.setWrapStyleWord(true);
564 JScrollPane textScrollPane = new JScrollPane(textArea);
566 speakTextButton = createJButton("Speak Text", speakMnemonic);
567 speakJSMLButton = createJButton("Speak JSML", speakJSMLMnemonic);
568 clearTextButton = createJButton("Clear", clearMnemonic);
570 BorderLayout borderLayout = new BorderLayout();
571 JPanel textPanel = new JPanel(borderLayout);
572 textPanel.setSize(width - border * 2, textPanel.getSize().height);
574 JPanel buttonsPanel = new JPanel();
575 buttonsPanel.add(speakTextButton);
576 buttonsPanel.add(speakJSMLButton);
577 buttonsPanel.add(clearTextButton);
579 TitledBorder titledBorder = new TitledBorder("Enter text:");
580 JLabel titleLabel = new JLabel("Enter text:");
581 titleLabel.setDisplayedMnemonic(textMnemonic);
582 titleLabel.setLabelFor(textArea);
584 EtchedBorder border = new EtchedBorder(Color.WHITE, Color.BLACK);
585 textPanel.setBorder(border);
586 textPanel.add(titleLabel, BorderLayout.NORTH);
587 textPanel.add(textScrollPane, BorderLayout.CENTER);
588 textPanel.add(buttonsPanel, BorderLayout.SOUTH);
590 addTextPanelActionListeners();
597 * Adds ActionListeners to the buttons on the text panel.
599 private void addTextPanelActionListeners() {
600 clearTextButton.addActionListener(new ActionListener() {
601 public void actionPerformed(ActionEvent e) {
602 textArea.setText("");
605 speakTextButton.addActionListener(new ActionListener() {
606 public void actionPerformed(ActionEvent e) {
607 String inputText = textArea.getText();
608 if (inputText.length() > 0) {
609 Playable textPlayable =
610 Playable.createTextPlayable(inputText);
611 playerModel.addPlayable(textPlayable);
612 speakablesList.setSelectedValue(textPlayable, true);
613 playerModel.play(textPlayable);
617 speakJSMLButton.addActionListener(new ActionListener() {
618 public void actionPerformed(ActionEvent e) {
619 String inputText = textArea.getText();
620 if (inputText.length() > 0) {
621 Playable jsmlPlayable =
622 Playable.createJSMLPlayable(inputText);
623 playerModel.addPlayable(jsmlPlayable);
624 speakablesList.setSelectedValue(jsmlPlayable, true);
625 playerModel.play(jsmlPlayable);
633 * Sets the given control JComponent to the application defined color.
635 * @param component the JComponent to set color
637 private void setControlColors(JComponent component) {
638 component.setBackground(controlColor);
643 * Returns the Playables JList.
645 * @return the Playables JList
647 public JList getPlayList() {
648 return speakablesList;