001 /* 002 * $Id: ColumnHeaderRenderer.java,v 1.11 2006/03/10 15:25:07 kleopatra Exp $ 003 * 004 * Copyright 2004 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 022 package org.jdesktop.swingx.table; 023 024 import java.awt.Color; 025 import java.awt.Component; 026 import java.awt.Font; 027 028 import javax.swing.Icon; 029 import javax.swing.JComponent; 030 import javax.swing.JLabel; 031 import javax.swing.JTable; 032 import javax.swing.UIManager; 033 import javax.swing.border.Border; 034 import javax.swing.border.CompoundBorder; 035 import javax.swing.plaf.UIResource; 036 import javax.swing.table.JTableHeader; 037 import javax.swing.table.TableCellRenderer; 038 039 import org.jdesktop.swingx.JXTable; 040 import org.jdesktop.swingx.LabelProperties; 041 import org.jdesktop.swingx.border.IconBorder; 042 import org.jdesktop.swingx.decorator.SortOrder; 043 import org.jdesktop.swingx.icon.SortArrowIcon; 044 import org.jdesktop.swingx.plaf.ColumnHeaderRendererAddon; 045 import org.jdesktop.swingx.plaf.LookAndFeelAddons; 046 047 /** 048 * Header renderer class which renders column sort feedback (arrows). 049 * 050 * PENDING: #25, #169 - Header doesn't look right in winXP/mac 051 * 052 * 053 * @author Amy Fowler 054 * @author Ramesh Gupta 055 * @author Jeanette Winzenburg 056 */ 057 public class ColumnHeaderRenderer extends JComponent implements TableCellRenderer { 058 // the inheritance is only to make sure we are updated on LF change 059 public static final String UP_ICON_KEY = "ColumnHeaderRenderer.upIcon"; 060 public static final String DOWN_ICON_KEY = "ColumnHeaderRenderer.downIcon"; 061 062 static { 063 LookAndFeelAddons.contribute(new ColumnHeaderRendererAddon()); 064 } 065 private static TableCellRenderer sharedInstance = null; 066 067 private static Icon defaultDownIcon = new SortArrowIcon(false); 068 069 private static Icon defaultUpIcon = new SortArrowIcon(true); 070 071 private Icon downIcon = defaultDownIcon; 072 073 private Icon upIcon = defaultUpIcon; 074 075 private IconBorder iconBorder = new IconBorder(); 076 private boolean antiAliasedText = false; 077 078 private TableCellRenderer delegateRenderer; 079 080 private LabelProperties label; 081 082 public static TableCellRenderer getSharedInstance() { 083 if (sharedInstance == null) { 084 sharedInstance = new ColumnHeaderRenderer(); 085 } 086 return sharedInstance; 087 } 088 089 public static ColumnHeaderRenderer createColumnHeaderRenderer() { 090 return new ColumnHeaderRenderer(); 091 } 092 093 /* 094 * JW: a story ... 095 * 096 * latest: don't use a custom component and don't add the original 097 * and the arrow - use the original only and compound a border with 098 * arrow icon. How does it look in XP/Mac? 099 * 100 * 101 * ----------------- below is the comment as of ColumnHeaderRenderer 102 * Original used a Label to show the typical text/icon part and another 103 * Label to show the up/down arrows, added both to this and configured both 104 * directly in getTableCellRendererComponent. 105 * 106 * My first shot to solve the issues was to delegate the text/icon part to 107 * the defaultRenderer as returned by the JTableHeader: replace the first 108 * label with the rendererComponent of the renderer. In 109 * getTableCellRendererComponent let the renderer configure the comp and 110 * "move" the border from the delegateComp to this - so it's bordering both 111 * the comp and the arrow. 112 * 113 * Besides not working (WinXP style headers are still not shown :-( it has 114 * issues with opaqueness: different combinations of this.opaque and 115 * delegate.opaque all have issues 116 * 1. if the delegate is not explicitly set to false the border looks wrong 117 * 2. if this is set to true we can have custom background 118 * per cell but no setting the header background has no 119 * effect - and changing LF doesn't take up the LF default background ... 120 * 3. if this is set to false we can't have custom cell background 121 * 122 * Any ideas? 123 * 124 * 125 */ 126 127 private ColumnHeaderRenderer() { 128 label = new LabelProperties(); 129 initDelegate(); 130 131 } 132 133 134 private void initDelegate() { 135 JTableHeader header = new JTableHeader(); 136 delegateRenderer = header.getDefaultRenderer(); 137 138 } 139 140 public Component getTableCellRendererComponent(JTable table, Object value, 141 boolean isSelected, boolean hasFocus, int rowIndex, int columnIndex) { 142 Component comp = configureDelegate(table, value, isSelected, hasFocus, rowIndex, 143 columnIndex); 144 145 if ((table instanceof JXTable) && (comp instanceof JComponent)) { 146 147 SortOrder sortOrder = ((JXTable) table).getSortOrder(columnIndex); 148 149 Border border = UIManager.getBorder("TableHeader.cellBorder"); 150 if (sortOrder.isSorted()) { 151 iconBorder.setIcon(sortOrder.isAscending() ? upIcon : downIcon); 152 Border origBorder = ((JComponent) comp).getBorder(); 153 border = new CompoundBorder(origBorder, iconBorder); 154 ((JComponent) comp).setBorder(border); 155 } 156 } 157 adjustComponentOrientation(comp); 158 return comp; 159 } 160 161 /** 162 * adjusts the Component's orientation to JXTable's CO if appropriate. 163 * Here: always. 164 * 165 * @param stamp 166 */ 167 protected void adjustComponentOrientation(Component stamp) { 168 if (stamp.getComponentOrientation().equals(getComponentOrientation())) return; 169 stamp.applyComponentOrientation(getComponentOrientation()); 170 } 171 172 private Component configureDelegate(JTable table, Object value, 173 boolean isSelected, boolean hasFocus, int rowIndex, int columnIndex) { 174 Component comp = delegateRenderer.getTableCellRendererComponent(table, 175 value, isSelected, hasFocus, rowIndex, columnIndex); 176 177 applyLabelProperties(comp); 178 return comp; 179 } 180 181 private void applyLabelProperties(Component delegateRendererComponent) { 182 if (delegateRendererComponent instanceof JLabel) { 183 label.applyPropertiesTo((JLabel) delegateRendererComponent); 184 } else { 185 label.applyPropertiesTo(delegateRenderer); 186 } 187 } 188 189 public void setAntiAliasedText(boolean antiAlias) { 190 this.antiAliasedText = antiAlias; 191 } 192 193 public boolean getAntiAliasedText() { 194 return antiAliasedText; 195 } 196 197 public void setBackground(Color background) { 198 // this is called somewhere along initialization of super? 199 if (label != null) { 200 label.setBackground(background); 201 } 202 } 203 204 public void setForeground(Color foreground) { 205 if (label != null) { 206 label.setForeground(foreground); 207 } 208 } 209 210 public void setFont(Font font) { 211 if (label != null) { 212 label.setFont(font); 213 } 214 } 215 216 public void setDownIcon(Icon icon) { 217 this.downIcon = icon; 218 } 219 220 public Icon getDownIcon() { 221 return downIcon; 222 } 223 224 public void setUpIcon(Icon icon) { 225 this.upIcon = icon; 226 } 227 228 public Icon getUpIcon() { 229 return upIcon; 230 } 231 232 public void setHorizontalAlignment(int alignment) { 233 label.setHorizontalAlignment(alignment); 234 } 235 236 public int getHorizontalAlignment() { 237 return label.getHorizontalAlignment(); 238 } 239 240 public void setHorizontalTextPosition(int textPosition) { 241 label.setHorizontalTextPosition(textPosition); 242 } 243 244 public int getHorizontalTextPosition() { 245 return label.getHorizontalTextPosition(); 246 } 247 248 public void setIcon(Icon icon) { 249 label.setIcon(icon); 250 } 251 252 public Icon getIcon() { 253 return label.getIcon(); 254 } 255 256 public void setIconTextGap(int iconTextGap) { 257 label.setIconTextGap(iconTextGap); 258 } 259 260 public int getIconTextGap() { 261 return label.getIconTextGap(); 262 } 263 264 public void setVerticalAlignment(int alignment) { 265 label.setVerticalAlignment(alignment); 266 } 267 268 public int getVerticalAlignment() { 269 return label.getVerticalAlignment(); 270 } 271 272 public void setVerticalTextPosition(int textPosition) { 273 label.setVerticalTextPosition(textPosition); 274 } 275 276 public int getVerticalTextPosition() { 277 return label.getVerticalTextPosition(); 278 } 279 280 public void updateUI() { 281 super.updateUI(); 282 initDelegate(); 283 updateIconUI(); 284 } 285 286 private void updateIconUI() { 287 if (getUpIcon() instanceof UIResource) { 288 Icon icon = UIManager.getIcon(UP_ICON_KEY); 289 setUpIcon(icon != null ? icon : defaultUpIcon); 290 291 } 292 if (getDownIcon() instanceof UIResource) { 293 Icon icon = UIManager.getIcon(DOWN_ICON_KEY); 294 setDownIcon(icon != null ? icon : defaultDownIcon); 295 296 } 297 } 298 }