001/*
002 * $Id$
003 *
004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 * 
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 * 
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 *
021 */
022package org.jdesktop.swingx.sort;
023
024import java.text.Collator;
025import java.util.Comparator;
026
027import javax.swing.table.TableModel;
028
029/**
030 * A SortController to use for a JXTable.<p>
031 * 
032 * @author Jeanette Winzenburg
033 */
034public class TableSortController<M extends TableModel> extends DefaultSortController<M>  {
035    /**
036     * Underlying model.
037     */
038    private M tableModel;
039    
040    public TableSortController() {
041        this(null);
042    }
043    
044    /**
045     * @param model
046     */
047    public TableSortController(M model) {
048        super();
049        setModel(model);
050    }
051
052    /**
053     * Sets the <code>TableModel</code> to use as the underlying model
054     * for this <code>TableRowSorter</code>.  A value of <code>null</code>
055     * can be used to set an empty model.
056     *
057     * @param model the underlying model to use, or <code>null</code>
058     */
059    public void setModel(M model) {
060        tableModel = model;
061        if (model != null)
062            cachedModelRowCount = model.getRowCount();
063        setModelWrapper(new TableRowSorterModelWrapper());
064    }
065
066    
067    /**
068     * Returns the <code>Comparator</code> for the specified 
069     * column.  If a <code>Comparator</code> has not been specified using
070     * the <code>setComparator</code> method a <code>Comparator</code>
071     * will be returned based on the column class
072     * (<code>TableModel.getColumnClass</code>) of the specified column.
073     * If the column class is <code>String</code>,
074     * <code>Collator.getInstance</code> is returned.  If the
075     * column class implements <code>Comparable</code> a private
076     * <code>Comparator</code> is returned that invokes the
077     * <code>compareTo</code> method.  Otherwise
078     * <code>Collator.getInstance</code> is returned.<p>
079     * 
080     * PENDING JW: think about implications to string value lookup!
081     *
082     * @throws IndexOutOfBoundsException {@inheritDoc}
083     */
084    @Override
085    public Comparator<?> getComparator(int column) {
086        Comparator<?> comparator = super.getComparator(column);
087        if (comparator != null) {
088            return comparator;
089        }
090        Class<?> columnClass = getModel().getColumnClass(column);
091        if (columnClass == String.class) {
092            return Collator.getInstance();
093        }
094        if (Comparable.class.isAssignableFrom(columnClass)) {
095            return COMPARABLE_COMPARATOR;
096        }
097        return Collator.getInstance();
098    }
099
100    /**
101     * {@inheritDoc}<p>
102     * Note: must implement same logic as the overridden comparator
103     * lookup, otherwise will throw ClassCastException because 
104     * here the comparator is never null. <p>
105     * 
106     * PENDING JW: think about implications to string value lookup!
107     * 
108     * @throws IndexOutOfBoundsException {@inheritDoc}
109     */
110    @Override
111    protected boolean useToString(int column) {
112        Comparator<?> comparator = super.getComparator(column);
113        if (comparator != null) {
114            return false;
115        }
116        Class<?> columnClass = getModel().getColumnClass(column);
117        if (columnClass == String.class) {
118            return false;
119        }
120        if (Comparable.class.isAssignableFrom(columnClass)) {
121            return false;
122        }
123        return true;
124    }
125
126
127    /**
128     * Implementation of DefaultRowSorter.ModelWrapper that delegates to a
129     * TableModel.
130     */
131    private class TableRowSorterModelWrapper extends ModelWrapper<M,Integer> {
132        @Override
133        public M getModel() {
134            return tableModel;
135        }
136
137        @Override
138        public int getColumnCount() {
139            return (tableModel == null) ? 0 : tableModel.getColumnCount();
140        }
141
142        @Override
143        public int getRowCount() {
144            return (tableModel == null) ? 0 : tableModel.getRowCount();
145        }
146
147        @Override
148        public Object getValueAt(int row, int column) {
149            return tableModel.getValueAt(row, column);
150        }
151
152        @Override
153        public String getStringValueAt(int row, int column) {
154            return getStringValueProvider().getStringValue(row, column)
155                .getString(getValueAt(row, column));
156        }
157
158        @Override
159        public Integer getIdentifier(int index) {
160            return index;
161        }
162    }
163
164
165}