Browse Source

Added a Project-Upgrader to allow automated (wizard-driven) upgrades from 3.0 projects to 3.1

MeFisto94 9 years ago
parent
commit
fd01359136

+ 53 - 16
jme3-core/src/com/jme3/gde/core/assets/AssetsLookupProvider.java

@@ -32,6 +32,7 @@
 package com.jme3.gde.core.assets;
 
 import com.jme3.gde.core.j2seproject.ProjectExtensionManager;
+import com.jme3.gde.core.j2seproject.actions.UpgradeProjectWizardAction;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -40,6 +41,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import org.netbeans.api.project.Project;
 import org.netbeans.api.project.ProjectManager;
+import org.netbeans.api.project.ProjectUtils;
 import org.netbeans.modules.java.j2seproject.J2SEProject;
 import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator;
 import org.netbeans.spi.project.LookupProvider;
@@ -65,6 +67,7 @@ public class AssetsLookupProvider implements LookupProvider {
 
     private static final Logger logger = Logger.getLogger(AssetsLookupProvider.class.getName());
     private Project project;
+    private ProjectOpenedHook openedHook;
     public static final String[] keyList = new String[]{
         "assets.jar.name",
         "assets.folder.name",
@@ -104,6 +107,7 @@ public class AssetsLookupProvider implements LookupProvider {
                 String assetsFolderName = properties.getProperty("assets.folder.name", "assets");
                 if (prj.getProjectDirectory().getFileObject(assetsFolderName) != null) {
                     logger.log(Level.FINE, "Valid jMP project, extending with ProjectAssetManager");
+                    openedHook = genOpenedHook(project);
                     return Lookups.fixed(new ProjectAssetManager(prj, assetsFolderName), openedHook);
                 }
             } catch (Exception ex) {
@@ -117,25 +121,58 @@ public class AssetsLookupProvider implements LookupProvider {
 
         return Lookups.fixed();
     }
-    private ProjectOpenedHook openedHook = new ProjectOpenedHook() {
-        @Override
-        protected void projectClosed() {
-        }
+    
+    private ProjectOpenedHook genOpenedHook(final Project context) {
+        return new ProjectOpenedHook() {
+            @Override
+            protected void projectClosed() {
+            }
 
-        @Override
-        protected void projectOpened() {
-            if (project instanceof J2SEProject) {
-                EditableProperties properties = getProperties(project);
-                if (properties.getProperty("assets.folder.name") != null) {
-                    manager.checkExtension(project);
-//                    String version = properties.getProperty("jme.project.version");
-//                    if(version == null){
-//                        DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("This project is not compatible with the current SDK.",Message.ERROR_MESSAGE));
-//                    }
+            @Override
+            protected void projectOpened() {
+                if (context instanceof J2SEProject) {
+                    EditableProperties properties = getProperties(context);
+                    if (properties.getProperty("assets.folder.name") != null) {
+                        manager.checkExtension(context);
+
+                        String version = properties.getProperty("jme.project.version");
+                        String projectName = ProjectUtils.getInformation(context).getDisplayName();
+                        if (version == null) {
+                            if (UpgradeProjectWizardAction.isJME31(context)) { /* Upgrade project.properties */
+
+                                logger.log(Level.WARNING, "[" + projectName + "] Found 3.1 project, upgrading project.properties");
+
+                                FileObject prProp = context.getProjectDirectory().getFileObject("nbproject/project.properties");
+                                if (prProp != null && prProp.isValid()) {
+                                    FileLock lock = null;
+                                    try {
+                                        lock = prProp.lock();
+                                        InputStream in = prProp.getInputStream();
+                                        EditableProperties edProps = new EditableProperties(true);
+                                        edProps.load(in);
+                                        in.close();
+
+                                        edProps.setProperty("jme.project.version", "3.1"); // Silently accept them.
+                                        OutputStream out = prProp.getOutputStream(lock);
+                                        edProps.store(out);
+                                        out.close();
+                                    } catch (Exception e) {
+                                        logger.log(Level.WARNING, "Error when trying to write project.properties. Exception: {0}", e.getMessage());
+                                    } finally {
+                                        if (lock != null) {
+                                            lock.releaseLock();
+                                        }
+                                    }
+                                }
+                            } else {
+                                DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("The project \"" + projectName + "\" is not compatible with the current SDK.\nIt has to be updated before you can use it.\nRight Click on the Project and select \"Upgrade Project\" (You can choose to keep 3.0 compatibility!)", Message.ERROR_MESSAGE));
+                            }
+                        }
+                    }
                 }
             }
-        }
-    };
+        };
+    }
 
     public static EditableProperties getProperties(Project project) {
         EditableProperties props = new EditableProperties(true);

+ 6 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/Bundle.properties

@@ -0,0 +1,6 @@
+UpgradeProjectVisualPanel1.jRadioButton1.text=Keep 3.0 Compatibility (Partial Upgrade)
+UpgradeProjectVisualPanel1.jRadioButton2.text=Upgrade to 3.1
+UpgradeProjectVisualPanel1.jTextPane1.text=As software evolves, old files can get deprecated and need an overhaul.\nThis also happened to SDK Project Files as we moved from 3.0 to 3.1\nLuckily there is this upgrader, which will do all the work for you.\n\n\
+Note: In case of emergency, open "nbproject/project.properties" with Netbeans\nand click on the history button in the upper left corner.\nThere you can revert the changes.\n\n\
+There are two ways I can do the upgrade: I can do a partial upgrade, which means\nyour file will be marked as a 3.0 project and only backwards-compatible changes\nare applied. That way you won't be able to compile the project under 3.1,\nbut it will work under 3.0 (and stop the warnings in 3.1). Use this way if you manage your dependencies (libs)\nmanually or if you don't use the Netbeans' compile/deploy.\n\n\
+The other way is the simple upgrade: Your project will be upgraded to 3.1,\nhowever it won't be openable under 3.0 anymore.

+ 87 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectVisualPanel1.form

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.ButtonGroup" name="buttonGroup1">
+    </Component>
+  </NonVisualComponents>
+  <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" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
+                  <Component id="jRadioButton1" pref="588" max="32767" attributes="0"/>
+                  <Component id="jRadioButton2" alignment="0" 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">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jScrollPane1" pref="274" max="32767" attributes="0"/>
+              <EmptySpace type="separate" max="-2" attributes="0"/>
+              <Component id="jRadioButton1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jRadioButton2" min="-2" pref="17" max="-2" attributes="0"/>
+              <EmptySpace max="-2" 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.JTextPane" name="jTextPane1">
+          <Properties>
+            <Property name="editable" type="boolean" value="false"/>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="com/jme3/gde/core/j2seproject/actions/Bundle.properties" key="UpgradeProjectVisualPanel1.jTextPane1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JRadioButton" name="jRadioButton1">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="buttonGroup1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/core/j2seproject/actions/Bundle.properties" key="UpgradeProjectVisualPanel1.jRadioButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="jRadioButton2">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="buttonGroup1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/jme3/gde/core/j2seproject/actions/Bundle.properties" key="UpgradeProjectVisualPanel1.jRadioButton2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>

+ 93 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectVisualPanel1.java

@@ -0,0 +1,93 @@
+package com.jme3.gde.core.j2seproject.actions;
+
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import org.netbeans.api.project.Project;
+
+public final class UpgradeProjectVisualPanel1 extends JPanel {
+
+    private final Project context;
+    /**
+     * Creates new form UpgradeProjectVisualPanel1
+     */
+    public UpgradeProjectVisualPanel1(Project context) {
+        this.context = context;
+        initComponents();
+        
+        jRadioButton2.setSelected(true);
+    }
+
+    @Override
+    public String getName() {
+        return "Introduction";
+    }
+    
+    public boolean flatUpgrade() {
+        return (jRadioButton1.isSelected());
+    }
+    
+    public JRadioButton getRadioButton1() {
+        return jRadioButton1;
+    }
+    
+    public JRadioButton getRadioButton2() {
+        return jRadioButton2;
+    }
+
+    /**
+     * 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() {
+
+        buttonGroup1 = new javax.swing.ButtonGroup();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTextPane1 = new javax.swing.JTextPane();
+        jRadioButton1 = new javax.swing.JRadioButton();
+        jRadioButton2 = new javax.swing.JRadioButton();
+
+        jTextPane1.setEditable(false);
+        jTextPane1.setText(org.openide.util.NbBundle.getMessage(UpgradeProjectVisualPanel1.class, "UpgradeProjectVisualPanel1.jTextPane1.text")); // NOI18N
+        jScrollPane1.setViewportView(jTextPane1);
+
+        buttonGroup1.add(jRadioButton1);
+        org.openide.awt.Mnemonics.setLocalizedText(jRadioButton1, org.openide.util.NbBundle.getMessage(UpgradeProjectVisualPanel1.class, "UpgradeProjectVisualPanel1.jRadioButton1.text")); // NOI18N
+
+        buttonGroup1.add(jRadioButton2);
+        org.openide.awt.Mnemonics.setLocalizedText(jRadioButton2, org.openide.util.NbBundle.getMessage(UpgradeProjectVisualPanel1.class, "UpgradeProjectVisualPanel1.jRadioButton2.text")); // NOI18N
+
+        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()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jScrollPane1)
+                    .addComponent(jRadioButton1, javax.swing.GroupLayout.DEFAULT_SIZE, 588, Short.MAX_VALUE)
+                    .addComponent(jRadioButton2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE)
+                .addGap(18, 18, 18)
+                .addComponent(jRadioButton1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jRadioButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap())
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.ButtonGroup buttonGroup1;
+    private javax.swing.JRadioButton jRadioButton1;
+    private javax.swing.JRadioButton jRadioButton2;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTextPane jTextPane1;
+    // End of variables declaration//GEN-END:variables
+}

+ 61 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectVisualPanel2.form

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <Properties>
+    <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[600, 350]"/>
+    </Property>
+  </Properties>
+  <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" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jScrollPane1" max="32767" attributes="0"/>
+                  <Component id="jProgressBar1" alignment="0" pref="588" 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">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jScrollPane1" pref="312" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jProgressBar1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" 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.JTextPane" name="jTextPane1">
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JProgressBar" name="jProgressBar1">
+    </Component>
+  </SubComponents>
+</Form>

+ 75 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectVisualPanel2.java

@@ -0,0 +1,75 @@
+package com.jme3.gde.core.j2seproject.actions;
+
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextPane;
+import org.netbeans.api.project.Project;
+
+public final class UpgradeProjectVisualPanel2 extends JPanel {
+    
+    Project context;
+    /**
+     * Creates new form UpgradeProjectVisualPanel2
+     */
+    public UpgradeProjectVisualPanel2(Project context) {
+        this.context = context;
+        initComponents();
+    }
+
+    @Override
+    public String getName() {
+        return "Converting the Project";
+    }
+    
+    public JTextPane getTextPane() {
+        return jTextPane1;
+    }
+    
+    public JProgressBar getProgressBar() {
+        return jProgressBar1;
+    }
+    
+    /**
+     * 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() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTextPane1 = new javax.swing.JTextPane();
+        jProgressBar1 = new javax.swing.JProgressBar();
+
+        setPreferredSize(new java.awt.Dimension(600, 350));
+
+        jScrollPane1.setViewportView(jTextPane1);
+
+        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()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jScrollPane1)
+                    .addComponent(jProgressBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 588, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 312, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap())
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JProgressBar jProgressBar1;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTextPane jTextPane1;
+    // End of variables declaration//GEN-END:variables
+}

+ 215 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectWizardAction.java

@@ -0,0 +1,215 @@
+package com.jme3.gde.core.j2seproject.actions;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JComponent;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.modules.java.j2seproject.J2SEProject;
+import org.netbeans.spi.project.support.ant.EditableProperties;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.WizardDescriptor;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionReferences;
+import org.openide.awt.ActionRegistration;
+import org.openide.filesystems.FileLock;
+import org.openide.filesystems.FileObject;
+import org.openide.util.NbBundle;
+
+// 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.j2seproject.actions.UpgradeProjectWizardAction")
+// @ActionRegistration(displayName="Open UpgradeProject Wizard")
+// @ActionReference(path="Menu/Tools", position=...)
+@ActionID(
+        category = "Project",
+        id = "com.jme3.gde.core.j2seproject.actions.UpgradeProjectWizardAction"
+)
+@ActionRegistration(
+        iconBase = "com/jme3/gde/core/icons/chimpanzee-smile.gif",
+        displayName = "#CTL_UpgradeProjectWizardAction"
+)
+@ActionReferences({
+    @ActionReference(path = "Menu/File", position = 1415),
+    @ActionReference(path = "Projects/org-netbeans-modules-java-j2seproject/Actions", position = 100)
+})
[email protected]("CTL_UpgradeProjectWizardAction=Upgrade Project")
+
+public final class UpgradeProjectWizardAction implements ActionListener {
+    private final Project context;
+    public final static Logger logger = Logger.getLogger(UpgradeProjectWizardAction.class.getName());
+    private boolean isValidProject = false;
+    
+    /**
+     * This is used for the actual conversion jme30<->jme31.
+     * It is also used to see whether a project is 3.0 or 3.1
+     */
+    public final static HashMap<String, String[]> libraries = new HashMap<String, String[]>() {{
+        put("${libs.jme3.classpath}",           new String[] {"${libs.jme3-core.classpath}"});
+        put("${libs.jme3-libraries.classpath}", new String[] {"${libs.jme3-desktop.classpath}",
+                                                "${libs.jme3-plugins.classpath}",
+                                                "${libs.jme3-effects.classpath}",
+                                                "${libs.jme3-networking.classpath}",
+                                                "${libs.jme3-jogg.classpath}",
+                                                "${libs.jme3-terrain.classpath}",
+                                                "${libs.jme3-lwjgl.classpath}", 
+                                                "${libs.jme3-bullet.classpath}",
+                                                "${libs.jme3-bullet-native.classpath}",
+                                                "${libs.jme3-niftygui.classpath}"});
+    }};
+    
+    public UpgradeProjectWizardAction(Project context) {
+        this.context = context;
+        
+        if (context instanceof J2SEProject) {
+             String assetsFolderName = getProperties(context).getProperty("assets.folder.name");
+             if (assetsFolderName == null)
+                 assetsFolderName = "assets";
+             
+                if (context.getProjectDirectory().getFileObject(assetsFolderName) != null) {
+                    isValidProject = true;// Valid JMP Project
+                }
+        }
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (context == null) {
+            DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("There is no project selected. Can't upgrade", NotifyDescriptor.Message.ERROR_MESSAGE));
+            return;
+        }
+        
+        if (!isValidProject) {
+            DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("The Project you selected isn't valid.\nMost likely it's no real JME Project but rather a usual Java Project.", NotifyDescriptor.Message.ERROR_MESSAGE));
+            return;
+        }
+        
+        if (isJME31(context)) {
+            DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Your Project is already 3.1 compliant. There is no need to upgrade it :)", NotifyDescriptor.Message.INFORMATION_MESSAGE));
+            return;
+        }
+        
+        List<WizardDescriptor.Panel<WizardDescriptor>> panels = new ArrayList<WizardDescriptor.Panel<WizardDescriptor>>();
+        panels.add(new UpgradeProjectWizardPanel1(context));
+        panels.add(new UpgradeProjectWizardPanel2(context));
+        String[] steps = new String[panels.size()];
+        for (int i = 0; i < panels.size(); i++) {
+            Component c = panels.get(i).getComponent();
+            // Default step name to component name of panel.
+            steps[i] = c.getName();
+            if (c instanceof JComponent) { // assume Swing components
+                JComponent jc = (JComponent) c;
+                jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i);
+                jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
+                jc.putClientProperty(WizardDescriptor.PROP_AUTO_WIZARD_STYLE, true);
+                jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DISPLAYED, true);
+                jc.putClientProperty(WizardDescriptor.PROP_CONTENT_NUMBERED, true);
+            }
+        }
+        WizardDescriptor wiz = new WizardDescriptor(new WizardDescriptor.ArrayIterator<WizardDescriptor>(panels));
+        // {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
+        wiz.setTitleFormat(new MessageFormat("{0}"));
+        wiz.setTitle("Upgrade jMonkeyPlatform Project");
+        if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) {
+            // do something
+        }
+    }
+    
+    /**
+     * Return the EditableProperties-Object of the <code>project.properties</code> file, but don't expand variables.
+     * @param project The Project who's Properties you want to change
+     * @return The Properties Object
+     */
+    public static EditableProperties getProperties(Project project) {
+        FileObject propFO = project.getProjectDirectory().getFileObject("nbproject/project.properties");
+        if (propFO != null && propFO.isValid()) {
+            FileLock lock = null;
+            try {
+                lock = propFO.lock();
+                InputStream in = propFO.getInputStream();
+                EditableProperties properties = new EditableProperties(true);
+                properties.load(in);
+                in.close();
+                return properties;
+            } catch (Exception e) {
+                logger.log(Level.WARNING, "Error when trying to open project.properties",e);
+            } finally {
+                if (lock != null) {
+                    lock.releaseLock();
+                }
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Determine if this Project is a JME 3.1 project or rather not.
+     * This is done by first looking for the <code>jme.project.version</code>, introduced in 3.1
+     * If the project doesn't contain that information, we compare the libraries the project depends on.
+     * @param project The Project to Test
+     * @param editableProperties The Properties which contain
+     * @return 
+     */
+    public static boolean isJME31(Project project)
+    {
+        EditableProperties properties = getProperties(project);
+        
+        String jmeVersion = properties.getProperty("jme.project.version");
+        if ("3.1".equals(jmeVersion))
+            return true;
+        
+        String javacClasspath = properties.getProperty("javac.classpath");
+        
+        if (javacClasspath != null) {
+            for (String[] s: libraries.values()) { /* 3.1 library names */
+                for (String t: s) { /* For each name */
+                    if (javacClasspath.contains(t))
+                            return true;
+                }
+            }
+            for (String s: libraries.keySet()) {
+                if (javacClasspath.contains(s)) /* 3.0 library name */
+                    return false;
+            }
+        }
+        
+        logger.log(Level.WARNING, "Could not determine whether the Project {0} is a JME 3.1 project or not. Assuming: No.", ProjectUtils.getInformation(project).getDisplayName());
+        return false;
+    }
+    
+    public static boolean isJME30(Project project)
+    {
+        EditableProperties properties = getProperties(project);
+        String jmeVersion = properties.getProperty("jme.project.version");
+        String javacClasspath = properties.getProperty("javac.classpath");
+        
+        if ("3.0".equals(jmeVersion))
+            return true;
+        
+        if (javacClasspath != null) {
+            for (String s: libraries.keySet()) {
+                if (javacClasspath.contains(s)) /* 3.0 library name */
+                    return true;
+            }
+            for (String[] s: libraries.values()) { /* 3.1 library names */
+                for (String t: s) { /* For each name */
+                    if (javacClasspath.contains(t))
+                            return false;
+                }
+            }
+        }
+        
+        logger.log(Level.WARNING, "Could not determine whether the Project {0} is a JME 3.0 project or not. Assuming: No.", ProjectUtils.getInformation(project).getDisplayName());
+        return false;
+    }
+}

+ 85 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectWizardPanel1.java

@@ -0,0 +1,85 @@
+package com.jme3.gde.core.j2seproject.actions;
+
+import javax.swing.event.ChangeListener;
+import org.netbeans.api.project.Project;
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.util.HelpCtx;
+
+
+
+public class UpgradeProjectWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDescriptor> {
+
+    public UpgradeProjectWizardPanel1(Project context) {
+        this.context = context;
+    }
+    
+    /**
+     * The reference to the project we work on.
+     */
+    private Project context;
+    
+    /**
+     * The visual component that displays this panel. If you need to access the
+     * component from this class, just use getComponent().
+     */
+    private UpgradeProjectVisualPanel1 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.
+    @Override
+    public UpgradeProjectVisualPanel1 getComponent() {
+        if (component == null) {
+            component = new UpgradeProjectVisualPanel1(context);
+        }
+        return component;
+    }
+
+    @Override
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx("help.key.here");
+    }
+
+    @Override
+    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...) and
+        // this condition changes (last form field filled in...) then
+        // use ChangeSupport to implement add/removeChangeListener below.
+        // WizardDescriptor.ERROR/WARNING/INFORMATION_MESSAGE will also be useful.
+    }
+
+    @Override
+    public void addChangeListener(ChangeListener l) {
+    }
+
+    @Override
+    public void removeChangeListener(ChangeListener l) {
+    }
+
+    @Override
+    public void readSettings(WizardDescriptor wiz) {
+        // use wiz.getProperty to retrieve previous panel state
+    }
+
+    @Override
+    public void storeSettings(WizardDescriptor wiz) {
+        UpgradeProjectVisualPanel1 pnl = (UpgradeProjectVisualPanel1)component;
+        wiz.putProperty("flatUpgrade", pnl.flatUpgrade());
+    }
+
+    @Override
+    public void validate() throws WizardValidationException
+    {
+        if (!component.getRadioButton1().isSelected() && !component.getRadioButton2().isSelected()) {
+            throw new WizardValidationException(null, " Select one Upgrade-Type!", null);
+        }
+    }
+    
+}

