1 /* 2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.apple.laf; 27 28 import java.awt.*; 29 30 import javax.swing.*; 31 import javax.swing.border.*; 32 import javax.swing.plaf.UIResource; 33 34 import apple.laf.JRSUIState; 35 import apple.laf.JRSUIConstants.*; 36 37 import com.apple.laf.AquaUtils.RecyclableSingleton; 38 39 public class AquaTableHeaderBorder extends AbstractBorder { 40 protected static final int SORT_NONE = 0; 41 protected static final int SORT_ASCENDING = 1; 42 protected static final int SORT_DECENDING = -1; 43 44 protected final Insets editorBorderInsets = new Insets(1, 3, 1, 3); 45 protected final AquaPainter<JRSUIState> painter = AquaPainter.create(JRSUIState.getInstance()); 46 47 protected static AquaTableHeaderBorder getListHeaderBorder() { 48 // we don't want to share this, because the .setSelected() state 49 // would persist to all other JTable instances 50 return new AquaTableHeaderBorder(); 51 } 52 53 protected AquaTableHeaderBorder() { 54 painter.state.set(AlignmentHorizontal.LEFT); 55 painter.state.set(AlignmentVertical.TOP); 56 } 57 58 /** 59 * Paints the border for the specified component with the specified 60 * position and size. 61 * @param c the component for which this border is being painted 62 * @param g the paint graphics 63 * @param x the x position of the painted border 64 * @param y the y position of the painted border 65 * @param width the width of the painted border 66 * @param height the height of the painted border 67 */ 68 protected boolean doPaint = true; 69 public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) { 70 if (!doPaint) return; 71 final JComponent jc = (JComponent)c; 72 73 // if the developer wants to set their own color, we should 74 // interpret this as "get out of the way", and don't draw aqua. 75 final Color componentBackground = jc.getBackground(); 76 if (!(componentBackground instanceof UIResource)) { 77 doPaint = false; 78 jc.paint(g); 79 getAlternateBorder().paintBorder(jc, g, x, y, width, height); 80 doPaint = true; 81 return; 82 } 83 84 final State state = getState(jc); 85 painter.state.set(state); 86 painter.state.set(jc.hasFocus() ? Focused.YES : Focused.NO); 87 painter.state.set(height > 16 ? Widget.BUTTON_BEVEL : Widget.BUTTON_LIST_HEADER); 88 painter.state.set(selected ? BooleanValue.YES : BooleanValue.NO); 89 90 switch (sortOrder) { 91 case SORT_ASCENDING: 92 painter.state.set(Direction.UP); 93 break; 94 case SORT_DECENDING: 95 painter.state.set(Direction.DOWN); 96 break; 97 default: 98 painter.state.set(Direction.NONE); 99 break; 100 } 101 102 final int newX = x; 103 final int newY = y; 104 final int newWidth = width; 105 final int newHeight = height; 106 107 painter.paint(g, c, newX - 1, newY - 1, newWidth + 1, newHeight); 108 109 // Draw the header 110 g.clipRect(newX, y, newWidth, height); 111 g.translate(fHorizontalShift, -1); 112 doPaint = false; 113 jc.paint(g); 114 doPaint = true; 115 } 116 117 protected State getState(final JComponent jc) { 118 if (!jc.isEnabled()) return State.DISABLED; 119 120 final JRootPane rootPane = jc.getRootPane(); 121 if (rootPane == null) return State.ACTIVE; 122 123 if (!AquaFocusHandler.isActive(rootPane)) return State.INACTIVE; 124 125 return State.ACTIVE; 126 } 127 128 static final RecyclableSingleton<Border> alternateBorder = new RecyclableSingleton<Border>() { 129 @Override 130 protected Border getInstance() { 131 return BorderFactory.createRaisedBevelBorder(); 132 } 133 }; 134 protected static Border getAlternateBorder() { 135 return alternateBorder.get(); 136 } 137 138 /** 139 * Returns the insets of the border. 140 * @param c the component for which this border insets value applies 141 */ 142 public Insets getBorderInsets(final Component c) { 143 // bad to create new one each time. For debugging only. 144 return editorBorderInsets; 145 } 146 147 public Insets getBorderInsets(final Component c, final Insets insets) { 148 insets.left = editorBorderInsets.left; 149 insets.top = editorBorderInsets.top; 150 insets.right = editorBorderInsets.right; 151 insets.bottom = editorBorderInsets.bottom; 152 return insets; 153 } 154 155 /** 156 * Returns whether or not the border is opaque. If the border 157 * is opaque, it is responsible for filling in it's own 158 * background when painting. 159 */ 160 public boolean isBorderOpaque() { 161 return false; 162 } 163 164 /** 165 * Sets whether or not this instance of Border draws selected or not. Used by AquaFileChooserUI 166 */ 167 private boolean selected = false; 168 protected void setSelected(final boolean inSelected) { 169 selected = inSelected; 170 } 171 172 /** 173 * Sets an amount to shift the position of the labels. Used by AquaFileChooserUI 174 */ 175 private int fHorizontalShift = 0; 176 protected void setHorizontalShift(final int inShift) { 177 fHorizontalShift = inShift; 178 } 179 180 private int sortOrder = SORT_NONE; 181 protected void setSortOrder(final int inSortOrder) { 182 if (inSortOrder < SORT_DECENDING || inSortOrder > SORT_ASCENDING) { 183 throw new IllegalArgumentException("Invalid sort order constant: " + inSortOrder); 184 } 185 186 sortOrder = inSortOrder; 187 } 188 }