Browse Source

SDK : One can now add and edit user data of a custom data type. The custom type must be a Savable with get and set accessors for every attribute and propper read an write method.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9671 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
rem..om 13 years ago
parent
commit
767257dfe5

+ 22 - 4
jme3-core/src/com/jme3/gde/core/properties/UserDataProperty.java

@@ -32,8 +32,12 @@
 package com.jme3.gde.core.properties;
 package com.jme3.gde.core.properties;
 
 
 import com.jme3.gde.core.scene.SceneApplication;
 import com.jme3.gde.core.scene.SceneApplication;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.UserDataDialog;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.Spatial;
+import java.awt.Component;
 import java.beans.PropertyEditor;
 import java.beans.PropertyEditor;
+import java.beans.PropertyEditorSupport;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.LinkedList;
@@ -42,6 +46,7 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutionException;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
+import javax.swing.JFrame;
 import org.openide.nodes.PropertySupport;
 import org.openide.nodes.PropertySupport;
 import org.openide.util.Exceptions;
 import org.openide.util.Exceptions;
 
 
@@ -52,15 +57,17 @@ import org.openide.util.Exceptions;
 public class UserDataProperty extends PropertySupport.ReadWrite<String> {
 public class UserDataProperty extends PropertySupport.ReadWrite<String> {
 
 
     private Spatial spatial;
     private Spatial spatial;
+    private JmeSpatial node;
     private String name = "null";
     private String name = "null";
     private int type = 0;
     private int type = 0;
     private List<ScenePropertyChangeListener> listeners = new LinkedList<ScenePropertyChangeListener>();
     private List<ScenePropertyChangeListener> listeners = new LinkedList<ScenePropertyChangeListener>();
 
 
-    public UserDataProperty(Spatial node, String name) {
+    public UserDataProperty(JmeSpatial node, String name) {
         super(name, String.class, name, "");
         super(name, String.class, name, "");
-        this.spatial = node;
+        this.spatial = node.getLookup().lookup(Spatial.class);
+        this.node = node;
         this.name = name;
         this.name = name;
-        this.type = getObjectType(node.getUserData(name));
+        this.type = getObjectType(spatial.getUserData(name));
     }
     }
 
 
     public static int getObjectType(Object type) {
     public static int getObjectType(Object type) {
@@ -126,7 +133,18 @@ public class UserDataProperty extends PropertySupport.ReadWrite<String> {
 
 
     @Override
     @Override
     public PropertyEditor getPropertyEditor() {
     public PropertyEditor getPropertyEditor() {
-        return null;
+        return new PropertyEditorSupport(spatial.getUserData(name)) {
+
+            @Override
+            public boolean supportsCustomEditor() {
+                return true;
+            }
+
+            @Override
+            public Component getCustomEditor() {
+                return new UserDataDialog(new JFrame(), true, node, name);
+            }
+        };
 //        return new AnimationPropertyEditor(control);
 //        return new AnimationPropertyEditor(control);
     }
     }
 
 

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

@@ -304,7 +304,7 @@ public class JmeSpatial extends AbstractSceneExplorerNode {
             set.setName(Spatial.class.getName() + "_UserData");
             set.setName(Spatial.class.getName() + "_UserData");
             for (Iterator<String> it = dataKeys.iterator(); it.hasNext();) {
             for (Iterator<String> it = dataKeys.iterator(); it.hasNext();) {
                 String string = it.next();
                 String string = it.next();
-                UserDataProperty prop = new UserDataProperty(spatial, string);
+                UserDataProperty prop = new UserDataProperty(this, string);
                 prop.addPropertyChangeListener(this);
                 prop.addPropertyChangeListener(this);
                 set.put(prop);
                 set.put(prop);
             }
             }

+ 1 - 1
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/AddUserDataAction.java

@@ -43,7 +43,7 @@ public final class AddUserDataAction implements ActionListener {
 
 
     public AddUserDataAction(JmeSpatial context) {
     public AddUserDataAction(JmeSpatial context) {
         this.context = context;
         this.context = context;
-        dialog=new UserDataDialog(new JFrame(), true, context);
+        dialog=new UserDataDialog(new JFrame(), true, context,null);
     }
     }
 
 
     public void actionPerformed(ActionEvent ev) {
     public void actionPerformed(ActionEvent ev) {

+ 5 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/Bundle.properties

@@ -5,3 +5,8 @@ UserDataDialog.jButton2.text=Cancel
 UserDataDialog.jLabel1.text=Name:
 UserDataDialog.jLabel1.text=Name:
 UserDataDialog.jTextField2.text=
 UserDataDialog.jTextField2.text=
 UserDataDialog.jLabel2.text=Data:
 UserDataDialog.jLabel2.text=Data:
+UserDataDialog.jButton3.text=Remove
+UserDataPicker.jPanel1.border.title=Chose a UserData type
+UserDataPicker.jTextField1.text=
+UserDataPicker.jButton1.text=Ok
+UserDataPicker.jButton2.text=Cancel

+ 58 - 10
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/UserDataDialog.form

@@ -1,6 +1,12 @@
 <?xml version="1.1" encoding="UTF-8" ?>
 <?xml version="1.1" encoding="UTF-8" ?>
 
 
 <Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
 <Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <NonVisualComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+    </Container>
+  </NonVisualComponents>
   <Properties>
   <Properties>
     <Property name="defaultCloseOperation" type="int" value="2"/>
     <Property name="defaultCloseOperation" type="int" value="2"/>
   </Properties>
   </Properties>
@@ -22,20 +28,19 @@
   <Layout>
   <Layout>
     <DimensionLayout dim="0">
     <DimensionLayout dim="0">
       <Group type="103" groupAlignment="0" attributes="0">
       <Group type="103" groupAlignment="0" attributes="0">
-          <Group type="102" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="0" attributes="0">
               <Group type="103" groupAlignment="0" attributes="0">
-                  <Group type="102" alignment="1" attributes="0">
-                      <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jPanel1" max="32767" attributes="0"/>
                       <EmptySpace max="-2" attributes="0"/>
                       <EmptySpace max="-2" attributes="0"/>
-                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
                   </Group>
                   </Group>
-                  <Group type="102" alignment="1" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
                       <Group type="103" groupAlignment="1" attributes="0">
                       <Group type="103" groupAlignment="1" attributes="0">
                           <Group type="102" alignment="0" attributes="0">
                           <Group type="102" alignment="0" attributes="0">
                               <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
                               <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
                               <EmptySpace max="-2" attributes="0"/>
                               <EmptySpace max="-2" attributes="0"/>
-                              <Component id="jTextField2" pref="187" max="32767" attributes="0"/>
+                              <Component id="jTextField2" pref="196" max="32767" attributes="0"/>
                           </Group>
                           </Group>
                           <Group type="102" alignment="1" attributes="0">
                           <Group type="102" alignment="1" attributes="0">
                               <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
                               <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
@@ -45,9 +50,17 @@
                       </Group>
                       </Group>
                       <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
                       <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
                       <Component id="jComboBox1" min="-2" max="-2" attributes="0"/>
                       <Component id="jComboBox1" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jButton3" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="123" max="32767" attributes="0"/>
+                      <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
                   </Group>
                   </Group>
               </Group>
               </Group>
-              <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
           </Group>
           </Group>
       </Group>
       </Group>
     </DimensionLayout>
     </DimensionLayout>
@@ -65,12 +78,15 @@
                   <Component id="jTextField1" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="jTextField1" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
               </Group>
               </Group>
-              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
               <Group type="103" groupAlignment="3" attributes="0">
               <Group type="103" groupAlignment="3" attributes="0">
                   <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButton3" alignment="3" min="-2" max="-2" attributes="0"/>
               </Group>
               </Group>
-              <EmptySpace max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
           </Group>
           </Group>
       </Group>
       </Group>
     </DimensionLayout>
     </DimensionLayout>
@@ -79,15 +95,19 @@
     <Component class="javax.swing.JComboBox" name="jComboBox1">
     <Component class="javax.swing.JComboBox" name="jComboBox1">
       <Properties>
       <Properties>
         <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
         <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
-          <StringArray count="5">
+          <StringArray count="6">
             <StringItem index="0" value="String"/>
             <StringItem index="0" value="String"/>
             <StringItem index="1" value="Int"/>
             <StringItem index="1" value="Int"/>
             <StringItem index="2" value="Float"/>
             <StringItem index="2" value="Float"/>
             <StringItem index="3" value="Boolean"/>
             <StringItem index="3" value="Boolean"/>
             <StringItem index="4" value="Long"/>
             <StringItem index="4" value="Long"/>
+            <StringItem index="5" value="Custom"/>
           </StringArray>
           </StringArray>
         </Property>
         </Property>
       </Properties>
       </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jComboBox1ActionPerformed"/>
+      </Events>
     </Component>
     </Component>
     <Component class="javax.swing.JTextField" name="jTextField1">
     <Component class="javax.swing.JTextField" name="jTextField1">
       <Properties>
       <Properties>
@@ -140,5 +160,33 @@
         </Property>
         </Property>
       </Properties>
       </Properties>
     </Component>
     </Component>
+    <Component class="javax.swing.JButton" name="jButton3">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/Bundle.properties" key="UserDataDialog.jButton3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton3ActionPerformed"/>
+      </Events>
+    </Component>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+      <Properties>
+        <Property name="autoscrolls" type="boolean" value="true"/>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <EmptySpace min="0" pref="322" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+    </Container>
   </SubComponents>
   </SubComponents>
 </Form>
 </Form>

+ 214 - 14
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/UserDataDialog.java

@@ -37,26 +37,119 @@
  */
  */
 package com.jme3.gde.core.sceneexplorer.nodes.actions;
 package com.jme3.gde.core.sceneexplorer.nodes.actions;
 
 
+import com.jme3.effect.influencers.ParticleInfluencer;
+import com.jme3.export.Savable;
+import com.jme3.gde.core.assets.ProjectAssetManager;
+import com.jme3.gde.core.properties.SceneExplorerProperty;
+import com.jme3.gde.core.properties.ScenePropertyChangeListener;
 import com.jme3.gde.core.scene.SceneApplication;
 import com.jme3.gde.core.scene.SceneApplication;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
 import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
+import com.jme3.gde.core.util.PropertyUtils;
 import com.jme3.scene.Spatial;
 import com.jme3.scene.Spatial;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Label;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutionException;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.explorer.propertysheet.PropertyPanel;
 import org.openide.loaders.DataObject;
 import org.openide.loaders.DataObject;
+import org.openide.nodes.Node.Property;
+import org.openide.util.Exceptions;
 
 
 /**
 /**
  *
  *
  * @author normenhansen
  * @author normenhansen
  */
  */
-public class UserDataDialog extends javax.swing.JDialog {
+public class UserDataDialog extends javax.swing.JDialog implements ScenePropertyChangeListener {
 
 
     JmeSpatial spat;
     JmeSpatial spat;
+    boolean initialized = false;
+    Object userData;
 
 
     /** Creates new form UserDataDialog */
     /** Creates new form UserDataDialog */
-    public UserDataDialog(java.awt.Frame parent, boolean modal, JmeSpatial spat) {
+    public UserDataDialog(java.awt.Frame parent, boolean modal, JmeSpatial spat, String userDataName) {
         super(parent, modal);
         super(parent, modal);
         this.spat = spat;
         this.spat = spat;
+
+        setLocationRelativeTo(null);
         initComponents();
         initComponents();
+        jButton3.setVisible(false);
+        if (userDataName != null) {
+            jButton3.setVisible(true);
+            jTextField2.setEditable(false);
+            jComboBox1.setEnabled(false);
+
+            userData = spat.getLookup().lookup(Spatial.class).getUserData(userDataName);
+            jTextField2.setText(userDataName);
+            jTextField1.setText(userData.toString());
+            jPanel1.setVisible(false);
+            if (userData instanceof String) {
+                jComboBox1.setSelectedItem("String");
+            } else if (userData instanceof Integer) {
+                jComboBox1.setSelectedItem("Int");
+            } else if (userData instanceof Float) {
+                jComboBox1.setSelectedItem("Float");
+            } else if (userData instanceof Boolean) {
+                jComboBox1.setSelectedItem("Boolean");
+            } else if (userData instanceof Long) {
+                jComboBox1.setSelectedItem("Long");
+            } else {
+                jComboBox1.setSelectedItem("Custom");
+
+                buildCustomSheet(userData);
+            }
+        }
+    }
+
+    private void buildCustomSheet(Object userData) {
+        jPanel1.setVisible(true);
+        jTextField1.setEditable(false);
+        jTextField1.setText(userData.getClass().getName());
+        Class c = userData.getClass();
+        if (!initialized) {
+            initialized = true;
+
+
+            GridLayout layout = new GridLayout(0, 2);
+            layout.setHgap(10);
+            jPanel1.setLayout(layout);
+            jPanel1.setPreferredSize(new Dimension(300, c.getDeclaredFields().length * 20));
+
+
+            for (Field field : c.getDeclaredFields()) {
+                PropertyDescriptor prop = PropertyUtils.getPropertyDescriptor(c, field);
+                if (prop != null) {
+                    PropertyPanel p = new PropertyPanel(makeProperty(userData, prop.getPropertyType(), prop.getReadMethod().getName(), prop.getWriteMethod().getName(), prop.getDisplayName()));
+                    jPanel1.add(new Label(field.getName() + " :", Label.RIGHT));
+                    jPanel1.add(p);
+                }
+            }
+        }
+        setSize(getWidth(), getHeight() + c.getDeclaredFields().length * 20);
+
+    }
+
+    public void propertyChange(String property, Object oldValue, Object newValue) {
+        //System.out.println(property + " changed");
+    }
+
+    protected Property makeProperty(Object obj, Class returntype, String method, String setter, String name) {
+        Property prop = null;
+        try {
+
+            prop = new SceneExplorerProperty(obj.getClass().cast(obj), returntype, method, setter, this);
+
+            prop.setName(name);
+
+        } catch (NoSuchMethodException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        return prop;
     }
     }
 
 
     private void updateSpatial() {
     private void updateSpatial() {
@@ -71,6 +164,7 @@ public class UserDataDialog extends javax.swing.JDialog {
             SceneApplication.getApplication().enqueue(new Callable<Void>() {
             SceneApplication.getApplication().enqueue(new Callable<Void>() {
 
 
                 public Void call() throws Exception {
                 public Void call() throws Exception {
+
                     if (format.equals("String")) {
                     if (format.equals("String")) {
                         spatial.setUserData(name, data);
                         spatial.setUserData(name, data);
                     } else if (format.equals("Int")) {
                     } else if (format.equals("Int")) {
@@ -81,6 +175,8 @@ public class UserDataDialog extends javax.swing.JDialog {
                         spatial.setUserData(name, Boolean.parseBoolean(data));
                         spatial.setUserData(name, Boolean.parseBoolean(data));
                     } else if (format.equals("Long")) {
                     } else if (format.equals("Long")) {
                         spatial.setUserData(name, Long.parseLong(data));
                         spatial.setUserData(name, Long.parseLong(data));
+                    } else if (userData != null) {
+                        spatial.setUserData(name, userData);
                     }
                     }
                     return null;
                     return null;
                 }
                 }
@@ -93,6 +189,46 @@ public class UserDataDialog extends javax.swing.JDialog {
         setVisible(false);
         setVisible(false);
     }
     }
 
 
+    public void setUserDataType(String className) {
+        ProjectAssetManager manager = (ProjectAssetManager) spat.getLookup().lookup(ProjectAssetManager.class);
+        List<ClassLoader> loaders = manager.getClassLoaders();
+
+
+        Class clazz = null;
+        try {
+            clazz = getClass().getClassLoader().loadClass(className);
+        } catch (ClassNotFoundException ex) {
+        }
+        for (ClassLoader classLoader : loaders) {
+            if (clazz == null) {
+                try {
+                    clazz = classLoader.loadClass(className);
+                } catch (ClassNotFoundException ex) {
+                }
+            }
+        }
+        if (clazz != null) {
+            try {
+                Object obj = clazz.newInstance();
+                if (obj instanceof Savable) {
+                    userData = obj;
+                    buildCustomSheet(userData);
+                } else {
+                    DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("This is no ParticleInfluencer class!"));
+                }
+            } catch (InstantiationException ex) {
+                Exceptions.printStackTrace(ex);
+                DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Error instatiating class!"));
+            } catch (IllegalAccessException ex) {
+                Exceptions.printStackTrace(ex);
+                DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Error instatiating class!"));
+            }
+        } else {
+            DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Cannot find class: " + className + "\nMake sure the name is correct and the project is compiled,\nbest enable 'Save on Compile' in the project preferences."));
+        }
+
+    }
+
     /** This method is called from within the constructor to
     /** This method is called from within the constructor to
      * initialize the form.
      * initialize the form.
      * WARNING: Do NOT modify this code. The content of this method is
      * WARNING: Do NOT modify this code. The content of this method is
@@ -102,6 +238,7 @@ public class UserDataDialog extends javax.swing.JDialog {
     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
     private void initComponents() {
     private void initComponents() {
 
 
+        jScrollPane1 = new javax.swing.JScrollPane();
         jComboBox1 = new javax.swing.JComboBox();
         jComboBox1 = new javax.swing.JComboBox();
         jTextField1 = new javax.swing.JTextField();
         jTextField1 = new javax.swing.JTextField();
         jButton1 = new javax.swing.JButton();
         jButton1 = new javax.swing.JButton();
@@ -109,10 +246,17 @@ public class UserDataDialog extends javax.swing.JDialog {
         jLabel1 = new javax.swing.JLabel();
         jLabel1 = new javax.swing.JLabel();
         jTextField2 = new javax.swing.JTextField();
         jTextField2 = new javax.swing.JTextField();
         jLabel2 = new javax.swing.JLabel();
         jLabel2 = new javax.swing.JLabel();
+        jButton3 = new javax.swing.JButton();
+        jPanel1 = new javax.swing.JPanel();
 
 
         setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
         setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
 
 
-        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "String", "Int", "Float", "Boolean", "Long" }));
+        jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "String", "Int", "Float", "Boolean", "Long", "Custom" }));
+        jComboBox1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jComboBox1ActionPerformed(evt);
+            }
+        });
 
 
         jTextField1.setText(org.openide.util.NbBundle.getMessage(UserDataDialog.class, "UserDataDialog.jTextField1.text")); // NOI18N
         jTextField1.setText(org.openide.util.NbBundle.getMessage(UserDataDialog.class, "UserDataDialog.jTextField1.text")); // NOI18N
         jTextField1.addActionListener(new java.awt.event.ActionListener() {
         jTextField1.addActionListener(new java.awt.event.ActionListener() {
@@ -141,6 +285,26 @@ public class UserDataDialog extends javax.swing.JDialog {
 
 
         jLabel2.setText(org.openide.util.NbBundle.getMessage(UserDataDialog.class, "UserDataDialog.jLabel2.text")); // NOI18N
         jLabel2.setText(org.openide.util.NbBundle.getMessage(UserDataDialog.class, "UserDataDialog.jLabel2.text")); // NOI18N
 
 
+        jButton3.setText(org.openide.util.NbBundle.getMessage(UserDataDialog.class, "UserDataDialog.jButton3.text")); // NOI18N
+        jButton3.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton3ActionPerformed(evt);
+            }
+        });
+
+        jPanel1.setAutoscrolls(true);
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 322, Short.MAX_VALUE)
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 0, Short.MAX_VALUE)
+        );
+
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
         getContentPane().setLayout(layout);
         getContentPane().setLayout(layout);
         layout.setHorizontalGroup(
         layout.setHorizontalGroup(
@@ -148,23 +312,29 @@ public class UserDataDialog extends javax.swing.JDialog {
             .addGroup(layout.createSequentialGroup()
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
                 .addContainerGap()
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
-                        .addComponent(jButton2)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(jButton1))
-                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addContainerGap())
+                    .addGroup(layout.createSequentialGroup()
                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                         .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                             .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                             .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                 .addComponent(jLabel1)
                                 .addComponent(jLabel1)
                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                                .addComponent(jTextField2, javax.swing.GroupLayout.DEFAULT_SIZE, 187, Short.MAX_VALUE))
+                                .addComponent(jTextField2, javax.swing.GroupLayout.DEFAULT_SIZE, 196, Short.MAX_VALUE))
                             .addGroup(layout.createSequentialGroup()
                             .addGroup(layout.createSequentialGroup()
                                 .addComponent(jLabel2)
                                 .addComponent(jLabel2)
                                 .addGap(18, 18, 18)
                                 .addGap(18, 18, 18)
                                 .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 186, Short.MAX_VALUE)))
                                 .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 186, Short.MAX_VALUE)))
                         .addGap(18, 18, 18)
                         .addGap(18, 18, 18)
-                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
-                .addGap(20, 20, 20))
+                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addGap(20, 20, 20))
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(jButton3)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 123, Short.MAX_VALUE)
+                        .addComponent(jButton2)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jButton1)
+                        .addGap(20, 20, 20))))
         );
         );
         layout.setVerticalGroup(
         layout.setVerticalGroup(
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -178,11 +348,14 @@ public class UserDataDialog extends javax.swing.JDialog {
                     .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                     .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                     .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                     .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                     .addComponent(jLabel2))
                     .addComponent(jLabel2))
-                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(jButton1)
                     .addComponent(jButton1)
-                    .addComponent(jButton2))
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                    .addComponent(jButton2)
+                    .addComponent(jButton3))
+                .addContainerGap())
         );
         );
 
 
         pack();
         pack();
@@ -199,12 +372,39 @@ public class UserDataDialog extends javax.swing.JDialog {
     private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
     private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
         updateSpatial();
         updateSpatial();
     }//GEN-LAST:event_jButton1ActionPerformed
     }//GEN-LAST:event_jButton1ActionPerformed
+
+private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
+    spat.getLookup().lookup(Spatial.class).setUserData(jTextField2.getText(), null);
+    spat.refreshProperties();
+    spat.getLookup().lookup(DataObject.class).setModified(true);
+    setVisible(false);
+}//GEN-LAST:event_jButton3ActionPerformed
+
+private void jComboBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jComboBox1ActionPerformed
+    if (jComboBox1.getSelectedItem().equals("Custom")) {
+        if (userData != null) {
+            buildCustomSheet(userData);
+
+        } else {
+            UserDataPicker picker = new UserDataPicker(null, true, this, spat);
+            picker.setVisible(true);
+        }
+    } else {
+        jPanel1.setVisible(false);
+        jTextField1.setEditable(true);
+        setSize(getWidth(), getHeight() - jPanel1.getHeight());
+
+    }
+}//GEN-LAST:event_jComboBox1ActionPerformed
     // Variables declaration - do not modify//GEN-BEGIN:variables
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JButton jButton1;
     private javax.swing.JButton jButton1;
     private javax.swing.JButton jButton2;
     private javax.swing.JButton jButton2;
+    private javax.swing.JButton jButton3;
     private javax.swing.JComboBox jComboBox1;
     private javax.swing.JComboBox jComboBox1;
     private javax.swing.JLabel jLabel1;
     private javax.swing.JLabel jLabel1;
     private javax.swing.JLabel jLabel2;
     private javax.swing.JLabel jLabel2;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JScrollPane jScrollPane1;
     private javax.swing.JTextField jTextField1;
     private javax.swing.JTextField jTextField1;
     private javax.swing.JTextField jTextField2;
     private javax.swing.JTextField jTextField2;
     // End of variables declaration//GEN-END:variables
     // End of variables declaration//GEN-END:variables

+ 138 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/UserDataPicker.form

@@ -0,0 +1,138 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <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">
+          <Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace pref="225" max="32767" attributes="0"/>
+              <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+              <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">
+              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="32767" 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.TitledBorderInfo">
+            <TitledBorder title="Chose a UserData type">
+              <ResourceString PropertyName="titleX" bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/Bundle.properties" key="UserDataPicker.jPanel1.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </TitledBorder>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="1" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="1" attributes="0">
+                      <Component id="jTextField1" alignment="0" pref="323" max="32767" attributes="0"/>
+                      <Component id="jScrollPane1" alignment="0" pref="323" max="32767" attributes="0"/>
+                  </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">
+                  <Component id="jScrollPane1" min="-2" pref="204" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jTextField1" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JList" name="jList1">
+              <Properties>
+                <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+                  <StringArray count="1">
+                    <StringItem index="0" value="Loading Savable types..."/>
+                  </StringArray>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jList1MouseClicked"/>
+                <EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="jList1ValueChanged"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <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/sceneexplorer/nodes/actions/Bundle.properties" key="UserDataPicker.jTextField1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButton1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/Bundle.properties" key="UserDataPicker.jButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButton2">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/core/sceneexplorer/nodes/actions/Bundle.properties" key="UserDataPicker.jButton2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton2ActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>

+ 284 - 0
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/UserDataPicker.java

@@ -0,0 +1,284 @@
+ /*
+ *  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.
+ */
+/*
+ * UserDataPicker.java
+ *
+ * Created on 20 août 2012, 22:09:04
+ */
+package com.jme3.gde.core.sceneexplorer.nodes.actions;
+
+import com.jme3.gde.core.assets.ProjectAssetManager;
+import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
+import java.awt.EventQueue;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.swing.DefaultListModel;
+import javax.swing.JComboBox;
+import javax.swing.ListModel;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.source.ClassIndex;
+import org.netbeans.api.java.source.ClassIndex.NameKind;
+import org.netbeans.api.java.source.ClassIndex.SearchScope;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.project.Sources;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Nehon
+ */
+public class UserDataPicker extends javax.swing.JDialog {
+
+    UserDataDialog parentDialog;
+    JmeSpatial spat;
+
+    /** Creates new form UserDataPicker */
+    public UserDataPicker(java.awt.Frame parent, boolean modal, UserDataDialog parentDialog, JmeSpatial spat) {
+        super(parent, modal);
+        this.spat = spat;
+        this.parentDialog = parentDialog;
+        initComponents();
+
+        setLocationRelativeTo(null);
+        ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
+
+        jList1.setEnabled(false);
+        //loading savable list in a new Thread
+        exec.execute(new Runnable() {
+
+            public void run() {
+                final DefaultListModel model = getSources();
+                EventQueue.invokeLater(new Runnable() {
+
+                    public void run() {
+                        jList1.setModel(model);
+                        jList1.setEnabled(true);
+                    }
+                });
+
+            }
+        });
+
+
+    }
+
+    private DefaultListModel getSources() {
+        final DefaultListModel model = new DefaultListModel();
+        Sources sources = spat.getLookup().lookup(ProjectAssetManager.class).getProject().getLookup().lookup(Sources.class);
+        if (sources != null) {
+            SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
+            if (groups != null) {
+                for (SourceGroup sourceGroup : groups) {
+                    ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.getClassPath(sourceGroup.getRootFolder(), ClassPath.BOOT),
+                            ClassPath.getClassPath(sourceGroup.getRootFolder(), ClassPath.COMPILE),
+                            ClassPath.getClassPath(sourceGroup.getRootFolder(), ClassPath.SOURCE));
+
+                    HashSet<SearchScope> set = new HashSet<SearchScope>();
+                    set.add(ClassIndex.SearchScope.SOURCE);
+
+                    Set<ElementHandle<TypeElement>> types = cpInfo.getClassIndex().getDeclaredTypes("", NameKind.PREFIX, set);
+                    for (Iterator<ElementHandle<TypeElement>> it = types.iterator(); it.hasNext();) {
+                        final ElementHandle<TypeElement> elementHandle = it.next();
+                        JavaSource js = JavaSource.create(cpInfo);
+                        try {
+                            js.runUserActionTask(new Task<CompilationController>() {
+
+                                public void run(CompilationController control)
+                                        throws Exception {
+                                    control.toPhase(Phase.RESOLVED);
+                                    //TODO: check with proper casting check.. gotta get TypeMirror of Control interface..
+//                                    TypeUtilities util = control.getTypeUtilities();//.isCastable(Types., null)
+//                                    util.isCastable(null, null);
+                                    TypeElement elem = elementHandle.resolve(control);
+                                    List<? extends TypeMirror> interfaces = elem.getInterfaces();
+                                    for (TypeMirror typeMirror : interfaces) {
+                                        String interfaceName = typeMirror.toString();
+                                        if ("com.jme3.export.Savable".equals(interfaceName)) {
+                                            model.addElement(elem.getQualifiedName().toString());
+                                        }
+                                    }
+                                }
+                            }, false);
+                        } catch (Exception ioe) {
+                            Exceptions.printStackTrace(ioe);
+                        }
+                    }
+
+                }
+            }
+        }
+        return model;
+    }
+
+    /** 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() {
+
+        jPanel1 = new javax.swing.JPanel();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jList1 = new javax.swing.JList();
+        jTextField1 = new javax.swing.JTextField();
+        jButton1 = new javax.swing.JButton();
+        jButton2 = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+
+        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(UserDataPicker.class, "UserDataPicker.jPanel1.border.title"))); // NOI18N
+
+        jList1.setModel(new javax.swing.AbstractListModel() {
+            String[] strings = { "Loading Savable types..." };
+            public int getSize() { return strings.length; }
+            public Object getElementAt(int i) { return strings[i]; }
+        });
+        jList1.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jList1MouseClicked(evt);
+            }
+        });
+        jList1.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
+                jList1ValueChanged(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jList1);
+
+        jTextField1.setText(org.openide.util.NbBundle.getMessage(UserDataPicker.class, "UserDataPicker.jTextField1.text")); // NOI18N
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(jTextField1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 323, Short.MAX_VALUE)
+                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 323, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 204, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jButton1.setText(org.openide.util.NbBundle.getMessage(UserDataPicker.class, "UserDataPicker.jButton1.text")); // NOI18N
+        jButton1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton1ActionPerformed(evt);
+            }
+        });
+
+        jButton2.setText(org.openide.util.NbBundle.getMessage(UserDataPicker.class, "UserDataPicker.jButton2.text")); // NOI18N
+        jButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton2ActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jButton2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 225, Short.MAX_VALUE)
+                .addComponent(jButton1)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jButton1)
+                    .addComponent(jButton2))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
+    setVisible(false);
+}//GEN-LAST:event_jButton2ActionPerformed
+
+private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
+
+
+    parentDialog.setUserDataType(jTextField1.getText());
+    setVisible(false);
+
+}//GEN-LAST:event_jButton1ActionPerformed
+
+private void jList1ValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jList1ValueChanged
+    jTextField1.setText(jList1.getSelectedValue().toString());
+}//GEN-LAST:event_jList1ValueChanged
+
+private void jList1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jList1MouseClicked
+    if (evt.getClickCount() == 2) {
+        jButton1ActionPerformed(null);
+    }
+}//GEN-LAST:event_jList1MouseClicked
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButton1;
+    private javax.swing.JButton jButton2;
+    private javax.swing.JList jList1;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTextField jTextField1;
+    // End of variables declaration//GEN-END:variables
+}