SortedTableModel.java Source code

Java tutorial

Introduction

Here is the source code for SortedTableModel.java

Source

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.EventObject;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TreeSet;

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

class SortedTableModel extends AbstractTableModel {
    protected TableModel sourceModel;
    protected int[] indexValues;

    public SortedTableModel(TableModel model) {
        super();
        sourceModel = model;
    }

    public int getRowCount() {
        return sourceModel.getRowCount();
    }

    public int getColumnCount() {
        return sourceModel.getColumnCount();
    }

    public Object getValueAt(int row, int column) {
        if (indexValues != null) {
            row = getSourceIndex(row);
        }
        return sourceModel.getValueAt(row, column);
    }

    public void setValueAt(Object value, int row, int column) {
        if (indexValues != null) {
            row = getSourceIndex(row);
        }
        sourceModel.setValueAt(value, row, column);
    }

    public boolean isCellEditable(int row, int column) {
        return sourceModel.isCellEditable(row, column);
    }

    public String getColumnName(int column) {
        return sourceModel.getColumnName(column);
    }

    public Class getColumnClass(int column) {
        return sourceModel.getColumnClass(column);
    }

    public int getSourceIndex(int index) {
        if (indexValues != null) {
            return indexValues[index];
        }
        return -1;
    }

    public void sortRows(int column, boolean ascending) {

        fireTableDataChanged();
    }

    public void clearSort() {
        indexValues = null;
        fireTableDataChanged();
    }
}

class SortedColumnHeaderRenderer implements TableCellRenderer {

    protected TableCellRenderer textRenderer;
    protected SortedTableModel sortedModel;
    protected int sortColumn = -1;
    protected boolean sortAscending = true;

    public SortedColumnHeaderRenderer(SortedTableModel model, TableCellRenderer renderer) {
        sortedModel = model;
        textRenderer = renderer;
    }

    public SortedColumnHeaderRenderer(SortedTableModel model) {
        this(model, null);
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column) {
        Component text;
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());

        if (textRenderer != null) {
            text = textRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        } else {
            text = new JLabel((String) value, JLabel.CENTER);
            LookAndFeel.installColorsAndFont((JComponent) text, "TableHeader.background", "TableHeader.foreground",
                    "TableHeader.font");
        }
        panel.add(text, BorderLayout.CENTER);

        if (column == sortColumn) {
            BasicArrowButton bab = new BasicArrowButton(
                    (sortAscending ? SwingConstants.NORTH : SwingConstants.SOUTH));
            panel.add(bab, BorderLayout.WEST);
        }
        LookAndFeel.installBorder(panel, "TableHeader.cellBorder");
        return panel;
    }

    public void columnSelected(int column) {
        if (column != sortColumn) {
            sortColumn = column;
            sortAscending = true;
        } else {
            sortAscending = !sortAscending;
            if (sortAscending)
                sortColumn = -1;
        }
        if (sortColumn != -1) {
            sortedModel.sortRows(sortColumn, sortAscending);
        } else {
            sortedModel.clearSort();
        }
    }

}

class TableValues extends AbstractTableModel {

    public final static int FIRST_NAME = 0;
    public final static int LAST_NAME = 1;
    public final static int DATE_OF_BIRTH = 2;
    public final static int ACCOUNT_BALANCE = 3;
    public final static int GENDER = 4;

    public final static boolean GENDER_MALE = true;
    public final static boolean GENDER_FEMALE = false;

    public final static String[] columnNames = { "First\nName", "Last\nName", "Date of\nBirth", "Account\nBalance",
            "Gender" };

    public Object[][] values = {
            { "A", "B", new GregorianCalendar(1962, Calendar.FEBRUARY, 20).getTime(), new Float(12345.67),
                    new Boolean(GENDER_MALE) },
            { "C", "D", new GregorianCalendar(1987, Calendar.JANUARY, 6).getTime(), new Float(23456.78),
                    new Boolean(GENDER_MALE) },
            { "E", "F", new GregorianCalendar(1989, Calendar.AUGUST, 31).getTime(), new Float(34567.89),
                    new Boolean(GENDER_FEMALE) },
            { "G", "H", new GregorianCalendar(1945, Calendar.JANUARY, 16).getTime(), new Float(-456.70),
                    new Boolean(GENDER_FEMALE) },
            { "I", "J", new GregorianCalendar(1907, Calendar.AUGUST, 2).getTime(), new Float(567.00),
                    new Boolean(GENDER_FEMALE) } };

