upstream version 1.2.2
[debian/freetts] / demo / JSAPI / WebStartClock / Clock.java
1 /**
2  * Copyright 2003 Sun Microsystems, Inc.
3  *
4  * See the file "license.terms" for information on usage and
5  * redistribution of this file, and for a DISCLAIMER OF ALL
6  * WARRANTIES.
7  */
8 import java.awt.BorderLayout;
9 import java.awt.FlowLayout;
10 import java.awt.Font;
11
12 import java.awt.event.ActionEvent;
13 import java.awt.event.ActionListener;
14 import java.awt.event.ItemEvent;
15 import java.awt.event.ItemListener;
16
17 import java.text.SimpleDateFormat;
18
19 import java.util.Calendar;
20 import java.util.Date;
21 import java.util.GregorianCalendar;
22
23 import javax.swing.JButton;
24 import javax.swing.JCheckBox;
25 import javax.swing.JFrame;
26 import javax.swing.JLabel;
27 import javax.swing.JPanel;
28 import javax.swing.JTextField;
29 import javax.swing.SwingUtilities;
30
31
32 /**
33  * A talking clock powered by FreeTTS.
34  */
35 public abstract class Clock extends JFrame {
36
37     private JLabel timeLabel;
38     private JCheckBox announceCheckBox;
39     private JTextField intervalTextField;
40     private int timeFontSize = 24;
41
42     private GregorianCalendar calendar;
43     private SimpleDateFormat dateFormat;
44
45     private long lastSpeakTime;            // in milliseconds
46     private int speakInterval = 300000;    // in milliseconds
47     private int sleepTime = 5000;          // in milliseconds
48
49     private static char announceMnemonic = 'A';
50     private static char minutesMnemonic = 'M';
51     private static char speakMnemonic = 'S';
52
53     private boolean debug = true;
54     
55
56     /**
57      * Constructs a default WebStartClock.
58      */
59     public Clock() {
60         super("FreeTTS Clock");
61         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
62         
63         JPanel timePanel = new JPanel(new BorderLayout());
64         timePanel.setAlignmentY(JPanel.CENTER_ALIGNMENT);
65
66         timeLabel = new JLabel("Loading...", JLabel.CENTER);
67         Font oldFont = timeLabel.getFont();
68         timeLabel.setFont(new Font(oldFont.getFontName(), oldFont.getStyle(),
69                                    timeFontSize));
70
71         timePanel.add(timeLabel, BorderLayout.CENTER);
72         timePanel.add(createAnnouncePanel(), BorderLayout.SOUTH);
73         
74         getContentPane().add(timePanel, BorderLayout.CENTER);
75
76         JButton speakButton = new JButton("Speak");
77         speakButton.setMnemonic(speakMnemonic);
78
79         speakButton.addActionListener(new ActionListener() {
80             public void actionPerformed(ActionEvent ae) {
81                 Runnable speaker = new Runnable() {
82                     public void run() {
83                         speakTime();
84                     }
85                 };
86                 (new Thread(speaker)).start();
87             }
88         });
89
90         getContentPane().add(speakButton, BorderLayout.SOUTH);
91         
92         createCalendar();
93     }
94
95
96     /**
97      * Start running the clock.
98      */
99     public void startClock() {
100         ClockThread clock = new ClockThread();
101         clock.start();
102     }
103
104
105     /**
106      * Creates the JPanel that allows you to specify the time announcing
107      * interval.
108      *
109      * @return a JPanel
110      */ 
111     private JPanel createAnnouncePanel() {
112         JPanel announcePanel = new JPanel(new FlowLayout());
113         announceCheckBox = new JCheckBox("announce every", true);
114         announceCheckBox.setMnemonic(announceMnemonic);
115         announceCheckBox.addItemListener(new ItemListener() {
116             public void itemStateChanged(ItemEvent ie) {
117                 if (ie.getStateChange() == ItemEvent.SELECTED) {
118                     lastSpeakTime = calendar.getTimeInMillis();
119                     debugPrintln
120                         ("Last speak time: "  + String.valueOf(lastSpeakTime));
121                 }
122             }
123         });
124
125         // a text field to enter the time announcing interval
126         intervalTextField = new JTextField("5", 3);
127         intervalTextField.addActionListener(new ActionListener() {
128             public void actionPerformed(ActionEvent e) {
129                 String text = intervalTextField.getText();
130                 if (text.matches("[1-9][0-9]*")) {
131                     debugPrintln("New announce interval : " + text);
132                     speakInterval = Integer.parseInt(text) * 60000;
133                 } else {
134                     debugPrintln("Invalid minutes input: " + text);
135                     intervalTextField.setText
136                         (String.valueOf(speakInterval / 60000));
137                 }
138             }
139         });
140
141         JLabel minutesLabel = new JLabel("mins");
142         minutesLabel.setDisplayedMnemonic(minutesMnemonic);
143         minutesLabel.setLabelFor(intervalTextField);
144
145         announcePanel.add(announceCheckBox);
146         announcePanel.add(intervalTextField);
147         announcePanel.add(minutesLabel);
148         return announcePanel;
149     }
150
151
152     /**
153      * Creates the synthesizer, called by the constructor.
154      * Implement this method to create the appropriate synthesizer.
155      * The created synthesizer will be used by the <code>speak()</code>
156      * method, also to be implemented in the subclass.
157      */
158     public abstract void createSynthesizer();
159
160
161     /**
162      * Asks the synthesizer to speak the time given in full text.
163      * Implement this method to call the appropriate method of the
164      * created synthesizer to speak the given time.
165      *
166      * @param time the time given in full text
167      */
168     protected abstract void speak(String time);
169
170
171     /**
172      * Create the GregorianCalendar that keeps track of the time.
173      */
174     private void createCalendar() {
175         calendar = new GregorianCalendar();
176
177         // sets the format to display the current time
178         // the format is "3:50 PM"
179         dateFormat = new SimpleDateFormat("h:mm a");
180         dateFormat.setCalendar(calendar);
181     }
182
183
184     /**
185      * Sets the time label.
186      *
187      * @time time the time to set
188      */
189     private void setTimeLabel(final String time) {
190         SwingUtilities.invokeLater(new Runnable() {
191             public void run() {
192                 timeLabel.setText(time);
193             }
194         });
195     };
196
197
198     /**
199      * Updates the calendar and the display with the current time.
200      */
201     private void updateTime() {
202         Date currentTime = new Date();
203         calendar.setTime(currentTime);
204         setTimeLabel(dateFormat.format(currentTime));
205     }
206
207
208     /**
209      * Speaks the current time.
210      */
211     private void speakTime() {
212         lastSpeakTime = calendar.getTimeInMillis();
213         int hour = calendar.get(Calendar.HOUR_OF_DAY);
214         int min = calendar.get(Calendar.MINUTE);        
215
216         if (hour < 0 || hour > 23) {
217             throw new IllegalArgumentException("Bad time format: hour");
218         }
219         if (min < 0 || min > 59) {
220             throw new IllegalArgumentException("Bad time format: min");
221         }
222         
223         String theTime = TimeUtils.timeToString(hour, min);
224         speak(theTime);
225     }
226
227
228     /**
229      * Return true if we enough time has elapsed since the last announce
230      * time.
231      *
232      * @return true its time to speak, false otherwise
233      */
234     private boolean isTimeToSpeak() {
235         return ((lastSpeakTime + speakInterval) < calendar.getTimeInMillis());
236     }
237
238
239     /**
240      * Print method for debug purposes.
241      *
242      * @param the debug message to print
243      */
244     private void debugPrintln(String line) {
245         if (debug) {
246             System.out.println(line);
247         }
248     }
249
250
251     /**
252      * A thread for the clock.
253      */
254     class ClockThread extends Thread {
255
256         public void run() {
257             while (true) {
258                 updateTime();
259                 if (announceCheckBox.isSelected() && isTimeToSpeak()) {
260                     speakTime();
261                 }
262
263                 try {
264                     Thread.sleep(sleepTime);
265                 } catch (InterruptedException ie) {
266                     ie.printStackTrace();
267                 }
268             }
269         }
270
271     }
272 }