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 }