Explorar o código

SDK :
- New way to visualize and play animations in the SceneExplorer
- Visualization of animation tracks
- Possibility to add and edit EffectTracks and AudioTracks
- reworked icons a bit too

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9635 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

rem..om %!s(int64=13) %!d(string=hai) anos
pai
achega
e609840bea
Modificáronse 38 ficheiros con 3304 adicións e 15 borrados
  1. 94 0
      jme3-core/src/com/jme3/gde/core/properties/AudioTrackProperty.java
  2. 138 0
      jme3-core/src/com/jme3/gde/core/properties/AudioTrackPropertyEditor.java
  3. 92 0
      jme3-core/src/com/jme3/gde/core/properties/EffectTrackEmitterProperty.java
  4. 138 0
      jme3-core/src/com/jme3/gde/core/properties/EffectTrackEmitterPropertyEditor.java
  5. 96 0
      jme3-core/src/com/jme3/gde/core/properties/SliderPropertyEditor.java
  6. 135 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeAnimChildren.java
  7. 151 15
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeAnimControl.java
  8. 273 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeAnimation.java
  9. 263 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeTrack.java
  10. 160 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeTrackChildren.java
  11. 89 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/TrackVisibilityPopup.java
  12. 183 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackVisualPanel1.form
  13. 232 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackVisualPanel1.java
  14. 119 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackWizardAction.java
  15. 126 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackWizardPanel1.java
  16. 11 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties
  17. 183 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackVisualPanel1.form
  18. 231 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackVisualPanel1.java
  19. 119 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackWizardAction.java
  20. 126 0
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackWizardPanel1.java
  21. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/anim.png
  22. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/animPlay.png
  23. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/animationcontrol.gif
  24. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/audioTrack.png
  25. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/bitmaptext.gif
  26. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/boneTrack.png
  27. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/charactercontrol.gif
  28. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/effectTrack.png
  29. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/geometry.gif
  30. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/ghostcontrol.gif
  31. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/ghostnode.gif
  32. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/physicscontrol.gif
  33. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/skeletonControl.gif
  34. BIN=BIN
      jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/track.png
  35. 1 0
      jme3-core/src/com/jme3/gde/core/util/Bundle.properties
  36. 127 0
      jme3-core/src/com/jme3/gde/core/util/SliderInplaceEditor.java
  37. 61 0
      jme3-core/src/com/jme3/gde/core/util/SliderPanel.form
  38. 156 0
      jme3-core/src/com/jme3/gde/core/util/SliderPanel.java

+ 94 - 0
jme3-core/src/com/jme3/gde/core/properties/AudioTrackProperty.java

