1 /*
   2  * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene.control;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.List;
  31 
  32 import javafx.beans.property.ObjectProperty;
  33 import javafx.beans.value.WritableValue;
  34 import javafx.geometry.HPos;
  35 import javafx.geometry.Orientation;
  36 import javafx.geometry.VPos;
  37 import javafx.css.StyleableObjectProperty;
  38 import javafx.css.CssMetaData;
  39 import javafx.css.PseudoClass;
  40 
  41 import javafx.css.converter.EnumConverter;
  42 import javafx.scene.control.skin.SeparatorSkin;
  43 
  44 import javafx.css.Styleable;
  45 import javafx.css.StyleableProperty;
  46 
  47 /**
  48  * A horizontal or vertical separator line. The visual appearance of this
  49  * separator can be controlled via CSS. A horizontal separator occupies the
  50  * full horizontal space allocated to it (less padding), and a vertical
  51  * separator occupies the full vertical space allocated to it (less padding).
  52  * The {@link #halignment} and {@link #valignment} properties determine how the
  53  * separator is positioned in the other dimension, for example, how a horizontal
  54  * separator is positioned vertically within its allocated space.
  55  * <p>
  56  * The separator is horizontal (i.e. <code>isVertical() == false</code>) by default.
  57  * <p>
  58  * The style-class for this control is "separator".
  59  * <p>
  60  * The separator provides two pseudo-classes "horizontal" and "vertical" which
  61  * are mutually exclusive. The "horizontal" pseudo-class applies if the
  62  * separator is horizontal, and the "vertical" pseudo-class applies if the
  63  * separator is vertical.
  64  *
  65  * <p>
  66  * Separator sets focusTraversable to false.
  67  * </p>
  68  * @since JavaFX 2.0
  69  */
  70 public class Separator extends Control {
  71 
  72     /***************************************************************************
  73      *                                                                         *
  74      * Constructors                                                            *
  75      *                                                                         *
  76      **************************************************************************/
  77 
  78     /**
  79      * Creates a new horizontal separator with halignment and valignment set to their
  80      * respective CENTER values.
  81      */
  82     public Separator() {
  83         this(Orientation.HORIZONTAL);
  84     }
  85 
  86     /**
  87      * Creates a new separator with halignment and valignment set to their respective CENTER
  88      * values. The direction of the separator is specified by the vertical property.
  89      *
  90      * @param orientation Specifies whether the Separator instance is initially
  91      *      vertical or horizontal.
  92      */
  93     public Separator(Orientation orientation) {
  94 
  95         getStyleClass().setAll(DEFAULT_STYLE_CLASS);
  96 
  97         // focusTraversable is styleable through css. Calling setFocusTraversable
  98         // makes it look to css like the user set the value and css will not
  99         // override. Initializing focusTraversable by calling applyStyle with null
 100         // StyleOrigin ensures that css will be able to override the value.
 101         ((StyleableProperty<Boolean>)(WritableValue<Boolean>)focusTraversableProperty()).applyStyle(null, Boolean.FALSE);
 102 
 103         // initialize pseudo-class state
 104         pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, orientation != Orientation.VERTICAL);
 105         pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE, orientation == Orientation.VERTICAL);
 106 
 107         ((StyleableProperty<Orientation>)(WritableValue<Orientation>)orientationProperty())
 108                 .applyStyle(null, orientation != null ? orientation : Orientation.HORIZONTAL);
 109     }
 110 
 111     /***************************************************************************
 112      *                                                                         *
 113      * Properties                                                              *
 114      *                                                                         *
 115      **************************************************************************/
 116 
 117     /**
 118      * The orientation of the {@code Separator} can either be horizontal
 119      * or vertical.
 120      */
 121     private ObjectProperty<Orientation> orientation =
 122         new StyleableObjectProperty<Orientation>(Orientation.HORIZONTAL) {
 123 
 124             @Override protected void invalidated() {
 125                 final boolean isVertical = (get() == Orientation.VERTICAL);
 126                 pseudoClassStateChanged(VERTICAL_PSEUDOCLASS_STATE,    isVertical);
 127                 pseudoClassStateChanged(HORIZONTAL_PSEUDOCLASS_STATE, !isVertical);
 128             }
 129 
 130             @Override
 131             public CssMetaData<Separator,Orientation> getCssMetaData() {
 132                 return StyleableProperties.ORIENTATION;
 133             }
 134 
 135             @Override
 136             public Object getBean() {
 137                 return Separator.this;
 138             }
 139 
 140             @Override
 141             public String getName() {
 142                 return "orientation";
 143             }
 144         };
 145     public final void setOrientation(Orientation value) { orientation.set(value); }
 146     public final Orientation getOrientation() { return orientation.get(); }
 147     public final ObjectProperty<Orientation> orientationProperty() { return orientation; }
 148 
 149     /**
 150      * For vertical separators, specifies the horizontal position of the
 151      * separator line within the separator control's space. Ignored for
 152      * horizontal separators.
 153      */
 154     private ObjectProperty<HPos> halignment;
 155 
 156     public final void setHalignment(HPos value) {
 157         halignmentProperty().set(value);
 158     }
 159 
 160     public final HPos getHalignment() {
 161         return halignment == null ? HPos.CENTER : halignment.get();
 162     }
 163 
 164     public final ObjectProperty<HPos> halignmentProperty() {
 165         if (halignment == null) {
 166             halignment = new StyleableObjectProperty<HPos>(HPos.CENTER) {
 167 
 168                 @Override
 169                 public Object getBean() {
 170                     return Separator.this;
 171                 }
 172 
 173                 @Override
 174                 public String getName() {
 175                     return "halignment";
 176                 }
 177 
 178                 @Override
 179                 public CssMetaData<Separator,HPos> getCssMetaData() {
 180                     return StyleableProperties.HALIGNMENT;
 181                 }
 182 
 183             };
 184         }
 185         return halignment;
 186     }
 187 
 188     /**
 189      * For horizontal separators, specifies the vertical alignment of the
 190      * separator line within the separator control's space. Ignored for
 191      * vertical separators.
 192      */
 193     private ObjectProperty<VPos> valignment;
 194     public final void setValignment(VPos value) {
 195         valignmentProperty().set(value);
 196     }
 197 
 198     public final VPos getValignment() {
 199         return valignment == null ? VPos.CENTER : valignment.get();
 200     }
 201 
 202     public final ObjectProperty<VPos> valignmentProperty() {
 203         if (valignment == null) {
 204             valignment = new StyleableObjectProperty<VPos>(VPos.CENTER) {
 205 
 206                 @Override
 207                 public Object getBean() {
 208                     return Separator.this;
 209                 }
 210 
 211                 @Override
 212                 public String getName() {
 213                     return "valignment";
 214                 }
 215 
 216                 @Override
 217                 public CssMetaData<Separator,VPos> getCssMetaData() {
 218                     return StyleableProperties.VALIGNMENT;
 219                 }
 220 
 221             };
 222         }
 223         return valignment;
 224     }
 225 
 226     /** {@inheritDoc} */
 227     @Override protected Skin<?> createDefaultSkin() {
 228         return new SeparatorSkin(this);
 229     }
 230 
 231     /***************************************************************************
 232      *                                                                         *
 233      * Stylesheet Handling                                                     *
 234      *                                                                         *
 235      **************************************************************************/
 236 
 237     private static final String DEFAULT_STYLE_CLASS = "separator";
 238 
 239     private static class StyleableProperties {
 240         private static final CssMetaData<Separator,Orientation> ORIENTATION =
 241                 new CssMetaData<Separator,Orientation>("-fx-orientation",
 242                 new EnumConverter<Orientation>(Orientation.class),
 243                 Orientation.HORIZONTAL) {
 244 
 245             @Override
 246             public Orientation getInitialValue(Separator node) {
 247                 // A vertical Separator should remain vertical
 248                 return node.getOrientation();
 249             }
 250 
 251             @Override
 252             public boolean isSettable(Separator n) {
 253                 return n.orientation == null || !n.orientation.isBound();
 254             }
 255 
 256             @Override
 257             public StyleableProperty<Orientation> getStyleableProperty(Separator n) {
 258                 return (StyleableProperty<Orientation>)(WritableValue<Orientation>)n.orientationProperty();
 259             }
 260         };
 261 
 262         private static final CssMetaData<Separator,HPos> HALIGNMENT =
 263                 new CssMetaData<Separator,HPos>("-fx-halignment",
 264                 new EnumConverter<HPos>(HPos.class),
 265                 HPos.CENTER) {
 266 
 267             @Override
 268             public boolean isSettable(Separator n) {
 269                 return n.halignment == null || !n.halignment.isBound();
 270             }
 271 
 272             @Override
 273             public StyleableProperty<HPos> getStyleableProperty(Separator n) {
 274                 return (StyleableProperty<HPos>)(WritableValue<HPos>)n.halignmentProperty();
 275             }
 276         };
 277 
 278         private static final CssMetaData<Separator,VPos> VALIGNMENT =
 279                 new CssMetaData<Separator,VPos>("-fx-valignment",
 280                 new EnumConverter<VPos>(VPos.class),
 281                 VPos.CENTER){
 282 
 283             @Override
 284             public boolean isSettable(Separator n) {
 285                 return n.valignment == null || !n.valignment.isBound();
 286             }
 287 
 288             @Override
 289             public StyleableProperty<VPos> getStyleableProperty(Separator n) {
 290                 return (StyleableProperty<VPos>)(WritableValue<VPos>)n.valignmentProperty();
 291             }
 292         };
 293 
 294         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 295         static {
 296             final List<CssMetaData<? extends Styleable, ?>> styleables =
 297                 new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData());
 298             styleables.add(ORIENTATION);
 299             styleables.add(HALIGNMENT);
 300             styleables.add(VALIGNMENT);
 301             STYLEABLES = Collections.unmodifiableList(styleables);
 302         }
 303     }
 304 
 305     /**
 306      * @return The CssMetaData associated with this class, which may include the
 307      * CssMetaData of its super classes.
 308      * @since JavaFX 8.0
 309      */
 310     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 311         return Separator.StyleableProperties.STYLEABLES;
 312     }
 313 
 314     /**
 315      * RT-19263
 316      * @treatAsPrivate implementation detail
 317      * @deprecated This is an experimental API that is not intended for general use and is subject to change in future versions
 318      * @since JavaFX 8.0
 319      */
 320     @Deprecated
 321     @Override protected List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
 322         return getClassCssMetaData();
 323     }
 324 
 325     private static final PseudoClass VERTICAL_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("vertical");
 326     private static final PseudoClass HORIZONTAL_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("horizontal");
 327 
 328     /**
 329      * Returns the initial focus traversable state of this control, for use
 330      * by the JavaFX CSS engine to correctly set its initial value. This method
 331      * is overridden as by default UI controls have focus traversable set to true,
 332      * but that is not appropriate for this control.
 333      *
 334      * @since 9
 335      */
 336     @Override protected Boolean getInitialFocusTraversable() {
 337         return Boolean.FALSE;
 338     }
 339 
 340 }