1 /* 2 * Copyright (c) 2011, 2014, 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 @SuppressWarnings("serial") // Superclass is not serializable across versions 40 public class AquaTableHeaderBorder extends AbstractBorder { 41 protected static final int SORT_NONE = 0; 42 protected static final int SORT_ASCENDING = 1; 43 protected static final int SORT_DECENDING = -1; 44 45 protected final Insets editorBorderInsets = new Insets(1, 3, 1, 3); 46 protected final AquaPainter<JRSUIState> painter = AquaPainter.create(JRSUIState.getInstance()); 47 getListHeaderBorder()48 protected static AquaTableHeaderBorder getListHeaderBorder() { 49 // we don't want to share this, because the .setSelected() state 50 // would persist to all other JTable instances 51 return new AquaTableHeaderBorder(); 52 } 53 AquaTableHeaderBorder()54 protected AquaTableHeaderBorder() { 55 painter.state.set(AlignmentHorizontal.LEFT); 56 painter.state.set(AlignmentVertical.TOP); 57 } 58 59 /** 60 * Paints the border for the specified component with the specified 61 * position and size. 62 * @param c the component for which this border is being painted 63 * @param g the paint graphics 64 * @param x the x position of the painted border 65 * @param y the y position of the painted border 66 * @param width the width of the painted border 67 * @param height the height of the painted border 68 */ 69 protected boolean doPaint = true; paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height)70 public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) { 71 if (!doPaint) return; 72 final JComponent jc = (JComponent)c; 73 74 // if the developer wants to set their own color, we should 75 // interpret this as "get out of the way", and don't draw aqua. 76 final Color componentBackground = jc.getBackground(); 77 if (!(componentBackground instanceof UIResource)) { 78 doPaint = false; 79 jc.paint(g); 80 getAlternateBorder().paintBorder(jc, g, x, y, width, height); 81 doPaint = true; 82 return; 83 } 84 85 final State state = getState(jc); 86 painter.state.set(state); 87 painter.state.set(jc.hasFocus() ? Focused.YES : Focused.NO); 88 painter.state.set(height > 16 ? Widget.BUTTON_BEVEL : Widget.BUTTON_LIST_HEADER); 89 painter.state.set(selected ? BooleanValue.YES : BooleanValue.NO); 90 91 switch (sortOrder) { 92 case SORT_ASCENDING: 93 painter.state.set(Direction.UP); 94 break; 95 case SORT_DECENDING: 96 painter.state.set(Direction.DOWN); 97 break; 98 default: 99 painter.state.set(Direction.NONE); 100 break; 101 } 102 103 final int newX = x; 104 final int newY = y; 105 final int newWidth = width; 106 final int newHeight = height; 107 108 painter.paint(g, c, newX - 1, newY - 1, newWidth + 1, newHeight); 109 110 // Draw the header 111 g.clipRect(newX, y, newWidth, height); 112 g.translate(fHorizontalShift, -1); 113 doPaint = false; 114 jc.paint(g); 115 doPaint = true; 116 } 117 getState(final JComponent jc)118 protected State getState(final JComponent jc) { 119 if (!jc.isEnabled()) return State.DISABLED; 120 121 final JRootPane rootPane = jc.getRootPane(); 122 if (rootPane == null) return State.ACTIVE; 123 124 if (!AquaFocusHandler.isActive(rootPane)) return State.INACTIVE; 125 126 return State.ACTIVE; 127 } 128 129 private static final RecyclableSingleton<Border> alternateBorder = new RecyclableSingleton<Border>() { 130 @Override 131 protected Border getInstance() { 132 return BorderFactory.createRaisedBevelBorder(); 133 } 134 }; getAlternateBorder()135 protected static Border getAlternateBorder() { 136 return alternateBorder.get(); 137 } 138 139 /** 140 * Returns the insets of the border. 141 * @param c the component for which this border insets value applies 142 */ getBorderInsets(final Component c)143 public Insets getBorderInsets(final Component c) { 144 // bad to create new one each time. For debugging only. 145 return editorBorderInsets; 146 } 147 getBorderInsets(final Component c, final Insets insets)148 public Insets getBorderInsets(final Component c, final Insets insets) { 149 insets.left = editorBorderInsets.left; 150 insets.top = editorBorderInsets.top; 151 insets.right = editorBorderInsets.right; 152 insets.bottom = editorBorderInsets.bottom; 153 return insets; 154 } 155 156 /** 157 * Returns whether or not the border is opaque. If the border 158 * is opaque, it is responsible for filling in it's own 159 * background when painting. 160 */ isBorderOpaque()161 public boolean isBorderOpaque() { 162 return false; 163 } 164 165 /** 166 * Sets whether or not this instance of Border draws selected or not. Used by AquaFileChooserUI 167 */ 168 private boolean selected = false; setSelected(final boolean inSelected)169 protected void setSelected(final boolean inSelected) { 170 selected = inSelected; 171 } 172 173 /** 174 * Sets an amount to shift the position of the labels. Used by AquaFileChooserUI 175 */ 176 private int fHorizontalShift = 0; setHorizontalShift(final int inShift)177 protected void setHorizontalShift(final int inShift) { 178 fHorizontalShift = inShift; 179 } 180 181 private int sortOrder = SORT_NONE; setSortOrder(final int inSortOrder)182 protected void setSortOrder(final int inSortOrder) { 183 if (inSortOrder < SORT_DECENDING || inSortOrder > SORT_ASCENDING) { 184 throw new IllegalArgumentException("Invalid sort order constant: " + inSortOrder); 185 } 186 187 sortOrder = inSortOrder; 188 } 189 } 190