World Clock

15 06 2014

World Clock

This project utilizes a Model View Controller and the system time to accomplish the task of creating a world clock.

  
WorldClock.java
 

public class WorldClock {
public static void main(String [] args) {
new WorldClock();
}

public WorldClock() {

ClockModel model = new ClockModel();
ClockController controller = new ClockController(model);
ClockView view = new ClockView();

/***************************************************************
* Sets a default clock which cannot be removed from the list. *
***************************************************************/
model.setCity("System Time");
model.setTimeZoneOffset(0.0);
view.add(model);
}
}

  
ClockModel.java
 

import javax.swing.JTextField;
import javax.swing.border.*;
import javax.swing.*;
import java.awt.*;

/************************************************************
* The following class inherits from the JTextField object. *
************************************************************/
public class ClockModel extends JTextField{
private String city;
private long timeInSeconds;
private Double timeZoneOffset = 0.0;
private Border lineBorder = BorderFactory.createLineBorder(Color.BLACK, 1);
public ClockModel() {
super(8);

Font font = new Font("Bradley Hand ITC", Font.BOLD, 24);
setFont(font);
setEditable(false);
setFocusable(false);
setVisible(true);
setHorizontalAlignment(JTextField.CENTER);
city = "No Input";

}
/****************************************************************
* The following set methods are called individually after *
* the creation of an instance. This method of input was chosen *
* so the clocks could be populated directly with information *
* from the JList opbject in the ClockView class. The *
* setTimeInSeconds() method is called in the ClockController *
* class. *
****************************************************************/
public void setCity(String city) {
this.city = city;
update();
}
/********************************************************************************
* The border is updated either when the city is updated or the timeZoneOffset. *
********************************************************************************/
public void update() {
setBorder(BorderFactory.createTitledBorder(lineBorder, city + " | " + timeZoneOffset + " GMT offset"));
}
/******************************************
* Called from the ClockController class. *
******************************************/
public void setTimeInSeconds(long timeInSeconds) {
this.timeInSeconds = timeInSeconds;
//setText(secondsAsTimeText());
}
/************************************
* Called from the ClockView class. *
************************************/
public void setTimeZoneOffset(Double timeZoneOffset) {
this.timeZoneOffset = timeZoneOffset;
update();
}
/***********************************************
* This method updates the text of the JLabel. *
***********************************************/
public void tick() {
setText(secondsAsTimeText());
}
/********************************************************
* This method formats the String for the time display *
* and also ensures the time stays within a 24 hour *
* period. *
********************************************************/
public String secondsAsTimeText () {
long hours, minutes, seconds;
timeInSeconds += (long)(timeZoneOffset*3600.0);

/**This if statement checks to see if the time is between 0 and 86400 seconds (24 hours)
and corrects otherwise to the correct time format.**/
if (this.timeInSeconds > 86400)
this.timeInSeconds %= 86400;
else if (this.timeInSeconds < 0)
this.timeInSeconds = 86400 + timeInSeconds;
minutes = timeInSeconds/60;
seconds = timeInSeconds%60;
hours = minutes/60;
minutes = minutes%60;

return String.format("%02d:%02d:%02d", hours, minutes, seconds);
}
}

  
ClockController.java
 

import java.util.GregorianCalendar;
import java.util.Calendar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class ClockController implements ActionListener {
private ClockModel model;
GregorianCalendar gCalendar= new GregorianCalendar();
private long timeInSeconds = ((gCalendar.get(Calendar.HOUR_OF_DAY))*3600 + gCalendar.get(Calendar.MINUTE)*60 + gCalendar.get(Calendar.SECOND));;
/**************************************************************
* This constructor utilizes GregorianCalendar & Calendar in *
* order to determine the system's current time of day. *
**************************************************************/
public ClockController(ClockModel model) {
this.model = model;
Timer timer = new Timer(1000, this);
timer.start();
}
/**********************************************************
* This method returns the system time and is used when *
* creating a new clock in order to pass the system time. *
**********************************************************/
public long getTimeInSeconds()
{
return timeInSeconds;
}
/*********************************************************************
* This method advances each clock and is powered by a Timer object. *
*********************************************************************/
public void actionPerformed(ActionEvent evt) {
this.model.setTimeInSeconds(timeInSeconds);
this.model.tick();
timeInSeconds++;
}
}

  
ClockView.java
 

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;
import javax.swing.event.*;
import java.awt.event.*;

