/*
* See COPYING in top-level directory.
*/
package com.monkygames.wox.health.gui;
// === java imports === //
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.Date;
import java.util.Vector;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
// === miglayout imports === //
import net.miginfocom.swing.MigLayout;
// === chart imports === //
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.labels.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.xy.*;
import org.jfree.data.time.*;
import org.jfree.ui.RectangleInsets;
// === wo imports === //
import com.monkygames.wo.avatar.Avatar;
import com.monkygames.wo.io.AvatarLoader;
import com.monkygames.wo.io.AvatarXMLParser;
// === wox imports === //
import com.monkygames.wox.health.data.*;
import com.monkygames.wox.health.io.*;
/**
* The main for the Health GUI.
* @version 1.0
*/
public class HealthGUI extends JFrame implements ActionListener, ItemListener{
/**
* Contains all of the content for the gui.
**/
private JPanel rootPanel;
/**
* Holds the mii names and buttons.
**/
private JPanel northPanel;
/**
* Holds the combo boxes for toggeling graph stats.
**/
private JPanel southPanel;
/**
* Contains the graph.
**/
private ChartPanel chartPanel;
/**
* Holds the avatar names.
**/
private JComboBox avatarsCB;
/**
* The Unit either kg or lbs.
**/
private JComboBox weightUnitCB;
/**
* Holds the status of the balance board.
**/
private JLabel balanceBoardStatusL;
/**
* The time increment to show for the weight: days, weeks, months, years.
**/
private JComboBox timeIncrCB;
/**
* Button for measing weight.
**/
private JButton measureWeightB;
/**
* Button for meanually entering weights.
**/
private JButton manualWeightInputB;
/**
* Used for finding the scale.
**/
private JButton findScaleB;
/**
* Button for using the scale without recording weight.
**/
private JButton freeWeightB;
/**
* Menu bar items.
**/
private JMenuItem loadItem,quitItem,aboutItem,helpItem,csvItem;
/**
* Handles the avatars in the database.
**/
private AvatarLoader avatarLoader;
/**
* For loading avatar files.
**/
private JFileChooser chooser;
/**
* For saving csv files.
**/
private JFileChooser csvChooser;
/**
* Handles loading avatar's from xml.
**/
private AvatarXMLParser avatarXMLParser;
/**
* Handles getting and setting health information to the db.
**/
private HealthLoader healthLoader;
/**
* Used for the scale.
**/
private ScaleGUI scaleGUI;
/**
* Used for measuring the weight without recording.
**/
private FreeScaleGUI freeScaleGUI;
// ============= Constructors ============== //
public HealthGUI(){
int w = 800;
int h = 600;
setSize(w,h);
setTitle("Wo Health");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setup();
getContentPane().add(rootPanel);
setVisible(true);
scaleGUI = new ScaleGUI(this);
freeScaleGUI = new FreeScaleGUI();
}
// ============= Public Methods ============== //
/**
* The weight that was calculated from the Scale will be added to the database.
* Note, the weight is added to the end of the list assuming this is the most
* up-to-date weight.
* @param weight the current weight calculated.
**/
public void updateWeight(Weight weight){
// set this weight to the avatar selected
Avatar avatar = (Avatar)avatarsCB.getSelectedItem();
if(avatar != null){
HealthData hd = healthLoader.getHealthData(avatar.info);
if(hd == null){
hd = new HealthData();
hd.info = avatar.info;
hd.weightV.add(weight);
healthLoader.createHealthData(hd);
}else{
hd.weightV.add(weight);
healthLoader.updateHealthData(hd);
}
// update gui
loadGraph(avatar);
}
}
/**
* Used for manually entering a weight.
* Note, this sorts the list based on the date.
* @param weight the weight to be added.
**/
public void updateWeightSorted(Weight weight){
boolean isAdded = false;
// set this weight to the avatar selected
Avatar avatar = (Avatar)avatarsCB.getSelectedItem();
if(avatar != null){
HealthData hd = healthLoader.getHealthData(avatar.info);
if(hd == null){
hd = new HealthData();
hd.info = avatar.info;
// sort!
for(int i = 0; i < hd.weightV.size(); i++){
if(hd.weightV.elementAt(i).date > weight.date){
hd.weightV.add(weight);
isAdded = true;
break;
}
}
if(!isAdded){
hd.weightV.add(weight);
}
healthLoader.createHealthData(hd);
}else{
hd.weightV.add(weight);
healthLoader.updateHealthData(hd);
}
// update gui
loadGraph(avatar);
}
}
/**
* Handles setting the scale to be used.
**/
public void setScale(Scale scale){
scaleGUI.setScale(scale);
freeScaleGUI.setScale(scale);
balanceBoardStatusL.setText("Balance Board: Connected - Battery["+scale.getBatteryLevel()+"]");
}
// ============= Protected Methods ============== //
// ============= Private Methods ============== //
private void setup(){
// initialize menu
initMenu();
rootPanel = new JPanel(new MigLayout("fill"));
northPanel = new JPanel(new MigLayout());
southPanel = new JPanel(new MigLayout("fill"));
// initialize combo boxes and buttons
avatarsCB = new JComboBox();
weightUnitCB = new JComboBox(new Object[]{"kg","lbs"});
balanceBoardStatusL = new JLabel("Balance Board: Disconnected");
timeIncrCB = new JComboBox(new Object[]{"day","month","year","week"});
measureWeightB = new JButton("Measure Weight");
manualWeightInputB = new JButton("Manual Weight Input");
findScaleB = new JButton("Find Scale");
freeWeightB = new JButton("Free Weight");
avatarsCB.addItemListener(this);
weightUnitCB.addItemListener(this);
timeIncrCB.addItemListener(this);
measureWeightB.addActionListener(this);
manualWeightInputB.addActionListener(this);
findScaleB.addActionListener(this);
freeWeightB.addActionListener(this);
// add to panels
northPanel.add(avatarsCB);
northPanel.add(measureWeightB);
northPanel.add(manualWeightInputB);
northPanel.add(freeWeightB);
northPanel.add(findScaleB);
southPanel.add(weightUnitCB,"dock west");
southPanel.add(timeIncrCB,"dock west");
southPanel.add(balanceBoardStatusL,"dock east");
southPanel.add(new JPanel(),"grow,push");
rootPanel.add(northPanel,"dock north");
rootPanel.add(southPanel,"dock south");
// setup avatars and health
healthLoader = new HealthLoader("health.db");
avatarLoader = new AvatarLoader("avatars.db");
loadAvatars();
// setup file chooser
chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("XML","xml");
chooser.setFileFilter(filter);
avatarXMLParser = new AvatarXMLParser();
csvChooser = new JFileChooser();
FileNameExtensionFilter filter2 = new FileNameExtensionFilter("CSV","csv");
csvChooser.setFileFilter(filter2);
}
private void initMenu(){
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
loadItem = new JMenuItem("Load Avatar");
quitItem = new JMenuItem("Quit");
csvItem = new JMenuItem("Export to CSV");
loadItem.addActionListener(this);
quitItem.addActionListener(this);
csvItem.addActionListener(this);
fileMenu.add(loadItem);
fileMenu.add(csvItem);
fileMenu.add(quitItem);
JMenu helpMenu = new JMenu("Help");
aboutItem = new JMenuItem("About");
helpItem = new JMenuItem("Instructions");
aboutItem.addActionListener(this);
helpItem.addActionListener(this);
helpMenu.add(helpItem);
helpMenu.add(aboutItem);
menuBar.add(fileMenu);
menuBar.add(helpMenu);
setJMenuBar(menuBar);
}
/**
* Loads the avatars from the Database and adds them to the combo box.
**/
private void loadAvatars(){
// clear out all
avatarsCB.removeItemListener(this);
avatarsCB.removeAllItems();
Vector <Avatar> avatarsV = avatarLoader.getAllAvatars();
for(int i = 0; i < avatarsV.size(); i++){
avatarsCB.addItem(avatarsV.elementAt(i));
}
avatarsCB.addItemListener(this);
if(avatarsV.size() > 0){
// load first avatar in graph
loadGraph(avatarsV.elementAt(0));
}
}
/**
* Loads the graph.
* TODO implement graphs
**/
private void loadGraph(Avatar avatar){
if(chartPanel != null){
rootPanel.remove(chartPanel);
}
// get health information
HealthData healthData = healthLoader.getHealthData(avatar.info);
//XYSeries series = new XYSeries(avatar.info.name);
TimeSeries series = null;
boolean isDay,isMonth,isYear,isWeek;
boolean isKG;
isDay = isMonth = isYear = isWeek = isKG = false;
String timeS = "";
String measurementS = "";
DateUtil dateUtil = new DateUtil(healthData.weightV);
if(weightUnitCB.getSelectedIndex() == 0){
isKG = true;
measurementS = "kg";
}else{
isKG = false;
measurementS = "bls";
}
switch(timeIncrCB.getSelectedIndex()){
case 1:
isMonth = true;
timeS = "Month";
series = dateUtil.getTimeSeriesByMonth(isKG);
break;
case 2:
isYear = true;
timeS = "Year";
series = dateUtil.getTimeSeriesByYear(isKG);
break;
case 3:
isWeek = true;
timeS = "Week";
series = dateUtil.getTimeSeriesByWeek(isKG);
break;
case 0:
default:
isDay = true;
timeS = "Day";
series = dateUtil.getTimeSeriesByDay(isKG);
}
// Add the series to your data set
//XYSeriesCollection dataset = new XYSeriesCollection();
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(series);
dataset.setDomainIsPointsInTime(true);
JFreeChart chart = ChartFactory.createXYLineChart("Weight History","Time ("+timeS+")", "Weight ("+measurementS+")",dataset,
PlotOrientation.VERTICAL, // Plot Orientation
true, // Show Legend
true, // Use tooltips
false // Configure chart to generate URLs?
); chart.setAntiAlias(true);
XYPlot plot = chart.getXYPlot();
//StandardXYZToolTipGenerator xyTTG = new StandardXYZToolTipGenerator();
//renderer.setBaseToolTipGenerator(xyTTG);
//plot.setRenderer(renderer);
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
plot.setAxisOffset(new RectangleInsets(5.0,5.0,5.0,5.0));
//plot.setBackgroundPaint(Color.lightGray);
//plot.setRangeGridlinePaint(Color.white);
//XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true,true);
//renderer.setUseOutlinePaint(true);
//renderer.setUseFillPaint(true);
XYItemRenderer renderer = plot.getRenderer();
if(renderer instanceof XYLineAndShapeRenderer){
XYLineAndShapeRenderer renderer2 = (XYLineAndShapeRenderer) renderer;
renderer2.setBaseShapesVisible(true);
renderer2.setBaseShapesFilled(true);
}
DateAxis dateAxis = new DateAxis();
if(isDay){
dateAxis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd"));
}else if(isMonth){
dateAxis.setDateFormatOverride(new SimpleDateFormat("yyyy-MMM"));
}else if(isYear){
dateAxis.setDateFormatOverride(new SimpleDateFormat("yyyy"));
}else if(isWeek){
dateAxis.setDateFormatOverride(new SimpleDateFormat("yyyy-MMM-W"));
}
plot.setDomainAxis(dateAxis);
chartPanel = new ChartPanel(chart);
chartPanel.setDomainZoomable(true);
//chartPanel.setVerticalAxisTrace(true);
rootPanel.add(chartPanel,"dock center");
updateGUI();
}
/**
* Adds an avatar from xml file.
**/
private void addAvatar(){
int retVal = chooser.showOpenDialog(this);
if(retVal == JFileChooser.APPROVE_OPTION){
Avatar avatar = avatarXMLParser.getAvatarFromFile(chooser.getSelectedFile().getAbsolutePath());
if(avatar != null){
if(avatarLoader.addAvatar(avatar)){
// create health information!
HealthData hd = new HealthData();
hd.info = avatar.info;
healthLoader.createHealthData(hd);
loadAvatars();
}
}
}
}
/**
* Prepares and starts to measure the weight.
**/
private void measureWeight(){
if(weightUnitCB.getSelectedIndex() == 0){
scaleGUI.init(true);
}else{
scaleGUI.init(false);
}
}
/**
* Prepares and starts to measure the weight without recording.
**/
private void freeMeasureWeight(){
if(weightUnitCB.getSelectedIndex() == 0){
freeScaleGUI.init(true);
}else{
freeScaleGUI.init(false);
}
}
/**
* Displays a help popup.
**/
private void popHelp(){
String data = "Wo Health enables you to measure your weight.\n";
data += "You will need a bluetooth adapter and a Wii Balance Board.\n";
data += "Before you can weight yourself, you will need an avatar.\n";
data += "The easest method of getting an avatar is going to: http://www.myavatareditor.com/\n";
data += "Build an avatar and then click on the save icon. Next click on XML, then click on save.\n";
data += "On Wo Health, click on file->load avatar and add the xml file you just saved.\n\n";
data += "You are ready to weight, click on the Measure Weight button.\n";
data += "Now turn on your wii (turn the wii upside-down, remove the battery cover, and press the red button.\n";
data += "The blue light should flash continously. Wait for onscreen instructions";
JOptionPane.showMessageDialog(this,data,"Help",JOptionPane.INFORMATION_MESSAGE);
}
/**
* Displays an about popup.
**/
private void popAbout(){
String data = "Wo Health is an extension of Wo\n Release Data: 2010/04/06";
JOptionPane.showMessageDialog(this,data,"About",JOptionPane.INFORMATION_MESSAGE);
}
private void manualInput(){
ManualInputGUI migui = new ManualInputGUI(this);
}
private void findScale(){
BalanceBoardFinderGUI bbf = new BalanceBoardFinderGUI(this);
bbf.init();
}
/**
* Exports to a CSV file.
**/
private void exportToCSV(){
Avatar avatar = (Avatar)avatarsCB.getSelectedItem();
boolean failed = false;
if(avatar != null){
HealthData hd = healthLoader.getHealthData(avatar.info);
if(hd != null){
int retVal = csvChooser.showSaveDialog(this);
if(retVal == JFileChooser.APPROVE_OPTION){
CSVWriter writer = new CSVWriter(csvChooser.getSelectedFile().getAbsolutePath(),hd);
failed = true;
}
}
}
String data = "";
if(failed){
data = "CSV Export Complete";
}else{
data = "CSV Export Failed";
}
JOptionPane.showMessageDialog(this,data,"CSV Export",JOptionPane.INFORMATION_MESSAGE);
}
/**
* Handles repating the graphics.
**/
private void updateGUI(){
rootPanel.repaint();
rootPanel.revalidate();
}
// ============= Implemented Methods ============== //
public void actionPerformed(ActionEvent evt){
Object src = evt.getSource();
if(src == loadItem){
addAvatar();
}else if(src == quitItem){
System.exit(1);
}else if(src == aboutItem){
popAbout();
}else if(src == helpItem){
popHelp();
}else if(src == measureWeightB){
measureWeight();
}else if(src == manualWeightInputB){
manualInput();
}else if(src == findScaleB){
findScale();
}else if(src == csvItem){
exportToCSV();
}else if(src == freeWeightB){
freeMeasureWeight();
}
}
public void itemStateChanged(ItemEvent evt){
Object src = evt.getSource();
if(src == avatarsCB || src == weightUnitCB || src == timeIncrCB){
// load the avatars information
Avatar avatar = (Avatar)avatarsCB.getSelectedItem();
loadGraph(avatar);
}
}
// ============= Extended Methods ============== //
// ============= Internal Classes ============== //
// ============= Static Methods ============== //
public static void main(String []args){
HealthGUI gui = new HealthGUI();
}
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*
* vim: ts=8 sts=4 sw=4 noexpandtab
*/