import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.util.*;

/** DemoList - program to demonstrate <code>JList</code>.<p>
*
* A list of quotations is displayed using <code>JList</code>.  The
* user selects a quotation and it appears in a separate text field.<p>
*
* Creating a <code>JList</code> is straight forward.  However,
* <code>JList</code> does not support scrolling directly; so,
* we also instantiate a <code>JScrollpane</code> object and make
* the <code>JList</code> its viewport.<p>
*
* This program uses a command-line argument to specify the name of the
* file containing the quotations.  This argument is passed on to the
* constructor of our extended <code>JFrame</code> class.  The file
* is opened and the quotations are read into a <code>Quotation</code>
* array.
* A simple inner class named <code>Quotation</code> is defined to store
* a quotation.<p>
*
* Although <code>JList</code> allows multiple items to be selected,
* this demo limits selection to a single item:<p>
*
* <pre>
*     quoteList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
* </pre>
*
* A <code>JList</code> fires a <i>list selection event</i> when an
* item is selected in the list.  Our application is setup to process these
* events by adding a list selection listener to the <code>JList</code>
* component:
* <p>
*
* <pre>
*     quoteList.addListSelectionListener(this);
* </pre>
*
* The extend <code>JFrame</code> containing the <code>JList</code>
* must include "implements ListSelectionListener" in its signature
* and it must implement the <code>valueChanged</code> method of
* the <code>ListSelectionListener</code>.<p>
*
* One small feature demonstrated in this program is dynamic updating
* of the application window's titlebar text.
* When a new quote is selected, the titlebar
* is updated with "DemoList - quote by <i>name</i>",
* where <i>name</i> is the
* person credited with the quotation.  Updating the quotation and
* the titlebar are performed in the <code>valueChanged</code> method
* as follows:<p>
*
* <pre>
*     Quotation q = (Quotation)quoteList.getSelectedValue();
*     quoteField.setText(q.toString());
*     this.setTitle("DemoList - quote from " + q.getName());
* </pre>
*
* Screen snap...<br>
* <center><img src="DemoList-1.gif"></center><p>
*
* @see <a href="DemoList.java">source code</a>
* @see <a href="quotations.txt">quotations.txt</a>
* @author Scott MacKenzie, 2002
*/
public class DemoList
{
   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) {}

      DemoListFrame frame = new DemoListFrame(args[0]);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("DemoList");
      frame.pack();
      frame.show();
   }
}

class DemoListFrame extends JFrame implements ListSelectionListener
{
   private JTextField quoteField;
   private JList quoteList;
   private Quotation[] q;

   public DemoListFrame(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
      // ----------------------------------

      quoteField = new JTextField("(please select a quotation)");
      quoteField.setFont(DEFAULT_FONT);
      quoteField.setEditable(false);
      quoteField.setBackground(BACKGROUND);
      quoteField.setForeground(FOREGROUND);
      quoteField.setBorder(BorderFactory.createLineBorder(Color.black));
      quoteField.setHorizontalAlignment(SwingConstants.CENTER);
      quoteField.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(quoteField);
      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)
   {
      Quotation q = (Quotation)quoteList.getSelectedValue();
      quoteField.setText(q.toString());
      this.setTitle("DemoList - quote from " + q.getName());
   }

   // -------------
   // other methods
   // -------------

   /** Yet another do-the-dirty-work-here method.  Open the specified
   * file, read the quotations, and place them in 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;

         if (line.length() == 0)
            continue;

         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 class
   // -----------

   /** 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; }
   }
}

