001/* ======================================================================== 002 * JCommon : a free general purpose class library for the Java(tm) platform 003 * ======================================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jcommon/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------------------- 028 * SortButtonRenderer.java 029 * ----------------------- 030 * (C) Copyright 2000-2004, by Nobuo Tamemasa and Contributors. 031 * 032 * Original Author: Nobuo Tamemasa; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * Gareth Davis; 035 * 036 * $Id: SortButtonRenderer.java,v 1.7 2008/09/10 09:26:11 mungady Exp $ 037 * 038 * Changes (from 26-Oct-2001) 039 * -------------------------- 040 * 26-Oct-2001 : Changed package to com.jrefinery.ui.* (DG); 041 * 26-Jun-2002 : Removed unnecessary import (DG); 042 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG); 043 * 044 */ 045 046package org.jfree.ui; 047 048import java.awt.Component; 049import java.awt.Insets; 050import javax.swing.JButton; 051import javax.swing.JComponent; 052import javax.swing.JLabel; 053import javax.swing.JTable; 054import javax.swing.SwingConstants; 055import javax.swing.UIManager; 056import javax.swing.border.Border; 057import javax.swing.table.JTableHeader; 058import javax.swing.table.TableCellRenderer; 059 060/** 061 * A table cell renderer for table headings - uses one of three JButton instances to indicate the 062 * sort order for the table column. 063 * <P> 064 * This class (and also BevelArrowIcon) is adapted from original code by Nobuo Tamemasa (version 065 * 1.0, 26-Feb-1999) posted on www.codeguru.com. 066 * 067 * @author David Gilbert 068 */ 069public class SortButtonRenderer implements TableCellRenderer { 070 071 /** 072 * Useful constant indicating NO sorting. 073 */ 074 public static final int NONE = 0; 075 076 /** 077 * Useful constant indicating ASCENDING (that is, arrow pointing down) sorting in the table. 078 */ 079 public static final int DOWN = 1; 080 081 /** 082 * Useful constant indicating DESCENDING (that is, arrow pointing up) sorting in the table. 083 */ 084 public static final int UP = 2; 085 086 /** 087 * The current pressed column (-1 for no column). 088 */ 089 private int pressedColumn = -1; 090 091 /** 092 * The three buttons that are used to render the table header cells. 093 */ 094 private JButton normalButton; 095 096 /** 097 * The three buttons that are used to render the table header cells. 098 */ 099 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 this.ascendingButton; 245 } 246 else { 247 return this.descendingButton; 248 } 249 } 250 else { 251 return this.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 this.ascendingLabel; 266 } 267 else { 268 return this.descendingLabel; 269 } 270 } 271 else { 272 return this.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}