@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.properties;
+
+import com.jme3.animation.AudioTrack;
+import com.jme3.animation.EffectTrack;
+import com.jme3.audio.AudioNode;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.scene.Spatial;
+import java.beans.PropertyEditor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.openide.nodes.PropertySupport;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class AudioTrackProperty extends PropertySupport.ReadWrite<AudioNode> {
+
+    private LinkedList<ScenePropertyChangeListener> listeners = new LinkedList<ScenePropertyChangeListener>();
+    private AudioTrack track;
+    private Spatial rootNode;
+
+    public AudioTrackProperty(AudioTrack track, Spatial rootNode) {
+        super("AudioNode", AudioNode.class, "Audio node", " ");
+        this.rootNode = rootNode;
+        this.track = track;
+
+    }
+
+    @Override
+    public AudioNode getValue() throws IllegalAccessException, InvocationTargetException {
+        return track.getAudio();
+    }
+
+    @Override
+    public void setValue(final AudioNode val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        AudioNode au = getValue();
+        track.setAudio(au);
+        notifyListeners(au, val);
+    }
+
+    @Override
+    public PropertyEditor getPropertyEditor() {
+        return new AudioTrackPropertyEditor(rootNode, track.getAudio());
+    }
+
+    public void addPropertyChangeListener(ScenePropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removePropertyChangeListener(ScenePropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(Object before, Object after) {
+        for (Iterator<ScenePropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            ScenePropertyChangeListener propertyChangeListener = it.next();
+            propertyChangeListener.propertyChange(getName(), before, after);
+        }
+
+    }
+}

+ 138 - 0
jme3-core/src/com/jme3/gde/core/properties/AudioTrackPropertyEditor.java

@@ -0,0 +1,138 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.properties;
+
+import com.jme3.audio.AudioNode;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyEditor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class AudioTrackPropertyEditor implements PropertyEditor {
+
+    private LinkedList<PropertyChangeListener> listeners = new LinkedList<PropertyChangeListener>();
+    Spatial rootNode;
+    AudioNode audio;
+
+    public AudioTrackPropertyEditor(Spatial rootNode, AudioNode audio) {
+        this.rootNode = rootNode;
+        this.audio = audio;
+    }
+
+    public void setValue(Object value) {
+        if (value instanceof AudioNode) {
+            audio = (AudioNode) value;
+        }
+    }
+
+    public Object getValue() {
+        return audio;
+    }
+
+    public boolean isPaintable() {
+        return false;
+    }
+
+    public void paintValue(Graphics gfx, Rectangle box) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public String getJavaInitializationString() {
+        return null;
+    }
+
+    public String getAsText() {
+        return audio.getName();
+    }
+
+    public void setAsText(String text) throws IllegalArgumentException {
+        AudioNode old = audio;
+
+        audio = (AudioNode) ((Node) rootNode).getChild(text);
+
+        notifyListeners(old, audio);
+    }
+
+    public String[] getTags() {
+        ArrayList<String> list = new ArrayList<String>();
+        gatherTags(rootNode, list);
+        String[] res = new String[list.size()];
+        return list.toArray(res);
+    }
+
+    private void gatherTags(Spatial root, ArrayList<String> list) {
+        if (root instanceof AudioNode) {
+            list.add(root.getName());
+        } else if (root instanceof Node) {
+            Node n = (Node) root;
+            for (Spatial child : n.getChildren()) {
+                gatherTags(child, list);
+            }
+        }
+    }
+
+    public Component getCustomEditor() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public boolean supportsCustomEditor() {
+        return false;
+    }
+
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(AudioNode before, AudioNode after) {
+        for (Iterator<PropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            PropertyChangeListener propertyChangeListener = it.next();
+            //TODO: check what the "programmatic name" is supposed to be here.. for now its Quaternion
+            propertyChangeListener.propertyChange(new PropertyChangeEvent(this, null, before, after));
+        }
+    }
+}

+ 92 - 0
jme3-core/src/com/jme3/gde/core/properties/EffectTrackEmitterProperty.java

@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.properties;
+
+import com.jme3.animation.EffectTrack;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.scene.Spatial;
+import java.beans.PropertyEditor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.openide.nodes.PropertySupport;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class EffectTrackEmitterProperty extends PropertySupport.ReadWrite<ParticleEmitter> {
+
+    private LinkedList<ScenePropertyChangeListener> listeners = new LinkedList<ScenePropertyChangeListener>();
+    private EffectTrack track;
+    private Spatial rootNode;
+
+    public EffectTrackEmitterProperty(EffectTrack track, Spatial rootNode) {
+        super("Emitter", ParticleEmitter.class, "Particle Emitter", " ");
+        this.rootNode = rootNode;
+        this.track = track;
+
+    }
+
+    @Override
+    public ParticleEmitter getValue() throws IllegalAccessException, InvocationTargetException {
+        return track.getEmitter();
+    }
+
+    @Override
+    public void setValue(final ParticleEmitter val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        ParticleEmitter em = getValue();
+        track.setEmitter(val);
+        notifyListeners(em, val);
+    }
+
+    @Override
+    public PropertyEditor getPropertyEditor() {
+        return new EffectTrackEmitterPropertyEditor(rootNode, track.getEmitter());
+    }
+
+    public void addPropertyChangeListener(ScenePropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removePropertyChangeListener(ScenePropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(Object before, Object after) {
+        for (Iterator<ScenePropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            ScenePropertyChangeListener propertyChangeListener = it.next();
+            propertyChangeListener.propertyChange(getName(), before, after);
+        }
+
+    }
+}

+ 138 - 0
jme3-core/src/com/jme3/gde/core/properties/EffectTrackEmitterPropertyEditor.java

@@ -0,0 +1,138 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.properties;
+
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyEditor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class EffectTrackEmitterPropertyEditor implements PropertyEditor {
+
+    private LinkedList<PropertyChangeListener> listeners = new LinkedList<PropertyChangeListener>();
+    Spatial rootNode;
+    ParticleEmitter emitter;
+
+    public EffectTrackEmitterPropertyEditor(Spatial rootNode,ParticleEmitter emitter) {
+        this.rootNode = rootNode;
+        this.emitter = emitter;
+    }
+
+    public void setValue(Object value) {
+        if (value instanceof ParticleEmitter) {
+            emitter = (ParticleEmitter)value;
+        }
+    }
+
+    public Object getValue() {
+        return emitter;
+    }
+
+    public boolean isPaintable() {
+        return false;
+    }
+
+    public void paintValue(Graphics gfx, Rectangle box) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public String getJavaInitializationString() {
+        return null;
+    }
+
+    public String getAsText() {
+        return emitter.getName();
+    }
+
+    public void setAsText(String text) throws IllegalArgumentException {
+        ParticleEmitter old = emitter;
+
+        emitter = (ParticleEmitter) ((Node) rootNode).getChild(text);
+
+        notifyListeners(old, emitter);
+    }
+
+    public String[] getTags() {       
+        ArrayList<String> list = new ArrayList<String>();
+        gatherTags(rootNode, list);
+        String[] res = new String[list.size()];
+        return list.toArray(res);
+    }
+
+    private void gatherTags(Spatial root, ArrayList<String> list) {
+        if (root instanceof Node) {
+            Node n = (Node) root;
+            for (Spatial child : n.getChildren()) {
+                gatherTags(child, list);
+            }
+        } else if (root instanceof ParticleEmitter) {
+            list.add(root.getName());
+        }
+    }
+
+    public Component getCustomEditor() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public boolean supportsCustomEditor() {
+        return false;
+    }
+
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(ParticleEmitter before, ParticleEmitter after) {
+        for (Iterator<PropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            PropertyChangeListener propertyChangeListener = it.next();
+            //TODO: check what the "programmatic name" is supposed to be here.. for now its Quaternion
+            propertyChangeListener.propertyChange(new PropertyChangeEvent(this, null, before, after));
+        }
+    }
+}

+ 96 - 0
jme3-core/src/com/jme3/gde/core/properties/SliderPropertyEditor.java

@@ -0,0 +1,96 @@
+package com.jme3.gde.core.properties;
+
+import com.jme3.gde.core.util.SliderInplaceEditor;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyEditorSupport;
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.openide.explorer.propertysheet.ExPropertyEditor;
+import org.openide.explorer.propertysheet.InplaceEditor;
+import org.openide.explorer.propertysheet.PropertyEnv;
+
+/**
+ *
+ * @author Nehon
+ */
+public class SliderPropertyEditor extends PropertyEditorSupport implements ExPropertyEditor, InplaceEditor.Factory {
+
+    private LinkedList<PropertyChangeListener> listeners = new LinkedList<PropertyChangeListener>();
+    PropertyEnv env;
+
+    public SliderPropertyEditor() {
+        ed = new SliderInplaceEditor(0f, 100f);
+    }
+
+    public void attachEnv(PropertyEnv env) {
+        this.env = env;
+        env.registerInplaceEditorFactory(this);
+    }
+
+    public SliderPropertyEditor(int min, int max) {
+        ed = new SliderInplaceEditor(min, max);
+    }
+
+    public SliderPropertyEditor(float min, float max) {
+        ed = new SliderInplaceEditor(min, max);
+    }
+
+    public void setRange(float min, float max) {
+        ed.setRangeFloat(min, max);
+    }
+
+    public void setRange(int min, int max) {
+        ed.setRangeInt(min, max);
+    }
+
+    @Override
+    public String getAsText() {
+        return ed.getValue().toString();
+    }
+
+    @Override
+    public void setAsText(String s) {
+        Object o = ed.getValue();
+        ((SliderInplaceEditor) ed).setAsText(s);
+        notifyListeners(o, ed.getValue());
+    }
+    private SliderInplaceEditor ed = null;
+
+    public InplaceEditor getInplaceEditor() {
+        return ed;
+    }
+
+    @Override
+    public void setValue(Object value) {
+        ed.setValue(value);
+
+    }
+
+    @Override
+    public Object getValue() {
+        return ed.getValue();
+    }
+
+    public PropertyEnv getEnv() {
+        return env;
+    }
+
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(Object before, Object after) {
+        for (Iterator<PropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            PropertyChangeListener propertyChangeListener = it.next();
+            //TODO: check what the "programmatic name" is supposed to be here.. for now its Quaternion
+            propertyChangeListener.propertyChange(new PropertyChangeEvent(this, null, before, after));
+        }
+    }
+}

+ 135 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeAnimChildren.java

@@ -0,0 +1,135 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.gde.core.scene.SceneApplication;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import org.openide.loaders.DataObject;
+import org.openide.nodes.Children;
+import org.openide.nodes.Node;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author nehon
+ */
+public class JmeAnimChildren extends Children.Keys<Object> {
+
+    protected JmeAnimControl jmeAnimControl;
+    protected boolean readOnly = true;
+    protected HashMap<Object, Node> map = new HashMap<Object, Node>();
+    private DataObject dataObject;
+
+    public JmeAnimChildren() {
+    }
+
+    public JmeAnimChildren(JmeAnimControl jmeAnimControl) {
+        this.jmeAnimControl = jmeAnimControl;
+    }
+
+    public void refreshChildren(boolean immediate) {
+        setKeys(createKeys());
+        refresh();
+    }
+
+    public void setReadOnly(boolean cookie) {
+        this.readOnly = cookie;
+    }
+
+    @Override
+    protected void addNotify() {
+        super.addNotify();
+        setKeys(createKeys());
+    }
+
+    protected List<Object> createKeys() {
+        try {
+            return SceneApplication.getApplication().enqueue(new Callable<List<Object>>() {
+
+                public List<Object> call() throws Exception {
+                    List<Object> keys = new LinkedList<Object>();
+                    AnimControl control = jmeAnimControl.getLookup().lookup(AnimControl.class);
+                    if (control != null) {
+                        for (String animName : control.getAnimationNames()) {
+                            keys.add(control.getAnim(animName));
+                        }
+                    }
+
+                    return keys;
+                }
+            }).get();
+        } catch (InterruptedException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (ExecutionException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        return null;
+    }
+
+    @Override
+    protected Node[] createNodes(Object key) {
+//        for (SceneExplorerNode di : Lookup.getDefault().lookupAll(SceneExplorerNode.class)) {
+//            if (di.getExplorerObjectClass().getName().equals(key.getClass().getName())) {
+//                Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Found {0}", di.getExplorerNodeClass());
+//                Node[] ret = di.createNodes(key, dataObject, readOnly);
+//                if (ret != null) {
+//                    return ret;
+//                }
+//            }
+//        }
+
+        if (key instanceof Animation) {
+            JmeTrackChildren children = new JmeTrackChildren();
+            children.setReadOnly(readOnly);            
+            return new Node[]{new JmeAnimation(jmeAnimControl, (Animation) key, children, dataObject).setReadOnly(readOnly)};
+        }
+        return new Node[]{Node.EMPTY};
+    }
+
+    public void setAnimControl(JmeAnimControl jmeAnimControl) {
+        this.jmeAnimControl = jmeAnimControl;
+    }
+
+    public DataObject getDataObject() {
+        return dataObject;
+    }
+
+    public void setDataObject(DataObject dataObject) {
+        this.dataObject = dataObject;
+    }
+}

+ 151 - 15
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeAnimControl.java

@@ -32,10 +32,9 @@
 package com.jme3.gde.core.sceneexplorer.nodes;
 
 import com.jme3.animation.AnimControl;
-import com.jme3.gde.core.scene.SceneApplication;
-import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode;
-import com.jme3.gde.core.sceneexplorer.nodes.SceneExplorerNode;
 import com.jme3.gde.core.properties.AnimationProperty;
+import com.jme3.gde.core.scene.SceneApplication;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.TrackVisibilityPopup;
 import com.jme3.scene.Spatial;
 import java.awt.Image;
 import java.io.IOException;
@@ -44,33 +43,41 @@ import java.util.concurrent.ExecutionException;
 import javax.swing.Action;
 import org.openide.actions.DeleteAction;
 import org.openide.loaders.DataObject;
-import org.openide.nodes.Children;
 import org.openide.nodes.Node;
 import org.openide.nodes.Sheet;
 import org.openide.util.Exceptions;
+import org.openide.util.HelpCtx;
 import org.openide.util.ImageUtilities;
+import org.openide.util.actions.BooleanStateAction;
 import org.openide.util.actions.SystemAction;
 
 /**
  *
  * @author normenhansen
  */
[email protected](service=SceneExplorerNode.class)
-public class JmeAnimControl extends AbstractSceneExplorerNode{
[email protected](service = SceneExplorerNode.class)
+public class JmeAnimControl extends AbstractSceneExplorerNode {
 
     private AnimControl animControl;
+    private JmeAnimation playingAnimation = null;
+    private boolean displayBoneTracks = false;
+    private boolean displayEffectTracks = true;
+    private boolean displayAudioTracks = true;
     private static Image smallImage =
             ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/animationcontrol.gif");
 
     public JmeAnimControl() {
     }
 
-    public JmeAnimControl(AnimControl animControl) {
-        super(Children.LEAF);
+    public JmeAnimControl(AnimControl animControl, JmeAnimChildren children, DataObject obj) {
+        super(children);
+        dataObject = obj;
+        children.setDataObject(dataObject);
         this.animControl = animControl;
         lookupContents.add(this);
         lookupContents.add(animControl);
         setName("AnimControl");
+        children.setAnimControl(this);
     }
 
     @Override
@@ -101,12 +108,23 @@ public class JmeAnimControl extends AbstractSceneExplorerNode{
 
     }
 
+    public boolean isPlaying() {
+        return playingAnimation != null;
+    }
+
+    public void setAnim(JmeAnimation anim) {
+        if (playingAnimation != null) {
+            playingAnimation.stop();
+        }
+        playingAnimation = anim;
+    }
+
     @Override
     public Action[] getActions(boolean context) {
-        return new SystemAction[]{
-                    //                    SystemAction.get(CopyAction.class),
-                    //                    SystemAction.get(CutAction.class),
-                    //                    SystemAction.get(PasteAction.class),
+
+
+        return new Action[]{
+                    new TrackVisibilityPopup(this),
                     SystemAction.get(DeleteAction.class)
                 };
     }
@@ -119,7 +137,7 @@ public class JmeAnimControl extends AbstractSceneExplorerNode{
     @Override
     public void destroy() throws IOException {
         super.destroy();
-        final Spatial spat=getParentNode().getLookup().lookup(Spatial.class);
+        final Spatial spat = getParentNode().getLookup().lookup(Spatial.class);
         try {
             SceneApplication.getApplication().enqueue(new Callable<Void>() {
 
@@ -128,7 +146,7 @@ public class JmeAnimControl extends AbstractSceneExplorerNode{
                     return null;
                 }
             }).get();
-            ((AbstractSceneExplorerNode)getParentNode()).refresh(true);
+            ((AbstractSceneExplorerNode) getParentNode()).refresh(true);
         } catch (InterruptedException ex) {
             Exceptions.printStackTrace(ex);
         } catch (ExecutionException ex) {
@@ -146,7 +164,125 @@ public class JmeAnimControl extends AbstractSceneExplorerNode{
 
     @Override
     public Node[] createNodes(Object key, DataObject key2, boolean cookie) {
-        return new Node[]{new JmeAnimControl((AnimControl)key)};
+        JmeAnimChildren children = new JmeAnimChildren(this);
+        return new Node[]{new JmeAnimControl((AnimControl) key, children, key2)};
+    }
+
+    public boolean isDisplayAudioTracks() {
+        return displayAudioTracks;
+    }
+
+    public boolean isDisplayBoneTracks() {
+        return displayBoneTracks;
     }
 
+    public boolean isDisplayEffectTracks() {
+        return displayEffectTracks;
+    }
+
+    public void setDisplayAudioTracks(boolean displayAudioTracks) {
+        this.displayAudioTracks = displayAudioTracks;
+        refreshChildren();
+    }
+
+    public void setDisplayBoneTracks(boolean displayBoneTracks) {
+        this.displayBoneTracks = displayBoneTracks;
+        refreshChildren();
+    }
+
+    public void setDisplayEffectTracks(boolean displayEffectTracks) {
+        this.displayEffectTracks = displayEffectTracks;
+        refreshChildren();
+    }
+
+    public void refreshChildren() {
+        for (Object node : getChildren().getNodes()) {
+            JmeAnimation anim = (JmeAnimation) node;
+            ((JmeTrackChildren) anim.getChildren()).refreshChildren(true);
+        }
+    }
+
+    class ToggleBoneTrackAction extends BooleanStateAction {
+
+        @Override
+        public String getName() {
+            return "Display bone tracks";
+        }
+
+        @Override
+        public void setBooleanState(boolean value) {
+            super.setBooleanState(value);
+            displayBoneTracks = value;
+            for (Object node : getChildren().getNodes()) {
+                JmeAnimation anim = (JmeAnimation) node;
+                ((JmeTrackChildren) anim.getChildren()).refreshChildren(true);
+            }
+        }
+
+        @Override
+        public boolean getBooleanState() {
+            return displayBoneTracks;
+        }
+
+        @Override
+        public HelpCtx getHelpCtx() {
+            return JmeAnimControl.this.getHelpCtx();
+        }
+    };
+
+    class ToggleEffectTrackAction extends BooleanStateAction {
+
+        @Override
+        public String getName() {
+            return "Display effect tracks";
+        }
+
+        @Override
+        public void setBooleanState(boolean value) {
+            super.setBooleanState(value);
+            displayEffectTracks = value;
+            for (Object node : getChildren().getNodes()) {
+                JmeAnimation anim = (JmeAnimation) node;
+                ((JmeTrackChildren) anim.getChildren()).refreshChildren(true);
+            }
+        }
+
+        @Override
+        public boolean getBooleanState() {
+            return displayEffectTracks;
+        }
+
+        @Override
+        public HelpCtx getHelpCtx() {
+            return JmeAnimControl.this.getHelpCtx();
+        }
+    };
+
+    class ToggleAudioTrackAction extends BooleanStateAction {
+
+        @Override
+        public String getName() {
+            return "Display audio tracks";
+        }
+
+        @Override
+        public void setBooleanState(boolean value) {
+            super.setBooleanState(value);
+            displayAudioTracks = value;
+            for (Object node : getChildren().getNodes()) {
+                JmeAnimation anim = (JmeAnimation) node;
+                ((JmeTrackChildren) anim.getChildren()).refreshChildren(true);
+            }
+        }
+
+        @Override
+        public boolean getBooleanState() {
+            return displayAudioTracks;
+        }
+
+        @Override
+        public HelpCtx getHelpCtx() {
+            return JmeAnimControl.this.getHelpCtx();
+        }
+    };
 }

+ 273 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeAnimation.java

@@ -0,0 +1,273 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.gde.core.scene.SceneApplication;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks.AudioTrackWizardAction;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks.EffectTrackWizardAction;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import javax.swing.Action;
+import org.openide.awt.Actions;
+import org.openide.loaders.DataObject;
+import org.openide.nodes.Node;
+import org.openide.nodes.Sheet;
+import org.openide.util.Exceptions;
+import org.openide.util.ImageUtilities;
+
+/**
+ *
+ * @author nehon
+ */
[email protected](service = SceneExplorerNode.class)
+public class JmeAnimation extends AbstractSceneExplorerNode {
+    
+    private Animation animation;
+    private static final String ICON = "com/jme3/gde/core/sceneexplorer/nodes/icons/anim.png";
+    private static final String ICON_PLAY = "com/jme3/gde/core/sceneexplorer/nodes/icons/animPlay.png";
+    private Image icon;
+    private JmeAnimControl jmeControl;
+    private boolean playing = false;
+    
+    public JmeAnimation() {
+    }
+    
+    public JmeAnimation(JmeAnimControl control, Animation animation, JmeTrackChildren children, DataObject dataObject) {
+        super(children);
+        this.dataObject = dataObject;
+        children.setDataObject(dataObject);
+        this.animation = animation;
+        this.jmeControl = control;
+        lookupContents.add(this);
+        lookupContents.add(animation);
+        setName(animation.getName());
+        children.setAnimation(this);
+        children.setAnimControl(jmeControl);
+        icon = ImageUtilities.loadImage(ICON);
+        
+    }
+    
+    @Override
+    public Image getIcon(int type) {
+        return icon;
+    }
+    
+    @Override
+    public Image getOpenedIcon(int type) {
+        
+        return icon;
+        
+    }
+    
+    public void toggleIcon(boolean enabled) {
+        if (!playing) {
+            icon = ImageUtilities.loadImage(ICON);
+            
+        } else {
+            icon = ImageUtilities.loadImage(ICON_PLAY);
+            
+        }
+        fireIconChange();
+    }
+    
+    @Override
+    public Action getPreferredAction() {
+        return Actions.alwaysEnabled(new PlayAction(), "Play", "", false);
+        
+    }
+    
+    private void play() {
+        playing = !playing;
+        toggleIcon(playing);
+        jmeControl.setAnim(this);
+    }
+    
+    @Override
+    protected Sheet createSheet() {
+        //TODO: multithreading..
+        Sheet sheet = Sheet.createDefault();
+        Sheet.Set set = Sheet.createPropertiesSet();
+        set.setDisplayName("Animation");
+        set.setName(Animation.class.getName());
+        if (animation == null) {
+            return sheet;
+        }
+
+        //  set.put(new AnimationProperty(animControl));
+
+        sheet.put(set);
+        return sheet;
+        
+    }
+    
+    public void setChanged() {
+        fireSave(true);
+    }
+    
+    @Override
+    public Action[] getActions(boolean context) {
+        
+        return new Action[]{Actions.alwaysEnabled(new PlayAction(), playing ? "Stop" : "Play", "", false),
+                    Actions.alwaysEnabled(new EffectTrackWizardAction(jmeControl.getLookup().lookup(AnimControl.class).getSpatial(), this), "Add Effect Track", "", false),
+                    Actions.alwaysEnabled(new AudioTrackWizardAction(jmeControl.getLookup().lookup(AnimControl.class).getSpatial(), this), "Add Audio Track", "", false)
+                };
+    }
+    
+    @Override
+    public boolean canDestroy() {
+        return false;
+    }
+    
+    public void stop() {
+        playing = false;
+        toggleIcon(playing);        
+    }
+    
+    @Override
+    public void destroy() throws IOException {
+//        super.destroy();
+//        final Spatial spat = getParentNode().getLookup().lookup(Spatial.class);
+//        try {
+//            SceneApplication.getApplication().enqueue(new Callable<Void>() {
+//
+//                public Void call() throws Exception {
+//                    spat.removeControl(skeletonControl);
+//                    return null;
+//                }
+//            }).get();
+//            ((AbstractSceneExplorerNode) getParentNode()).refresh(true);
+//        } catch (InterruptedException ex) {
+//            Exceptions.printStackTrace(ex);
+//        } catch (ExecutionException ex) {
+//            Exceptions.printStackTrace(ex);
+//        }
+    }
+    
+    @Override
+    public void refresh(boolean immediate) {
+        super.refresh(immediate);
+        ((JmeTrackChildren) getChildren()).refreshChildren(false);
+    }
+    
+    public Class getExplorerObjectClass() {
+        return Animation.class;
+    }
+    
+    @Override
+    public Class getExplorerNodeClass() {
+        return JmeAnimation.class;
+    }
+    
+    @Override
+    public Node[] createNodes(Object key, DataObject key2, boolean cookie) {
+        JmeTrackChildren children = new JmeTrackChildren(this, jmeControl);
+        JmeAnimation jsc = new JmeAnimation(jmeControl, (Animation) key, children, key2);
+        return new Node[]{jsc};
+    }
+    
+    class PlayAction implements ActionListener {
+        
+        public void actionPerformed(ActionEvent e) {
+            final AnimControl control = jmeControl.getLookup().lookup(AnimControl.class);
+            if (control == null) {
+                return;
+            }
+            try {
+                SceneApplication.getApplication().enqueue(new Callable<Void>() {
+                    
+                    public Void call() throws Exception {
+                        if (playing) {
+                            control.clearChannels();
+                            jmeControl.setAnim(null);
+                            return null;
+                        }
+                        control.clearChannels();
+                        control.createChannel().setAnim(animation.getName());
+                        play();
+                        
+                        return null;
+                    }
+                }).get();
+            } catch (InterruptedException ex) {
+                Exceptions.printStackTrace(ex);
+            } catch (ExecutionException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+            
+        }
+    }
+//
+//    class AddTrackAction implements ActionListener {
+//
+//        public void actionPerformed(ActionEvent e) {
+//
+//            WizardDescriptor.Iterator iterator = new NewEffectTrackWizardIterator();
+//            WizardDescriptor wizardDescriptor = new WizardDescriptor(iterator);
+//            // {0} will be replaced by WizardDescriptor.Panel.getComponent().getName()
+//            // {1} will be replaced by WizardDescriptor.Iterator.name()
+//            wizardDescriptor.setTitleFormat(new MessageFormat("{0} ({1})"));
+//            wizardDescriptor.setTitle("Your wizard dialog title here");
+//            Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
+//            dialog.setVisible(true);
+//            dialog.toFront();
+//            boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
+//            if (!cancelled) {
+//                // do something
+//            }
+//            final AnimControl control = jmeControl.getLookup().lookup(AnimControl.class);
+//            if (control == null) {
+//                return;
+//            }
+//            try {
+//                SceneApplication.getApplication().enqueue(new Callable<Void>() {
+//
+//                    public Void call() throws Exception {
+//                        animation.addTrack(new EffectTrack());
+//                        animation.addTrack(new AudioTrack());
+//                        return null;
+//                    }
+//                }).get();
+//            } catch (InterruptedException ex) {
+//                Exceptions.printStackTrace(ex);
+//            } catch (ExecutionException ex) {
+//                Exceptions.printStackTrace(ex);
+//            }
+//            ((JmeTrackChildren) getChildren()).refreshChildren(false);
+//        }
+//    }
+}

+ 263 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeTrack.java

@@ -0,0 +1,263 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.animation.AudioTrack;
+import com.jme3.animation.BoneTrack;
+import com.jme3.animation.EffectTrack;
+import com.jme3.animation.Track;
+import com.jme3.gde.core.properties.AudioTrackProperty;
+import com.jme3.gde.core.properties.EffectTrackEmitterProperty;
+import com.jme3.gde.core.properties.SceneExplorerProperty;
+import com.jme3.gde.core.properties.SliderPropertyEditor;
+import com.jme3.gde.core.scene.SceneApplication;
+import java.awt.Image;
+import java.beans.PropertyEditor;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import javax.swing.Action;
+import org.openide.actions.DeleteAction;
+import org.openide.loaders.DataObject;
+import org.openide.nodes.Children;
+import org.openide.nodes.Sheet;
+import org.openide.util.Exceptions;
+import org.openide.util.ImageUtilities;
+import org.openide.util.actions.SystemAction;
+
+/**
+ *
+ * @author normenhansen
+ */
[email protected](service = SceneExplorerNode.class)
+public class JmeTrack extends AbstractSceneExplorerNode {
+    
+    private static Image iconBoneTrack =
+            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/boneTrack.png");
+    private static Image iconEffectTrack =
+            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/effectTrack.png");
+    private static Image iconAudioTrack =
+            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/audioTrack.png");
+    private static Image iconTrack =
+            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/track.png");
+    private Track track;
+    private AnimControl control;
+    
+    public JmeTrack() {
+    }
+    
+    public JmeTrack(Track track, AnimControl control, DataObject obj) {
+        super(Children.LEAF);
+        dataObject = obj;
+        
+        getLookupContents().add(track);
+        getLookupContents().add(this);
+        this.track = track;
+        this.control = control;
+        setName();
+    }
+
+    private void setName() {
+        if (track instanceof BoneTrack) {
+            BoneTrack boneTrack = (BoneTrack) track;
+            super.setName("BoneTrack : " + control.getSkeleton().getBone(boneTrack.getTargetBoneIndex()).getName());
+        } else if (track instanceof EffectTrack) {
+            EffectTrack effectTrack = (EffectTrack) track;
+            super.setName("EffectTrack : " + effectTrack.getEmitter().getName());            
+        } else if (track instanceof AudioTrack) {
+            AudioTrack audioTrack = (AudioTrack) track;
+            super.setName("AudioTrack : " + audioTrack.getAudio().getName());
+            
+        } else {
+            super.setName(track.getClass().getSimpleName());
+        }
+    }
+    
+    
+    
+    @Override
+    public Image getIcon(int type) {
+        if (track instanceof BoneTrack) {
+            return iconBoneTrack;
+        } else if (track instanceof EffectTrack) {
+            return iconEffectTrack;
+        } else if (track instanceof AudioTrack) {
+            return iconAudioTrack;
+        }
+        return iconTrack;
+        
+    }
+    
+    @Override
+    public Image getOpenedIcon(int type) {
+        if (track instanceof BoneTrack) {
+            return iconBoneTrack;
+        } else if (track instanceof EffectTrack) {
+            return iconEffectTrack;
+        } else if (track instanceof AudioTrack) {
+            return iconAudioTrack;
+        }
+        return iconTrack;
+    }
+    
+    public class dum {
+        
+        float val;
+        
+        public float getVal() {
+            return val;
+        }
+        
+        public void setVal(float val) {
+            this.val = val;
+        }
+    }
+    
+    @Override
+    protected Sheet createSheet() {
+        //TODO: multithreading..
+        Sheet sheet = super.createSheet();
+        Sheet.Set set = Sheet.createPropertiesSet();
+        set.setDisplayName("Track");
+        set.setName(track.getClass().getSimpleName());
+        Track obj = track;//getLookup().lookup(Spatial.class);
+        if (obj == null) {
+            return sheet;
+        }
+        set.put(makeProperty(obj, float.class, "getLength", "Track length"));
+        if (track instanceof EffectTrack) {
+            EffectTrackEmitterProperty prop = new EffectTrackEmitterProperty((EffectTrack) track, control.getSpatial());
+            prop.addPropertyChangeListener(this);
+            set.put(prop);
+        }
+        if (track instanceof AudioTrack) {
+            AudioTrackProperty prop = new AudioTrackProperty((AudioTrack) track, control.getSpatial());
+            prop.addPropertyChangeListener(this);
+            set.put(prop);
+        }
+        if (track instanceof EffectTrack || track instanceof AudioTrack) {
+            try {
+                // set.put(createSliderProperty(track));
+
+                SceneExplorerProperty prop = new SceneExplorerProperty(track, float.class, "getStartOffset", "setStartOffset", this) {
+                    
+                    SliderPropertyEditor editor = null;
+                    
+                    @Override
+                    public PropertyEditor getPropertyEditor() {
+                        if (editor == null) {
+                            if (track instanceof EffectTrack) {
+                                editor = new SliderPropertyEditor(0f, ((EffectTrack) track).getLength());
+                                
+                            } else {
+                                editor = new SliderPropertyEditor(0f, ((AudioTrack) track).getLength());
+                                
+                            }
+                        }
+                        return editor;
+                    }
+                };
+                set.put(prop);
+            } catch (NoSuchMethodException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+            
+        }
+
+        //  set.put(makeProperty(obj, boolean.class, "isEnabled", "setEnabled", "Enabled"));
+        //set.put(makeProperty(obj, boolean.class, "isEnabled", "setEnabled", "Enabled"));
+//        set.put(makeProperty(obj, ParticleMesh.Type.class, "getMeshType", "setMeshType", "Mesh Type"));
+//        set.put(makeProperty(obj, EmitterShape.class, "getShape", "setShape", "Emitter Shape"));
+        sheet.put(set);
+        return sheet;
+        
+    }
+    
+    @Override
+    public Action[] getActions(boolean context) {
+        
+        return new Action[]{
+                    SystemAction.get(DeleteAction.class)
+                };
+    }
+    
+    @Override
+    public boolean canDestroy() {
+        return !(track instanceof BoneTrack);
+    }
+    
+    @Override
+    public void destroy() throws IOException {
+        super.destroy();
+        fireSave(true);
+        final Animation anim = getParentNode().getLookup().lookup(Animation.class);
+        try {
+            SceneApplication.getApplication().enqueue(new Callable<Void>() {
+                
+                public Void call() throws Exception {
+                    anim.removeTrack(track);
+                    return null;
+                }
+            }).get();
+            ((AbstractSceneExplorerNode) getParentNode()).refresh(true);
+        } catch (InterruptedException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (ExecutionException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+    
+    public Class getExplorerObjectClass() {
+        return Track.class;
+    }
+    
+    @Override
+    public Class getExplorerNodeClass() {
+        return JmeTrack.class;
+    }
+    
+    @Override
+    public org.openide.nodes.Node[] createNodes(Object key, DataObject key2, boolean cookie) {
+        return new org.openide.nodes.Node[]{new JmeTrack((Track) key, control, key2).setReadOnly(cookie)};
+    }
+
+    @Override
+    public void propertyChange(String name, Object before, Object after) {
+        super.propertyChange(name, before, after);
+        setName();
+    }
+    
+    
+    
+}

+ 160 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeTrackChildren.java

@@ -0,0 +1,160 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes;
+
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.Animation;
+import com.jme3.animation.AudioTrack;
+import com.jme3.animation.BoneTrack;
+import com.jme3.animation.EffectTrack;
+import com.jme3.animation.Track;
+import com.jme3.gde.core.scene.SceneApplication;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import org.openide.loaders.DataObject;
+import org.openide.nodes.Children;
+import org.openide.nodes.Node;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author nehon
+ */
+public class JmeTrackChildren extends Children.Keys<Object> {
+
+    protected JmeAnimation jmeAnimation;
+    protected boolean readOnly = true;
+    protected HashMap<Object, Node> map = new HashMap<Object, Node>();
+    private DataObject dataObject;
+    private JmeAnimControl jmeControl;
+
+    public JmeTrackChildren() {
+    }
+
+    public JmeTrackChildren(JmeAnimation jmeAnimation, JmeAnimControl jmeControl) {
+        this.jmeAnimation = jmeAnimation;
+        this.jmeControl = jmeControl;
+    }
+
+    public void refreshChildren(boolean immediate) {
+        setKeys(createKeys());
+        refresh();
+    }
+
+    public void setReadOnly(boolean cookie) {
+        this.readOnly = cookie;
+    }
+
+    @Override
+    protected void addNotify() {
+        super.addNotify();
+        setKeys(createKeys());
+    }
+
+    protected List<Object> createKeys() {
+        try {
+            return SceneApplication.getApplication().enqueue(new Callable<List<Object>>() {
+
+                public List<Object> call() throws Exception {
+                    List<Object> keys = new LinkedList<Object>();
+                    Animation anim = jmeAnimation.getLookup().lookup(Animation.class);
+                    if (anim != null) {
+                        for (Track track : anim.getTracks()) {
+                            if (track instanceof BoneTrack) {
+                                if (jmeControl.isDisplayBoneTracks()) {
+                                    keys.add(track);
+                                }
+                            } else if (track instanceof EffectTrack) {
+                                if (jmeControl.isDisplayEffectTracks()) {
+                                    keys.add(track);
+                                }
+
+                            } else if (track instanceof AudioTrack) {
+                                if (jmeControl.isDisplayAudioTracks()) {
+                                    keys.add(track);
+                                }
+                            } else {
+                                keys.add(track);
+                            }
+
+                        }
+
+                    }
+
+                    return keys;
+                }
+            }).get();
+        } catch (InterruptedException ex) {
+            Exceptions.printStackTrace(ex);
+        } catch (ExecutionException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        return null;
+    }
+
+    @Override
+    protected Node[] createNodes(Object key) {
+//        for (SceneExplorerNode di : Lookup.getDefault().lookupAll(SceneExplorerNode.class)) {
+//            if (di.getExplorerObjectClass().getName().equals(key.getClass().getName())) {
+//                Logger.getLogger(this.getClass().getName()).log(Level.FINE, "Found {0}", di.getExplorerNodeClass());
+//                Node[] ret = di.createNodes(key, dataObject, readOnly);
+//                if (ret != null) {
+//                    return ret;
+//                }
+//            }
+//        }
+
+        if (key instanceof Track) {
+            return new Node[]{new JmeTrack((Track) key, jmeControl.getLookup().lookup(AnimControl.class), dataObject).setReadOnly(readOnly)};
+        }
+        return new Node[]{Node.EMPTY};
+    }
+
+    public void setAnimation(JmeAnimation jmeAnimation) {
+        this.jmeAnimation = jmeAnimation;
+    }
+
+    public void setAnimControl(JmeAnimControl jmeControl) {
+        this.jmeControl = jmeControl;
+    }
+
+    public DataObject getDataObject() {
+        return dataObject;
+    }
+
+    public void setDataObject(DataObject dataObject) {
+        this.dataObject = dataObject;
+    }
+}

+ 89 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/TrackVisibilityPopup.java

@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions;
+
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimControl;
+import java.awt.event.ActionEvent;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import org.openide.loaders.DataObject;
+import org.openide.util.actions.Presenter;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class TrackVisibilityPopup extends AbstractAction implements Presenter.Popup {
+
+    protected JmeAnimControl jmeControl;
+
+    public TrackVisibilityPopup(JmeAnimControl jmeControl) {
+        this.jmeControl = jmeControl;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+    }
+
+    public JMenuItem getPopupPresenter() {
+        JMenu result = new JMenu("Display...");
+        JCheckBoxMenuItem boneTrackItem = new JCheckBoxMenuItem(new AbstractAction("Bone tracks") {
+
+            public void actionPerformed(ActionEvent e) {
+                jmeControl.setDisplayBoneTracks(((JCheckBoxMenuItem) e.getSource()).isSelected());
+            }
+        });
+        boneTrackItem.setSelected(jmeControl.isDisplayBoneTracks());
+        result.add(boneTrackItem);
+        JCheckBoxMenuItem effectTrackItem = new JCheckBoxMenuItem(new AbstractAction("Effect tracks") {
+
+            public void actionPerformed(ActionEvent e) {
+                jmeControl.setDisplayEffectTracks(((JCheckBoxMenuItem) e.getSource()).isSelected());
+            }
+        });
+        effectTrackItem.setSelected(jmeControl.isDisplayEffectTracks());
+        result.add(effectTrackItem);
+        JCheckBoxMenuItem audioTrackItem = new JCheckBoxMenuItem(new AbstractAction("Audio tracks") {
+
+            public void actionPerformed(ActionEvent e) {
+                jmeControl.setDisplayAudioTracks(((JCheckBoxMenuItem) e.getSource()).isSelected());
+            }
+        });
+        audioTrackItem.setSelected(jmeControl.isDisplayAudioTracks());
+        result.add(audioTrackItem);
+
+
+        return result;
+    }
+}

+ 183 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackVisualPanel1.form

@@ -0,0 +1,183 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
+            <EtchetBorder/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jLabel1" pref="390" max="32767" attributes="0"/>
+                      <Component id="jSeparator1" alignment="1" pref="390" max="32767" attributes="0"/>
+                      <Group type="102" alignment="0" attributes="0">
+                          <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                              <Component id="jLabel2" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jLabel5" alignment="0" pref="107" max="32767" attributes="1"/>
+                              <Component id="jLabel3" alignment="1" min="-2" pref="92" max="-2" attributes="1"/>
+                          </Group>
+                          <EmptySpace type="separate" max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                              <Component id="lengthLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="jComboBox1" alignment="0" pref="157" max="32767" attributes="1"/>
+                              <Component id="jLabel4" alignment="0" pref="243" max="32767" attributes="0"/>
+                              <Component id="jSlider1" alignment="1" max="32767" attributes="1"/>
+                          </Group>
+                          <EmptySpace pref="22" max="32767" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="lengthLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="jComboBox1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace min="14" pref="14" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                      <Component id="jSlider1" min="-2" pref="23" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace pref="27" max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="jLabel1">
+          <Properties>
+            <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+              <Font name="Tahoma" size="12" style="1"/>
+            </Property>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/com/jme3/gde/core/sceneexplorer/nodes/icons/audioTrack.png"/>
+            </Property>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="AudioTrackVisualPanel1.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JSeparator" name="jSeparator1">
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel2">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="4"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="AudioTrackVisualPanel1.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel3">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="11"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="AudioTrackVisualPanel1.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="verticalAlignment" type="int" value="1"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="jComboBox1">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="4">
+                <StringItem index="0" value="Item 1"/>
+                <StringItem index="1" value="Item 2"/>
+                <StringItem index="2" value="Item 3"/>
+                <StringItem index="3" value="Item 4"/>
+              </StringArray>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JSlider" name="jSlider1">
+          <Properties>
+            <Property name="value" type="int" value="0"/>
+          </Properties>
+          <Events>
+            <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="jSlider1StateChanged"/>
+            <EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="jSlider1PropertyChange"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel4">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="0"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="jSlider1.getValue()+&quot;&quot;" type="code"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel5">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="4"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="AudioTrackVisualPanel1.jLabel5.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="lengthLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="AudioTrackVisualPanel1.lengthLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>

+ 232 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackVisualPanel1.java

@@ -0,0 +1,232 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks;
+
+import com.jme3.animation.Animation;
+import com.jme3.audio.AudioNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimation;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+
+public final class AudioTrackVisualPanel1 extends JPanel {
+
+    Spatial rootNode;
+    JmeAnimation animation;
+
+    /** Creates new form AudioTrackVisualPanel1 */
+    public AudioTrackVisualPanel1(Spatial rootNode, JmeAnimation animation) {
+        this.rootNode = rootNode;
+        this.animation = animation;
+        initComponents();
+        lengthLabel.setText(animation.getLookup().lookup(Animation.class).getLength() + "");
+        DefaultComboBoxModel model = new DefaultComboBoxModel();
+
+        populateModel(rootNode, model);
+        
+        jComboBox1.setModel(model);
+        jComboBox1.setRenderer(new ListCellRenderer() {
+
+            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                return new JLabel(((Spatial)value).getName());
+            }
+        }); 
+        jSlider1.setMaximum((int) (animation.getLookup().lookup(Animation.class).getLength() * 100));
+    }
+
+    private void populateModel(Spatial root, DefaultComboBoxModel model) {
+        if (root instanceof AudioNode) {
+            model.addElement((AudioNode) root);
+        } else if (root instanceof Node) {
+            Node n = (Node) root;
+            for (Spatial child : n.getChildren()) {
+                populateModel(child, model);
+            }
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "Create a new AudioTrack";
+    }
+
+    public AudioNode getAudioNode() {
+        return (AudioNode) jComboBox1.getSelectedItem();
+    }
+
+    public float getStartOffset() {
+        return (float) jSlider1.getValue() / 100f;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanel1 = new javax.swing.JPanel();
+        jLabel1 = new javax.swing.JLabel();
+        jSeparator1 = new javax.swing.JSeparator();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jComboBox1 = new javax.swing.JComboBox();
+        jSlider1 = new javax.swing.JSlider();
+        jLabel4 = new javax.swing.JLabel();
+        jLabel5 = new javax.swing.JLabel();
+        lengthLabel = new javax.swing.JLabel();
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
+
+        jLabel1.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
+        jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/core/sceneexplorer/nodes/icons/audioTrack.png"))); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(AudioTrackVisualPanel1.class, "AudioTrackVisualPanel1.jLabel1.text")); // NOI18N
+
+        jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AudioTrackVisualPanel1.class, "AudioTrackVisualPanel1.jLabel2.text")); // NOI18N
+
+        jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(AudioTrackVisualPanel1.class, "AudioTrackVisualPanel1.jLabel3.text")); // NOI18N
+        jLabel3.setVerticalAlignment(javax.swing.SwingConstants.TOP);
+
+        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+
+        jSlider1.setValue(0);
+        jSlider1.addChangeListener(new javax.swing.event.ChangeListener() {
+            public void stateChanged(javax.swing.event.ChangeEvent evt) {
+                jSlider1StateChanged(evt);
+            }
+        });
+        jSlider1.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
+            public void propertyChange(java.beans.PropertyChangeEvent evt) {
+                jSlider1PropertyChange(evt);
+            }
+        });
+
+        jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, jSlider1.getValue()+"");
+
+        jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(AudioTrackVisualPanel1.class, "AudioTrackVisualPanel1.jLabel5.text")); // NOI18N
+
+        org.openide.awt.Mnemonics.setLocalizedText(lengthLabel, org.openide.util.NbBundle.getMessage(AudioTrackVisualPanel1.class, "AudioTrackVisualPanel1.lengthLabel.text")); // NOI18N
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE)
+                    .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                            .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(jLabel5, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
+                            .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addGap(18, 18, 18)
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                            .addComponent(lengthLabel, javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jComboBox1, javax.swing.GroupLayout.Alignment.LEADING, 0, 157, Short.MAX_VALUE)
+                            .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE)
+                            .addComponent(jSlider1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 22, Short.MAX_VALUE)))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel5)
+                    .addComponent(lengthLabel))
+                .addGap(18, 18, 18)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel2)
+                    .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addGap(14, 14, 14)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel3)
+                    .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel4)
+                .addContainerGap(27, Short.MAX_VALUE))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+private void jSlider1PropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_jSlider1PropertyChange
+}//GEN-LAST:event_jSlider1PropertyChange
+
+private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider1StateChanged
+    jLabel4.setText(((float) jSlider1.getValue() / 100f) + "");
+}//GEN-LAST:event_jSlider1StateChanged
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JComboBox jComboBox1;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JSlider jSlider1;
+    private javax.swing.JLabel lengthLabel;
+    // End of variables declaration//GEN-END:variables
+}

+ 119 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackWizardAction.java

@@ -0,0 +1,119 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks;
+
+import com.jme3.animation.Animation;
+import com.jme3.animation.AudioTrack;
+import com.jme3.audio.AudioNode;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimation;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.MessageFormat;
+import javax.swing.JComponent;
+import org.openide.DialogDisplayer;
+import org.openide.WizardDescriptor;
+
+// An example action demonstrating how the wizard could be called from within
+// your code. You can move the code below wherever you need, or register an action:
+// @ActionID(category="...", id="com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks.EffectTrackWizardAction")
+// @ActionRegistration(displayName="Open EffectTrack Wizard")
+// @ActionReference(path="Menu/Tools", position=...)
+public final class AudioTrackWizardAction implements ActionListener {
+
+    private WizardDescriptor.Panel[] panels;
+    Spatial rootNode;
+    JmeAnimation animation;
+
+    public AudioTrackWizardAction(Spatial rootNode, JmeAnimation animation) {
+        this.rootNode = rootNode;
+        this.animation = animation;
+    }
+
+    public @Override
+    void actionPerformed(ActionEvent e) {
+        WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
+        // {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
+        wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
+        wizardDescriptor.setTitle("Create a new AudioTrack");
+        Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
+        dialog.setVisible(true);
+        dialog.toFront();
+        boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
+        if (!cancelled) {
+            AudioNode audio = (AudioNode) wizardDescriptor.getProperty("Audio");
+            float startOffset = (Float) wizardDescriptor.getProperty("startOffset");
+            Animation anim = animation.getLookup().lookup(Animation.class);
+            anim.addTrack(new AudioTrack(audio, anim.getLength(), startOffset));
+
+            animation.refresh(false);
+            animation.setChanged();
+        }
+    }
+
+    /**
+     * Initialize panels representing individual wizard's steps and sets
+     * various properties for them influencing wizard appearance.
+     */
+    private WizardDescriptor.Panel[] getPanels() {
+        if (panels == null) {
+            panels = new WizardDescriptor.Panel[]{
+                new AudioTrackWizardPanel1(rootNode, animation)
+            };
+            String[] steps = new String[panels.length];
+            for (int i = 0; i < panels.length; i++) {
+                Component c = panels[i].getComponent();
+                // Default step name to component name of panel. Mainly useful
+                // for getting the name of the target chooser to appear in the
+                // list of steps.
+                steps[i] = c.getName();
+                if (c instanceof JComponent) { // assume Swing components
+                    JComponent jc = (JComponent) c;
+                    // Sets step number of a component
+                    // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*:
+                    jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
+                    // Sets steps names for a panel
+                    jc.putClientProperty("WizardPanel_contentData", steps);
+                    // Turn on subtitle creation on each step
+                    jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
+                    // Show steps on the left side with the image on the background
+                    jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
+                    // Turn on numbering of all steps
+                    jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
+                }
+            }
+        }
+        return panels;
+    }
+}

+ 126 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/AudioTrackWizardPanel1.java

@@ -0,0 +1,126 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks;
+
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimation;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.util.HelpCtx;
+
+public class AudioTrackWizardPanel1 implements WizardDescriptor.Panel {
+
+    Spatial rootNode;
+    JmeAnimation animation;
+
+    public AudioTrackWizardPanel1(Spatial rootNode, JmeAnimation animation) {
+        this.rootNode = rootNode;
+        this.animation = animation;
+    }
+    /**
+     * The visual component that displays this panel. If you need to access the
+     * component from this class, just use getComponent().
+     */
+    private Component component;
+
+    // Get the visual component for the panel. In this template, the component
+    // is kept separate. This can be more efficient: if the wizard is created
+    // but never displayed, or not all panels are displayed, it is better to
+    // create only those which really need to be visible.
+    public Component getComponent() {
+        if (component == null) {
+            component = new AudioTrackVisualPanel1(rootNode, animation);
+        }
+        return component;
+    }
+
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx(SampleWizardPanel1.class);
+    }
+
+    public boolean isValid() {
+        // If it is always OK to press Next or Finish, then:
+        return true;
+        // If it depends on some condition (form filled out...), then:
+        // return someCondition();
+        // and when this condition changes (last form field filled in...) then:
+        // fireChangeEvent();
+        // and uncomment the complicated stuff below.
+    }
+
+    public final void addChangeListener(ChangeListener l) {
+    }
+
+    public final void removeChangeListener(ChangeListener l) {
+    }
+    /*
+    private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(1); // or can use ChangeSupport in NB 6.0
+    public final void addChangeListener(ChangeListener l) {
+    synchronized (listeners) {
+    listeners.add(l);
+    }
+    }
+    public final void removeChangeListener(ChangeListener l) {
+    synchronized (listeners) {
+    listeners.remove(l);
+    }
+    }
+    protected final void fireChangeEvent() {
+    Iterator<ChangeListener> it;
+    synchronized (listeners) {
+    it = new HashSet<ChangeListener>(listeners).iterator();
+    }
+    ChangeEvent ev = new ChangeEvent(this);
+    while (it.hasNext()) {
+    it.next().stateChanged(ev);
+    }
+    }
+     */
+
+    // You can use a settings object to keep track of state. Normally the
+    // settings object will be the WizardDescriptor, so you can use
+    // WizardDescriptor.getProperty & putProperty to store information entered
+    // by the user.
+    public void readSettings(Object settings) {
+    }
+
+    public void storeSettings(Object settings) {
+        WizardDescriptor wiz = (WizardDescriptor) settings;
+        AudioTrackVisualPanel1 comp = (AudioTrackVisualPanel1) getComponent();
+        wiz.putProperty("Audio", comp.getAudioNode());
+        wiz.putProperty("startOffset", comp.getStartOffset());
+    }
+}

+ 11 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties

@@ -0,0 +1,11 @@
+Error reading included file Templates/Other/../Licenses/license-jme.txt
+EffectTrackVisualPanel1.jLabel1.text=Effect Track
+EffectTrackVisualPanel1.jLabel2.text=Particle emitter
+EffectTrackVisualPanel1.jLabel3.text=Start offset
+EffectTrackVisualPanel1.jLabel5.text=Length
+EffectTrackVisualPanel1.lengthLabel.text=jLabel6
+AudioTrackVisualPanel1.jLabel1.text=Audio Track
+AudioTrackVisualPanel1.jLabel5.text=Length
+AudioTrackVisualPanel1.jLabel2.text=Audio node
+AudioTrackVisualPanel1.jLabel3.text=Start offset
+AudioTrackVisualPanel1.lengthLabel.text=jLabel6

+ 183 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackVisualPanel1.form

@@ -0,0 +1,183 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
+            <EtchetBorder/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jLabel1" pref="390" max="32767" attributes="0"/>
+                      <Component id="jSeparator1" alignment="1" pref="390" max="32767" attributes="0"/>
+                      <Group type="102" alignment="0" attributes="0">
+                          <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                              <Component id="jLabel2" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jLabel5" alignment="0" pref="107" max="32767" attributes="1"/>
+                              <Component id="jLabel3" alignment="1" min="-2" pref="92" max="-2" attributes="1"/>
+                          </Group>
+                          <EmptySpace type="separate" max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                              <Component id="lengthLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="jComboBox1" alignment="0" pref="157" max="32767" attributes="1"/>
+                              <Component id="jLabel4" alignment="0" pref="243" max="32767" attributes="0"/>
+                              <Component id="jSlider1" alignment="1" max="32767" attributes="1"/>
+                          </Group>
+                          <EmptySpace pref="22" max="32767" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="lengthLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="jComboBox1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace min="14" pref="14" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                      <Component id="jSlider1" min="-2" pref="23" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace pref="27" max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="jLabel1">
+          <Properties>
+            <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+              <Font name="Tahoma" size="12" style="1"/>
+            </Property>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/com/jme3/gde/core/sceneexplorer/nodes/icons/effectTrack.png"/>
+            </Property>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="EffectTrackVisualPanel1.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JSeparator" name="jSeparator1">
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel2">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="4"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="EffectTrackVisualPanel1.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel3">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="11"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="EffectTrackVisualPanel1.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+            <Property name="verticalAlignment" type="int" value="1"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="jComboBox1">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="4">
+                <StringItem index="0" value="Item 1"/>
+                <StringItem index="1" value="Item 2"/>
+                <StringItem index="2" value="Item 3"/>
+                <StringItem index="3" value="Item 4"/>
+              </StringArray>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JSlider" name="jSlider1">
+          <Properties>
+            <Property name="value" type="int" value="0"/>
+          </Properties>
+          <Events>
+            <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="jSlider1StateChanged"/>
+            <EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="jSlider1PropertyChange"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel4">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="0"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="jSlider1.getValue()+&quot;&quot;" type="code"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel5">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="4"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="EffectTrackVisualPanel1.jLabel5.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="lengthLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/Bundle.properties" key="EffectTrackVisualPanel1.lengthLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>

+ 231 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackVisualPanel1.java

@@ -0,0 +1,231 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks;
+
+import com.jme3.animation.Animation;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimation;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+
+public final class EffectTrackVisualPanel1 extends JPanel {
+
+    Spatial rootNode;
+    JmeAnimation animation;
+
+    /** Creates new form EffectTrackVisualPanel1 */
+    public EffectTrackVisualPanel1(Spatial rootNode, JmeAnimation animation) {
+        this.rootNode = rootNode;
+        this.animation = animation;
+        initComponents();
+        lengthLabel.setText(animation.getLookup().lookup(Animation.class).getLength() + "");
+        DefaultComboBoxModel model = new DefaultComboBoxModel();
+
+        populateModel(rootNode, model);
+        jComboBox1.setModel(model);
+        jComboBox1.setRenderer(new ListCellRenderer() {
+
+            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                return new JLabel(((Spatial) value).getName());
+            }
+        });
+        jSlider1.setMaximum((int) (animation.getLookup().lookup(Animation.class).getLength() * 100));
+    }
+
+    private void populateModel(Spatial root, DefaultComboBoxModel model) {
+        if (root instanceof Node) {
+            Node n = (Node) root;
+            for (Spatial child : n.getChildren()) {
+                populateModel(child, model);
+            }
+        } else if (root instanceof ParticleEmitter) {
+            model.addElement((ParticleEmitter) root);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "Create a new EffectTrack";
+    }
+
+    public ParticleEmitter getEmitter() {
+        return (ParticleEmitter) jComboBox1.getSelectedItem();
+    }
+
+    public float getStartOffset() {
+        return (float) jSlider1.getValue() / 100f;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanel1 = new javax.swing.JPanel();
+        jLabel1 = new javax.swing.JLabel();
+        jSeparator1 = new javax.swing.JSeparator();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jComboBox1 = new javax.swing.JComboBox();
+        jSlider1 = new javax.swing.JSlider();
+        jLabel4 = new javax.swing.JLabel();
+        jLabel5 = new javax.swing.JLabel();
+        lengthLabel = new javax.swing.JLabel();
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
+
+        jLabel1.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
+        jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/core/sceneexplorer/nodes/icons/effectTrack.png"))); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(EffectTrackVisualPanel1.class, "EffectTrackVisualPanel1.jLabel1.text")); // NOI18N
+
+        jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(EffectTrackVisualPanel1.class, "EffectTrackVisualPanel1.jLabel2.text")); // NOI18N
+
+        jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(EffectTrackVisualPanel1.class, "EffectTrackVisualPanel1.jLabel3.text")); // NOI18N
+        jLabel3.setVerticalAlignment(javax.swing.SwingConstants.TOP);
+
+        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+
+        jSlider1.setValue(0);
+        jSlider1.addChangeListener(new javax.swing.event.ChangeListener() {
+            public void stateChanged(javax.swing.event.ChangeEvent evt) {
+                jSlider1StateChanged(evt);
+            }
+        });
+        jSlider1.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
+            public void propertyChange(java.beans.PropertyChangeEvent evt) {
+                jSlider1PropertyChange(evt);
+            }
+        });
+
+        jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, jSlider1.getValue()+"");
+
+        jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel5, org.openide.util.NbBundle.getMessage(EffectTrackVisualPanel1.class, "EffectTrackVisualPanel1.jLabel5.text")); // NOI18N
+
+        org.openide.awt.Mnemonics.setLocalizedText(lengthLabel, org.openide.util.NbBundle.getMessage(EffectTrackVisualPanel1.class, "EffectTrackVisualPanel1.lengthLabel.text")); // NOI18N
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE)
+                    .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 390, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                            .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(jLabel5, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
+                            .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addGap(18, 18, 18)
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                            .addComponent(lengthLabel, javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jComboBox1, javax.swing.GroupLayout.Alignment.LEADING, 0, 157, Short.MAX_VALUE)
+                            .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE)
+                            .addComponent(jSlider1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 22, Short.MAX_VALUE)))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel5)
+                    .addComponent(lengthLabel))
+                .addGap(18, 18, 18)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel2)
+                    .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addGap(14, 14, 14)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel3)
+                    .addComponent(jSlider1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel4)
+                .addContainerGap(27, Short.MAX_VALUE))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+private void jSlider1PropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_jSlider1PropertyChange
+}//GEN-LAST:event_jSlider1PropertyChange
+
+private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider1StateChanged
+    jLabel4.setText(((float) jSlider1.getValue() / 100f) + "");
+}//GEN-LAST:event_jSlider1StateChanged
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JComboBox jComboBox1;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JSlider jSlider1;
+    private javax.swing.JLabel lengthLabel;
+    // End of variables declaration//GEN-END:variables
+}

