Source for org.jfree.ui.SortButtonRenderer

   1: /* ========================================================================
   2:  * JCommon : a free general purpose class library for the Java(tm) platform
   3:  * ========================================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  * 
   7:  * Project Info:  http://www.jfree.org/jcommon/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * -----------------------
  28:  * SortButtonRenderer.java
  29:  * -----------------------
  30:  * (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors.
  31:  *
  32:  * Original Author:  Nobuo Tamemasa;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *                   Gareth Davis;
  35:  *
  36:  * $Id: SortButtonRenderer.java,v 1.6 2005/11/16 15:58:41 taqua Exp $
  37:  *
  38:  * Changes (from 26-Oct-2001)
  39:  * --------------------------
  40:  * 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG);
  41:  * 26-Jun-2002 : Removed unnecessary import (DG);
  42:  * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  43:  *
  44:  */
  45: 
  46: package org.jfree.ui;
  47: 
  48: import java.awt.Component;
  49: import java.awt.Insets;
  50: import javax.swing.JButton;
  51: import javax.swing.JComponent;
  52: import javax.swing.JLabel;
  53: import javax.swing.JTable;
  54: import javax.swing.SwingConstants;
  55: import javax.swing.UIManager;
  56: import javax.swing.border.Border;
  57: import javax.swing.table.JTableHeader;
  58: import javax.swing.table.TableCellRenderer;
  59: 
  60: /**
  61:  * A table cell renderer for table headings - uses one of three JButton instances to indicate the
  62:  * sort order for the table column.
  63:  * <P>
  64:  * This class (and also BevelArrowIcon) is adapted from original code by Nobuo Tamemasa (version
  65:  * 1.0, 26-Feb-1999) posted on www.codeguru.com.
  66:  *
  67:  * @author David Gilbert
  68:  */
  69: public class SortButtonRenderer implements TableCellRenderer {
  70: 
  71:     /**
  72:      * Useful constant indicating NO sorting.
  73:      */
  74:     public static final int NONE = 0;
  75: 
  76:     /**
  77:      * Useful constant indicating ASCENDING (that is, arrow pointing down) sorting in the table.
  78:      */
  79:     public static final int DOWN = 1;
  80: 
  81:     /**
  82:      * Useful constant indicating DESCENDING (that is, arrow pointing up) sorting in the table.
  83:      */
  84:     public static final int UP = 2;
  85: 
  86:     /**
  87:      * The current pressed column (-1 for no column).
  88:      */
  89:     private int pressedColumn = -1;
  90: 
  91:     /**
  92:      * The three buttons that are used to render the table header cells.
  93:      */
  94:     private JButton normalButton;
  95: 
  96:     /**
  97:      * The three buttons that are used to render the table header cells.
  98:      */
  99:     private JButton ascendingButton;
 100: 
 101:     /**
 102:      * The three buttons that are used to render the table header cells.
 103:      */
 104:     private JButton descendingButton;
 105: 
 106:     /**
 107:      * Used to allow the class to work out whether to use the buttuns
 108:      * or labels. Labels are required when using the aqua look and feel cos the
 109:      * buttons won't fit.
 110:      */
 111:     private boolean useLabels;
 112: 
 113:     /**
 114:      * The normal label (only used with MacOSX).
 115:      */
 116:     private JLabel normalLabel;
 117: 
 118:     /**
 119:      * The ascending label (only used with MacOSX).
 120:      */
 121:     private JLabel ascendingLabel;
 122: 
 123:     /**
 124:      * The descending label (only used with MacOSX).
 125:      */
 126:     private JLabel descendingLabel;
 127: 
 128:     /**
 129:      * Creates a new button renderer.
 130:      */
 131:     public SortButtonRenderer() {
 132: 
 133:         this.pressedColumn = -1;
 134:         this.useLabels = UIManager.getLookAndFeel().getID().equals("Aqua");
 135: 
 136:         final Border border = UIManager.getBorder("TableHeader.cellBorder");
 137: 
 138:         if (this.useLabels) {
 139:             this.normalLabel = new JLabel();
 140:             this.normalLabel.setHorizontalAlignment(SwingConstants.LEADING);
 141: 
 142:             this.ascendingLabel = new JLabel();
 143:             this.ascendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
 144:             this.ascendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
 145:             this.ascendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
 146: 
 147:             this.descendingLabel = new JLabel();
 148:             this.descendingLabel.setHorizontalAlignment(SwingConstants.LEADING);
 149:             this.descendingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
 150:             this.descendingLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
 151: 
 152:             this.normalLabel.setBorder(border);
 153:             this.ascendingLabel.setBorder(border);
 154:             this.descendingLabel.setBorder(border);
 155:         }
 156:         else {
 157:             this.normalButton = new JButton();
 158:             this.normalButton.setMargin(new Insets(0, 0, 0, 0));
 159:             this.normalButton.setHorizontalAlignment(SwingConstants.LEADING);
 160: 
 161:             this.ascendingButton = new JButton();
 162:             this.ascendingButton.setMargin(new Insets(0, 0, 0, 0));
 163:             this.ascendingButton.setHorizontalAlignment(SwingConstants.LEADING);
 164:             this.ascendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
 165:             this.ascendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
 166:             this.ascendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
 167: 
 168:             this.descendingButton = new JButton();
 169:             this.descendingButton.setMargin(new Insets(0, 0, 0, 0));
 170:             this.descendingButton.setHorizontalAlignment(SwingConstants.LEADING);
 171:             this.descendingButton.setHorizontalTextPosition(SwingConstants.LEFT);
 172:             this.descendingButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
 173:             this.descendingButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, true));
 174: 
 175:             this.normalButton.setBorder(border);
 176:             this.ascendingButton.setBorder(border);
 177:             this.descendingButton.setBorder(border);
 178: 
 179:         }
 180: 
 181:     }
 182: 
 183:     /**
 184:      * Returns the renderer component.
 185:      *
 186:      * @param table      the table.
 187:      * @param value      the value.
 188:      * @param isSelected selected?
 189:      * @param hasFocus   focussed?
 190:      * @param row        the row.
 191:      * @param column     the column.
 192:      * @return the renderer.
 193:      */
 194:     public Component getTableCellRendererComponent(final JTable table,
 195:                                                    final Object value,
 196:                                                    final boolean isSelected,
 197:                                                    final boolean hasFocus,
 198:                                                    final int row, final int column) {
 199: 
 200:         if (table == null) {
 201:             throw new NullPointerException("Table must not be null.");
 202:         }
 203: 
 204:         final JComponent component;
 205:         final SortableTableModel model = (SortableTableModel) table.getModel();
 206:         final int cc = table.convertColumnIndexToModel(column);
 207:         final boolean isSorting = (model.getSortingColumn() == cc);
 208:         final boolean isAscending = model.isAscending();
 209: 
 210:         final JTableHeader header = table.getTableHeader();
 211:         final boolean isPressed = (cc == this.pressedColumn);
 212: 
 213:         if (this.useLabels) {
 214:             final JLabel label = getRendererLabel(isSorting, isAscending);
 215:             label.setText((value == null) ? "" : value.toString());
 216:             component = label;
 217:         }
 218:         else {
 219:             final JButton button = getRendererButton(isSorting, isAscending);
 220:             button.setText((value == null) ? "" : value.toString());
 221:             button.getModel().setPressed(isPressed);
 222:             button.getModel().setArmed(isPressed);
 223:             component = button;
 224:         }
 225: 
 226:         if (header != null) {
 227:             component.setForeground(header.getForeground());
 228:             component.setBackground(header.getBackground());
 229:             component.setFont(header.getFont());
 230:         }
 231:         return component;
 232:     }
 233: 
 234:     /**
 235:      * Returns the correct button component.
 236:      *
 237:      * @param isSorting whether the render component represents the sort column.
 238:      * @param isAscending whether the model is ascending.
 239:      * @return either the ascending, descending or normal button.
 240:      */
 241:     private JButton getRendererButton(final boolean isSorting, final boolean isAscending) {
 242:         if (isSorting) {
 243:             if (isAscending) {
 244:                 return ascendingButton;
 245:             }
 246:             else {
 247:                 return descendingButton;
 248:             }
 249:         }
 250:         else {
 251:             return normalButton;
 252:         }
 253:     }
 254: 
 255:     /**
 256:      * Returns the correct label component.
 257:      *
 258:      * @param isSorting whether the render component represents the sort column.
 259:      * @param isAscending whether the model is ascending.
 260:      * @return either the ascending, descending or normal label.
 261:      */
 262:     private JLabel getRendererLabel(final boolean isSorting, final boolean isAscending) {
 263:         if (isSorting) {
 264:             if (isAscending) {
 265:                 return ascendingLabel;
 266:             }
 267:             else {
 268:                 return descendingLabel;
 269:             }
 270:         }
 271:         else {
 272:             return normalLabel;
 273:         }
 274:     }
 275: 
 276:     /**
 277:      * Sets the pressed column.
 278:      *
 279:      * @param column the column.
 280:      */
 281:     public void setPressedColumn(final int column) {
 282:         this.pressedColumn = column;
 283:     }
 284: 
 285: }