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 gnu.java.lang.CPStringBuilder;
042    
043    import java.awt.Component;
044    import java.awt.Graphics;
045    import java.beans.PropertyChangeEvent;
046    
047    import javax.accessibility.Accessible;
048    import javax.accessibility.AccessibleContext;
049    import javax.accessibility.AccessibleRole;
050    import javax.accessibility.AccessibleState;
051    import javax.accessibility.AccessibleStateSet;
052    import javax.accessibility.AccessibleValue;
053    import 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     */
061    public 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    }