diff --git a/src/dashboard.form b/src/dashboard.form
new file mode 100644
index 0000000..769eecd
--- /dev/null
+++ b/src/dashboard.form
@@ -0,0 +1,35 @@
+
+
+
diff --git a/src/dashboard.java b/src/dashboard.java
new file mode 100644
index 0000000..99e986f
--- /dev/null
+++ b/src/dashboard.java
@@ -0,0 +1,82 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/**
+ *
+ * @author st8511x
+ */
+public class dashboard extends javax.swing.JFrame {
+
+ /**
+ * Creates new form dashboard
+ */
+ public dashboard() {
+ initComponents();
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ //
+ private void initComponents() {
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(0, 400, Short.MAX_VALUE)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(0, 300, Short.MAX_VALUE)
+ );
+
+ pack();
+ }//
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String args[]) {
+ /* Set the Nimbus look and feel */
+ //
+ /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
+ * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
+ */
+ try {
+ for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
+ if ("Nimbus".equals(info.getName())) {
+ javax.swing.UIManager.setLookAndFeel(info.getClassName());
+ break;
+ }
+ }
+ } catch (ClassNotFoundException ex) {
+ java.util.logging.Logger.getLogger(dashboard.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+ } catch (InstantiationException ex) {
+ java.util.logging.Logger.getLogger(dashboard.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+ } catch (IllegalAccessException ex) {
+ java.util.logging.Logger.getLogger(dashboard.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+ } catch (javax.swing.UnsupportedLookAndFeelException ex) {
+ java.util.logging.Logger.getLogger(dashboard.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
+ }
+ //
+
+ /* Create and display the form */
+ java.awt.EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ new dashboard().setVisible(true);
+ }
+ });
+ }
+
+ // Variables declaration - do not modify
+ // End of variables declaration
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/DashboardDemoMain.java b/src/uk/ac/gre/comp1549/dashboard/DashboardDemoMain.java
new file mode 100644
index 0000000..061d4f9
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/DashboardDemoMain.java
@@ -0,0 +1,209 @@
+package uk.ac.gre.comp1549.dashboard;
+
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JButton;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.WindowConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import uk.ac.gre.comp1549.dashboard.controls.BarPanel;
+import uk.ac.gre.comp1549.dashboard.controls.DialPanel;
+import uk.ac.gre.comp1549.dashboard.controls.IndicatorFactory;
+import uk.ac.gre.comp1549.dashboard.events.*;
+import uk.ac.gre.comp1549.dashboard.scriptreader.DashboardEventGeneratorFromXML;
+import uk.ac.gre.comp1549.dashboard.controls.IIndicator;
+import uk.ac.gre.comp1549.dashboard.controls.Singleton;
+import uk.ac.gre.comp1549.dashboard.controls.ArrivalBoard;
+
+/**
+ * DashboardDemoMain.java Contains the main method for the Dashboard demo
+ * application. It: a) provides the controller screen which allows user input
+ * which is passed to the display indicators, b) allows the user to run the XML
+ * script which changes indicator values, c) creates the dashboard JFrame and
+ * adds display indicators to it.
+ *
+ * @author COMP1549
+ * @version 2.0
+ */
+public class DashboardDemoMain extends JFrame {
+
+ /**
+ * Name of the XML script file - change here if you want to use a different
+ * filename
+ */
+ public static final String XML_SCRIPT = "dashboard_script.xml";
+
+ // fields that appear on the control panel
+ private JButton btnScript;
+
+ // fields that appear on the dashboard itself
+ private DialPanel speedDial, fuelDial, compassDial, altitudeDial;
+ private BarPanel fuelBar;
+
+ /**
+ * Constructor. Does maybe more work than is good for a constructor.
+ */
+ public DashboardDemoMain() {
+ // Set up the frame for the controller
+ setTitle("Dashboard demonstration controller");
+ setLayout(new FlowLayout());
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ JPanel panel = new JPanel();
+
+ btnScript = new JButton("Run XML Script");
+
+ // When the button is read the XML script will be run
+ btnScript.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ new Thread() {
+ public void run() {
+ runXMLScript();
+ }
+ }.start();
+ }
+ });
+ panel.add(btnScript);
+ add(panel);
+ pack();//size determined by contained components
+
+ setLocationRelativeTo(null); // display in centre of screen
+ // this.setVisible(true);
+
+ // Set up the dashboard screen
+ JFrame dashboard = new JFrame("Demo dashboard");
+ dashboard.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ dashboard.setLayout(new FlowLayout());
+
+// IndicatorFactory indicatorFactory = new IndicatorFactory();
+// IIndicator fullDial = indicatorFactory.createIndicator("full");
+ compassDial = new DialPanel("full");//full dial
+ compassDial.setLabel("COMPASS (deg.)");
+ dashboard.add(compassDial);
+
+ speedDial = new DialPanel("threequater");//three quaters dial
+ speedDial.setLabel("AIR SPEED (m/s)");
+ dashboard.add(speedDial);
+
+
+ altitudeDial = new DialPanel("half");//half dial
+ altitudeDial.setLabel("ALTITUDE (km)");
+ dashboard.add(altitudeDial);
+
+ fuelDial = new DialPanel(("quater"));//quater dial
+ fuelDial.setLabel("FUEL (1000L)");
+ dashboard.add(fuelDial);
+
+
+ DocumentListener petrolListener = new PetrolValueListener();
+ fuelDial.txtUserInput.getDocument().addDocumentListener(petrolListener);
+
+ // add the petrol Bar
+ fuelBar = new BarPanel();
+ fuelBar.setLabel("FUEL");
+ fuelBar.setValue(100);
+ dashboard.add(fuelBar);
+ ArrivalBoard ab = new ArrivalBoard();
+ dashboard.add(ab);
+
+//dashboard.pack();
+ dashboard.setSize(1000, 300); //w,h
+
+ dashboard.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ //dashboard.setUndecorated(true);
+ dashboard.add(panel);
+ // centre the dashboard frame above the control frame
+// Point topLeft = this.getLocationOnScreen(); // top left of control frame (this)
+ int hControl = this.getHeight(); // height of control frame (this)
+ int wControl = this.getWidth(); // width of control frame (this)
+ int hDash = dashboard.getHeight(); // height of dashboard frame
+ int wDash = dashboard.getWidth(); // width of dashboard frame
+ // calculate where top left of the dashboard goes to centre it over the control frame
+ //Point p2 = new Point((int) topLeft.getX() - (wDash - wControl) / 2, (int) topLeft.getY() - (hDash + hControl));
+ //dashboard.setLocation(p2);
+
+ dashboard.setVisible(true);
+ }
+
+ public void setFuel() {
+ try {
+ int value = Integer.parseInt(fuelDial.txtUserInput.getText().trim());
+ fuelBar.setValue(value);
+ } catch (NumberFormatException e) {
+ }
+ // don't set the speed if the input can't be parsed
+ }
+
+ /**
+ * Respond to user input in the Petrol textfield
+ */
+ private class PetrolValueListener implements DocumentListener {
+
+ @Override
+ public void insertUpdate(DocumentEvent event) {
+ setFuel();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent event) {
+ setFuel();
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent event) {
+ }
+ }
+
+ /**
+ * Run the XML script file which generates events for the dashboard
+ * indicators
+ */
+ private void runXMLScript() {
+ try {
+ DashboardEventGeneratorFromXML dbegXML = new DashboardEventGeneratorFromXML();
+
+ // Register for speed events from the XML script file
+ DashBoardEventListener dbelSpeed = new DashBoardEventListener() {
+ @Override
+ public void processDashBoardEvent(Object originator, DashBoardEvent dbe) {
+ speedDial.setValue(Integer.parseInt(dbe.getValue()));
+ }
+ };
+ dbegXML.registerDashBoardEventListener("speed", dbelSpeed);
+
+ // Register for petrol events from the XML script file
+ DashBoardEventListener dbelPetrol = new DashBoardEventListener() {
+ @Override
+ public void processDashBoardEvent(Object originator, DashBoardEvent dbe) {
+ fuelDial.setValue(Integer.parseInt(dbe.getValue()));
+ fuelBar.setValue(Integer.parseInt(dbe.getValue()));
+ }
+ };
+ dbegXML.registerDashBoardEventListener("petrol", dbelPetrol);
+
+ // Process the script file - it willgenerate events as it runs
+ dbegXML.processScriptFile(XML_SCRIPT);
+
+ } catch (Exception ex) {
+ Logger.getLogger(DashboardDemoMain.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /**
+ *
+ * @param args - unused
+ */
+ public static void main(String[] args) {
+ final DashboardDemoMain me = new DashboardDemoMain();
+ }
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/ArrivalBoard.form b/src/uk/ac/gre/comp1549/dashboard/controls/ArrivalBoard.form
new file mode 100644
index 0000000..72142fc
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/ArrivalBoard.form
@@ -0,0 +1,304 @@
+
+
+
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/ArrivalBoard.java b/src/uk/ac/gre/comp1549/dashboard/controls/ArrivalBoard.java
new file mode 100644
index 0000000..2cd448d
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/ArrivalBoard.java
@@ -0,0 +1,207 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+/**
+ *
+ * @author st8511x
+ */
+public class ArrivalBoard extends javax.swing.JPanel {
+
+ /**
+ * Creates new form testBean
+ */
+ public ArrivalBoard() {
+ initComponents();
+ }
+
+ /**
+ * This method is called from within the constructor to initialise the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ jLabel1 = new javax.swing.JLabel();
+ jLabel2 = new javax.swing.JLabel();
+ jLabel3 = new javax.swing.JLabel();
+ jLabel4 = new javax.swing.JLabel();
+ cmdStatus = new javax.swing.JComboBox();
+ panEnterDate = new javax.swing.JPanel();
+ cmdHrs = new javax.swing.JComboBox();
+ cmdMins = new javax.swing.JComboBox();
+ cmdAmPm = new javax.swing.JComboBox();
+ txtDestination = new javax.swing.JTextField();
+ btnShow = new javax.swing.JButton();
+ board = new myjavabean.Bean();
+
+ jLabel1.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
+ jLabel1.setText("Status");
+
+ jLabel2.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
+ jLabel2.setText("Arrival:");
+
+ jLabel3.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
+ jLabel3.setText("Destination");
+
+ jLabel4.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
+ jLabel4.setText("Time");
+
+ cmdStatus.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
+ cmdStatus.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "On Time", "Delayed ", "Cancelled" }));
+
+ panEnterDate.setLayout(new java.awt.GridBagLayout());
+
+ cmdHrs.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
+ cmdHrs.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24" }));
+ cmdHrs.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmdHrsActionPerformed(evt);
+ }
+ });
+ panEnterDate.add(cmdHrs, new java.awt.GridBagConstraints());
+
+ cmdMins.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
+ cmdMins.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59" }));
+ cmdMins.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmdMinsActionPerformed(evt);
+ }
+ });
+ panEnterDate.add(cmdMins, new java.awt.GridBagConstraints());
+
+ cmdAmPm.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N
+ cmdAmPm.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "am", "pm" }));
+ cmdAmPm.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ cmdAmPmActionPerformed(evt);
+ }
+ });
+ panEnterDate.add(cmdAmPm, new java.awt.GridBagConstraints());
+
+ txtDestination.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ txtDestinationActionPerformed(evt);
+ }
+ });
+
+ btnShow.setText("show");
+ btnShow.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnShowActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGap(12, 12, 12)
+ .addComponent(jLabel3))
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(txtDestination, javax.swing.GroupLayout.PREFERRED_SIZE, 89, javax.swing.GroupLayout.PREFERRED_SIZE)))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(panEnterDate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(jLabel4))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel1)
+ .addComponent(cmdStatus, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jLabel2)
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+ .addGap(0, 0, Short.MAX_VALUE)
+ .addComponent(btnShow)
+ .addGap(26, 26, 26)
+ .addComponent(board, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))))
+ .addContainerGap())
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(jLabel2)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel3)
+ .addComponent(jLabel4)
+ .addComponent(jLabel1))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(txtDestination, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(cmdStatus)
+ .addComponent(panEnterDate, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addGap(13, 13, 13)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(btnShow)
+ .addComponent(board, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addContainerGap())
+ );
+ }// //GEN-END:initComponents
+
+ private void txtDestinationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtDestinationActionPerformed
+
+ // TODO add your handling code here:
+ }//GEN-LAST:event_txtDestinationActionPerformed
+
+ private void cmdMinsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmdMinsActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_cmdMinsActionPerformed
+
+ private void cmdHrsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmdHrsActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_cmdHrsActionPerformed
+
+ private void btnShowActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnShowActionPerformed
+ String strDest = String.format(txtDestination.getText());
+ String strHrs = "" + cmdHrs.getSelectedItem();
+ String strMins = "" + cmdMins.getSelectedItem();
+ String strAMPM = "" + cmdAmPm.getSelectedItem();
+ String strStatus = "" + cmdStatus.getSelectedItem();
+
+ board.setDestination(strDest);
+ board.setHrs(strHrs);
+ board.setMins(strMins);
+ board.setAMPM(strAMPM);
+ board.setStatus(strStatus);
+
+ // TODO add your handling code here:
+ }//GEN-LAST:event_btnShowActionPerformed
+
+ private void cmdAmPmActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cmdAmPmActionPerformed
+ // TODO add your handling code here:
+ }//GEN-LAST:event_cmdAmPmActionPerformed
+
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private myjavabean.Bean board;
+ private javax.swing.JButton btnShow;
+ private javax.swing.JComboBox cmdAmPm;
+ private javax.swing.JComboBox cmdHrs;
+ private javax.swing.JComboBox cmdMins;
+ private javax.swing.JComboBox cmdStatus;
+ private javax.swing.JLabel jLabel1;
+ private javax.swing.JLabel jLabel2;
+ private javax.swing.JLabel jLabel3;
+ private javax.swing.JLabel jLabel4;
+ private javax.swing.JPanel panEnterDate;
+ private javax.swing.JTextField txtDestination;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/BarIndicator.java b/src/uk/ac/gre/comp1549/dashboard/controls/BarIndicator.java
new file mode 100644
index 0000000..b6e2cf6
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/BarIndicator.java
@@ -0,0 +1,100 @@
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.JPanel;
+
+/**
+ * BarDrawPanel. Draw a horizontal bar indicator and show its current value
+ *
+ * @author COMP1549
+ * @version 2.0
+ */
+public class BarIndicator extends JPanel implements IIndicator {//because it shall be used in the facory pattern
+
+ private int value; // current value - will be indicated on the bar
+
+ private int barLength; // length/width of the bar
+ private int barHeight; // height of the bar
+
+ private int padding; // padding around the bar
+ private float barMaxValue; // bar runs from 0 to barMaxValue
+
+ /**
+ * Default constructor - sets default values
+ */
+ public BarIndicator() {
+ this(200, 20, 8, 100, 0);
+ }
+
+ /**
+ *
+ * @param length - length of the horizontal bar
+ * @param height - height of the bar
+ * @param padding - padding around the bar
+ * @param barMaxValue - bar runs from 0 to barMaxValue
+ * @param value - current value that will be indicated on the bar
+ */
+ public BarIndicator(int length, int height, int padding, int barMaxValue, int value) {
+ // set size of the JPanel to be big enough to hold the bar plus padding
+ setPreferredSize(new Dimension(length + (2 * padding), height + (2 * padding)));
+
+ this.barLength = length;
+ this.barHeight = height;
+ this.padding = padding;
+ this.barMaxValue = barMaxValue;
+ this.value = value;
+ }
+
+ /**
+ * This method is called every time the Bar needs drawing for instance when
+ * the value has changed. It draws the bar itself and the indicator in the
+ * correct position to indicate the current value
+ *
+ * @param g - graphics object used to draw on the JPanel
+ */
+ @Override
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ Graphics2D g2 = (Graphics2D) g; // get a Graphics2D object to draw with
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ // Draw the bar itself. The first 10% of the bar is red. The last 30% is yellow. Between 10% and 30%
+ // the colour graduates from red to yellow. Check the API documentation for GradientPaint to see
+ // how this works.
+ Rectangle2D barx = new Rectangle2D.Double(padding, padding, barLength, barHeight);
+
+ GradientPaint redtoyellow = new GradientPaint(0 + (float) barx.getWidth() * 0.1F, 0, Color.RED, (float) barx.getWidth() * 0.3F, 0, Color.YELLOW);
+ g2.setPaint(redtoyellow);
+
+ g2.fill(barx);
+
+ // draw the value indicator to show the current value
+ g2.setStroke(new BasicStroke(barLength / 40, BasicStroke.CAP_SQUARE, 0));
+ g2.setPaint(Color.GRAY);
+ Line2D valueIndicator = new Line2D.Double(padding + (barLength * value / barMaxValue), padding / 2F, padding + (barLength * value / barMaxValue), barHeight + (padding * 1.5F));
+
+ //valueIndicator.
+ g2.draw(valueIndicator);
+ }
+
+ /**
+ * Set the value to be displayed on the bar
+ *
+ * @param value value
+ */
+ public void setValue(int value) {
+ // don't let the value go over the maximum for the bar. But what about the minimum?
+ this.value = value > barMaxValue ? (int) barMaxValue : value;
+ repaint(); // causes paintComponent() to be called
+ }
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/BarPanel.java b/src/uk/ac/gre/comp1549/dashboard/controls/BarPanel.java
new file mode 100644
index 0000000..7a25437
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/BarPanel.java
@@ -0,0 +1,57 @@
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.awt.BorderLayout;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.BevelBorder;
+
+/**
+ * BarPanel. Container for BarDrawPanel to hold bar and label. If a label is not
+ * needed BarDrawPanel an be used on its own
+ *
+ * @author COMP1549
+ * @version 2.0
+ */
+public class BarPanel extends JPanel implements IIndicatorPanel{
+
+ private BarIndicator bar; // the bar itself
+ private JLabel lblTitle; // the label which always appears above the bar
+
+ /**
+ * Default constructor
+ */
+ public BarPanel() {
+ setLayout(new BorderLayout());
+ // set the style of the border
+ setBorder(new BevelBorder(BevelBorder.LOWERED));
+
+ // position the label above the bar
+ lblTitle = new JLabel();
+ lblTitle.setHorizontalAlignment(JLabel.CENTER);
+ add(lblTitle, BorderLayout.NORTH);
+ bar = new BarIndicator();
+
+ // bar.
+ add(bar, BorderLayout.CENTER);
+
+ }
+
+ /**
+ * Set the value for the bar
+ *
+ * @param value - value for the bar
+ */
+ public void setValue(int value) {
+ bar.setValue(value);
+ }
+
+ /**
+ *
+ * @param label - label to appear above the dial
+ */
+ public void setLabel(String label) {
+ lblTitle.setText(label);
+ }
+
+
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/DialPanel.java b/src/uk/ac/gre/comp1549/dashboard/controls/DialPanel.java
new file mode 100644
index 0000000..8f3575b
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/DialPanel.java
@@ -0,0 +1,130 @@
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridBagLayout;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.BevelBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import uk.ac.gre.comp1549.dashboard.DashboardDemoMain;
+
+/**
+ * DialPanel. Container for DialDrawPanel to hold dial and label. If a label is
+ * not needed DialDrawPanel an be used on its own
+ *
+ * @author COMP1549
+ * @version 2.0
+ */
+public class DialPanel extends JPanel implements IIndicatorPanel {
+
+
+
+ private JLabel lblTitle; // the label which always appears above the dial
+ public JTextField txtUserInput;
+
+ IIndicator indicator;
+ String indicatorType;
+ IndicatorFactory indicatorFactory = new IndicatorFactory();
+
+ /**
+ * Default constructor
+ *
+ * @param degrees
+ */
+ //STATIC POLYMORPHISM
+ public DialPanel(String userDesiredType) {
+ setLayout(new BorderLayout());
+ indicatorType = userDesiredType;
+ labelDial();
+
+ //Indicator fullDial = indicatorFactory.createIndicator("full");
+ indicator = getIndicatorFromFactory(indicatorType);
+ if (indicator != null) {//allows for null singleton handling with invalid parameter
+ add((Component) indicator, BorderLayout.CENTER);
+ displayInputFields();
+
+ DocumentListener inputListener = new UserInputListener();
+ txtUserInput.getDocument().addDocumentListener(inputListener);
+ }
+ }
+
+//METHOD THAT BRIDGES DIAL PANEL TO FACOTORY CLASS
+ public IIndicator getIndicatorFromFactory(String indicator) {
+ IIndicator in = indicatorFactory.createIndicator(indicator);
+
+ return in;
+ }
+
+ //Listens for changes in user input fields for changes
+ private class UserInputListener implements DocumentListener {
+
+ @Override
+ public void insertUpdate(DocumentEvent event) {
+ setDialValue();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent event) {
+ setDialValue();
+ }
+
+ @Override
+ public void changedUpdate(DocumentEvent event) {
+ }
+ }
+
+ //set Dial Value according to user input
+ public void setDialValue() {
+ try {
+ int value = Integer.parseInt(txtUserInput.getText().trim());
+ indicator.setValue(value);
+ } catch (NumberFormatException e) {
+ JOptionPane.showMessageDialog(this, " Invalid input type: " + e.getMessage());
+
+ }
+ // don't set the speed if the input can't be parsed
+ }
+
+ private void displayInputFields() {
+ // this.add(new JLabel("Input value"), BorderLayout.SOUTH);
+ txtUserInput = new JTextField("0", 3);
+ //txtuserInput.SET
+ txtUserInput.setMaximumSize(txtUserInput.getPreferredSize());
+ add(txtUserInput, BorderLayout.SOUTH);
+ }
+
+ private void labelDial() {
+ setLayout(new BorderLayout());
+
+ // set the style of the border
+ setBorder(new BevelBorder(BevelBorder.LOWERED));
+
+ // position the label above the dial
+ lblTitle = new JLabel();
+ lblTitle.setHorizontalAlignment(JLabel.CENTER);
+ add(lblTitle, BorderLayout.NORTH);
+ }
+
+ /**
+ * Set the value for the dial
+ *
+ * @param value - value for the dial
+ */
+ public void setValue(int value) {//USED FOR XML?
+ indicator.setValue(value);
+ }
+
+ /**
+ *
+ * @param label - label to appear above the dial
+ */
+ public void setLabel(String label) {
+
+ lblTitle.setText(label);
+ }
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/Dial_FullCircle.java b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_FullCircle.java
new file mode 100644
index 0000000..060d2c6
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_FullCircle.java
@@ -0,0 +1,171 @@
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.awt.BasicStroke;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import javafx.scene.paint.Color;
+import javax.swing.JOptionPane;
+
+import javax.swing.JPanel;
+
+/**
+ * Dial_FullCircle. Draw a dial and indicate current value.
+ *
+ * @author COMP1549
+ * @version 2.0
+ */
+public class Dial_FullCircle extends JPanel implements IIndicator {//COMPASS
+
+ protected int radius; // radius of dial
+ protected int padding; // padding outside the dial
+ protected float dialMaxValue; // dial runs from 0 to dialMaxValue
+ protected int value; // current value - where the hand will point
+ protected float dialMinValue = 0;//the starting value
+ protected double handLength; // length of indicator hand
+ protected double angle;
+ /**
+ * The extent of the dial. For a full circle this would be 360
+ */
+ protected float DIAL_EXTENT_DEGREES = 360;
+
+ /**
+ * Where the dial starts being draw from. Due north is 90.
+ */
+ //protected final float DIAL_START_OFFSET_DEGREES = -45;
+ protected float DIAL_START_OFFSET_DEGREES = 90;
+
+ /**
+ * Default constructor - sets default values
+ */
+ public Dial_FullCircle() {
+ this(100, 10, 360, 0);//radius, padding, max, pointValue
+
+ }
+
+ /**
+ * @param radius - radius of the dial
+ * @param padding - padding outside the dial
+ * @param dialMaxValue - dial runs from 0 to dialMaxValue
+ * @param value - current value - where the hand will point
+ */
+ public Dial_FullCircle(int radius, int padding, int dialMaxValue, int value) {
+ // set size of the JPanel to be big enough to hold the dial plus padding
+ setPreferredSize(new Dimension(2 * (radius + padding), 2 * (radius + padding)));
+ this.radius = radius;
+ this.padding = padding;
+ this.dialMaxValue = dialMaxValue;
+ this.value = value;
+ handLength = 0.9 * radius; // hand length is fixed at 90% of radius
+ //this.setBackground(java.awt.Color.red);
+ }
+
+ /**
+ * This method is called every time the Dial needs drawing for instance when
+ * the value has changed. It draws the dial itself and the hand in the
+ * correct position to indicate the current value
+ *
+ * @param g - graphics object used to draw on the JPanel
+ */
+ @Override
+ public void paintComponent(Graphics g) {
+ //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ super.paintComponent(g);
+ Graphics2D g2 = (Graphics2D) g; // get a Graphics2D object to draw with
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, 0));
+
+ // draw centre of the dial as a small circle of fixed size
+ Ellipse2D circle = new Ellipse2D.Double((radius + padding) - 5, (radius + padding) - 5, 10, 10);
+ g2.fill(circle);
+
+ // draw the dial itself
+ Arc2D arc = new Arc2D.Double(padding, padding, 2 * radius, 2 * radius, DIAL_START_OFFSET_DEGREES, DIAL_EXTENT_DEGREES, Arc2D.Double.OPEN);
+// Arc2D arc = new Arc2D.Double(padding, padding, 2 * radius, 2 * radius, dialMinValue, dialMaxValue, Arc2D.Double.OPEN);
+
+ g2.draw(arc);
+ //g.fillArc(35, 45, 75, 95, 0, 90);
+ g.setColor(java.awt.Color.BLUE);
+
+ // draw the little lines at the start and end of the dial
+ drawDialEnd(g2, Math.toRadians(DIAL_START_OFFSET_DEGREES));
+ drawDialEnd(g2, Math.toRadians(DIAL_START_OFFSET_DEGREES + DIAL_EXTENT_DEGREES));//start mark
+
+ float startMark = (DIAL_START_OFFSET_DEGREES + DIAL_EXTENT_DEGREES);
+ float endMark = DIAL_START_OFFSET_DEGREES;
+
+ // double angle = ((value / dialMaxValue) * DIAL_EXTENT_DEGREES);
+ if (DIAL_EXTENT_DEGREES != 90) {
+ angle = Math.toRadians((180 - (DIAL_START_OFFSET_DEGREES)) - (value * (DIAL_EXTENT_DEGREES / dialMaxValue)));//****ORIGINAL****
+ } else if (DIAL_EXTENT_DEGREES == 90) {
+ angle = Math.toRadians((180 - (90 - DIAL_START_OFFSET_DEGREES)) - (value * (DIAL_EXTENT_DEGREES / dialMaxValue)));//****ORIGINAL****
+
+ }
+ drawHand(g2, angle, handLength);
+ }
+
+ protected void drawDialEnd(Graphics2D g2, double angle) {
+ // calculate endpoint of line furthest from centre of dial
+ Point2D outerEnd = new Point2D.Double((radius + padding) + radius * Math.cos(angle),
+ (radius + padding) - radius * Math.sin(angle));
+ // calculate endpoint of line closest to centre of dial
+ Point2D innerEnd = new Point2D.Double((radius + padding) + ((radius + padding) * .8) * Math.cos(angle),
+ (radius + padding) - ((radius + padding) * .8) * Math.sin(angle));
+ // draw the line
+ g2.draw(new Line2D.Double(outerEnd, innerEnd));
+ //g2.draw(new Line2D.Double(outerEnd, innerEnd));
+ // g2.setColor(java.awt.Color.red);
+
+ }
+
+ /**
+ * Draw the hand on the dial to indicate the current value
+ *
+ * @param g2 - graphics object used to draw on the JPanel
+ * @param angle - the angle on the dial at which the hand is to point
+ * @param handLength - length of the hand
+ */
+ protected void drawHand(Graphics2D g2, double angle, double handLength) {
+ // calculate the outer end of the hand
+ Point2D end = new Point2D.Double((radius + padding) + handLength * Math.cos(angle), (radius + padding) - handLength * Math.sin(angle));
+
+ // Point2D end = outerEnd;
+// calculate the centre
+ Point2D center = new Point2D.Double(radius + padding, radius + padding);
+ // Draw the line
+ //g2.draw(new Line2D.Double(center, end));
+ g2.draw(new Line2D.Double(center, end));
+ }
+
+ /**
+ * Set the value to be displayed on the dial
+ *
+ * @param value value
+ */
+ public void setValue(int value) {
+ // don't let the value go over the maximum for the dial. But what about the minimum?
+ // this.value = (int) (value > dialMaxValue ? dialMaxValue : value);
+
+ try {
+ if (value <= dialMaxValue && value >= dialMinValue) {
+ this.value = value;
+ } else {
+ JOptionPane.showMessageDialog(this,
+ "Range needs to be between " + dialMinValue + " & " + dialMaxValue,
+ "Invalid range",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ repaint(); // causes paintComponent() to be called
+ } catch (Exception e) {
+ JOptionPane.showMessageDialog(this,e.getMessage());
+
+ }
+
+ }
+
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/Dial_HalfCircle.java b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_HalfCircle.java
new file mode 100644
index 0000000..9bd8327
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_HalfCircle.java
@@ -0,0 +1,23 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+/**
+ *
+ * @author st8511x
+ */
+//DIAL TYPE 2.
+public class Dial_HalfCircle extends Dial_FullCircle{//Child Class 1/3 of 270 deg.
+
+ public Dial_HalfCircle() {
+ super(100, 10, 45, 0);//radius, padding, max, pointValue
+ DIAL_EXTENT_DEGREES = 180;
+ DIAL_START_OFFSET_DEGREES = 0;
+ dialMinValue = 0;
+ // double angle = Math.toRadians((180 - (DIAL_START_OFFSET_DEGREES)) - (value * (DIAL_EXTENT_DEGREES / dialMaxValue)));//****ORIGINAL****
+
+ }
+}//CLASS
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/Dial_QuaterCircle.java b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_QuaterCircle.java
new file mode 100644
index 0000000..90c9233
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_QuaterCircle.java
@@ -0,0 +1,26 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+/**
+ *
+ * @author st8511x
+ */
+//DIAL TYPE 2.
+public class Dial_QuaterCircle extends Dial_FullCircle {//Child Class 1/3 of 270 deg.
+
+ public Dial_QuaterCircle() {
+ super(100, 10, 180, 0);//radius, padding, max, pointValue
+ DIAL_EXTENT_DEGREES = 90;
+ DIAL_START_OFFSET_DEGREES = 50;
+ dialMinValue = 0;
+
+ // super.paintComponent(g);
+ repaint();
+ //double angle = Math.toRadians(((90 - DIAL_START_OFFSET_DEGREES)) - (value * (DIAL_EXTENT_DEGREES / dialMaxValue)));//****ORIGINAL****
+ }
+
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/Dial_ThreeQuartersCircle.java b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_ThreeQuartersCircle.java
new file mode 100644
index 0000000..bc1f2cc
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/Dial_ThreeQuartersCircle.java
@@ -0,0 +1,31 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+
+/**
+ *
+ * @author st8511x
+ */
+//DIAL TYPE 2.
+public class Dial_ThreeQuartersCircle extends Dial_FullCircle{//Child Class 1/3 of 270 deg.
+
+ public Dial_ThreeQuartersCircle() {
+ super(100, 10, 500, 0);//radius, padding, max, pointValue
+ DIAL_EXTENT_DEGREES = 270;
+ DIAL_START_OFFSET_DEGREES = -45;
+ dialMinValue = 0;
+ // this.setBackground(Color.CYAN);
+ }
+
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/IIndicator.java b/src/uk/ac/gre/comp1549/dashboard/controls/IIndicator.java
new file mode 100644
index 0000000..9c6dcc0
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/IIndicator.java
@@ -0,0 +1,22 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import javax.swing.JOptionPane;
+
+/**
+ *
+ * @author st8511x
+ */
+public interface IIndicator {
+
+ void paintComponent(Graphics g);
+
+ void setValue(int value);
+ //the remaining methods in the base class full circle dial made more sense to be protected
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/IIndicatorPanel.java b/src/uk/ac/gre/comp1549/dashboard/controls/IIndicatorPanel.java
new file mode 100644
index 0000000..39ddaa8
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/IIndicatorPanel.java
@@ -0,0 +1,20 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import javax.swing.JLabel;
+
+/**
+ *
+ * @author st8511x
+ */
+//ALL PANELS MUST HAVE...
+public interface IIndicatorPanel {
+
+ void setLabel(String label);
+
+ void setValue(int value);
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/IndicatorFactory.java b/src/uk/ac/gre/comp1549/dashboard/controls/IndicatorFactory.java
new file mode 100644
index 0000000..223d716
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/IndicatorFactory.java
@@ -0,0 +1,42 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import com.sun.org.apache.xalan.internal.xsltc.dom.SingletonIterator;
+
+/**
+ *
+ * @author st8511x
+ */
+//IS IN CHARGE OF INSTANTIATING DESIRED OBJECTS BY USER
+public class IndicatorFactory {
+
+ //factory method
+ public IIndicator createIndicator(String Indicatortype) {
+ if (Indicatortype == null) {
+ return null;
+
+ } else if (Indicatortype.equalsIgnoreCase("full")) {
+
+ return Singleton.getDialTypeSingleton(Indicatortype);//Use of singleton of base class
+
+ } else if (Indicatortype.equalsIgnoreCase("threequater")) {
+ return Singleton.getDialTypeSingleton(Indicatortype);
+
+ } else if (Indicatortype.equalsIgnoreCase("half")) {
+ return Singleton.getDialTypeSingleton(Indicatortype);
+
+ } else if (Indicatortype.equalsIgnoreCase("quater")) {
+ return Singleton.getDialTypeSingleton(Indicatortype);
+
+ }
+ else{
+ return null;
+ }
+ }//factory method
+
+//INCLUDE BARRRRRRR
+}//factory
diff --git a/src/uk/ac/gre/comp1549/dashboard/controls/Singleton.java b/src/uk/ac/gre/comp1549/dashboard/controls/Singleton.java
new file mode 100644
index 0000000..448ae5b
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/controls/Singleton.java
@@ -0,0 +1,53 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package uk.ac.gre.comp1549.dashboard.controls;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author st8511x
+ */
+//ENSURES THAT ONLY A SINGLE INSTANCE OF INDICATOR IS ACTED UPON
+public class Singleton {
+
+ //static full dial is only newed up once
+ private static Dial_FullCircle fullDialSingleton = null;//static instance for singleton
+ private static Dial_ThreeQuartersCircle threequaterSingleton = null;//static instance for singleton
+ private static Dial_HalfCircle halfSingleton = null;//static instance for singleton
+ private static final Dial_QuaterCircle quaterSingleton = null;//static instance for singleton
+
+ private Singleton() {
+
+ }
+
+ //returns singleton of desired dial type by use
+ public static IIndicator getDialTypeSingleton(String dialType) {
+ IIndicator dial = null;
+
+ switch (dialType) {//conditional operators f
+ case "full":
+ dial = (fullDialSingleton == null) ? new Dial_FullCircle() : fullDialSingleton;
+ break;
+ case "threequater":
+ dial = (threequaterSingleton == null) ? new Dial_ThreeQuartersCircle() : threequaterSingleton;
+ break;
+ case "half":
+ dial = (halfSingleton == null) ? new Dial_HalfCircle() : halfSingleton;
+
+ break;
+ case "quater":
+ dial = (quaterSingleton == null) ? new Dial_QuaterCircle() : quaterSingleton;
+
+ break;
+ default:
+ dial = null;
+ }
+ return dial;
+ }
+
+}//singleton class
diff --git a/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEvent.java b/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEvent.java
new file mode 100644
index 0000000..166353e
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEvent.java
@@ -0,0 +1,34 @@
+package uk.ac.gre.comp1549.dashboard.events;
+
+/**
+ *Holds information about DashBoardEvents that can be
+ * passed to DashBoardEventListeners.
+ * @author COMP1549
+ */
+public class DashBoardEvent {
+
+ private String type; // type of event e.g "speed"
+ private String value; // value of the event e.g. "30"
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+ @Override
+ public String toString() {
+ return "type:" + type + " value:" + value;
+
+ }
+
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEventList.java b/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEventList.java
new file mode 100644
index 0000000..b1dc416
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEventList.java
@@ -0,0 +1,61 @@
+package uk.ac.gre.comp1549.dashboard.events;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Holds a Map the keys of which are types of DashBoardEvents (e.g type "speed)
+ * the values are the list of Listeners registered for that type of event.
+ *
+ * @author COMP1549
+ */
+public class DashBoardEventList {
+
+ // key is event type, value is list of listeners for that type
+ HashMap> eventListeners;
+
+ /**
+ * default constructor
+ */
+ public DashBoardEventList() {
+ eventListeners = new HashMap<>();
+ }
+
+ /**
+ * Add a DashBoardEventListener
+ *
+ * @param type - the type of event listened for (e.g "speed")
+ * @param listener - reference to the listener object
+ */
+ public void addListener(String type, DashBoardEventListener listener) {
+ List dbl = eventListeners.get(type);
+ if (dbl == null) { // if no listeners for this type already registered
+ dbl = new ArrayList<>(); // create a new list
+ }
+ dbl.add(listener); // add the listener to the list
+ eventListeners.put(type, dbl); // update the map
+ }
+
+ /**
+ * Remove a DashBoardEventListener
+ *
+ * @param type - the type of event listened for (e.g "speed")
+ * @param listener - reference to the listener object
+ */
+ public void removeListener(String type, DashBoardEventListener listener) {
+ List dbl = eventListeners.get(type);
+ if (dbl != null) { // if there are any listeners for the specified event type
+ while (dbl.remove(listener)); // remove listener looping in case more than one
+ }
+ }
+
+ /**
+ * Return a list of DashBoardEventListeners for a specified type of event
+ * @param type - the type of event for which listeners are required (e.g. "speed")
+ * @return - the list of listeners of the specified type
+ */
+ public List getListeners(String type) {
+ return eventListeners.get(type);
+ }
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEventListener.java b/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEventListener.java
new file mode 100644
index 0000000..02fbd27
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/events/DashBoardEventListener.java
@@ -0,0 +1,10 @@
+package uk.ac.gre.comp1549.dashboard.events;
+
+/**
+ * Interface implemented by classes that want to be notified of DashBoardEvents
+ * @author COMP1549
+ */
+public interface DashBoardEventListener {
+ public void processDashBoardEvent(Object originator, DashBoardEvent dbe);
+
+}
diff --git a/src/uk/ac/gre/comp1549/dashboard/scriptreader/DashboardEventGeneratorFromXML.java b/src/uk/ac/gre/comp1549/dashboard/scriptreader/DashboardEventGeneratorFromXML.java
new file mode 100644
index 0000000..dadacd6
--- /dev/null
+++ b/src/uk/ac/gre/comp1549/dashboard/scriptreader/DashboardEventGeneratorFromXML.java
@@ -0,0 +1,279 @@
+package uk.ac.gre.comp1549.dashboard.scriptreader;
+
+import javax.xml.parsers.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+import java.util.*;
+import java.io.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import uk.ac.gre.comp1549.dashboard.events.*;
+
+/**
+ * DashboardEventGeneratorFromXML reads and parses an XML file which holds a
+ * script of dashboard events (i.e. events that may cause a change in the value
+ * of a dashboard indicator). It generates DashBoardEvents which listeners can
+ * register to receive.
+ *
+ * @author COMP1549
+ * @version 3.0
+ */
+public class DashboardEventGeneratorFromXML extends DefaultHandler {
+
+ // constants used to control processing of the XML file
+ /**
+ * XML tag used to indicate a dashboard event
+ */
+ public final static String EVENT_TAG = "dashboard_event";
+
+ /**
+ * XML tag used to indicate the type of event
+ */
+ public final static String TYPE_TAG = "type";
+
+ /**
+ * XML tag used to indicate the value of event
+ */
+ public final static String VALUE_TAG = "value";
+
+ /**
+ * XML tag used to indicate the a time delay in the script
+ */
+ public final static String DELAY_TAG = "delay";
+
+ /**
+ * How many milliseconds each unit in a delay element is to cause the script
+ * to pause for. To speed up the script processing, decrease the number. To
+ * slow the script processing, increase the number.
+ */
+ public final static int delayUnits = 100; // 1000 = 1 second
+
+ // current event being processed
+ private DashBoardEvent currentEvent = null;
+ private String currentTag = ""; // current tag being processed
+
+ // list of listeners registered to receive dashboard events
+ private final DashBoardEventList dashBoardListeners;
+
+ // the xml parser object
+ private final XMLReader xmlReader;
+
+ /**
+ *
+ * @throws Exception - problem creating the parser
+ */
+ public DashboardEventGeneratorFromXML() throws Exception {
+ dashBoardListeners = new DashBoardEventList();
+
+ // The following code configures and creates an object known as a SAXParser which is capable of
+ // reading and interpreting an XML file.
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ SAXParser saxParser = spf.newSAXParser();
+ xmlReader = saxParser.getXMLReader();
+ }
+
+ /**
+ *
+ * @param filename - filename of the XML file to be processed
+ * @throws IOException - problem reading the file
+ * @throws SAXException - problem parsing the file
+ */
+ public void processScriptFile(String filename) throws IOException, SAXException {
+ // register the current object to receive callbacks when elements are encountered in the XML file
+ xmlReader.setContentHandler(this);
+ // Start the parsing process. As the file is processed methods in the startElement(), endElement() and
+ // characters() methods in the current object will be called to handle the content of the XML file.
+ xmlReader.parse(convertToFileURL(filename));
+ }
+
+ /**
+ * startElement() is called by the parser whenever a start tag (tag =
+ * element) is encountered in the XML file. Store the tag's name and if it
+ is an EVENT_tag create a new DashBoardEvent object that will be
+ populated with data by the character() method
+ *
+ * @param namespaceURI
+ * @param localName - the name of the tag e.g. "dashboard_event"
+ * @param atts
+ * @throws SAXException - problem parsing the file
+ */
+ @Override
+ public void startElement(String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+
+ currentTag = localName;
+
+ if (currentTag.equals(EVENT_TAG)) {
+ currentEvent = new DashBoardEvent();
+ }
+ }
+
+ /**
+ * characters() is called by the parser when character content is to be
+ * processed. Note that we need to check what type of tag is currently being
+ * processed in order to know what to do with the characters. For instance
+ * if we are processing a delay tag we want to pause processing for the
+ * specified amount of time.
+ *
+ * @param ch - array holding the characters to be processed
+ * @param start - start position of current characters within the array
+ * @param length - number of characters to process
+ * @throws SAXException
+ */
+ @Override
+ public void characters(char ch[], int start, int length)
+ throws SAXException {
+ // get the characters into a String and lose any unwanted whitespace
+ String val = new String(ch, start, length).trim();
+
+ if (val.length() < 1) { // is no characters to process (was all whitespace) just return
+ return;
+ }
+
+ // process the characters based on what type of tag we are currently dealing with.
+ switch (currentTag) {
+ case TYPE_TAG:
+ currentEvent.setType(val);
+ break;
+ case VALUE_TAG:
+ currentEvent.setValue(val);
+ break;
+ case DELAY_TAG:
+ pause(Integer.parseInt(val));
+ break;
+ }
+ }
+
+ /**
+ * endElement() is called by the parser when the end tag of an element is
+ * encountered. At that point know that we have finished processing that
+ * tag. The only situation we are interested in is when the end
+ * "dashboard_event" tag is found. At that [point we know that we have all
+ * the data for the event and can fire the event by creating the event
+ * object and passing it to all the listeners
+ *
+ * @param uri
+ * @param localName - the name of the tag e.g. "dashboard_event"
+ * @param qName
+ * @throws SAXException
+ */
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+
+ if (localName.equals(EVENT_TAG)) {
+ // get all listeners
+ List listeners = dashBoardListeners.getListeners(currentEvent.getType());
+ if (listeners != null) {
+ // loop through the listeners passing the event object to them - this is "firing" the event
+ for (DashBoardEventListener dbel : listeners) {
+ dbel.processDashBoardEvent(this, currentEvent);
+ }
+ }
+ currentEvent = null;
+ }
+ currentTag = "";
+ }
+
+ /**
+ *
+ * @param delay - the length of the delay
+ */
+ private void pause(int delay) {
+ try {
+ Thread.sleep(delay * delayUnits);
+ } catch (InterruptedException ex) {
+ Logger.getLogger(DashboardEventGeneratorFromXML.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /**
+ * registerDashBoardEventListener() is called by objects that want to be
+ * notified when a dashboard event occurs,
+ *
+ * @param type - type of the event listener is interested in (e.g. "speed")
+ * @param dbel - reference to the listener object
+ */
+ public void registerDashBoardEventListener(String type, DashBoardEventListener dbel) {
+ dashBoardListeners.addListener(type, dbel);
+ }
+
+ /**
+ * removeDashBoardEventListener() is called by objects that not longer want
+ * to be notified when a dashboard event occurs,
+ *
+ * @param type - type of the event listener wishes to deregister for (e.g.
+ * "speed")
+ * @param dbel - reference to the listener object
+ */
+ public void removeDashBoardEventListener(String type, DashBoardEventListener dbel) {
+ dashBoardListeners.removeListener(type, dbel);
+ }
+
+ /**
+ * convertToFileURL() is a utility method just used if DashboardDemoMain is
+ * run in standalone mode to test the class
+ *
+ * @param filename - name of the xml file
+ * @return filename in URL format e.g "file:///c:/files/file.xml"
+ */
+ private static String convertToFileURL(String filename) {
+ String path = new File(filename).getAbsolutePath();
+ if (File.separatorChar != '/') {
+ path = path.replace(File.separatorChar, '/');
+ }
+
+ if (!path.startsWith("/")) {
+ path = "/" + path;
+ }
+ return "file:" + path;
+ }
+
+ /**
+ * Output a help message to the user
+ */
+ private static void usage() {
+ System.err.println("Usage: DashboardEventGeneratorFromXML ");
+ System.err.println(" -usage or -help = this message");
+ System.exit(1);
+ }
+
+ /**
+ * main() method is only used if the class is run in standalone mode for testing purposes.
+ * @param args - last argument (args[length-1]) is the name of the xml file to process
+ * @throws Exception
+ */
+ public static void main(String[] args) throws Exception {
+ String filename = null;
+
+ // get the filename if persent
+ for (int i = 0; i < args.length; i++) {
+ filename = args[i];
+ if (i != args.length - 1) {
+ usage();
+ }
+ }
+
+ if (filename == null) {
+ usage();
+ }
+
+ // Create an instance of DashboardEventGeneratorFromXML and test it
+ DashboardEventGeneratorFromXML me = new DashboardEventGeneratorFromXML();
+ DashBoardEventListener dbel = new DashBoardEventListener() {
+ @Override
+ public void processDashBoardEvent(Object originator, DashBoardEvent dbe) {
+ System.out.println("***** " + dbe);
+ }
+ };
+ me.registerDashBoardEventListener("speed", dbel);
+ me.processScriptFile(filename);
+ me.removeDashBoardEventListener("speed", dbel);
+ me.processScriptFile(filename);
+ }
+}