import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.util.*;

/** DemoTable - demo of <code>JTable</code>.<p>
*
* In designing a demo of <code>JTable</code>, one of the first
* decisions is on
* the location of the data to present in the table.  Rather than
* reading a small data set embedded within the source code, this demo
* reads data from an external text file.  The file is
* specified using a command-line
* argument.<p>
*
* Each line in the data file must contain
* the same number of entries. 
* If the data file contains ten entries per line, for example, the resulting
* table will have ten columns.
* The number of rows in the table equals the number of lines read from
* the data file.
* <p>
*
* The <code>StringTokenizer</code> class in the <code>java.util</code>
* package is used to separate the entries on each line.  By default,
* <code>StringTokenizer</code> uses the delimiter set
* <code>" \t\n\r\f"</code>.  However, this can be changed for this demo
* via the <code>-d</code> command-line option.  See below for examples.<p>
*
* If the first row of the data file contains the column header names,
* an additional command-line argument can be appended (<code>-h</code>)
* to use these as column names in the table.
* If column names are not included in the data file, generic names
* are used (<code>A</code>, <code>B</code>, etc.)<p>
*
* Four invocations of the application are demonstrated below.  The first
* just shows a usage message. 
* The second uses the data set
* <code>worldrecordsmen.txt</code>, containing the current men's world
* records in athletics (see <code>http://www.iaaf.com/</code>).  Each row
* contains six comma-delimited data entries.  Additionally, the first
* row contains six comma-delimited entries for the column names.<p>
*
* The second invocation uses <code>quotations.txt</code>, the data set
* used 
* earlier with <code>DemoList</code>.  A backslash character delimits each
* quotation from the person credited with the quotation.  Column names are
* not included.<p>
*
* The third invocation uses <code>d1-wordfreq.txt</code>, a list
* of words and their frequencies in the English language.  The list was
* derived from the British National Corpus
* (see <code>ftp://ftp.itri.bton.ac.uk/bnc/</code>).  The entries are
* space delimited.  Column names are not included.<p>
*
* Example invocation showing usage message:<p>
*
* <pre>
*     PROMPT>java DemoTable
*     usage: java DemoTable file [-dc] [-h]
*     
*     where file  = file containing data to place in table
*           [-dc] = use delimiter character(s) c for row entries
*           [-h]  = first line in file contains column header names
* </pre>                         
*
* Invocations and screen snaps with example data sets...<p>
*
* <code>PROMPT>java DemoTable worldrecordsmen.txt -d, -h<br>
* <center><img src="DemoTable-1.gif"></center><p>
*
* PROMPT>java DemoTable quotations.txt -d\<br>
* <center><img src="DemoTable-2.gif"></center><p>
*
* PROMPT>java DemoTable d1-wordfreq.txt        (resized)
* <center><img src="DemoTable-3.gif"></center><p>
* </code>
*
* @see <a href="DemoTable.java">source code</a>
* @see <a href="worldrecordsmen.txt">worldrecordsmen.txt</a>
* @see <a href="worldrecordswomen.txt">worldrecordswomen.txt</a>
* @see <a href="quotations.txt">quotations.txt</a>
* @see <a href="d1-wordfreq.txt">d1-wordfreq.txt</a>
* @author Scott MacKenzie, 2002
*/
public class DemoTable
{
   public static void main(String[] args)
   {
      // 1-3 command-line args required

      if (args.length < 1 || args.length > 3)
      {
         System.out.println(
            "usage: java DemoTable file [-dc] [-h]\n\n" +
            "where file  = file containing data to place in table\n" +
            "      [-dc] = use delimiter character(s) c for row entries\n" +
            "      [-h]  = first line in file contains column header names"
         );
         System.exit(0);
      }

      // get command-line arguments

      String fileName = args[0];

      boolean headerOption = false;
      String delimiterString = " \t\n\r\f"; // default for StringTokenizer

      for (int i = 1; i < args.length; ++i)
      {
         if (args[i].indexOf("-d") == 0 && args[i].length() > 2)
            delimiterString = args[i].substring(2);

         if (args[i].equals("-h"))
            headerOption = true;
      }

      // prepare to read data file

      BufferedReader br = null;
      try
      {
         br = new BufferedReader(new FileReader(fileName));
      } catch (FileNotFoundException e)
      {
         System.out.println("File not found: " + fileName);
         System.exit(1);
      }

      StringTokenizer st;
      String line = null;
      int first = 0;
      int n = 0;

      // verify that each row contains the same number of elements

      while (true)
      {
         try
         {
            line = br.readLine();
         }
         catch (IOException e)
         {
            System.out.println("Error reading data file");
            System.exit(1);
         }
         if (line == null) break;

         st = new StringTokenizer(line, delimiterString);
         n = st.countTokens();
         if (first == 0) first = n;
         if (n != first)
         {
            System.out.println("Data format error!");
            System.exit(1);
         }
      }

      // close file

      try
      {
         br.close();
      } catch (IOException e) {}

      // re-open file

      try
      {
         br = new BufferedReader(new FileReader(fileName));
      } catch (FileNotFoundException e) {}

      // read the column names into a Vector (if -h option)

      Vector columnNames = new Vector();
      if (headerOption)
      {
         try
         {
            line = br.readLine();
         }
         catch (IOException e)
         {
            System.out.println("Error reading data file");
            System.exit(1);
         }
         if (line == null) return;

         st = new StringTokenizer(line, delimiterString);
         while (st.hasMoreTokens())
            columnNames.add(st.nextToken());
      }

      // read the row data into a Vector of Vectors

      Vector rowData = new Vector();
      Vector tmp;
      while (true)
      {
         try
         {
            line = br.readLine();
         }
         catch (IOException e)
         {
            System.out.println("Error reading data file");
            System.exit(1);
         }
         if (line == null) break;

         tmp = new Vector();
         st = new StringTokenizer(line, delimiterString);
         while (st.hasMoreTokens())
            tmp.add(st.nextToken());
         rowData.add(tmp);
      }

      // use generic column names, if necessary

      if (!headerOption)
      {
         for (int i = 0; i < n; ++i)
            columnNames.add("" + (char)('A' + i));
      }

      // OK, we're ready to build the GUI with the data in a JTable

      DemoTableFrame frame = new DemoTableFrame(rowData, columnNames);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("DemoTable");
      frame.pack();
      frame.show();
   }
}

class DemoTableFrame extends JFrame
{
   public DemoTableFrame(Vector rowData, Vector columnNames)
   {
      // -------------------------------
      // create and configure components
      // -------------------------------

      JTable t = new JTable(rowData, columnNames);
      t.setPreferredScrollableViewportSize(new Dimension(600, 200));

      JScrollPane sp = new JScrollPane(t);
      //sp.setPreferredSize(new Dimension(600, 200));

      // put components in a panel

      JPanel p = new JPanel(new BorderLayout());
      p.add(sp, "Center");

      // make panel this JFrame's content pane

      this.setContentPane(p);
   }
}

