All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.javafx.scene.control.LabeledText Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.javafx.scene.control;

import javafx.css.converter.BooleanConverter;
import javafx.css.converter.EnumConverter;
import javafx.css.converter.PaintConverter;
import javafx.css.converter.SizeConverter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WritableValue;
import javafx.css.*;
import javafx.scene.control.Labeled;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;

/**
 * LabeledText allows the Text to be styled by the CSS properties of Labeled
 * that are meant to style the textual component of the Labeled.
 *
 * LabeledText has the style class "text"
 */
public class LabeledText extends Text {

   private final Labeled labeled;

   public LabeledText(Labeled labeled) {
       super();

       if (labeled == null) {
           throw new IllegalArgumentException("labeled cannot be null");
       }

       this.labeled = labeled;

       //
       // init the state of this Text object to that of the Labeled
       //
       this.setFill(this.labeled.getTextFill());
       this.setFont(this.labeled.getFont());
       this.setTextAlignment(this.labeled.getTextAlignment());
       this.setUnderline(this.labeled.isUnderline());
       this.setLineSpacing(this.labeled.getLineSpacing());

       //
       // Bind the state of this Text object to that of the Labeled.
       // Binding these properties prevents CSS from setting them
       //
       this.fillProperty().bind(this.labeled.textFillProperty());
       this.fontProperty().bind(this.labeled.fontProperty());
       // do not bind text - Text doesn't have -fx-text
       this.textAlignmentProperty().bind(this.labeled.textAlignmentProperty());
       this.underlineProperty().bind(this.labeled.underlineProperty());
       this.lineSpacingProperty().bind(this.labeled.lineSpacingProperty());

       getStyleClass().addAll("text");
   }

