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