/*
* Copyright (c) 1998, 2003, 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 javax.swing.plaf.metal;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.*;
/**
* Metal's split pane divider
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans<sup><font size="-2">TM</font></sup>
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Steve Wilson
* @author Ralph kar
*/
class MetalSplitPaneDivider extends BasicSplitPaneDivider
{
private MetalBumps bumps = new MetalBumps(10, 10,
MetalLookAndFeel.getControlHighlight(),
MetalLookAndFeel.getControlDarkShadow(),
MetalLookAndFeel.getControl() );
private MetalBumps focusBumps = new MetalBumps(10, 10,
MetalLookAndFeel.getPrimaryControlHighlight(),
MetalLookAndFeel.getPrimaryControlDarkShadow(),
UIManager.getColor("SplitPane.dividerFocusColor"));
private int inset = 2;
private Color controlColor = MetalLookAndFeel.getControl();
private Color primaryControlColor = UIManager.getColor(
"SplitPane.dividerFocusColor");
public MetalSplitPaneDivider(BasicSplitPaneUI ui) {
super(ui);
}
public void paint(Graphics g) {
MetalBumps usedBumps;
if (splitPane.hasFocus()) {
usedBumps = focusBumps;
g.setColor(primaryControlColor);
}
else {
usedBumps = bumps;
g.setColor(controlColor);
}
Rectangle clip = g.getClipBounds();
Insets insets = getInsets();
g.fillRect(clip.x, clip.y, clip.width, clip.height);
Dimension size = getSize();
size.width -= inset * 2;
size.height -= inset * 2;
int drawX = inset;
int drawY = inset;
if (insets != null) {
size.width -= (insets.left + insets.right);
size.height -= (insets.top + insets.bottom);
drawX += insets.left;
drawY += insets.top;
}
usedBumps.setBumpArea(size);
usedBumps.paintIcon(this, g, drawX, drawY);
super.paint(g);
}
/**
* Creates and return an instance of JButton that can be used to
* collapse the left component in the metal split pane.
*/
protected JButton createLeftOneTouchButton() {
JButton b = new JButton() {
// Sprite buffer for the arrow image of the left button
int[][] buffer = {{0, 0, 0, 2, 2, 0, 0, 0, 0},
{0, 0, 2, 1, 1, 1, 0, 0, 0},
{0, 2, 1, 1, 1, 1, 1, 0, 0},
{2, 1, 1, 1, 1, 1, 1, 1, 0},
{0, 3, 3, 3, 3, 3, 3, 3, 3}};
public void setBorder(Border b) {
}
public void paint(Graphics g) {
JSplitPane splitPane = getSplitPaneFromSuper();
if(splitPane != null) {
int oneTouchSize = getOneTouchSizeFromSuper();
int orientation = getOrientationFromSuper();
int blockSize = Math.min(getDividerSize(),
oneTouchSize);
// Initialize the color array
Color[] colors = {
this.getBackground(),
MetalLookAndFeel.getPrimaryControlDarkShadow(),
MetalLookAndFeel.getPrimaryControlInfo(),
MetalLookAndFeel.getPrimaryControlHighlight()};
// Fill the background first ...
g.setColor(this.getBackground());
if (isOpaque()) {
g.fillRect(0, 0, this.getWidth(),
this.getHeight());
}
// ... then draw the arrow.
if (getModel().isPressed()) {
// Adjust color mapping for pressed button state
colors[1] = colors[2];
}
if(orientation == JSplitPane.VERTICAL_SPLIT) {
// Draw the image for a vertical split
for (int i=1; i<=buffer[0].length; i++) {
for (int j=1; j<blockSize; j++) {
if (buffer[j-1][i-1] == 0) {
continue;
}
else {
g.setColor(
colors[buffer[j-1][i-1]]);
}
g.drawLine(i, j, i, j);
}
}
}
else {
// Draw the image for a horizontal split
// by simply swaping the i and j axis.
// Except the drawLine() call this code is
// identical to the code block above. This was done
// in order to remove the additional orientation
// check for each pixel.
for (int i=1; i<=buffer[0].length; i++) {
for (int j=1; j<blockSize; j++) {
if (buffer[j-1][i-1] == 0) {
// Nothing needs
// to be drawn
continue;
}
else {
// Set the color from the
// color map
g.setColor(
colors[buffer[j-1][i-1]]);
}
// Draw a pixel
g.drawLine(j, i, j, i);
}
}
}
}
}
// Don't want the button to participate in focus traversable.
public boolean isFocusTraversable() {
return false;
}
};
b.setRequestFocusEnabled(false);
b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
b.setFocusPainted(false);
b.setBorderPainted(false);
maybeMakeButtonOpaque(b);
return b;
}
/**
* If necessary <code>c</code> is made opaque.
*/
private void maybeMakeButtonOpaque(JComponent c) {
Object opaque = UIManager.get("SplitPane.oneTouchButtonsOpaque");
if (opaque != null) {
c.setOpaque(((Boolean)opaque).booleanValue());
}
}
/**
* Creates and return an instance of JButton that can be used to
* collapse the right component in the metal split pane.
*/
protected JButton createRightOneTouchButton() {
JButton b = new JButton() {
// Sprite buffer for the arrow image of the right button
int[][] buffer = {{2, 2, 2, 2, 2, 2, 2, 2},
{0, 1, 1, 1, 1, 1, 1, 3},
{0, 0, 1, 1, 1, 1, 3, 0},
{0, 0, 0, 1, 1, 3, 0, 0},
{0, 0, 0, 0, 3, 0, 0, 0}};
public void setBorder(Border border) {
}
public void paint(Graphics g) {
JSplitPane splitPane = getSplitPaneFromSuper();
if(splitPane != null) {
int oneTouchSize = getOneTouchSizeFromSuper();
int orientation = getOrientationFromSuper();
int blockSize = Math.min(getDividerSize(),
oneTouchSize);
// Initialize the color array
Color[] colors = {
this.getBackground(),
MetalLookAndFeel.getPrimaryControlDarkShadow(),
MetalLookAndFeel.getPrimaryControlInfo(),
MetalLookAndFeel.getPrimaryControlHighlight()};
// Fill the background first ...
g.setColor(this.getBackground());
if (isOpaque()) {
g.fillRect(0, 0, this.getWidth(),
this.getHeight());
}
// ... then draw the arrow.
if (getModel().isPressed()) {
// Adjust color mapping for pressed button state
colors[1] = colors[2];
}
if(orientation == JSplitPane.VERTICAL_SPLIT) {
// Draw the image for a vertical split
for (int i=1; i<=buffer[0].length; i++) {
for (int j=1; j<blockSize; j++) {
if (buffer[j-1][i-1] == 0) {
continue;
}
else {
g.setColor(
colors[buffer[j-1][i-1]]);
}
g.drawLine(i, j, i, j);
}
}
}
else {
// Draw the image for a horizontal split
// by simply swaping the i and j axis.
// Except the drawLine() call this code is
// identical to the code block above. This was done
// in order to remove the additional orientation
// check for each pixel.
for (int i=1; i<=buffer[0].length; i++) {
for (int j=1; j<blockSize; j++) {
if (buffer[j-1][i-1] == 0) {
// Nothing needs
// to be drawn
continue;
}
else {
// Set the color from the
// color map
g.setColor(
colors[buffer[j-1][i-1]]);
}
// Draw a pixel
g.drawLine(j, i, j, i);
}
}
}
}
}
// Don't want the button to participate in focus traversable.
public boolean isFocusTraversable() {
return false;
}
};
b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
b.setFocusPainted(false);
b.setBorderPainted(false);
b.setRequestFocusEnabled(false);
maybeMakeButtonOpaque(b);
return b;
}
/**
* Used to layout a MetalSplitPaneDivider. Layout for the divider
* involves appropriately moving the left/right buttons around.
* <p>
* This class should be treated as a &quot;protected&quot; inner class.
* Instantiate it only within subclasses of MetalSplitPaneDivider.
*/
public class MetalDividerLayout implements LayoutManager {
// NOTE NOTE NOTE NOTE NOTE
// This class is no longer used, the functionality has
// been rolled into BasicSplitPaneDivider.DividerLayout as a
// defaults property
public void layoutContainer(Container c) {
JButton leftButton = getLeftButtonFromSuper();
JButton rightButton = getRightButtonFromSuper();
JSplitPane splitPane = getSplitPaneFromSuper();
int orientation = getOrientationFromSuper();
int oneTouchSize = getOneTouchSizeFromSuper();
int oneTouchOffset = getOneTouchOffsetFromSuper();
Insets insets = getInsets();
// This layout differs from the one used in BasicSplitPaneDivider.
// It does not center justify the oneTouchExpadable buttons.
// This was necessary in order to meet the spec of the Metal
// splitpane divider.
if (leftButton != null && rightButton != null &&
c == MetalSplitPaneDivider.this) {
if (splitPane.isOneTouchExpandable()) {
if (orientation == JSplitPane.VERTICAL_SPLIT) {
int extraY = (insets != null) ? insets.top : 0;
int blockSize = getDividerSize();
if (insets != null) {
blockSize -= (insets.top + insets.bottom);
}
blockSize = Math.min(blockSize, oneTouchSize);
leftButton.setBounds(oneTouchOffset, extraY,
blockSize * 2, blockSize);
rightButton.setBounds(oneTouchOffset +
oneTouchSize * 2, extraY,
blockSize * 2, blockSize);
}
else {
int blockSize = getDividerSize();
int extraX = (insets != null) ? insets.left : 0;
if (insets != null) {
blockSize -= (insets.left + insets.right);
}
blockSize = Math.min(blockSize, oneTouchSize);
leftButton.setBounds(extraX, oneTouchOffset,
blockSize, blockSize * 2);
rightButton.setBounds(extraX, oneTouchOffset +
oneTouchSize * 2, blockSize,
blockSize * 2);
}
}
else {
leftButton.setBounds(-5, -5, 1, 1);
rightButton.setBounds(-5, -5, 1, 1);
}
}
}
public Dimension minimumLayoutSize(Container c) {
return new Dimension(0,0);
}
public Dimension preferredLayoutSize(Container c) {
return new Dimension(0, 0);
}
public void removeLayoutComponent(Component c) {}
public void addLayoutComponent(String string, Component c) {}
}
/*
* The following methods only exist in order to be able to access protected
* members in the superclass, because these are otherwise not available
* in any inner class.
*/
int getOneTouchSizeFromSuper() {
return super.ONE_TOUCH_SIZE;
}
int getOneTouchOffsetFromSuper() {
return super.ONE_TOUCH_OFFSET;
}
int getOrientationFromSuper() {
return super.orientation;
}
JSplitPane getSplitPaneFromSuper() {
return super.splitPane;
}
JButton getLeftButtonFromSuper() {
return super.leftButton;
}
JButton getRightButtonFromSuper() {
return super.rightButton;
}
}