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.property.DoubleProperty;
032import javafx.beans.property.ObjectProperty;
033import javafx.beans.property.SimpleDoubleProperty;
034import javafx.geometry.Orientation;
035
036import com.sun.javafx.Utils;
037import javafx.css.CssMetaData;
038import javafx.css.PseudoClass;
039import javafx.css.StyleableDoubleProperty;
040import javafx.css.StyleableObjectProperty;
041import com.sun.javafx.css.converters.EnumConverter;
042import com.sun.javafx.css.converters.SizeConverter;
043import com.sun.javafx.scene.control.skin.ScrollBarSkin;
044import javafx.css.Styleable;
045import javafx.css.StyleableProperty;
046
047
048/**
049 * Either a horizontal or vertical bar with increment and decrement buttons and
050 * a "thumb" with which the user can interact. Typically not used alone but used
051 * for building up more complicated controls such as the ScrollPane and ListView.
052 * <p>
053 * ScrollBar sets focusTraversable to false.
054 * </p>
055 *
056 * <p>
057 * This example creates a vertical ScrollBar :
058 * <pre><code>
059 * import javafx.scene.control.ScrollBar;
060 *
061 * ScrollBar s1 = new ScrollBar();
062 * s1.setOrientation(Orientation.VERTICAL);
063 * </code></pre>
064 *
065 * Implementation of ScrollBar According to JavaFX UI Control API Specification
066 */
067
068public class ScrollBar extends Control {
069
070    /***************************************************************************
071     *                                                                         *
072     * Constructors                                                            *
073     *                                                                         *
074     **************************************************************************/
075
076    /**
077     * Creates a new horizontal (i.e. <code>getOrientation() == Orientation.HORIZONTAL</code>)
078     * ScrollBar.
079     */
080    public ScrollBar() {
081        // TODO : we need to ensure we have a width and height
082        setWidth(ScrollBarSkin.DEFAULT_WIDTH);
083        setHeight(ScrollBarSkin.DEFAULT_LENGTH);
084        getStyleClass().setAll(DEFAULT_STYLE_CLASS);
085        // focusTraversable is styleable through css. Calling setFocusTraversable
086        // makes it look to css like the user set the value and css will not 
087        // override. Initializing focusTraversable by calling applyStyle with null
088        // for StyleOrigin ensures that css will be able to override the value.
089        ((StyleableProperty)focusTraversableProperty()).applyStyle(null,Boolean.FALSE);
090
091        // set pseudo-class state to horizontal
092        pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, true);
093        
094    }
095    /***************************************************************************
096     *                                                                         *
097     * Properties                                                              *
098     *                                                                         *
099     **************************************************************************/
100    /**
101     * The minimum value represented by this {@code ScrollBar}. This should be a
102     * value less than or equal to {@link #maxProperty max}.
103     */
104    private DoubleProperty min;
105    public final void setMin(double value) {
106        minProperty().set(value);
107    }
108
109    public final double getMin() {
110        return min == null ? 0 : min.get();
111    }
112
113    public final DoubleProperty minProperty() {
114        if (min == null) {
115            min = new SimpleDoubleProperty(this, "min");
116        }
117        return min;
118    }
119    /**
120     * The maximum value represented by this {@code ScrollBar}. This should be a
121     * value greater than or equal to {@link #minProperty min}.
122     */
123    private DoubleProperty max;
124    public final void setMax(double value) {
125        maxProperty().set(value);
126    }
127
128    public final double getMax() {
129        return max == null ? 100 : max.get();
130    }
131
132    public final DoubleProperty maxProperty() {
133        if (max == null) {
134            max = new SimpleDoubleProperty(this, "max", 100);
135        }
136        return max;
137    }
138    /**
139     * The current value represented by this {@code ScrollBar}. This value should
140     * be between {@link #minProperty min} and {@link #maxProperty max}, inclusive.
141     */
142    private DoubleProperty value;
143    public final void setValue(double value) {
144        valueProperty().set(value);
145    }
146
147    public final double getValue() {
148        return value == null ? 0 : value.get();
149    }
150
151    public final DoubleProperty valueProperty() {
152        if (value == null) {
153            value = new SimpleDoubleProperty(this, "value");
154        }
155        return value;
156    }
157    /**
158     * The orientation of the {@code ScrollBar} can either be {@link javafx.geometry.Orientation#HORIZONTAL HORIZONTAL}
159     * or {@link javafx.geometry.Orientation#VERTICAL VERTICAL}.
160     */
161    private ObjectProperty<Orientation> orientation;
162    public final void setOrientation(Orientation value) {
163        orientationProperty().set(value);
164    }
165
166    public final Orientation getOrientation() {
167        return orientation == null ? Orientation.HORIZONTAL : orientation.get();
168    }
169
170    public final ObjectProperty<Orientation> orientationProperty() {
171        if (orientation == null) {
172            orientation = new StyleableObjectProperty<Orientation>(Orientation.HORIZONTAL) {
173                @Override protected void invalidated() {
174                    final boolean vertical = (get() == Orientation.VERTICAL);
175                    pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE,    vertical);
176                    pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, !vertical);
177                }
178
179                @Override 
180                public CssMetaData<ScrollBar,Orientation> getCssMetaData() {
181                    return StyleableProperties.ORIENTATION;
182                }
183                    
184                @Override
185                public Object getBean() {
186                    return ScrollBar.this;
187                }
188
189                @Override
190                public String getName() {
191                    return "orientation";
192                }
193            };
194        }
195        return orientation;
196    }
197    
198    /**
199     * The amount by which to adjust the ScrollBar when the {@link #increment() increment} or
200     * {@link #decrement() decrement} methods are called.
201     */
202    private DoubleProperty unitIncrement;
203    public final void setUnitIncrement(double value) {
204        unitIncrementProperty().set(value);
205    }
206
207    public final double getUnitIncrement() {
208        return unitIncrement == null ? 1 : unitIncrement.get();
209    }
210
211    public final DoubleProperty unitIncrementProperty() {
212        if (unitIncrement == null) {
213            unitIncrement = new StyleableDoubleProperty(1) {
214
215                @Override
216                public CssMetaData<ScrollBar,Number> getCssMetaData() {
217                    return StyleableProperties.UNIT_INCREMENT;
218                }
219
220                @Override
221                public Object getBean() {
222                    return ScrollBar.this;
223                }
224
225                @Override
226                public String getName() {
227                    return "unitIncrement";
228                }
229            };
230        }
231        return unitIncrement;
232    }
233    /**
234     * The amount by which to adjust the scrollbar if the track of the bar is
235     * clicked.
236     */
237    private DoubleProperty blockIncrement;
238    public final void setBlockIncrement(double value) {
239        blockIncrementProperty().set(value);
240    }
241
242    public final double getBlockIncrement() {
243        return blockIncrement == null ? 10 : blockIncrement.get();
244    }
245
246    public final DoubleProperty blockIncrementProperty() {
247        if (blockIncrement == null) {
248            blockIncrement = new StyleableDoubleProperty(10) {
249
250                @Override
251                public CssMetaData<ScrollBar,Number> getCssMetaData() {
252                    return StyleableProperties.BLOCK_INCREMENT;
253                }
254
255                @Override
256                public Object getBean() {
257                    return ScrollBar.this;
258                }
259
260                @Override
261                public String getName() {
262                    return "blockIncrement";
263                }
264            };
265        }
266        return blockIncrement;
267    }
268    /**
269     * Visible amount of the scrollbar's range, typically represented by
270     * the size of the scroll bar's thumb.
271     *
272     * @since JavaFX 1.3
273     */
274    private DoubleProperty visibleAmount;
275
276    public final void setVisibleAmount(double value) {
277        visibleAmountProperty().set(value);
278    }
279
280    public final double getVisibleAmount() {
281        return visibleAmount == null ? 15 : visibleAmount.get();
282    }
283
284    public final DoubleProperty visibleAmountProperty() {
285        if (visibleAmount == null) {
286            visibleAmount = new SimpleDoubleProperty(this, "visibleAmount");
287        }
288        return visibleAmount;
289    }
290
291    /***************************************************************************
292     *                                                                         *
293     * Methods                                                                 *
294     *                                                                         *
295     **************************************************************************/
296
297    /**
298     * Adjusts the {@link #valueProperty() value} property by 
299     * {@link #blockIncrementProperty() blockIncrement}. The {@code position} is the fractional amount 
300     * between the {@link #minProperty min} and {@link #maxProperty max}. For
301     * example, it might be 50%. If {@code #minProperty min} were 0 and {@code #maxProperty max}
302     * were 100 and {@link #valueProperty() value} were 25, then a position of .5 would indicate
303     * that we should increment {@link #valueProperty() value} by 
304     * {@code blockIncrement}. If {@link #valueProperty() value} were 75, then a
305     * position of .5 would indicate that we
306     * should decrement {@link #valueProperty() value} by {@link #blockIncrementProperty blockIncrement}. 
307     *
308     * @expert This function is intended to be used by experts, primarily
309     *         by those implementing new Skins or Behaviors. It is not common
310     *         for developers or designers to access this function directly.
311     */
312    public void adjustValue(double position) {
313        // figure out the "value" associated with the specified position
314        double posValue = ((getMax() - getMin()) * Utils.clamp(0, position, 1))+getMin();
315        double newValue;
316        if (Double.compare(posValue, getValue()) != 0) {
317            if (posValue > getValue()) {
318                newValue = getValue() + getBlockIncrement();
319            }
320            else {
321                newValue = getValue() - getBlockIncrement();
322            }
323            
324            boolean incrementing = position > ((getValue() - getMin())/(getMax() - getMin()));
325            if (incrementing && newValue > posValue) newValue = posValue;
326            if (! incrementing && newValue < posValue) newValue = posValue;
327            setValue(Utils.clamp(getMin(), newValue, getMax()));
328        }
329    }
330
331    /**
332     * Increments the value of the {@code ScrollBar} by the
333     * {@link #unitIncrementProperty unitIncrement}
334     */
335    public void increment() {
336        setValue(Utils.clamp(getMin(), getValue() + getUnitIncrement(), getMax()));
337    }
338
339    /**
340     * Decrements the value of the {@code ScrollBar} by the
341     * {@link #unitIncrementProperty unitIncrement}
342     */
343    public void decrement() {
344        setValue(Utils.clamp(getMin(), getValue() - getUnitIncrement(), getMax()));
345    }
346
347    /** {@inheritDoc} */
348    @Override protected Skin<?> createDefaultSkin() {
349        return new ScrollBarSkin(this);
350    }
351
352    /***************************************************************************
353     *                                                                         *
354     * Stylesheet Handling                                                     *
355     *                                                                         *
356     **************************************************************************/
357
358    /**
359     * Initialize the style class to 'scroll-bar'.
360     *
361     * This is the selector class from which CSS can be used to style
362     * this control.
363     */
364    private static final String DEFAULT_STYLE_CLASS = "scroll-bar";
365
366    private static class StyleableProperties {
367        private static final CssMetaData<ScrollBar,Orientation> ORIENTATION = 
368            new CssMetaData<ScrollBar,Orientation>("-fx-orientation",
369                new EnumConverter<Orientation>(Orientation.class),
370                Orientation.HORIZONTAL) {
371
372            @Override
373            public Orientation getInitialValue(ScrollBar node) {
374                // A vertical ScrollBar should remain vertical 
375                return node.getOrientation();
376            }
377                    
378            @Override
379            public boolean isSettable(ScrollBar n) {
380                return n.orientation == null || !n.orientation.isBound();
381            }
382
383            @Override
384            public StyleableProperty<Orientation> getStyleableProperty(ScrollBar n) {
385                return (StyleableProperty<Orientation>)n.orientationProperty();
386            }
387        };
388        
389        private static final CssMetaData<ScrollBar,Number> UNIT_INCREMENT = 
390            new CssMetaData<ScrollBar,Number>("-fx-unit-increment",
391                SizeConverter.getInstance(), 1.0) {
392
393            @Override
394            public boolean isSettable(ScrollBar n) {
395                return n.unitIncrement == null || !n.unitIncrement.isBound();
396            }
397
398            @Override
399            public StyleableProperty<Number> getStyleableProperty(ScrollBar n) {
400                return (StyleableProperty<Number>)n.unitIncrementProperty();
401            }
402                    
403        };
404        
405        private static final CssMetaData<ScrollBar,Number> BLOCK_INCREMENT = 
406            new CssMetaData<ScrollBar,Number>("-fx-block-increment",
407                SizeConverter.getInstance(), 10.0) {
408
409            @Override
410            public boolean isSettable(ScrollBar n) {
411                return n.blockIncrement == null || !n.blockIncrement.isBound();
412            }
413
414            @Override
415            public StyleableProperty<Number> getStyleableProperty(ScrollBar n) {
416                return (StyleableProperty<Number>)n.blockIncrementProperty();
417            }
418                    
419        };
420        
421        private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
422        static {
423            final List<CssMetaData<? extends Styleable, ?>> styleables = 
424                new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData());
425            styleables.add(ORIENTATION);
426            styleables.add(UNIT_INCREMENT);
427            styleables.add(BLOCK_INCREMENT);
428            STYLEABLES = Collections.unmodifiableList(styleables);
429        }
430    }
431
432    /**
433     * @return The CssMetaData associated with this class, which may include the
434     * CssMetaData of its super classes.
435     */
436    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
437        return StyleableProperties.STYLEABLES;
438    }
439
440    /**
441     * {@inheritDoc}
442     */
443    @Override
444    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
445        return getClassCssMetaData();
446    }
447
448    /**
449     * Pseud-class indicating this is a vertical ScrollBar.
450     */
451    private static final PseudoClass VERTICAL_PSEUDOCLASS_STATE =
452            PseudoClass.getPseudoClass("vertical");
453
454    /**
455     * Pseudo-class indicating this is a horizontal ScrollBar.
456     */
457    private static final PseudoClass HORIZONTAL_PSEUDOCLASS_STATE =
458            PseudoClass.getPseudoClass("horizontal");
459    
460    /**
461      * Most Controls return true for focusTraversable, so Control overrides
462      * this method to return true, but ScrollBar returns false for
463      * focusTraversable's initial value; hence the override of the override. 
464      * This method is called from CSS code to get the correct initial value.
465      * @treatAsPrivate implementation detail
466      */
467    @Deprecated @Override
468    protected /*do not make final*/ Boolean impl_cssGetFocusTraversableInitialValue() {
469        return Boolean.FALSE;
470    }
471    
472}