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 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 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; 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 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 static final RecyclableSingleton<Border> alternateBorder = new RecyclableSingleton<Border>() { 130 @Override 131 protected Border getInstance() { 132 return BorderFactory.createRaisedBevelBorder(); 133 } 134 }; 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 */ 143 public Insets getBorderInsets(final Component c) { 144 // bad to create new one each time. For debugging only. 145 return editorBorderInsets; 146 } 147 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 */ 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; 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; 177 protected void setHorizontalShift(final int inShift) { 178 fHorizontalShift = inShift; 179 } 180 181 private int sortOrder = SORT_NONE; 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 }