0N/A/*
2362N/A * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/A
0N/Apackage javax.swing.plaf.basic;
0N/A
0N/A
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.border.Border;
0N/Aimport java.beans.*;
0N/Aimport sun.swing.DefaultLookup;
0N/A
0N/A
0N/A
0N/A/**
0N/A * Divider used by BasicSplitPaneUI. Subclassers may wish to override
0N/A * paint to do something more interesting.
0N/A * The border effect is drawn in BasicSplitPaneUI, so if you don't like
0N/A * that border, reset it there.
0N/A * To conditionally drag from certain areas subclass mousePressed and
0N/A * call super when you wish the dragging to begin.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @author Scott Violet
0N/A */
0N/Apublic class BasicSplitPaneDivider extends Container
0N/A implements PropertyChangeListener
0N/A{
0N/A /**
0N/A * Width or height of the divider based on orientation
0N/A * BasicSplitPaneUI adds two to this.
0N/A */
0N/A protected static final int ONE_TOUCH_SIZE = 6;
0N/A protected static final int ONE_TOUCH_OFFSET = 2;
0N/A
0N/A /**
0N/A * Handles mouse dragging message to do the actual dragging.
0N/A */
0N/A protected DragController dragger;
0N/A
0N/A /**
0N/A * UI this instance was created from.
0N/A */
0N/A protected BasicSplitPaneUI splitPaneUI;
0N/A
0N/A /**
0N/A * Size of the divider.
0N/A */
0N/A protected int dividerSize = 0; // default - SET TO 0???
0N/A
0N/A /**
0N/A * Divider that is used for noncontinuous layout mode.
0N/A */
0N/A protected Component hiddenDivider;
0N/A
0N/A /**
0N/A * JSplitPane the receiver is contained in.
0N/A */
0N/A protected JSplitPane splitPane;
0N/A
0N/A /**
0N/A * Handles mouse events from both this class, and the split pane.
0N/A * Mouse events are handled for the splitpane since you want to be able
0N/A * to drag when clicking on the border of the divider, which is not
0N/A * drawn by the divider.
0N/A */
0N/A protected MouseHandler mouseHandler;
0N/A
0N/A /**
0N/A * Orientation of the JSplitPane.
0N/A */
0N/A protected int orientation;
0N/A
0N/A /**
0N/A * Button for quickly toggling the left component.
0N/A */
0N/A protected JButton leftButton;
0N/A
0N/A /**
0N/A * Button for quickly toggling the right component.
0N/A */
0N/A protected JButton rightButton;
0N/A
0N/A /** Border. */
0N/A private Border border;
0N/A
0N/A /**
0N/A * Is the mouse over the divider?
0N/A */
0N/A private boolean mouseOver;
0N/A
0N/A private int oneTouchSize;
0N/A private int oneTouchOffset;
0N/A
0N/A /**
0N/A * If true the one touch buttons are centered on the divider.
0N/A */
0N/A private boolean centerOneTouchButtons;
0N/A
0N/A
0N/A /**
0N/A * Creates an instance of BasicSplitPaneDivider. Registers this
0N/A * instance for mouse events and mouse dragged events.
0N/A */
0N/A public BasicSplitPaneDivider(BasicSplitPaneUI ui) {
0N/A oneTouchSize = DefaultLookup.getInt(ui.getSplitPane(), ui,
0N/A "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE);
0N/A oneTouchOffset = DefaultLookup.getInt(ui.getSplitPane(), ui,
0N/A "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET);
0N/A centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(),
0N/A ui, "SplitPane.centerOneTouchButtons", true);
0N/A setLayout(new DividerLayout());
0N/A setBasicSplitPaneUI(ui);
0N/A orientation = splitPane.getOrientation();
0N/A setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
0N/A Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
0N/A Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
0N/A setBackground(UIManager.getColor("SplitPane.background"));
0N/A }
0N/A
4074N/A private void revalidateSplitPane() {
0N/A invalidate();
0N/A if (splitPane != null) {
0N/A splitPane.revalidate();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the SplitPaneUI that is using the receiver.
0N/A */
0N/A public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) {
0N/A if (splitPane != null) {
0N/A splitPane.removePropertyChangeListener(this);
0N/A if (mouseHandler != null) {
0N/A splitPane.removeMouseListener(mouseHandler);
0N/A splitPane.removeMouseMotionListener(mouseHandler);
0N/A removeMouseListener(mouseHandler);
0N/A removeMouseMotionListener(mouseHandler);
0N/A mouseHandler = null;
0N/A }
0N/A }
0N/A splitPaneUI = newUI;
0N/A if (newUI != null) {
0N/A splitPane = newUI.getSplitPane();
0N/A if (splitPane != null) {
0N/A if (mouseHandler == null) mouseHandler = new MouseHandler();
0N/A splitPane.addMouseListener(mouseHandler);
0N/A splitPane.addMouseMotionListener(mouseHandler);
0N/A addMouseListener(mouseHandler);
0N/A addMouseMotionListener(mouseHandler);
0N/A splitPane.addPropertyChangeListener(this);
0N/A if (splitPane.isOneTouchExpandable()) {
0N/A oneTouchExpandableChanged();
0N/A }
0N/A }
0N/A }
0N/A else {
0N/A splitPane = null;
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the <code>SplitPaneUI</code> the receiver is currently
0N/A * in.
0N/A */
0N/A public BasicSplitPaneUI getBasicSplitPaneUI() {
0N/A return splitPaneUI;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sets the size of the divider to <code>newSize</code>. That is
0N/A * the width if the splitpane is <code>HORIZONTAL_SPLIT</code>, or
0N/A * the height of <code>VERTICAL_SPLIT</code>.
0N/A */
0N/A public void setDividerSize(int newSize) {
0N/A dividerSize = newSize;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the size of the divider, that is the width if the splitpane
0N/A * is HORIZONTAL_SPLIT, or the height of VERTICAL_SPLIT.
0N/A */
0N/A public int getDividerSize() {
0N/A return dividerSize;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sets the border of this component.
0N/A * @since 1.3
0N/A */
0N/A public void setBorder(Border border) {
0N/A Border oldBorder = this.border;
0N/A
0N/A this.border = border;
0N/A }
0N/A
0N/A /**
0N/A * Returns the border of this component or null if no border is
0N/A * currently set.
0N/A *
0N/A * @return the border object for this component
0N/A * @see #setBorder
0N/A * @since 1.3
0N/A */
0N/A public Border getBorder() {
0N/A return border;
0N/A }
0N/A
0N/A /**
0N/A * If a border has been set on this component, returns the
0N/A * border's insets, else calls super.getInsets.
0N/A *
0N/A * @return the value of the insets property.
0N/A * @see #setBorder
0N/A */
0N/A public Insets getInsets() {
0N/A Border border = getBorder();
0N/A
0N/A if (border != null) {
0N/A return border.getBorderInsets(this);
0N/A }
0N/A return super.getInsets();
0N/A }
0N/A
0N/A /**
0N/A * Sets whether or not the mouse is currently over the divider.
0N/A *
0N/A * @param mouseOver whether or not the mouse is currently over the divider
0N/A * @since 1.5
0N/A */
0N/A protected void setMouseOver(boolean mouseOver) {
0N/A this.mouseOver = mouseOver;
0N/A }
0N/A
0N/A /**
0N/A * Returns whether or not the mouse is currently over the divider
0N/A *
0N/A * @return whether or not the mouse is currently over the divider
0N/A * @since 1.5
0N/A */
0N/A public boolean isMouseOver() {
0N/A return mouseOver;
0N/A }
0N/A
0N/A /**
0N/A * Returns dividerSize x dividerSize
0N/A */
0N/A public Dimension getPreferredSize() {
0N/A // Ideally this would return the size from the layout manager,
0N/A // but that could result in the layed out size being different from
0N/A // the dividerSize, which may break developers as well as
0N/A // BasicSplitPaneUI.
0N/A if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
0N/A return new Dimension(getDividerSize(), 1);
0N/A }
0N/A return new Dimension(1, getDividerSize());
0N/A }
0N/A
0N/A /**
0N/A * Returns dividerSize x dividerSize
0N/A */
0N/A public Dimension getMinimumSize() {
0N/A return getPreferredSize();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Property change event, presumably from the JSplitPane, will message
0N/A * updateOrientation if necessary.
0N/A */
0N/A public void propertyChange(PropertyChangeEvent e) {
0N/A if (e.getSource() == splitPane) {
0N/A if (e.getPropertyName() == JSplitPane.ORIENTATION_PROPERTY) {
0N/A orientation = splitPane.getOrientation();
0N/A setCursor((orientation == JSplitPane.HORIZONTAL_SPLIT) ?
0N/A Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR) :
0N/A Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
4074N/A revalidateSplitPane();
0N/A }
0N/A else if (e.getPropertyName() == JSplitPane.
0N/A ONE_TOUCH_EXPANDABLE_PROPERTY) {
0N/A oneTouchExpandableChanged();
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Paints the divider.
0N/A */
0N/A public void paint(Graphics g) {
0N/A super.paint(g);
0N/A
0N/A // Paint the border.
0N/A Border border = getBorder();
0N/A
0N/A if (border != null) {
0N/A Dimension size = getSize();
0N/A
0N/A border.paintBorder(this, g, 0, 0, size.width, size.height);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Messaged when the oneTouchExpandable value of the JSplitPane the
0N/A * receiver is contained in changes. Will create the
0N/A * <code>leftButton</code> and <code>rightButton</code> if they
0N/A * are null. invalidates the receiver as well.
0N/A */
0N/A protected void oneTouchExpandableChanged() {
0N/A if (!DefaultLookup.getBoolean(splitPane, splitPaneUI,
0N/A "SplitPane.supportsOneTouchButtons", true)) {
0N/A // Look and feel doesn't want to support one touch buttons, bail.
0N/A return;
0N/A }
0N/A if (splitPane.isOneTouchExpandable() &&
0N/A leftButton == null &&
0N/A rightButton == null) {
0N/A /* Create the left button and add an action listener to
0N/A expand/collapse it. */
0N/A leftButton = createLeftOneTouchButton();
0N/A if (leftButton != null)
0N/A leftButton.addActionListener(new OneTouchActionHandler(true));
0N/A
0N/A
0N/A /* Create the right button and add an action listener to
0N/A expand/collapse it. */
0N/A rightButton = createRightOneTouchButton();
0N/A if (rightButton != null)
0N/A rightButton.addActionListener(new OneTouchActionHandler
0N/A (false));
0N/A
0N/A if (leftButton != null && rightButton != null) {
0N/A add(leftButton);
0N/A add(rightButton);
0N/A }
0N/A }
4074N/A revalidateSplitPane();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Creates and return an instance of JButton that can be used to
0N/A * collapse the left component in the split pane.
0N/A */
0N/A protected JButton createLeftOneTouchButton() {
0N/A JButton b = new JButton() {
0N/A public void setBorder(Border b) {
0N/A }
0N/A public void paint(Graphics g) {
0N/A if (splitPane != null) {
0N/A int[] xs = new int[3];
0N/A int[] ys = new int[3];
0N/A int blockSize;
0N/A
0N/A // Fill the background first ...
0N/A g.setColor(this.getBackground());
0N/A g.fillRect(0, 0, this.getWidth(),
0N/A this.getHeight());
0N/A
0N/A // ... then draw the arrow.
0N/A g.setColor(Color.black);
0N/A if (orientation == JSplitPane.VERTICAL_SPLIT) {
0N/A blockSize = Math.min(getHeight(), oneTouchSize);
0N/A xs[0] = blockSize;
0N/A xs[1] = 0;
0N/A xs[2] = blockSize << 1;
0N/A ys[0] = 0;
0N/A ys[1] = ys[2] = blockSize;
0N/A g.drawPolygon(xs, ys, 3); // Little trick to make the
0N/A // arrows of equal size
0N/A }
0N/A else {
0N/A blockSize = Math.min(getWidth(), oneTouchSize);
0N/A xs[0] = xs[2] = blockSize;
0N/A xs[1] = 0;
0N/A ys[0] = 0;
0N/A ys[1] = blockSize;
0N/A ys[2] = blockSize << 1;
0N/A }
0N/A g.fillPolygon(xs, ys, 3);
0N/A }
0N/A }
0N/A // Don't want the button to participate in focus traversable.
0N/A public boolean isFocusTraversable() {
0N/A return false;
0N/A }
0N/A };
0N/A b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
0N/A b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
0N/A b.setFocusPainted(false);
0N/A b.setBorderPainted(false);
0N/A b.setRequestFocusEnabled(false);
0N/A return b;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Creates and return an instance of JButton that can be used to
0N/A * collapse the right component in the split pane.
0N/A */
0N/A protected JButton createRightOneTouchButton() {
0N/A JButton b = new JButton() {
0N/A public void setBorder(Border border) {
0N/A }
0N/A public void paint(Graphics g) {
0N/A if (splitPane != null) {
0N/A int[] xs = new int[3];
0N/A int[] ys = new int[3];
0N/A int blockSize;
0N/A
0N/A // Fill the background first ...
0N/A g.setColor(this.getBackground());
0N/A g.fillRect(0, 0, this.getWidth(),
0N/A this.getHeight());
0N/A
0N/A // ... then draw the arrow.
0N/A if (orientation == JSplitPane.VERTICAL_SPLIT) {
0N/A blockSize = Math.min(getHeight(), oneTouchSize);
0N/A xs[0] = blockSize;
0N/A xs[1] = blockSize << 1;
0N/A xs[2] = 0;
0N/A ys[0] = blockSize;
0N/A ys[1] = ys[2] = 0;
0N/A }
0N/A else {
0N/A blockSize = Math.min(getWidth(), oneTouchSize);
0N/A xs[0] = xs[2] = 0;
0N/A xs[1] = blockSize;
0N/A ys[0] = 0;
0N/A ys[1] = blockSize;
0N/A ys[2] = blockSize << 1;
0N/A }
0N/A g.setColor(Color.black);
0N/A g.fillPolygon(xs, ys, 3);
0N/A }
0N/A }
0N/A // Don't want the button to participate in focus traversable.
0N/A public boolean isFocusTraversable() {
0N/A return false;
0N/A }
0N/A };
0N/A b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
0N/A b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
0N/A b.setFocusPainted(false);
0N/A b.setBorderPainted(false);
0N/A b.setRequestFocusEnabled(false);
0N/A return b;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Message to prepare for dragging. This messages the BasicSplitPaneUI
0N/A * with startDragging.
0N/A */
0N/A protected void prepareForDragging() {
0N/A splitPaneUI.startDragging();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Messages the BasicSplitPaneUI with dragDividerTo that this instance
0N/A * is contained in.
0N/A */
0N/A protected void dragDividerTo(int location) {
0N/A splitPaneUI.dragDividerTo(location);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Messages the BasicSplitPaneUI with finishDraggingTo that this instance
0N/A * is contained in.
0N/A */
0N/A protected void finishDraggingTo(int location) {
0N/A splitPaneUI.finishDraggingTo(location);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * MouseHandler is responsible for converting mouse events
0N/A * (released, dragged...) into the appropriate DragController
0N/A * methods.
0N/A * <p>
0N/A */
0N/A protected class MouseHandler extends MouseAdapter
0N/A implements MouseMotionListener
0N/A {
0N/A /**
0N/A * Starts the dragging session by creating the appropriate instance
0N/A * of DragController.
0N/A */
0N/A public void mousePressed(MouseEvent e) {
0N/A if ((e.getSource() == BasicSplitPaneDivider.this ||
0N/A e.getSource() == splitPane) &&
0N/A dragger == null &&splitPane.isEnabled()) {
0N/A Component newHiddenDivider = splitPaneUI.
0N/A getNonContinuousLayoutDivider();
0N/A
0N/A if (hiddenDivider != newHiddenDivider) {
0N/A if (hiddenDivider != null) {
0N/A hiddenDivider.removeMouseListener(this);
0N/A hiddenDivider.removeMouseMotionListener(this);
0N/A }
0N/A hiddenDivider = newHiddenDivider;
0N/A if (hiddenDivider != null) {
0N/A hiddenDivider.addMouseMotionListener(this);
0N/A hiddenDivider.addMouseListener(this);
0N/A }
0N/A }
0N/A if (splitPane.getLeftComponent() != null &&
0N/A splitPane.getRightComponent() != null) {
0N/A if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
0N/A dragger = new DragController(e);
0N/A }
0N/A else {
0N/A dragger = new VerticalDragController(e);
0N/A }
0N/A if (!dragger.isValid()) {
0N/A dragger = null;
0N/A }
0N/A else {
0N/A prepareForDragging();
0N/A dragger.continueDrag(e);
0N/A }
0N/A }
0N/A e.consume();
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * If dragger is not null it is messaged with completeDrag.
0N/A */
0N/A public void mouseReleased(MouseEvent e) {
0N/A if (dragger != null) {
0N/A if (e.getSource() == splitPane) {
0N/A dragger.completeDrag(e.getX(), e.getY());
0N/A }
0N/A else if (e.getSource() == BasicSplitPaneDivider.this) {
0N/A Point ourLoc = getLocation();
0N/A
0N/A dragger.completeDrag(e.getX() + ourLoc.x,
0N/A e.getY() + ourLoc.y);
0N/A }
0N/A else if (e.getSource() == hiddenDivider) {
0N/A Point hDividerLoc = hiddenDivider.getLocation();
0N/A int ourX = e.getX() + hDividerLoc.x;
0N/A int ourY = e.getY() + hDividerLoc.y;
0N/A
0N/A dragger.completeDrag(ourX, ourY);
0N/A }
0N/A dragger = null;
0N/A e.consume();
0N/A }
0N/A }
0N/A
0N/A
0N/A //
0N/A // MouseMotionListener
0N/A //
0N/A
0N/A /**
0N/A * If dragger is not null it is messaged with continueDrag.
0N/A */
0N/A public void mouseDragged(MouseEvent e) {
0N/A if (dragger != null) {
0N/A if (e.getSource() == splitPane) {
0N/A dragger.continueDrag(e.getX(), e.getY());
0N/A }
0N/A else if (e.getSource() == BasicSplitPaneDivider.this) {
0N/A Point ourLoc = getLocation();
0N/A
0N/A dragger.continueDrag(e.getX() + ourLoc.x,
0N/A e.getY() + ourLoc.y);
0N/A }
0N/A else if (e.getSource() == hiddenDivider) {
0N/A Point hDividerLoc = hiddenDivider.getLocation();
0N/A int ourX = e.getX() + hDividerLoc.x;
0N/A int ourY = e.getY() + hDividerLoc.y;
0N/A
0N/A dragger.continueDrag(ourX, ourY);
0N/A }
0N/A e.consume();
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Resets the cursor based on the orientation.
0N/A */
0N/A public void mouseMoved(MouseEvent e) {
0N/A }
0N/A
0N/A /**
0N/A * Invoked when the mouse enters a component.
0N/A *
0N/A * @param e MouseEvent describing the details of the enter event.
0N/A * @since 1.5
0N/A */
0N/A public void mouseEntered(MouseEvent e) {
0N/A if (e.getSource() == BasicSplitPaneDivider.this) {
0N/A setMouseOver(true);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Invoked when the mouse exits a component.
0N/A *
0N/A * @param e MouseEvent describing the details of the exit event.
0N/A * @since 1.5
0N/A */
0N/A public void mouseExited(MouseEvent e) {
0N/A if (e.getSource() == BasicSplitPaneDivider.this) {
0N/A setMouseOver(false);
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Handles the events during a dragging session for a
0N/A * HORIZONTAL_SPLIT oriented split pane. This continually
0N/A * messages <code>dragDividerTo</code> and then when done messages
0N/A * <code>finishDraggingTo</code>. When an instance is created it should be
0N/A * messaged with <code>isValid</code> to insure that dragging can happen
0N/A * (dragging won't be allowed if the two views can not be resized).
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A */
0N/A protected class DragController
0N/A {
0N/A /**
0N/A * Initial location of the divider.
0N/A */
0N/A int initialX;
0N/A
0N/A /**
0N/A * Maximum and minimum positions to drag to.
0N/A */
0N/A int maxX, minX;
0N/A
0N/A /**
0N/A * Initial location the mouse down happened at.
0N/A */
0N/A int offset;
0N/A
0N/A
0N/A protected DragController(MouseEvent e) {
0N/A JSplitPane splitPane = splitPaneUI.getSplitPane();
0N/A Component leftC = splitPane.getLeftComponent();
0N/A Component rightC = splitPane.getRightComponent();
0N/A
0N/A initialX = getLocation().x;
0N/A if (e.getSource() == BasicSplitPaneDivider.this) {
0N/A offset = e.getX();
0N/A }
0N/A else { // splitPane
0N/A offset = e.getX() - initialX;
0N/A }
0N/A if (leftC == null || rightC == null || offset < -1 ||
0N/A offset >= getSize().width) {
0N/A // Don't allow dragging.
0N/A maxX = -1;
0N/A }
0N/A else {
0N/A Insets insets = splitPane.getInsets();
0N/A
0N/A if (leftC.isVisible()) {
0N/A minX = leftC.getMinimumSize().width;
0N/A if (insets != null) {
0N/A minX += insets.left;
0N/A }
0N/A }
0N/A else {
0N/A minX = 0;
0N/A }
0N/A if (rightC.isVisible()) {
0N/A int right = (insets != null) ? insets.right : 0;
0N/A maxX = Math.max(0, splitPane.getSize().width -
0N/A (getSize().width + right) -
0N/A rightC.getMinimumSize().width);
0N/A }
0N/A else {
0N/A int right = (insets != null) ? insets.right : 0;
0N/A maxX = Math.max(0, splitPane.getSize().width -
0N/A (getSize().width + right));
0N/A }
0N/A if (maxX < minX) minX = maxX = 0;
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns true if the dragging session is valid.
0N/A */
0N/A protected boolean isValid() {
0N/A return (maxX > 0);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the new position to put the divider at based on
0N/A * the passed in MouseEvent.
0N/A */
0N/A protected int positionForMouseEvent(MouseEvent e) {
0N/A int newX = (e.getSource() == BasicSplitPaneDivider.this) ?
0N/A (e.getX() + getLocation().x) : e.getX();
0N/A
0N/A newX = Math.min(maxX, Math.max(minX, newX - offset));
0N/A return newX;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the x argument, since this is used for horizontal
0N/A * splits.
0N/A */
0N/A protected int getNeededLocation(int x, int y) {
0N/A int newX;
0N/A
0N/A newX = Math.min(maxX, Math.max(minX, x - offset));
0N/A return newX;
0N/A }
0N/A
0N/A
0N/A protected void continueDrag(int newX, int newY) {
0N/A dragDividerTo(getNeededLocation(newX, newY));
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Messages dragDividerTo with the new location for the mouse
0N/A * event.
0N/A */
0N/A protected void continueDrag(MouseEvent e) {
0N/A dragDividerTo(positionForMouseEvent(e));
0N/A }
0N/A
0N/A
0N/A protected void completeDrag(int x, int y) {
0N/A finishDraggingTo(getNeededLocation(x, y));
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Messages finishDraggingTo with the new location for the mouse
0N/A * event.
0N/A */
0N/A protected void completeDrag(MouseEvent e) {
0N/A finishDraggingTo(positionForMouseEvent(e));
0N/A }
0N/A } // End of BasicSplitPaneDivider.DragController
0N/A
0N/A
0N/A /**
0N/A * Handles the events during a dragging session for a
0N/A * VERTICAL_SPLIT oriented split pane. This continually
0N/A * messages <code>dragDividerTo</code> and then when done messages
0N/A * <code>finishDraggingTo</code>. When an instance is created it should be
0N/A * messaged with <code>isValid</code> to insure that dragging can happen
0N/A * (dragging won't be allowed if the two views can not be resized).
0N/A */
0N/A protected class VerticalDragController extends DragController
0N/A {
0N/A /* DragControllers ivars are now in terms of y, not x. */
0N/A protected VerticalDragController(MouseEvent e) {
0N/A super(e);
0N/A JSplitPane splitPane = splitPaneUI.getSplitPane();
0N/A Component leftC = splitPane.getLeftComponent();
0N/A Component rightC = splitPane.getRightComponent();
0N/A
0N/A initialX = getLocation().y;
0N/A if (e.getSource() == BasicSplitPaneDivider.this) {
0N/A offset = e.getY();
0N/A }
0N/A else {
0N/A offset = e.getY() - initialX;
0N/A }
0N/A if (leftC == null || rightC == null || offset < -1 ||
0N/A offset > getSize().height) {
0N/A // Don't allow dragging.
0N/A maxX = -1;
0N/A }
0N/A else {
0N/A Insets insets = splitPane.getInsets();
0N/A
0N/A if (leftC.isVisible()) {
0N/A minX = leftC.getMinimumSize().height;
0N/A if (insets != null) {
0N/A minX += insets.top;
0N/A }
0N/A }
0N/A else {
0N/A minX = 0;
0N/A }
0N/A if (rightC.isVisible()) {
0N/A int bottom = (insets != null) ? insets.bottom : 0;
0N/A
0N/A maxX = Math.max(0, splitPane.getSize().height -
0N/A (getSize().height + bottom) -
0N/A rightC.getMinimumSize().height);
0N/A }
0N/A else {
0N/A int bottom = (insets != null) ? insets.bottom : 0;
0N/A
0N/A maxX = Math.max(0, splitPane.getSize().height -
0N/A (getSize().height + bottom));
0N/A }
0N/A if (maxX < minX) minX = maxX = 0;
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the y argument, since this is used for vertical
0N/A * splits.
0N/A */
0N/A protected int getNeededLocation(int x, int y) {
0N/A int newY;
0N/A
0N/A newY = Math.min(maxX, Math.max(minX, y - offset));
0N/A return newY;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the new position to put the divider at based on
0N/A * the passed in MouseEvent.
0N/A */
0N/A protected int positionForMouseEvent(MouseEvent e) {
0N/A int newY = (e.getSource() == BasicSplitPaneDivider.this) ?
0N/A (e.getY() + getLocation().y) : e.getY();
0N/A
0N/A
0N/A newY = Math.min(maxX, Math.max(minX, newY - offset));
0N/A return newY;
0N/A }
0N/A } // End of BasicSplitPaneDividier.VerticalDragController
0N/A
0N/A
0N/A /**
0N/A * Used to layout a <code>BasicSplitPaneDivider</code>.
0N/A * Layout for the divider
0N/A * involves appropriately moving the left/right buttons around.
0N/A * <p>
0N/A */
0N/A protected class DividerLayout implements LayoutManager
0N/A {
0N/A public void layoutContainer(Container c) {
0N/A if (leftButton != null && rightButton != null &&
0N/A c == BasicSplitPaneDivider.this) {
0N/A if (splitPane.isOneTouchExpandable()) {
0N/A Insets insets = getInsets();
0N/A
0N/A if (orientation == JSplitPane.VERTICAL_SPLIT) {
0N/A int extraX = (insets != null) ? insets.left : 0;
0N/A int blockSize = getHeight();
0N/A
0N/A if (insets != null) {
0N/A blockSize -= (insets.top + insets.bottom);
0N/A blockSize = Math.max(blockSize, 0);
0N/A }
0N/A blockSize = Math.min(blockSize, oneTouchSize);
0N/A
0N/A int y = (c.getSize().height - blockSize) / 2;
0N/A
0N/A if (!centerOneTouchButtons) {
0N/A y = (insets != null) ? insets.top : 0;
0N/A extraX = 0;
0N/A }
0N/A leftButton.setBounds(extraX + oneTouchOffset, y,
0N/A blockSize * 2, blockSize);
0N/A rightButton.setBounds(extraX + oneTouchOffset +
0N/A oneTouchSize * 2, y,
0N/A blockSize * 2, blockSize);
0N/A }
0N/A else {
0N/A int extraY = (insets != null) ? insets.top : 0;
0N/A int blockSize = getWidth();
0N/A
0N/A if (insets != null) {
0N/A blockSize -= (insets.left + insets.right);
0N/A blockSize = Math.max(blockSize, 0);
0N/A }
0N/A blockSize = Math.min(blockSize, oneTouchSize);
0N/A
0N/A int x = (c.getSize().width - blockSize) / 2;
0N/A
0N/A if (!centerOneTouchButtons) {
0N/A x = (insets != null) ? insets.left : 0;
0N/A extraY = 0;
0N/A }
0N/A
0N/A leftButton.setBounds(x, extraY + oneTouchOffset,
0N/A blockSize, blockSize * 2);
0N/A rightButton.setBounds(x, extraY + oneTouchOffset +
0N/A oneTouchSize * 2, blockSize,
0N/A blockSize * 2);
0N/A }
0N/A }
0N/A else {
0N/A leftButton.setBounds(-5, -5, 1, 1);
0N/A rightButton.setBounds(-5, -5, 1, 1);
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A public Dimension minimumLayoutSize(Container c) {
0N/A // NOTE: This isn't really used, refer to
0N/A // BasicSplitPaneDivider.getPreferredSize for the reason.
0N/A // I leave it in hopes of having this used at some point.
0N/A if (c != BasicSplitPaneDivider.this || splitPane == null) {
0N/A return new Dimension(0,0);
0N/A }
0N/A Dimension buttonMinSize = null;
0N/A
0N/A if (splitPane.isOneTouchExpandable() && leftButton != null) {
0N/A buttonMinSize = leftButton.getMinimumSize();
0N/A }
0N/A
0N/A Insets insets = getInsets();
0N/A int width = getDividerSize();
0N/A int height = width;
0N/A
0N/A if (orientation == JSplitPane.VERTICAL_SPLIT) {
0N/A if (buttonMinSize != null) {
0N/A int size = buttonMinSize.height;
0N/A if (insets != null) {
0N/A size += insets.top + insets.bottom;
0N/A }
0N/A height = Math.max(height, size);
0N/A }
0N/A width = 1;
0N/A }
0N/A else {
0N/A if (buttonMinSize != null) {
0N/A int size = buttonMinSize.width;
0N/A if (insets != null) {
0N/A size += insets.left + insets.right;
0N/A }
0N/A width = Math.max(width, size);
0N/A }
0N/A height = 1;
0N/A }
0N/A return new Dimension(width, height);
0N/A }
0N/A
0N/A
0N/A public Dimension preferredLayoutSize(Container c) {
0N/A return minimumLayoutSize(c);
0N/A }
0N/A
0N/A
0N/A public void removeLayoutComponent(Component c) {}
0N/A
0N/A public void addLayoutComponent(String string, Component c) {}
0N/A } // End of class BasicSplitPaneDivider.DividerLayout
0N/A
0N/A
0N/A /**
0N/A * Listeners installed on the one touch expandable buttons.
0N/A */
0N/A private class OneTouchActionHandler implements ActionListener {
0N/A /** True indicates the resize should go the minimum (top or left)
0N/A * vs false which indicates the resize should go to the maximum.
0N/A */
0N/A private boolean toMinimum;
0N/A
0N/A OneTouchActionHandler(boolean toMinimum) {
0N/A this.toMinimum = toMinimum;
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent e) {
0N/A Insets insets = splitPane.getInsets();
0N/A int lastLoc = splitPane.getLastDividerLocation();
0N/A int currentLoc = splitPaneUI.getDividerLocation(splitPane);
0N/A int newLoc;
0N/A
0N/A // We use the location from the UI directly, as the location the
0N/A // JSplitPane itself maintains is not necessarly correct.
0N/A if (toMinimum) {
0N/A if (orientation == JSplitPane.VERTICAL_SPLIT) {
0N/A if (currentLoc >= (splitPane.getHeight() -
0N/A insets.bottom - getHeight())) {
0N/A int maxLoc = splitPane.getMaximumDividerLocation();
0N/A newLoc = Math.min(lastLoc, maxLoc);
0N/A splitPaneUI.setKeepHidden(false);
0N/A }
0N/A else {
0N/A newLoc = insets.top;
0N/A splitPaneUI.setKeepHidden(true);
0N/A }
0N/A }
0N/A else {
0N/A if (currentLoc >= (splitPane.getWidth() -
0N/A insets.right - getWidth())) {
0N/A int maxLoc = splitPane.getMaximumDividerLocation();
0N/A newLoc = Math.min(lastLoc, maxLoc);
0N/A splitPaneUI.setKeepHidden(false);
0N/A }
0N/A else {
0N/A newLoc = insets.left;
0N/A splitPaneUI.setKeepHidden(true);
0N/A }
0N/A }
0N/A }
0N/A else {
0N/A if (orientation == JSplitPane.VERTICAL_SPLIT) {
0N/A if (currentLoc == insets.top) {
0N/A int maxLoc = splitPane.getMaximumDividerLocation();
0N/A newLoc = Math.min(lastLoc, maxLoc);
0N/A splitPaneUI.setKeepHidden(false);
0N/A }
0N/A else {
0N/A newLoc = splitPane.getHeight() - getHeight() -
0N/A insets.top;
0N/A splitPaneUI.setKeepHidden(true);
0N/A }
0N/A }
0N/A else {
0N/A if (currentLoc == insets.left) {
0N/A int maxLoc = splitPane.getMaximumDividerLocation();
0N/A newLoc = Math.min(lastLoc, maxLoc);
0N/A splitPaneUI.setKeepHidden(false);
0N/A }
0N/A else {
0N/A newLoc = splitPane.getWidth() - getWidth() -
0N/A insets.left;
0N/A splitPaneUI.setKeepHidden(true);
0N/A }
0N/A }
0N/A }
0N/A if (currentLoc != newLoc) {
0N/A splitPane.setDividerLocation(newLoc);
0N/A // We do this in case the dividers notion of the location
0N/A // differs from the real location.
0N/A splitPane.setLastDividerLocation(currentLoc);
0N/A }
0N/A }
0N/A } // End of class BasicSplitPaneDivider.LeftActionListener
0N/A}