// Make it easy to access classes and methods of selected packages. import java.awt.*; import java.awt.event.*; import java.applet.*; import java.util.*; import java.text.*; /** * This class subclasses Applet to define an applet for determining the day of * the week and number of days from today for a target date entered by the user. * It implements the ActionListener and TextListener interfaces to respond to * events. * * Written by: Jon Huhtala */ public class App extends Applet implements ActionListener, TextListener { // Instance variables for referencing a panel and thread to display the // current date and time (to be updated every second). private TimePanel time; private Thread timeThread; // Instance variables for referencing the input area (in which the user may // enter the target date) and the output area (in which the information will // be displayed). private TextField targetDateField; private TextArea result; // Instance variable for a date formatter to be used in parsing the value // entered by the user in the target date field. The formatter will use the // short date format of the United States: MM/DD/YY private DateFormat localDate = DateFormat.getDateInstance(DateFormat.SHORT,Locale.US); // Instance variable for referencing the target date. private MyCalendar targetDate; // Instance variable for a string that contains a message to assist the user. private final String helpMessage = "Enter the target date in" + "\n" + "MM/DD/YY format"; // This method defines initial (one-time) applet processing. public void init() { // Set the background color for the applet. setBackground(Color.lightGray); // Instantiate a panel and thread to display the current system date and // time, start its processing, and add it to the applet window. TimePanel time = new TimePanel(); timeThread = new Thread(time); timeThread.start(); add(time); // Construct a label and text field in which the user may enter the target // date, add them to the applet window, and register listeners to be // notified of user actions. add(new Label("Target date")); targetDateField = new TextField(8); add(targetDateField); targetDateField.addActionListener(this); targetDateField.addTextListener(this); // Do NOT allow the date formatter to be lenient in its parsing. This will // prevent a date like "6/35/02" from being accepted as 7/5/02. localDate.setLenient(false); // Create a non-scrollable text area in which to display output information, // make it non-editable, and add it to the applet window. The area will // initially contain a message to assist the user. result = new TextArea(helpMessage,2,18,TextArea.SCROLLBARS_NONE); result.setEditable(false); add(result); } // This method implements the abstract event handler method of the // ActionListener interface to handle ActionEvents. public void actionPerformed(ActionEvent e) { // If the user pressed the "ENTER" key in the target date text field, // process the event. if (e.getSource().equals(targetDateField)) { // Construct a target date object and set its date/time to the value // entered by the user. This requires parsing the string in accordance // with the date formatter. A try-catch is needed in case parsing fails. // If all is successful, the calculate() method is called to calculate // and display output information. targetDate = new MyCalendar(); try { targetDate.setTime(localDate.parse(targetDateField.getText().trim())); calculate(); } catch (ParseException err) {} } } // This method implements the abstract event handler method of the // TextListener interface to handle TextEvents. public void textValueChanged(TextEvent e) { // If the user has made a change to the target date field, re-display the // message to assist them in entering a valid date. if (e.getSource().equals(targetDateField)) { result.setText(helpMessage); } } // This method calculates and displays the target date's day of the week and // its number of days from today. private void calculate() { // Construct a local object for the current date/time. MyCalendar today = new MyCalendar(); // If the target date is 0 days from today, display information about today. if (targetDate.daysFrom(today) == 0) { result.setText("Is a " + targetDate.dayOfWeek() + ",\n" + "today..."); } // Otherwise, the target is either before or after today. else { // If the target date is before today, display its day of the week and // the number of days ago. if (targetDate.before(today)) { result.setText("Was a " + targetDate.dayOfWeek() + ",\n" + new Integer(targetDate.daysFrom(today)).toString() + " day(s) ago..." ); } // Otherwise, the target date is after today. Display its day of the week // and the number of days from now. else { result.setText("Will be a " + targetDate.dayOfWeek() + ",\n" + new Integer(targetDate.daysFrom(today)).toString() + " day(s) from now..." ); } } } } // This class extends GregorianCalendar to provide additional features. class MyCalendar extends GregorianCalendar { // This constructor simply calls the superclass constructor to initialize // the object to the current system date and time. public MyCalendar() { super(); } // This method can be called to retrieve the time in milliseconds. It // provides an indirect way for an application to call the protected // getTimeInMillis() method of the superclass. public long toMillis() { return getTimeInMillis(); } // This method can be called to get the day of the week, in English, as a // string. public String dayOfWeek() { // Local array for the days of the week. String[] days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; // Return the appropriate string value. Note that "Sunday" has a day // value of 1. return days[this.get(Calendar.DAY_OF_WEEK)-1]; } // This method can be called to obtain a positive integer representing the // number of days between "this" date/time object and some other date/time // object. public int daysFrom(MyCalendar other) { // Determine the number of days between the two objects based on the // difference in their millisecond equivalents. int days = (int) Math.abs((other.toMillis() - toMillis())/(24*60*60*1000)); // If the "other" date/time object comes before "this" date/time object, // add one day to compensate for a partial day. if (other.before(this)) { days++; } // Return the value to the caller. return days; } } // This class subclasses Panel and implements the Runnable interface to display // the current date and time every second. class TimePanel extends Panel implements Runnable { // Instance variable for knowing the current thread state. private boolean alive; // Instance variable for referencing a label to display the current date and // time. private Label time; // Instance variables for referencing the current date/time object. private MyCalendar now; // Instance variable for referencing the formatter to be used in converting // the current date/time object to a displayable form. private DateFormat dtFormat; // This method constructs the panel object to display the current date and // time. public TimePanel() { // Set the thread state to indicate that the thread is alive. alive = true; // Create the date/time formatter. It will use the LONG date format, and the // MEDIUM time format of the United States. dtFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.US); // Set the time zone to that of the local machine. dtFormat.setTimeZone(TimeZone.getDefault()); // Construct a label with the formatted value of the current date and time, // set its color and font, center its text, and add it to the panel. time = new Label(dtFormat.format(new GregorianCalendar().getTime())); time.setBackground(Color.black); time.setForeground(Color.yellow); time.setFont(new Font("San Serif", Font.PLAIN, 14)); time.setAlignment(Label.CENTER); add(time); } // This method implements the abstract run() method of the Runnable interface. // It defines thread processing. public void run() { // Loop as long as the thread state indicates the thread is alive. while (alive == true) { // Sleep for one second. The try-catch is needed because the sleep() // method may throw an InterruptedException. try { Thread.sleep(1000); } catch (InterruptedException err) {} // Update the label to display the formatted value of the current date // and time. time.setText(dtFormat.format(new GregorianCalendar().getTime())); } // This return will only be executed if the thread state indicates the // thread is no longer alive. return; } // Calling this method will set the thread state to indicate the thread is // no longer alive. public void killThread() { alive = false; } }