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 33 package com.oracle.javafx.scenebuilder.kit.editor.job.reference; 34 35 import com.oracle.javafx.scenebuilder.kit.editor.EditorController; 36 import com.oracle.javafx.scenebuilder.kit.editor.job.Job; 37 import com.oracle.javafx.scenebuilder.kit.editor.job.atomic.RemoveNodeJob; 38 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMCloner; 39 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMCollection; 40 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; 41 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance; 42 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMIntrinsic; 43 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNode; 44 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNodes; 45 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; 46 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMProperty; 47 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyC; 48 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyT; 49 import com.oracle.javafx.scenebuilder.kit.metadata.util.PrefixedValue; 50 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName; 51 import com.oracle.javafx.scenebuilder.kit.util.JavaLanguage; 52 import java.util.HashSet; 53 import java.util.LinkedList; 54 import java.util.List; 55 import java.util.Map; 56 import java.util.Set; 57 58 /** 59 * 60 */ 61 public class ReferencesUpdater { 62 63 private final EditorController editorController; 64 private final FXOMDocument fxomDocument; 65 private final List<Job> executedJobs = new LinkedList<>(); 66 private final Set<String> declaredFxIds = new HashSet<>(); 67 private final FXOMCloner cloner; 68 69 public ReferencesUpdater(EditorController editorController) { 70 assert editorController != null; 71 assert editorController.getFxomDocument() != null; 72 this.editorController = editorController; 73 this.fxomDocument = editorController.getFxomDocument(); 74 this.cloner = new FXOMCloner(this.fxomDocument); 75 } 76 77 public void update() { 78 if (fxomDocument.getFxomRoot() != null) { 79 declaredFxIds.clear(); 80 update(fxomDocument.getFxomRoot()); 81 } 82 } 83 84 public List<Job> getExecutedJobs() { 85 return new LinkedList<>(executedJobs); 86 } 87 88 89 /* 90 * Private 91 */ 92 93 private void update(FXOMNode node) { 94 if (node instanceof FXOMCollection) { 95 updateCollection((FXOMCollection) node); 96 } else if (node instanceof FXOMInstance) { 97 updateInstance((FXOMInstance) node); 98 } else if (node instanceof FXOMIntrinsic) { 99 updateIntrinsic((FXOMIntrinsic) node); 100 } else if (node instanceof FXOMPropertyC) { 101 updatePropertyC((FXOMPropertyC) node); 102 } else if (node instanceof FXOMPropertyT) { 103 updatePropertyT((FXOMPropertyT) node); 104 } else { 105 throw new RuntimeException("Bug"); //NOI18N 106 } 107 } 108 109 110 private void updateCollection(FXOMCollection collection) { 111 if (collection.getFxId() != null) { 112 declaredFxIds.add(collection.getFxId()); 113 } 114 final List<FXOMObject> items = collection.getItems(); 115 for (int i = 0, count = items.size(); i < count; i++) { 116 update(items.get(i)); 117 } 118 } 119 120 121 private void updateInstance(FXOMInstance instance) { 122 if (instance.getFxId() != null) { 123 declaredFxIds.add(instance.getFxId()); 124 } 125 final Map<PropertyName, FXOMProperty> properties = instance.getProperties(); 126 final List<PropertyName> names = new LinkedList<>(properties.keySet()); 127 for (PropertyName propertyName : names) { 128 update(properties.get(propertyName)); 129 } 130 } 131 132 133 private void updateIntrinsic(FXOMIntrinsic intrinsic) { 134 switch(intrinsic.getType()) { 135 case FX_REFERENCE: 136 case FX_COPY: 137 updateReference(intrinsic, intrinsic.getSource()); 138 break; 139 default: 140 break; 141 } 142 } 143 144 145 private void updatePropertyC(FXOMPropertyC property) { 146 final List<FXOMObject> values = property.getValues(); 147 for (int i = 0, count = values.size(); i < count; i++) { 148 update(values.get(i)); 149 } 150 } 151 152 153 private void updatePropertyT(FXOMPropertyT property) { 154 final PrefixedValue pv = new PrefixedValue(property.getValue()); 155 if (pv.isExpression()) { 156 final String suffix = pv.getSuffix(); 157 if (JavaLanguage.isIdentifier(suffix)) { 158 updateReference(property, suffix); 159 } 160 } 161 } 162 163 164 private void updateReference(FXOMNode r, String fxId) { 165 assert (r instanceof FXOMPropertyT) || (r instanceof FXOMIntrinsic); 166 assert fxId != null; 167 168 if (declaredFxIds.contains(fxId) == false) { 169 // r is a forward reference 170 // 171 // 0) r is a toggleGroup reference 172 // => if toggle group exists, we swap it with the reference 173 // => if not, replace the reference by a new toggle group 174 // 1) r is a weak reference (like labelFor) 175 // => we remove the reference 176 // 2) else r is a strong reference 177 // => we expand the reference 178 179 180 final FXOMObject declarer = fxomDocument.searchWithFxId(fxId); 181 182 // 0) 183 if (FXOMNodes.isToggleGroupReference(r)) { 184 final Job fixJob = new FixToggleGroupReferenceJob(r, editorController); 185 fixJob.execute(); 186 executedJobs.add(fixJob); 187 declaredFxIds.add(fxId); 188 } 189 190 // 1 191 else if (FXOMNodes.isWeakReference(r) || (declarer == null)) { 192 final Job removeJob = new RemoveNodeJob(r, editorController); 193 removeJob.execute(); 194 executedJobs.add(removeJob); 195 196 // 2) 197 } else { 198 199 final Job expandJob = new ExpandReferenceJob(r, cloner, editorController); 200 expandJob.execute(); 201 executedJobs.add(expandJob); 202 } 203 } 204 } 205 206 }