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.editor.job.atomic.RemoveObjectJob; 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.FXOMNode; 43 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNodes; 44 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; 45 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMProperty; 46 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMPropertyC; 47 import java.util.LinkedList; 48 import java.util.List; 49 50 /** 51 */ 52 53 public class ObjectDeleter { 54 55 private final EditorController editorController; 56 private final FXOMDocument fxomDocument; 57 private final List<Job> executedJobs = new LinkedList<>(); 58 59 public ObjectDeleter(EditorController editorController) { 60 assert editorController != null; 61 assert editorController.getFxomDocument() != null; 62 this.editorController = editorController; 63 this.fxomDocument = editorController.getFxomDocument(); 64 } 65 66 public void delete(FXOMObject target) { 67 final FXOMNode node = prepareDeleteObject(target, target); 68 69 if (node == target) { 70 final RemoveObjectJob removeJob = new RemoveObjectJob(target, editorController); 71 removeJob.execute(); 72 executedJobs.add(removeJob); 73 } 74 } 75 76 public void prepareDelete(FXOMObject target) { 77 assert target != null; 78 assert target.getFxomDocument() == fxomDocument; 79 assert fxomDocument.getFxomRoot() != null; // At least target 80 81 prepareDeleteObject(target, target); 82 } 83 84 public List<Job> getExecutedJobs() { 85 return new LinkedList<>(executedJobs); 86 } 87 88 89 /* 90 * Private 91 */ 92 93 private FXOMNode prepareDeleteObject(FXOMObject node, FXOMObject target) { 94 final FXOMNode result; 95 96 final String nodeFxId = node.getFxId(); 97 if (nodeFxId == null) { 98 // node has no fx:id : it can be deleted safely 99 result = node; 100 } else { 101 final FXOMObject fxomRoot = fxomDocument.getFxomRoot(); 102 final List<FXOMNode> references = fxomRoot.collectReferences(nodeFxId, target); 103 if (references.isEmpty()) { 104 // node has an fx:id but this one is not referenced 105 // outside of the delete target : it can be deleted safely 106 result = node; 107 } else { 108 // node has an fx:id referenced outside of the delete target 109 // => we find the first strong reference R to it 110 // => we remove all the weak references between node and R 111 // => we combine node with R 112 FXOMNode firstReference = null; 113 for (FXOMNode r : references) { 114 if (FXOMNodes.isWeakReference(r)) { 115 // This weak reference will become a forward reference 116 // after the deletion => we remove it. 117 final Job clearJob = new RemoveNodeJob(r, editorController); 118 clearJob.execute(); 119 executedJobs.add(clearJob); 120 } else { 121 firstReference = r; 122 break; 123 } 124 } 125 126 if (firstReference == null) { 127 // node has only weak references ; those references have 128 // been removed => node can be delete safely 129 result = node; 130 } else { 131 // we combine firstReference with node ie node is 132 // disconnected from its parent and put in place of 133 // firstReference 134 final Job combineJob = new CombineReferenceJob(firstReference, editorController); 135 combineJob.execute(); 136 executedJobs.add(combineJob); 137 result = null; 138 } 139 } 140 } 141 142 if (result == node) { 143 if (node instanceof FXOMInstance) { 144 final FXOMInstance fxomInstance = (FXOMInstance) node; 145 for (FXOMProperty p : new LinkedList<>(fxomInstance.getProperties().values())) { 146 if (p instanceof FXOMPropertyC) { 147 final FXOMPropertyC cp = (FXOMPropertyC) p; 148 for (FXOMObject value : new LinkedList<>(cp.getValues())) { 149 prepareDeleteObject(value, target); 150 } 151 } 152 } 153 } else if (result instanceof FXOMCollection) { 154 final FXOMCollection fxomCollection = (FXOMCollection) result; 155 for (FXOMObject i : new LinkedList<>(fxomCollection.getItems())) { 156 prepareDeleteObject(i, target); 157 } 158 } // else no prework needed 159 } 160 161 return result; 162 } 163 }