/* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.apple.laf; import java.awt.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.UIResource; import apple.laf.JRSUIState; import apple.laf.JRSUIConstants.*; import com.apple.laf.AquaUtils.RecyclableSingleton; public class AquaTableHeaderBorder extends AbstractBorder { protected static final int SORT_NONE = 0; protected static final int SORT_ASCENDING = 1; protected static final int SORT_DECENDING = -1; protected final Insets editorBorderInsets = new Insets(1, 3, 1, 3); protected final AquaPainter painter = AquaPainter.create(JRSUIState.getInstance()); protected static AquaTableHeaderBorder getListHeaderBorder() { // we don't want to share this, because the .setSelected() state // would persist to all other JTable instances return new AquaTableHeaderBorder(); } protected AquaTableHeaderBorder() { painter.state.set(AlignmentHorizontal.LEFT); painter.state.set(AlignmentVertical.TOP); } /** * Paints the border for the specified component with the specified * position and size. * @param c the component for which this border is being painted * @param g the paint graphics * @param x the x position of the painted border * @param y the y position of the painted border * @param width the width of the painted border * @param height the height of the painted border */ protected boolean doPaint = true; public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) { if (!doPaint) return; final JComponent jc = (JComponent)c; // if the developer wants to set their own color, we should // interpret this as "get out of the way", and don't draw aqua. final Color componentBackground = jc.getBackground(); if (!(componentBackground instanceof UIResource)) { doPaint = false; jc.paint(g); getAlternateBorder().paintBorder(jc, g, x, y, width, height); doPaint = true; return; } final State state = getState(jc); painter.state.set(state); painter.state.set(jc.hasFocus() ? Focused.YES : Focused.NO); painter.state.set(height > 16 ? Widget.BUTTON_BEVEL : Widget.BUTTON_LIST_HEADER); painter.state.set(selected ? BooleanValue.YES : BooleanValue.NO); switch (sortOrder) { case SORT_ASCENDING: painter.state.set(Direction.UP); break; case SORT_DECENDING: painter.state.set(Direction.DOWN); break; default: painter.state.set(Direction.NONE); break; } final int newX = x; final int newY = y; final int newWidth = width; final int newHeight = height; painter.paint(g, c, newX - 1, newY - 1, newWidth + 1, newHeight); // Draw the header g.clipRect(newX, y, newWidth, height); g.translate(fHorizontalShift, -1); doPaint = false; jc.paint(g); doPaint = true; } protected State getState(final JComponent jc) { if (!jc.isEnabled()) return State.DISABLED; final JRootPane rootPane = jc.getRootPane(); if (rootPane == null) return State.ACTIVE; if (!AquaFocusHandler.isActive(rootPane)) return State.INACTIVE; return State.ACTIVE; } static final RecyclableSingleton alternateBorder = new RecyclableSingleton() { @Override protected Border getInstance() { return BorderFactory.createRaisedBevelBorder(); } }; protected static Border getAlternateBorder() { return alternateBorder.get(); } /** * Returns the insets of the border. * @param c the component for which this border insets value applies */ public Insets getBorderInsets(final Component c) { // bad to create new one each time. For debugging only. return editorBorderInsets; } public Insets getBorderInsets(final Component c, final Insets insets) { insets.left = editorBorderInsets.left; insets.top = editorBorderInsets.top; insets.right = editorBorderInsets.right; insets.bottom = editorBorderInsets.bottom; return insets; } /** * Returns whether or not the border is opaque. If the border * is opaque, it is responsible for filling in it's own * background when painting. */ public boolean isBorderOpaque() { return false; } /** * Sets whether or not this instance of Border draws selected or not. Used by AquaFileChooserUI */ private boolean selected = false; protected void setSelected(final boolean inSelected) { selected = inSelected; } /** * Sets an amount to shift the position of the labels. Used by AquaFileChooserUI */ private int fHorizontalShift = 0; protected void setHorizontalShift(final int inShift) { fHorizontalShift = inShift; } private int sortOrder = SORT_NONE; protected void setSortOrder(final int inSortOrder) { if (inSortOrder < SORT_DECENDING || inSortOrder > SORT_ASCENDING) { throw new IllegalArgumentException("Invalid sort order constant: " + inSortOrder); } sortOrder = inSortOrder; } }