UNB/ CS/ David Bremner/ teaching/ java/ PlotProducts.java
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import java.awt.geom.Ellipse2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class PlotProducts 
{  public static void main(String[] args)
   {  PlotProductsFrame frame = new PlotProductsFrame();
      frame.setTitle("Product Plot");
      frame.show();
   }
}   

class PlotProductsFrame extends JFrame
{  public PlotProductsFrame()
   {  final int DEFAULT_FRAME_WIDTH = 300;
      final int DEFAULT_FRAME_HEIGHT = 300;
      setSize(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);

      addWindowListener(new WindowCloser());
      
      // add panel to content pane
      
      Container contentPane = getContentPane();
   
      panel = new ProductPanel();
      contentPane.add(panel, "Center");
      
      // set menu items
      
      JMenuBar menuBar = new JMenuBar();
      setJMenuBar(menuBar);
      
      JMenu fileMenu = new JMenu("File");
      menuBar.add(fileMenu);

      MenuListener listener = new MenuListener();
      
      openMenuItem = new JMenuItem("Open");      
      fileMenu.add(openMenuItem);
      openMenuItem.addActionListener(listener);

      exitMenuItem = new JMenuItem("Exit");      
      fileMenu.add(exitMenuItem);
      exitMenuItem.addActionListener(listener);
   }
   

   /**
      Handles the open file menu. Prompts user for file
      name and reads products from file.
   */
   public void openFile()
   {  BufferedReader in = null;
      try
      {  // show file chooser dialog
      
         JFileChooser chooser = new JFileChooser();
         if (chooser.showOpenDialog(null) 
            == JFileChooser.APPROVE_OPTION)
         {  // construct reader and read products
         
            File selectedFile = chooser.getSelectedFile();   
            in = new BufferedReader
               (new FileReader(selectedFile));

            plotProducts(in);
         }
      }
      catch(FileNotFoundException e)
      {  JOptionPane.showMessageDialog
            (null, "Bad filename. Try again.");
      }
      catch(IOException e)
      {  JOptionPane.showMessageDialog
            (null, "Corrupted file. Try again.");
      }
      finally
      {  if (in != null) 
            try
            {   in.close();
            }
            catch(IOException e)
            {  JOptionPane.showMessageDialog
                  (null, "Error closing file.");
            }
      }
   }

   /**
      Reads products and adds them to the product panel.
      @param in the buffered reader to read from
   */
   public void plotProducts(BufferedReader in) 
      throws IOException
   {  panel.clearProducts();
      boolean done = false;
      while (!done)
      {  Product p = new Product();
         if (p.read(in))
            panel.addProduct(p);
         else // last product read
            done = true;
      }
   }
       
   private JMenuItem openMenuItem;
   private JMenuItem exitMenuItem;
   private ProductPanel panel;

   private class MenuListener implements ActionListener
   {  public void actionPerformed(ActionEvent event)
      {  Object source = event.getSource();
         if (source == openMenuItem) openFile();
         else if (source == exitMenuItem) System.exit(0);
      }
   }

   private class WindowCloser extends WindowAdapter
   {  public void windowClosing(WindowEvent event)
      {  System.exit(0);
      }
   }
}

class ProductPanel extends JPanel 
{  public ProductPanel()
   {  final int PRODUCTS_LENGTH = 100;
      products = new Product[PRODUCTS_LENGTH];
      productsSize = 0;   
   }

   public void paintComponent(Graphics g)
   {  super.paintComponent(g);
      Graphics2D g2 = (Graphics2D)g;
      
      // compute price range
      
      if (productsSize == 0) return; // nothing to plot
      double minPrice = products[0].getPrice();
      double maxPrice = products[0].getPrice();
      
      for (int i = 1; i < productsSize; i++)
      {  double price = products[i].getPrice();
         if (price < minPrice) minPrice = price;
         if (price > maxPrice) maxPrice = price;
      }
      
      final int MAX_SCORE = 100;      
      
      UnitConverter units 
         = new UnitConverter(minPrice, maxPrice, 
            0, MAX_SCORE, getWidth(), getHeight());
            
      // draw a labeled point for each product            
            
      for (int i = 0; i < productsSize; i++)
      {  Product p = products[i];

         double x = units.xToPixel(p.getPrice());
         double y = units.yToPixel(p.getScore());

         final double SMALL_CIRCLE_RADIUS = 2;

         Ellipse2D.Double circle = new Ellipse2D.Double(
            x - SMALL_CIRCLE_RADIUS,
            y - SMALL_CIRCLE_RADIUS,
            2 * SMALL_CIRCLE_RADIUS,
            2 * SMALL_CIRCLE_RADIUS);

         g2.draw(circle);
         g2.drawString(p.getName(), (float)x, (float)y);
      }
   }

   /**
      Clears all products from the graph and repaints it.
   */
   public void clearProducts()   
   {  productsSize = 0;
      repaint();
   }

   /**
      Adds a new product to the graph and repaints it.
      @param p the product to add
   */
   public void addProduct(Product p)   
   {  if (productsSize < products.length)
      {  products[productsSize] = p;
         productsSize++;
      }
      repaint();
   }
   
   private Product[] products;
   private int productsSize;  
}