diff options
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java')
-rw-r--r-- | libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java | 1556 |
1 files changed, 1556 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java new file mode 100644 index 00000000000..ff7e8acfbb6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -0,0 +1,1556 @@ +/* BasicSplitPaneUI.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager2; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JSplitPane; +import javax.swing.KeyStroke; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SplitPaneUI; + +/** + * This is the Basic Look and Feel implementation of the SplitPaneUI class. + */ +public class BasicSplitPaneUI extends SplitPaneUI +{ + /** + * This Layout Manager controls the position and size of the components when + * the JSplitPane's orientation is HORIZONTAL_SPLIT. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class BasicHorizontalLayoutManager implements LayoutManager2 + { + // 3 components at a time. + // LEFT/TOP = 0 + // RIGHT/BOTTOM = 1 + // DIVIDER = 2 + + /** + * This array contains the components in the JSplitPane. The left/top + * component is at index 0, the right/bottom is at 1, and the divider is + * at 2. + */ + protected Component[] components = new Component[3]; + + // These are the _current_ widths of the associated component. + + /** + * This array contains the current width (for HORIZONTAL_SPLIT) or height + * (for VERTICAL_SPLIT) of the components. The indices are the same as + * for components. + */ + protected int[] sizes = new int[3]; + + /** + * This method adds the component given to the JSplitPane. The position of + * the component is given by the constraints object. + * + * @param comp The Component to add. + * @param constraints The constraints that bind the object. + */ + public void addLayoutComponent(Component comp, Object constraints) + { + addLayoutComponent((String) constraints, comp); + } + + /** + * This method is called to add a Component to the JSplitPane. The + * placement string determines where the Component will be placed. The + * string should be one of LEFT, RIGHT, TOP, BOTTOM or null (signals that + * the component is the divider). + * + * @param place The placement of the Component. + * @param component The Component to add. + * + * @throws IllegalArgumentException DOCUMENT ME! + */ + public void addLayoutComponent(String place, Component component) + { + int i = 0; + if (place == null) + i = 2; + else if (place.equals(JSplitPane.TOP) || place.equals(JSplitPane.LEFT)) + i = 0; + else if (place.equals(JSplitPane.BOTTOM) + || place.equals(JSplitPane.RIGHT)) + i = 1; + else + throw new IllegalArgumentException("Illegal placement in JSplitPane"); + components[i] = component; + resetSizeAt(i); + splitPane.revalidate(); + splitPane.repaint(); + } + + /** + * This method returns the width of the JSplitPane minus the insets. + * + * @param containerSize The Dimensions of the JSplitPane. + * @param insets The Insets of the JSplitPane. + * + * @return The width of the JSplitPane minus the insets. + */ + protected int getAvailableSize(Dimension containerSize, Insets insets) + { + return containerSize.width - insets.left - insets.right; + } + + /** + * This method returns the given insets left value. If the given inset is + * null, then 0 is returned. + * + * @param insets The Insets to use with the JSplitPane. + * + * @return The inset's left value. + */ + protected int getInitialLocation(Insets insets) + { + if (insets != null) + return insets.left; + return 0; + } + + /** + * This specifies how a component is aligned with respect to other + * components in the x fdirection. + * + * @param target The container. + * + * @return The component's alignment. + */ + public float getLayoutAlignmentX(Container target) + { + return target.getAlignmentX(); + } + + /** + * This specifies how a component is aligned with respect to other + * components in the y direction. + * + * @param target The container. + * + * @return The component's alignment. + */ + public float getLayoutAlignmentY(Container target) + { + return target.getAlignmentY(); + } + + /** + * This method returns the preferred width of the component. + * + * @param c The component to measure. + * + * @return The preferred width of the component. + */ + protected int getPreferredSizeOfComponent(Component c) + { + Dimension dims = c.getPreferredSize(); + if (dims != null) + return dims.width; + return 0; + } + + /** + * This method returns the current width of the component. + * + * @param c The component to measure. + * + * @return The width of the component. + */ + protected int getSizeOfComponent(Component c) + { + return c.getWidth(); + } + + /** + * This method returns the sizes array. + * + * @return The sizes array. + */ + protected int[] getSizes() + { + return sizes; + } + + /** + * This method invalidates the layout. It does nothing. + * + * @param c The container to invalidate. + */ + public void invalidateLayout(Container c) + { + // DO NOTHING + } + + /** + * This method lays out the components in the container. + * + * @param container The container to lay out. + */ + public void layoutContainer(Container container) + { + if (container instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) container; + distributeExtraSpace(); + Insets insets = split.getInsets(); + int width = getInitialLocation(insets); + Dimension dims = split.getSize(); + for (int i = 0; i < components.length; i += 2) + { + if (components[i] == null) + continue; + setComponentToSize(components[i], sizes[i], width, insets, dims); + width += sizes[i]; + } + if (components[1] != null) + { + setComponentToSize(components[1], sizes[1], width, insets, dims); + width += sizes[1]; + } + } + } + + /** + * This method returns the maximum size for the container given the + * components. It returns a new Dimension object that has width and + * height equal to Integer.MAX_VALUE. + * + * @param target The container to measure. + * + * @return The maximum size. + */ + public Dimension maximumLayoutSize(Container target) + { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * This method returns the container's minimum size. The minimum width is + * the sum of all the component's minimum widths. The minimum height is + * the maximum of all the components' minimum heights. + * + * @param target The container to measure. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container target) + { + if (target instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) target; + Insets insets = target.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getMinimumSize(); + if (dims != null) + { + width += dims.width; + height = Math.max(height, dims.height); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method returns the container's preferred size. The preferred width + * is the sum of all the component's preferred widths. The preferred + * height is the maximum of all the components' preferred heights. + * + * @param target The container to measure. + * + * @return The preferred size. + */ + public Dimension preferredLayoutSize(Container target) + { + if (target instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) target; + Insets insets = target.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getPreferredSize(); + if (dims != null) + { + width += dims.width; + if (! (components[i] instanceof BasicSplitPaneDivider)) + height = Math.max(height, dims.height); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method removes the component from the layout. + * + * @param component The component to remove from the layout. + */ + public void removeLayoutComponent(Component component) + { + for (int i = 0; i < components.length; i++) + { + if (component == components[i]) + { + components[i] = null; + sizes[i] = 0; + } + } + } + + /** + * This method resets the size of Component to the preferred size. + * + * @param index The index of the component to reset. + */ + protected void resetSizeAt(int index) + { + if (components[index] != null) + sizes[index] = getPreferredSizeOfComponent(components[index]); + } + + /** + * This method resets the sizes of all the components. + */ + public void resetToPreferredSizes() + { + for (int i = 0; i < components.length; i++) + resetSizeAt(i); + } + + /** + * This methods sets the bounds of the given component. The width is the + * size. The height is the container size minus the top and bottom + * inset. The x coordinate is the location given. The y coordinate is + * the top inset. + * + * @param c The component to set. + * @param size The width of the component. + * @param location The x coordinate. + * @param insets The insets to use. + * @param containerSize The height of the container. + */ + protected void setComponentToSize(Component c, int size, int location, + Insets insets, Dimension containerSize) + { + int w = size; + int h = containerSize.height - insets.top - insets.bottom; + int x = location; + int y = insets.top; + c.setBounds(x, y, w, h); + } + + /** + * This method stores the given int array as the new sizes array. + * + * @param newSizes The array to use as sizes. + */ + protected void setSizes(int[] newSizes) + { + sizes = newSizes; + } + + /** + * This method determines the size of each component. It should be called + * when a new Layout Manager is created for an existing JSplitPane. + */ + protected void updateComponents() + { + Component left = splitPane.getLeftComponent(); + Component right = splitPane.getRightComponent(); + + if (left != null) + { + components[0] = left; + resetSizeAt(0); + } + if (right != null) + { + components[1] = right; + resetSizeAt(1); + } + components[2] = divider; + resetSizeAt(2); + } + + /** + * This method resizes the left and right components to fit inside the + * JSplitPane when there is extra space. + */ + void distributeExtraSpace() + { + int availSize = getAvailableSize(splitPane.getSize(), + splitPane.getInsets()); + int[] newSizes = new int[3]; + double weight = splitPane.getResizeWeight(); + + int oldLen = sizes[0] + sizes[1]; + + // dividers don't change size. + availSize -= sizes[2] + oldLen; + + int rightAlloc = (int) (availSize * (1 - weight)); + int leftAlloc = availSize - rightAlloc; + + sizes[0] += leftAlloc; + sizes[1] += rightAlloc; + } + + /** + * This method returns the minimum width of the component at the given + * index. + * + * @param index The index to check. + * + * @return The minimum width. + */ + int minimumSizeOfComponent(int index) + { + Dimension dims = components[index].getMinimumSize(); + if (dims != null) + return dims.width; + else + return 0; + } + } //end BasicHorizontalLayoutManager + + /** + * This class is the Layout Manager for the JSplitPane when the orientation + * is VERTICAL_SPLIT. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class BasicVerticalLayoutManager + extends BasicHorizontalLayoutManager + { + /** + * This method returns the height of the container minus the top and + * bottom inset. + * + * @param containerSize The size of the container. + * @param insets The insets of the container. + * + * @return The height minus top and bottom inset. + */ + protected int getAvailableSize(Dimension containerSize, Insets insets) + { + return containerSize.height - insets.top - insets.bottom; + } + + /** + * This method returns the top inset. + * + * @param insets The Insets to use. + * + * @return The top inset. + */ + protected int getInitialLocation(Insets insets) + { + return insets.top; + } + + /** + * This method returns the preferred height of the component. + * + * @param c The component to measure. + * + * @return The preferred height of the component. + */ + protected int getPreferredSizeOfComponent(Component c) + { + Dimension dims = c.getPreferredSize(); + if (dims != null) + return dims.height; + return 0; + } + + /** + * This method returns the current height of the component. + * + * @param c The component to measure. + * + * @return The current height of the component. + */ + protected int getSizeOfComponent(Component c) + { + return c.getHeight(); + } + + /** + * This method returns the minimum layout size. The minimum height is the + * sum of all the components' minimum heights. The minimum width is the + * maximum of all the components' minimum widths. + * + * @param container The container to measure. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container container) + { + if (container instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) container; + Insets insets = container.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getMinimumSize(); + if (dims != null) + { + height += dims.height; + width = Math.max(width, dims.width); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method returns the preferred layout size. The preferred height is + * the sum of all the components' preferred heights. The preferred width + * is the maximum of all the components' preferred widths. + * + * @param container The container to measure. + * + * @return The preferred size. + */ + public Dimension preferredLayoutSize(Container container) + { + if (container instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) container; + Insets insets = container.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getPreferredSize(); + if (dims != null) + { + height += dims.height; + width = Math.max(width, dims.width); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method sets the bounds of the given component. The y coordinate is + * the location given. The x coordinate is the left inset. The height is + * the size given. The width is the container size minus the left and + * right inset. + * + * @param c The component to set bounds for. + * @param size The height. + * @param location The y coordinate. + * @param insets The insets to use. + * @param containerSize The container's size. + */ + protected void setComponentToSize(Component c, int size, int location, + Insets insets, Dimension containerSize) + { + int y = location; + int x = insets.left; + int h = size; + int w = containerSize.width - insets.left - insets.right; + + c.setBounds(x, y, w, h); + } + + /** + * This method returns the minimum height of the component at the given + * index. + * + * @param index The index of the component to check. + * + * @return The minimum height of the given component. + */ + int minimumSizeOfComponent(int index) + { + Dimension dims = components[index].getMinimumSize(); + if (dims != null) + return dims.height; + else + return 0; + } + } + + /** + * This class handles FocusEvents from the JComponent. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class FocusHandler extends FocusAdapter + { + /** + * This method is called when the JSplitPane gains focus. + * + * @param ev The FocusEvent. + */ + public void focusGained(FocusEvent ev) + { + // FIXME: implement. + } + + /** + * This method is called when the JSplitPane loses focus. + * + * @param ev The FocusEvent. + */ + public void focusLost(FocusEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling down + * and right key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardDownRightHandler implements ActionListener + { + /** + * This method is called when the down or right keys are pressed. + * + * @param ev The ActionEvent + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling end + * key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardEndHandler implements ActionListener + { + /** + * This method is called when the end key is pressed. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling home + * key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardHomeHandler implements ActionListener + { + /** + * This method is called when the home key is pressed. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling resize + * toggles. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardResizeToggleHandler implements ActionListener + { + /** + * This method is called when a resize is toggled. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handler up and + * left key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardUpLeftHandler implements ActionListener + { + /** + * This method is called when the left or up keys are pressed. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This helper class handles PropertyChangeEvents from the JSplitPane. When + * a property changes, this will update the UI accordingly. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class PropertyHandler implements PropertyChangeListener + { + /** + * This method is called whenever one of the JSplitPane's properties + * change. + * + * @param e DOCUMENT ME! + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY)) + { + int newSize = splitPane.getDividerSize(); + int[] tmpSizes = layoutManager.getSizes(); + dividerSize = tmpSizes[2]; + Component left = splitPane.getLeftComponent(); + Component right = splitPane.getRightComponent(); + int newSpace = newSize - tmpSizes[2]; + + tmpSizes[2] = newSize; + + tmpSizes[0] += newSpace / 2; + tmpSizes[1] += newSpace / 2; + + layoutManager.setSizes(tmpSizes); + } + else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) + { + int max = layoutManager.getAvailableSize(splitPane.getSize(), + splitPane.getInsets()); + int dividerLoc = getDividerLocation(splitPane); + double prop = ((double) dividerLoc) / max; + + resetLayoutManager(); + if (prop <= 1 && prop >= 0) + splitPane.setDividerLocation(prop); + } + layoutManager.layoutContainer(splitPane); + splitPane.repaint(); + // Don't have to deal with continuous_layout - only + // necessary in dragging modes (and it's checked + // every time you drag there) + // Don't have to deal with resize_weight (as there + // will be no extra space associated with this + // event - the changes to the weighting will + // be taken into account the next time the + // sizes change.) + // Don't have to deal with divider_location + // The method in JSplitPane calls our setDividerLocation + // so we'll know about those anyway. + // Don't have to deal with last_divider_location + // Although I'm not sure why, it doesn't seem to + // have any effect on Sun's JSplitPane. + // one_touch_expandable changes are dealt with + // by our divider. + } + } + + /** The location of the divider when dragging began. */ + protected int beginDragDividerLocation; + + /** The size of the divider while dragging. */ + protected int dividerSize; + + /** The location where the last drag location ended. */ + transient int lastDragLocation = -1; + + /** The distance the divider is moved when moved by keyboard actions. */ + protected static int KEYBOARD_DIVIDER_MOVE_OFFSET; + + /** The divider that divides this JSplitPane. */ + protected BasicSplitPaneDivider divider; + + /** The listener that listens for PropertyChangeEvents from the JSplitPane. */ + protected PropertyChangeListener propertyChangeListener; + + /** The JSplitPane's focus handler. */ + protected FocusListener focusListener; + + /** @deprecated The handler for down and right key presses. */ + protected ActionListener keyboardDownRightListener; + + /** @deprecated The handler for end key presses. */ + protected ActionListener keyboardEndListener; + + /** @deprecated The handler for home key presses. */ + protected ActionListener keyboardHomeListener; + + /** @deprecated The handler for toggling resizes. */ + protected ActionListener keyboardResizeToggleListener; + + /** @deprecated The handler for up and left key presses. */ + protected ActionListener keyboardUpLeftListener; + + /** The JSplitPane's current layout manager. */ + protected BasicHorizontalLayoutManager layoutManager; + + /** @deprecated The divider resize toggle key. */ + protected KeyStroke dividerResizeToggleKey; + + /** @deprecated The down key. */ + protected KeyStroke downKey; + + /** @deprecated The end key. */ + protected KeyStroke endKey; + + /** @deprecated The home key. */ + protected KeyStroke homeKey; + + /** @deprecated The left key. */ + protected KeyStroke leftKey; + + /** @deprecated The right key. */ + protected KeyStroke rightKey; + + /** @deprecated The up key. */ + protected KeyStroke upKey; + + /** Set to true when dragging heavy weight components. */ + protected boolean draggingHW; + + /** + * The constraints object used when adding the non-continuous divider to the + * JSplitPane. + */ + protected static final String NON_CONTINUOUS_DIVIDER + = "nonContinuousDivider"; + + /** The dark divider used when dragging in non-continuous layout mode. */ + protected Component nonContinuousLayoutDivider; + + /** The JSplitPane that this UI draws. */ + protected JSplitPane splitPane; + + /** + * Creates a new BasicSplitPaneUI object. + */ + public BasicSplitPaneUI() + { + } + + /** + * This method creates a new BasicSplitPaneUI for the given JComponent. + * + * @param x The JComponent to create a UI for. + * + * @return A new BasicSplitPaneUI. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicSplitPaneUI(); + } + + /** + * This method installs the BasicSplitPaneUI for the given JComponent. + * + * @param c The JComponent to install the UI for. + */ + public void installUI(JComponent c) + { + if (c instanceof JSplitPane) + { + splitPane = (JSplitPane) c; + installDefaults(); + installListeners(); + installKeyboardActions(); + } + } + + /** + * This method uninstalls the BasicSplitPaneUI for the given JComponent. + * + * @param c The JComponent to uninstall the UI for. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallDefaults(); + + splitPane = null; + } + + /** + * This method installs the defaults given by the Look and Feel. + */ + protected void installDefaults() + { + divider = createDefaultDivider(); + resetLayoutManager(); + nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); + splitPane.add(divider, JSplitPane.DIVIDER); + + // There is no need to add the nonContinuousLayoutDivider + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + splitPane.setBackground(defaults.getColor("SplitPane.background")); + splitPane.setBorder(defaults.getBorder("SplitPane.border")); + splitPane.setDividerSize(defaults.getInt("SplitPane.dividerSize")); + splitPane.setOpaque(true); + } + + /** + * This method uninstalls the defaults and nulls any objects created during + * install. + */ + protected void uninstallDefaults() + { + layoutManager = null; + splitPane.remove(divider); + divider = null; + nonContinuousLayoutDivider = null; + + splitPane.setBackground(null); + splitPane.setBorder(null); + } + + /** + * This method installs the listeners needed for this UI to function. + */ + protected void installListeners() + { + propertyChangeListener = createPropertyChangeListener(); + focusListener = createFocusListener(); + + splitPane.addPropertyChangeListener(propertyChangeListener); + splitPane.addFocusListener(focusListener); + } + + /** + * This method uninstalls all listeners registered for the UI. + */ + protected void uninstallListeners() + { + splitPane.removePropertyChangeListener(propertyChangeListener); + splitPane.removeFocusListener(focusListener); + + focusListener = null; + propertyChangeListener = null; + } + + /** + * This method installs the keyboard actions for the JSplitPane. + */ + protected void installKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method reverses the work done in installKeyboardActions. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method creates a new PropertyChangeListener. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyHandler(); + } + + /** + * This method creates a new FocusListener. + * + * @return A new FocusListener. + */ + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + + /** + * This method creates a new ActionListener for up and left key presses. + * + * @return A new ActionListener for up and left keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardUpLeftListener() + { + return new KeyboardUpLeftHandler(); + } + + /** + * This method creates a new ActionListener for down and right key presses. + * + * @return A new ActionListener for down and right keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardDownRightListener() + { + return new KeyboardDownRightHandler(); + } + + /** + * This method creates a new ActionListener for home key presses. + * + * @return A new ActionListener for home keys. + * + * @deprecated + */ + protected ActionListener createKeyboardHomeListener() + { + return new KeyboardHomeHandler(); + } + + /** + * This method creates a new ActionListener for end key presses.i + * + * @return A new ActionListener for end keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardEndListener() + { + return new KeyboardEndHandler(); + } + + /** + * This method creates a new ActionListener for resize toggle key events. + * + * @return A new ActionListener for resize toggle keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardResizeToggleListener() + { + return new KeyboardResizeToggleHandler(); + } + + /** + * This method returns the orientation of the JSplitPane. + * + * @return The orientation of the JSplitPane. + */ + public int getOrientation() + { + return splitPane.getOrientation(); + } + + /** + * This method sets the orientation of the JSplitPane. + * + * @param orientation The new orientation of the JSplitPane. + */ + public void setOrientation(int orientation) + { + splitPane.setOrientation(orientation); + } + + /** + * This method returns true if the JSplitPane is using continuous layout. + * + * @return True if the JSplitPane is using continuous layout. + */ + public boolean isContinuousLayout() + { + return splitPane.isContinuousLayout(); + } + + /** + * This method sets the continuous layout property of the JSplitPane. + * + * @param b True if the JsplitPane is to use continuous layout. + */ + public void setContinuousLayout(boolean b) + { + splitPane.setContinuousLayout(b); + } + + /** + * This method returns the last location the divider was dragged to. + * + * @return The last location the divider was dragged to. + */ + public int getLastDragLocation() + { + return lastDragLocation; + } + + /** + * This method sets the last location the divider was dragged to. + * + * @param l The last location the divider was dragged to. + */ + public void setLastDragLocation(int l) + { + lastDragLocation = l; + } + + /** + * This method returns the BasicSplitPaneDivider that divides this + * JSplitPane. + * + * @return The divider for the JSplitPane. + */ + public BasicSplitPaneDivider getDivider() + { + return divider; + } + + /** + * This method creates a nonContinuousLayoutDivider for use with the + * JSplitPane in nonContinousLayout mode. The default divider is a gray + * Canvas. + * + * @return The default nonContinousLayoutDivider. + */ + protected Component createDefaultNonContinuousLayoutDivider() + { + if (nonContinuousLayoutDivider == null) + { + nonContinuousLayoutDivider = new Canvas(); + nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY); + } + return nonContinuousLayoutDivider; + } + + /** + * This method sets the component to use as the nonContinuousLayoutDivider. + * + * @param newDivider The component to use as the nonContinuousLayoutDivider. + */ + protected void setNonContinuousLayoutDivider(Component newDivider) + { + setNonContinuousLayoutDivider(newDivider, true); + } + + /** + * This method sets the component to use as the nonContinuousLayoutDivider. + * + * @param newDivider The component to use as the nonContinuousLayoutDivider. + * @param rememberSizes FIXME: document. + */ + protected void setNonContinuousLayoutDivider(Component newDivider, + boolean rememberSizes) + { + // FIXME: use rememberSizes for something + nonContinuousLayoutDivider = newDivider; + } + + /** + * This method returns the nonContinuousLayoutDivider. + * + * @return The nonContinuousLayoutDivider. + */ + public Component getNonContinuousLayoutDivider() + { + return nonContinuousLayoutDivider; + } + + /** + * This method returns the JSplitPane that this BasicSplitPaneUI draws. + * + * @return The JSplitPane. + */ + public JSplitPane getSplitPane() + { + return splitPane; + } + + /** + * This method creates the divider used normally with the JSplitPane. + * + * @return The default divider. + */ + public BasicSplitPaneDivider createDefaultDivider() + { + if (divider == null) + divider = new BasicSplitPaneDivider(this); + return divider; + } + + /** + * This method is called when JSplitPane's resetToPreferredSizes is called. + * It resets the sizes of all components in the JSplitPane. + * + * @param jc The JSplitPane to reset. + */ + public void resetToPreferredSizes(JSplitPane jc) + { + layoutManager.resetToPreferredSizes(); + } + + /** + * This method sets the location of the divider. + * + * @param jc The JSplitPane to set the divider location in. + * @param location The new location of the divider. + */ + public void setDividerLocation(JSplitPane jc, int location) + { + setLastDragLocation(getDividerLocation(splitPane)); + splitPane.setLastDividerLocation(getDividerLocation(splitPane)); + int[] tmpSizes = layoutManager.getSizes(); + tmpSizes[0] = location + - layoutManager.getInitialLocation(splitPane.getInsets()); + tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(), + splitPane.getInsets()) + - tmpSizes[0] - tmpSizes[1]; + + layoutManager.setSizes(tmpSizes); + splitPane.revalidate(); + splitPane.repaint(); + } + + /** + * This method returns the location of the divider. + * + * @param jc The JSplitPane to retrieve the location for. + * + * @return The location of the divider. + */ + public int getDividerLocation(JSplitPane jc) + { + return layoutManager.sizes[0] + + layoutManager.getInitialLocation(splitPane.getInsets()); + } + + /** + * This method returns the smallest value possible for the location of the + * divider. + * + * @param jc The JSplitPane. + * + * @return The minimum divider location. + */ + public int getMinimumDividerLocation(JSplitPane jc) + { + int value = layoutManager.getInitialLocation(jc.getInsets()); + if (layoutManager.components[0] != null) + value += layoutManager.minimumSizeOfComponent(0); + return value; + } + + /** + * This method returns the largest value possible for the location of the + * divider. + * + * @param jc The JSplitPane. + * + * @return The maximum divider location. + */ + public int getMaximumDividerLocation(JSplitPane jc) + { + int value = layoutManager.getInitialLocation(jc.getInsets()) + + layoutManager.getAvailableSize(jc.getSize(), jc.getInsets()) + - splitPane.getDividerSize(); + if (layoutManager.components[1] != null) + value -= layoutManager.minimumSizeOfComponent(1); + return value; + } + + /** + * This method is called after the children of the JSplitPane are painted. + * + * @param jc The JSplitPane. + * @param g The Graphics object to paint with. + */ + public void finishedPaintingChildren(JSplitPane jc, Graphics g) + { + if (! splitPane.isContinuousLayout() && nonContinuousLayoutDivider != null + && nonContinuousLayoutDivider.isVisible()) + javax.swing.SwingUtilities.paintComponent(g, nonContinuousLayoutDivider, + null, + nonContinuousLayoutDivider + .getBounds()); + } + + /** + * This method is called to paint the JSplitPane. + * + * @param g The Graphics object to paint with. + * @param jc The JSplitPane to paint. + */ + public void paint(Graphics g, JComponent jc) + { + } + + /** + * This method returns the preferred size of the JSplitPane. + * + * @param jc The JSplitPane. + * + * @return The preferred size of the JSplitPane. + */ + public Dimension getPreferredSize(JComponent jc) + { + return layoutManager.preferredLayoutSize((Container) jc); + } + + /** + * This method returns the minimum size of the JSplitPane. + * + * @param jc The JSplitPane. + * + * @return The minimum size of the JSplitPane. + */ + public Dimension getMinimumSize(JComponent jc) + { + return layoutManager.minimumLayoutSize((Container) jc); + } + + /** + * This method returns the maximum size of the JSplitPane. + * + * @param jc The JSplitPane. + * + * @return The maximum size of the JSplitPane. + */ + public Dimension getMaximumSize(JComponent jc) + { + return layoutManager.maximumLayoutSize((Container) jc); + } + + /** + * This method returns the border insets of the current border. + * + * @param jc The JSplitPane. + * + * @return The current border insets. + */ + public Insets getInsets(JComponent jc) + { + return splitPane.getBorder().getBorderInsets(splitPane); + } + + /** + * This method resets the current layout manager. The type of layout manager + * is dependent on the current orientation. + */ + protected void resetLayoutManager() + { + if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) + layoutManager = new BasicHorizontalLayoutManager(); + else + layoutManager = new BasicVerticalLayoutManager(); + getSplitPane().setLayout(layoutManager); + layoutManager.updateComponents(); + + // invalidating by itself does not invalidate the layout. + getSplitPane().revalidate(); + } + + /** + * This method is called when dragging starts. It resets lastDragLocation + * and dividerSize. + */ + protected void startDragging() + { + dividerSize = divider.getDividerSize(); + setLastDragLocation(-1); + + if (! splitPane.getLeftComponent().isLightweight() + || ! splitPane.getRightComponent().isLightweight()) + draggingHW = true; + + if (splitPane.isContinuousLayout()) + nonContinuousLayoutDivider.setVisible(false); + else + { + nonContinuousLayoutDivider.setVisible(true); + nonContinuousLayoutDivider.setBounds(divider.getBounds()); + } + splitPane.revalidate(); + splitPane.repaint(); + } + + /** + * This method is called whenever the divider is dragged. If the JSplitPane + * is in continuousLayout mode, the divider needs to be moved and the + * JSplitPane needs to be laid out. + * + * @param location The new location of the divider. + */ + protected void dragDividerTo(int location) + { + location = validLocation(location); + if (beginDragDividerLocation == -1) + beginDragDividerLocation = location; + + if (splitPane.isContinuousLayout()) + splitPane.setDividerLocation(location); + else + { + Point p = nonContinuousLayoutDivider.getLocation(); + if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) + p.x = location; + else + p.y = location; + nonContinuousLayoutDivider.setLocation(p); + } + setLastDragLocation(location); + splitPane.repaint(); + } + + /** + * This method is called when the dragging is finished. + * + * @param location The location where the drag finished. + */ + protected void finishDraggingTo(int location) + { + if (nonContinuousLayoutDivider != null) + nonContinuousLayoutDivider.setVisible(false); + draggingHW = false; + location = validLocation(location); + dragDividerTo(location); + splitPane.setDividerLocation(location); + splitPane.setLastDividerLocation(beginDragDividerLocation); + beginDragDividerLocation = -1; + splitPane.repaint(); + } + + /** + * This method returns the width of one of the sides of the divider's border. + * + * @return The width of one side of the divider's border. + * + * @deprecated 1.3 + */ + protected int getDividerBorderSize() + { + if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) + return divider.getBorder().getBorderInsets(divider).left; + else + return divider.getBorder().getBorderInsets(divider).top; + } + + /** + * This is a helper method that returns a valid location for the divider + * when dragging. + * + * @param location The location to check. + * + * @return A valid location. + */ + private int validLocation(int location) + { + if (location < getMinimumDividerLocation(splitPane)) + return getMinimumDividerLocation(splitPane); + if (location > getMaximumDividerLocation(splitPane)) + return getMaximumDividerLocation(splitPane); + return location; + } +} |