Browse Source

Fixes #41 - Completely change structure to use Index.ArrayChildren and implement overrides to recalculate the Spline properly

MeFisto94 9 years ago
parent
commit
f4d5d44d84

+ 1 - 5
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeMotionPath.java

@@ -229,6 +229,7 @@ public class JmeMotionPath extends AbstractSceneExplorerNode {
     
     
     public void refreshChildren() {
     public void refreshChildren() {
         ((JmeVector3fChildren)this.jmeChildren).refreshChildren(true);
         ((JmeVector3fChildren)this.jmeChildren).refreshChildren(true);
+        updateSpline(false);
     }
     }
     
     
     @Override
     @Override
@@ -240,11 +241,6 @@ public class JmeMotionPath extends AbstractSceneExplorerNode {
         ((AbstractSceneExplorerNode) getParentNode()).refresh(true);
         ((AbstractSceneExplorerNode) getParentNode()).refresh(true);
     }
     }
     
     
-    public void removeWaypoint(JmeVector3f jme) {
-        motionPath.removeWayPoint(jme.getVector3f()); // We need to clear this or else the keys will still have that Vector3f.
-        // Also we should modify the motionPath instead of just showing the changes ;)
-    }
-    
     public void enableDebugShapes() {
     public void enableDebugShapes() {
         for (Node n : getChildren().getNodes()) {
         for (Node n : getChildren().getNodes()) {
             if (n instanceof JmeVector3f) {
             if (n instanceof JmeVector3f) {

+ 3 - 3
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeVector3f.java

@@ -47,6 +47,7 @@ import org.openide.actions.DeleteAction;
 import org.openide.actions.MoveDownAction;
 import org.openide.actions.MoveDownAction;
 import org.openide.actions.MoveUpAction;
 import org.openide.actions.MoveUpAction;
 import org.openide.loaders.DataObject;
 import org.openide.loaders.DataObject;
+import org.openide.nodes.Node;
 import org.openide.nodes.Sheet;
 import org.openide.nodes.Sheet;
 import org.openide.util.actions.SystemAction;
 import org.openide.util.actions.SystemAction;
 
 
@@ -199,20 +200,19 @@ public class JmeVector3f extends JmeSpatial {
     @Override
     @Override
     public void destroy() throws IOException {
     public void destroy() throws IOException {
         detachBox(spatial);
         detachBox(spatial);
-        jmeMotionPath.updateSpline(true);
         
         
         /* These are mandatory:
         /* These are mandatory:
          * Without them the Node looks like it's undeletable
          * Without them the Node looks like it's undeletable
          * (since it stays in the Motion Path and gets readded everytime)
          * (since it stays in the Motion Path and gets readded everytime)
          */
          */
-        jmeMotionPath.removeWaypoint(this);
+        parent.remove(new Node[] { this });
         parent.refreshChildren(true);
         parent.refreshChildren(true);
+        jmeMotionPath.updateSpline(true);
         super.destroy();
         super.destroy();
     }
     }
 
 
 // </editor-fold>
 // </editor-fold>
     
     
-    
     /* For Properties */
     /* For Properties */
     public int getChildIndex() {
     public int getChildIndex() {
         int idx = parent.indexOf(this);
         int idx = parent.indexOf(this);

+ 96 - 163
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeVector3fChildren.java

@@ -31,22 +31,17 @@
  */
  */
 package com.jme3.gde.core.sceneexplorer.nodes;
 package com.jme3.gde.core.sceneexplorer.nodes;
 
 
-import com.jme3.cinematic.MotionPath;
 import com.jme3.gde.core.scene.SceneApplication;
 import com.jme3.gde.core.scene.SceneApplication;
-import com.jme3.gde.core.scene.controller.SceneToolController;
-import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
+import com.jme3.math.Spline;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
+import java.util.logging.Logger;
 import java.util.ArrayList;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutionException;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
+import java.util.logging.Level;
 import org.openide.loaders.DataObject;
 import org.openide.loaders.DataObject;
-import org.openide.nodes.Children;
 import org.openide.nodes.Index;
 import org.openide.nodes.Index;
 import org.openide.nodes.Node;
 import org.openide.nodes.Node;
 import org.openide.util.Exceptions;
 import org.openide.util.Exceptions;
@@ -58,13 +53,10 @@ import org.openide.util.Exceptions;
  * It will use this class as Children (which are JmeMotionPaths)<br>
  * It will use this class as Children (which are JmeMotionPaths)<br>
  * @author MeFisto94
  * @author MeFisto94
  */
  */
-public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Index {
+public class JmeVector3fChildren extends Index.ArrayChildren {
 
 
     protected JmeMotionPath jmeMotionPath;
     protected JmeMotionPath jmeMotionPath;
     protected boolean readOnly = true;
     protected boolean readOnly = true;
-    
-    protected List<Vector3f> keys;
-    protected LinkedList<ChangeListener> listeners = new LinkedList<ChangeListener>();
     private DataObject dataObject;
     private DataObject dataObject;
 
 
     public JmeVector3fChildren() {
     public JmeVector3fChildren() {
@@ -75,22 +67,16 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
     }
     }
 
 
     public void refreshChildren(boolean immediate) {
     public void refreshChildren(boolean immediate) {
-        keys = createKeys();
-        setKeys(keys);
         refresh();
         refresh();
+        for (Node n : getNodes()) {
+            n.setDisplayName("Waypoint " + indexOf(n));
+        }
     }
     }
 
 
     public void setReadOnly(boolean cookie) {
     public void setReadOnly(boolean cookie) {
         this.readOnly = cookie;
         this.readOnly = cookie;
     }
     }
 
 
-    @Override
-    protected void addNotify() {
-        super.addNotify();
-        keys = createKeys();
-        setKeys(keys);
-    }
-
     protected List<Vector3f> createKeys() {
     protected List<Vector3f> createKeys() {
         try {
         try {
             return SceneApplication.getApplication().enqueue(new Callable<List<Vector3f>>() {
             return SceneApplication.getApplication().enqueue(new Callable<List<Vector3f>>() {
@@ -114,14 +100,66 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
         }
         }
         return null;
         return null;
     }
     }
-    
+   
+    /**
+     * This is called when Index.ArrayChildren initiates it's list.
+     * It's similar to createNodes and createKeys.
+     * @return 
+     */
     @Override
     @Override
-    protected Node[] createNodes(Vector3f key) {
-        Node n = new JmeVector3f(this, jmeMotionPath, key).setReadOnly(readOnly);
-        n.setDisplayName("Waypoint " + keys.indexOf(key));
-        return new Node[]{ n };
+    protected List<Node> initCollection() {
+        List<Vector3f> keyList = createKeys();
+        ArrayList<Node> nodeList = new ArrayList<Node>(keyList.size());
+        int i = 0;
+        
+        for (Vector3f v: keyList) {
+            Node n = new JmeVector3f(this, jmeMotionPath, v).setReadOnly(readOnly);
+            n.setDisplayName("Waypoint " + i);
+            nodeList.add(n);
+            i++;
+        }
+        
+        return nodeList;
     }
     }
 
 
+    @Override
+    public boolean remove(Node[] arr) {
+        for (Node n : arr) {
+            jmeMotionPath.getMotionPath().removeWayPoint(((JmeVector3f)n).getVector3f());
+        }
+        
+        return super.remove(arr);
+    }
+
+    @Override
+    public boolean add(Node[] arr) {
+        for (Node n: arr) {
+            //DON'T USE THIS -> jmeMotionPath.getMotionPath().addWayPoint(v);
+            // It will clone v and as such we're not able to change it anymore.
+            //jmeMotionPath.getMotionPath().getSpline().getControlPoints().add(((JmeVector3f)n).getVector3f());
+            addControlPoint(jmeMotionPath.getMotionPath().getSpline(), ((JmeVector3f)n).getVector3f());
+            // Alternative could be nodes = initCollection()
+        }
+        
+        return super.add(arr);
+    }
+    
+    /* Code taken from Spline.java, except the clone part */
+    private void addControlPoint(Spline spline, Vector3f controlPoint) {
+        List<Vector3f> controlPoints = spline.getControlPoints();
+        if (controlPoints.size() > 2 && spline.isCycle()) {
+            controlPoints.remove(controlPoints.size() - 1);
+        }
+        controlPoints.add(controlPoint);
+        if (controlPoints.size() >= 2 && spline.isCycle()) {
+            controlPoints.add(controlPoints.get(0).clone());
+        }
+        if (controlPoints.size() > 1) {
+            // spline.computeTotalLength();
+            spline.setCurveTension(spline.getCurveTension());
+        }
+    }
+    
     /**
     /**
      * This Method is used because before createNodes takes place we are called by the default constructor and have to pass things...
      * This Method is used because before createNodes takes place we are called by the default constructor and have to pass things...
      * @param jmeMotionPath The JmeMotionPath instance which is this nodes parent. 
      * @param jmeMotionPath The JmeMotionPath instance which is this nodes parent. 
@@ -137,135 +175,33 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
         this.dataObject = dataObject;
         this.dataObject = dataObject;
     }
     }
 
 
-    @Override
-    public int indexOf(Node node) {
-        Vector3f key = node.getLookup().lookup(Vector3f.class); // reverseLookup.get(node);
-        
-        if (key == null)
-            return -1;
-        
-        return keys.indexOf(key); // For this to work, keys has to have ALWAYS be in sync for EVERY Change to the MotionPath.Waypoints
-    }
-
-    /**
-     * &quot;Invoke a dialog for reordering the children.&quot;
+    /* Basically we should override everything from Index.ArrayChildren, but it's no fun and since we don't support dragging them (which could need exchange()
+     * we just stick with this way :P
      */
      */
-    @Override
-    public void reorder() {
-        // We wont...
-    }
-
-    /**
-     * Reorder all children with a given permutation.
-     * TODO: Test this....
-     * @param perm - permutation with the length of current nodes. The permutation lists the new positions of the original nodes, that is, for nodes [A,B,C,D] and permutation [0,3,1,2], the final order would be [A,C,D,B].
-     * @throws IllegalArgumentException - if the permutation is not valid
-     */
-    @Override
-    public void reorder(int[] perm) {
-        List<Vector3f> oldKeys = Arrays.asList((Vector3f[])keys.toArray());
-        
-        for (int i = 0; i < perm.length; i++) {
-            keys.get(i).set(oldKeys.get(perm[i]));
-        }
-        
-        triggerChangeListeners();
-        
-        for (Node n: getNodes()) {
-            ((JmeVector3f)n).moveBox();
-        }
-    }
-
-    /**
-     * Move the element at the x-th position to the y-th position. All elements after the y-th position are moved down.
-     * @param x the position to remove the element from
-     * @param y the position to insert the element to
-     */
-    @Override
-    public void move(int x, int y) {
-        MotionPath m = jmeMotionPath.getMotionPath();
-        /* TODO: Check and Implement Method correctly. */
-        if (x < y) { /* X above Y, means: remove x, shift everything until y up, move everything from y one down. set x to y's value. */
-            Vector3f v_x = keys.get(x).clone(); // We can't use remove() because of the MotionPaths
-            for (int i = x+1; i <= y - 1; i++) {
-                moveUp(i); // This causes quite some rendering updates and messes up the selection, but when it's there, we use it.
-            }
-            
-            for (int i = keys.size() - 2; i >= y; i--) {
-                moveDown(i);
-            }
-            
-            keys.get(y).set(v_x);
-        } else { /* X below Y, means: remove x, shift everything until end up, move everyting from x one down. set y to x's value */
-            // TODO IMPLEMENT
-        }
-        
-        triggerChangeListeners();
-    }
-
+    
     /**
     /**
-     * Exchange two elements.
-     * @param x Position of the first Element
-     * @param y Position of the second Element
+     * Move an element up
+     * @param i index of element to move up
      */
      */
     @Override
     @Override
-    public void exchange(int x, int y) {
-        
-        /**
-         * There are two ways to achieve this Exchange. Keep in mind we actually have two lists:
-         * We have the "keys" and the motionPaths Waypoints (controlPoints). In order to exchange, we have:
-         * 
-         * Method A: Exchanging the Vector3f Reference in BOTH keys and motionPaths (this basically means reordering them, really!)
-         *           This is problematic, because MotionPath doesn't support accessing it's list.
-         * 
-         * Method B: Exchanging the Vector3f's Values. This means The upper Node (Waypoint) will still be the upper, but it's contents just change
-         *           This is easy to achieve using Vector3f#set(). The downside is that that since the keys have not been altered, they aren't recreated.
-         *           We will just call the apropriate update Methods for the Visual Representations.
-         *           Note: I don't know yet what netbeans thinks of Method B. Probably we need ugly reflection and Method A.
-         */
-        
-        /* Clone because the contents will be altered */
-        Vector3f v_x = keys.get(x).clone();
-        Vector3f v_y = keys.get(y).clone();
-        
-        // Exchange keys
-        /* METHOD A:
-        //keys.set(x, v_y);
-        //keys.set(y, v_x);*/
-        
-        keys.get(x).set(v_y);
-        keys.get(y).set(v_x);
+    public void moveUp(int i) {
+        super.moveUp(i);
         
         
-        MotionPath m = jmeMotionPath.getMotionPath();
+        List<Vector3f> controlPoints = jmeMotionPath.getMotionPath().getSpline().getControlPoints();
         
         
-        // Exchange Waypoints
-        // This only works because waypoint y == keys.y (v_y). If this isn't true we messed up somewhere, really hard.
-        // it would mean that the saved Motion Path derives from the shown...
+        if (i < 1 || i > controlPoints.size())
+            throw new IndexOutOfBoundsException();
         
         
-        m.getWayPoint(x).set(v_y);
-        m.getWayPoint(y).set(v_x);
+        Vector3f element = controlPoints.get(i);
+        Vector3f over_element = controlPoints.get(i - 1);
         
         
+        controlPoints.set(i - 1, element);
+        controlPoints.set(i, over_element);
         
         
-        /* Let the nodes know that their content has been changed */
-        ((JmeVector3f)getNodeAt(x)).moveBox();
-        ((JmeVector3f)getNodeAt(y)).moveBox();
-        //jmeMotionPath.updateSpline(true);// MoveBox calls UpdateSpline
+        jmeMotionPath.getMotionPath().getSpline().setType(jmeMotionPath.getMotionPath().getSpline().getType()); // retrigger some internal computations
         
         
-        // Netbeans API wants that.
-        triggerChangeListeners();
-        SceneExplorerTopComponent.findInstance().setSelectedNode((AbstractSceneExplorerNode)getNodeAt(y)); // Speak: "Replace X with Y"
-    }
-
-    /**
-     * Move an element up
-     * @param i index of element to move up
-     */
-    @Override
-    public void moveUp(int i) {
-        if (i <= 0 || i >= keys.size()) // Can't move up
-            throw new IndexOutOfBoundsException(); 
-        
-        exchange(i, i-1); // Clever Code reusing, huh? ;)
+        refreshChildren(true);
+        jmeMotionPath.updateSpline(true);
     }
     }
 
 
     /**
     /**
@@ -274,25 +210,22 @@ public class JmeVector3fChildren extends Children.Keys<Vector3f> implements Inde
      */
      */
     @Override
     @Override
     public void moveDown(int i) {
     public void moveDown(int i) {
-        if (i < 0 || i >= keys.size() - 1)
+        super.moveDown(i);
+        List<Vector3f> controlPoints = jmeMotionPath.getMotionPath().getSpline().getControlPoints();
+        
+        if (i < 0 || i >= controlPoints.size())
             throw new IndexOutOfBoundsException();
             throw new IndexOutOfBoundsException();
         
         
-        exchange(i, i+1); // moveUp(i+1); wouldn't respect the setSelectedNode
-    }
-    
-    private void triggerChangeListeners() {
-        for (ChangeListener cl : listeners) {
-            cl.stateChanged(new ChangeEvent(this));
-        }
-    }
-
-    @Override
-    public void addChangeListener(ChangeListener cl) {
-        listeners.add(cl);
-    }
-
-    @Override
-    public void removeChangeListener(ChangeListener cl) {
-        listeners.remove(cl);
+        Vector3f element = controlPoints.get(i);
+        Vector3f under_element = controlPoints.get(i + 1);
+        
+        controlPoints.set(i + 1, element);
+        controlPoints.set(i, under_element);
+        
+        jmeMotionPath.getMotionPath().getSpline().setType(jmeMotionPath.getMotionPath().getSpline().getType()); // retrigger some internal computations
+        
+        
+        refreshChildren(true);
+        jmeMotionPath.updateSpline(true);
     }
     }
 }
 }

+ 5 - 2
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/MotionPathPopup.java

@@ -37,13 +37,14 @@ import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
 import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode;
 import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeMotionPath;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeMotionPath;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeVector3f;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeVector3f;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeVector3fChildren;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
-import com.jme3.scene.Node;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionEvent;
 import javax.swing.AbstractAction;
 import javax.swing.AbstractAction;
 import javax.swing.JMenu;
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
 import javax.swing.JMenuItem;
 import org.openide.loaders.DataObject;
 import org.openide.loaders.DataObject;
+import org.openide.nodes.Node;
 import org.openide.util.actions.Presenter;
 import org.openide.util.actions.Presenter;
 
 
 /**
 /**
@@ -117,7 +118,9 @@ public class MotionPathPopup extends AbstractAction implements Presenter.Popup {
                     }
                     }
                 }
                 }
                 
                 
-                jmeMotionPath.getMotionPath().addWayPoint(pos);
+                JmeVector3fChildren children = (JmeVector3fChildren)jmeMotionPath.getChildren();
+                JmeVector3f jme = new JmeVector3f(children, jmeMotionPath, pos);
+                children.add(new Node[] {jme});
                 jmeMotionPath.refreshChildren();
                 jmeMotionPath.refreshChildren();
             }
             }
         };
         };