+ 119 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackWizardAction.java

@@ -0,0 +1,119 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks;
+
+import com.jme3.animation.Animation;
+import com.jme3.animation.EffectTrack;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimation;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.MessageFormat;
+import javax.swing.JComponent;
+import org.openide.DialogDisplayer;
+import org.openide.WizardDescriptor;
+
+// An example action demonstrating how the wizard could be called from within
+// your code. You can move the code below wherever you need, or register an action:
+// @ActionID(category="...", id="com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks.EffectTrackWizardAction")
+// @ActionRegistration(displayName="Open EffectTrack Wizard")
+// @ActionReference(path="Menu/Tools", position=...)
+public final class EffectTrackWizardAction implements ActionListener {
+
+    private WizardDescriptor.Panel[] panels;
+    Spatial rootNode;
+    JmeAnimation animation;
+
+    public EffectTrackWizardAction(Spatial rootNode, JmeAnimation animation) {
+        this.rootNode = rootNode;
+        this.animation = animation;
+    }
+
+    public @Override
+    void actionPerformed(ActionEvent e) {
+        WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
+        // {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
+        wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
+        wizardDescriptor.setTitle("Create a new EffectTrack");
+        Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
+        dialog.setVisible(true);
+        dialog.toFront();
+        boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
+        if (!cancelled) {
+            ParticleEmitter emitter = (ParticleEmitter) wizardDescriptor.getProperty("Emitter");
+            float startOffset = (Float) wizardDescriptor.getProperty("startOffset");
+            Animation anim = animation.getLookup().lookup(Animation.class);
+            anim.addTrack(new EffectTrack(emitter, anim.getLength(), startOffset));                        
+                    
+            animation.refresh(false);
+            animation.setChanged();
+        }
+    }
+
+    /**
+     * Initialize panels representing individual wizard's steps and sets
+     * various properties for them influencing wizard appearance.
+     */
+    private WizardDescriptor.Panel[] getPanels() {
+        if (panels == null) {
+            panels = new WizardDescriptor.Panel[]{
+                new EffectTrackWizardPanel1(rootNode, animation)
+            };
+            String[] steps = new String[panels.length];
+            for (int i = 0; i < panels.length; i++) {
+                Component c = panels[i].getComponent();
+                // Default step name to component name of panel. Mainly useful
+                // for getting the name of the target chooser to appear in the
+                // list of steps.
+                steps[i] = c.getName();
+                if (c instanceof JComponent) { // assume Swing components
+                    JComponent jc = (JComponent) c;
+                    // Sets step number of a component
+                    // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*:
+                    jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
+                    // Sets steps names for a panel
+                    jc.putClientProperty("WizardPanel_contentData", steps);
+                    // Turn on subtitle creation on each step
+                    jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
+                    // Show steps on the left side with the image on the background
+                    jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
+                    // Turn on numbering of all steps
+                    jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
+                }
+            }
+        }
+        return panels;
+    }
+}

