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.editor.drag.target;
  33 
  34 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
  35 import com.oracle.javafx.scenebuilder.kit.editor.drag.source.AbstractDragSource;
  36 import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
  37 import com.oracle.javafx.scenebuilder.kit.editor.job.BatchJob;
  38 import com.oracle.javafx.scenebuilder.kit.editor.job.InsertAsAccessoryJob;
  39 import com.oracle.javafx.scenebuilder.kit.editor.job.atomic.ModifyObjectJob;
  40 import com.oracle.javafx.scenebuilder.kit.editor.job.atomic.RemoveObjectJob;
  41 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
  42 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
  43 import com.oracle.javafx.scenebuilder.kit.metadata.property.value.EnumerationPropertyMetadata;
  44 import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask;
  45 import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask.Accessory;
  46 import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
  47 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
  48 import java.util.Objects;
  49 import javafx.geometry.Pos;
  50 import javafx.scene.layout.BorderPane;
  51 
  52 /**
  53  *
  54  */
  55 public class AccessoryDropTarget extends AbstractDropTarget {
  56 
  57     private final FXOMInstance targetContainer;
  58     private final Accessory accessory;
  59 
  60     public AccessoryDropTarget(FXOMInstance targetContainer, Accessory accessory) {
  61         assert targetContainer != null;
  62         this.targetContainer = targetContainer;
  63         this.accessory = accessory;
  64     }
  65 
  66     public Accessory getAccessory() {
  67         return accessory;
  68     }
  69 
  70 
  71     /*
  72      * AbstractDropTarget
  73      */
  74     @Override
  75     public FXOMObject getTargetObject() {
  76         return targetContainer;
  77     }
  78 
  79     @Override
  80     public boolean acceptDragSource(AbstractDragSource dragSource) {
  81         assert dragSource != null;
  82 
  83         final boolean result;
  84         if (dragSource.getDraggedObjects().size() != 1) {
  85             result = false;
  86         } else {
  87             final DesignHierarchyMask m = new DesignHierarchyMask(targetContainer);
  88             final FXOMObject draggedObject = dragSource.getDraggedObjects().get(0);
  89             result = m.isAcceptingAccessory(accessory, draggedObject)
  90                     && m.getAccessory(accessory) == null;
  91         }
  92 
  93         return result;
  94     }
  95 
  96     @Override
  97     public Job makeDropJob(AbstractDragSource dragSource, EditorController editorController) {
  98         assert acceptDragSource(dragSource);
  99         assert editorController != null;
 100 
 101         final boolean shouldRefreshSceneGraph = true;
 102         final BatchJob result = new BatchJob(editorController,
 103                 shouldRefreshSceneGraph, dragSource.makeDropJobDescription());
 104 
 105         final FXOMObject draggedObject = dragSource.getDraggedObjects().get(0);
 106         final FXOMObject currentParent = draggedObject.getParentObject();
 107 
 108         // Two steps :
 109         //  - remove drag source object from its current parent (if any)
 110         //  - set the drag source object as accessory of the drop target
 111 
 112         if (currentParent != null) {
 113             result.addSubJob(new RemoveObjectJob(draggedObject, editorController));
 114         }
 115         final Job j = new InsertAsAccessoryJob(draggedObject,
 116                 targetContainer, accessory, editorController);
 117         result.addSubJob(j);
 118 
 119         if ((targetContainer.getSceneGraphObject() instanceof BorderPane)
 120                 && (draggedObject instanceof FXOMInstance)) {
 121 
 122             // We add a job which sets BorderPane.alignment=CENTER on draggedObject
 123             final FXOMInstance draggedInstance
 124                     = (FXOMInstance) draggedObject;
 125             final PropertyName alignmentName
 126                     = new PropertyName("alignment", BorderPane.class); //NOI18N
 127             final EnumerationPropertyMetadata alignmentMeta
 128                     = new EnumerationPropertyMetadata(alignmentName, Pos.class,
 129                     "UNUSED", true /* readWrite */, InspectorPath.UNUSED); //NOI18N
 130             final Job alignmentJob
 131                     = new ModifyObjectJob(draggedInstance, alignmentMeta,
 132                             Pos.CENTER.toString(), editorController);
 133             result.addSubJob(alignmentJob);
 134         }
 135 
 136         assert result.isExecutable();
 137 
 138         return result;
 139     }
 140 
 141     @Override
 142     public boolean isSelectRequiredAfterDrop() {
 143         return true;
 144     }
 145 
 146     /*
 147      * Objects
 148      */
 149     @Override
 150     public int hashCode() {
 151         int hash = 3;
 152         hash = 97 * hash + Objects.hashCode(this.targetContainer);
 153         hash = 97 * hash + (this.accessory != null ? this.accessory.hashCode() : 0);
 154         return hash;
 155     }
 156 
 157     @Override
 158     public boolean equals(Object obj) {
 159         if (obj == null) {
 160             return false;
 161         }
 162         if (getClass() != obj.getClass()) {
 163             return false;
 164         }
 165         final AccessoryDropTarget other = (AccessoryDropTarget) obj;
 166         if (!Objects.equals(this.targetContainer, other.targetContainer)) {
 167             return false;
 168         }
 169         if (this.accessory != other.accessory) {
 170             return false;
 171         }
 172         return true;
 173     }
 174 
 175     @Override
 176     public String toString() {
 177         return "AccessoryDropTarget{" + "targetContainer=" + targetContainer + ", accessory=" + accessory + '}'; //NOI18N
 178     }
 179 
 180 
 181 }