public class ClockView implements ActionListener, ListSelectionListener{
private JPanel clockDisplay, cityListDisplay, mainDisplay;
private ClockController defaultController;
private JList listSource;
private String [] citiesAndTimeOffsets= loadCityTimeOffsets("CityTimeOffsets.txt");
private ArrayList testModelArrayList = new ArrayList();

public ClockView() {

JFrame clockFace = new JFrame("World Time");
clockFace.setSize(400, 400);
clockFace.setLocationRelativeTo(null);
clockFace.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Container contentPane = clockFace.getContentPane();

mainDisplay = new JPanel(new GridLayout(1, 2));
mainDisplay.setVisible(true);
clockDisplay = new JPanel(new GridLayout(0, 1));
cityListDisplay = new JPanel(new BorderLayout());
cityListDisplay.setPreferredSize(new Dimension(400, 200));

JList list = new JList(citiesAndTimeOffsets);
list.addListSelectionListener(this);
JScrollPane listScroll = new JScrollPane(list);

cityListDisplay.setVisible(true);

JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER));
JButton addCity = new JButton("+");
JButton subtractCity = new JButton("-");
buttons.add(addCity);
buttons.add(subtractCity);

addCity.addActionListener(this);
subtractCity.addActionListener(this);

cityListDisplay.add(buttons, BorderLayout.NORTH);
cityListDisplay.add(listScroll, BorderLayout.CENTER);

mainDisplay.add(cityListDisplay);
mainDisplay.add(clockDisplay);
contentPane.add(mainDisplay);

update();
clockFace.setVisible(true);
}
/******************************************************
* This method is taken directly from the example *
* code provided on the CSIS website. *
******************************************************/
public String[] loadCityTimeOffsets(String fileName) {
try {
FileReader aFileReader = new FileReader(fileName);
BufferedReader aBufferReader = new BufferedReader(aFileReader);

String cityName = "";
int separatorPos = 0;
double offset = 0.0;
ArrayList wordList = new ArrayList();

String lineFromFile = aBufferReader.readLine() ;
while (lineFromFile != null) {
// Add the word to the word list
separatorPos = lineFromFile.indexOf(",");
cityName = lineFromFile.substring(0,separatorPos);
offset = Double.parseDouble(lineFromFile.substring(separatorPos+1));
wordList.add(lineFromFile) ;
lineFromFile = aBufferReader.readLine() ;
}
aBufferReader.close();
aFileReader.close();
return wordList.toArray(new String[0]) ;
}
catch(IOException x) {
return null ;
}
}
/*********************************************************************
* This method validates the clockDisplay JPanel whever called upon. *
*********************************************************************/
public void update() {
clockDisplay.validate();
}
/***********************************************
* This method gets the source from the JList. *
***********************************************/
public void valueChanged(ListSelectionEvent d) {
JList source = (JList)d.getSource();
this.listSource = source;
}
/*********************************************************
* The following method detwrmines which button click *
* created the ActionEvent and then either adds or *
* removes a clock. To add, an object of ClockModel *
* type is created and populated with the information *
* given from the JList value that was selected when *
* and "+" button was clicked. That is then added to an *
* ArrayList and also to the clockDisplay JPanel. *
* The remove function simply removes the last entered *
* object from the ArrayList. I was unable to figure *
* out how to remove specific clocks unfortunately *
* or was I able to add/remove multiple clocks. *
* This problem I think has something to do with *
* an array of ClockModels with matching indeces *
* but I was unable to implement this system *
* successfully. *
*********************************************************/
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getSource();
Double timeZone = 0.0;
String selectedValue = (String)this.listSource.getSelectedValue();
ClockModel addRemModel = new ClockModel();
String [] values = selectedValue.split(",");
String cityName = values[0];
timeZone = Double.parseDouble(values[1]);