+ 259 - 0
jme3-core/src/com/jme3/gde/core/j2seproject/actions/UpgradeProjectWizardPanel2.java

@@ -0,0 +1,259 @@
+package com.jme3.gde.core.j2seproject.actions;
+
+import com.jme3.gde.core.j2seproject.ProjectExtensionManager;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.logging.Level;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeListener;
+import org.netbeans.api.project.Project;
+import org.netbeans.spi.project.support.ant.EditableProperties;
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.filesystems.FileLock;
+import org.openide.filesystems.FileObject;
+import org.openide.util.HelpCtx;
+
+public class UpgradeProjectWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDescriptor> {
+
+    public UpgradeProjectWizardPanel2(Project context) {
+        this.context = context;
+    }
+    
+    /**
+     * The reference to the project we work on.
+     */
+    private Project context;
+    Thread thread = null;
+    private boolean flatUpgrade;
+    
+    /**
+     * The visual component that displays this panel. If you need to access the
+     * component from this class, just use getComponent().
+     */
+    private UpgradeProjectVisualPanel2 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.
+    @Override
+    public UpgradeProjectVisualPanel2 getComponent() {
+        if (component == null) {
+            component = new UpgradeProjectVisualPanel2(context);
+        }
+        return component;
+    }
+
+    @Override
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx("help.key.here");
+    }
+
+    @Override
+    public boolean isValid() {
+        return true;
+    }
+
+    @Override
+    public void validate() throws WizardValidationException {
+        if (thread == null || (thread.isAlive()))
+            throw new WizardValidationException(null, " Wait for the process to finish!", null);
+    }
+    
+    @Override
+    public void addChangeListener(ChangeListener l) {
+    }
+
+    @Override
+    public void removeChangeListener(ChangeListener l) {
+    }
+
+    @Override
+    public void readSettings(WizardDescriptor wiz) {
+        Object o = wiz.getProperty("flatUpgrade");
+        if (o != null) {
+            flatUpgrade = (Boolean)o;
+        } else {
+            UpgradeProjectWizardAction.logger.log(Level.WARNING, "Could not read Settings for Panel 2. Got a null Property.");
+        }
+        
+        thread = new Thread(new Runnable() { public void run() {doWork();}}, "Worker");
+        thread.start(); // Evil hack, but Wizards seem to be design to usually execute code AFTER they have been closed...
+    }
+
+    @Override
+    public void storeSettings(WizardDescriptor wiz) {
+    }
+    
+    public void doWork() {
+        final UpgradeProjectVisualPanel2 comp = component;
+        
+        FileObject prProp = context.getProjectDirectory().getFileObject("nbproject/project.properties");
+        if (prProp != null && prProp.isValid()) {
+            FileLock lock = null;
+            try {
+                lock = prProp.lock();
+                InputStream in = prProp.getInputStream();
+                EditableProperties edProps = new EditableProperties(true);
+                edProps.load(in);
+                in.close();
+                
+                setProgress(20);
+                boolean haveDeployment = false;
+                
+                if (flatUpgrade) {
+                    edProps.setProperty("jme.project.version", "3.0");
+                    setProgress(80);
+                } else {
+                    edProps.setProperty("jme.project.version", "3.1");
+                    setProgress(40);
+                    LinkedList<String> newClasspath = new LinkedList<String>(); /* We need this list so we can pass each new library as seperate String */
+                    /* Only then the EditableProperties will correctly split them along the lines. */
+                    boolean foundIt = false;
+                    
+                    for (String key : UpgradeProjectWizardAction.libraries.keySet()) { /* For each to-be-replaced-Library */
+                        for (String cP : edProps.getProperty("javac.classpath").split(":")) { /* For each classpath entry */
+                            if (cP.contains(key)) { /* This entry is our to-be-replaced */
+                                foundIt = true;
+                                newClasspath.addAll(Arrays.asList(UpgradeProjectWizardAction.libraries.get(key)));
+                                appendLog("Found pattern \"" + key + "\"!");
+                            }
+                        }
+                        if (!foundIt) {
+                            appendLog("Missing(!) pattern \"" + key + "\". Did you edit the file manually?");
+                        }
+                        foundIt = false;
+                    }
+                    
+                    setProgress(60);
+                    
+                    for (String cP : edProps.getProperty("javac.classpath").split(":")) {
+                        if (!UpgradeProjectWizardAction.libraries.containsKey(cP)) {
+                            appendLog("Found unknown classpath entry \"" + cP + "\". Passing through.");
+                            newClasspath.add(cP);
+                        }
+                    }
+                    
+                    for (int i = 0; i < newClasspath.size(); i++) { /* add ":"'s, which are needed for netbeans/ant */
+                        if (i != newClasspath.size() - 1) {
+                            String s = newClasspath.get(i);
+                            s += ":";
+                            newClasspath.set(i, s);
+                        }
+                    }
+                    
+                    edProps.setProperty("javac.classpath", newClasspath.toArray(new String[newClasspath.size()]));
+                    setProgress(60);
+                    
+                    if (edProps.getProperty("launch4j.exe.enabled") != null) {
+                        appendLog("Found Windows Deployment! Switching to newer system...");
+                        if (edProps.getProperty("launch4j.exe.enabled").equals("true")) {
+                            appendLog("Removing old ProjectExtension...");
+                            ProjectExtensionManager pem = new ProjectExtensionManager("launch4j", "v1.4", new String[]{"jar", "-launch4j-exe"});
+                            pem.setAntTaskLibrary("launch4j");
+                            try {
+                                pem.removeExtension(context);
+                            } catch (Exception e) {} // When launch4j ant task lib is missing...
+                            
+                            FileObject fo = context.getProjectDirectory().getFileObject("resources/launch4j");
+                            if (fo != null) {
+                                appendLog("Deleting resources/launch4j");
+                                fo.delete();
+                            }
+                            haveDeployment = true;
+                        }
+            
+                        edProps.setProperty("windows-x64.app.enabled", edProps.getProperty("launch4j.exe.enabled"));
+                        edProps.setProperty("windows-x86.app.enabled", edProps.getProperty("launch4j.exe.enabled"));
+                        edProps.remove("launch4j.exe.enabled");
+                    }
+                    if (edProps.getProperty("linux.launcher.enabled") != null) {
+                        appendLog("Found Linux Deployment! Switching to newer system...");
+                        if (edProps.getProperty("linux.launcher.enabled").equals("true")) {
+                            appendLog("Removing old ProjectExtension...");
+                            ProjectExtensionManager pem = new ProjectExtensionManager("linuxlauncher", "v1.1", new String[]{"jar", "-linux-launcher"});
+                            pem.removeExtension(context);
+                            
+                            haveDeployment = true;
+                        }
+                        edProps.setProperty("linux-x64.app.enabled", edProps.getProperty("linux.launcher.enabled"));
+                        edProps.setProperty("linux-x86.app.enabled", edProps.getProperty("linux.launcher.enabled"));
+                        edProps.remove("linux.launcher.enabled");
+                    }
+                    if (edProps.getProperty("mac.app.enabled") != null) {
+                        appendLog("Found Mac Deployment! Switching to newer system...");
+                        if (edProps.getProperty("mac.app.enabled").equals("true")) {
+                            appendLog("Removing old ProjectExtension...");
+                            ProjectExtensionManager pem = new ProjectExtensionManager("macapp", "v2.0", new String[]{"jar", "-mac-app"});
+                            pem.removeExtension(context);
+                            
+                            FileObject fo = context.getProjectDirectory().getFileObject("resources/macapp");
+                            
+                            if (fo != null) {
+                                appendLog("Deleting resources/macapp");
+                                fo.delete();
+                            }
+                            
+                            haveDeployment = true;
+                        }
+                        edProps.setProperty("macosx-x64.app.enabled", edProps.getProperty("mac.app.enabled"));// edProps.setProperty("linux-x86.app.enabled", edProps.getProperty("linux.launcher.enabled"));
+                        edProps.remove("mac.app.enabled");
+                    }
+                    
+                    setProgress(80);
+                }
+                
+                OutputStream out = prProp.getOutputStream(lock);
+                edProps.store(out);
+                out.close();
+                setProgress(90);
+                
+                if (haveDeployment) {
+                    appendLog("\nIMPORTANT: Open the Project Properties -> Application -> Desktop and uncheck/check the options and press Apply, if you encounter errors during clean & build.");
+                }
+                
+                setProgress(100);
+                if (flatUpgrade)
+                    appendLog("Chapeau! We are done :)\nNote: You can always re-run this Wizard, if you feel the need to Upgrade to 3.1");
+                else
+                    appendLog("\n\nChapeau! We are done :)\nNow that your project is 3.1 compatible, feel free to remove the NiftyGUI,\nBullet-Native, Terrain, etc. libraries to your liking, if you don't need them. (They were always-included in 3.0)");
+                
+            } catch (Exception e) {
+                appendLog("Error when trying to write project.properties. Exception: " + e.getMessage());
+            } finally {
+                if (lock != null) {
+                    lock.releaseLock();
+                }
+                
+            }
+        } else {
+            setProgress(0);
+            appendLog("FATAL ERROR: Can't open nbproject/project.properties. The file is either inaccessible or not found.");
+        }
+    }
+    
+    private void appendLog(final String s) {
+        final UpgradeProjectVisualPanel2 comp = component;
+        SwingUtilities.invokeLater(new Runnable () {
+            public void run() {
+                comp.getTextPane().setText(comp.getTextPane().getText() + s + "\n");
+            }
+        });
+    }
+    
+    private void setProgress(final int value) {
+        final UpgradeProjectVisualPanel2 comp = component;
+        SwingUtilities.invokeLater(new Runnable () {
+            public void run() {
+                comp.getProgressBar().setValue(value);
+            }
+        });
+    
+    }
+}