javafx.scene.control.Labeled Maven / Gradle / Ivy
/*
* Copyright (c) 2010, 2024, 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 javafx.scene.control;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.beans.DefaultProperty;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.WritableValue;
import javafx.css.CssMetaData;
import javafx.css.FontCssMetaData;
import javafx.css.StyleOrigin;
import javafx.css.Styleable;
import javafx.css.StyleableBooleanProperty;
import javafx.css.StyleableDoubleProperty;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.css.StyleableStringProperty;
import javafx.css.converter.BooleanConverter;
import javafx.css.converter.EnumConverter;
import javafx.css.converter.InsetsConverter;
import javafx.css.converter.PaintConverter;
import javafx.css.converter.SizeConverter;
import javafx.css.converter.StringConverter;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import com.sun.javafx.css.StyleManager;
import com.sun.javafx.scene.NodeHelper;
import com.sun.javafx.scene.control.LabeledHelper;
/**
* A Labeled {@link Control} is one which has as part of its user interface
* a textual content associated with it. For example, a {@link Button} displays
* {@code text}, as does a {@link Label}, a {@link Tooltip}, and many
* other controls.
*
* Labeled is also a convenient base class from which to extend when building
* new Controls which, as part of their UI, display read-only textual content.
*
*
* Example of how to place a graphic above the text:
*
* Image image = new Image(getClass().getResourceAsStream("image.png"));
* ImageView imageView = new ImageView();
* imageView.setImage(image);
* Label label = new Label("text", imageView);
* label.setContentDisplay(ContentDisplay.TOP);
*
*
* @see Button
* @see Label
* @see ToggleButton
* @since JavaFX 2.0
*/
@DefaultProperty("text")
public abstract class Labeled extends Control {
private final static String DEFAULT_ELLIPSIS_STRING = "...";
static {
LabeledHelper.setAccessor(new LabeledHelper.Accessor() {
@Override
public void setTextTruncated(Labeled c, boolean on) {
c.setTextTruncated(on);
}
});
}
/* *************************************************************************
* *
* Constructors *
* *
**************************************************************************/
/**
* Creates a Label with no text and graphic
*/
public Labeled() { }
/**
* Creates a Label with text
* @param text The text for the label.
*/
public Labeled(String text) {
setText(text);
}
/**
* Creates a Label with text and a graphic
* @param text The text for the label.
* @param graphic The graphic for the label.
*/
public Labeled(String text, Node graphic) {
setText(text);
((StyleableProperty)(WritableValue)graphicProperty()).applyStyle(null, graphic);
}
/* *************************************************************************
* *
* Properties *
* *
**************************************************************************/
/**
* The text to display in the label. The text may be null.
*
* @return the text to display in the label
* @defaultValue empty string
*/
public final StringProperty textProperty() {
if (text == null) {
text = new SimpleStringProperty(this, "text", "");
}
return text;
}
private StringProperty text;
public final void setText(String value) { textProperty().setValue(value); }
public final String getText() { return text == null ? "" : text.getValue(); }
/**
* Specifies how the text and graphic within the Labeled should be
* aligned when there is empty space within the Labeled.
*
* @return the alignment within this labeled
* @defaultValue {@code Pos.CENTER_LEFT}
*/
public final ObjectProperty alignmentProperty() {
if (alignment == null) {
alignment = new StyleableObjectProperty(Pos.CENTER_LEFT) {
@Override public CssMetaData getCssMetaData() {
return StyleableProperties.ALIGNMENT;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "alignment";
}
};
}
return alignment;
}
private ObjectProperty alignment;
public final void setAlignment(Pos value) { alignmentProperty().set(value); }
public final Pos getAlignment() { return alignment == null ? Pos.CENTER_LEFT : alignment.get(); }
/**
* Specifies the behavior for lines of text when text is multiline.
* Unlike {@link #contentDisplayProperty} which affects the graphic and text, this setting
* only affects multiple lines of text relative to the text bounds.
*
* @return the alignment of lines of text within this labeled
* @defaultValue {@code TextAlignment.LEFT}
*/
public final ObjectProperty textAlignmentProperty() {
if (textAlignment == null) {
textAlignment = new StyleableObjectProperty(TextAlignment.LEFT) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.TEXT_ALIGNMENT;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "textAlignment";
}
};
}
return textAlignment;
}
private ObjectProperty textAlignment;
public final void setTextAlignment(TextAlignment value) { textAlignmentProperty().setValue(value); }
public final TextAlignment getTextAlignment() { return textAlignment == null ? TextAlignment.LEFT : textAlignment.getValue(); }
/**
* Specifies the behavior to use if the text of the {@code Labeled}
* exceeds the available space for rendering the text.
*
* @return the overrun behavior if the text exceeds the available space
* @defaultValue {@code OverrunStyle.ELLIPSIS}
*/
public final ObjectProperty textOverrunProperty() {
if (textOverrun == null) {
textOverrun = new StyleableObjectProperty(OverrunStyle.ELLIPSIS) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.TEXT_OVERRUN;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "textOverrun";
}
};
}
return textOverrun;
}
private ObjectProperty textOverrun;
public final void setTextOverrun(OverrunStyle value) { textOverrunProperty().setValue(value); }
public final OverrunStyle getTextOverrun() { return textOverrun == null ? OverrunStyle.ELLIPSIS : textOverrun.getValue(); }
/**
* Specifies the string to display for the ellipsis when text is truncated.
*
*
* Ellipsis Table
* Examples
* "..." Default value for most locales
* " . . . "
* " [...] "
* "\u2026" The Unicode ellipsis character '…'
* "" No ellipsis, just display the truncated string
*
*
* Note that not all fonts support all Unicode characters.
*
* @return the ellipsis property on the string to display for the ellipsis
* when text is truncated
* @see Wikipedia:ellipsis
* @defaultValue {@code "..."}
* @since JavaFX 2.2
*/
public final StringProperty ellipsisStringProperty() {
if (ellipsisString == null) {
ellipsisString = new StyleableStringProperty(DEFAULT_ELLIPSIS_STRING) {
@Override public Object getBean() {
return Labeled.this;
}
@Override public String getName() {
return "ellipsisString";
}
@Override public CssMetaData getCssMetaData() {
return StyleableProperties.ELLIPSIS_STRING;
}
};
}
return ellipsisString;
}
private StringProperty ellipsisString;
public final void setEllipsisString(String value) { ellipsisStringProperty().set((value == null) ? "" : value); }
public final String getEllipsisString() { return ellipsisString == null ? DEFAULT_ELLIPSIS_STRING : ellipsisString.get(); }
/**
* If a run of text exceeds the width of the Labeled, then this variable
* indicates whether the text should wrap onto another line.
*
* @return the wrap property if a run of text exceeds the width of the Labeled
* @defaultValue {@code false}
*/
public final BooleanProperty wrapTextProperty() {
if (wrapText == null) {
wrapText = new StyleableBooleanProperty() {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.WRAP_TEXT;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "wrapText";
}
};
}
return wrapText;
}
private BooleanProperty wrapText;
public final void setWrapText(boolean value) { wrapTextProperty().setValue(value); }
public final boolean isWrapText() { return wrapText == null ? false : wrapText.getValue(); }
/**
* If wrapText is true, then contentBias will be HORIZONTAL, otherwise it is null.
* @return orientation of width/height dependency or null if there is none
*/
@Override public Orientation getContentBias() {
return isWrapText()? Orientation.HORIZONTAL : null;
}
/**
* The default font to use for text in the Labeled. If the Label's text is
* rich text then this font may or may not be used depending on the font
* information embedded in the rich text, but in any case where a default
* font is required, this font will be used.
*
* @return the default font to use for text in this labeled
* @defaultValue {@link Font#getDefault()}
*/
public final ObjectProperty fontProperty() {
if (font == null) {
font = new StyleableObjectProperty(Font.getDefault()) {
private boolean fontSetByCss = false;
@Override
public void applyStyle(StyleOrigin newOrigin, Font value) {
//
// RT-20727 - if CSS is setting the font, then make sure invalidate doesn't call NodeHelper.reapplyCSS
//
try {
// super.applyStyle calls set which might throw if value is bound.
// Have to make sure fontSetByCss is reset.
fontSetByCss = true;
super.applyStyle(newOrigin, value);
} catch(Exception e) {
throw e;
} finally {
fontSetByCss = false;
}
}
@Override
public void set(Font value) {
final Font oldValue = get();
if (value != null ? !value.equals(oldValue) : oldValue != null) {
super.set(value);
NodeHelper.recalculateRelativeSizeProperties(Labeled.this, value);
}
}
@Override
protected void invalidated() {
// RT-20727 - if font is changed by calling setFont, then
// css might need to be reapplied since font size affects
// calculated values for styles with relative values
if(fontSetByCss == false) {
NodeHelper.reapplyCSS(Labeled.this);
}
}
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.FONT;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "font";
}
};
}
return font;
}
private ObjectProperty font;
public final void setFont(Font value) { fontProperty().setValue(value); }
public final Font getFont() { return font == null ? Font.getDefault() : font.getValue(); }
/**
* An optional icon for the Labeled. This can be positioned relative to the
* text by using {@link #setContentDisplay}. The node specified for this
* variable cannot appear elsewhere in the scene graph, otherwise
* the {@code IllegalArgumentException} is thrown. See the class
* description of {@link Node} for more detail.
*
* @return the optional icon for this labeled
* @defaultValue {@code null}
*/
public final ObjectProperty graphicProperty() {
if (graphic == null) {
graphic = new StyleableObjectProperty<>() {
// The graphic is styleable by css, but it is the
// imageUrlProperty that handles the style value.
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.GRAPHIC;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "graphic";
}
};
}
return graphic;
}
private ObjectProperty graphic;
public final void setGraphic(Node value) {
graphicProperty().setValue(value);
}
public final Node getGraphic() { return graphic == null ? null : graphic.getValue(); }
private StyleableStringProperty imageUrl = null;
/**
* The imageUrl property is set from CSS and then the graphic property is
* set from the invalidated method. This ensures that the same image isn't
* reloaded.
*/
private StyleableStringProperty imageUrlProperty() {
if (imageUrl == null) {
imageUrl = new StyleableStringProperty() {
//
// If imageUrlProperty is invalidated, this is the origin of the style that
// triggered the invalidation. This is used in the invalidated() method where the
// value of super.getStyleOrigin() is not valid until after the call to set(v) returns,
// by which time invalidated will have been called.
// This value is initialized to USER in case someone calls set on the imageUrlProperty, which
// is possible:
// CssMetaData metaData = ((StyleableProperty)labeled.graphicProperty()).getCssMetaData();
// StyleableProperty prop = metaData.getStyleableProperty(labeled);
// prop.set(someUrl);
//
// TODO: Note that prop != labeled, which violates the contract between StyleableProperty and CssMetaData.
//
StyleOrigin origin = StyleOrigin.USER;
@Override
public void applyStyle(StyleOrigin origin, String v) {
this.origin = origin;
// Don't want applyStyle to throw an exception which would leave this.origin set to the wrong value
if (graphic == null || graphic.isBound() == false) super.applyStyle(origin, v);
// Origin is only valid for this invocation of applyStyle, so reset it to USER in case someone calls set.
this.origin = StyleOrigin.USER;
}
@Override
protected void invalidated() {
// need to call super.get() here since get() is overridden to return the graphicProperty's value
final String url = super.get();
if (url == null) {
((StyleableProperty)(WritableValue)graphicProperty()).applyStyle(origin, null);
} else {
// RT-34466 - if graphic's url is the same as this property's value, then don't overwrite.
final Node graphicNode = Labeled.this.getGraphic();
if (graphicNode instanceof ImageView) {
final ImageView imageView = (ImageView)graphicNode;
final Image image = imageView.getImage();
if (image != null) {
final String imageViewUrl = image.getUrl();
if (url.equals(imageViewUrl)) return;
}
}
final Image img = StyleManager.getInstance().getCachedImage(url);
if (img != null) {
//
// Note that it is tempting to try to re-use existing ImageView simply by setting
// the image on the current ImageView, if there is one. This would effectively change
// the image, but not the ImageView which means that no graphicProperty listeners would
// be notified. This is probably not what we want.
//
//
// Have to call applyStyle on graphicProperty so that the graphicProperty's
// origin matches the imageUrlProperty's origin.
//
((StyleableProperty)(WritableValue)graphicProperty()).applyStyle(origin, new ImageView(img));
}
}
}
@Override
public String get() {
//
// The value of the imageUrlProperty is that of the graphicProperty.
// Return the value in a way that doesn't expand the graphicProperty.
//
final Node graphic = getGraphic();
if (graphic instanceof ImageView) {
final Image image = ((ImageView)graphic).getImage();
if (image != null) {
return image.getUrl();
}
}
return null;
}
@Override
public StyleOrigin getStyleOrigin() {
//
// The origin of the imageUrlProperty is that of the graphicProperty.
// Return the origin in a way that doesn't expand the graphicProperty.
//
return graphic != null ? ((StyleableProperty)(WritableValue)graphic).getStyleOrigin() : null;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "imageUrl";
}
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.GRAPHIC;
}
};
}
return imageUrl;
}
/**
* Whether all text should be underlined.
*
* @return the underline property of all text in this labeled
* @defaultValue {@code false}
*/
public final BooleanProperty underlineProperty() {
if (underline == null) {
underline = new StyleableBooleanProperty(false) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.UNDERLINE;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "underline";
}
};
}
return underline;
}
private BooleanProperty underline;
public final void setUnderline(boolean value) { underlineProperty().setValue(value); }
public final boolean isUnderline() { return underline == null ? false : underline.getValue(); }
/**
* Specifies the space in pixel between lines.
*
* @return the line spacing property between lines in this labeled
* @defaultValue 0
* @since JavaFX 8.0
*/
public final DoubleProperty lineSpacingProperty() {
if (lineSpacing == null) {
lineSpacing = new StyleableDoubleProperty(0) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.LINE_SPACING;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "lineSpacing";
}
};
}
return lineSpacing;
}
private DoubleProperty lineSpacing;
public final void setLineSpacing(double value) { lineSpacingProperty().setValue(value); }
public final double getLineSpacing() { return lineSpacing == null ? 0 : lineSpacing.getValue(); }
/**
* Specifies the positioning of the graphic relative to the text.
*
* @return content display property of this labeled
* @defaultValue {@code ContentDisplay.LEFT}
*/
public final ObjectProperty contentDisplayProperty() {
if (contentDisplay == null) {
contentDisplay = new StyleableObjectProperty(ContentDisplay.LEFT) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.CONTENT_DISPLAY;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "contentDisplay";
}
};
}
return contentDisplay;
}
private ObjectProperty contentDisplay;
public final void setContentDisplay(ContentDisplay value) { contentDisplayProperty().setValue(value); }
public final ContentDisplay getContentDisplay() { return contentDisplay == null ? ContentDisplay.LEFT : contentDisplay.getValue(); }
/**
* The padding around the Labeled's text and graphic content.
* By default labelPadding is Insets.EMPTY and cannot be set to null.
* Subclasses may add nodes outside this padding and inside the Labeled's padding.
*
* This property can only be set from CSS.
*
* @return the label padding property of this labeled
* @defaultValue {@code Insets.EMPTY}
*/
public final ReadOnlyObjectProperty labelPaddingProperty() {
return labelPaddingPropertyImpl();
}
private ObjectProperty labelPaddingPropertyImpl() {
if (labelPadding == null) {
labelPadding = new StyleableObjectProperty(Insets.EMPTY) {
private Insets lastValidValue = Insets.EMPTY;
@Override
public void invalidated() {
final Insets newValue = get();
if (newValue == null) {
set(lastValidValue);
throw new NullPointerException("cannot set labelPadding to null");
}
lastValidValue = newValue;
requestLayout();
}
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.LABEL_PADDING;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "labelPadding";
}
};
}
return labelPadding;
}
private ObjectProperty labelPadding;
private void setLabelPadding(Insets value) { labelPaddingPropertyImpl().set(value); }
public final Insets getLabelPadding() { return labelPadding == null ? Insets.EMPTY : labelPadding.get(); }
/**
* The amount of space between the graphic and text
*
* @return the graphics text gap property of this labeled
* @defaultValue 4
*/
public final DoubleProperty graphicTextGapProperty() {
if (graphicTextGap == null) {
graphicTextGap = new StyleableDoubleProperty(4) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.GRAPHIC_TEXT_GAP;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "graphicTextGap";
}
};
}
return graphicTextGap;
}
private DoubleProperty graphicTextGap;
public final void setGraphicTextGap(double value) { graphicTextGapProperty().setValue(value); }
public final double getGraphicTextGap() { return graphicTextGap == null ? 4 : graphicTextGap.getValue(); }
/**
* The {@link Paint} used to fill the text.
*
* @defaultValue {@code Color.BLACK}
*/
private ObjectProperty textFill; // TODO for now change this
public final void setTextFill(Paint value) {
textFillProperty().set(value);
}
public final Paint getTextFill() {
return textFill == null ? Color.BLACK : textFill.get();
}
public final ObjectProperty textFillProperty() {
if (textFill == null) {
textFill = new StyleableObjectProperty(Color.BLACK) {
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.TEXT_FILL;
}
@Override
public Object getBean() {
return Labeled.this;
}
@Override
public String getName() {
return "textFill";
}
};
}
return textFill;
}
/**
* MnemonicParsing property to enable/disable text parsing.
* If this is set to true, then the Label text will be
* parsed to see if it contains the mnemonic parsing character '_'.
* When a mnemonic is detected the key combination will
* be determined based on the succeeding character, and the mnemonic
* added.
*
* @defaultValue {@code false}; {@code true} for some {@code Control}s.
*/
private BooleanProperty mnemonicParsing;
public final void setMnemonicParsing(boolean value) {
mnemonicParsingProperty().set(value);
}
public final boolean isMnemonicParsing() {
return mnemonicParsing == null ? false : mnemonicParsing.get();
}
public final BooleanProperty mnemonicParsingProperty() {
if (mnemonicParsing == null) {
mnemonicParsing = new SimpleBooleanProperty(this, "mnemonicParsing");
}
return mnemonicParsing;
}
/**
* Indicates whether the text has been truncated
* because it cannot fit into the available width.
*
* When truncated, the {@link #ellipsisStringProperty() ellipsisString}
* gets inserted in the place dictated by the
* {@link #textOverrunProperty textOverrun} property.
*
* @since 23
*/
private ReadOnlyBooleanWrapper textTruncated;
public final ReadOnlyBooleanProperty textTruncatedProperty() {
return textTruncated().getReadOnlyProperty();
}
public final boolean isTextTruncated() {
return textTruncated().get();
}
private final void setTextTruncated(boolean on) {
textTruncated().set(on);
}
private ReadOnlyBooleanWrapper textTruncated() {
if (textTruncated == null) {
textTruncated = new ReadOnlyBooleanWrapper(this, "textTruncated");
}
return textTruncated;
}
@Override public String toString() {
StringBuilder builder =
new StringBuilder(super.toString())
.append("'").append(getText()).append("'");
return builder.toString();
}
/* *************************************************************************
* *
* Stylesheet Handling *
* *
**************************************************************************/
/**
* Returns the initial alignment state of this control, for use
* by the JavaFX CSS engine to correctly set its initial value. This method
* is overridden to use Pos.CENTER_LEFT initially.
*
* @return the initial alignment state of this control
* @since 9
*/
protected Pos getInitialAlignment() {
return Pos.CENTER_LEFT;
}
private static class StyleableProperties {
private static final FontCssMetaData FONT =
new FontCssMetaData<>("-fx-font", Font.getDefault()) {
@Override
public boolean isSettable(Labeled n) {
return n.font == null || !n.font.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.fontProperty();
}
};
private static final CssMetaData ALIGNMENT =
new CssMetaData<>("-fx-alignment",
new EnumConverter<>(Pos.class), Pos.CENTER_LEFT ) {
@Override
public boolean isSettable(Labeled n) {
return n.alignment == null || !n.alignment.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.alignmentProperty();
}
@Override
public Pos getInitialValue(Labeled n) {
return n.getInitialAlignment();
}
};
private static final CssMetaData TEXT_ALIGNMENT =
new CssMetaData<>("-fx-text-alignment",
new EnumConverter<>(TextAlignment.class),
TextAlignment.LEFT) {
@Override
public boolean isSettable(Labeled n) {
return n.textAlignment == null || !n.textAlignment.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.textAlignmentProperty();
}
};
private static final CssMetaData TEXT_FILL =
new CssMetaData<>("-fx-text-fill",
PaintConverter.getInstance(), Color.BLACK) {
@Override
public boolean isSettable(Labeled n) {
return n.textFill == null || !n.textFill.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.textFillProperty();
}
};
private static final CssMetaData TEXT_OVERRUN =
new CssMetaData<>("-fx-text-overrun",
new EnumConverter<>(OverrunStyle.class),
OverrunStyle.ELLIPSIS) {
@Override
public boolean isSettable(Labeled n) {
return n.textOverrun == null || !n.textOverrun.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.textOverrunProperty();
}
};
private static final CssMetaData ELLIPSIS_STRING =
new CssMetaData<>("-fx-ellipsis-string",
StringConverter.getInstance(), DEFAULT_ELLIPSIS_STRING) {
@Override public boolean isSettable(Labeled n) {
return n.ellipsisString == null || !n.ellipsisString.isBound();
}
@Override public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)n.ellipsisStringProperty();
}
};
private static final CssMetaData WRAP_TEXT =
new CssMetaData<>("-fx-wrap-text",
BooleanConverter.getInstance(), false) {
@Override
public boolean isSettable(Labeled n) {
return n.wrapText == null || !n.wrapText.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)n.wrapTextProperty();
}
};
private static final CssMetaData GRAPHIC =
new CssMetaData<>("-fx-graphic",
StringConverter.getInstance()) {
@Override
public boolean isSettable(Labeled n) {
// Note that we care about the graphic, not imageUrl
return n.graphic == null || !n.graphic.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return n.imageUrlProperty();
}
};
private static final CssMetaData UNDERLINE =
new CssMetaData<>("-fx-underline",
BooleanConverter.getInstance(), Boolean.FALSE) {
@Override
public boolean isSettable(Labeled n) {
return n.underline == null || !n.underline.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)n.underlineProperty();
}
};
private static final CssMetaData LINE_SPACING =
new CssMetaData<>("-fx-line-spacing",
SizeConverter.getInstance(), 0) {
@Override
public boolean isSettable(Labeled n) {
return n.lineSpacing == null || !n.lineSpacing.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)n.lineSpacingProperty();
}
};
private static final CssMetaData CONTENT_DISPLAY =
new CssMetaData<>("-fx-content-display",
new EnumConverter<>(ContentDisplay.class),
ContentDisplay.LEFT) {
@Override
public boolean isSettable(Labeled n) {
return n.contentDisplay == null || !n.contentDisplay.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.contentDisplayProperty();
}
};
private static final CssMetaData LABEL_PADDING =
new CssMetaData<>("-fx-label-padding",
InsetsConverter.getInstance(), Insets.EMPTY) {
@Override
public boolean isSettable(Labeled n) {
return n.labelPadding == null || !n.labelPadding.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)(WritableValue)n.labelPaddingPropertyImpl();
}
};
private static final CssMetaData GRAPHIC_TEXT_GAP =
new CssMetaData<>("-fx-graphic-text-gap",
SizeConverter.getInstance(), 4.0) {
@Override
public boolean isSettable(Labeled n) {
return n.graphicTextGap == null || !n.graphicTextGap.isBound();
}
@Override
public StyleableProperty getStyleableProperty(Labeled n) {
return (StyleableProperty)n.graphicTextGapProperty();
}
};
private static final List> STYLEABLES;
static {
final List> styleables =
new ArrayList<>(Control.getClassCssMetaData());
Collections.addAll(styleables,
FONT,
ALIGNMENT,
TEXT_ALIGNMENT,
TEXT_FILL,
TEXT_OVERRUN,
ELLIPSIS_STRING,
WRAP_TEXT,
GRAPHIC,
UNDERLINE,
LINE_SPACING,
CONTENT_DISPLAY,
LABEL_PADDING,
GRAPHIC_TEXT_GAP
);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
/**
* Gets the {@code CssMetaData} associated with this class, which may include the
* {@code CssMetaData} of its superclasses.
* @return the {@code CssMetaData}
* @since JavaFX 8.0
*/
public static List> getClassCssMetaData() {
return StyleableProperties.STYLEABLES;
}
/**
* {@inheritDoc}
* @since JavaFX 8.0
*/
@Override
public List> getControlCssMetaData() {
return getClassCssMetaData();
}
}