/**************************************************************
* The following if statement checks which button is clicked. *
**************************************************************/
if ((source.getText()) == "+") {
defaultController = new ClockController(addRemModel);

addRemModel.setCity(cityName);
addRemModel.setTimeZoneOffset(timeZone);
addRemModel.setTimeInSeconds(defaultController.getTimeInSeconds());
addRemModel.setText(addRemModel.secondsAsTimeText());

testModelArrayList.add(addRemModel);
add(testModelArrayList.get(testModelArrayList.size()-1));
}
else if ((source.getText()) == "-") {
testModelArrayList.remove(addRemModel);
addRemModel.setVisible(false);
remove(testModelArrayList.get(testModelArrayList.size()-1));
}
update();
}
/*************************************************
* These final two methods add and remove clocks.*
*************************************************/
public void add(ClockModel c) {
clockDisplay.add(c);
clockDisplay.validate();
}

public void remove(ClockModel c) {
clockDisplay.remove(c);
clockDisplay.validate();
}
}

  
CityTimeOffsets.txt
 

Accra,-1.0
Addis Ababa,+2.0
Adelaide,+8.5
Algiers,+0.0
Almaty,+5.0
Amman*,+2.0
Amsterdam*,+1.0
Anadyr,+11.0
Anchorage*,-9.0
Ankara*,+2.0
Antananarivo,+2.0
Asuncion,-5.0
Athens*,+2.0
Atlanta*,-5.0
Auckland,+11.0
Baghdad,+2.0
Bangalore,+4.5
Bangkok,+6.0
Barcelona*,+1.0
Beijing,+7.0
Beirut*,+2.0
Belgrade*,+1.0
Berlin*,+1.0
Bogota,-6.0
Boston*,-5.0
Brasilia,-4.0
Brisbane,+9.0
Brussels*,+1.0
Bucharest*,+2.0
Budapest*,+1.0
Buenos Aires,-4.0
Cairo,+1.0
Calgary*,-7.0
Canberra,+9.0
Cape Town,+1.0
Caracas,-5.5
Casablanca*,+0.0
Chicago*,-6.0
Columbus*,-5.0
Copenhagen*,+1.0
Dallas*,-6.0
Dar es Salaam,+2.0
Darwin,+8.5
Denver*,-7.0
Detroit*,-5.0
Dhaka,+5.0
Doha,+2.0
Dubai,+3.0
Dublin*,+0.0
Edmonton*,-7.0
Frankfurt*,+1.0
Guatemala,-7.0
Halifax*,-4.0
Hanoi,+6.0
Harare,+1.0
Havana*,-5.0
Helsinki*,+2.0
Hong Kong,+7.0
Honolulu,-11.0
Houston*,-6.0
Indianapolis*,-5.0
Islamabad,+4.0
Istanbul*,+2.0
Jakarta,+6.0
Jerusalem*,+2.0
Johannesburg,+1.0
Kabul,+3.5
Karachi,+4.0
Kathmandu,+4.8
Khartoum,+2.0
Kingston,-6.0
Kinshasa,+0.0
Kiritimati,+13.0
Kolkata,+4.5
Kuala Lumpur,+7.0
Kuwait City,+2.0
Kyiv*,+2.0
La Paz,-5.0
Lagos,+0.0
Lahore,+4.0
Las Vegas*,-8.0
Lima,-6.0
Limerick,+0.0
Lisbon*,+0.0
London*,+0.0
Los Angeles*,-8.0
Madrid*,+1.0
Managua,-7.0
Manila,+7.0
Melbourne,+9.0
Mexico City*,-6.0
Miami*,-5.0
Minneapolis*,-6.0
Minsk,+2.0
Montevideo,-4.0
Montreal*,-5.0
Moscow,+3.0
Mumbai,+4.5
Nairobi,+2.0
Nassau*,-5.0
New Delhi,+4.5
New Orleans*,-6.0
New York*,-5.0
Oslo*,+1.0
Ottawa*,-5.0
Paris*,+1.0


Actions

Information




%d bloggers like this: