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;
  33 
  34 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
  35 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
  36 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
  37 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMProperty;
  38 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyC;
  39 import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
  40 import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
  41 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
  42 import java.util.Objects;
  43 import javafx.util.Callback;
  44 
  45 /**
  46  *
  47  */
  48 
  49 public abstract class CallbackPropertyMetadata extends ValuePropertyMetadata {
  50 
  51     private final Object defaultValue;
  52 
  53     public CallbackPropertyMetadata(PropertyName name, boolean readWrite, Object defaultValue, InspectorPath inspectorPath) {
  54         super(name, readWrite, inspectorPath);
  55         this.defaultValue = defaultValue;
  56     }
  57 
  58     public Object getDefaultValue() {
  59         return defaultValue;
  60     }
  61 
  62     public Object getValue(FXOMInstance fxomInstance) {
  63         final Object result;
  64 
  65         if (isReadWrite()) {
  66             final FXOMProperty fxomProperty = fxomInstance.getProperties().get(getName());
  67             if (fxomProperty instanceof FXOMPropertyC) {
  68 
  69                 final FXOMPropertyC fxomPropertyC = (FXOMPropertyC) fxomProperty;
  70                 assert fxomPropertyC.getValues().size() == 1;
  71 
  72                 final FXOMObject valueFxomObject = fxomPropertyC.getValues().get(0);
  73                 final Object sceneGraphObject = valueFxomObject.getSceneGraphObject();
  74 
  75                 result = castValue(sceneGraphObject);
  76             } else {
  77                 assert fxomProperty == null;
  78 
  79                 // propertyName is not specified in the fxom instance.
  80                 // We return the default value specified in the metadata of the
  81                 // property
  82                 result = defaultValue;
  83             }
  84         } else {
  85             result = castValue(getName().getValue(fxomInstance.getSceneGraphObject()));
  86         }
  87 
  88         return result;
  89     }
  90 
  91     public void setValue(FXOMInstance fxomInstance, Object value) {
  92         assert isReadWrite();
  93 
  94         final FXOMProperty fxomProperty = fxomInstance.getProperties().get(getName());
  95 
  96         if (Objects.equals(value, getDefaultValueObject())) {
  97             // We must remove the fxom property if any
  98             if (fxomProperty != null) {
  99                 fxomProperty.removeFromParentInstance();
 100             }
 101         } else {
 102             if (fxomProperty == null) {
 103                 // propertyName is not specified in the fxom instance.
 104                 // We insert a new fxom property
 105                 final FXOMProperty newProperty
 106                         = makeFxomPropertyFromValue(fxomInstance, value);
 107                 newProperty.addToParentInstance(-1, fxomInstance);
 108             } else {
 109                 updateFxomPropertyWithValue(fxomProperty, value);
 110             }
 111         }
 112     }
 113 
 114 
 115     protected abstract void updateFxomInstanceWithValue(FXOMInstance valueInstance, Object value);
 116     protected abstract Class<?> getFxConstantClass();
 117     protected abstract Object castValue(Object value);
 118 
 119 
 120 
 121 
 122     /*
 123      * ValuePropertyMetadata
 124      */
 125 
 126     @Override
 127     public Class<?> getValueClass() {
 128         return Callback.class;
 129     }
 130 
 131     @Override
 132     public Object getDefaultValueObject() {
 133         return defaultValue;
 134     }
 135 
 136     @Override
 137     public Object getValueObject(FXOMInstance fxomInstance) {
 138         return getValue(fxomInstance);
 139     }
 140 
 141     @Override
 142     public void setValueObject(FXOMInstance fxomInstance, Object valueObject) {
 143         setValue(fxomInstance, castValue(valueObject));
 144     }
 145 
 146 
 147     /*
 148      * Private
 149      */
 150 
 151     protected FXOMProperty makeFxomPropertyFromValue(FXOMInstance fxomInstance, Object value) {
 152         assert fxomInstance != null;
 153         assert value != null;
 154 
 155         final FXOMDocument fxomDocument = fxomInstance.getFxomDocument();
 156         final FXOMInstance valueInstance = new FXOMInstance(fxomDocument, getFxConstantClass());
 157         updateFxomInstanceWithValue(valueInstance, value);
 158         return new FXOMPropertyC(fxomDocument, getName(), valueInstance);
 159     }
 160 
 161     protected void updateFxomPropertyWithValue(FXOMProperty fxomProperty, Object value) {
 162         assert value != null;
 163         assert fxomProperty instanceof FXOMPropertyC; // Because Callback are expressed using fx:constant
 164 
 165         final FXOMPropertyC fxomPropertyC = (FXOMPropertyC) fxomProperty;
 166         assert fxomPropertyC.getValues().size() == 1;
 167 
 168         FXOMObject valueObject = fxomPropertyC.getValues().get(0);
 169         if (valueObject instanceof FXOMInstance) {
 170             updateFxomInstanceWithValue((FXOMInstance) valueObject, value);
 171         } else {
 172             final FXOMDocument fxomDocument = fxomProperty.getFxomDocument();
 173             final FXOMInstance valueInstance = new FXOMInstance(fxomDocument, getFxConstantClass());
 174             updateFxomInstanceWithValue(valueInstance, value);
 175             valueInstance.addToParentProperty(0, fxomPropertyC);
 176             valueObject.removeFromParentProperty();
 177         }
 178     }
 179 
 180 }