001/* JSplitPane.java -- 
002   Copyright (C) 2004, 2006,  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing;
040
041import gnu.java.lang.CPStringBuilder;
042
043import java.awt.Component;
044import java.awt.Graphics;
045import java.beans.PropertyChangeEvent;
046
047import javax.accessibility.Accessible;
048import javax.accessibility.AccessibleContext;
049import javax.accessibility.AccessibleRole;
050import javax.accessibility.AccessibleState;
051import javax.accessibility.AccessibleStateSet;
052import javax.accessibility.AccessibleValue;
053import javax.swing.plaf.SplitPaneUI;
054
055/**
056 * This class implements JSplitPane. It is used to divide two components. By
057 * dragging the SplitPane's divider, the user can resize the two components.
058 * Note that the divider cannot resize a component to smaller than it's
059 * minimum size.
060 */
061public class JSplitPane extends JComponent implements Accessible
062{
063
064  /**
065   * Provides the accessibility features for the <code>JSplitPane</code>
066   * component.
067   */
068  protected class AccessibleJSplitPane extends JComponent.AccessibleJComponent
069    implements AccessibleValue
070  {
071  private static final long serialVersionUID = -1788116871416305366L;
072  
073    /**
074     * Creates a new <code>AccessibleJSplitPane</code> instance.
075     */
076    protected AccessibleJSplitPane()
077    {
078      // Nothing to do here.
079    }
080
081    /**
082     * Returns a set containing the current state of the {@link JSplitPane} 
083     * component.
084     *
085     * @return The accessible state set.
086     */
087    public AccessibleStateSet getAccessibleStateSet()
088    {
089      AccessibleStateSet result = super.getAccessibleStateSet();
090      if (getOrientation() == HORIZONTAL_SPLIT)
091        {
092          result.add(AccessibleState.HORIZONTAL);
093        }
094      else if (getOrientation() == VERTICAL_SPLIT)
095        {
096          result.add(AccessibleState.VERTICAL);
097        }
098      return result;
099    }
100
101    /**
102     * Returns the accessible role for the <code>JSplitPane</code> component.
103     *
104     * @return {@link AccessibleRole#SPLIT_PANE}.
105     */
106    public AccessibleRole getAccessibleRole()
107    {
108      return AccessibleRole.SPLIT_PANE;
109    }
110
111    /**
112     * Returns an object that provides access to the current, minimum and 
113     * maximum values for the {@link JSplitPane}.  Since this class implements 
114     * {@link AccessibleValue}, it returns itself.
115     *
116     * @return The accessible value.
117     */
118    public AccessibleValue getAccessibleValue()
119    {
120      return this;
121    }
122
123    /**
124     * Returns the current divider location for the {@link JSplitPane} 
125     * component, as an {@link Integer}.
126     *
127     * @return The current divider location.
128     */
129    public Number getCurrentAccessibleValue()
130    {
131      return new Integer(getDividerLocation());
132    }
133
134    /**
135     * Sets the divider location for the {@link JSplitPane} component and sends 
136     * a {@link PropertyChangeEvent} (with the property name 
137     * {@link AccessibleContext#ACCESSIBLE_VALUE_PROPERTY}) to all registered
138     * listeners.  If the supplied value is <code>null</code>, this method 
139     * does nothing and returns <code>false</code>.
140     *
141     * @param value  the new divider location (<code>null</code> permitted).
142     *
143     * @return <code>true</code> if the divider location value is updated, and 
144     *     <code>false</code> otherwise.
145     */
146    public boolean setCurrentAccessibleValue(Number value)
147    {
148      if (value == null)
149        return false;
150      Number oldValue = getCurrentAccessibleValue();
151      setDividerLocation(value.intValue());
152      firePropertyChange(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY, oldValue, 
153                         new Integer(value.intValue()));
154      return true;
155    }
156
157    /**
158     * Returns the minimum divider location for the {@link JSplitPane} 
159     * component, as an {@link Integer}.
160     *
161     * @return The minimum divider location.
162     */
163    public Number getMinimumAccessibleValue()
164    {
165      return new Integer(getMinimumDividerLocation());
166    }
167
168    /**
169     * Returns the maximum divider location for the {@link JSplitPane} 
170     * component, as an {@link Integer}.
171     *
172     * @return The maximum divider location.
173     */
174    public Number getMaximumAccessibleValue()
175    {
176      return new Integer(getMaximumDividerLocation());
177    }
178  }
179
180  private static final long serialVersionUID = -5634142046175988380L;
181  
182  /** The constraints string used to add components to the bottom. */
183  public static final String BOTTOM = "bottom";
184
185  /** The property fired when the continuousLayout property changes. */
186  public static final String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout";
187
188  /** The property fired when the divider property changes. */
189  public static final String DIVIDER = "divider";
190
191  /** The property fired when the divider location property changes. */
192  public static final String DIVIDER_LOCATION_PROPERTY = "dividerLocation";
193
194  /** The property fired when the divider size property changes. */
195  public static final String DIVIDER_SIZE_PROPERTY = "dividerSize";
196
197  /**
198   * The value of the orientation when the components are split horizontally.
199   */
200  public static final int HORIZONTAL_SPLIT = 1;
201
202  /** The property fired when the last divider location property changes. */
203  public static final String LAST_DIVIDER_LOCATION_PROPERTY = 
204    "lastDividerLocation";
205
206  /** The constraints string used to add components to the left. */
207  public static final String LEFT = "left";
208
209  /** The property fired when the one touch expandable property changes. */
210  public static final String ONE_TOUCH_EXPANDABLE_PROPERTY = 
211    "oneTouchExpandable";
212
213  /** The property fired when the orientation property changes. */
214  public static final String ORIENTATION_PROPERTY = "orientation";
215
216  /** The property fired when the resize weight property changes. */
217  public static final String RESIZE_WEIGHT_PROPERTY = "resizeWeight";
218
219  /** The constraints string used to add components to the right. */
220  public static final String RIGHT = "right";
221
222  /** The constraints string used to add components to the top. */
223  public static final String TOP = "top";
224
225  /** The value of the orientation when the components are split vertically. */
226  public static final int VERTICAL_SPLIT = 0;
227
228  /** Whether the JSplitPane uses continuous layout. */
229  protected boolean continuousLayout;
230
231  /** Whether the JSplitPane uses one touch expandable buttons. */
232  protected boolean oneTouchExpandable = false;
233
234  // This is the master dividerSize variable and sets the 
235  // BasicSplitPaneDivider one accordingly
236
237  /** The size of the divider. */
238  protected int dividerSize = 10;
239
240  /** The last location of the divider given by the UI. */
241  protected int lastDividerLocation;
242
243  /** The orientation of the JSplitPane. */
244  protected int orientation;
245
246  /** The component on the top or left. */
247  protected Component leftComponent;
248
249  /** The component on the right or bottom. */
250  protected Component rightComponent;
251
252  /**
253   * The divider location.
254   */
255  private int dividerLocation;
256
257  /** Determines how extra space should be allocated. */
258  private transient double resizeWeight;
259
260  /**
261   * Indicates if the dividerSize property has been set by a client program or
262   * by the UI.
263   *
264   * @see #setUIProperty(String, Object)
265   * @see LookAndFeel#installProperty(JComponent, String, Object)
266   */
267  private boolean clientDividerSizeSet = false;
268
269  /**
270   * Indicates if the oneTouchExpandable property has been set by a client
271   * program or by the UI.
272   *
273   * @see #setUIProperty(String, Object)
274   * @see LookAndFeel#installProperty(JComponent, String, Object)
275   */
276  private boolean clientOneTouchExpandableSet = false;
277
278  /**
279   * Creates a new JSplitPane object with the given orientation, layout mode,
280   * and left and right components.
281   *
282   * @param newOrientation The orientation to use.
283   * @param newContinuousLayout The layout mode to use.
284   * @param newLeftComponent The left component.
285   * @param newRightComponent The right component.
286   *
287   * @throws IllegalArgumentException DOCUMENT ME!
288   */
289  public JSplitPane(int newOrientation, boolean newContinuousLayout,
290                    Component newLeftComponent, Component newRightComponent)
291  {
292    if (newOrientation != HORIZONTAL_SPLIT && newOrientation != VERTICAL_SPLIT)
293      throw new IllegalArgumentException("orientation is invalid.");
294    orientation = newOrientation;
295    continuousLayout = newContinuousLayout;
296    setLeftComponent(newLeftComponent);
297    setRightComponent(newRightComponent);
298    dividerLocation = -1;
299    updateUI();
300  }
301
302  /**
303   * Creates a new JSplitPane object using nonContinuousLayout mode, the given
304   * orientation and left and right components.
305   *
306   * @param newOrientation The orientation to use.
307   * @param newLeftComponent The left component.
308   * @param newRightComponent The right component.
309   */
310  public JSplitPane(int newOrientation, Component newLeftComponent,
311                    Component newRightComponent)
312  {
313    this(newOrientation, false, newLeftComponent, newRightComponent);
314  }
315
316  /**
317   * Creates a new JSplitPane object with the given layout mode and
318   * orientation.
319   *
320   * @param newOrientation The orientation to use.
321   * @param newContinuousLayout The layout mode to use.
322   */
323  public JSplitPane(int newOrientation, boolean newContinuousLayout)
324  {
325    this(newOrientation, newContinuousLayout, null, null);
326  }
327
328  /**
329   * Creates a new JSplitPane object using a nonContinuousLayout mode and the
330   * given orientation.
331   *
332   * @param newOrientation The orientation to use.
333   */
334  public JSplitPane(int newOrientation)
335  {
336    this(newOrientation, false, null, null);
337  }
338
339  /**
340   * Creates a new JSplitPane object using HORIZONTAL_SPLIT and a
341   * nonContinuousLayout mode.
342   */
343  public JSplitPane()
344  {
345    this(HORIZONTAL_SPLIT, false, new JButton("left button"),
346         new JButton("right button"));
347  }
348
349  /**
350   * This method adds a component to the JSplitPane. The constraints object is
351   * a string that identifies where this component should go. If the
352   * constraints is not a known one, it will throw an
353   * IllegalArgumentException. The valid constraints are LEFT, TOP, RIGHT,
354   * BOTTOM and DIVIDER.
355   *
356   * @param comp The component to add.
357   * @param constraints The constraints string to use.
358   * @param index Where to place to component in the list of components.
359   *
360   * @throws IllegalArgumentException When the constraints is not a known 
361   * identifier.
362   */
363  protected void addImpl(Component comp, Object constraints, int index)
364  {
365    if (constraints == null)
366      {
367        if (leftComponent == null)
368          constraints = LEFT;
369        else if (rightComponent == null)
370          constraints = RIGHT;
371      }
372
373    if (constraints instanceof String)
374      {
375        String placement = (String) constraints;
376
377        if (placement.equals(BOTTOM) || placement.equals(RIGHT))
378          {
379            if (rightComponent != null)
380              remove(rightComponent);
381            rightComponent = comp;
382          }
383        else if (placement.equals(LEFT) || placement.equals(TOP))
384          {
385            if (leftComponent != null)
386              remove(leftComponent);
387            leftComponent = comp;
388          }
389        else if (placement.equals(DIVIDER))
390          constraints = null;
391        else
392          throw new 
393            IllegalArgumentException("Constraints is not a known identifier.");
394
395        // If no dividerLocation has been set, then we need to trigger an
396        // initial layout.
397        if (getDividerLocation() != -1)
398          resetToPreferredSizes();
399
400        super.addImpl(comp, constraints, index);
401      }
402  }
403
404  /**
405   * Returns the object that provides accessibility features for this
406   * <code>JSplitPane</code> component.
407   *
408   * @return The accessible context (an instance of 
409   *     {@link AccessibleJSplitPane}).
410   */
411  public AccessibleContext getAccessibleContext()
412  {
413    if (accessibleContext == null)
414      accessibleContext = new AccessibleJSplitPane();
415    
416    return accessibleContext;
417  }
418
419  /**
420   * This method returns the bottom component.
421   *
422   * @return The bottom component.
423   */
424  public Component getBottomComponent()
425  {
426    return rightComponent;
427  }
428
429  /**
430   * This method returns the location of the divider. This method is passed to
431   * the UI.
432   *
433   * @return The location of the divider.
434   */
435  public int getDividerLocation()
436  {
437    return dividerLocation;
438  }
439
440  /**
441   * This method returns the size of the divider.
442   *
443   * @return The size of the divider.
444   */
445  public int getDividerSize()
446  {
447    return dividerSize;
448  }
449
450  /**
451   * This method returns the last divider location.
452   *
453   * @return The last divider location.
454   */
455  public int getLastDividerLocation()
456  {
457    return lastDividerLocation;
458  }
459
460  /**
461   * This method returns the left component.
462   *
463   * @return The left component.
464   */
465  public Component getLeftComponent()
466  {
467    return leftComponent;
468  }
469
470  /**
471   * This method returns the maximum divider location. This method is passed
472   * to  the UI.
473   *
474   * @return DOCUMENT ME!
475   */
476  public int getMaximumDividerLocation()
477  {
478    if (ui != null)
479      return ((SplitPaneUI) ui).getMaximumDividerLocation(this);
480    else
481      return -1;
482  }
483
484  /**
485   * This method returns the minimum divider location. This method is passed
486   * to the UI.
487   *
488   * @return The minimum divider location.
489   */
490  public int getMinimumDividerLocation()
491  {
492    if (ui != null)
493      return ((SplitPaneUI) ui).getMinimumDividerLocation(this);
494    else
495      return -1;
496  }
497
498  /**
499   * This method returns the orientation that the JSplitPane is using.
500   *
501   * @return The current orientation.
502   */
503  public int getOrientation()
504  {
505    return orientation;
506  }
507
508  /**
509   * This method returns the current resize weight.
510   *
511   * @return The current resize weight.
512   */
513  public double getResizeWeight()
514  {
515    return resizeWeight;
516  }
517
518  /**
519   * This method returns the right component.
520   *
521   * @return The right component.
522   */
523  public Component getRightComponent()
524  {
525    return rightComponent;
526  }
527
528  /**
529   * This method returns the top component.
530   *
531   * @return The top component.
532   */
533  public Component getTopComponent()
534  {
535    return leftComponent;
536  }
537
538  /**
539   * This method returns the UI.
540   *
541   * @return The UI.
542   */
543  public SplitPaneUI getUI()
544  {
545    return (SplitPaneUI) ui;
546  }
547
548  /**
549   * This method returns true if the JSplitPane is using a continuousLayout.
550   *
551   * @return True if using a continuousLayout.
552   */
553  public boolean isContinuousLayout()
554  {
555    return continuousLayout;
556  }
557
558  /**
559   * This method returns true if the divider has one touch expandable buttons.
560   *
561   * @return True if one touch expandable is used.
562   */
563  public boolean isOneTouchExpandable()
564  {
565    return oneTouchExpandable;
566  }
567
568  /**
569   * This method returns true.
570   *
571   * @return true.
572   */
573  public boolean isValidateRoot()
574  {
575    return true;
576  }
577
578  /**
579   * This method overrides JComponent's paintChildren so the UI can be
580   * messaged when the children have finished painting.
581   *
582   * @param g The Graphics object to paint with.
583   */
584  protected void paintChildren(Graphics g)
585  {
586    super.paintChildren(g);
587    if (ui != null)
588      ((SplitPaneUI) ui).finishedPaintingChildren(this, g);
589  }
590
591  /**
592   * Returns an implementation-dependent string describing the attributes of
593   * this <code>JSplitPane</code>.
594   *
595   * @return A string describing the attributes of this <code>JSplitPane</code>
596   *         (never <code>null</code>).
597   */
598  protected String paramString()
599  {
600    // FIXME: the next line can be restored once PR27208 is fixed
601    String superParamStr = ""; //super.paramString();
602    CPStringBuilder sb = new CPStringBuilder();
603    sb.append(",continuousLayout=").append(isContinuousLayout());
604    sb.append(",dividerSize=").append(getDividerSize());
605    sb.append(",lastDividerLocation=").append(getLastDividerLocation());
606    sb.append(",oneTouchExpandable=").append(isOneTouchExpandable());
607    sb.append(",orientation=");
608    if (orientation == HORIZONTAL_SPLIT)
609      sb.append("HORIZONTAL_SPLIT");
610    else
611      sb.append("VERTICAL_SPLIT");
612    return superParamStr + sb.toString();
613  }
614
615  /**
616   * This method removes the given component from the JSplitPane.
617   *
618   * @param component The Component to remove.
619   */
620  public void remove(Component component)
621  {
622    if (component == leftComponent)
623      leftComponent = null;
624    else if (component == rightComponent)
625      rightComponent = null;
626    super.remove(component);
627  }
628
629  /**
630   * This method removes the component at the given index.
631   *
632   * @param index The index of the component to remove.
633   */
634  public void remove(int index)
635  {
636    Component component = getComponent(index);
637    if (component == leftComponent)
638      leftComponent = null;
639    else if (component == rightComponent)
640      rightComponent = null;
641    super.remove(index);
642  }
643
644  /**
645   * This method removes all components from the JSplitPane.
646   */
647  public void removeAll()
648  {
649    leftComponent = null;
650    rightComponent = null;
651    super.removeAll();
652  }
653
654  /**
655   * This method resets all children of the JSplitPane to their preferred
656   * sizes.
657   */
658  public void resetToPreferredSizes()
659  {
660    if (ui != null)
661      ((SplitPaneUI) ui).resetToPreferredSizes(this);
662  }
663
664  /**
665   * This method sets the bottom component.
666   *
667   * @param comp The Component to be placed at the bottom.
668   */
669  public void setBottomComponent(Component comp)
670  {
671    if (comp != null)
672      add(comp, BOTTOM);
673    else
674      add(new JButton("right button"), BOTTOM);
675  }
676
677  /**
678   * This method sets the layout mode for the JSplitPane.
679   *
680   * @param newContinuousLayout Whether the JSplitPane is in continuousLayout
681   *        mode.
682   */
683  public void setContinuousLayout(boolean newContinuousLayout)
684  {
685    if (newContinuousLayout != continuousLayout)
686      {
687        boolean oldValue = continuousLayout;
688        continuousLayout = newContinuousLayout;
689        firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldValue,
690                           continuousLayout);
691      }
692  }
693
694  /**
695   * This method sets the location of the divider. A value of 0 sets the
696   * divider to the farthest left. A value of 1 sets the divider to the
697   * farthest right.
698   *
699   * @param proportionalLocation A double that describes the location of the
700   *        divider.
701   *
702   * @throws IllegalArgumentException if <code>proportionalLocation</code> is
703   *     not in the range from 0.0 to 1.0 inclusive.
704   */
705  public void setDividerLocation(double proportionalLocation)
706  {
707    if (proportionalLocation > 1 || proportionalLocation < 0)
708      throw new IllegalArgumentException
709        ("proportion has to be between 0 and 1.");
710
711    int max = ((orientation == HORIZONTAL_SPLIT) ? getWidth() : getHeight())
712              - getDividerSize();
713    setDividerLocation((int) (proportionalLocation * max));
714  }
715
716  /**
717   * This method sets the location of the divider.
718   * 
719   * @param location The location of the divider. The negative value forces to
720   *          compute the new location from the preferred sizes of the split
721   *          pane components.
722   */
723  public void setDividerLocation(int location)
724  {
725    int oldLocation = dividerLocation;
726    dividerLocation = location;
727    SplitPaneUI ui = getUI();
728    if (ui != null)
729      ui.setDividerLocation(this, location);
730    firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation, 
731                       location);
732  }
733
734  /**
735   * This method sets the size of the divider.
736   *
737   * @param newSize The size of the divider.
738   */
739  public void setDividerSize(int newSize)
740  {
741    clientDividerSizeSet = true;
742    if (newSize != dividerSize)
743      {
744        int oldSize = dividerSize;
745        dividerSize = newSize;
746        firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, dividerSize);
747      }
748  }
749
750  // This doesn't appear to do anything when set from user side.
751  // so it probably is only used from the UI side to change the
752  // lastDividerLocation var.
753
754  /**
755   * This method sets the last location of the divider.
756   *
757   * @param newLastLocation The last location of the divider.
758   */
759  public void setLastDividerLocation(int newLastLocation)
760  {
761    if (newLastLocation != lastDividerLocation)
762      {
763        int oldValue = lastDividerLocation;
764        lastDividerLocation = newLastLocation;
765        firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldValue,
766                           lastDividerLocation);
767      }
768  }
769
770  /**
771   * This method sets the left component.
772   *
773   * @param comp The left component.
774   */
775  public void setLeftComponent(Component comp)
776  {    
777    if (comp != null)
778      add(comp, LEFT);
779    else
780      remove (leftComponent);
781  }
782
783  /**
784   * This method sets whether the divider has one touch expandable buttons.
785   * The one touch expandable buttons can expand the size of either component
786   * to the maximum allowed size.
787   *
788   * @param newValue Whether the divider will have one touch expandable
789   *        buttons.
790   */
791  public void setOneTouchExpandable(boolean newValue)
792  {
793    clientOneTouchExpandableSet = true;
794    if (newValue != oneTouchExpandable)
795      {
796        boolean oldValue = oneTouchExpandable;
797        oneTouchExpandable = newValue;
798        firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue,
799                           oneTouchExpandable);
800      }
801  }
802
803  /**
804   * Sets the orientation for the <code>JSplitPane</code> and sends a 
805   * {@link PropertyChangeEvent} (with the property name 
806   * {@link #ORIENTATION_PROPERTY}) to all registered listeners.
807   *
808   * @param orientation  the orientation (either {@link #HORIZONTAL_SPLIT}
809   * or {@link #VERTICAL_SPLIT}).
810   *
811   * @throws IllegalArgumentException if <code>orientation</code> is not one of
812   *     the listed values.
813   */
814  public void setOrientation(int orientation)
815  {
816    if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT)
817      throw new IllegalArgumentException
818        ("orientation must be one of VERTICAL_SPLIT, HORIZONTAL_SPLIT");
819    if (orientation != this.orientation)
820      {
821        int oldOrientation = this.orientation;
822        this.orientation = orientation;
823        firePropertyChange(ORIENTATION_PROPERTY, oldOrientation,
824                           this.orientation);
825      }
826  }
827
828  /**
829   * This method determines how extra space will be distributed among the left
830   * and right components. A value of 0 will allocate all extra space to the
831   * right component. A value of 1 indicates that all extra space will go to
832   * the left component. A value in between 1 and 0 will split the space
833   * accordingly.
834   *
835   * @param value The resize weight.
836   */
837  public void setResizeWeight(double value)
838  {
839    if (value < 0.0 || value > 1.0)
840      throw new IllegalArgumentException("Value outside permitted range.");
841    if (this.resizeWeight != value)
842      { 
843        double old = resizeWeight;
844        resizeWeight = value;
845        firePropertyChange(RESIZE_WEIGHT_PROPERTY, old, value);
846      }
847  }
848
849  /**
850   * This method sets the right component.
851   *
852   * @param comp The right component.
853   */
854  public void setRightComponent(Component comp)
855  {
856    if (comp != null)
857      add(comp, RIGHT);
858    else
859      remove (rightComponent);
860  }
861
862  /**
863   * This method sets the top component.
864   *
865   * @param comp The top component.
866   */
867  public void setTopComponent(Component comp)
868  {
869    if (comp != null)
870      add(comp, TOP);
871    else
872      add(new JButton("left button"), TOP);
873  }
874
875  /**
876   * This method sets the UI used by the JSplitPane.
877   *
878   * @param ui The UI to use.
879   */
880  public void setUI(SplitPaneUI ui)
881  {
882    super.setUI(ui);
883  }
884
885  /**
886   * This method resets the UI to the one specified by the current Look and
887   * Feel.
888   */
889  public void updateUI()
890  {
891    setUI((SplitPaneUI) UIManager.getUI(this));
892  }
893
894  /**
895   * This method returns a string identifier to determine which UI class it
896   * needs.
897   *
898   * @return A string that identifies it's UI class.
899   */
900  public String getUIClassID()
901  {
902    return "SplitPaneUI";
903  }
904
905  /**
906   * Helper method for
907   * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
908   * 
909   * @param propertyName the name of the property
910   * @param value the value of the property
911   *
912   * @throws IllegalArgumentException if the specified property cannot be set
913   *         by this method
914   * @throws ClassCastException if the property value does not match the
915   *         property type
916   * @throws NullPointerException if <code>c</code> or
917   *         <code>propertyValue</code> is <code>null</code>
918   */
919  void setUIProperty(String propertyName, Object value)
920  {
921    if (propertyName.equals("dividerSize"))
922      {
923        if (! clientDividerSizeSet)
924          {
925            setDividerSize(((Integer) value).intValue());
926            clientDividerSizeSet = false;
927          }
928      }
929    else if (propertyName.equals("oneTouchExpandable"))
930      {
931        if (! clientOneTouchExpandableSet)
932          {
933            setOneTouchExpandable(((Boolean) value).booleanValue());
934            clientOneTouchExpandableSet = false;
935          }
936      }
937    else
938      {
939        super.setUIProperty(propertyName, value);
940      }
941  }
942}