All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.shredzone.jshred.swing.SortTableHeader Maven / Gradle / Ivy

/**
 * jshred - Shred's Toolbox
 *
 * Copyright (C) 2009 Richard "Shred" Körber
 *   http://jshred.shredzone.org
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License / GNU Lesser
 * General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 */
package net.shredzone.jshred.swing;

import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.Serializable;

import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

/**
 * This is a {@link JTableHeader} that shows the currently sorted column of a
 * {@link SortableTableModel} and allows to select columns to be sorted.
 *
 * @author Richard "Shred" Körber
 */
public class SortTableHeader extends JTableHeader implements MouseListener, MouseMotionListener {
    private static final long serialVersionUID = 3256728372658124082L;

    private boolean pressed;                // Mouse is pressed
    private boolean dragged;                // Mouse is being dragged
    private boolean sortingAllowed = true;  // Sorting allowed?
    private int pressedIndex;               // Index of the currently clicked column
    private Icon iconAsc;                   // Icon for ascending sort order
    private Icon iconDesc;                  // Icon for descending sort order

    /**
     * Creates a new SortTableHeader.
     */
    public SortTableHeader() {
        super(null);
    }

    /**
     * Creates a new SortTableHeader with the given {@link TableColumnModel}
     *
     * @param cm
     *            {@link TableColumnModel} to be used
     */
    public SortTableHeader(TableColumnModel cm) {
        super(cm);

        // --- Initialize the default iconset ---
        iconAsc = new ArrowIcon(7, 6, SwingConstants.SOUTH);
        iconDesc = new ArrowIcon(7, 6, SwingConstants.NORTH);

        // --- Set the default renderer ---
        setDefaultRenderer(new SortTableCellRenderer(createDefaultRenderer()));

        // --- Listen to the mouse ---
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    /**
     * Sets if the user is allowed to sort columns by clicking on their headline.
     *
     * @param b
     *            Sorting allowed? true=Yes (default), false=No
     */
    public void setSortingAllowed(boolean b) {
        sortingAllowed = b;
    }

    /**
     * Finds out if sorting is allowed.
     *
     * @return true: sorting is allowed, false: not allowed
     */
    public boolean isSortingAllowed() {
        return sortingAllowed;
    }

    /**
     * Sets the icon for ascending order.
     *
     * @param icon
     *            Ascending icon, or null for none
     */
    public void setIconAsc(Icon icon) {
        iconAsc = icon;
    }

    /**
     * Gets the current icon for ascending order.
     *
     * @return Ascending icon, may be null
     */
    public Icon getIconAsc() {
        return iconAsc;
    }

    /**
     * Sets the icon for descending order.
     *
     * @param icon
     *            Descending icon, or null for none
     */
    public void setIconDesc(Icon icon) {
        iconDesc = icon;
    }

    /**
     * Gets the current icon for descending order.
     *
     * @return Descending icon, may be null
     */
    public Icon getIconDesc() {
        return iconDesc;
    }

    @Override
    public void mousePressed(MouseEvent e) {
        pressed = true;
        pressedIndex = columnAtPoint(e.getPoint());
        repaint();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if (!dragged) {
            // --- Find the column ---
            TableModel model = table.getModel();
            if (model instanceof SortableTableModel) {
                int column = table.convertColumnIndexToModel(pressedIndex);

                do {
                    if (!sortingAllowed) break;

                    if (column < 0 || column >= columnModel.getColumnCount()) break;

                    if (model instanceof ExtendedSortableTableModel) {
                        if (!((ExtendedSortableTableModel) model).isColumnSortable(column)) {
                            break;
                        }
                    }

                    ((JSortedTable) table).sortByColumn(column);
                } while (false);
            }
        }
        pressed = false;
        dragged = false;
        repaint();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        dragged = true;
        pressed = false;
        repaint();
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        dragged = false;
    }

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

    /**
     * This is a TableCellRenderer that shows the selection and sorting state of each
     * column, according to the {@link SortTableHeader}.
     */
    private class SortTableCellRenderer implements TableCellRenderer, Serializable {
        private static final long serialVersionUID = 3256437023551468342L;
        private TableCellRenderer parent;

        /**
         * Creates a new SortTableCellRenderer. A parent {@link TableCellRenderer} is
         * given, its result will be manipulated. Usually you will pass the
         * {@link JTableHeader}'s default {@link TableCellRenderer} here.
         *
         * @param parent
         *            Parent {@link TableCellRenderer}
         */
        public SortTableCellRenderer(TableCellRenderer parent) {
            this.parent = parent;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            // --- Get the original Component ---
            Component c = parent.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

            // --- It should be a JLabel ---
            if (c instanceof JLabel) {
                JLabel cl = (JLabel) c;

                // --- Show the depressed state ---
                if (pressed && pressedIndex == column) {
                    cl.setBackground(cl.getBackground().darker());
                }

                // --- Show the sorting state ---
                TableModel model = table.getModel();
                if (model instanceof SortableTableModel) {
                    SortableTableModel sortmodel = (SortableTableModel) model;
                    int modelcolumn = table.convertColumnIndexToModel(column);
                    if (sortmodel.getSortedColumn() == modelcolumn) {
                        cl.setHorizontalTextPosition(SwingConstants.LEADING);
                        if (sortmodel.isDescending()) {
                            cl.setIcon(iconDesc);
                        } else {
                            cl.setIcon(iconAsc);
                        }
                    } else {
                        cl.setIcon(null);
                    }
                }
            }

            // --- Return the manipulated Component ---
            return c;
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy