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.selection;
  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.value.IntegerPropertyMetadata;
  40 import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask;
  41 import com.oracle.javafx.scenebuilder.kit.metadata.util.InspectorPath;
  42 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
  43 import java.util.ArrayList;
  44 import java.util.Collections;
  45 import java.util.HashSet;
  46 import java.util.List;
  47 import java.util.Objects;
  48 import java.util.Set;
  49 import javafx.scene.layout.ColumnConstraints;
  50 import javafx.scene.layout.GridPane;
  51 import javafx.scene.layout.RowConstraints;
  52 
  53 /**
  54  *
  55  *
  56  */
  57 public class GridSelectionGroup extends AbstractSelectionGroup {
  58 
  59     public enum Type { ROW, COLUMN };
  60 
  61     private final FXOMObject parentObject;
  62     private final Type type;
  63     private final Set<Integer> indexes = new HashSet<>();
  64 
  65     public GridSelectionGroup(FXOMObject parentObject, Type type, int index) {
  66         assert parentObject != null;
  67         assert parentObject.getSceneGraphObject() instanceof GridPane;
  68         assert index >= 0;
  69 
  70         this.parentObject = parentObject;
  71         this.type = type;
  72         this.indexes.add(index);
  73     }
  74 
  75     public GridSelectionGroup(FXOMObject parentObject, Type type, Set<Integer> indexes) {
  76         assert parentObject != null;
  77         assert parentObject.getSceneGraphObject() instanceof GridPane;
  78         assert indexes != null;
  79         assert indexes.isEmpty() == false;
  80 
  81         this.parentObject = parentObject;
  82         this.type = type;
  83         this.indexes.addAll(indexes);
  84     }
  85 
  86     public FXOMObject getParentObject() {
  87         return parentObject;
  88     }
  89 
  90     public Type getType() {
  91         return type;
  92     }
  93 
  94     public Set<Integer> getIndexes() {
  95         return Collections.unmodifiableSet(indexes);
  96     }
  97 
  98     public List<FXOMInstance> collectConstraintInstances() {
  99         final List<FXOMInstance> result;
 100 
 101         switch(type) {
 102             case ROW:
 103                 result = collectRowConstraintsInstances();
 104                 break;
 105             case COLUMN:
 106                 result = collectColumnConstraintsInstances();
 107                 break;
 108             default:
 109                 throw new RuntimeException("Bug");
 110         }
 111 
 112         return result;
 113     }
 114 
 115     public List<FXOMObject> collectSelectedObjects() {
 116         final List<FXOMObject> result;
 117 
 118         switch(type) {
 119             case ROW:
 120                 result = collectSelectedObjectsInRow();
 121                 break;
 122             case COLUMN:
 123                 result = collectSelectedObjectsInColumn();
 124                 break;
 125             default:
 126                 throw new RuntimeException("Bug");
 127         }
 128 
 129         return result;
 130     }
 131 
 132     /*
 133      * AbstractSelectionGroup
 134      */
 135 
 136     @Override
 137     public FXOMObject getAncestor() {
 138         return parentObject;
 139     }
 140 
 141     @Override
 142     public boolean isValid(FXOMDocument fxomDocument) {
 143         assert fxomDocument != null;
 144 
 145         final boolean result;
 146         final FXOMObject fxomRoot = fxomDocument.getFxomRoot();
 147         if (fxomRoot == null) {
 148             result = false;
 149         } else {
 150             result = (parentObject == fxomRoot) || parentObject.isDescendantOf(fxomRoot);
 151         }
 152 
 153         return result;
 154     }
 155 
 156 
 157     /*
 158      * Cloneable
 159      */
 160     @Override
 161     public GridSelectionGroup clone() throws CloneNotSupportedException {
 162         return (GridSelectionGroup)super.clone();
 163     }
 164 
 165 
 166     /*
 167      * Object
 168      */
 169     @Override
 170     public int hashCode() {
 171         int hash = 7;
 172         hash = 47 * hash + Objects.hashCode(this.parentObject);
 173         hash = 47 * hash + Objects.hashCode(this.type);
 174         hash = 47 * hash + Objects.hashCode(this.indexes);
 175         return hash;
 176     }
 177 
 178     @Override
 179     public boolean equals(Object obj) {
 180         if (obj == null) {
 181             return false;
 182         }
 183         if (getClass() != obj.getClass()) {
 184             return false;
 185         }
 186         final GridSelectionGroup other = (GridSelectionGroup) obj;
 187         if (!Objects.equals(this.parentObject, other.parentObject)) {
 188             return false;
 189         }
 190         if (this.type != other.type) {
 191             return false;
 192         }
 193         if (!Objects.equals(this.indexes, other.indexes)) {
 194             return false;
 195         }
 196         return true;
 197     }
 198 
 199 
 200     /*
 201      * Private
 202      */
 203 
 204     static private final PropertyName rowConstraintsName
 205             = new PropertyName("rowConstraints");
 206 
 207     private List<FXOMInstance> collectRowConstraintsInstances() {
 208         final List<FXOMInstance> result = new ArrayList<>();
 209 
 210         final FXOMInstance gridPaneInstance
 211                 = (FXOMInstance) parentObject;
 212         final FXOMProperty fxomProperty
 213                 = gridPaneInstance.getProperties().get(rowConstraintsName);
 214         if (fxomProperty != null) {
 215             assert fxomProperty instanceof FXOMPropertyC;
 216             final FXOMPropertyC fxomPropertyC = (FXOMPropertyC) fxomProperty;
 217             int index = 0;
 218             for (FXOMObject v : fxomPropertyC.getValues()) {
 219                 assert v.getSceneGraphObject() instanceof RowConstraints;
 220                 assert v instanceof FXOMInstance;
 221                 if (indexes.contains(index++)) {
 222                     result.add((FXOMInstance)v);
 223                 }
 224             }
 225         }
 226 
 227         return result;
 228     }
 229 
 230     static private final PropertyName columnConstraintsName
 231             = new PropertyName("columnConstraints");
 232 
 233     private List<FXOMInstance> collectColumnConstraintsInstances() {
 234         final List<FXOMInstance> result = new ArrayList<>();
 235 
 236         final FXOMInstance gridPaneInstance
 237                 = (FXOMInstance) parentObject;
 238         final FXOMProperty fxomProperty
 239                 = gridPaneInstance.getProperties().get(columnConstraintsName);
 240         if (fxomProperty != null) {
 241             assert fxomProperty instanceof FXOMPropertyC;
 242             final FXOMPropertyC fxomPropertyC = (FXOMPropertyC) fxomProperty;
 243             int index = 0;
 244             for (FXOMObject v : fxomPropertyC.getValues()) {
 245                 assert v.getSceneGraphObject() instanceof ColumnConstraints;
 246                 assert v instanceof FXOMInstance;
 247                 if (indexes.contains(index++)) {
 248                     result.add((FXOMInstance)v);
 249                 }
 250             }
 251         }
 252 
 253         return result;
 254     }
 255 
 256 
 257     private static final IntegerPropertyMetadata columnIndexMeta =
 258             new IntegerPropertyMetadata(
 259                 new PropertyName("columnIndex", GridPane.class), //NOI18N
 260                 true, /* readWrite */
 261                 0, /* defaultValue */
 262                 InspectorPath.UNUSED);
 263 
 264     private List<FXOMObject> collectSelectedObjectsInColumn() {
 265         final List<FXOMObject> result = new ArrayList<>();
 266 
 267         final DesignHierarchyMask m = new DesignHierarchyMask(parentObject);
 268         assert m.isAcceptingSubComponent();
 269 
 270         for (int i = 0, count = m.getSubComponentCount(); i <  count; i++) {
 271             final FXOMObject childObject = m.getSubComponentAtIndex(i);
 272             if (childObject instanceof FXOMInstance) {
 273                 final FXOMInstance childInstance = (FXOMInstance) childObject;
 274                 if (indexes.contains(columnIndexMeta.getValue(childInstance))) {
 275                     // child belongs to a selected column
 276                     result.add(childInstance);
 277                 }
 278             }
 279         }
 280 
 281         return result;
 282     }
 283 
 284     private static final IntegerPropertyMetadata rowIndexMeta =
 285             new IntegerPropertyMetadata(
 286                 new PropertyName("rowIndex", GridPane.class), //NOI18N
 287                 true, /* readWrite */
 288                 0, /* defaultValue */
 289                 InspectorPath.UNUSED);
 290 
 291     private List<FXOMObject> collectSelectedObjectsInRow() {
 292         final List<FXOMObject> result = new ArrayList<>();
 293 
 294         final DesignHierarchyMask m = new DesignHierarchyMask(parentObject);
 295         assert m.isAcceptingSubComponent();
 296 
 297         for (int i = 0, count = m.getSubComponentCount(); i <  count; i++) {
 298             final FXOMObject childObject = m.getSubComponentAtIndex(i);
 299             if (childObject instanceof FXOMInstance) {
 300                 final FXOMInstance childInstance = (FXOMInstance) childObject;
 301                 if (indexes.contains(rowIndexMeta.getValue(childInstance))) {
 302                     // child belongs to a selected column
 303                     result.add(childInstance);
 304                 }
 305             }
 306         }
 307 
 308         return result;
 309     }
 310 
 311 }