1 /* 2 * Copyright (c) 2011, 2013, 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 /* 27 * To change this template, choose Tools | Templates 28 * and open the template in the editor. 29 */ 30 31 package com.sun.javafx.scene.control; 32 33 import javafx.beans.InvalidationListener; 34 import javafx.beans.Observable; 35 import javafx.scene.control.Label; 36 import javafx.scene.control.Labeled; 37 38 import javafx.css.CssMetaData; 39 import javafx.css.StyleOrigin; 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.List; 43 import javafx.css.Styleable; 44 import javafx.css.StyleableProperty; 45 import javafx.scene.layout.Region; 46 47 48 public class LabeledImpl extends Label { 49 50 public LabeledImpl(final Labeled labeled) { 51 shuttler = new Shuttler(this, labeled); 52 } 53 private final Shuttler shuttler; 54 55 private static void initialize(Shuttler shuttler, LabeledImpl labeledImpl, Labeled labeled) { 56 57 labeledImpl.setText(labeled.getText()); 58 labeled.textProperty().addListener(shuttler); 59 60 labeledImpl.setGraphic(labeled.getGraphic()); 61 labeled.graphicProperty().addListener(shuttler); 62 63 final List<CssMetaData<? extends Styleable, ?>> styleables = StyleableProperties.STYLEABLES_TO_MIRROR; 64 65 for(int n=0, nMax=styleables.size(); n<nMax; n++) { 66 @SuppressWarnings("unchecked") 67 final CssMetaData<Styleable,Object> styleable = (CssMetaData<Styleable,Object>)styleables.get(n); 68 69 // the Labeled isn't necessarily a Label, so skip the skin or 70 // we'll get an argument type mismatch on the invocation of the 71 // skin constructor. 72 if ("-fx-skin".equals(styleable.getProperty())) continue; 73 74 final StyleableProperty<?> fromVal = styleable.getStyleableProperty(labeled); 75 if (fromVal instanceof Observable) { 76 // listen for changes to this property 77 ((Observable)fromVal).addListener(shuttler); 78 // set this LabeledImpl's property to the same value as the Labeled. 79 final StyleOrigin origin = fromVal.getStyleOrigin(); 80 if (origin == null) continue; 81 final StyleableProperty<Object> styleableProperty = styleable.getStyleableProperty(labeledImpl); 82 styleableProperty.applyStyle(origin, fromVal.getValue()); 83 } 84 } 85 } 86 87 private static class Shuttler implements InvalidationListener { 88 89 private final LabeledImpl labeledImpl; 90 private final Labeled labeled; 91 92 Shuttler(LabeledImpl labeledImpl, Labeled labeled) { 93 this.labeledImpl = labeledImpl; 94 this.labeled = labeled; 95 initialize(this, labeledImpl, labeled); 96 97 } 98 99 @Override public void invalidated(Observable valueModel) { 100 101 if (valueModel == labeled.textProperty()) { 102 labeledImpl.setText(labeled.getText()); 103 } else if (valueModel == labeled.graphicProperty()) { 104 // If the user set the graphic, then mirror that. 105 // Otherwise, the graphic was set via the imageUrlProperty which 106 // will be mirrored onto the labeledImpl by the next block. 107 StyleOrigin origin = ((StyleableProperty<?>)labeled.graphicProperty()).getStyleOrigin(); 108 if (origin == null || origin == StyleOrigin.USER) { 109 labeledImpl.setGraphic(labeled.getGraphic()); 110 } 111 112 } else if (valueModel instanceof StyleableProperty) { 113 StyleableProperty<?> styleableProperty = (StyleableProperty<?>)valueModel; 114 @SuppressWarnings("unchecked") 115 CssMetaData<Styleable,Object> cssMetaData = (CssMetaData<Styleable,Object>)styleableProperty.getCssMetaData(); 116 if (cssMetaData != null) { 117 StyleOrigin origin = styleableProperty.getStyleOrigin(); 118 StyleableProperty<Object> targetProperty = cssMetaData.getStyleableProperty(labeledImpl); 119 targetProperty.applyStyle(origin, styleableProperty.getValue()); 120 } 121 } 122 } 123 } 124 125 /** Protected for unit test purposes */ 126 static final class StyleableProperties { 127 128 static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES_TO_MIRROR; 129 static { 130 // 131 // We do this as we only want to mirror the Labeled's keys, 132 // none of Parent's, otherwise all of the properties on Parent, 133 // like opacity, would be applied twice (once to the Labeled and 134 // again to the LabeledImpl). 135 // 136 // Note, however, that this subset is not the list of properties 137 // for this LabeledImpl that can be styled. For that, we want all 138 // the properites that are inherited by virtue of LabeledImpl 139 // being a Label. This allows for the LabledImpl to be styled 140 // with styles like .menu-button .label { -fx-opacity: 80%; } 141 // If just this subset were returned (by impl_CSS_STYLEABLE) then 142 // -fx-opacity (for example) would be meaningless to the Labeled. 143 // 144 final List<CssMetaData<? extends Styleable, ?>> labeledStyleables = Labeled.getClassCssMetaData(); 145 final List<CssMetaData<? extends Styleable, ?>> parentStyleables = Region.getClassCssMetaData(); 146 final List<CssMetaData<? extends Styleable, ?>> styleables = 147 new ArrayList<CssMetaData<? extends Styleable, ?>>(labeledStyleables); 148 styleables.removeAll(parentStyleables); 149 STYLEABLES_TO_MIRROR = Collections.unmodifiableList(styleables); 150 } 151 } 152 153 }