1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package com.oracle.javafx.scenebuilder.kit.metadata.property.value.list; 33 34 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; 35 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; 36 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMProperty; 37 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance; 38 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNodes; 39 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyC; 40 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyT; 41 import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata; 42 import com.oracle.javafx.scenebuilder.kit.metadata.property.value.SingleValuePropertyMetadata; 43 import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath; 44 import com.oracle.javafx.scenebuilder.kit.metadata.util.PrefixedValue; 45 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; 46 import java.util.ArrayList; 47 import java.util.Collections; 48 import java.util.List; 49 import java.util.Objects; 50 import javafx.fxml.FXMLLoader; 51 52 /** 53 * 54 */ 55 public abstract class ListValuePropertyMetadata<T> extends ValuePropertyMetadata { 56 57 private final Class<T> itemClass; 58 private final SingleValuePropertyMetadata<T> itemMetadata; 59 private final List<T> defaultValue; 60 61 public ListValuePropertyMetadata(PropertyName name, 62 Class<T> itemClass, SingleValuePropertyMetadata<T> itemMetadata, 63 boolean readWrite, List<T> defaultValue, InspectorPath inspectorPath) { 64 super(name, readWrite, inspectorPath); 65 this.itemClass = itemClass; 66 this.defaultValue = defaultValue; 67 this.itemMetadata = itemMetadata; 68 } 69 70 public Class<T> getItemClass() { 71 return itemClass; 72 } 73 74 public List<T> getDefaultValue() { 75 return defaultValue; 76 } 77 78 public List<T> getValue(FXOMInstance fxomInstance) { 79 final List<T> result; 80 81 if (isReadWrite()) { 82 final FXOMProperty fxomProperty = fxomInstance.getProperties().get(getName()); 83 if (fxomProperty == null) { 84 // propertyName is not specified in the fxom instance. 85 // We return the default value specified in the metadata of the 86 // property 87 result = defaultValue; 88 } else if (fxomProperty instanceof FXOMPropertyT) { 89 final FXOMPropertyT fxomPropertyT = (FXOMPropertyT) fxomProperty; 90 final PrefixedValue pv = new PrefixedValue(fxomPropertyT.getValue()); 91 if (pv.isBindingExpression()) { 92 result = getDefaultValue(); 93 } else { 94 result = makeValueFromString(fxomPropertyT.getValue()); 95 } 96 } else if (fxomProperty instanceof FXOMPropertyC) { 97 final FXOMPropertyC fxomPropertyC = (FXOMPropertyC) fxomProperty; 98 result = new ArrayList<>(); 99 for (FXOMObject itemFxomObject : fxomPropertyC.getValues()) { 100 if (itemFxomObject instanceof FXOMInstance) { 101 final FXOMInstance itemFxomInstance = (FXOMInstance) itemFxomObject; 102 result.add(itemMetadata.makeValueFromFxomInstance(itemFxomInstance)); 103 } else { 104 assert false; 105 } 106 } 107 } else { 108 assert false; 109 result = defaultValue; 110 } 111 } else { 112 final List<?> items = (List<?>)getName().getValue(fxomInstance.getSceneGraphObject()); 113 result = new ArrayList<>(); 114 for (Object item : items) { 115 result.add(getItemClass().cast(item)); 116 } 117 } 118 119 return result; 120 } 121 122 public void setValue(FXOMInstance fxomInstance, List<T> value) { 123 assert isReadWrite(); 124 125 final FXOMProperty fxomProperty = fxomInstance.getProperties().get(getName()); 126 127 if (Objects.equals(value, getDefaultValueObject()) || value.isEmpty()) { 128 // We must remove the fxom property if any 129 if (fxomProperty != null) { 130 fxomProperty.removeFromParentInstance(); 131 } 132 } else { 133 final FXOMDocument fxomDocument = fxomInstance.getFxomDocument(); 134 final FXOMProperty newProperty; 135 if (canMakeStringFromValue(value)) { 136 final String valueString = makeStringFromValue(value); 137 newProperty = new FXOMPropertyT(fxomDocument, getName(), valueString); 138 } else { 139 final List<FXOMObject> items = new ArrayList<>(); 140 for (T i : value) { 141 items.add(itemMetadata.makeFxomInstanceFromValue(i, fxomDocument)); 142 } 143 newProperty = new FXOMPropertyC(fxomDocument, getName(), items); 144 } 145 FXOMNodes.updateProperty(fxomInstance, newProperty); 146 } 147 } 148 149 150 /* 151 * To be subclassed 152 */ 153 154 protected boolean canMakeStringFromValue(List<T> value) { 155 boolean result = true; 156 157 for (T i : value) { 158 result = itemMetadata.canMakeStringFromValue(i); 159 if (result == false) { 160 break; 161 } 162 } 163 164 return result; 165 } 166 167 protected String makeStringFromValue(List<T> value) { 168 assert canMakeStringFromValue(value); 169 170 final StringBuilder result = new StringBuilder(); 171 172 for (T item : value) { 173 if (result.length() >= 1) { 174 result.append(FXMLLoader.ARRAY_COMPONENT_DELIMITER); 175 result.append(' '); 176 } 177 result.append(itemMetadata.makeStringFromValue(item)); 178 } 179 180 return result.toString(); 181 } 182 183 184 protected List<T> makeValueFromString(String string) { 185 final List<T> result; 186 187 final String[] items = string.split(FXMLLoader.ARRAY_COMPONENT_DELIMITER); 188 if (items.length == 0) { 189 result = Collections.emptyList(); 190 } else { 191 result = new ArrayList<>(); 192 for (String itemString : items) { 193 result.add(itemMetadata.makeValueFromString(itemString)); 194 } 195 } 196 197 return result; 198 } 199 200 /* 201 * ValuePropertyMetadata 202 */ 203 204 @Override 205 public Class<?> getValueClass() { 206 return List.class; 207 } 208 209 @Override 210 public Object getDefaultValueObject() { 211 return defaultValue; 212 } 213 214 @Override 215 public Object getValueObject(FXOMInstance fxomInstance) { 216 return getValue(fxomInstance); 217 } 218 219 @Override 220 public void setValueObject(FXOMInstance fxomInstance, Object valueObject) { 221 assert valueObject instanceof List; 222 setValue(fxomInstance, castItemList((List<?>)valueObject)); 223 } 224 225 /* 226 * Private 227 */ 228 229 private List<T> castItemList(List<?> valueObject) { 230 final List<T> result = new ArrayList<>(); 231 232 for (Object itemValueObject : valueObject) { 233 result.add(getItemClass().cast(itemValueObject)); 234 } 235 236 return result; 237 } 238 }