View Javadoc

1   // Copyright 2004, FreeHEP.
2   package org.lcsim.plugin.browser.sort;
3   
4   import java.awt.Component;
5   import java.awt.Graphics;
6   import java.beans.PropertyChangeEvent;
7   import java.beans.PropertyChangeListener;
8   
9   import javax.swing.Icon;
10  import javax.swing.JLabel;
11  import javax.swing.JTable;
12  import javax.swing.table.JTableHeader;
13  import javax.swing.table.TableModel;
14  import org.freehep.swing.table.TableColumnHeaderListener;
15  import org.freehep.swing.table.TableHeaderCellRenderer;
16  
17  /**
18   * Utility to add a sorter for columns to a JTable which has a SortableTableModel.
19   * <p>
20   * Example of use:
21   * <pre>
22   *  TableModel model = ...
23   *  DefaultSortableTableModel sm = new DefaultSortableTableModel(model);
24   *  JTable table = new JTable(sm);
25   *  TableSorter sorter = new TableSorter(table);
26   * </pre>
27   * @author Mark Donszelmann
28   * @author Tony Johnson
29   * @version $Id: TableSorter.java,v 1.1 2007/06/01 23:58:58 tonyj Exp $
30   * @see org.freehep.swing.table.SortableTableModel
31   */
32  public class TableSorter
33  {
34     private static Icon downTriangle = new Triangle(false);
35     private static Icon upTriangle = new Triangle(true);
36     
37     private SortableTableModel model;
38     private JTableHeader header;
39     
40     /**
41      * Create a TableSorter. The table will initially be unsorted.
42      * @param table The table to be sorted
43      */
44     public TableSorter(JTable table)
45     {
46        table.addPropertyChangeListener("model",new ModelChangeListener());
47        modelChanged(table.getModel());
48        header = table.getTableHeader();
49        header.addMouseListener(new HeaderListener());
50        header.setDefaultRenderer(new HeaderRenderer());
51     }
52     
53     /**
54      * Create a TableSorter. The table will initially be sorted in ascending order by the given column.
55      * @param table The table to be sorted.
56      * @param column The column on which to sort, or <CODE>SortableTableModel.UNSORTED</CODE>
57      */
58     public TableSorter(JTable table, int column)
59     {
60        this(table, column, true);
61     }
62     
63     /**
64      * Create a TableSorter specifiying initial sorting parameters.
65      * @param table The table to be sorted.
66      * @param column The column on which to sort, or <CODE>SortableTableModel.UNSORTED</CODE>
67      * @param ascending <CODE>true</CODE> for ascending order, <CODE>false</CODE> for descending order
68      */
69     public TableSorter(JTable table, int column, boolean ascending)
70     {
71        this(table);
72        sort(column,ascending);
73     }
74     
75     /**
76      * Find the current sort column.
77      * @return The current sort column, or <CODE>SortableTableModel.UNSORTED</CODE>
78      */
79     public int getSortOnColumn()
80     {
81        return model == null ? SortableTableModel.UNSORTED : model.getSortOnColumn();
82     }
83     
84     /**
85      * Set the sort column.
86      * @param column The column on which to sort, or <CODE>SortableTableModel.UNSORTED</CODE>
87      */
88     public void setSortOnColumn(int column)
89     {
90        if (model != null) model.sort(column,true);
91     }
92     
93     /**
94      * Get the current sort order.
95      * @return <CODE>true</CODE> if ascending order, <CODE>false</CODE> for descending order.
96      */
97     public boolean isSortAscending()
98     {
99        return model == null ? true : model.isSortAscending();
100    }
101    
102    /**
103     * Set the current sort order.
104     * @param ascending <CODE>true</CODE> for ascending order, <CODE>false</CODE> for descending order
105     */
106    public void setSortAscending(boolean ascending)
107    {
108       if (model != null) model.sort(model.getSortOnColumn(),ascending);
109    }
110    
111    private void sort(int sortOnColumn, boolean sortAscending)
112    {
113       if (model != null)
114       {
115          model.sort(sortOnColumn, sortAscending);
116          header.resizeAndRepaint();
117       }
118    }
119    private void modelChanged(TableModel model)
120    {
121       this.model = model instanceof SortableTableModel ? (SortableTableModel) model : null;
122    }
123    private class ModelChangeListener implements PropertyChangeListener
124    {
125       public void propertyChange(PropertyChangeEvent evt)
126       {
127          modelChanged((TableModel) evt.getNewValue());
128       }
129    }
130    private class HeaderListener extends TableColumnHeaderListener
131    {
132       
133       public void headerClicked(JTable table, int col)
134       {
135          if (model != null)
136          {
137             if (col != model.getSortOnColumn())
138             {
139                sort(col, true);
140             }
141             else
142             {
143                sort(model.getSortOnColumn(), !model.isSortAscending());
144             }
145          }
146       }
147    }
148    
149    private class HeaderRenderer extends TableHeaderCellRenderer
150    {
151       
152       public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
153       {
154          JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
155          if (model != null && table.convertColumnIndexToModel(col) == model.getSortOnColumn())
156          {
157             label.setIcon(model.isSortAscending() ? downTriangle : upTriangle);
158          }
159          else
160          {
161             label.setIcon(null);
162          }
163          return label;
164       }
165    }
166    private static class Triangle implements Icon
167    {
168       private boolean up;
169       private static final int size = 16;
170       private static final int[] xxdown = { 3 , 12, 7 };
171       private static final int[] yydown = { 5 , 5, 10 };
172       private static final int[] xxup = { 2 , 12, 7 };
173       private static final int[] yyup = { 10 , 10, 4 };
174       Triangle(boolean up)
175       {
176          this.up = up;
177       }
178       
179       public int getIconHeight()
180       {
181          return size;
182       }
183       
184       public int getIconWidth()
185       {
186          return size;
187       }
188       
189       public void paintIcon(Component c, Graphics g, int x, int y)
190       {
191          int[] xp = new int[3];
192          int[] yp = new int[3];
193          for (int i=0; i<3; i++)
194          {
195             xp[i] = x + (up ? xxup[i] : xxdown[i]);
196             yp[i] = y + (up ? yyup[i] : yydown[i]);
197          }
198          g.setColor(c.getForeground());
199          g.fillPolygon(xp,yp,3);
200       }
201    }
202 }