    /**
     * @return The CssMetaData associated with this class, which may include the
     * CssMetaData of its superclasses.
     */
    public static List> getClassCssMetaData() {
        return STYLEABLES;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List> getCssMetaData() {
        return getClassCssMetaData();
    }

   //
   // Replace all of Text's CssMetaData instances that overlap with Labeled
   // with instances of CssMetaData that redirect to Labeled. Thus, when
   // the Labeled is styled,
   //

    private StyleablePropertyMirror fontMirror = null;
    private StyleableProperty fontMirror() {
        if (fontMirror == null) {
            fontMirror = new StyleablePropertyMirror<>(FONT, "fontMirror", Font.getDefault(), (StyleableProperty)(WritableValue)labeled.fontProperty());
            fontProperty().addListener(fontMirror);
        }
        return fontMirror;
    }

    private static final CssMetaData FONT =
        new FontCssMetaData<>("-fx-font", Font.getDefault()) {

        @Override
        public boolean isSettable(LabeledText node) {
            return node.labeled != null ? node.labeled.fontProperty().isBound() == false : true;
        }

        @Override
        public StyleableProperty getStyleableProperty(LabeledText node) {
            return node.fontMirror();
        }
    };

    private StyleablePropertyMirror fillMirror;
    private StyleableProperty fillMirror() {
        if (fillMirror == null) {
            fillMirror = new StyleablePropertyMirror<>(FILL, "fillMirror", Color.BLACK, (StyleableProperty)(WritableValue)labeled.textFillProperty());
            fillProperty().addListener(fillMirror);
        }
        return fillMirror;
    }

    private static final CssMetaData FILL =
        new CssMetaData<>("-fx-fill",
            PaintConverter.getInstance(), Color.BLACK) {

            @Override
            public boolean isSettable(LabeledText node) {
                return node.labeled.textFillProperty().isBound() == false;
            }

            @Override
            public StyleableProperty getStyleableProperty(LabeledText node) {
                return node.fillMirror();
            }
        };

    private StyleablePropertyMirror textAlignmentMirror;
    private StyleableProperty textAlignmentMirror() {
        if (textAlignmentMirror == null) {
            textAlignmentMirror = new StyleablePropertyMirror<>(TEXT_ALIGNMENT, "textAlignmentMirror", TextAlignment.LEFT, (StyleableProperty)(WritableValue)labeled.textAlignmentProperty());
            textAlignmentProperty().addListener(textAlignmentMirror);
        }
        return textAlignmentMirror;
    }

    private static final CssMetaData TEXT_ALIGNMENT =
        new CssMetaData<>("-fx-text-alignment",
        new EnumConverter<>(TextAlignment.class),
        TextAlignment.LEFT) {

            @Override
            public boolean isSettable(LabeledText node) {
                return node.labeled.textAlignmentProperty().isBound() == false;
            }

            @Override
            public StyleableProperty getStyleableProperty(LabeledText node) {
                return node.textAlignmentMirror();
            }
        };

    private StyleablePropertyMirror underlineMirror;
    private StyleableProperty underlineMirror() {
        if (underlineMirror == null) {
            underlineMirror = new StyleablePropertyMirror<>(UNDERLINE, "underLineMirror", Boolean.FALSE, (StyleableProperty)labeled.underlineProperty());
            underlineProperty().addListener(underlineMirror);
        }
        return underlineMirror;
    }

    private static final CssMetaData UNDERLINE =
            new CssMetaData<>("-fx-underline",
            BooleanConverter.getInstance(),
            Boolean.FALSE) {

            @Override
            public boolean isSettable(LabeledText node) {
                return node.labeled.underlineProperty().isBound() == false;
            }

            @Override
            public StyleableProperty getStyleableProperty(LabeledText node) {
                return node.underlineMirror();
            }
        };

    private StyleablePropertyMirror lineSpacingMirror;
    private StyleableProperty lineSpacingMirror() {
        if (lineSpacingMirror == null) {
            lineSpacingMirror = new StyleablePropertyMirror<>(LINE_SPACING, "lineSpacingMirror", 0d, (StyleableProperty)labeled.lineSpacingProperty());
            lineSpacingProperty().addListener(lineSpacingMirror);
        }
        return lineSpacingMirror;
    }

    private static final CssMetaData LINE_SPACING =
        new CssMetaData<>("-fx-line-spacing",
            SizeConverter.getInstance(),
                0) {

            @Override
            public boolean isSettable(LabeledText node) {
                return node.labeled.lineSpacingProperty().isBound() == false;
            }

            @Override
            public StyleableProperty getStyleableProperty(LabeledText node) {
                return node.lineSpacingMirror();
            }
        };

    private static final List> STYLEABLES;
    static {

       final List> styleables =
           new ArrayList<>(Text.getClassCssMetaData());

       for (int n=0,nMax=styleables.size(); n extends SimpleStyleableObjectProperty implements InvalidationListener {

        private StyleablePropertyMirror(CssMetaData cssMetaData, String name, T initialValue, StyleableProperty property) {
            super(cssMetaData, LabeledText.this, name, initialValue);
            this.property = property;
            this.applying = false;
        }

        @Override
        public void invalidated(Observable observable) {
            // if Text's property is changing but not because a style is being applied,
            // then it's either because the set method was called on the Labeled's property or
            // because CSS is resetting Labeled's property to its initial value
            // (see CssStyleHelper#resetToInitialValues(Styleable))
            if (applying == false) {
                super.applyStyle(null, ((ObservableValue)observable).getValue());
            }
        }

        @Override
        public void applyStyle(StyleOrigin newOrigin, T value) {

            applying = true;
            //
            // In the case where the Labeled's property was set by an
            // inline style, this inline style should override values
            // from lesser origins.
            //
            StyleOrigin propOrigin = property.getStyleOrigin();

            //
            // if propOrigin is null, then the property is in init state
            // if newOrigin is null, then CSS is resetting this property -
            //    but don't let CSS overwrite a user set value
            // if propOrigin is greater than origin, then the style should
            //    not override
            //
            if (propOrigin == null ||
                    (newOrigin != null
                            ? propOrigin.compareTo(newOrigin) <= 0
                            : propOrigin != StyleOrigin.USER)) {
                super.applyStyle(newOrigin, value);
                property.applyStyle(newOrigin, value);
            }
            applying = false;
        }

        @Override public StyleOrigin getStyleOrigin() {
            return property.getStyleOrigin();
        }

        boolean applying;
        private final StyleableProperty property;
    }

}