+ 126 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/impl/tracks/EffectTrackWizardPanel1.java

@@ -0,0 +1,126 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions.impl.tracks;
+
+import com.jme3.gde.core.sceneexplorer.nodes.JmeAnimation;
+import com.jme3.scene.Spatial;
+import java.awt.Component;
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.util.HelpCtx;
+
+public class EffectTrackWizardPanel1 implements WizardDescriptor.Panel {
+
+    Spatial rootNode;
+    JmeAnimation animation;
+
+    public EffectTrackWizardPanel1(Spatial rootNode, JmeAnimation animation) {
+        this.rootNode = rootNode;
+        this.animation = animation;
+    }
+    /**
+     * The visual component that displays this panel. If you need to access the
+     * component from this class, just use getComponent().
+     */
+    private Component component;
+
+    // Get the visual component for the panel. In this template, the component
+    // is kept separate. This can be more efficient: if the wizard is created
+    // but never displayed, or not all panels are displayed, it is better to
+    // create only those which really need to be visible.
+    public Component getComponent() {
+        if (component == null) {
+            component = new EffectTrackVisualPanel1(rootNode, animation);
+        }
+        return component;
+    }
+
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx(SampleWizardPanel1.class);
+    }
+
+    public boolean isValid() {
+        // If it is always OK to press Next or Finish, then:
+        return true;
+        // If it depends on some condition (form filled out...), then:
+        // return someCondition();
+        // and when this condition changes (last form field filled in...) then:
+        // fireChangeEvent();
+        // and uncomment the complicated stuff below.
+    }
+
+    public final void addChangeListener(ChangeListener l) {
+    }
+
+    public final void removeChangeListener(ChangeListener l) {
+    }
+    /*
+    private final Set<ChangeListener> listeners = new HashSet<ChangeListener>(1); // or can use ChangeSupport in NB 6.0
+    public final void addChangeListener(ChangeListener l) {
+    synchronized (listeners) {
+    listeners.add(l);
+    }
+    }
+    public final void removeChangeListener(ChangeListener l) {
+    synchronized (listeners) {
+    listeners.remove(l);
+    }
+    }
+    protected final void fireChangeEvent() {
+    Iterator<ChangeListener> it;
+    synchronized (listeners) {
+    it = new HashSet<ChangeListener>(listeners).iterator();
+    }
+    ChangeEvent ev = new ChangeEvent(this);
+    while (it.hasNext()) {
+    it.next().stateChanged(ev);
+    }
+    }
+     */
+
+    // You can use a settings object to keep track of state. Normally the
+    // settings object will be the WizardDescriptor, so you can use
+    // WizardDescriptor.getProperty & putProperty to store information entered
+    // by the user.
+    public void readSettings(Object settings) {
+    }
+
+    public void storeSettings(Object settings) {
+         WizardDescriptor wiz = (WizardDescriptor) settings;
+        EffectTrackVisualPanel1 comp = (EffectTrackVisualPanel1) getComponent();        
+        wiz.putProperty("Emitter", comp.getEmitter());
+        wiz.putProperty("startOffset", comp.getStartOffset());
+    }
+}

BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/anim.png


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/animPlay.png


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/animationcontrol.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/audioTrack.png


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/bitmaptext.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/boneTrack.png


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/charactercontrol.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/effectTrack.png


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/geometry.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/ghostcontrol.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/ghostnode.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/physicscontrol.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/skeletonControl.gif


BIN=BIN
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/icons/track.png


+ 1 - 0
jme3-core/src/com/jme3/gde/core/util/Bundle.properties

@@ -30,3 +30,4 @@
 
 ProjectSelection.jButton1.text=OK
 ProjectSelection.jButton2.text=Cancel
+SliderPanel.jTextField1.text=jTextField1

+ 127 - 0
jme3-core/src/com/jme3/gde/core/util/SliderInplaceEditor.java

@@ -0,0 +1,127 @@
+package com.jme3.gde.core.util;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.beans.PropertyEditor;
+import javax.swing.JComponent;
+import javax.swing.KeyStroke;
+import org.openide.explorer.propertysheet.InplaceEditor;
+import org.openide.explorer.propertysheet.PropertyEnv;
+import org.openide.explorer.propertysheet.PropertyModel;
+
+/**
+ *
+ * @author Nehon
+ */
+public class SliderInplaceEditor implements InplaceEditor {
+
+    private PropertyEditor editor = null;
+    private PropertyModel model;
+    private PropertyEnv env;
+    private SliderPanel slider = new SliderPanel();
+
+    public SliderInplaceEditor(float min, float max) {
+        super();
+        slider.setRangeFloat(min, max);
+    }
+
+    public SliderInplaceEditor(int min, int max) {
+        super();
+        slider.setRangeInt(min, max);
+    }
+
+    public void connect(PropertyEditor pe, PropertyEnv pe1) {
+        editor = pe;
+        env = pe1;
+        reset();
+    }
+
+    public void setRangeInt(int min, int max) {
+        slider.setRangeInt(min, max);
+    }
+
+    public void setRangeFloat(float min, float max) {
+        slider.setRangeFloat(min, max);
+    }
+
+    public JComponent getComponent() {
+        return slider;
+    }
+
+    public void setAsText(String s) {
+        slider.setAsText(s);
+    }
+
+    public void clear() {
+        editor = null;
+        model = null;
+    }
+
+    public Object getValue() {
+        if (slider.floatValue) {
+            return slider.getFloatValue();
+        } else {
+            return slider.getIntValue();
+        }
+    }
+
+    public void setValue(Object o) {
+        if (slider.floatValue) {
+            slider.setFloatValue((Float) o);
+        } else {
+            slider.setIntValue((Integer) o);
+        }
+    }
+
+    public boolean supportsTextEntry() {
+        return true;
+    }
+
+    public void reset() {
+        if (slider.floatValue) {
+            Float f = (Float) editor.getValue();
+            if (f != null) {
+                slider.setFloatValue(f);
+            }
+
+        } else {
+            Integer i = (Integer) editor.getValue();
+            if (i != null) {
+                slider.setIntValue(i);
+            }
+        }
+
+    }
+
+    public KeyStroke[] getKeyStrokes() {
+        return new KeyStroke[0];
+    }
+
+    public PropertyEditor getPropertyEditor() {
+        return editor;
+    }
+
+    public PropertyModel getPropertyModel() {
+        return model;
+    }
+
+    public void setPropertyModel(PropertyModel pm) {
+
+        this.model = pm;
+    }
+
+    public boolean isKnownComponent(Component cmpnt) {
+        return cmpnt == slider || slider.isAncestorOf(cmpnt);
+    }
+
+    public void addActionListener(ActionListener al) {
+        slider.addActionListener(al);
+    }
+
+    public void removeActionListener(ActionListener al) {
+        slider.removeActionListener(al);
+    }
+}

