Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.control;
027
028import java.util.ArrayList;
029import java.util.Collections;
030import java.util.List;
031import javafx.beans.DefaultProperty;
032import javafx.beans.property.BooleanProperty;
033import javafx.beans.property.DoubleProperty;
034import javafx.beans.property.ObjectProperty;
035import javafx.beans.property.ObjectPropertyBase;
036import javafx.beans.property.SimpleDoubleProperty;
037import javafx.beans.property.SimpleObjectProperty;
038import javafx.css.CssMetaData;
039import javafx.css.PseudoClass;
040import javafx.css.StyleableBooleanProperty;
041import javafx.css.StyleableObjectProperty;
042import javafx.css.StyleableProperty;
043import javafx.event.Event;
044import javafx.event.EventHandler;
045import javafx.geometry.BoundingBox;
046import javafx.geometry.Bounds;
047import javafx.scene.Node;
048import com.sun.javafx.css.converters.BooleanConverter;
049import com.sun.javafx.css.converters.EnumConverter;
050import com.sun.javafx.scene.control.skin.ScrollPaneSkin;
051import javafx.css.Styleable;
052
053/**
054 * A Control that provides a scrolled, clipped viewport of its contents. It
055 * allows the user to scroll the content around either directly (panning) or
056 * by using scroll bars. The ScrollPane allows specification of the scroll
057 * bar policy, which determines when scroll bars are displayed: always, never,
058 * or only when they are needed. The scroll bar policy can be specified
059 * independently for the horizontal and vertical scroll bars.
060 * <p>
061 * The ScrollPane allows the application to set the current, minimum, and
062 * maximum values for positioning the contents in the horizontal and
063 * vertical directions. These values are mapped proportionally onto the
064 * {@link javafx.scene.Node#layoutBoundsProperty layoutBounds} of the contained node.
065 * <p>
066 * ScrollPane layout calculations are based on the layoutBounds rather than
067 * the boundsInParent (visual bounds) of the scroll node.
068 * If an application wants the scrolling to be based on the visual bounds
069 * of the node (for scaled content etc.), they need to wrap the scroll
070 * node in a Group.
071 * <p>
072 * ScrollPane sets focusTraversable to false.
073 * </p>
074 *
075 * <p>
076 * This example creates a ScrollPane, which contains a Rectangle :
077 * <pre><code>
078 * import javafx.scene.control.ScrollPane;
079 * import javafx.scene.shape.Rectangle;
080 * 
081 * Rectangle rect = new Rectangle(200, 200, Color.RED);
082 * ScrollPane s1 = new ScrollPane();
083 * s1.setPrefSize(120, 120);
084 * s1.setContent(rect);
085 * </code></pre>
086 *
087 * Implementation of ScrollPane According to JavaFX UI Control API Specification
088 */
089@DefaultProperty("content")
090public class ScrollPane extends Control {
091
092    /***************************************************************************
093     *                                                                         *
094     * Constructors                                                            *
095     *                                                                         *
096     **************************************************************************/
097
098    /**
099     * Creates a new ScrollPane.
100     */
101    public ScrollPane() {
102        getStyleClass().setAll(DEFAULT_STYLE_CLASS);
103        // focusTraversable is styleable through css. Calling setFocusTraversable
104        // makes it look to css like the user set the value and css will not 
105        // override. Initializing focusTraversable by calling applyStyle with
106        // null StyleOrigin ensures that css will be able to override the value.
107        ((StyleableProperty<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE); 
108    }
109
110    /**
111     * Creates a new ScrollPane.
112     * @param content the initial content for the ScrollPane
113     */
114    public ScrollPane(Node content) {
115        this();
116        setContent(content);
117    }
118
119    /***************************************************************************
120     *                                                                         *
121     * Properties                                                              *
122     *                                                                         *
123     **************************************************************************/
124    /**
125     * Specifies the policy for showing the horizontal scroll bar.
126     */
127    private ObjectProperty<ScrollBarPolicy> hbarPolicy;
128    public final void setHbarPolicy(ScrollBarPolicy value) {
129        hbarPolicyProperty().set(value);
130    }
131
132    public final ScrollBarPolicy getHbarPolicy() {
133        return hbarPolicy == null ? ScrollBarPolicy.AS_NEEDED : hbarPolicy.get();
134    }
135
136    public final ObjectProperty<ScrollBarPolicy> hbarPolicyProperty() {
137        if (hbarPolicy == null) {
138            hbarPolicy = new StyleableObjectProperty<ScrollBarPolicy>(ScrollBarPolicy.AS_NEEDED) {
139
140                @Override
141                public CssMetaData<ScrollPane,ScrollBarPolicy> getCssMetaData() {
142                    return StyleableProperties.HBAR_POLICY;
143                }
144
145                @Override
146                public Object getBean() {
147                    return ScrollPane.this;
148                }
149
150                @Override
151                public String getName() {
152                    return "hbarPolicy";
153                }
154            };
155        }
156        return hbarPolicy;
157    }
158    /**
159     * Specifies the policy for showing the vertical scroll bar.
160     */
161    private ObjectProperty<ScrollBarPolicy> vbarPolicy;
162    public final void setVbarPolicy(ScrollBarPolicy value) {
163        vbarPolicyProperty().set(value);
164    }
165
166    public final ScrollBarPolicy getVbarPolicy() {
167        return vbarPolicy == null ? ScrollBarPolicy.AS_NEEDED : vbarPolicy.get();
168    }
169
170    public final ObjectProperty<ScrollBarPolicy> vbarPolicyProperty() {
171        if (vbarPolicy == null) {
172            vbarPolicy = new StyleableObjectProperty<ScrollBarPolicy>(ScrollBarPolicy.AS_NEEDED) {
173
174                @Override
175                public CssMetaData<ScrollPane,ScrollBarPolicy> getCssMetaData() {
176                    return StyleableProperties.VBAR_POLICY;
177                }
178
179                @Override
180                public Object getBean() {
181                    return ScrollPane.this;
182                }
183
184                @Override
185                public String getName() {
186                    return "vbarPolicy";
187                }
188            };
189        }
190        return vbarPolicy;
191    }
192    /**
193     * The node used as the content of this ScrollPane.
194     */
195    private ObjectProperty<Node> content;
196
197    public final void setContent(Node value) {
198        contentProperty().set(value);
199    }
200
201    public final Node getContent() {
202        return content == null ? null : content.get();
203    }
204
205    public final ObjectProperty<Node> contentProperty() {
206        if (content == null) {
207            content = new SimpleObjectProperty<Node>(this, "content");
208        }
209        return content;
210    }
211    /**
212     * The current horizontal scroll position of the ScrollPane. This value
213     * may be set by the application to scroll the view programatically.
214     * The ScrollPane will update this value whenever the viewport is
215     * scrolled or panned by the user. This value must always be within
216     * the range of {@link #hminProperty hmin} to {@link #hmaxProperty hmax}. When {@link #hvalueProperty hvalue}
217     * equals {@link #hminProperty hmin}, the contained node is positioned so that
218     * its layoutBounds {@link javafx.geometry.Bounds#getMinX minX} is visible. When {@link #hvalueProperty hvalue}
219     * equals {@link #hmaxProperty hmax}, the contained node is positioned so that its
220     * layoutBounds {@link javafx.geometry.Bounds#getMaxX maxX} is visible. When {@link #hvalueProperty hvalue} is between
221     * {@link #hminProperty hmin} and {@link #hmaxProperty hmax}, the contained node is positioned
222     * proportionally between layoutBounds {@link javafx.geometry.Bounds#getMinX minX} and
223     * layoutBounds {@link javafx.geometry.Bounds#getMaxX maxX}.
224     */
225    private DoubleProperty hvalue;
226
227    public final void setHvalue(double value) {
228        hvalueProperty().set(value);
229    }
230
231    public final double getHvalue() {
232        return hvalue == null ? 0.0 : hvalue.get();
233    }
234
235    public final DoubleProperty hvalueProperty() {
236        if (hvalue == null) {
237            hvalue = new SimpleDoubleProperty(this, "hvalue");
238        }
239        return hvalue;
240    }
241    /**
242     * The current vertical scroll position of the ScrollPane. This value
243     * may be set by the application to scroll the view programatically.
244     * The ScrollPane will update this value whenever the viewport is
245     * scrolled or panned by the user. This value must always be within
246     * the range of {@link #vminProperty vmin} to {@link #vmaxProperty vmax}. When {@link #vvalueProperty vvalue}
247     * equals {@link #vminProperty vmin}, the contained node is positioned so that
248     * its layoutBounds {@link javafx.geometry.Bounds#getMinY minY} is visible. When {@link #vvalueProperty vvalue}
249     * equals {@link #vmaxProperty vmax}, the contained node is positioned so that its
250     * layoutBounds {@link javafx.geometry.Bounds#getMaxY maxY} is visible. When {@link #vvalueProperty vvalue} is between
251     * {@link #vminProperty vmin} and {@link #vmaxProperty vmax}, the contained node is positioned
252     * proportionally between layoutBounds {@link javafx.geometry.Bounds#getMinY minY} and
253     * layoutBounds {@link javafx.geometry.Bounds#getMaxY maxY}.
254     */
255    private DoubleProperty vvalue;
256
257    public final void setVvalue(double value) {
258        vvalueProperty().set(value);
259    }
260
261    public final double getVvalue() {
262        return vvalue == null ? 0.0 : vvalue.get();
263    }
264
265    public final DoubleProperty vvalueProperty() {
266        if (vvalue == null) {
267            vvalue = new SimpleDoubleProperty(this, "vvalue");
268        }
269        return vvalue;
270    }
271    /**
272     * The minimum allowable {@link #hvalueProperty hvalue} for this ScrollPane.
273     */
274    private DoubleProperty hmin;
275
276    public final void setHmin(double value) {
277        hminProperty().set(value);
278    }
279
280    public final double getHmin() {
281        return hmin == null ? 0.0F : hmin.get();
282    }
283
284    public final DoubleProperty hminProperty() {
285        if (hmin == null) {
286            hmin = new SimpleDoubleProperty(this, "hmin", 0.0);
287        }
288        return hmin;
289    }
290    /**
291     * The minimum allowable {@link #hvalueProperty vvalue} for this ScrollPane.
292     */
293    private DoubleProperty vmin;
294
295    public final void setVmin(double value) {
296        vminProperty().set(value);
297    }
298
299    public final double getVmin() {
300        return vmin == null ? 0.0F : vmin.get();
301    }
302
303    public final DoubleProperty vminProperty() {
304        if (vmin == null) {
305            vmin = new SimpleDoubleProperty(this, "vmin", 0.0);
306        }
307        return vmin;
308    }
309    /**
310     * The maximum allowable {@link #hvalueProperty hvalue} for this ScrollPane.
311     */
312    private DoubleProperty hmax;
313
314    public final void setHmax(double value) {
315        hmaxProperty().set(value);
316    }
317
318    public final double getHmax() {
319        return hmax == null ? 1.0F : hmax.get();
320    }
321
322    public final DoubleProperty hmaxProperty() {
323        if (hmax == null) {
324            hmax = new SimpleDoubleProperty(this, "hmax", 1.0);
325        }
326        return hmax;
327    }
328    /**
329     * The maximum allowable {@link #hvalueProperty vvalue} for this ScrollPane.
330     */
331    private DoubleProperty vmax;
332
333    public final void setVmax(double value) {
334        vmaxProperty().set(value);
335    }
336
337    public final double getVmax() {
338        return vmax == null ? 1.0F : vmax.get();
339    }
340
341    public final DoubleProperty vmaxProperty() {
342        if (vmax == null) {
343            vmax = new SimpleDoubleProperty(this, "vmax", 1.0);
344        }
345        return vmax;
346    }
347    /**
348     * If true and if the contained node is a Resizable, then the node will be
349     * kept resized to match the width of the ScrollPane's viewport. If the
350     * contained node is not a Resizable, this value is ignored.
351     */
352    private BooleanProperty fitToWidth;
353    public final void setFitToWidth(boolean value) {
354        fitToWidthProperty().set(value);
355    }
356    public final boolean isFitToWidth() {
357        return fitToWidth == null ? false : fitToWidth.get();
358    }
359    public final BooleanProperty fitToWidthProperty() {
360        if (fitToWidth == null) {
361            fitToWidth = new StyleableBooleanProperty(false) {
362                @Override public void invalidated() {
363                    pseudoClassStateChanged(FIT_TO_WIDTH_PSEUDOCLASS_STATE, get());
364                }
365                
366                @Override
367                public CssMetaData<ScrollPane,Boolean> getCssMetaData() {
368                    return StyleableProperties.FIT_TO_WIDTH;
369                }
370
371                @Override
372                public Object getBean() {
373                    return ScrollPane.this;
374                }
375
376                @Override
377                public String getName() {
378                    return "fitToWidth";
379                }
380            };
381        }
382        return fitToWidth;
383    }
384    /**
385     * If true and if the contained node is a Resizable, then the node will be
386     * kept resized to match the height of the ScrollPane's viewport. If the
387     * contained node is not a Resizable, this value is ignored.
388     */
389    private BooleanProperty fitToHeight;
390    public final void setFitToHeight(boolean value) {
391        fitToHeightProperty().set(value);
392    }
393    public final boolean isFitToHeight() {
394        return fitToHeight == null ? false : fitToHeight.get();
395    }
396    public final BooleanProperty fitToHeightProperty() {
397        if (fitToHeight == null) {
398            fitToHeight = new StyleableBooleanProperty(false) {
399                @Override public void invalidated() {
400                    pseudoClassStateChanged(FIT_TO_HEIGHT_PSEUDOCLASS_STATE, get());
401                }
402
403                @Override
404                public CssMetaData<ScrollPane,Boolean> getCssMetaData() {
405                    return StyleableProperties.FIT_TO_HEIGHT;
406                }
407
408                @Override
409                public Object getBean() {
410                    return ScrollPane.this;
411                }
412
413                @Override
414                public String getName() {
415                    return "fitToHeight";
416                }
417            };
418        }
419        return fitToHeight;
420    }
421    /**
422     * Specifies whether the user should be able to pan the viewport by using
423     * the mouse. If mouse events reach the ScrollPane (that is, if mouse
424     * events are not blocked by the contained node or one of its children)
425     * then {@link #pannableProperty pannable} is consulted to determine if the events should be
426     * used for panning.
427     */
428    private BooleanProperty pannable;
429    public final void setPannable(boolean value) {
430        pannableProperty().set(value);
431    }
432    public final boolean isPannable() {
433        return pannable == null ? false : pannable.get();
434    }
435    public final BooleanProperty pannableProperty() {
436        if (pannable == null) {
437            pannable = new StyleableBooleanProperty(false) {
438                @Override public void invalidated() {
439                    pseudoClassStateChanged(PANNABLE_PSEUDOCLASS_STATE, get());
440                }
441
442                @Override
443                public CssMetaData<ScrollPane,Boolean> getCssMetaData() {
444                    return StyleableProperties.PANNABLE;
445                }
446                
447                @Override
448                public Object getBean() {
449                    return ScrollPane.this;
450                }
451
452                @Override
453                public String getName() {
454                    return "pannable";
455                }
456            };
457        }
458        return pannable;
459    }
460
461
462    /**
463     * Specify the perferred width of the ScrollPane Viewport.
464     * This is the width that will be available to the content node.
465     * The overall width of the ScrollPane is the ViewportWidth + padding
466     */
467    private DoubleProperty prefViewportWidth;
468
469    public final void setPrefViewportWidth(double value) {
470        prefViewportWidthProperty().set(value);
471    }
472
473    public final double getPrefViewportWidth() {
474        return prefViewportWidth == null ? 0.0F : prefViewportWidth.get();
475    }
476
477    public final DoubleProperty prefViewportWidthProperty() {
478        if (prefViewportWidth == null) {
479            prefViewportWidth = new SimpleDoubleProperty(this, "prefViewportWidth");
480        }
481        return prefViewportWidth;
482    }
483
484    /**
485     * Specify the preferred height of the ScrollPane Viewport.
486     * This is the height that will be available to the content node.
487     * The overall height of the ScrollPane is the ViewportHeight + padding
488     */
489    private DoubleProperty prefViewportHeight;
490
491    public final void setPrefViewportHeight(double value) {
492        prefViewportHeightProperty().set(value);
493    }
494
495    public final double getPrefViewportHeight() {
496        return prefViewportHeight == null ? 0.0F : prefViewportHeight.get();
497    }
498
499    public final DoubleProperty prefViewportHeightProperty() {
500        if (prefViewportHeight == null) {
501            prefViewportHeight = new SimpleDoubleProperty(this, "prefViewportHeight");
502        }
503        return prefViewportHeight;
504    }
505
506    /**
507     * The actual Bounds of the ScrollPane Viewport.
508     * This is the Bounds of the content node.
509     */
510    private ObjectProperty<Bounds> viewportBounds;
511
512    public final void setViewportBounds(Bounds value) {
513        viewportBoundsProperty().set(value);
514    }
515
516    public final Bounds getViewportBounds() {
517        return viewportBounds == null ? new BoundingBox(0,0,0,0) : viewportBounds.get();
518    }
519
520    public final ObjectProperty<Bounds> viewportBoundsProperty() {
521        if (viewportBounds == null) {
522            viewportBounds = new SimpleObjectProperty<Bounds>(this, "viewportBounds");
523        }
524        return viewportBounds;
525    }
526
527
528    /***************************************************************************
529     *                                                                         *
530     * Methods                                                                 *
531     *                                                                         *
532     **************************************************************************/
533
534    /*
535     * TODO The unit increment and block increment variables have been
536     * removed from the public API. These are intended to be mapped to
537     * the corresponding variables of the scrollbars. However, the problem
538     * is that they are specified in terms of the logical corrdinate space
539     * of the ScrollPane (that is, [hmin..hmax] by [vmin..vmax]. This is
540     * incorrect. Scrolling is a user action and should properly be based
541     * on how much of the content is visible, not on some abstract
542     * coordinate space. At some later date we may add a finer-grained
543     * API to allow applications to control this. Meanwhile, the skin should
544     * set unit and block increments for the scroll bars to do something
545     * reasonable based on the viewport size, e.g. the block increment
546     * should scroll 90% of the pixel size of the viewport, and the unit
547     * increment should scroll 10% of the pixel size of the viewport.
548     */
549
550    /**
551     * Defines the horizontal unit increment amount. Typically this is used when clicking on the
552     * increment or decrement arrow buttons of the horizontal scroll bar.
553     */
554    // public var hunitIncrement:Number = 20.0;
555
556    /**
557     * Defines the vertical unit increment amount. Typically this is used when clicking on the
558     * increment or decrement arrow buttons of the vertical scroll bar.
559     */
560    // public var vunitIncrement:Number = 20.0;
561
562    /**
563     * Defines the horizontal block increment amount. Typically this is used when clicking on the
564     * track of the scroll bar.
565     */
566    // public var hblockIncrement:Number = -1;
567
568    /**
569     * Defines the vertical block increment amount. Typically this is used when clicking on the
570     * track of the scroll bar.
571     */
572    // public var vblockIncrement:Number = -1;
573
574    /** {@inheritDoc} */
575    @Override protected Skin<?> createDefaultSkin() {
576        return new ScrollPaneSkin(this);
577    }
578
579    /***************************************************************************
580     *                                                                         *
581     *                         Stylesheet Handling                             *
582     *                                                                         *
583     **************************************************************************/
584
585    /**
586     * Initialize the style class to 'scroll-view'.
587     *
588     * This is the selector class from which CSS can be used to style
589     * this control.
590     */
591    private static final String DEFAULT_STYLE_CLASS = "scroll-pane";
592
593    /**
594     * Pseudoclass indicating the fitToWidth property is {@code true}
595     */
596    private static final String PSEUDO_CLASS_FIT_TO_WIDTH = "fitToWidth";
597
598    /**
599     * Pseudoclass indicating the fitToHeight property is {@code true}
600     */
601    private static final String PSEUDO_CLASS_FIT_TO_HEIGHT = "fitToHeight";
602
603    /**
604     * Pseudoclass indicating the pannable property is {@code true}
605     */
606    private static final String PSEUDO_CLASS_PANNABLE = "pannable";
607
608    /**
609     * @treatAsPrivate
610     */
611    private static class StyleableProperties {
612        private static final CssMetaData<ScrollPane,ScrollBarPolicy> HBAR_POLICY =
613            new CssMetaData<ScrollPane,ScrollBarPolicy>("-fx-hbar-policy",
614                 new EnumConverter<ScrollBarPolicy>(ScrollBarPolicy.class),
615                        ScrollBarPolicy.AS_NEEDED){
616
617            @Override
618            public boolean isSettable(ScrollPane n) {
619                return n.hbarPolicy == null || !n.hbarPolicy.isBound();
620            }
621
622            @Override
623            public StyleableProperty<ScrollBarPolicy> getStyleableProperty(ScrollPane n) {
624                return (StyleableProperty<ScrollBarPolicy>)n.hbarPolicyProperty();
625            }
626        };
627                
628        private static final CssMetaData<ScrollPane,ScrollBarPolicy> VBAR_POLICY =
629            new CssMetaData<ScrollPane,ScrollBarPolicy>("-fx-vbar-policy",
630                new EnumConverter<ScrollBarPolicy>(ScrollBarPolicy.class),
631                        ScrollBarPolicy.AS_NEEDED){
632
633            @Override
634            public boolean isSettable(ScrollPane n) {
635                return n.vbarPolicy == null || !n.vbarPolicy.isBound();
636            }
637
638            @Override
639            public StyleableProperty<ScrollBarPolicy> getStyleableProperty(ScrollPane n) {
640                return (StyleableProperty<ScrollBarPolicy>)n.vbarPolicyProperty();
641            }
642        };
643                
644        private static final CssMetaData<ScrollPane,Boolean> FIT_TO_WIDTH =
645            new CssMetaData<ScrollPane, Boolean>("-fx-fit-to-width",
646                BooleanConverter.getInstance(), Boolean.FALSE){
647
648            @Override
649            public boolean isSettable(ScrollPane n) {
650                return n.fitToWidth == null || !n.fitToWidth.isBound();
651            }
652
653            @Override
654            public StyleableProperty<Boolean> getStyleableProperty(ScrollPane n) {
655                return (StyleableProperty<Boolean>)n.fitToWidthProperty();
656            }
657        };
658                
659        private static final CssMetaData<ScrollPane,Boolean> FIT_TO_HEIGHT =
660            new CssMetaData<ScrollPane, Boolean>("-fx-fit-to-height",
661                BooleanConverter.getInstance(), Boolean.FALSE){
662
663            @Override
664            public boolean isSettable(ScrollPane n) {
665                return n.fitToHeight == null || !n.fitToHeight.isBound();
666            }
667
668            @Override
669            public StyleableProperty<Boolean> getStyleableProperty(ScrollPane n) {
670                return (StyleableProperty<Boolean>)n.fitToHeightProperty();
671            }
672        };
673                
674        private static final CssMetaData<ScrollPane,Boolean> PANNABLE =
675            new CssMetaData<ScrollPane, Boolean>("-fx-pannable",
676                BooleanConverter.getInstance(), Boolean.FALSE){
677
678            @Override
679            public boolean isSettable(ScrollPane n) {
680                return n.pannable == null || !n.pannable.isBound();
681            }
682
683            @Override
684            public StyleableProperty<Boolean> getStyleableProperty(ScrollPane n) {
685                return (StyleableProperty<Boolean>)n.pannableProperty();
686            }
687        };
688
689        private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
690        static {
691            final List<CssMetaData<? extends Styleable, ?>> styleables = 
692                new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData());
693            styleables.add(HBAR_POLICY);
694            styleables.add(VBAR_POLICY);
695            styleables.add(FIT_TO_WIDTH);
696            styleables.add(FIT_TO_HEIGHT);
697            styleables.add(PANNABLE);
698            STYLEABLES = Collections.unmodifiableList(styleables);
699        }
700    }
701
702    /**
703     * @return The CssMetaData associated with this class, which may include the
704     * CssMetaData of its super classes.
705     */
706    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
707        return StyleableProperties.STYLEABLES;
708    }
709
710    /**
711     * {@inheritDoc}
712     */
713    @Override
714    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
715        return getClassCssMetaData();
716    }
717
718    private static final PseudoClass PANNABLE_PSEUDOCLASS_STATE =
719            PseudoClass.getPseudoClass("pannable");
720    private static final PseudoClass FIT_TO_WIDTH_PSEUDOCLASS_STATE =
721            PseudoClass.getPseudoClass("fitToWidth");
722    private static final PseudoClass FIT_TO_HEIGHT_PSEUDOCLASS_STATE =
723            PseudoClass.getPseudoClass("fitToHeight");
724    
725    /**
726      * Most Controls return true for focusTraversable, so Control overrides
727      * this method to return true, but ScrollPane returns false for
728      * focusTraversable's initial value; hence the override of the override. 
729      * This method is called from CSS code to get the correct initial value.
730      * @treatAsPrivate implementation detail
731      */
732    @Deprecated @Override
733    protected /*do not make final*/ Boolean impl_cssGetFocusTraversableInitialValue() {
734        return Boolean.FALSE;
735    }
736    
737    /**
738     * An enumeration denoting the policy to be used by a scrollable
739     * Control in deciding whether to show a scroll bar.
740     */
741    public static enum ScrollBarPolicy {
742        /**
743         * Indicates that a scroll bar should never be shown.
744         */
745        NEVER,
746        /**
747         * Indicates that a scroll bar should always be shown.
748         */
749        ALWAYS,
750        /**
751         * Indicates that a scroll bar should be shown when required.
752         */
753        AS_NEEDED
754    }
755}