View Javadoc

1   /*
2    * $Id: SortFilterModel.java 439747 2006-09-03 09:22:46Z mrdon $
3    *
4    * Copyright 2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts2.components.table;
19  
20  import java.awt.event.MouseAdapter;
21  import java.awt.event.MouseEvent;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  
25  import javax.swing.JTable;
26  import javax.swing.event.TableModelEvent;
27  import javax.swing.event.TableModelListener;
28  import javax.swing.table.TableModel;
29  
30  
31  /***
32   */
33  public class SortFilterModel extends AbstractFilterModel implements TableModelListener, SortableTableModel {
34  
35  	private static final long serialVersionUID = 2214225803442793597L;
36  
37  	private ArrayList rows = new ArrayList();
38  
39      /***
40       * These are just here to implement the interface
41       */
42      private String _sortDirection = NONE;
43      private boolean dirty = true;
44      private int sortColumn = -1;
45  
46  
47      public SortFilterModel(TableModel tm) {
48          super(tm);
49          setModel(tm);
50      }
51  
52  
53      public boolean isCellEditable(int r, int c) {
54          if ((rows.size() > 0) && (r < rows.size())) {
55              return model.isCellEditable(((Row) rows.get(r)).index, c);
56          }
57  
58          return false;
59      }
60  
61      public void setModel(TableModel tm) {
62          super.setModel(tm);
63          rows.ensureCapacity(model.getRowCount());
64          model.addTableModelListener(this);
65          sortColumn = -1;
66          dirty = true;
67          refresh();
68      }
69  
70      public int getSortedColumnNumber() {
71          return sortColumn;
72      }
73  
74      public String getSortedDirection(int columnNumber) {
75          if (getSortedColumnNumber() < 0) {
76              return NONE;
77          }
78  
79          return _sortDirection;
80      }
81  
82      public void setValueAt(Object aValue, int r, int c) {
83          if ((rows.size() > 0) && (r < rows.size())) {
84              model.setValueAt(aValue, ((Row) rows.get(r)).index, c);
85          }
86      }
87  
88      /* compute the moved row for the three methods that access
89         model elements
90      */
91      public Object getValueAt(int r, int c) {
92          if ((rows.size() > 0) && (r < rows.size())) {
93              return model.getValueAt(((Row) rows.get(r)).index, c);
94          }
95  
96          return null;
97      }
98  
99      public void addMouseListener(final JTable table) {
100         table.getTableHeader().addMouseListener(new MouseAdapter() {
101             public void mouseClicked(MouseEvent event) {
102                 // check for double click
103                 if (event.getClickCount() < 2) {
104                     return;
105                 }
106 
107                 // find column of click and
108                 int tableColumn = table.columnAtPoint(event.getPoint());
109 
110                 // translate to table model index and sort
111                 int modelColumn = table.convertColumnIndexToModel(tableColumn);
112                 sort(modelColumn);
113             }
114         });
115     }
116 
117     public void removeRow(int rowNum) throws ArrayIndexOutOfBoundsException, IllegalStateException {
118         int mappedRow = ((Row) rows.get(rowNum)).index;
119         super.removeRow(mappedRow);
120     }
121 
122     public void sort(int columnNumber, String direction) {
123         _sortDirection = ASC;
124         dirty = true;
125         sort(columnNumber);
126 
127         if (DESC.equals(direction)) {
128             sort(columnNumber);
129             _sortDirection = DESC;
130         }
131     }
132 
133     /***
134      * Implements the TableModelListener interface to receive
135      * notifications of * changes to the table model. SortFilterModel needs
136      * to receive events for adding and removing rows.
137      */
138     public void tableChanged(TableModelEvent e) {
139         dirty = true;
140         refresh();
141         fireTableChanged(e);
142     }
143 
144     protected void refresh() {
145         rows.clear();
146 
147         for (int i = 0; i < model.getRowCount(); i++) {
148             rows.add(new Row(i));
149         }
150 
151         if (dirty && (sortColumn > -1)) {
152             sort(sortColumn);
153         }
154     }
155 
156     protected void sort(int c) {
157         boolean sorted = (sortColumn == c);
158         sortColumn = c;
159 
160         if (dirty || !sorted) {
161             Collections.sort(rows);
162             dirty = false;
163         } else {
164             Collections.reverse(rows);
165         }
166 
167         fireTableDataChanged();
168     }
169 
170 
171     /* this inner class holds the index of the model row
172      * Rows are compared by looking at the model row entries
173      * in the sort column
174      */
175     private class Row implements Comparable {
176         public int index;
177 
178         public Row(int index) {
179             this.index = index;
180         }
181 
182         public int compareTo(Object other) {
183             Row otherRow = (Row) other;
184             Object a = model.getValueAt(index, sortColumn);
185             Object b = model.getValueAt(otherRow.index, sortColumn);
186 
187             boolean areTheyCompareable = (a instanceof Comparable && b instanceof Comparable && (a.getClass() == b.getClass()));
188 
189             if (areTheyCompareable) {
190                 return ((Comparable) a).compareTo((Comparable) b);
191             } else {
192                 return a.toString().compareTo(b.toString());
193             }
194         }
195     }
196 }