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.job.gridpane;
  33 
  34 import com.oracle.javafx.scenebuilder.kit.editor.EditorController;
  35 import com.oracle.javafx.scenebuilder.kit.editor.job.BatchJob;
  36 import com.oracle.javafx.scenebuilder.kit.editor.job.Job;
  37 import com.oracle.javafx.scenebuilder.kit.editor.job.atomic.ModifyObjectJob;
  38 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
  39 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
  40 import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
  41 import com.oracle.javafx.scenebuilder.kit.metadata.Metadata;
  42 import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata;
  43 import com.oracle.javafx.scenebuilder.kit.metadata.util.DesignHierarchyMask;
  44 import com.oracle.javafx.scenebuilder.kit.metadata.util.PropertyName;
  45 import java.util.ArrayList;
  46 import java.util.List;
  47 
  48 /**
  49  * Job invoked when re-indexing rows content.
  50  *
  51  * IMPORTANT:
  52  * This job cannot extends BatchDocumentJob because its sub jobs list cannot be initialized lazily.
  53  */
  54 public class ReIndexRowContentJob extends Job {
  55 
  56     private BatchJob subJob;
  57     private final int offset;
  58     private final FXOMObject targetGridPane;
  59     private final List<Integer> targetIndexes;
  60 
  61     public ReIndexRowContentJob(
  62             final EditorController editorController,
  63             final int offset,
  64             final FXOMObject targetGridPane,
  65             final List<Integer> targetIndexes) {
  66         super(editorController);
  67         this.offset = offset;
  68         this.targetGridPane = targetGridPane;
  69         this.targetIndexes = targetIndexes;
  70         buildSubJobs();
  71     }
  72 
  73     public ReIndexRowContentJob(
  74             final EditorController editorController,
  75             final int offset,
  76             final FXOMObject targetGridPane,
  77             final int targetIndex) {
  78         super(editorController);
  79         this.offset = offset;
  80         this.targetGridPane = targetGridPane;
  81         this.targetIndexes = new ArrayList<>();
  82         this.targetIndexes.add(targetIndex);
  83         buildSubJobs();
  84     }
  85 
  86     @Override
  87     public boolean isExecutable() {
  88         // When the rows are empty, there is no content to move and the
  89         // sub job list may be empty.
  90         // => we do not invoke subJob.isExecutable() here.
  91         return subJob != null;
  92     }
  93 
  94     @Override
  95     public void execute() {
  96         final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
  97         assert isExecutable();
  98         fxomDocument.beginUpdate();
  99         subJob.execute();
 100         fxomDocument.endUpdate();
 101     }
 102 
 103     @Override
 104     public void undo() {
 105         final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
 106         fxomDocument.beginUpdate();
 107         subJob.undo();
 108         fxomDocument.endUpdate();
 109     }
 110 
 111     @Override
 112     public void redo() {
 113         final FXOMDocument fxomDocument = getEditorController().getFxomDocument();
 114         fxomDocument.beginUpdate();
 115         subJob.redo();
 116         fxomDocument.endUpdate();
 117     }
 118 
 119     @Override
 120     public String getDescription() {
 121         return "ReIndex Row Content"; //NOI18N
 122     }
 123 
 124     private void buildSubJobs() {
 125 
 126         // Create sub job
 127         subJob = new BatchJob(getEditorController(),
 128                 true /* shouldRefreshSceneGraph */, null);
 129 
 130         assert targetIndexes.isEmpty() == false;
 131         final DesignHierarchyMask targetGridPaneMask
 132                 = new DesignHierarchyMask(targetGridPane);
 133         final PropertyName propertyName = new PropertyName(
 134                 "rowIndex", javafx.scene.layout.GridPane.class); //NOI18N
 135 
 136         for (int targetIndex : targetIndexes) {
 137             final List<FXOMObject> children
 138                     = targetGridPaneMask.getRowContentAtIndex(targetIndex);
 139             for (FXOMObject child : children) {
 140                 assert child instanceof FXOMInstance;
 141                 final FXOMInstance childInstance = (FXOMInstance) child;
 142                 final ValuePropertyMetadata vpm = Metadata.getMetadata().
 143                         queryValueProperty(childInstance, propertyName);
 144                 int newIndexValue = targetIndex + offset;
 145                 final Job modifyJob = new ModifyObjectJob(
 146                         childInstance, vpm, newIndexValue, getEditorController());
 147                 subJob.addSubJob(modifyJob);
 148             }
 149         }
 150     }
 151 }