/*
* Copyright (c) 2009 Kathryn Huxtable and Kenneth Orr.
*
* This file is part of the SeaGlass Pluggable Look and Feel.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $Id$
*/
package com.seaglasslookandfeel.component;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import javax.swing.JButton;
import javax.swing.JSplitPane;
import javax.swing.SwingConstants;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import javax.swing.plaf.synth.Region;
import com.seaglasslookandfeel.SeaGlassContext;
import com.seaglasslookandfeel.SeaGlassLookAndFeel;
import com.seaglasslookandfeel.ui.SeaGlassSplitPaneUI;
import sun.swing.DefaultLookup;
/**
* SeaGlassSplitPaneDivider implementation.
*
* <p>Based on Synth's divider.</p>
*
* @see javax.swing.plaf.synth.SynthSplitPaneDivider
*/
public class SeaGlassSplitPaneDivider extends BasicSplitPaneDivider {
private static final long serialVersionUID = 5876267823818018895L;
/**
* Width or height of the divider based on orientation BasicSplitPaneUI adds
* two to this.
*/
protected static final int ONE_TOUCH_SIZE = 6;
/** The offset for the one-touch buttons. */
protected static final int ONE_TOUCH_OFFSET = 2;
private int oneTouchSize;
private int oneTouchOffset;
/** If true the one touch buttons are centered on the divider. */
private boolean centerOneTouchButtons;
int oneTouchVOffset;
/**
* Creates a new SeaGlassSplitPaneDivider object.
*
* @param ui the parent UI delegate.
*/
public SeaGlassSplitPaneDivider(BasicSplitPaneUI ui) {
super(ui);
oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui, "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE);
oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui, "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET);
centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(), ui, "SplitPane.centerOneTouchButtons", true);
oneTouchVOffset = DefaultLookup.getInt(ui.getSplitPane(), ui, "SplitPane.oneTouchButtonVOffset", 0);
setLayout(new DividerLayout());
}
/**
* @see javax.swing.plaf.basic.BasicSplitPaneDivider#setMouseOver(boolean)
*/
protected void setMouseOver(boolean mouseOver) {
if (isMouseOver() != mouseOver) {
repaint();
}
super.setMouseOver(mouseOver);
}
/**
* @see javax.swing.plaf.basic.BasicSplitPaneDivider#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent e) {
super.propertyChange(e);
if (e.getSource() == splitPane) {
if (e.getPropertyName() == JSplitPane.ORIENTATION_PROPERTY) {
if (leftButton instanceof SeaGlassArrowButton) {
((SeaGlassArrowButton) leftButton).setDirection(mapDirection(true));
}
if (rightButton instanceof SeaGlassArrowButton) {
((SeaGlassArrowButton) rightButton).setDirection(mapDirection(false));
}
}
}
}
/**
* @see javax.swing.plaf.basic.BasicSplitPaneDivider#paint(java.awt.Graphics)
*/
public void paint(Graphics g) {
Graphics g2 = g.create();
SeaGlassContext context = ((SeaGlassSplitPaneUI) splitPaneUI).getContext(splitPane, Region.SPLIT_PANE_DIVIDER);
Rectangle bounds = getBounds();
bounds.x = bounds.y = 0;
SeaGlassLookAndFeel.updateSubregion(context, g, bounds);
context.getPainter().paintSplitPaneDividerBackground(context, g, 0, 0, bounds.width, bounds.height, splitPane.getOrientation());
context.getPainter().paintSplitPaneDividerForeground(context, g, 0, 0, getWidth(), getHeight(), splitPane.getOrientation());
context.dispose();
// super.paint(g2);
for (int counter = 0; counter < getComponentCount(); counter++) {
Component child = getComponent(counter);
Rectangle childBounds = child.getBounds();
Graphics childG = g.create(childBounds.x, childBounds.y, childBounds.width, childBounds.height);
child.paint(childG);
childG.dispose();
}
g2.dispose();
}
/**
* Convert the orientation of the pane into compass points based on the pane
* orientation and the left-right orientation of the containter.
*
* @param isLeft {@code true} if the component's container is laid out
* left-to-right, otherwise {@code false}.
*
* @return the compass direction for increasing the divider.
*/
private int mapDirection(boolean isLeft) {
if (isLeft) {
if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
return SwingConstants.WEST;
}
return SwingConstants.NORTH;
}
if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
return SwingConstants.EAST;
}
return SwingConstants.SOUTH;
}
/**
* Creates and return an instance of JButton that can be used to collapse
* the left/top component in the split pane.
*
* @return a one-touch button.
*/
protected JButton createLeftOneTouchButton() {
SeaGlassArrowButton b = new SeaGlassArrowButton(SwingConstants.NORTH);
int oneTouchSize = lookupOneTouchSize();
b.setName("SplitPaneDivider.leftOneTouchButton");
b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
b.setCursor(Cursor.getPredefinedCursor(
splitPane.getOrientation() ==
JSplitPane.HORIZONTAL_SPLIT ?
Cursor.W_RESIZE_CURSOR:Cursor.N_RESIZE_CURSOR));
b.setFocusPainted(false);
b.setBorderPainted(false);
b.setRequestFocusEnabled(false);
b.setDirection(mapDirection(true));
return b;
}
/**
* Get the size of the one-touch button.
*
* @return the button size.
*/
private int lookupOneTouchSize() {
return DefaultLookup.getInt(splitPaneUI.getSplitPane(), splitPaneUI, "SplitPaneDivider.oneTouchButtonSize", ONE_TOUCH_SIZE);
}
/**
* Creates and return an instance of JButton that can be used to collapse
* the right component in the split pane.
*
* @return a one-touch button
*/
protected JButton createRightOneTouchButton() {
SeaGlassArrowButton b = new SeaGlassArrowButton(SwingConstants.NORTH);
int oneTouchSize = lookupOneTouchSize();
b.setName("SplitPaneDivider.rightOneTouchButton");
b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
// Rossi: Change cursors on "one touch" buttons. Better would be an mouse over effect
b.setCursor(Cursor.getPredefinedCursor(
splitPane.getOrientation() ==
JSplitPane.HORIZONTAL_SPLIT ?
Cursor.E_RESIZE_CURSOR:Cursor.S_RESIZE_CURSOR));
b.setFocusPainted(false);
b.setBorderPainted(false);
b.setRequestFocusEnabled(false);
b.setDirection(mapDirection(false));
return b;
}
/**
* Used to layout a <code>BasicSplitPaneDivider</code>. Layout for the
* divider involves appropriately moving the left/right buttons around.
*/
protected class DividerLayout implements LayoutManager {
/**
* @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
*/
public void layoutContainer(Container c) {
if (leftButton != null && rightButton != null && c == SeaGlassSplitPaneDivider.this) {
if (splitPane.isOneTouchExpandable()) {
Insets insets = getInsets();
if (orientation == JSplitPane.VERTICAL_SPLIT) {
int extraX = (insets != null) ? insets.left : 0;
int blockSize = getHeight();
if (insets != null) {
blockSize -= (insets.top + insets.bottom);
blockSize = Math.max(blockSize, 0);
}
blockSize = Math.min(blockSize, oneTouchSize);
int y = (c.getSize().height - blockSize) / 2;
if (!centerOneTouchButtons) {
y = (insets != null) ? insets.top : 0;
extraX = 0;
}
leftButton.setBounds(extraX + oneTouchOffset, y - oneTouchVOffset, blockSize * 2, blockSize);
rightButton.setBounds(extraX + oneTouchOffset, y + oneTouchVOffset + 1, blockSize * 2, blockSize);
} else {
int extraY = (insets != null) ? insets.top : 0;
int blockSize = getWidth();
if (insets != null) {
blockSize -= (insets.left + insets.right);
blockSize = Math.max(blockSize, 0);
}
blockSize = Math.min(blockSize, oneTouchSize);
int x = (c.getSize().width - blockSize) / 2;
if (!centerOneTouchButtons) {
x = (insets != null) ? insets.left : 0;
extraY = 0;
}
leftButton.setBounds(x - oneTouchVOffset, extraY + oneTouchOffset, blockSize, blockSize * 2);
rightButton.setBounds(x + oneTouchVOffset + 1, extraY + oneTouchOffset, blockSize, blockSize * 2);
}
} else {
leftButton.setBounds(-5, -5, 1, 1);
rightButton.setBounds(-5, -5, 1, 1);
}
}
}
/**
* @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
*/
public Dimension minimumLayoutSize(Container c) {
// NOTE: This isn't really used, refer to
// BasicSplitPaneDivider.getPreferredSize for the reason.
// I leave it in hopes of having this used at some point.
if (c != SeaGlassSplitPaneDivider.this || splitPane == null) {
return new Dimension(0, 0);
}
Dimension buttonMinSize = null;
if (splitPane.isOneTouchExpandable() && leftButton != null) {
buttonMinSize = leftButton.getMinimumSize();
}
Insets insets = getInsets();
int width = getDividerSize();
int height = width;
if (orientation == JSplitPane.VERTICAL_SPLIT) {
if (buttonMinSize != null) {
int size = buttonMinSize.height;
if (insets != null) {
size += insets.top + insets.bottom;
}
height = Math.max(height, size);
}
width = 1;
} else {
if (buttonMinSize != null) {
int size = buttonMinSize.width;
if (insets != null) {
size += insets.left + insets.right;
}
width = Math.max(width, size);
}
height = 1;
}
return new Dimension(width, height);
}
/**
* @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
*/
public Dimension preferredLayoutSize(Container c) {
return minimumLayoutSize(c);
}
/**
* @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
*/
public void removeLayoutComponent(Component c) {
}
/**
* @see java.awt.LayoutManager#addLayoutComponent(java.lang.String, java.awt.Component)
*/
public void addLayoutComponent(String string, Component c) {
}
}
}