Sorting a bound JTable

I posted a question about this a week or so ago and it was determined that I needed to override some methods in JUTableSortModel. I'm posting again because I'm at a loss for which methods to override. I do have a method of sorting in mind.
My problem was that once a header is clicked in a JClient table, selection of rows is disabled. It was determined that Oracle simply didn't feel like implementing this, so I would need to extend their JUTableSortModel. My plan is to listen for clicks on the table, find out which header it was on, and add that header's name to the OrderBy clause of the view object. Should I override addMouseListenerToHeaderInTable in the TableSortModel class, or simply add a mouse listener to the table itself in my UI?

spaist - thanks for posting your code. I found it very helpful. Here's generalized version that can be used with any ADF-bound JTable.
Note that like your code we toggle back and forth between DESC and ASC. If you double click a column sorting is turned off (but I haven't specialized the double click listener so the query actually gets executed twice for double clicks).
If someone out there wants to expand this and make a nice little Strategy pattern that's easier to implement please post your code.
import com.sun.java.util.collections.ArrayList;
import com.sun.java.util.collections.Iterator;
import java.awt.Event;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.table.TableColumnModel;
import oracle.jbo.AttributeDef;
import oracle.jbo.AttributeHints;
import oracle.jbo.LocaleContext;
import oracle.jbo.ViewObject;
import oracle.jbo.common.DefLocaleContext;
public class TableHeaderSortListener extends MouseAdapter
  private ViewObject vo;
  private TableColumnModel tcm;
  private ArrayList sortList;
  private String orderBy = "";
  private LocaleContext locale;
  public TableHeaderSortListener(ViewObject v, TableColumnModel cm)
    sortList = new ArrayList();
    locale =  new DefLocaleContext();
    vo = v;
    tcm = cm;
  public void mouseClicked(MouseEvent e)
    String columnName = (String)tcm.getColumn(tcm.getColumnIndexAtX(e.getX())).getHeaderValue();
    AttributeDef[] ad = vo.getAttributeDefs();
    String sSortList = "";
    for (int j = 0; j < ad.length; j++)
      AttributeHints ah = ad[j].getUIHelper();
      if (columnName.equals(ah.getLabel(locale)))
        orderBy = ad[j].getColumnName();
        if (!sortList.isEmpty())
          if (sortList.contains(orderBy))
            sortList.remove(orderBy);
            orderBy += " DESC";                       
          } else if (sortList.contains(orderBy + " DESC"))
            sortList.remove(orderBy + " DESC");
        sortList.add(orderBy.toUpperCase());
        break;
    if (e.getClickCount() > 1)
      sortList.remove(orderBy.toUpperCase());
    if (sortList.size()>1) {
      sSortList = join(sortList, ","); 
    } else if (sortList.size()>0)
      sSortList = sortList.get(0).toString();
    // Last little check
    if (sortList.size() > 0)
      vo.setOrderByClause(sSortList);     
    } else
      vo.setOrderByClause(null);
    vo.executeQuery();
   * Join()
   * Similar to the Perl function
   * @return String
   * @param token
   * @param st
  public String join(ArrayList st, String token)
    StringBuffer sb = new StringBuffer();
    Iterator it = st.iterator();
    while (it.hasNext())
      sb.append(it.next() + token);
    sb.replace(sb.length()-1, sb.length(), "");
    return sb.toString();
}You can import this into classes which contain JTables and refer to it as follows (first you have to follow Frank's advice and turn off the default JUTableSortModel)
jbinit(){
    removeTableHeaderMouseListeners();
    TableHeaderSortListener ths = new TableHeaderSortListener(panelBinding.findIterBinding("<YOUR_ITERATOR>").getViewObject(), <YOUR_TABLE>.getColumnModel());
    <YOUR_TABLE>.getTableHeader().addMouseListener(ths);
   public void removeTableHeaderMouseListeners()
        MouseListener[] ml = <YOUR_TABLE>.getTableHeader().getMouseListeners();
    for (int j = 0; j < ml.length; j++)
        // Note - the name of your JUTableSortModel may be slightly differnet
        if (ml[j].getClass().toString().indexOf("oracle.jbo.uicli.jui.JUTableSortModel$1")>-1)
        <YOUR_TABLE>.getTableHeader().removeMouseListener(ml[j]);
  }

Similar Messages

  • Programmatically Sorting columns in JTable

    Hi,
    How can I programmatically sort a particular column in JTable without having to click on column header.
    Thanks.

    to sort the desired column w/o click on header
    int columnIndexToSort = 1;
    RowSorter.SortKey sortKey = new RowSorter.SortKey(columnIndexToSort,SortOrder.ASCENDING);
    ArrayList alist = new ArrayList(1);
    alist.add(sortKey);
    ((DefaultRowSorter)table.getRowSorter()).setSortable(columnIndexToSort , true);
    ((DefaultRowSorter)table.getRowSorter()).setSortKeys(alist);
    ((DefaultRowSorter)table.getRowSorter()).sort();expecting dukestars..

  • Sorting Columns in JTable Using Different Comparators

    Is there any way to sort each column in a JTable using different comparators?

    you'll have to write your own tableSorter

  • Sort rows in JTable except the last row

    Hi All,
    I have a JTable, which contains columns with numbers. The last row contains column sums.
    I want to be able to sort rows, but the last row with sums must remain motionless.
    Does anyone know the solution of this problem?
    Thanks in advance.

    These two posts are my example. It works pretty good but there is one significant niggle - when moving a column the 'total' table does not move smoothly but it does move. I look forward to 'camickr' reducing this to about 1 line.
    Part A.
    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.Font;
    import java.text.DecimalFormat;
    import java.util.Comparator;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.TableColumnModelEvent;
    import javax.swing.event.TableColumnModelListener;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.JTableHeader;
    import javax.swing.table.TableColumnModel;
    import javax.swing.table.TableModel;
    import javax.swing.table.TableRowSorter;
    public class Sabre20090331
        static private class TotalizingTableComponent extends JScrollPane
            private TotalizingTableComponent(final TableModel tableModel)
                final SecondaryTableModel secondaryTableModel = new SecondaryTableModel(tableModel);
                final JTable secondaryTable = new JTable(secondaryTableModel);
                for (int i = 1; i < secondaryTableModel.getColumnCount(); i++)
                    secondaryTable.getColumnModel().getColumn(i).setCellRenderer(new NumberCellRenderer());
                secondaryTable.getColumnModel().getColumn(0).setCellRenderer(new TitleCellRenderer());
                final TableColumnModel secondaryTableColumnModel = secondaryTable.getColumnModel();
                secondaryTable.setRowSelectionAllowed(false);
                final JTable primaryTable = new JTable(tableModel);
                for (int i = 1; i < tableModel.getColumnCount(); i++)
                    primaryTable.getColumnModel().getColumn(i).setCellRenderer(new NumberCellRenderer());
                final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel);
                final DoubleComparator doubleComparator = new DoubleComparator();
                for (int i = 1; i < tableModel.getColumnCount(); i++)
                    sorter.setComparator(i, doubleComparator);
                primaryTable.setRowSorter(sorter);
                primaryTable.getColumnModel().addColumnModelListener(new TableColumnModelListener()
                    @Override
                    public void columnAdded(TableColumnModelEvent e)
                        // System.out.println("columnAdded()" + e);
                    @Override
                    public void columnRemoved(TableColumnModelEvent e)
                        // System.out.println("columnRemoved()" + e);
                    @Override
                    public void columnMoved(TableColumnModelEvent e)
                        //System.out.println("columnMoved()" + e);
                        secondaryTableColumnModel.moveColumn(e.getFromIndex(), e.getToIndex());
                    @Override
                    public void columnMarginChanged(ChangeEvent e)
                        //System.out.println("columnMarginChanged()" + e);
                        final TableColumnModel cm = (TableColumnModel) e.getSource();
                        for (int i = 0; i < cm.getColumnCount(); i++)
                            secondaryTableColumnModel.getColumn(i).setPreferredWidth(cm.getColumn(i).getWidth());
                    @Override
                    public void columnSelectionChanged(ListSelectionEvent e)
                        //System.out.println("columnSelectionChanged()" + e);
                final JTableHeader primaryHeader = primaryTable.getTableHeader();
                JPanel inner = new JPanel(new BorderLayout());
                this.setColumnHeaderView(primaryHeader);
                this.setViewportView(inner);
                inner.add(primaryTable, BorderLayout.NORTH);
                inner.add(secondaryTable, BorderLayout.CENTER);
            public static void main(String[] args)
                final JFrame frame = new JFrame("Totalizing JTable Example");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                final TableModel tableModel = new PrimaryTableModel();
                frame.setContentPane(new TotalizingTableComponent(tableModel));
                frame.pack();
                frame.setVisible(true);
    }Edited by: sabre150 on Apr 1, 2009 9:21 AM
    Changed the layout of the inner panel so that the secondary table is now in the CENTER. This stops the secondary table becoming detached from the primary when one expands the frame beyond the prefferred size.

  • Sorting array of jtables

    Hi all
    I have a JFrame with 5 JTables on it. I would like to order it as follows:
    JTable where cell(0,0) has the least value must be first on the JFrame.
    JTable where cell(0,0) has the second least value must be second.
    till
    JTable where cell(0,0) has the most value must be last on the JFrame.
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.table.*;
    public class TestTable extends JFrame{
    JTable[] table = new JTable[5];
    TableModel[] model = new TableModel[5];
    JPanel pane = new JPanel();
    int m=0;
    public TestTable(){
    super();
    for(int k=0;k<5;k++){
    model[k] = new AbstractTableModel(){
    public boolean isCellEditable(int row, int col){
         return false;
    public int getColumnCount () {
    return 2;
    public int getRowCount () {
    return 2;
    public Object getValueAt (int row, int col) {
    m=m+2;
    return new Integer ((row*col)+m);
    table[k] = new JTable (model[k]);
    table[k].setColumnSelectionAllowed(false);
    table[k].setRowSelectionAllowed(false);
    table[k].setEnabled(false);
    pane.add(table[k]);
    m=m+2;
    setContentPane(pane);
    public static void main(String[] args){
    TestTable f = new TestTable();
    f.pack();
    f.setBounds(new Rectangle(20,20,200,300));
    f.setVisible(true);
    Thanks
    Chris

    Hi,
    have a look at Arrays.sort(Object[] a)
    http://java.sun.com/j2se/1.4.2/docs/api/java/util/Arrays.html

  • How do i change the cursor on a jtable header when clicked for sorting?

    here is my question, how do i change the cursor on a jtable header when I click the header for sorting?
    I think it is suppose to be in the fragment of code where the header listener is implemented for sorting, but I'm not quite sure what is the exact component that holds everything so that i can change the cursor...
    below is what I've tried, but it doesn't seem to work... thank you
    public void addMouseListenerToHeaderInTable(JTable table) {
    final TableSorter sorter = this;
    final JTable tableView = table;
    tableView.setColumnSelectionAllowed(false);
    MouseAdapter listMouseListener = new
    MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    TableColumnModel columnModel =
    tableView.getColumnModel();
    int viewColumn =
    columnModel.getColumnIndexAtX(e.getX());
    int column =
    tableView.convertColumnIndexToModel
    (viewColumn);
    System.out.println("column = "+column);
    if (e.getClickCount() == 1 && column != -1) {
    System.out.println("Sorting ...");
    Cursor oldCursor =
    tableView.getRootPane().getCursor();
    System.out.println("oldCursor.getType()
    = "+oldCursor.getType());
    if (oldCursor.getType() !=
    Cursor.WAIT_CURSOR){
    JComponent parentPane =
    tableView.getRootPane();
    parentPane.getContentPane().setCursor
    (new Cursor(Cursor.WAIT_CURSOR));
    parentPane.setCursor(new Cursor
    (Cursor.WAIT_CURSOR));
    Cursor newCursor =
    parentPane.getCursor();
    System.out.println("newCursor.getType
    () = "+newCursor.getType());
    int shiftPressed = e.getModifiers(
    &InputEvent.SHIFT_MASK;
    boolean ascending = (shiftPressed == 0);
    //System.out.println("tableView.getRootPane()
    is "+tableView.getRootPane().getRootPane());
    sorter.sortByColumn(column, ascending);
    tableView.getRootPane().setCursor(new Cursor
    (Cursor.DEFAULT_CURSOR));
    //System.out.println("Done sorting");
    JTableHeader th = tableView.getTableHeader();
    th.addMouseListener(listMouseListener);
    }

    Hi,
    Try setting the cursor for the table header.
    table.getHeader().setCursor(Wait_Cursor);
    Bala.

  • JTable sorting and filtering

    I want to sort and Filter JTable.
    Sample code is avialable for this ?.
    Also i would like to know about 3rd party classes.
    Renjith

    Hi,
    There is a such sample on the tutorials for swing/JTable. In this tutorial, u will find 2 files and then make the corresponding classes :
    TableMap and TableSorter
    u can use them like this :
    TableSorter sorter = new TableSorter(myModel);
    //JTable table = new JTable(myModel); //OLD
    JTable table = new JTable(sorter);
    sorter.addMouseListenerToHeaderInTable(table);
    It is very simple, and you can easily modifie these classes to add filters..
    Regards, JFB

  • Unable to sort the content of the jTable

    Hi all ,
    I m using this code for sorting in the Jtable
    JTable table = new JTable(new MyTable());
            table.setPreferredScrollableViewportSize(new Dimension(500,500));
            table.setFillsViewportHeight(true);
            table.setAutoCreateRowSorter(true);Where MyTable --> is the AbstractTableModel.
    Im using LookAndFeel -- com.birosoft.liquid.
    With this lookandfeel , when I click the columnheader , it is not sorting :(
    But when I change the lookandfeel as default it is working.
    Can anybody tell what Im doing wrong. or is there any method through which I can sort with com.birosoft lookandfeel
    Thanks and regards
    Anshuman Srivastava

    Thaks for advice .
    I have checked their API , theere is some bug for sorting it.
    So what I have done . this JTable I opened in a Jdialog , for which I have made the lookandfeel as default.
    This code when I making the JDialog
    try{
                   UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
              catch(Exception e){}
              panel = new JPanel();Now when closing the JDialog , Im making resetting the lookandfeel
    @Override
                   public void windowClosing(WindowEvent e) {
                        // TODO Auto-generated method stub
                        try{
                             UIManager.setLookAndFeel("com.birosoft.liquid.LiquidLookAndFeel");
                             SwingUtilities.updateComponentTreeUI(parent);
                             parent.pack();
                             parent.repaint();
                        catch(Exception ecc){}
                   }where in this parent is the frame over which I have opened the JDilaog.
    But after it didnt reset the lookandfeel for the other component
    Thanks and regards
    Anshuman Srivastava

  • Need Help regarding JTable Sort?

    Hello friends, i am working on the JTable and want to sort it by clicking on header of the column. I am using jdk1.5 and as my project is based on it so i cant change the jdk. I dont have the rowsorter class in jdk 1.5. So Is there any way through which i can sort the the Jtable by clicking its column header.
    Thanks for any help.

    Here is a link to the 1.5 Swing tutorial:
    https://www.cs.auckland.ac.nz/references/java/java1.5/tutorial/uiswing/TOC.html
    The Table section has a sorting example.

  • JTable Custom sort

    That was a hassle signing up here; hopefully someone can help me after that :)
    I'm using a JXTable aka JTable, and wanting to add a custom sort to it. Basically I want to be able to sort a table like the JFileChooser, where puts the folders on top of the sort and then sorts by alphabetical.
    I tried searching around but couldn't find anything I want, or otherwise risk moving to a library which requires a lot of changes.
    So to sum it up how do I sort a column by my data and not the value of the cell?
    Any help will be grateful.

    Hello,
    That was a hassle signing up here; hopefully someone can help me after that :)Welcome to the forums. Yes generally newcomers are well received after they have survived the registration trial and won their "abnegation" feather.
    I'm using a JXTable aka JTableWrong start: JXTable is not JTable. JXTable is a class from a specific library (SwingX, right?). This class may or may not extend JTavle (probably it does), but it is not another name for JTable. There are certainly (correction: there are) specific capabilities and behaviors in JXTable that are not in JTable. I suggest you read the documentation for both APIs.
    and wanting to add a custom sort to it. Basically I want to be able to sort a table like the JFileChooser, where puts the folders on top of the sort and then sorts by alphabetical.The Swing tutorial provides examples for sorting techniques in JTable; I advise to to read it: http://download.oracle.com/javase/tutorial/uiswing/components/table.html#sorting
    SwingX' JXTable probably has some specific sorting capabilities too. Please read its documenation.
    I tried searching around but couldn't find anything I want, or otherwise risk moving to a library which requires a lot of changes.You mean you didn't find anything about sorting in Swing, or in SwingX, or that you found something but that wasn't enough like what you needed?
    It the latter, then I suggest you post which approaches you found, and which is closest to what you want, and how it differs.
    So to sum it up how do I sort a column by my data and not the value of the cell?See the tutorial link I provided. Feel free to come back with more specific questions if you don't understand it.
    Best regards,
    J.

  • Sort indicator missing on JTable in OSX

    I just added column sorting to the JTables in my app. On windows it works as advertised. On OSX, the table is sorted when I click the headers, but the sort indicator does not show up. So the first time the user clicks a header for a column that's already sorted, it looks like nothing happens. On Windows, they see the sort indicator appear, so they know their action had an effect. Plus, they can see the sort direction at any time.
    Is there perhaps a property I need to set to make the sort indicator appear in OSX? Or is this the way it was designed for OSX?

    I should have mentioned, it's the Java implementation on OSX where the problem occurs. JTable is the Java implementation of an emulated native table control.
    As revealed to me on the [email protected] list, there are some client properties that can be set to specify specific Cocoa behaviors in the Java implementation of certain JComponent classes. The properties are listed and their usage explained here.
    http://developer.apple.com/mac/library/technotes/tn2007/tn2196.html#GENID1
    An Apple engineer pointed out that these are workarounds, as OSX should work out of the box same as Windows. I'll submit a bug report, per his suggestion.
    Here's my implementation of the fix for the problem I encouontered. The following method is called from the JTable constructor, so the methods invoked in it are JTable methods.
    private void setupRowSorter() {
    setAutoCreateRowSorter(true);//Java6 only. For Java 5, create a TableRowSorter and add it to the JTable
    getTableHeader().addMouseListener(new MouseListener() {
    @Override
    public void mouseClicked(MouseEvent e) {
    getTableHeader().putClientProperty("JTableHeader.selectedColumn", getTableHeader().columnAtPoint(e.getPoint()));
    if (getTableHeader().getClientProperty("JTableHeader.sortDirection") == null) {
    getTableHeader().putClientProperty("JTableHeader.sortDirection", "ascending");
    } else if (getTableHeader().getClientProperty("JTableHeader.sortDirection").equals("ascending")) {
    getTableHeader().putClientProperty("JTableHeader.sortDirection", "decending");//misspelling is required, per Apple documentation
    } else {
    getTableHeader().putClientProperty("JTableHeader.sortDirection", "ascending");
    @Override
    public void mouseEntered(MouseEvent arg0) {
    // TODO Auto-generated method stub
    @Override
    public void mouseExited(MouseEvent arg0) {
    // TODO Auto-generated method stub
    @Override
    public void mousePressed(MouseEvent arg0) {
    // TODO Auto-generated method stub
    @Override
    public void mouseReleased(MouseEvent arg0) {
    // TODO Auto-generated method stub

  • Sorting on JTable (JDK 1.6)

    Hi,
    I currently investigate the new sorting features of JTable in 1.6 (TableRowSorter, etc). By this I came across the following questions:
    * Is there a way to access the sorting order of a column? [Background: my comparators are not symmetric: rows which do not contain any value in the given column need to be displayed always at the very end; at the 'beginning' all other rows are sorted accordingly]
    * Is there a way to just use the new rendering of the table header, register for sorting events, and do the actual sorting 'manually'? [Background: I already have all the sorting and filtering capabilities in place (in a performance efficient way), but of course want to benefit from the new header rendering]
    Any hints are welcome :-)
    Thanks in advance,
    Hans

    Hi,
    I currently investigate the new sorting features of JTable in 1.6 (TableRowSorter, etc). By this I came across the following questions:
    * Is there a way to access the sorting order of a column? [Background: my comparators are not symmetric: rows which do not contain any value in the given column need to be displayed always at the very end; at the 'beginning' all other rows are sorted accordingly]
    * Is there a way to just use the new rendering of the table header, register for sorting events, and do the actual sorting 'manually'? [Background: I already have all the sorting and filtering capabilities in place (in a performance efficient way), but of course want to benefit from the new header rendering]
    Any hints are welcome :-)
    Thanks in advance,
    Hans

  • JTable displays string in wrong order : my code problem or Java problem ?

    I have the following code that displays data in a JTable, most of the time it works fine, but I've realized when I have a cell with values like : "Snowboarding"+"[123456789]"
    It would display it as : [Snowboarding[123456789
    For a string like : "Chasing toddlers"+"<123456789>"
    It would display it as : <Chasing toddlers<123456789
    It not only moved the last bracket to the front, but also changed its direction from "]" to "[" and from ">" to "<"
    Is there anything wrong with my code ? Or is this a Java problem ?
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import java.io.*;
    import java.sql.*;
    import java.util.*;
    import java.util.List;
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;
    public class Table_Panel extends JPanel implements ItemListener
      public static final long serialVersionUID=26362862L;
      static final int Row_Color_Style_Default=-1,Row_Color_Style_None=0,Row_Color_Style_Blue_Gray=1,Row_Color_Style_Cyan_Gray=2,Row_Color_Style_Blue=3,
                       Row_Color_Style_Gray=4,Row_Color_Style_Red_Green=5,Row_Color_Style_Green_Yellow=6,Row_Color_Style_Red_Yellow=7,
                       Max_Header_Cell_Width=0,Header_Width=1,Cell_Width=2;
      static int Row_Color_Style=Row_Color_Style_Cyan_Gray,Preffered_Width=Header_Width;
    //  static int Row_Color_Style=Row_Color_Style_None,Preffered_Width=Header_Width;
    //boolean        Debug=true,
      boolean        Debug=false,
    //               Use_Row_Colors=true,
                     Use_Row_Colors=false;
      JFrame Table_Frame;
      TableModel My_Model;
      JScrollPane scrollPane=new JScrollPane();
      public JTable Table;
      static String columnNames[],Default_Delimiter=\",\";
      Object[][] data;
      static Dimension Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
      int Column_Width[];
      static Color Default_Selection_Color=new Color(250,135,200);
      Color Selection_Color=Default_Selection_Color;
      public Table_Panel(ResultSet RS,String Table_Name,boolean Show_External_Table,int Row_Color_Style,int Preffered_Width,boolean In_Original_Order)
        String Value,Table_Column_Names[]=null;
        Object[][] Table_Data=null;
        int Row_Count,Index=0;
        try
          if (RS==null) return;
          else
            RS.last();
            Row_Count=RS.getRow();
            RS.beforeFirst();
          ResultSetMetaData rsmd=RS.getMetaData();
          int Column_Count=rsmd.getColumnCount();
          Table_Column_Names=new String[Column_Count];
          Table_Data=new Object[Row_Count][Column_Count];
          for (int i=1;i<=Column_Count;i++) Table_Column_Names[i-1]=rsmd.getColumnLabel(i);            // Get column names
    //Out("Row_Count="+Row_Count+"  Column_Count="+Column_Count);
          while (RS.next())                                                                            // Get all rows
            for (int i=1;i<=Column_Count;i++)
              Value=RS.getString(i);
              Table_Data[Index][i-1]=(Value==null)?"null":Value;
            Index++;
    //      if (Test_Ct++>300) break;
        catch (Exception e) { e.printStackTrace(); }
        scrollPane=new Table_Panel(Table_Name,Table_Column_Names,Table_Data,Table_Data.length,false,Show_External_Table,false,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order).scrollPane;
      public Table_Panel(String[] Table_Column_Names,Object[][] Table_Data,Color Selection_Color,boolean In_Original_Order)
        this("",Table_Column_Names,Table_Data,Table_Data.length,false,false,false,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order);
      public Table_Panel(String Table_Name,String[] Table_Column_Names,Object[][] Table_Data,boolean Show_External_Table,Color Selection_Color,boolean In_Original_Order)
        this(Table_Name,Table_Column_Names,Table_Data,Table_Data.length,false,Show_External_Table,false,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order);
      public Table_Panel(String Table_Name,String[] Table_Column_Names,Object[][] Table_Data,int Row_Count,boolean Is_Child,boolean Show_External_Table,boolean Manage_Attachment,int Row_Color_Style,int Preffered_Width,Color Selection_Color,boolean In_Original_Order)
        columnNames=Table_Column_Names;
        if (In_Original_Order) data=Table_Data;
        else
          data=new Object[Table_Data.length][columnNames.length];
          for (int row=0;row<Table_Data.length;row++)
            data[row]=new Object[columnNames.length];
            for (int Column=0;Column<Table_Data[row].length;Column++) data[row][Column]=Table_Data[Table_Data.length-1-row][Column];
        Column_Width=new int[columnNames.length];
        this.Row_Color_Style=Row_Color_Style;
        Use_Row_Colors=(Row_Color_Style!=Row_Color_Style_None);
        this.Preffered_Width=Preffered_Width;
        if (Selection_Color!=null) this.Selection_Color=Selection_Color;
    //    Out("this.Selection_Color="+this.Selection_Color);
    //    TableModel My_Model=new DefaultTableModel(Table_Data,columnNames)
        TableModel My_Model=new DefaultTableModel(data,columnNames)
          public int getColumnCount() { return columnNames.length; }
          public int getRowCount() { return data.length; }
          public String getColumnName(int col) { return columnNames[col]; }
          public Object getValueAt(int row,int col)
    //      Out(row+","+col+"["+data[row][col]+"]   data.length="+data.length+"  data[0].length="+data[0].length);
            return (data[row][col]==null)?"":((data[row][col] instanceof Boolean)?data[row][col]:data[row][col].toString()); // Non-boolean values will have bgcolor
          public Class getColumnClass(int column)
            Class returnValue;
            if ((column>=0) && (column<getColumnCount())) returnValue=getValueAt(0,column).getClass();
            else returnValue=Object.class;
            return returnValue;
        // JTable uses this method to determine the default renderer/editor for each cell. If we didn't implement this method, then the last column would contain text ("true"/"false"), rather than a check box.
    //    public Class getColumnClass(int c) { return getValueAt(0,c).getClass(); }
          // Don't need to implement this method unless your table's editable.
          public boolean isCellEditable(int row,int col)
            //Note that the data/cell address is constant, no matter where the cell appears onscreen.
            if (col<0) return false;
            else return true;
          // Don't need to implement this method unless your table's data can change.
          public void setValueAt(Object value,int row,int col)
            String Execution_Dir=getClass().getProtectionDomain().getCodeSource().getLocation().toString();
            if (Debug) System.out.println("Execution_Dir="+Execution_Dir+"\nLast_Value="+Table_Grid_Cell_Renderer.Last_Value+"  Setting value at [ "+row+","+col+" ] to "+value+" (an instance of "+value.getClass()+")");
            if (Execution_Dir.toLowerCase().indexOf("c:/")!=-1 || value.getClass()==Boolean.class || !Use_Row_Colors) data[row][col]=value;
    //     else data[row][col]=(Table_Grid_CellRenderer.Last_Value==null)?value:value.toString().substring(Table_Grid_CellRenderer.Last_Value.toString().length());
            fireTableCellUpdated(row,col);
            if (Debug)
              System.out.println("New value of data :");
              printDebugData();
          private void printDebugData()
            int numRows=getRowCount();
            int numCols=getColumnCount();
            for (int i=0;i<numRows;i++)
              System.out.print("    row "+i+":");
              for (int j=0;j<numCols;j++) System.out.print("  "+data[i][j]);
              System.out.println();
            System.out.println("--------------------------------------------------------------------------");
        TableSorter sorter=new TableSorter(My_Model);
        Table=new JTable(sorter)
    //    Table=new JTable(My_Model)
          public static final long serialVersionUID=26362862L;
          public String getToolTipText(MouseEvent e)           // Implement table cell tool tips.
            Object Cell_Tip;
            String tip=null;
            java.awt.Point p=e.getPoint();
            int rowIndex=rowAtPoint(p);
            int colIndex=columnAtPoint(p);
            int realColumnIndex=convertColumnIndexToModel(colIndex);
            Cell_Tip=getValueAt(rowIndex,colIndex);
    //        if (realColumnIndex == 2)                         //Sport column
              tip=Cell_Tip.toString();
            else if (realColumnIndex == 4)                      //Veggie column
              TableModel model=getModel();
              String firstName=(String)model.getValueAt(rowIndex,0);
              String lastName=(String)model.getValueAt(rowIndex,1);
              Boolean veggie=(Boolean)model.getValueAt(rowIndex,4);
              if (Boolean.TRUE.equals(veggie)) tip=firstName+" "+lastName+" is a vegetarian";
              else tip=firstName+" "+lastName+" is not a vegetarian";
            else
              // You can omit this part if you know you don't have any renderers that supply their own tool tips.
              tip=super.getToolTipText(e);
            return tip;
    //    RowSorter<TableModel> sorter=new TableRowSorter<TableModel>(My_Model);
    //    Table.setRowSorter(sorter);
        Table.setSelectionBackground(this.Selection_Color);
        int Table_Height=Table.getRowHeight()*Row_Count;
        // sorter.addMouseListenerToHeaderInTable(Table);      // ADDED THIS
        sorter.setTableHeader(Table.getTableHeader());
        if (Table_Column_Names.length>20) Table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        if (Manage_Attachment) Table.setPreferredScrollableViewportSize(new Dimension(500,(Table_Height>850)?850:Table_Height));
        else Table.setPreferredScrollableViewportSize(new Dimension(1000,(Table_Height>850)?850:Table_Height));
        if (Use_Row_Colors) Table.setDefaultRenderer(Object.class,new Table_Grid_Cell_Renderer());
        //Create the scroll pane and add the table to it.
        scrollPane=new JScrollPane(Table);
        //Set up column sizes.
        initColumnSizes(Table,My_Model);
        //Add the scroll pane to this window.
        if (Show_External_Table)
          Table_Frame=new JFrame(Table_Name);
          Table_Frame.getContentPane().add(scrollPane);
          Table_Frame.addWindowListener(new WindowAdapter()
            public void windowActivated(WindowEvent e) { }
            public void windowClosed(WindowEvent e) { }
            public void windowClosing(WindowEvent e)  { System.exit(0); }
            public void windowDeactivated(WindowEvent e)  { }
            public void windowDeiconified(WindowEvent e)  { scrollPane.repaint(); }
            public void windowGainedFocus(WindowEvent e)  { scrollPane.repaint(); }
            public void windowIconified(WindowEvent e)  { }
            public void windowLostFocus(WindowEvent e)  { }
            public void windowOpening(WindowEvent e) { scrollPane.repaint(); }
            public void windowOpened(WindowEvent e)  { }
            public void windowResized(WindowEvent e) { scrollPane.repaint(); } 
            public void windowStateChanged(WindowEvent e) { scrollPane.repaint(); }
          Table_Frame.pack();
          Table_Frame.setBounds((Screen_Size.width-Table_Frame.getWidth())/2,(Screen_Size.height-Table_Frame.getHeight())/2,Table_Frame.getWidth(),Table_Frame.getHeight());
          Table_Frame.setVisible(true);
          if (Is_Child) Table_Frame.addComponentListener(new ComponentAdapter() { public void componentClosing(ComponentEvent e) { System.exit(0); } });
        else add(scrollPane);
      public Table_Panel(String File_Name) { this(File_Name,false,Row_Color_Style_Cyan_Gray,Preffered_Width,null,Default_Selection_Color,true); }
      public Table_Panel(String File_Name,int Row_Color_Style,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style,Preffered_Width,null,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,String Delimiter,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style_Cyan_Gray,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,int Preffered_Width,String Delimiter,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,int Row_Color_Style,int Preffered_Width,String Delimiter,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,boolean Show_External_Table,boolean In_Original_Order) { this(File_Name,Show_External_Table,Row_Color_Style,Preffered_Width,null,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,boolean Show_External_Table,String Delimiter,boolean In_Original_Order) { this(File_Name,Show_External_Table,Row_Color_Style,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,boolean Show_External_Table,int Row_Color_Style,int Preffered_Width,String Delimiter,Color Selection_Color,boolean In_Original_Order)
        String Table_Column_Names[],Column_Name_Line="";
        int Row_Count=0,Index=0;
        boolean Is_Child=false,Manage_Attachment=false;
        StringTokenizer ST;
        if (Delimiter==null) Delimiter=Default_Delimiter;
        if (new File(File_Name).exists())
          try
            String Line,Str=Tool_Lib.Read_File(File_Name).toString();
            ST=new StringTokenizer(Str,"\n");
            Line=ST.nextToken();
            Row_Count=ST.countTokens();
            Object[][] Table_Data=new Object[Row_Count][];
            if (Delimiter.equals(" ")) Line=Line.replaceAll(" {2,}"," ").trim();     // Replace multiple spaces with the delimiter space
            Table_Column_Names=Line.split(Delimiter);
            columnNames=Table_Column_Names;
            for (int i=0;i<Table_Column_Names.length;i++) Column_Name_Line+=Table_Column_Names[i]+"  ";
    //Out("Column_Name_Line [ "+Table_Column_Names.length+" ]="+Column_Name_Line);
            while (ST.hasMoreTokens())
              Line=ST.nextToken();
    //Out(Line);
              if (Delimiter.equals(" ")) Line=Line.replaceAll(" {2,}"," ").trim();   // Replace multiple spaces with the delimiter space
              if (Line.indexOf(Delimiter)!=-1) Table_Data[Index]=Line.split(Delimiter);
              else
                Table_Data[Index]=new Object[Table_Column_Names.length];
                Table_Data[Index][0]=Line;
                for (int i=1;i<Table_Column_Names.length;i++) Table_Data[Index]="";
    Index++;
    Line="";
    for (int i=0;i<Table_Data.length;i++)
    Line+="[ "+Table_Data[i].length+" ] ";
    for (int j=0;j<Table_Data[i].length;j++) Line+=Table_Data[i][j]+" ";
    Line+="\n";
    Out(Line);
    Table_Panel A_Table_Panel=new Table_Panel(File_Name,Table_Column_Names,Table_Data,Row_Count,Is_Child,Show_External_Table,Manage_Attachment,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order);
    Table=A_Table_Panel.Table;
    scrollPane=A_Table_Panel.scrollPane;
    Column_Width=A_Table_Panel.Column_Width;
    data=A_Table_Panel.data;
    catch (Exception e) { e.printStackTrace(); }
    public void setPreferredSize(Dimension A_Dimension) { scrollPane.setPreferredSize(A_Dimension); }
    // This method picks good column sizes. If all column heads are wider than the column's cells' contents, then you can just use column.sizeWidthToFit().
    void initColumnSizes(JTable table,TableModel model)
    TableColumn column=null;
    Component comp=null;
    int headerWidth=0,cellWidth=0;
    Object[] longValues=(data.length>0)?data[0]:null;
    TableCellRenderer headerRenderer=table.getTableHeader().getDefaultRenderer();
    if (data.length<1) return;
    for (int i=0;i<model.getColumnCount();i++)
    column=table.getColumnModel().getColumn(i);
    comp=headerRenderer.getTableCellRendererComponent(null,column.getHeaderValue(),false,false,0,0);
    headerWidth=comp.getPreferredSize().width;
    comp=table.getDefaultRenderer(model.getColumnClass(i)).
    getTableCellRendererComponent(table,longValues[i],false,false,0,i);
    cellWidth=comp.getPreferredSize().width;
    switch (Preffered_Width)
    case Max_Header_Cell_Width : column.setPreferredWidth(Math.max(headerWidth,cellWidth));break;
    case Header_Width : column.setPreferredWidth(headerWidth);break;
    case Cell_Width : column.setPreferredWidth(cellWidth);break;
    Column_Width[i]=column.getPreferredWidth();
    if (Debug) Out("Initializing width of column "+i+". "+"headerWidth="+headerWidth+"; cellWidth="+cellWidth+" Column_Width["+i+"]="+Column_Width[i]);
    // Detects a state change in any of the Lists. Resets the variable corresponding to the selected item in a particular List. Invokes changeFont with the currently selected fontname, style and size attributes.
    public void itemStateChanged(ItemEvent e)
    Out(e.toString());
    if (e.getStateChange() != ItemEvent.SELECTED) return;
    Object list=e.getSource();
    public static void Out(String message) { System.out.println(message); }
    // Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
    static void Create_And_Show_GUI()
    boolean Demo_External_Table=true;
    // boolean Demo_External_Table=false;
    final Table_Panel demo;
    String[] columnNames={"First Names","Last Names","Sport","Num of Years","Vegetarian"};
    Object[][] data={{"Mary","Campione","Snowboarding"+"[123456789]",new Integer(5),new Boolean(false)},
    {"Alison","Huml","Rowing"+":123456789]",new Integer(3),new Boolean(true)},
    {"Frank","Ni","Running"+":123456789", new Integer(12), new Boolean(false)},
    {"Kathy","Walrath","Chasing toddlers"+"<123456789>", new Integer(2), new Boolean(false)},
    {"Mark", "Andrews","Speed reading",new Integer(20),new Boolean(true)},
    {"Angela","Lih","Teaching high school",new Integer(36),new Boolean(false)} };
    // Row_Color_Style=Row_Color_Style_Default;
    // Row_Color_Style=Row_Color_Style_None;
    // Row_Color_Style=Row_Color_Style_Blue_Gray;
    Row_Color_Style=Row_Color_Style_Cyan_Gray;
    // Row_Color_Style=Row_Color_Style_Blue;
    // Row_Color_Style=Row_Color_Style_Gray;
    // Row_Color_Style=Row_Color_Style_Red_Green;
    // Row_Color_Style=Row_Color_Style_Green_Yellow;
    // Row_Color_Style=Row_Color_Style_Red_Yellow;
    Preffered_Width=Max_Header_Cell_Width;
    if (Demo_External_Table) demo=new Table_Panel("External Table Demo",columnNames,data,data.length,false,Demo_External_Table,false,Row_Color_Style,Max_Header_Cell_Width,Default_Selection_Color,true);
    else
    JFrame Table_Frame=new JFrame("Internal Table Demo");
    // demo=new Table_Panel(Nm_Lib.Dir_A_Test+"ELX.csv",false,Row_Color_Style,Preffered_Width,null);
    // demo=new Table_Panel(Nm_Lib.Dir_Stock_Data+"ABV_Data.txt",false,Row_Color_Style,Preffered_Width," ");
    demo=new Table_Panel("C:/Dir_Stock_Data/EOP.txt",",",false);
    // demo=new Table_Panel(Nm_Lib.Dir_Stock_Data+"ABV_Data.txt"," ",false);
    Table_Frame.getContentPane().add(demo.scrollPane);
    Table_Frame.addWindowListener(new WindowAdapter()
    public void windowActivated(WindowEvent e) { }
    public void windowClosed(WindowEvent e) { }
    public void windowClosing(WindowEvent e) { System.exit(0); }
    public void windowDeactivated(WindowEvent e) { }
    public void windowDeiconified(WindowEvent e) { demo.repaint(); }
    public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
    public void windowIconified(WindowEvent e) { }
    public void windowLostFocus(WindowEvent e) { }
    public void windowOpening(WindowEvent e) { demo.repaint(); }
    public void windowOpened(WindowEvent e) { }
    public void windowResized(WindowEvent e) { demo.repaint(); }
    public void windowStateChanged(WindowEvent e) { demo.repaint(); }
    Table_Frame.pack();
    Table_Frame.setBounds((Screen_Size.width-Table_Frame.getWidth())/2,(Screen_Size.height-Table_Frame.getHeight())/2,Table_Frame.getWidth(),Table_Frame.getHeight());
    Table_Frame.setVisible(true);
    public static void main(String[] args)
    // Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
    SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
    * TableSorter is a decorator for TableModels; adding sorting functionality to a supplied TableModel. TableSorter does not store
    * or copy the data in its TableModel; instead it maintains a map from the row indexes of the view to the row indexes of the
    * model. As requests are made of the sorter (like getValueAt(row, col)) they are passed to the underlying model after the row numbers
    * have been translated via the internal mapping array. This way, the TableSorter appears to hold another copy of the table
    * with the rows in a different order.
    * <p/>
    * TableSorter registers itself as a listener to the underlying model, just as the JTable itself would. Events recieved from the model
    * are examined, sometimes manipulated (typically widened), and then passed on to the TableSorter's listeners (typically the JTable).
    * If a change to the model has invalidated the order of TableSorter's rows, a note of this is made and the sorter will resort the
    * rows the next time a value is requested.
    * <p/>
    * When the tableHeader property is set, either by using the setTableHeader() method or the two argument constructor, the table
    * header may be used as a complete UI for TableSorter. The default renderer of the tableHeader is decorated with a renderer
    * that indicates the sorting status of each column. In addition, a mouse listener is installed with the following behavior:
    * <ul>
    * <li>
    * Mouse-click: Clears the sorting status of all other columns and advances the sorting status of that column through three
    * values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to NOT_SORTED again).
    * <li>
    * SHIFT-mouse-click: Clears the sorting status of all other columns and cycles the sorting status of the column through the same
    * three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
    * <li>
    * CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except that the changes to the column do not cancel the statuses of columns
    * that are already sorting - giving a way to initiate a compound sort.
    * </ul>
    * <p/>
    * This is a long overdue rewrite of a class of the same name that first appeared in the swing table demos in 1997.
    * @author Philip Milne
    * @author Brendon McLean
    * @author Dan van Enckevort
    * @author Parwinder Sekhon
    * @version 2.0 02/27/04
    class TableSorter extends AbstractTableModel
    public static final long serialVersionUID=26362862L;
    protected TableModel tableModel;
    public static final int DESCENDING = -1;
    public static final int NOT_SORTED = 0;
    public static final int ASCENDING = 1;
    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
    public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() { public int compare(Object o1, Object o2) { return ((Comparable) o1).compareTo(o2); } };
    public static final Comparator LEXICAL_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } };
    private Row[] viewToModel;
    private int[] modelToView;
    private JTableHeader tableHeader;
    private MouseListener mouseListener;
    private TableModelListener tableModelListener;
    private Map<Class,Comparator> columnComparators = new HashMap<Class,Comparator>();
    private List<Directive> sortingColumns = new ArrayList<Directive>();
    public TableSorter()
    this.mouseListener = new MouseHandler();
    this.tableModelListener = new TableModelHandler();
    public TableSorter(TableModel tableModel)
    this();
    setTableModel(tableModel);
    public TableSorter(TableModel tableModel, JTableHeader tableHeader)
    this();
    setTableHeader(tableHeader);
    setTableModel(tableModel);
    private void clearSortingState()
    viewToModel = null;
    modelToView = null;
    public TableModel getTableModel() { return tableModel; }
    public void setTableModel(TableModel tableModel)
    if (this.tableModel != null) { this.tableModel.removeTableModelListener(tableModelListener); }
    this.tableModel = tableModel;
    if (this.tableModel != null) { this.tableModel.addTableModelListener(tableModelListener); }
    clearSortingState();
    fireTableStructureChanged();
    public JTableHeader getTableHeader() { return tableHeader; }
    public void setTableHeader(JTableHeader tableHeader)
    if (this.tableHeader != null)
    this.tableHeader.removeMouseListener(mouseListener);
    TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
    if (defaultRenderer instanceof SortableHeaderRenderer) this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
    this.tableHeader = tableHeader;
    if (this.tableHeader != null)
    this.tableHeader.addMouseListener(mouseListener);
    this.tableHeader.setDefaultRenderer(
    new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
    public boolean isSorting() { return sortingColumns.size() != 0; }
    private Directive getDirective(int column)
    for (int i = 0; i < sortingColumns.size(); i++)
    Directive directive = (Directive)sortingColumns.get(i);
    if (directive.column == column) { return directive; }
    return EMPTY_DIRECTIVE;
    public int getSortingStatus(int column) { return getDirective(column).direction; }
    private void sortingStatusChanged()
    clearSortingState();
    fireTableDataChanged();
    if (tableHeader != null) { tableHeader.repaint(); }
    public void setSortingStatus(int column, int status)
    Directive directive = getDirective(column);
    if (directive != EMPTY_DIRECTIVE) { sortingColumns.remove(directive); }
    if (status != NOT_SORTED) { sortingColumns.add(new Directive(column, status)); }
    sortingStatusChanged();
    protected Icon getHeaderRendererIcon(int column, int size)
    Directive directive = getDirective(column);
    if (directive == EMPTY_DIRECTIVE) { return null; }
    return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));
    private void cancelSorting()
    sortingColumns.clear();
    sortingStatusChanged();
    public void setColumnComparator(Class type, Comparator comparator)
    if (comparator == null) { columnComparators.remove(type); }
    else { columnComparators.put(type, comparator); }
    protected Comparator getComparator(int column)
    Class columnType = tableModel.getColumnClass(column);
    Comparator comparator = (Comparator) columnComparators.get(columnType);
    if (comparator != null) { return comparator; }
    if (Comparable.class.isAssignableFrom(columnType)) { return COMPARABLE_COMAPRATOR; }
    return LEXICAL_COMPARATOR;
    private Row[] getViewToModel()
    if (viewToModel == null)
    int tableModelRowCount = tableModel.getRowCount();
    viewToModel = new Row[tableModelRowCount];
    for (int row = 0; row < tableModelRowCount; row++) { viewToModel[row] = new Row(row); }
    if (isSorting()) { Arrays.sort(viewToModel); }
    return viewToModel;
    public int modelIndex(int viewIndex) { return getViewToModel()[viewIndex].modelIndex; }
    private int[] getModelToView()
    if (modelToView == null)
    int n = getViewToModel().length;
    modelToView = new int[n];
    for (int i = 0; i < n; i++) { modelToView[modelIndex(i)] = i; }
    return modelToView;
    // TableModel interface methods
    public int getRowCount() { return (tableModel == null) ? 0 : tableModel.getRowCount(); }
    public int getColumnCount() { return (tableModel == null) ? 0 : tableModel.getColumnCount(); }
    public String getColumnName(int column) { return tableModel.getColumnName(column); }
    public Class getColumnClass(int column) { return tableModel.getColumnClass(column); }
    public boolean isCellEditable(int row, int column) { return tableModel.isCellEditable(modelIndex(row), column); }
    public Object getValueAt(int row, int column) { return tableModel.getValueAt(modelIndex(row), column); }
    public void setValueAt(Object aValue, int row, int column) { tableModel.setValueAt(aValue, modelIndex(row), column); }
    // Helper classes
    private class Row implements Comparable
    private int modelIndex;
    public Row(int index) { this.modelIndex = index; }
    public int compareTo(Object o)
    int row1 = modelIndex;
    int row2 = ((Row) o).modelIndex;
    for (Iterator it = sortingColumns.iterator(); it.hasNext();)
    Directive directive = (Directive) it.next();
    int column = directive.column;
    Object o1 = tableModel.getValueAt(row1, column);
    Object o2 = tableModel.getValueAt(row2, column);
    int comparison = 0;
    // Define null less than everything, except null.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import java.io.*;
    import java.sql.*;
    import java.util.*;
    import java.util.List;
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;
    public class Table_Panel extends JPanel implements ItemListener
      public static final long serialVersionUID=26362862L;
      static final int Row_Color_Style_Default=-1,Row_Color_Style_None=0,Row_Color_Style_Blue_Gray=1,Row_Color_Style_Cyan_Gray=2,Row_Color_Style_Blue=3,
                       Row_Color_Style_Gray=4,Row_Color_Style_Red_Green=5,Row_Color_Style_Green_Yellow=6,Row_Color_Style_Red_Yellow=7,
                       Max_Header_Cell_Width=0,Header_Width=1,Cell_Width=2;
      static int Row_Color_Style=Row_Color_Style_Cyan_Gray,Preffered_Width=Header_Width;
    //  static int Row_Color_Style=Row_Color_Style_None,Preffered_Width=Header_Width;
    //boolean        Debug=true,
      boolean        Debug=false,
    //               Use_Row_Colors=true,
                     Use_Row_Colors=false;
      JFrame Table_Frame;
      TableModel My_Model;
      JScrollPane scrollPane=new JScrollPane();
      public JTable Table;
      static String columnNames[],Default_Delimiter=",";
      Object[][] data;
      static Dimension Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
      int Column_Width[];
      static Color Default_Selection_Color=new Color(250,135,200);
      Color Selection_Color=Default_Selection_Color;
      public Table_Panel(ResultSet RS,String Table_Name,boolean Show_External_Table,int Row_Color_Style,int Preffered_Width,boolean In_Original_Order)
        String Value,Table_Column_Names[]=null;
        Object[][] Table_Data=null;
        int Row_Count,Index=0;
        try
          if (RS==null) return;
          else
            RS.last();
            Row_Count=RS.getRow();
            RS.beforeFirst();
          ResultSetMetaData rsmd=RS.getMetaData();
          int Column_Count=rsmd.getColumnCount();
          Table_Column_Names=new String[Column_Count];
          Table_Data=new Object[Row_Count][Column_Count];
          for (int i=1;i<=Column_Count;i++) Table_Column_Names[i-1]=rsmd.getColumnLabel(i);            // Get column names
    //Out("Row_Count="+Row_Count+"  Column_Count="+Column_Count);
          while (RS.next())                                                                            // Get all rows
            for (int i=1;i<=Column_Count;i++)
              Value=RS.getString(i);
              Table_Data[Index][i-1]=(Value==null)?"null":Value;
            Index++;
    //      if (Test_Ct++>300) break;
        catch (Exception e) { e.printStackTrace(); }
        scrollPane=new Table_Panel(Table_Name,Table_Column_Names,Table_Data,Table_Data.length,false,Show_External_Table,false,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order).scrollPane;
      public Table_Panel(String[] Table_Column_Names,Object[][] Table_Data,Color Selection_Color,boolean In_Original_Order)
        this("",Table_Column_Names,Table_Data,Table_Data.length,false,false,false,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order);
      public Table_Panel(String Table_Name,String[] Table_Column_Names,Object[][] Table_Data,boolean Show_External_Table,Color Selection_Color,boolean In_Original_Order)
        this(Table_Name,Table_Column_Names,Table_Data,Table_Data.length,false,Show_External_Table,false,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order);
      public Table_Panel(String Table_Name,String[] Table_Column_Names,Object[][] Table_Data,int Row_Count,boolean Is_Child,boolean Show_External_Table,boolean Manage_Attachment,int Row_Color_Style,int Preffered_Width,Color Selection_Color,boolean In_Original_Order)
        columnNames=Table_Column_Names;
        if (In_Original_Order) data=Table_Data;
        else
          data=new Object[Table_Data.length][columnNames.length];
          for (int row=0;row<Table_Data.length;row++)
            data[row]=new Object[columnNames.length];
            for (int Column=0;Column<Table_Data[row].length;Column++) data[row][Column]=Table_Data[Table_Data.length-1-row][Column];
        Column_Width=new int[columnNames.length];
        this.Row_Color_Style=Row_Color_Style;
        Use_Row_Colors=(Row_Color_Style!=Row_Color_Style_None);
        this.Preffered_Width=Preffered_Width;
        if (Selection_Color!=null) this.Selection_Color=Selection_Color;
    //    Out("this.Selection_Color="+this.Selection_Color);
    //    TableModel My_Model=new DefaultTableModel(Table_Data,columnNames)
        TableModel My_Model=new DefaultTableModel(data,columnNames)
          public int getColumnCount() { return columnNames.length; }
          public int getRowCount() { return data.length; }
          public String getColumnName(int col) { return columnNames[col]; }
          public Object getValueAt(int row,int col)
    //      Out(row+","+col+"["+data[row][col]+"]   data.length="+data.length+"  data[0].length="+data[0].length);
            return (data[row][col]==null)?"":((data[row][col] instanceof Boolean)?data[row][col]:data[row][col].toString()); // Non-boolean values will have bgcolor
          public Class getColumnClass(int column)
            Class returnValue;
            if ((column>=0) && (column<getColumnCount())) returnValue=getValueAt(0,column).getClass();
            else returnValue=Object.class;
            return returnValue;
        // JTable uses this method to determine the default renderer/editor for each cell. If we didn't implement this method, then the last column would contain text ("true"/"false"), rather than a check box.
    //    public Class getColumnClass(int c) { return getValueAt(0,c).getClass(); }
          // Don't need to implement this method unless your table's editable.
          public boolean isCellEditable(int row,int col)
            //Note that the data/cell address is constant, no matter where the cell appears onscreen.
            if (col<0) return false;
            else return true;
          // Don't need to implement this method unless your table's data can change.
          public void setValueAt(Object value,int row,int col)
            String Execution_Dir=getClass().getProtectionDomain().getCodeSource().getLocation().toString();
            if (Debug) System.out.println("Execution_Dir="+Execution_Dir+"\nLast_Value="+Table_Grid_Cell_Renderer.Last_Value+"  Setting value at [ "+row+","+col+" ] to "+value+" (an instance of "+value.getClass()+")");
            if (Execution_Dir.toLowerCase().indexOf("c:/")!=-1 || value.getClass()==Boolean.class || !Use_Row_Colors) data[row][col]=value;
    //     else data[row][col]=(Table_Grid_CellRenderer.Last_Value==null)?value:value.toString().substring(Table_Grid_CellRenderer.Last_Value.toString().length());
            fireTableCellUpdated(row,col);
            if (Debug)
              System.out.println("New value of data :");
              printDebugData();
          private void printDebugData()
            int numRows=getRowCount();
            int numCols=getColumnCount();
            for (int i=0;i<numRows;i++)
              System.out.print("    row "+i+":");
              for (int j=0;j<numCols;j++) System.out.print("  "+data[i][j]);
              System.out.println();
            System.out.println("--------------------------------------------------------------------------");
        TableSorter sorter=new TableSorter(My_Model);
        Table=new JTable(sorter)
    //    Table=new JTable(My_Model)
          public static final long serialVersionUID=26362862L;
          public String getToolTipText(MouseEvent e)           // Implement table cell tool tips.
            Object Cell_Tip;
            String tip=null;
            java.awt.Point p=e.getPoint();
            int rowIndex=rowAtPoint(p);
            int colIndex=columnAtPoint(p);
            int realColumnIndex=convertColumnIndexToModel(colIndex);
            Cell_Tip=getValueAt(rowIndex,colIndex);
    //        if (realColumnIndex == 2)                         //Sport column
              tip=Cell_Tip.toString();
            else if (realColumnIndex == 4)                      //Veggie column
              TableModel model=getModel();
              String firstName=(String)model.getValueAt(rowIndex,0);
              String lastName=(String)model.getValueAt(rowIndex,1);
              Boolean veggie=(Boolean)model.getValueAt(rowIndex,4);
              if (Boolean.TRUE.equals(veggie)) tip=firstName+" "+lastName+" is a vegetarian";
              else tip=firstName+" "+lastName+" is not a vegetarian";
            else
              // You can omit this part if you know you don't have any renderers that supply their own tool tips.
              tip=super.getToolTipText(e);
            return tip;
    //    RowSorter<TableModel> sorter=new TableRowSorter<TableModel>(My_Model);
    //    Table.setRowSorter(sorter);
        Table.setSelectionBackground(this.Selection_Color);
        int Table_Height=Table.getRowHeight()*Row_Count;
        // sorter.addMouseListenerToHeaderInTable(Table);      // ADDED THIS
        sorter.setTableHeader(Table.getTableHeader());
        if (Table_Column_Names.length>20) Table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        if (Manage_Attachment) Table.setPreferredScrollableViewportSize(new Dimension(500,(Table_Height>850)?850:Table_Height));
        else Table.setPreferredScrollableViewportSize(new Dimension(1000,(Table_Height>850)?850:Table_Height));
        if (Use_Row_Colors) Table.setDefaultRenderer(Object.class,new Table_Grid_Cell_Renderer());
        //Create the scroll pane and add the table to it.
        scrollPane=new JScrollPane(Table);
        //Set up column sizes.
        initColumnSizes(Table,My_Model);
        //Add the scroll pane to this window.
        if (Show_External_Table)
          Table_Frame=new JFrame(Table_Name);
          Table_Frame.getContentPane().add(scrollPane);
          Table_Frame.addWindowListener(new WindowAdapter()
            public void windowActivated(WindowEvent e) { }
            public void windowClosed(WindowEvent e) { }
            public void windowClosing(WindowEvent e)  { System.exit(0); }
            public void windowDeactivated(WindowEvent e)  { }
            public void windowDeiconified(WindowEvent e)  { scrollPane.repaint(); }
            public void windowGainedFocus(WindowEvent e)  { scrollPane.repaint(); }
            public void windowIconified(WindowEvent e)  { }
            public void windowLostFocus(WindowEvent e)  { }
            public void windowOpening(WindowEvent e) { scrollPane.repaint(); }
            public void windowOpened(WindowEvent e)  { }
            public void windowResized(WindowEvent e) { scrollPane.repaint(); } 
            public void windowStateChanged(WindowEvent e) { scrollPane.repaint(); }
          Table_Frame.pack();
          Table_Frame.setBounds((Screen_Size.width-Table_Frame.getWidth())/2,(Screen_Size.height-Table_Frame.getHeight())/2,Table_Frame.getWidth(),Table_Frame.getHeight());
          Table_Frame.setVisible(true);
          if (Is_Child) Table_Frame.addComponentListener(new ComponentAdapter() { public void componentClosing(ComponentEvent e) { System.exit(0); } });
        else add(scrollPane);
      public Table_Panel(String File_Name) { this(File_Name,false,Row_Color_Style_Cyan_Gray,Preffered_Width,null,Default_Selection_Color,true); }
      public Table_Panel(String File_Name,int Row_Color_Style,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style,Preffered_Width,null,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,String Delimiter,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style_Cyan_Gray,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,int Preffered_Width,String Delimiter,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,int Row_Color_Style,int Preffered_Width,String Delimiter,boolean In_Original_Order) { this(File_Name,false,Row_Color_Style,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,boolean Show_External_Table,boolean In_Original_Order) { this(File_Name,Show_External_Table,Row_Color_Style,Preffered_Width,null,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,boolean Show_External_Table,String Delimiter,boolean In_Original_Order) { this(File_Name,Show_External_Table,Row_Color_Style,Preffered_Width,Delimiter,Default_Selection_Color,In_Original_Order); }
      public Table_Panel(String File_Name,boolean Show_External_Table,int Row_Color_Style,int Preffered_Width,String Delimiter,Color Selection_Color,boolean In_Original_Order)
        String Table_Column_Names[],Column_Name_Line="";
        int Row_Count=0,Index=0;
        boolean Is_Child=false,Manage_Attachment=false;
        StringTokenizer ST;
        if (Delimiter==null) Delimiter=Default_Delimiter;
        if (new File(File_Name).exists())
          try
            String Line,Str=Tool_Lib.Read_File(File_Name).toString();
            ST=new StringTokenizer(Str,"\n");
            Line=ST.nextToken();
            Row_Count=ST.countTokens();
            Object[][] Table_Data=new Object[Row_Count][];
            if (Delimiter.equals(" ")) Line=Line.replaceAll(" {2,}"," ").trim();     // Replace multiple spaces with the delimiter space
            Table_Column_Names=Line.split(Delimiter);
            columnNames=Table_Column_Names;
            for (int i=0;i<Table_Column_Names.length;i++) Column_Name_Line+=Table_Column_Names[i]+"  ";
    //Out("Column_Name_Line [ "+Table_Column_Names.length+" ]="+Column_Name_Line);
            while (ST.hasMoreTokens())
              Line=ST.nextToken();
    //Out(Line);
              if (Delimiter.equals(" ")) Line=Line.replaceAll(" {2,}"," ").trim();   // Replace multiple spaces with the delimiter space
              if (Line.indexOf(Delimiter)!=-1) Table_Data[Index]=Line.split(Delimiter);
              else
                Table_Data[Index]=new Object[Table_Column_Names.length];
                Table_Data[Index][0]=Line;
                for (int i=1;i<Table_Column_Names.length;i++) Table_Data[Index]="";
    Index++;
    Line="";
    for (int i=0;i<Table_Data.length;i++)
    Line+="[ "+Table_Data[i].length+" ] ";
    for (int j=0;j<Table_Data[i].length;j++) Line+=Table_Data[i][j]+" ";
    Line+="\n";
    Out(Line);
    Table_Panel A_Table_Panel=new Table_Panel(File_Name,Table_Column_Names,Table_Data,Row_Count,Is_Child,Show_External_Table,Manage_Attachment,Row_Color_Style,Preffered_Width,Selection_Color,In_Original_Order);
    Table=A_Table_Panel.Table;
    scrollPane=A_Table_Panel.scrollPane;
    Column_Width=A_Table_Panel.Column_Width;
    data=A_Table_Panel.data;
    catch (Exception e) { e.printStackTrace(); }
    public void setPreferredSize(Dimension A_Dimension) { scrollPane.setPreferredSize(A_Dimension); }
    // This method picks good column sizes. If all column heads are wider than the column's cells' contents, then you can just use column.sizeWidthToFit().
    void initColumnSizes(JTable table,TableModel model)
    TableColumn column=null;
    Component comp=null;
    int headerWidth=0,cellWidth=0;
    Object[] longValues=(data.length>0)?data[0]:null;
    TableCellRenderer headerRenderer=table.getTableHeader().getDefaultRenderer();
    if (data.length<1) return;
    for (int i=0;i<model.getColumnCount();i++)
    column=table.getColumnModel().getColumn(i);
    comp=headerRenderer.getTableCellRendererComponent(null,column.getHeaderValue(),false,false,0,0);
    headerWidth=comp.getPreferredSize().width;
    comp=table.getDefaultRenderer(model.getColumnClass(i)).
    getTableCellRendererComponent(table,longValues[i],false,false,0,i);
    cellWidth=comp.getPreferredSize().width;
    switch (Preffered_Width)
    case Max_Header_Cell_Width : column.setPreferredWidth(Math.max(headerWidth,cellWidth));break;
    case Header_Width : column.setPreferredWidth(headerWidth);break;
    case Cell_Width : column.setPreferredWidth(cellWidth);break;
    Column_Width[i]=column.getPreferredWidth();
    if (Debug) Out("Initializing width of column "+i+". "+"headerWidth="+headerWidth+"; cellWidth="+cellWidth+" Column_Width["+i+"]="+Column_Width[i]);
    // Detects a state change in any of the Lists. Resets the variable corresponding to the selected item in a particular List. Invokes changeFont with the currently selected fontname, style and size attributes.
    public void itemStateChanged(ItemEvent e)
    Out(e.toString());
    if (e.getStateChange() != ItemEvent.SELECTED) return;
    Object list=e.getSource();
    public static void Out(String message) { System.out.println(message); }
    // Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
    static void Create_And_Show_GUI()
    boolean Demo_External_Table=true;
    // boolean Demo_External_Table=false;
    final Table_Panel demo;
    String[] columnNames={"First Names","Last Names","Sport","Num of Years","Vegetarian"};
    Object[][] data={{"Mary","Campione","Snowboarding"+"[123456789]",new Integer(5),new Boolean(false)},
    {"Alison","Huml","Rowing"+":123456789]",new Integer(3),new Boolean(true)},
    {"Frank","Ni","Running"+":123456789", new Integer(12), new Boolean(false)},
    {"Kathy","Walrath","Chasing toddlers"+"<123456789>", new Integer(2), new Boolean(false)},
    {"Mark", "Andrews","Speed reading",new Integer(20),new Boolean(true)},
    {"Angela","Lih","Teaching high school",new Integer(36),new Boolean(false)} };
    // Row_Color_Style=Row_Color_Style_Default;
    // Row_Color_Style=Row_Color_Style_None;
    // Row_Color_Style=Row_Color_Style_Blue_Gray;
    Row_Color_Style=Row_Color_Style_Cyan_Gray;
    // Row_Color_Style=Row_Color_Style_Blue;
    // Row_Color_Style=Row_Color_Style_Gray;
    // Row_Color_Style=Row_Color_Style_Red_Green;
    // Row_Color_Style=Row_Color_Style_Green_Yellow;
    // Row_Color_Style=Row_Color_Style_Red_Yellow;
    Preffered_Width=Max_Header_Cell_Width;
    if (Demo_External_Table) demo=new Table_Panel("External Table Demo",columnNames,data,data.length,false,Demo_External_Table,false,Row_Color_Style,Max_Header_Cell_Width,Default_Selection_Color,true);
    else
    JFrame Table_Frame=new JFrame("Internal Table Demo");
    // demo=new Table_Panel(Nm_Lib.Dir_A_Test+"ELX.csv",false,Row_Color_Style,Preffered_Width,null);
    // demo=new Table_Panel(Nm_Lib.Dir_Stock_Data+"ABV_Data.txt",false,Row_Color_Style,Preffered_Width," ");
    demo=new Table_Panel("C:/Dir_Stock_Data/EOP.txt",",",false);
    // demo=new Table_Panel(Nm_Lib.Dir_Stock_Data+"ABV_Data.txt"," ",false);
    Table_Frame.getContentPane().add(demo.scrollPane);
    Table_Frame.addWindowListener(new WindowAdapter()
    public void windowActivated(WindowEvent e) { }
    public void windowClosed(WindowEvent e) { }
    public void windowClosing(WindowEvent e) { System.exit(0); }
    public void windowDeactivated(WindowEvent e) { }
    public void windowDeiconified(WindowEvent e) { demo.repaint(); }
    public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
    public void windowIconified(WindowEvent e) { }
    public void windowLostFocus(WindowEvent e) { }
    public void windowOpening(WindowEvent e) { demo.repaint(); }
    public void windowOpened(WindowEvent e) { }
    public void windowResized(WindowEvent e) { demo.repaint(); }
    public void windowStateChanged(WindowEvent e) { demo.repaint(); }
    Table_Frame.pack();
    Table_Frame.setBounds((Screen_Size.width-Table_Frame.getWidth())/2,(Screen_Size.height-Table_Frame.getHeight())/2,Table_Frame.getWidth(),Table_Frame.getHeight());
    Table_Frame.setVisible(true);
    public static void main(String[] args)
    // Schedule a job for the event-dispatching thread : creating and showing this application's GUI.
    SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } });
    * TableSorter is a decorator for TableModels; adding sorting functionality to a supplied TableModel. TableSorter does not store
    * or copy the data in its TableModel; instead it maintains a map from the row indexes of the view to the row indexes of the
    * model. As requests are made of the sorter (like getValueAt(row, col)) they are passed to the underlying model after the row numbers
    * have been translated via the internal mapping array. This way, the TableSorter appears to hold another copy of the table
    * with the rows in a different order.
    * <p/>
    * TableSorter registers itself as a listener to the underlying model, just as the JTable itself would. Events recieved from the model
    * are examined, sometimes manipulated (typically widened), and then passed on to the TableSorter's listeners (typically the JTable).
    * If a change to the model has invalidated the order of TableSorter's rows, a note of this is made and the sorter will resort the
    * rows the next time a value is requested.
    * <p/>
    * When the tableHeader property is set, either by using the setTableHeader() method or the two argument constructor, the table
    * header may be used as a complete UI for TableSorter. The default renderer of the tableHeader is decorated with a renderer
    * that indicates the sorting status of each column. In addition, a mouse listener is installed with the following behavior:
    * <ul>
    * <li>
    * Mouse-click: Clears the sorting status of all other columns and advances the sorting status of that column through three
    * values: {NOT_SORTED, ASCENDING, DESCENDING} (then back to NOT_SORTED again).
    * <li>
    * SHIFT-mouse-click: Clears the sorting status of all other columns and cycles the sorting status of the column through the same
    * three values, in the opposite order: {NOT_SORTED, DESCENDING, ASCENDING}.
    * <li>
    * CONTROL-mouse-click and CONTROL-SHIFT-mouse-click: as above except that the changes to the column do not cancel the statuses of columns
    * that are already sorting - giving a way to initiate a compound sort.
    * </ul>
    * <p/>
    * This is a long overdue rewrite of a class of the same name that first appeared in the swing table demos in 1997.
    * @author Philip Milne
    * @author Brendon McLean
    * @author Dan van Enckevort
    * @author Parwinder Sekhon
    * @version 2.0 02/27/04
    class TableSorter extends AbstractTableModel
    public static final long serialVersionUID=26362862L;
    protected TableModel tableModel;
    public static final int DESCENDING = -1;
    public static final int NOT_SORTED = 0;
    public static final int ASCENDING = 1;
    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
    public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() { public int compare(Object o1, Object o2) { return ((Comparable) o1).compareTo(o2); } };
    public static final Comparator LEXICAL_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } };
    private Row[] viewToModel;
    private int[] modelToView;
    private JTableHeader tableHeader;
    private MouseListener mouseListener;
    private TableModelListener tableModelListener;
    private Map<Class,Comparator> columnComparators = new HashMap<Class,Comparator>();
    private List<Directive> sortingColumns = new ArrayList<Directive>();
    public TableSorter()
    this.mouseListener = new MouseHandler();
    this.tableModelListener = new TableModelHandler();
    public TableSorter(TableModel tableModel)
    this();
    setTableModel(tableModel);
    public TableSorter(TableModel tableModel, JTableHeader tableHeader)
    this();
    setTableHeader(tableHeader);
    setTableModel(tableModel);
    private void clearSortingState()
    viewToModel = null;
    modelToView = null;
    public TableModel getTableModel() { return tableModel; }
    public void setTableModel(TableModel tableModel)
    if (this.tableModel != null) { this.tableModel.removeTableModelListener(tableModelListener); }
    this.tableModel = tableModel;
    if (this.tableModel != null) { this.tableModel.addTableModelListener(tableModelListener); }
    clearSortingState();
    fireTableStructureChanged();
    public JTableHeader getTableHeader() { return tableHeader; }
    public void setTableHeader(JTableHeader tableHeader)
    if (this.tableHeader != null)
    this.tableHeader.removeMouseListener(mouseListener);
    TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
    if (defaultRenderer instanceof SortableHeaderRenderer) this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
    this.tableHeader = tableHeader;
    if (this.tableHeader != null)
    this.tableHeader.addMouseListener(mouseListener);
    this.tableHeader.setDefaultRenderer(
    new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
    public boolean isSorting() { return sortingColumns.size() != 0; }
    private Directive getDirective(int column)
    for (int i = 0; i < sortingColumns.size(); i++)
    Directive directive = (Directive)sortingColumns.get(i);
    if (directive.column == column) { return directive; }
    return EMPTY_DIRECTIVE;
    public int getSortingStatus(int column) { return getDirective(column).direction; }
    private void sortingStatusChanged()
    clearSortingState();
    fireTableDataChanged();
    if (tableHeader != null) { tableHeader.repaint(); }
    public void setSortingStatus(int column, int status)
    Directive directive = getDirective(column);
    if (directive != EMPTY_DIRECTIVE) { sortingColumns.remove(directive); }
    if (status != NOT_SORTED) { sortingColumns.add(new Directive(column, status)); }
    sortingStatusChanged();
    protected Icon getHeaderRendererIcon(int column, int size)
    Directive directive = getDirective(column);
    if (directive == EMPTY_DIRECTIVE) { return null; }
    return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));
    private void cancelSorting()
    sortingColumns.clear();
    sortingStatusChanged();
    public void setColumnComparator(Class type, Comparator comparator)
    if (comparator == null) { columnComparators.remove(type); }
    else { columnComparators.put(type, comparator); }
    protected Comparator getComparator(int column)
    Class columnType = tableModel.getColumnClass(column);
    Comparator comparator = (Comparator) columnComparators.get(columnType);
    if (comparator != null) { return comparator; }
    if (Comparable.class.isAssignableFrom(columnType)) { return COMPARABLE_COMAPRATOR; }
    return LEXICAL_COMPARATOR;
    private Row[] getViewToModel()
    if (viewToModel == null)
    int tableModelRowCount = tableModel.getRowCount();
    viewToModel = new Row[tableModelRowCount];
    for (int row = 0; row < tableModelRowCount; row++) { viewToModel[row] = new Row(row); }
    if (isSorting()) { Arrays.sort(viewToModel); }
    return viewToModel;
    public int modelIndex(int viewIndex) { return getViewToModel()[viewIndex].modelIndex; }
    private int[] getModelToView()
    if (modelToView == null)
    int n = getViewToModel().length;
    modelToView = new int[n];
    for (int i = 0; i < n; i++) { modelToView[modelIndex(i)] = i; }
    return modelToView;
    // TableModel interface methods
    public int getRowCount() { return (tableModel == null) ? 0 : tableModel.getRowCount(); }
    public int getColumnCount() { return (tableModel == null) ? 0 : tableModel.getColumnCount(); }
    public String getColumnName(int column) { return tableModel.getColumnName(column); }
    public Class getColumnClass(int column) { return tableModel.getColumnClass(column); }
    public boolean isCellEditable(int row, int column) { return tableModel.isCellEditable(modelIndex(row), column); }
    public Object getValueAt(int row, int column) { return tableModel.getValueAt(modelIndex(row), column); }
    public void setValueAt(Object aValue, int row, int column) { tableModel.setValueAt(aValue, modelIndex(row), column); }
    // Helper classes
    private class Row implements Comparable
    private int modelIndex;
    public Row(int index) { this.modelIndex = index; }
    public int compareTo(Object o)
    int row1 = modelIndex;
    int row2 = ((Row) o).modelIndex;
    for (Iterator it = sortingColumns.iterator(); it.hasNext();)
    Directive directive = (Directive) it.next();
    int column = directive.column;
    Object o1 = tableModel.getValueAt(row1, column);
    Object o2 = tableModel.getValueAt(row2, column);
    int comparison = 0;
    // Define null less than everything, except null.
    if (o1 == null && o2 == null) { comparison = 0; }
    else if (o1 == null) { comparison = -1; }
    else if (o2 == null) { comparison = 1; }
    else { comparison = getComparator(column).compare(o1, o2); }
    if (comparison != 0) { return directive.direction == DESCENDING ? -comparison : comparison; }
    return 0;
    private class TableModelHandler implements TableModelListener
    public void tableChanged(TableModelEvent e)
    // If we're not sorting by anything

  • Changing a JTable's model

    Hello everyone,
    I dont have a whole lot of experience w/ JTables and this problem has been troubling me for a while now. I have a JTable that significantly changes when the user hits the calculate button, so instead of going through the trouble of completely reformatting the table by adding/removing columns and table headers, I simple make a new model and set the table's model to the new one, and then call table.updateUI(). The problem is that my custom cell renderer that displays a down or up arrow depending on how the given column is sorted stops working. The sorter works properly and the table displays properly, but the arrows do not change from up to down or vise versa when a column is resorted. The whole process works just fine the first time, but the more times the user pushes the calculate button the more off it gets. I have added a flag in the actionPerformed method in my cell renderer that tells me when the table header is clicked. Every time the calculate button is hit, more flags appear when the table header is clicked. Therefore the arrows change position on odd numbers and do not on evens (because the evens cancel eachother out and the arrow appears to sit still), however the sorter still works properly. It seems as though somehow a new mouse listener or cell renderer is added after each time the calculate button is pressed. Either that or the entire table is not being reset somehow and something is still invisible in the background.
    Here is some of my code.
    // The initial table with no data
    String[] str = {"class 1", "class 2", "class 3", "class 4", "class 5", "= GPA"};
    String[][]  data= {{"", "", "", "", "", ""},
    pmModel = new ProjectionModel(str, data);
    mainTable = new JTable(pmModel);
    mainTable.getTableHeader().setDefaultRenderer(new SortButtonRenderer());
    // After the calculate button has been pushed:
    // The table is reset here. TableSorter extends TableMap
        ProjectionModel newModel = new ProjectionModel(courseList, charList);
        TableSorter sorter = new TableSorter(newModel);
        // this method is shown below
        sorter.addMouseListenerToHeaderInTable(mainTable);
        sorter.sortedUp = false;
        mainTable.addNotify();
        mainTable.setModel(sorter);
        // SortButtonRenderer extends TableCellRenderer
        SortButtonRenderer renderer = new SortButtonRenderer();
        mainTable.getTableHeader().setDefaultRenderer(renderer);
        // set the arrow to DOWN on the first column
        renderer.setSelectedColumn(0);
        renderer.setSelectedColumn(0);
        mainTable.updateUI();
    // This is the addMouseListenerToTable(JTable table) found in the TableSorter class
        public void addMouseListenerToHeaderInTable(JTable table) {
            final TableSorter sorter = this;
            final JTable tableView = table;
            tableView.setColumnSelectionAllowed(false);
            MouseAdapter listMouseListener = new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    TableColumnModel columnModel = tableView.getColumnModel();
                    int viewColumn = columnModel.getColumnIndexAtX(e.getX());
                    int column = tableView.convertColumnIndexToModel(viewColumn);
                    if (e.getClickCount() == 1 && column != -1) {
                      SortButtonRenderer renderer =
                            (SortButtonRenderer)tableView.getTableHeader().getDefaultRenderer();
                        //int shiftPressed = e.getModifiers()&InputEvent.SHIFT_MASK;
                        //boolean ascending = (shiftPressed == 0);
                        boolean ascending = (renderer.getLastColumn() == column && !sortedUp);
                        renderer.setLastColumn(column);
                        sorter.sortByColumn(column, ascending);
                        if (ascending) sortedUp = true;
                        else sortedUp = false;
                        renderer.setSelectedColumn(column);
                        // the flag that prints the column that is pressed
                        System.out.println(column + " " + sortedUp);
            JTableHeader th = tableView.getTableHeader();
            th.addMouseListener(listMouseListener); // it seems like i need a way to remove any
    // previous mouseListeners here, i think this would solve the problem
        }The flag's output looks something like this:
    < first time calculate button is clicked >
    < column 0 is clicked> 0 false
    < column 0 is clicked again > 0 true
    < second time calculate button is clicked >
    < column 0 is clicked >
    0 false
    0 true
    notice they cancel eachother out so the arrow stays in the same position
    < third time calculate button is clicked >
    < column 0 is clicked >
    0 false
    0 true
    0 false
    notice they dont cancel eachother out, so the arrow changes positions
    This problem is really bugging me. I appreciate any help. Thanks.
    -kc

    Well I fixed my problem but I kind of cheated...
    I used a static variable in the class that inits the GUI to keep track of the MouseListeners that are added to the table headers by the TableSorter. In the TableSorter class's addMouseListenerToTableHeader(JTable table) class I added a line of code before the "th.addMouseListener(listListener)" line: "th.removeMouseListener(Projector.lastListener))"
    It works but it kind of sucks. If there is a better way to do it that would be great. I'm sorry if you read through all of that stuff and then I ended up fixing my own problem anyway :(
    Thanks anyway.
    -kc

  • Editing a JTable Feild (setValueAt)

    Hi, I have a series of tables that each pull different data from a database and then desplay the data to the user. The user has the ability to update the shown data by editing the field(s) displayed in the table. To complete the update, I want to error check their change (to make sure they didn't leave the field blank for example) and then I want to update the database before allowing the new value to be the one that's shown in the table. In other words if error checking or updating the database result in an error, an error message is displayed and the origional value is left in the "updated" field.
    What I was doing to accomplish this was adding a custom Table Model to each table with error checking code in the setValueAt method of the Table Model.
    Now, I want a standard table model that all of my tables use to reduce the number of classes I have from 1 frame, x number of table models to 1 frame, 1 table model. The problem I'm having is, by standardizing the table model, I have to remove all error checking and database updates as they are unique to each individual table. I've tryed to add TableModelListeners to my frame but I found out that the TableModelListener is executed after the setValueAt in the Table Model. This won't work for me as, while I can error check and update the newly changed data, if there is an error, I can't revert back to what was previously displayed without recalling the database.
    I guess what my questions are are: What can I do to stop setValueAt from running until after I've error checked. Also, what tells the table/table model about the end of an edit and calls setValueAt in the first place?
    Any help would be wonderful. Thanks in advance!
    --Ethan                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

    what I think you should do is this: extend this class (which i found on the sun site) and extend it for your needs.
    the idea is to have a model as a proxy of the real model - this model holds a different model inside it and before activiating it it can do stuff, meaning - before call the "real" setValueAt you can do error checking.
    I'm also adding the SortModel which I found to be very helpful - it allows you to sort any table with 0 code. (and it's a nice example to how to use the TableMap class.
    all the luck to you.
    btw, you will still have as many tableModels, just smaller in code.
    public class TableMap extends AbstractTableModel
    implements TableModelListener {
    protected TableModel model;
    public TableModel getModel() {
    return model;
    public void setModel(TableModel model) {
    this.model = model;
    model.addTableModelListener(this);
    // By default, implement TableModel by forwarding all messages
    // to the model.
    public Object getValueAt(int aRow, int aColumn) {
    return model.getValueAt(aRow, aColumn);
    public void setValueAt(Object aValue, int aRow, int aColumn) {
    model.setValueAt(aValue, aRow, aColumn);
    public int getRowCount() {
    return (model == null) ? 0 : model.getRowCount();
    public int getColumnCount() {
    return (model == null) ? 0 : model.getColumnCount();
    public String getColumnName(int aColumn) {
    return model.getColumnName(aColumn);
    public Class getColumnClass(int aColumn) {
    return model.getColumnClass(aColumn);
    public boolean isCellEditable(int row, int column) {
    return model.isCellEditable(row, column);
    // Implementation of the TableModelListener interface,
    // By default forward all events to all the listeners.
    public void tableChanged(TableModelEvent e) {
    fireTableChanged(e);
    * A sorter for TableModels. The sorter has a model (conforming to TableModel)
    * and itself implements TableModel. TableSorter does not store or copy
    * the data in the TableModel, instead it maintains an array of
    * integers which it keeps the same size as the number of rows in its
    * model. When the model changes it notifies the sorter that something
    * has changed eg. "rowsAdded" so that its internal array of integers
    * can be reallocated. As requests are made of the sorter (like
    * getValueAt(row, col) it redirects them to its model via the mapping
    * array. That way the TableSorter appears to hold another copy of the table
    * with the rows in a different order. The sorting algorthm used is stable
    * which means that it does not move around rows when its comparison
    * function returns 0 to denote that they are equivalent.
    * @version 1.5 12/17/97
    * @author Philip Milne
    import java.util.*;
    import javax.swing.table.TableModel;
    import javax.swing.event.TableModelEvent;
    // Imports for picking up mouse events from the JTable.
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.event.InputEvent;
    import javax.swing.JTable;
    import javax.swing.table.JTableHeader;
    import javax.swing.table.TableColumnModel;
    public class TableSorter extends TableMap {
    int indexes[];
    Vector sortingColumns = new Vector();
    boolean ascending = true;
    int compares;
    public TableSorter() {
    indexes = new int[0]; // for consistency
    public TableSorter(TableModel model) {
    setModel(model);
    public void setModel(TableModel model) {
    super.setModel(model);
    reallocateIndexes();
    public int compareRowsByColumn(int row1, int row2, int column) {
    Class type = model.getColumnClass(column);
    TableModel data = model;
    // Check for nulls.
    Object o1 = data.getValueAt(row1, column);
    Object o2 = data.getValueAt(row2, column);
    // If both values are null, return 0.
    if (o1 == null && o2 == null) {
    return 0;
    } else if (o1 == null) { // Define null less than everything.
    return -1;
    } else if (o2 == null) {
    return 1;
    * We copy all returned values from the getValue call in case
    * an optimised model is reusing one object to return many
    * values. The Number subclasses in the JDK are immutable and
    * so will not be used in this way but other subclasses of
    * Number might want to do this to save space and avoid
    * unnecessary heap allocation.
    if (type.getSuperclass() == java.lang.Number.class) {
    Number n1 = (Number)data.getValueAt(row1, column);
    double d1 = n1.doubleValue();
    Number n2 = (Number)data.getValueAt(row2, column);
    double d2 = n2.doubleValue();
    if (d1 < d2) {
    return -1;
    } else if (d1 > d2) {
    return 1;
    } else {
    return 0;
    } else if (type == java.util.Date.class) {
    Date d1 = (Date)data.getValueAt(row1, column);
    long n1 = d1.getTime();
    Date d2 = (Date)data.getValueAt(row2, column);
    long n2 = d2.getTime();
    if (n1 < n2) {
    return -1;
    } else if (n1 > n2) {
    return 1;
    } else {
    return 0;
    } else if (type == String.class) {
    String s1 = (String)data.getValueAt(row1, column);
    String s2 = (String)data.getValueAt(row2, column);
    int result = s1.compareTo(s2);
    if (result < 0) {
    return -1;
    } else if (result > 0) {
    return 1;
    } else {
    return 0;
    } else if (type == Boolean.class) {
    Boolean bool1 = (Boolean)data.getValueAt(row1, column);
    boolean b1 = bool1.booleanValue();
    Boolean bool2 = (Boolean)data.getValueAt(row2, column);
    boolean b2 = bool2.booleanValue();
    if (b1 == b2) {
    return 0;
    } else if (b1) { // Define false < true
    return 1;
    } else {
    return -1;
    } else {
    Object v1 = data.getValueAt(row1, column);
    String s1 = v1.toString();
    Object v2 = data.getValueAt(row2, column);
    String s2 = v2.toString();
    int result = s1.compareTo(s2);
    if (result < 0) {
    return -1;
    } else if (result > 0) {
    return 1;
    } else {
         return 0;
    public int compare(int row1, int row2) {
    compares++;
    for (int level = 0; level < sortingColumns.size(); level++) {
    Integer column = (Integer)sortingColumns.elementAt(level);
    int result = compareRowsByColumn(row1, row2, column.intValue());
    if (result != 0) {
    return ascending ? result : -result;
    return 0;
    public void reallocateIndexes() {
    int rowCount = model.getRowCount();
    // Set up a new array of indexes with the right number of elements
    // for the new data model.
    indexes = new int[rowCount];
    // Initialise with the identity mapping.
    for (int row = 0; row < rowCount; row++) {
    indexes[row] = row;
    public void tableChanged(TableModelEvent e) {
    reallocateIndexes();
    super.tableChanged(e);
    public void checkModel() {
    if (indexes.length != model.getRowCount()) {
    System.err.println("Sorter not informed of a change in model.");
    public void sort(Object sender) {
    checkModel();
    compares = 0;
    // n2sort();
    // qsort(0, indexes.length-1);
    shuttlesort((int[])indexes.clone(), indexes, 0, indexes.length);
    public void n2sort() {
    for (int i = 0; i < getRowCount(); i++) {
    for (int j = i+1; j < getRowCount(); j++) {
    if (compare(indexes, indexes[j]) == -1) {
    swap(i, j);
    // This is a home-grown implementation which we have not had time
    // to research - it may perform poorly in some circumstances. It
    // requires twice the space of an in-place algorithm and makes
    // NlogN assigments shuttling the values between the two
    // arrays. The number of compares appears to vary between N-1 and
    // NlogN depending on the initial order but the main reason for
    // using it here is that, unlike qsort, it is stable.
    public void shuttlesort(int from[], int to[], int low, int high) {
    if (high - low < 2) {
    return;
    int middle = (low + high)/2;
    shuttlesort(to, from, low, middle);
    shuttlesort(to, from, middle, high);
    int p = low;
    int q = middle;
    /* This is an optional short-cut; at each recursive call,
    check to see if the elements in this subset are already
    ordered. If so, no further comparisons are needed; the
    sub-array can just be copied. The array must be copied rather
    than assigned otherwise sister calls in the recursion might
    get out of sinc. When the number of elements is three they
    are partitioned so that the first set, [low, mid), has one
            element and and the second, [mid, high), has two. We skip the
            optimisation when the number of elements is three or less as
            the first compare in the normal merge will produce the same
            sequence of steps. This optimisation seems to be worthwhile
            for partially ordered lists but some analysis is needed to
            find out how the performance drops to Nlog(N) as the initial
            order diminishes - it may drop very quickly.  */
            if (high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) {
    for (int i = low; i < high; i++) {
    to[i] = from[i];
    return;
    // A normal merge.
    for (int i = low; i < high; i++) {
    if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
    to[i] = from[p++];
    else {
    to[i] = from[q++];
    public void swap(int i, int j) {
    int tmp = indexes[i];
    indexes[i] = indexes[j];
    indexes[j] = tmp;
    // The mapping only affects the contents of the data rows.
    // Pass all requests to these rows through the mapping array: "indexes".
    public Object getValueAt(int aRow, int aColumn) {
    checkModel();
    return model.getValueAt(indexes[aRow], aColumn);
    public void setValueAt(Object aValue, int aRow, int aColumn) {
    checkModel();
    model.setValueAt(aValue, indexes[aRow], aColumn);
    public void sortByColumn(int column) {
    sortByColumn(column, true);
    public void sortByColumn(int column, boolean ascending) {
    this.ascending = ascending;
    sortingColumns.removeAllElements();
    sortingColumns.addElement(new Integer(column));
    sort(this);
    super.tableChanged(new TableModelEvent(this));
    // There is no-where else to put this.
    // Add a mouse listener to the Table to trigger a table sort
    // when a column heading is clicked in the JTable.
    public void addMouseListenerToHeaderInTable(JTable table) {
    final TableSorter sorter = this;
    final JTable tableView = table;
    tableView.setColumnSelectionAllowed(false);
    MouseAdapter listMouseListener = new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
    TableColumnModel columnModel = tableView.getColumnModel();
    int viewColumn = columnModel.getColumnIndexAtX(e.getX());
    int column = tableView.convertColumnIndexToModel(viewColumn);
    if (e.getClickCount() == 1 && column != -1) {
    int shiftPressed = e.getModifiers()&InputEvent.SHIFT_MASK;
    boolean ascending = (shiftPressed == 0);
    sorter.sortByColumn(column, ascending);
    JTableHeader th = tableView.getTableHeader();
    th.addMouseListener(listMouseListener);
    Glazberg.

Maybe you are looking for

  • Differernce between SQL Tuning Pack and SQL Tuning Advisor, Access Advisor

    Hi. all. I have been using "TKPROF" in order to tune SQL till now. I am learning 10g, and would like to know the difference between "1. SQL Tuning Pack" and "2. SQL Tuning Advisor, Access Advisor". Are they same thing? If not, what are the difference

  • I book G 4 used 2004- 2005

    I boughtthis off e-bay& it is not starting up properly. It goes to a grey screen & stops. Nothing else happens. II have a sheet from the genius Bar they had done before they sold it to me which says theyzerod out drive &installed Tiger & I life 06& u

  • Configure DAQ cards in RT PXI system

    Greetings all, I'm just trying to learn how to use Real Time and I'm having trouble setting up the DAQ cards in the PXI chassis. I am able to successfully connect to the PXI RT system and run simple VI's that have no DAQ or VISA access. What I can't

  • WBS Scheduling procedure --

    Good Morning Experts .. Please explain me all the steps to be  required  in WBS scheduling at user end .. as per me in our scenario - we are doing- 1.first of all we assign the activitis to WBS then we make the relationship between them then we sched

  • What is the BEST file format for editing HD in CS5?

    We are building a remote production truck and it will be tapeless with all hard disk video recording. We have not decided on what brand of disk based recording system we are getting. I am looking for opinions of what the most ideal file format to cap