001: /*
002: * $Id: SortFilterModel.java 471756 2006-11-06 15:01:43Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.components.table;
022:
023: import java.awt.event.MouseAdapter;
024: import java.awt.event.MouseEvent;
025: import java.util.ArrayList;
026: import java.util.Collections;
027:
028: import javax.swing.JTable;
029: import javax.swing.event.TableModelEvent;
030: import javax.swing.event.TableModelListener;
031: import javax.swing.table.TableModel;
032:
033: /**
034: */
035: public class SortFilterModel extends AbstractFilterModel implements
036: TableModelListener, SortableTableModel {
037:
038: private static final long serialVersionUID = 2214225803442793597L;
039:
040: private ArrayList rows = new ArrayList();
041:
042: /**
043: * These are just here to implement the interface
044: */
045: private String _sortDirection = NONE;
046: private boolean dirty = true;
047: private int sortColumn = -1;
048:
049: public SortFilterModel(TableModel tm) {
050: super (tm);
051: setModel(tm);
052: }
053:
054: public boolean isCellEditable(int r, int c) {
055: if ((rows.size() > 0) && (r < rows.size())) {
056: return model.isCellEditable(((Row) rows.get(r)).index, c);
057: }
058:
059: return false;
060: }
061:
062: public void setModel(TableModel tm) {
063: super .setModel(tm);
064: rows.ensureCapacity(model.getRowCount());
065: model.addTableModelListener(this );
066: sortColumn = -1;
067: dirty = true;
068: refresh();
069: }
070:
071: public int getSortedColumnNumber() {
072: return sortColumn;
073: }
074:
075: public String getSortedDirection(int columnNumber) {
076: if (getSortedColumnNumber() < 0) {
077: return NONE;
078: }
079:
080: return _sortDirection;
081: }
082:
083: public void setValueAt(Object aValue, int r, int c) {
084: if ((rows.size() > 0) && (r < rows.size())) {
085: model.setValueAt(aValue, ((Row) rows.get(r)).index, c);
086: }
087: }
088:
089: /* compute the moved row for the three methods that access
090: model elements
091: */
092: public Object getValueAt(int r, int c) {
093: if ((rows.size() > 0) && (r < rows.size())) {
094: return model.getValueAt(((Row) rows.get(r)).index, c);
095: }
096:
097: return null;
098: }
099:
100: public void addMouseListener(final JTable table) {
101: table.getTableHeader().addMouseListener(new MouseAdapter() {
102: public void mouseClicked(MouseEvent event) {
103: // check for double click
104: if (event.getClickCount() < 2) {
105: return;
106: }
107:
108: // find column of click and
109: int tableColumn = table.columnAtPoint(event.getPoint());
110:
111: // translate to table model index and sort
112: int modelColumn = table
113: .convertColumnIndexToModel(tableColumn);
114: sort(modelColumn);
115: }
116: });
117: }
118:
119: public void removeRow(int rowNum)
120: throws ArrayIndexOutOfBoundsException,
121: IllegalStateException {
122: int mappedRow = ((Row) rows.get(rowNum)).index;
123: super .removeRow(mappedRow);
124: }
125:
126: public void sort(int columnNumber, String direction) {
127: _sortDirection = ASC;
128: dirty = true;
129: sort(columnNumber);
130:
131: if (DESC.equals(direction)) {
132: sort(columnNumber);
133: _sortDirection = DESC;
134: }
135: }
136:
137: /**
138: * Implements the TableModelListener interface to receive
139: * notifications of * changes to the table model. SortFilterModel needs
140: * to receive events for adding and removing rows.
141: */
142: public void tableChanged(TableModelEvent e) {
143: dirty = true;
144: refresh();
145: fireTableChanged(e);
146: }
147:
148: protected void refresh() {
149: rows.clear();
150:
151: for (int i = 0; i < model.getRowCount(); i++) {
152: rows.add(new Row(i));
153: }
154:
155: if (dirty && (sortColumn > -1)) {
156: sort(sortColumn);
157: }
158: }
159:
160: protected void sort(int c) {
161: boolean sorted = (sortColumn == c);
162: sortColumn = c;
163:
164: if (dirty || !sorted) {
165: Collections.sort(rows);
166: dirty = false;
167: } else {
168: Collections.reverse(rows);
169: }
170:
171: fireTableDataChanged();
172: }
173:
174: /* this inner class holds the index of the model row
175: * Rows are compared by looking at the model row entries
176: * in the sort column
177: */
178: private class Row implements Comparable {
179: public int index;
180:
181: public Row(int index) {
182: this .index = index;
183: }
184:
185: public int compareTo(Object other) {
186: Row otherRow = (Row) other;
187: Object a = model.getValueAt(index, sortColumn);
188: Object b = model.getValueAt(otherRow.index, sortColumn);
189:
190: boolean areTheyCompareable = (a instanceof Comparable
191: && b instanceof Comparable && (a.getClass() == b
192: .getClass()));
193:
194: if (areTheyCompareable) {
195: return ((Comparable) a).compareTo((Comparable) b);
196: } else {
197: return a.toString().compareTo(b.toString());
198: }
199: }
200: }
201: }
|