+ 61 - 0
jme3-core/src/com/jme3/gde/core/util/SliderPanel.form

@@ -0,0 +1,61 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jTextField1" min="-2" pref="38" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jSlider1" pref="272" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jTextField1" alignment="0" max="32767" attributes="1"/>
+          <Component id="jSlider1" alignment="0" min="0" pref="0" max="32767" attributes="1"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JSlider" name="jSlider1">
+      <Properties>
+        <Property name="value" type="int" value="0"/>
+      </Properties>
+      <Events>
+        <EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="jSlider1StateChanged"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jTextField1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/core/util/Bundle.properties" key="SliderPanel.jTextField1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[6, 20]"/>
+        </Property>
+        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[6, 20]"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jTextField1ActionPerformed"/>
+        <EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="jTextField1PropertyChange"/>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTextField1KeyPressed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>

+ 156 - 0
jme3-core/src/com/jme3/gde/core/util/SliderPanel.java

@@ -0,0 +1,156 @@
+
+/*
+ * SliderPanel.java
+ *
+ * Created on 4 août 2012, 00:25:41
+ */
+package com.jme3.gde.core.util;
+
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+
+/**
+ *
+ * @author Nehon
+ */
+public class SliderPanel extends javax.swing.JPanel {
+
+    protected boolean floatValue = false;
+
+    /** Creates new form SliderPanel */
+    public SliderPanel() {
+        initComponents();
+    }
+
+    public void setRangeInt(int min, int max) {
+        jSlider1.setMaximum(max);
+        jSlider1.setMinimum(min);
+        floatValue = false;
+    }
+
+    public void setRangeFloat(float min, float max) {
+        jSlider1.setMaximum((int) (max * 100f));
+        jSlider1.setMinimum((int) (min * 100f));
+        floatValue = true;
+    }
+
+    public void setFloatValue(float value) {
+        jSlider1.setValue((int) (value * 100f));
+    }
+
+    public void setIntValue(int value) {
+        jSlider1.setValue(value);
+    }
+
+    public float getFloatValue() {
+        return (float) jSlider1.getValue() / 100f;
+
+    }
+
+    public int getIntValue() {
+        return jSlider1.getValue();
+    }
+
+    public void setAsText(String s) {
+        try {
+            if (floatValue) {
+                jSlider1.setValue((int) (Float.parseFloat(s) * 100f));               
+            } else {
+                jSlider1.setValue(Integer.parseInt(s));                               
+            }            
+        } catch (NumberFormatException e) {
+            jSlider1.setValue(0);
+        }
+    }
+    
+    public void addActionListener(ActionListener al) {
+        jTextField1.addActionListener(al);
+    }
+
+    public void removeActionListener(ActionListener al) {
+        jTextField1.removeActionListener(al);
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jSlider1 = new javax.swing.JSlider();
+        jTextField1 = new javax.swing.JTextField();
+
+        jSlider1.setValue(0);
+        jSlider1.addChangeListener(new javax.swing.event.ChangeListener() {
+            public void stateChanged(javax.swing.event.ChangeEvent evt) {
+                jSlider1StateChanged(evt);
+            }
+        });
+
+        jTextField1.setText(org.openide.util.NbBundle.getMessage(SliderPanel.class, "SliderPanel.jTextField1.text")); // NOI18N
+        jTextField1.setMaximumSize(new java.awt.Dimension(6, 20));
+        jTextField1.setPreferredSize(new java.awt.Dimension(6, 20));
+        jTextField1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jTextField1ActionPerformed(evt);
+            }
+        });
+        jTextField1.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
+            public void propertyChange(java.beans.PropertyChangeEvent evt) {
+                jTextField1PropertyChange(evt);
+            }
+        });
+        jTextField1.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jTextField1KeyPressed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jSlider1, javax.swing.GroupLayout.DEFAULT_SIZE, 272, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(jSlider1, 0, 0, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider1StateChanged
+    if (floatValue) {
+        jTextField1.setText(((float) jSlider1.getValue() / 100f) + "");        
+    } else {
+        jTextField1.setText(jSlider1.getValue() + "");
+    }
+
+}//GEN-LAST:event_jSlider1StateChanged
+
+private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextField1ActionPerformed
+// TODO add your handling code here:
+}//GEN-LAST:event_jTextField1ActionPerformed
+
+private void jTextField1PropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_jTextField1PropertyChange
+    setAsText(jTextField1.getText());
+}//GEN-LAST:event_jTextField1PropertyChange
+
+private void jTextField1KeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextField1KeyPressed
+    if (evt.getKeyCode() == KeyEvent.VK_ENTER){
+        setAsText(jTextField1.getText());
+        jTextField1.setActionCommand("success");
+    }
+}//GEN-LAST:event_jTextField1KeyPressed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JSlider jSlider1;
+    private javax.swing.JTextField jTextField1;
+    // End of variables declaration//GEN-END:variables
+}