|
What this is
Other links
The source code// $Id: Splitter.java,v 1.11 2004/09/21 19:03:28 mvw Exp $ // Copyright (c) 2003 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. /* * Splitter.java */ package org.argouml.swingext; import java.awt.*; import java.awt.event.*; import javax.swing.JComponent; import javax.swing.JSplitPane; import javax.swing.plaf.SplitPaneUI; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; /** * Acts as a seperator between components and will automatically * resize those components when the splitter is moved by dragging the * mouse across it. * * @author Bob Tarling * * TODO: Bring splitter to top when not dynamic resize * TODO: Add constructor and getter/setter for dynamic resize * * TODO: Implement the setLocation method, anything currently calling * setLocation should then call super.setLocation. */ public class Splitter extends JComponent { /** * The orientation for a horizontal splitter */ private static final Orientation HORIZONTAL_SPLIT = Horizontal.getInstance(); /** * The orientation for a vertical splitter */ private static final Orientation VERTICAL_SPLIT = Vertical.getInstance(); /** The side of the splitter of the component to be hidden on * a quick hide action. */ protected static final int NONE = -1; /** The side of the splitter to be hidden on a quick hide action: WEST */ protected static final int WEST = 0; /** The side of the splitter to be hidden on a quick hide action: EAST */ protected static final int EAST = 1; /** The side of the splitter to be hidden on a quick hide action: NORTH */ protected static final int NORTH = 0; /** The side of the splitter to be hidden on a quick hide action: SOUTH */ protected static final int SOUTH = 1; /** * The orientation of this splitter. Orientation does not * represent the shape of the splitter but rather the layout of * the objects being seperated by the splitter. In other words a * horizontal splitter seperates components layed out in a * horizontal row. */ private Orientation orientation; private int lastPosition; private int lastLength; /** * Is quick hide available and if so which component ahould it hide */ private int quickHide = NONE; /** * True if a component has been hidden by using the quick hide * process of the Splitter */ private boolean panelHidden = false; /** * True if components are resized dymically when the plitter is * dragged. If false then components are only resized when the * splitter is dropped by releasing the mouse. */ private boolean dynamicResize = true; /** * The 2 components which the splitter is designed to seperate */ private Component sideComponent[] = new Component[2]; /** * The standard width of a splitter */ private int splitterSize = 10; /** * The quick hide buttons */ private ArrowButton buttonNorth = null; /** * The quick hide buttons */ private ArrowButton buttonSouth = null; /** * Component which knows how to paint the split divider. **/ private BasicSplitPaneDivider divider = null; /** * Padding around the JSplitPane that is not included in the divider **/ private static final int DIVIDER_PADDING = 4; /** * Minimum size of the splitter in pixels. Must be at least this size * to properly display the toggle buttons. **/ private static final int MIN_SPLITTER_SIZE = 5; /** * The constructor * * @param o A Horizontal or Vertical Orientation object to * indicate whether this splitter is designed to seperate * components laid out horizontally or vertically. */ public Splitter(Orientation o) { super(); this.orientation = o; // Create a JSplitPane for the purpose of extracting the // divider UI and determining the splitter size. JSplitPane splitpane; if (o == HORIZONTAL_SPLIT) { splitpane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true); splitterSize = Math.max(splitpane.getPreferredSize().width - DIVIDER_PADDING, MIN_SPLITTER_SIZE); } else { splitpane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true); splitterSize = Math.max(splitpane.getPreferredSize().height - DIVIDER_PADDING, MIN_SPLITTER_SIZE); } setLayout(new SerialLayout(o.getPerpendicular())); setSize(splitterSize, splitterSize); setPreferredSize(this.getSize()); // Get the BasicSplitPaneDivider if the current look and feel // is based on the Basic look and feel. If not, the splitter // will still work, but the divider area will appear empty. SplitPaneUI ui = splitpane.getUI(); if (ui instanceof BasicSplitPaneUI) { divider = ((BasicSplitPaneUI) ui).createDefaultDivider(); divider.setSize(getSize()); } setCursor(o.getCursor()); MyMouseListener myMouseListener = new MyMouseListener(); addMouseListener(myMouseListener); addMouseMotionListener(myMouseListener); } /** * Register a component to be resized by this splitter. * * @param side the side of the splitter to place the component * being one of the constants NORTH, SOUTH, EAST or WEST * * @param comp the component to be resized */ public void registerComponent(int side, Component comp) { this.sideComponent[side] = comp; setVisible(this.sideComponent[WEST] != null && this.sideComponent[EAST] != null); } /** * Get a registered component. * * @param side the side of the splitter of the component to * return, being one of the constants NORTH, SOUTH, EAST or WEST * @return the registered component */ public Component getRegisteredComponent(int side) { return sideComponent[side]; } /** * Change the quick hide action. If quick hide is turned on then * an arrow button appears on the splitter to allow the user to * instantly reposition the splitter to hide one of the * components. * * @param side the side of the splitter of the component to be * hidden on a quick hide action. This being one of the constants * NORTH, SOUTH, EAST, WEST or NONE. */ public void setQuickHide(int side) { quickHide = side; // Only create the arrow buttons the first time they are required. if (side != NONE && buttonNorth == null) { buttonNorth = orientation.getStartArrowButton(); buttonSouth = orientation.getEndArrowButton(); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { toggleHide(); } }; buttonNorth.addActionListener(al); buttonSouth.addActionListener(al); add(buttonNorth); add(buttonSouth); } showButtons(); } /* * Show the correct button symbol. The arrow button should point * in the direction that the splitter will move on the button * press. This will be towards the component to hide or if already * hidden it should point away from the hidden component. */ private void showButtons() { if (buttonNorth != null) { if (panelHidden) { buttonNorth.setVisible(quickHide == SOUTH); buttonSouth.setVisible(quickHide == NORTH); } else { buttonNorth.setVisible(quickHide == NORTH); buttonSouth.setVisible(quickHide == SOUTH); } } } /** * Hide or restore the component currently selected as the quick * hide component. */ public void toggleHide() { if (quickHide == NONE) return; int position = 0; if (panelHidden) { position = lastPosition; if (quickHide == EAST) { position = orientation.getPosition(this) - lastLength; } } else if (quickHide == EAST) { position = orientation.getPosition(this) + orientation.getLength(sideComponent[EAST]); } lastLength = orientation.getLength(sideComponent[quickHide]); lastPosition = orientation.getPosition(this); setLocation(orientation.setPosition(getLocation(), position)); resizeComponents(position - lastPosition); panelHidden = !panelHidden; showButtons(); } /** * Resizes the divider delegate when this component is resized. * * @see java.awt.Component#setSize(java.awt.Dimension) */ public void setSize(Dimension d) { super.setSize(d); if (divider != null) { divider.setSize(d); } } /** * Resizes the divider delegate when this component is resized. * * @see java.awt.Component#setSize(int, int) */ public void setSize(int width, int height) { super.setSize(width, height); if (divider != null) { divider.setSize(width, height); } } /** * Delegates painting to the UI component responsible for the split pane * divider. * * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ public void paintComponent(Graphics g) { if (divider != null) { divider.paint(g); } } /* * Attempt to move the splitter by a given amount. It may not be * possible to move the splitter as far as requested because it * may result in one of the components having a negative size or * breaking it min/max size. * * @param movement the distance in pixels to move the splitter * from its current position. * * @return the actual number of pixels the splitter was moved. */ private int moveSplitter(int movement) { if (sideComponent[WEST] != null && sideComponent[EAST] != null) { int restrictedMovement = 0; if (movement >= 0) { restrictedMovement = restrictMovement(sideComponent[WEST], sideComponent[EAST], movement, -1); } else { restrictedMovement = restrictMovement(sideComponent[EAST], sideComponent[WEST], movement, 1); } setLocation(orientation.addToPosition(getLocation(), restrictedMovement)); return restrictedMovement; } return 0; } /** * Resize and reposition the components according to the movement * of the splitter * * @param movement the distance the splitter has moved. */ private void resizeComponents(int movement) { sideComponent[NORTH] .setSize(orientation.addLength(sideComponent[NORTH].getSize(), movement)); sideComponent[SOUTH] .setSize(orientation.subtractLength(sideComponent[SOUTH].getSize(), movement)); sideComponent[SOUTH]. setLocation(orientation .addToPosition(sideComponent[SOUTH].getLocation(), movement)); sideComponent[NORTH].validate(); sideComponent[SOUTH].validate(); } /** * calculates any restriction of movement based on the min/max values of the * registered components. * * @param growingComponent The component that is expanding as * the result of a splitter move. * @param shrinkingComponent The component that is shrinking * as the result of a splitter move. * @param movement The number of pixels of the attempted move * @param sign The direction of the move -ve or +ve (-1 or +1) */ private int restrictMovement(Component growingComponent, Component shrinkingComponent, int movement, int sign) { Dimension maxSize = growingComponent.getMaximumSize(); int maxLength = orientation.getLength(maxSize); int currentLength = orientation.getLength(growingComponent); if (currentLength + movement * sign > maxLength) { movement = (currentLength - maxLength) * sign; } Dimension minSize = shrinkingComponent.getMinimumSize(); int minLength = orientation.getLength(minSize); currentLength = orientation.getLength(shrinkingComponent); if (currentLength + movement * sign < minLength) { movement = (minLength - currentLength) * sign; } return movement; } /** * The mouse listener to detect mouse interaction with this splitter */ private class MyMouseListener implements MouseMotionListener, MouseListener { /** * When the mouse is pressed the splitter position is recorded * so that the the difference in position can be calculated * when the mouse is released. */ private int positionOfSplitterWhenPressed; /** * A value is recorded here when the mouse is pressed on the * splitter. This allows the position of the mouse on the * splitter to remain consistent when the splitter is moved. */ private int mousePositionOnSplitterWhenPressed; /** * On a mouse release make sure that components are repositioned. */ public void mouseReleased(MouseEvent me) { if (!dynamicResize) { moveSplitter(orientation.getPosition(me) - mousePositionOnSplitterWhenPressed); resizeComponents(orientation.getPosition(getLocation()) - positionOfSplitterWhenPressed); } mousePositionOnSplitterWhenPressed = 0; positionOfSplitterWhenPressed = 0; } /** * On a mouse drag attempt to reposition splitter. */ public void mouseDragged(MouseEvent me) { int mouseMovement = orientation.getPosition(me) - mousePositionOnSplitterWhenPressed; int restrictedMovement = moveSplitter(mouseMovement); if (restrictedMovement == 0) return; if (dynamicResize) { resizeComponents(restrictedMovement); } if (panelHidden) { panelHidden = false; showButtons(); } } /** * On a mouse press record the position of the splitter and * the position of the mouse on the splitter. * */ public void mousePressed(MouseEvent me) { mousePositionOnSplitterWhenPressed = orientation.getPosition(me); positionOfSplitterWhenPressed = orientation.getPosition(getLocation()); } /** * On a double click either hide or show the component * selected for quick hide. * */ public void mouseClicked(MouseEvent me) { if (me.getClickCount() == 2 && sideComponent[WEST] != null && sideComponent[EAST] != null) { toggleHide(); } } /** * Empty method to satisy interface only, there is * no action when mouse enters splitter area */ public void mouseEntered(MouseEvent me) { } /** * Empty method to satisy interface only, there is * no action when mouse leaves splitter area */ public void mouseExited(MouseEvent me) { } /** * Empty method to satisy interface only, there is * no action when mouse moves through splitter area */ public void mouseMoved(MouseEvent me) { } } } |
... this post is sponsored by my books ... | |
![]() #1 New Release! |
![]() FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.