    public int getRowCount() {
        return values.length;
    }

    public int getColumnCount() {
        return values[0].length;
    }

    public Object getValueAt(int row, int column) {
        return values[row][column];
    }

    public String getColumnName(int column) {
        return columnNames[column];
    }

    public Class getColumnClass(int column) {
        Class dataType = super.getColumnClass(column);
        if (column == ACCOUNT_BALANCE) {
            dataType = Float.class;
        } else if (column == DATE_OF_BIRTH) {
            dataType = java.util.Date.class;
        } else if ((column == FIRST_NAME) || (column == LAST_NAME)) {
            dataType = String.class;
        } else if (column == GENDER) {
            dataType = Boolean.class;
        }
        return dataType;
    }

    public boolean isCellEditable(int row, int column) {
        if (column == GENDER) {
            return true;
        }
        return false;
    }

    public void setValueAt(Object value, int row, int column) {
        values[row][column] = value;
    }

}

public class SimpleTableTestMultilineHeader extends JFrame {

    protected JTable table;
    protected SortedColumnHeaderRenderer renderer;

    public static void main(String[] args) {
        SimpleTableTestMultilineHeader stt = new SimpleTableTestMultilineHeader();
        stt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        stt.setSize(400, 200);
        stt.setVisible(true);
    }

    public SimpleTableTestMultilineHeader() {
        Container pane = getContentPane();
        pane.setLayout(new BorderLayout());
        TableValues tv = new TableValues();
        SortedTableModel stm = new SortedTableModel(tv);
        stm.sortRows(TableValues.ACCOUNT_BALANCE, true);
        table = new JTable(stm);
        table.setRowSelectionAllowed(false);
        table.setColumnSelectionAllowed(true);
        TableColumnModel tcm = table.getColumnModel();
        TableColumn tc = tcm.getColumn(TableValues.GENDER);
        MultiLineHeaderRenderer mlhr = new MultiLineHeaderRenderer();
        tc = tcm.getColumn(TableValues.ACCOUNT_BALANCE);
        tc.setHeaderRenderer(mlhr);
        renderer = new SortedColumnHeaderRenderer(stm, mlhr);
        int count = tcm.getColumnCount();
        for (int i = 0; i < count; i++) {
            tc = tcm.getColumn(i);
            tc.setHeaderRenderer(renderer);
        }
        JTableHeaderToolTips jthtt = new JTableHeaderToolTips(table.getColumnModel());
        jthtt.setToolTips(new String[] { "Customer's First Name", "Customer's Last Name",
                "Customer's Date of Birth", "Customer's Account Balance", "Customer's Gender" });
        table.setTableHeader(jthtt);
        JScrollPane jsp = new JScrollPane(table);
        pane.add(jsp, BorderLayout.CENTER);
        addHeaderListener();
    }

    public void addHeaderListener() {
        table.getTableHeader().addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent event) {
                JTableHeader header = (JTableHeader) (event.getSource());
                int index = header.columnAtPoint(event.getPoint());
                Class dataType = table.getModel().getColumnClass(index);
                Class[] interfaces = dataType.getInterfaces();
                for (int i = 0; i < interfaces.length; i++) {
                    if (interfaces[i].equals(java.lang.Comparable.class)) {
                        renderer.columnSelected(index);
                        break;
                    }
                }
                table.setColumnSelectionInterval(index, index);
            }
        });
    }

}

class JTableHeaderToolTips extends JTableHeader {

    protected String[] toolTips;

    public JTableHeaderToolTips(TableColumnModel tcm) {
        super(tcm);
    }

    public void setToolTips(String[] tips) {
        toolTips = tips;
    }

    public String getToolTipText(MouseEvent event) {
        String tip = super.getToolTipText(event);
        int column = columnAtPoint(event.getPoint());
        if ((toolTips != null) && (column < toolTips.length) && (toolTips[column] != null)) {
            tip = toolTips[column];
        }
        return tip;
    }

}

class MultiLineHeaderRenderer extends JPanel implements TableCellRenderer {

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column) {
        JLabel label;
        removeAll();
        String[] header = ((String) value).split("\n");
        setLayout(new GridLayout(header.length, 1));
        for (String s : header) {
            label = new JLabel(s, JLabel.CENTER);
            LookAndFeel.installColorsAndFont(label, "TableHeader.background", "TableHeader.foreground",
                    "TableHeader.font");
            add(label);
        }
        LookAndFeel.installBorder(this, "TableHeader.cellBorder");
        return this;
    }

}