import java.awt.geom.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.io.*;
import java.util.*;

/** DemoList3 - similar to <code>DemoList</code> and
* <code>DemoList2</code> except
* using a paint panel to present the quotation.<p>
*
* In this demo
* we define a <code>PaintPanel</code>
* class -- an extension of <code>JPanel</code> -- in which to "paint"
* the quotation.  The result is much the same as in <code>DemoList2</code>
* however the possibilities for embellishing the presentation of the quotation
* are greatly enhanced by using Java's graphics primitives.<p>
*
* Screen snap...<br>
* <center><img src="DemoList3-1.gif"></center><p>
*
* @see <a href="DemoList3.java">source code</a>
* @see <a href="quotations.txt">quotations.txt</a>
* @author Scott MacKenzie, 2002
*/
public class DemoList3
{
   public static void main(String[] args)
   {
      if (args.length != 1)
      {
         System.out.println("usage: java DemoList file");
         System.exit(0);
      } 

      // Hmmm... Java L&F looks better
      //try {
      //   UIManager.setLookAndFeel(
      //      UIManager.getSystemLookAndFeelClassName());
      //} catch (Exception e) {}

      DemoList3Frame frame = new DemoList3Frame(args[0]);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("DemoList3");
      frame.pack();
      frame.show();
   }
}

class DemoList3Frame extends JFrame implements ListSelectionListener
{
   private PaintPanel quotePanel;
   private JList quoteList;
   private Quotation[] q;

   public DemoList3Frame(String fileName)
   {
      final Color FOREGROUND = Color.blue;
      final Color BACKGROUND = Color.pink;
      final Font DEFAULT_FONT = new Font("Serif", Font.PLAIN, 18);

      // get the quotes from a file and place in a Quotation array

      q = getQuotes(fileName);

      // exit if q is null (Note: an error message was sent to the console)

      if (q == null)
         System.exit(0);

      // ----------------------------------
      // construct and configure components
      // ----------------------------------

      quotePanel = new PaintPanel();
      quotePanel.setBackground(BACKGROUND);
      quotePanel.setForeground(FOREGROUND);
      quotePanel.setBorder(BorderFactory.createLineBorder(Color.black));
      quotePanel.setPreferredSize(new Dimension(400, 100));

      // create a JList of quotations

      quoteList = new JList(q);
      quoteList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      quoteList.setSelectedIndex(0);

      // put the JList in a JScrollPane

      JScrollPane quoteScrollPane = new JScrollPane(quoteList);
      quoteScrollPane.setPreferredSize(new Dimension(400, 100));
      quoteScrollPane.setBorder(BorderFactory.createLineBorder(Color.black));

      // -------------
      // add listeners
      // -------------

      quoteList.addListSelectionListener(this);

      // -----------------
      // layout components
      // -----------------

      JPanel contentPane = new JPanel();
      contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
      contentPane.add(quoteScrollPane);
      contentPane.add(Box.createRigidArea(new Dimension(0, 10)));
      contentPane.add(quotePanel);
      contentPane.setBorder(BorderFactory.createEmptyBorder(30, 30, 30, 30));

      // make panel this JFrame's content pane

      this.setContentPane(contentPane);
   }

   // --------------------------------------
   // implement ListSelectionListener method
   // --------------------------------------

   public void valueChanged(ListSelectionEvent lse)
   {
      int idx = quoteList.getSelectedIndex();

      quotePanel.drawQuotation(q[idx].getQuote(), q[idx].getName());
      this.setTitle("DemoList3 - quote from " + q[idx].getName());
   }

   // -------------
   // other methods
   // -------------

   /** Yet another do-the-dirty-work-here method.  Open the specified
   * file, read the quotations, and place them into a
   * <code>Quotation</code> array.<p>
   *
   * Each line in the quotations file contains a quotation and the name
   * of the person credited with the quotation.  A backward slash separates
   * the quotation from the name.<p>
   *
   * @param fileArg a string specifying the name of the file containing the
   * quotations
   * @return a reference to an array of <code>Quotation</code> objects, or
   * <code>null</code> if an error was encountered opening or reading the
   * file.
   */
   public Quotation[] getQuotes(String fileArg)
   {
      // prepare to read the quotations from a disk file
      BufferedReader br = null;
      try
      {
         br = new BufferedReader(new FileReader(fileArg));
      } catch (FileNotFoundException e)
      {
         System.out.println("File not found: " + fileArg);
         return null;
      }

      String line = null;
      Vector v = new Vector();
      StringTokenizer st;
      while (true)
      {
         try
         {
            line = br.readLine();
         } catch (IOException e)
         {
            System.out.println("Error reading file: " + fileArg);
            return null;
         }

         if (line == null)
            break;

         st = new StringTokenizer(line, "\\");

         // exactly two entries per line required
         if (st.countTokens() != 2)
         {
            System.out.println("Data format error in file: " + fileArg);
            return null;
         }

         // get the quotation and name
         String quotation = st.nextToken();
         String name = st.nextToken();

         // add to vector as a Quotation object
         v.addElement(new Quotation(quotation, name));
      }

      // initialize quotation array with just the right amount of space
      Quotation[] tmp = new Quotation[v.size()];

      // copy elements from vector into array
      v.copyInto(tmp);

      // return a reference to the quotation array (whew!)
      return tmp;
   }

   // -------------
   // inner classes
   // -------------

   /** A simple inner class to store a quotation
   */
   class Quotation
   {
      private String quote;
      private String name;

      Quotation(String quoteArg, String nameArg)
      {
         quote = quoteArg;
         name = nameArg;
      }

      public String getName()  { return name; }
      public String getQuote() { return quote; }
      public String toString() { return quote + " --" + name; }
   }

   /** simple paint panel class
   */
   class PaintPanel extends JPanel
   {
      private String quote;
      private String name;
      private String leader;

      PaintPanel()
      {
         quote = "";
         name = "";
         leader = "";
      }

      public void paintComponent(Graphics g)
      {
         super.paintComponent(g);
         Graphics2D g2 = (Graphics2D)g;

         // font characteristics for quote
         g2.setColor(Color.blue);
         g2.setFont(new Font("Serif", Font.ITALIC, 24));

         FontMetrics fm = g2.getFontMetrics();

         int width = fm.stringWidth(quote); // width of quote (in pixels)
         int height = fm.getHeight();       // of characters (for given font)
         int w = this.getWidth();           // width of panel
         int h = this.getHeight();          // height of panel

         // draw the quote string in the middle of the panel
         g2.drawString(quote, w/2 - width/2, h/2);

         // change the appearance of the name
         g2.setFont(new Font("Serif", Font.PLAIN, 20));

         // draw the name string below the quote and offset a bit
         g2.drawString(leader + name, w/2 - width/2, h/2 + height); 
      }

      public void drawQuotation(String quoteArg, String nameArg)
      {
         quote = quoteArg;
         name = nameArg;
         leader = "   --";
         this.repaint();
      }
   }
}

