2 Copyright (C) 2004, 2006, Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java.awt.Component;
42 import java.awt.Graphics;
43 import java.beans.PropertyChangeEvent;
45 import javax.accessibility.Accessible;
46 import javax.accessibility.AccessibleContext;
47 import javax.accessibility.AccessibleRole;
48 import javax.accessibility.AccessibleState;
49 import javax.accessibility.AccessibleStateSet;
50 import javax.accessibility.AccessibleValue;
51 import javax.swing.plaf.SplitPaneUI;
54 * This class implements JSplitPane. It is used to divide two components. By
55 * dragging the SplitPane's divider, the user can resize the two components.
56 * Note that the divider cannot resize a component to smaller than it's
59 public class JSplitPane extends JComponent implements Accessible
63 * Provides the accessibility features for the <code>JSplitPane</code>
66 protected class AccessibleJSplitPane extends JComponent.AccessibleJComponent
67 implements AccessibleValue
69 private static final long serialVersionUID = -1788116871416305366L;
72 * Creates a new <code>AccessibleJSplitPane</code> instance.
74 protected AccessibleJSplitPane()
76 // Nothing to do here.
80 * Returns a set containing the current state of the {@link JSplitPane}
83 * @return The accessible state set.
85 public AccessibleStateSet getAccessibleStateSet()
87 AccessibleStateSet result = super.getAccessibleStateSet();
88 if (getOrientation() == HORIZONTAL_SPLIT)
90 result.add(AccessibleState.HORIZONTAL);
92 else if (getOrientation() == VERTICAL_SPLIT)
94 result.add(AccessibleState.VERTICAL);
100 * Returns the accessible role for the <code>JSplitPane</code> component.
102 * @return {@link AccessibleRole#SPLIT_PANE}.
104 public AccessibleRole getAccessibleRole()
106 return AccessibleRole.SPLIT_PANE;
110 * Returns an object that provides access to the current, minimum and
111 * maximum values for the {@link JSplitPane}. Since this class implements
112 * {@link AccessibleValue}, it returns itself.
114 * @return The accessible value.
116 public AccessibleValue getAccessibleValue()
122 * Returns the current divider location for the {@link JSplitPane}
123 * component, as an {@link Integer}.
125 * @return The current divider location.
127 public Number getCurrentAccessibleValue()
129 return new Integer(getDividerLocation());
133 * Sets the divider location for the {@link JSplitPane} component and sends
134 * a {@link PropertyChangeEvent} (with the property name
135 * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered
136 * listeners. If the supplied value is <code>null</code>, this method
137 * does nothing and returns <code>false</code>.
139 * @param value the new divider location (<code>null</code> permitted).
141 * @return <code>true</code> if the divider location value is updated, and
142 * <code>false</code> otherwise.
144 public boolean setCurrentAccessibleValue(Number value)
148 Number oldValue = getCurrentAccessibleValue();
149 setDividerLocation(value.intValue());
150 firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue,
151 new Integer(value.intValue()));
156 * Returns the minimum divider location for the {@link JSplitPane}
157 * component, as an {@link Integer}.
159 * @return The minimum divider location.
161 public Number getMinimumAccessibleValue()
163 return new Integer(getMinimumDividerLocation());
167 * Returns the maximum divider location for the {@link JSplitPane}
168 * component, as an {@link Integer}.
170 * @return The maximum divider location.
172 public Number getMaximumAccessibleValue()
174 return new Integer(getMaximumDividerLocation());
178 private static final long serialVersionUID = -5634142046175988380L;
180 /** The constraints string used to add components to the bottom. */
181 public static final String BOTTOM = "bottom";
183 /** The property fired when the continuousLayout property changes. */
184 public static final String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout";
186 /** The property fired when the divider property changes. */
187 public static final String DIVIDER = "divider";
189 /** The property fired when the divider location property changes. */
190 public static final String DIVIDER_LOCATION_PROPERTY = "dividerLocation";
192 /** The property fired when the divider size property changes. */
193 public static final String DIVIDER_SIZE_PROPERTY = "dividerSize";
196 * The value of the orientation when the components are split horizontally.
198 public static final int HORIZONTAL_SPLIT = 1;
200 /** The property fired when the last divider location property changes. */
201 public static final String LAST_DIVIDER_LOCATION_PROPERTY =
202 "lastDividerLocation";
204 /** The constraints string used to add components to the left. */
205 public static final String LEFT = "left";
207 /** The property fired when the one touch expandable property changes. */
208 public static final String ONE_TOUCH_EXPANDABLE_PROPERTY =
209 "oneTouchExpandable";
211 /** The property fired when the orientation property changes. */
212 public static final String ORIENTATION_PROPERTY = "orientation";
214 /** The property fired when the resize weight property changes. */
215 public static final String RESIZE_WEIGHT_PROPERTY = "resizeWeight";
217 /** The constraints string used to add components to the right. */
218 public static final String RIGHT = "right";
220 /** The constraints string used to add components to the top. */
221 public static final String TOP = "top";
223 /** The value of the orientation when the components are split vertically. */
224 public static final int VERTICAL_SPLIT = 0;
226 /** Whether the JSplitPane uses continuous layout. */
227 protected boolean continuousLayout;
229 /** Whether the JSplitPane uses one touch expandable buttons. */
230 protected boolean oneTouchExpandable = false;
232 // This is the master dividerSize variable and sets the
233 // BasicSplitPaneDivider one accordingly
235 /** The size of the divider. */
236 protected int dividerSize = 10;
238 /** The last location of the divider given by the UI. */
239 protected int lastDividerLocation;
241 /** The orientation of the JSplitPane. */
242 protected int orientation;
244 /** The component on the top or left. */
245 protected Component leftComponent;
247 /** The component on the right or bottom. */
248 protected Component rightComponent;
251 * The divider location.
253 private int dividerLocation;
255 /** Determines how extra space should be allocated. */
256 private transient double resizeWeight;
259 * Indicates if the dividerSize property has been set by a client program or
262 * @see #setUIProperty(String, Object)
263 * @see LookAndFeel#installProperty(JComponent, String, Object)
265 private boolean clientDividerSizeSet = false;
268 * Indicates if the oneTouchExpandable property has been set by a client
269 * program or by the UI.
271 * @see #setUIProperty(String, Object)
272 * @see LookAndFeel#installProperty(JComponent, String, Object)
274 private boolean clientOneTouchExpandableSet = false;
277 * Creates a new JSplitPane object with the given orientation, layout mode,
278 * and left and right components.
280 * @param newOrientation The orientation to use.
281 * @param newContinuousLayout The layout mode to use.
282 * @param newLeftComponent The left component.
283 * @param newRightComponent The right component.
285 * @throws IllegalArgumentException DOCUMENT ME!
287 public JSplitPane(int newOrientation, boolean newContinuousLayout,
288 Component newLeftComponent, Component newRightComponent)
290 if (newOrientation != HORIZONTAL_SPLIT && newOrientation != VERTICAL_SPLIT)
291 throw new IllegalArgumentException("orientation is invalid.");
292 orientation = newOrientation;
293 continuousLayout = newContinuousLayout;
294 setLeftComponent(newLeftComponent);
295 setRightComponent(newRightComponent);
296 dividerLocation = -1;
301 * Creates a new JSplitPane object using nonContinuousLayout mode, the given
302 * orientation and left and right components.
304 * @param newOrientation The orientation to use.
305 * @param newLeftComponent The left component.
306 * @param newRightComponent The right component.
308 public JSplitPane(int newOrientation, Component newLeftComponent,
309 Component newRightComponent)
311 this(newOrientation, false, newLeftComponent, newRightComponent);
315 * Creates a new JSplitPane object with the given layout mode and
318 * @param newOrientation The orientation to use.
319 * @param newContinuousLayout The layout mode to use.
321 public JSplitPane(int newOrientation, boolean newContinuousLayout)
323 this(newOrientation, newContinuousLayout, null, null);
327 * Creates a new JSplitPane object using a nonContinuousLayout mode and the
330 * @param newOrientation The orientation to use.
332 public JSplitPane(int newOrientation)
334 this(newOrientation, false, null, null);
338 * Creates a new JSplitPane object using HORIZONTAL_SPLIT and a
339 * nonContinuousLayout mode.
343 this(HORIZONTAL_SPLIT, false, new JButton("left button"),
344 new JButton("right button"));
348 * This method adds a component to the JSplitPane. The constraints object is
349 * a string that identifies where this component should go. If the
350 * constraints is not a known one, it will throw an
351 * IllegalArgumentException. The valid constraints are LEFT, TOP, RIGHT,
352 * BOTTOM and DIVIDER.
354 * @param comp The component to add.
355 * @param constraints The constraints string to use.
356 * @param index Where to place to component in the list of components.
358 * @throws IllegalArgumentException When the constraints is not a known
361 protected void addImpl(Component comp, Object constraints, int index)
363 if (constraints == null)
365 if (leftComponent == null)
367 else if (rightComponent == null)
371 if (constraints instanceof String)
373 String placement = (String) constraints;
375 if (placement.equals(BOTTOM) || placement.equals(RIGHT))
377 if (rightComponent != null)
378 remove(rightComponent);
379 rightComponent = comp;
381 else if (placement.equals(LEFT) || placement.equals(TOP))
383 if (leftComponent != null)
384 remove(leftComponent);
385 leftComponent = comp;
387 else if (placement.equals(DIVIDER))
391 IllegalArgumentException("Constraints is not a known identifier.");
393 // If no dividerLocation has been set, then we need to trigger an
395 if (getDividerLocation() != -1)
396 resetToPreferredSizes();
398 super.addImpl(comp, constraints, index);
403 * Returns the object that provides accessibility features for this
404 * <code>JSplitPane</code> component.
406 * @return The accessible context (an instance of
407 * {@link AccessibleJSplitPane}).
409 public AccessibleContext getAccessibleContext()
411 if (accessibleContext == null)
412 accessibleContext = new AccessibleJSplitPane();
414 return accessibleContext;
418 * This method returns the bottom component.
420 * @return The bottom component.
422 public Component getBottomComponent()
424 return rightComponent;
428 * This method returns the location of the divider. This method is passed to
431 * @return The location of the divider.
433 public int getDividerLocation()
435 return dividerLocation;
439 * This method returns the size of the divider.
441 * @return The size of the divider.
443 public int getDividerSize()
449 * This method returns the last divider location.
451 * @return The last divider location.
453 public int getLastDividerLocation()
455 return lastDividerLocation;
459 * This method returns the left component.
461 * @return The left component.
463 public Component getLeftComponent()
465 return leftComponent;
469 * This method returns the maximum divider location. This method is passed
472 * @return DOCUMENT ME!
474 public int getMaximumDividerLocation()
477 return ((SplitPaneUI) ui).getMaximumDividerLocation(this);
483 * This method returns the minimum divider location. This method is passed
486 * @return The minimum divider location.
488 public int getMinimumDividerLocation()
491 return ((SplitPaneUI) ui).getMinimumDividerLocation(this);
497 * This method returns the orientation that the JSplitPane is using.
499 * @return The current orientation.
501 public int getOrientation()
507 * This method returns the current resize weight.
509 * @return The current resize weight.
511 public double getResizeWeight()
517 * This method returns the right component.
519 * @return The right component.
521 public Component getRightComponent()
523 return rightComponent;
527 * This method returns the top component.
529 * @return The top component.
531 public Component getTopComponent()
533 return leftComponent;
537 * This method returns the UI.
541 public SplitPaneUI getUI()
543 return (SplitPaneUI) ui;
547 * This method returns true if the JSplitPane is using a continuousLayout.
549 * @return True if using a continuousLayout.
551 public boolean isContinuousLayout()
553 return continuousLayout;
557 * This method returns true if the divider has one touch expandable buttons.
559 * @return True if one touch expandable is used.
561 public boolean isOneTouchExpandable()
563 return oneTouchExpandable;
567 * This method returns true.
571 public boolean isValidateRoot()
577 * This method overrides JComponent's paintChildren so the UI can be
578 * messaged when the children have finished painting.
580 * @param g The Graphics object to paint with.
582 protected void paintChildren(Graphics g)
584 super.paintChildren(g);
586 ((SplitPaneUI) ui).finishedPaintingChildren(this, g);
590 * Returns an implementation-dependent string describing the attributes of
591 * this <code>JSplitPane</code>.
593 * @return A string describing the attributes of this <code>JSplitPane</code>
594 * (never <code>null</code>).
596 protected String paramString()
598 // FIXME: the next line can be restored once PR27208 is fixed
599 String superParamStr = ""; //super.paramString();
600 StringBuffer sb = new StringBuffer();
601 sb.append(",continuousLayout=").append(isContinuousLayout());
602 sb.append(",dividerSize=").append(getDividerSize());
603 sb.append(",lastDividerLocation=").append(getLastDividerLocation());
604 sb.append(",oneTouchExpandable=").append(isOneTouchExpandable());
605 sb.append(",orientation=");
606 if (orientation == HORIZONTAL_SPLIT)
607 sb.append("HORIZONTAL_SPLIT");
609 sb.append("VERTICAL_SPLIT");
610 return superParamStr + sb.toString();
614 * This method removes the given component from the JSplitPane.
616 * @param component The Component to remove.
618 public void remove(Component component)
620 if (component == leftComponent)
621 leftComponent = null;
622 else if (component == rightComponent)
623 rightComponent = null;
624 super.remove(component);
628 * This method removes the component at the given index.
630 * @param index The index of the component to remove.
632 public void remove(int index)
634 Component component = getComponent(index);
635 if (component == leftComponent)
636 leftComponent = null;
637 else if (component == rightComponent)
638 rightComponent = null;
643 * This method removes all components from the JSplitPane.
645 public void removeAll()
647 leftComponent = null;
648 rightComponent = null;
653 * This method resets all children of the JSplitPane to their preferred
656 public void resetToPreferredSizes()
659 ((SplitPaneUI) ui).resetToPreferredSizes(this);
663 * This method sets the bottom component.
665 * @param comp The Component to be placed at the bottom.
667 public void setBottomComponent(Component comp)
672 add(new JButton("right button"), BOTTOM);
676 * This method sets the layout mode for the JSplitPane.
678 * @param newContinuousLayout Whether the JSplitPane is in continuousLayout
681 public void setContinuousLayout(boolean newContinuousLayout)
683 if (newContinuousLayout != continuousLayout)
685 boolean oldValue = continuousLayout;
686 continuousLayout = newContinuousLayout;
687 firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldValue,
693 * This method sets the location of the divider. A value of 0 sets the
694 * divider to the farthest left. A value of 1 sets the divider to the
697 * @param proportionalLocation A double that describes the location of the
700 * @throws IllegalArgumentException if <code>proportionalLocation</code> is
701 * not in the range from 0.0 to 1.0 inclusive.
703 public void setDividerLocation(double proportionalLocation)
705 if (proportionalLocation > 1 || proportionalLocation < 0)
706 throw new IllegalArgumentException
707 ("proportion has to be between 0 and 1.");
709 int max = ((orientation == HORIZONTAL_SPLIT) ? getWidth() : getHeight())
711 setDividerLocation((int) (proportionalLocation * max));
715 * This method sets the location of the divider.
717 * @param location The location of the divider. The negative value forces to
718 * compute the new location from the preferred sizes of the split
721 public void setDividerLocation(int location)
723 int oldLocation = dividerLocation;
724 dividerLocation = location;
725 SplitPaneUI ui = getUI();
727 ui.setDividerLocation(this, location);
728 firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation,
733 * This method sets the size of the divider.
735 * @param newSize The size of the divider.
737 public void setDividerSize(int newSize)
739 clientDividerSizeSet = true;
740 if (newSize != dividerSize)
742 int oldSize = dividerSize;
743 dividerSize = newSize;
744 firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, dividerSize);
748 // This doesn't appear to do anything when set from user side.
749 // so it probably is only used from the UI side to change the
750 // lastDividerLocation var.
753 * This method sets the last location of the divider.
755 * @param newLastLocation The last location of the divider.
757 public void setLastDividerLocation(int newLastLocation)
759 if (newLastLocation != lastDividerLocation)
761 int oldValue = lastDividerLocation;
762 lastDividerLocation = newLastLocation;
763 firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldValue,
764 lastDividerLocation);
769 * This method sets the left component.
771 * @param comp The left component.
773 public void setLeftComponent(Component comp)
778 remove (leftComponent);
782 * This method sets whether the divider has one touch expandable buttons.
783 * The one touch expandable buttons can expand the size of either component
784 * to the maximum allowed size.
786 * @param newValue Whether the divider will have one touch expandable
789 public void setOneTouchExpandable(boolean newValue)
791 clientOneTouchExpandableSet = true;
792 if (newValue != oneTouchExpandable)
794 boolean oldValue = oneTouchExpandable;
795 oneTouchExpandable = newValue;
796 firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue,
802 * Sets the orientation for the <code>JSplitPane</code> and sends a
803 * {@link PropertyChangeEvent} (with the property name
804 * {@link #ORIENTATION_PROPERTY}) to all registered listeners.
806 * @param orientation the orientation (either {@link #HORIZONTAL_SPLIT}
807 * or {@link #VERTICAL_SPLIT}).
809 * @throws IllegalArgumentException if <code>orientation</code> is not one of
812 public void setOrientation(int orientation)
814 if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT)
815 throw new IllegalArgumentException
816 ("orientation must be one of VERTICAL_SPLIT, HORIZONTAL_SPLIT");
817 if (orientation != this.orientation)
819 int oldOrientation = this.orientation;
820 this.orientation = orientation;
821 firePropertyChange(ORIENTATION_PROPERTY, oldOrientation,
827 * This method determines how extra space will be distributed among the left
828 * and right components. A value of 0 will allocate all extra space to the
829 * right component. A value of 1 indicates that all extra space will go to
830 * the left component. A value in between 1 and 0 will split the space
833 * @param value The resize weight.
835 public void setResizeWeight(double value)
837 if (value < 0.0 || value > 1.0)
838 throw new IllegalArgumentException("Value outside permitted range.");
839 if (this.resizeWeight != value)
841 double old = resizeWeight;
842 resizeWeight = value;
843 firePropertyChange(RESIZE_WEIGHT_PROPERTY, old, value);
848 * This method sets the right component.
850 * @param comp The right component.
852 public void setRightComponent(Component comp)
857 remove (rightComponent);
861 * This method sets the top component.
863 * @param comp The top component.
865 public void setTopComponent(Component comp)
870 add(new JButton("left button"), TOP);
874 * This method sets the UI used by the JSplitPane.
876 * @param ui The UI to use.
878 public void setUI(SplitPaneUI ui)
884 * This method resets the UI to the one specified by the current Look and
887 public void updateUI()
889 setUI((SplitPaneUI) UIManager.getUI(this));
893 * This method returns a string identifier to determine which UI class it
896 * @return A string that identifies it's UI class.
898 public String getUIClassID()
900 return "SplitPaneUI";
905 * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
907 * @param propertyName the name of the property
908 * @param value the value of the property
910 * @throws IllegalArgumentException if the specified property cannot be set
912 * @throws ClassCastException if the property value does not match the
914 * @throws NullPointerException if <code>c</code> or
915 * <code>propertyValue</code> is <code>null</code>
917 void setUIProperty(String propertyName, Object value)
919 if (propertyName.equals("dividerSize"))
921 if (! clientDividerSizeSet)
923 setDividerSize(((Integer) value).intValue());
924 clientDividerSizeSet = false;
927 else if (propertyName.equals("oneTouchExpandable"))
929 if (! clientOneTouchExpandableSet)
931 setOneTouchExpandable(((Boolean) value).booleanValue());
932 clientOneTouchExpandableSet = false;
937 super.setUIProperty(propertyName, value);