Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

InfoTableSorter.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Philip Milne.
00022  * Contributor(s): Emmanuel Cecchet.
00023  */
00024 
00025 package org.objectweb.cjdbc.console.views;
00026 
00027 import java.awt.event.InputEvent;
00028 import java.awt.event.MouseAdapter;
00029 import java.awt.event.MouseEvent;
00030 import java.util.Date;
00031 import java.util.Vector;
00032 
00033 import javax.swing.JTable;
00034 import javax.swing.event.TableModelEvent;
00035 import javax.swing.event.TableModelListener;
00036 import javax.swing.table.AbstractTableModel;
00037 import javax.swing.table.JTableHeader;
00038 import javax.swing.table.TableColumnModel;
00039 import javax.swing.table.TableModel;
00040 
00041 /**
00042  * This code is inspired from the Swing tutorial demo version 1.5 12/17/97 from
00043  * Philip Milne. It sorts the table when you click on a header.
00044  * 
00045  * @author Philip Milne
00046  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet</a>
00047  * @version 1.0
00048  */
00049 
00050 public class InfoTableSorter
00051   extends AbstractTableModel
00052   implements TableModelListener
00053 {
00054   private TableModel model;
00055   private int indexes[];
00056   private Vector sortingColumns = new Vector();
00057   private boolean ascending = true;
00058   private int compares;
00059 
00060   /**
00061    * Constructor
00062    * 
00063    * @param model TableModel to use
00064    */
00065   public InfoTableSorter(TableModel model)
00066   {
00067     setModel(model);
00068   }
00069 
00070   private void setModel(TableModel model)
00071   {
00072     this.model = model;
00073     model.addTableModelListener(this);
00074     reallocateIndexes();
00075   }
00076 
00077   /**
00078    * @see javax.swing.table.TableModel#getRowCount()
00079    */
00080   public int getRowCount()
00081   {
00082     return (model == null) ? 0 : model.getRowCount();
00083   }
00084 
00085   /**
00086    * @see javax.swing.table.TableModel#getColumnCount()
00087    */
00088   public int getColumnCount()
00089   {
00090     return (model == null) ? 0 : model.getColumnCount();
00091   }
00092 
00093   /**
00094    * @see javax.swing.table.TableModel#getColumnName(int)
00095    */
00096   public String getColumnName(int aColumn)
00097   {
00098     return model.getColumnName(aColumn);
00099   }
00100 
00101   /**
00102    * @see javax.swing.table.TableModel#getColumnClass(int)
00103    */
00104   public Class getColumnClass(int aColumn)
00105   {
00106     return model.getColumnClass(aColumn);
00107   }
00108 
00109   /**
00110    * @see javax.swing.event.TableModelListener#tableChanged(javax.swing.event.TableModelEvent)
00111    */
00112   public void tableChanged(TableModelEvent e)
00113   {
00114     reallocateIndexes();
00115     fireTableChanged(e);
00116   }
00117 
00118   // The mapping only affects the contents of the data rows.
00119   // Pass all requests to these rows through the mapping array: "indexes".
00120 
00121   /**
00122    * @see javax.swing.table.TableModel#getValueAt(int, int)
00123    */
00124   public Object getValueAt(int aRow, int aColumn)
00125   {
00126     return model.getValueAt(indexes[aRow], aColumn);
00127   }
00128 
00129   /**
00130    * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
00131    */
00132   public void setValueAt(Object aValue, int aRow, int aColumn)
00133   {
00134     model.setValueAt(aValue, indexes[aRow], aColumn);
00135   }
00136 
00137   /**
00138    * Add a mouse listener to the Table to trigger a table sort when a column
00139    * heading is clicked in the JTable.
00140    * 
00141    * @param table the JTable to sort
00142    */
00143   public void addMouseListenerToHeaderInTable(JTable table)
00144   {
00145     final InfoTableSorter sorter = this;
00146     final JTable tableView = table;
00147     tableView.setColumnSelectionAllowed(false);
00148     MouseAdapter listMouseListener = new MouseAdapter()
00149     {
00150       public void mouseClicked(MouseEvent e)
00151       {
00152         TableColumnModel columnModel = tableView.getColumnModel();
00153         int viewColumn = columnModel.getColumnIndexAtX(e.getX());
00154         int column = tableView.convertColumnIndexToModel(viewColumn);
00155         if (e.getClickCount() == 1 && column != -1)
00156         {
00157           int shiftPressed = e.getModifiers() & InputEvent.SHIFT_MASK;
00158           boolean ascending = (shiftPressed == 0);
00159           sorter.sortByColumn(column, ascending);
00160         }
00161       }
00162     };
00163     JTableHeader th = tableView.getTableHeader();
00164     th.addMouseListener(listMouseListener);
00165   }
00166 
00167   private void sortByColumn(int column, boolean ascending)
00168   {
00169     this.ascending = ascending;
00170     sortingColumns.removeAllElements();
00171     sortingColumns.addElement(new Integer(column));
00172     compares = 0;
00173     for (int i = 0; i < getRowCount(); i++)
00174       for (int j = i + 1; j < getRowCount(); j++)
00175         if (compare(indexes[i], indexes[j]) == -1)
00176           swap(i, j);
00177 
00178     fireTableChanged(new TableModelEvent(this));
00179   }
00180 
00181   private int compareRowsByColumn(int row1, int row2, int column)
00182   {
00183     int result = 0;
00184     Class type = model.getColumnClass(column);
00185     TableModel data = model;
00186 
00187     // Check for nulls.
00188 
00189     Object o1 = data.getValueAt(row1, column);
00190     Object o2 = data.getValueAt(row2, column);
00191 
00192     // If both values are null, return 0.
00193     if (o1 == null && o2 == null)
00194       return 0;
00195     else if (o1 == null)
00196       // Define null less than everything.
00197       return -1;
00198     else if (o2 == null)
00199       return 1;
00200 
00201     if (type.getSuperclass() == java.lang.Number.class)
00202     {
00203       Number n1 = (Number) data.getValueAt(row1, column);
00204       double d1 = n1.doubleValue();
00205       Number n2 = (Number) data.getValueAt(row2, column);
00206       double d2 = n2.doubleValue();
00207       result = (int) (d1 - d2);
00208     }
00209     else if (type == java.util.Date.class)
00210     {
00211       Date d1 = (Date) data.getValueAt(row1, column);
00212       long n1 = d1.getTime();
00213       Date d2 = (Date) data.getValueAt(row2, column);
00214       long n2 = d2.getTime();
00215       result = (int) (n1 - n2);
00216     }
00217     else if (type == String.class)
00218     {
00219       String s1 = (String) data.getValueAt(row1, column);
00220       String s2 = (String) data.getValueAt(row2, column);
00221       result = s1.compareTo(s2);
00222     }
00223     else
00224     {
00225       Object v1 = data.getValueAt(row1, column);
00226       String s1 = v1.toString();
00227       Object v2 = data.getValueAt(row2, column);
00228       String s2 = v2.toString();
00229       result = s1.compareTo(s2);
00230     }
00231     if (result < 0)
00232       return -1;
00233     else if (result > 0)
00234       return 1;
00235     else
00236       return 0;
00237   }
00238 
00239   private int compare(int row1, int row2)
00240   {
00241     compares++;
00242     for (int level = 0; level < sortingColumns.size(); level++)
00243     {
00244       Integer column = (Integer) sortingColumns.elementAt(level);
00245       int result = compareRowsByColumn(row1, row2, column.intValue());
00246       if (result != 0)
00247         return ascending ? result : -result;
00248     }
00249     return 0;
00250   }
00251 
00252   private void reallocateIndexes()
00253   {
00254     int rowCount = model.getRowCount();
00255 
00256     // Set up a new array of indexes with the right number of elements
00257     // for the new data model.
00258     indexes = new int[rowCount];
00259 
00260     // Initialise with the identity mapping.
00261     for (int row = 0; row < rowCount; row++)
00262     {
00263       indexes[row] = row;
00264     }
00265   }
00266 
00267   private void swap(int i, int j)
00268   {
00269     int tmp = indexes[i];
00270     indexes[i] = indexes[j];
00271     indexes[j] = tmp;
00272   }
00273 
00274 }

Generated on Mon Apr 11 22:01:32 2005 for C-JDBC by  doxygen 1.3.9.1