diff --git a/jme3-templates/src/com/jme3/gde/templates/Bundle.properties b/jme3-templates/src/com/jme3/gde/templates/Bundle.properties index 8e086f4d..4edb0237 100644 --- a/jme3-templates/src/com/jme3/gde/templates/Bundle.properties +++ b/jme3-templates/src/com/jme3/gde/templates/Bundle.properties @@ -5,4 +5,7 @@ OpenIDE-Module-Long-Description=\ OpenIDE-Module-Name=Project Templates OpenIDE-Module-Short-Description=Provides Project Templates Templates/Project/JME3/BasicGameProject.zip=Basic Game (with Ant) -Templates/Project/JME3/GradleDesktopGameProject.zip=Basic Game (with Gradle) \ No newline at end of file +Templates/Project/JME3/GradleDesktopGameProject.zip=Basic Game (with Gradle) +Templates/Project/JME3/Examples/RollingTheMonkeyProject.zip=Rolling The Monkey +Templates/Project/JME3/Examples/MonkeyZone=Monkey Zone +Templates/Project/JME3/Examples/JaimesAscent=Jaimes Ascent \ No newline at end of file diff --git a/jme3-templates/src/com/jme3/gde/templates/GradleDesktopGameProject.zip b/jme3-templates/src/com/jme3/gde/templates/GradleDesktopGameProject.zip index 1fd3f16b..0651c528 100644 Binary files a/jme3-templates/src/com/jme3/gde/templates/GradleDesktopGameProject.zip and b/jme3-templates/src/com/jme3/gde/templates/GradleDesktopGameProject.zip differ diff --git a/jme3-templates/src/com/jme3/gde/templates/RollingTheMonkeyProject.zip b/jme3-templates/src/com/jme3/gde/templates/RollingTheMonkeyProject.zip new file mode 100644 index 00000000..00789f9f Binary files /dev/null and b/jme3-templates/src/com/jme3/gde/templates/RollingTheMonkeyProject.zip differ diff --git a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/AdditionalLibrary.java b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/AdditionalLibrary.java index 690b5640..041c66e9 100644 --- a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/AdditionalLibrary.java +++ b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/AdditionalLibrary.java @@ -90,7 +90,7 @@ public enum AdditionalLibrary implements TemplateLibrary { HEART("Heart Library", NbBundle.getMessage(AdditionalLibrary.class, "additionalLibrary.heart.description"), "com.github.stephengold", "Heart", - "8.1.0", false), + "9.0.0", false), PARTICLE_MONKEY("Particle Monkey", NbBundle.getMessage(AdditionalLibrary.class, "additionalLibrary.particlemonkey.description"), @@ -111,7 +111,11 @@ public enum AdditionalLibrary implements TemplateLibrary { ZAY_ES_NET("Zay-ES-Net Networking Extension", NbBundle.getMessage(AdditionalLibrary.class, "additionalLibrary.zayesnet.description"), - "com.simsilica", "zay-es-net", "1.5.0", false); + "com.simsilica", "zay-es-net", "1.5.0", false), + WES("Wes Library", NbBundle.getMessage(AdditionalLibrary.class, + "additionalLibrary.wes.description"), + "com.github.stephengold", "Wes", + "0.8.1", false),; /** * The name of the library. This will be displayed in the jComboBox in the diff --git a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/Bundle.properties b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/Bundle.properties index a292da8a..a6eee1ba 100644 --- a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/Bundle.properties +++ b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/Bundle.properties @@ -5,7 +5,8 @@ additionalLibrary.jme3-vr.description=Core jMonkeyEngine library providing Virtu additionalLibrary.heart.description=The Heart Library provides an assortment of useful classes and assets to augment jMonkeyEngine. additionalLibrary.particlemonkey.description=Particle Monkey is a more modern particle system with better artistic controls. additionalLibrary.shaderblowex.description=Extended filters library for JMonkey Game Engine. -additionalLibrary.sio2.description=A base library of useful utility code for JME-based games. \ +additionalLibrary.sio2.description=A base library of useful utility code for JME-based games. +additionalLibrary.wes.description=An animation editing and retargeting library for jMonkeyEngine. \ Includes game system management infrastructure, useful base app states, an event bus, and useful Zay-ES utilities. \ This is a useful base library for any JME game. additionalLibrary.zayes.description=Zay-ES (pronounced like Doctor Zaius from Planet of the Apes) is a high-performance \ diff --git a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/NetworkingLibrary.java b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/NetworkingLibrary.java index 79f1912d..e26e2d89 100644 --- a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/NetworkingLibrary.java +++ b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/NetworkingLibrary.java @@ -79,7 +79,7 @@ public enum NetworkingLibrary implements TemplateLibrary { SIMETHEREAL("SimEthereal", NbBundle.getMessage(NetworkingLibrary.class, "networkinglibrary.simethereal.description"), "com.simsilica", "sim-ethereal", - "1.7.0", false); + "1.8.0", false); /** * The name of the library. This will be displayed in the jComboBox in the diff --git a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/PhysicsLibrary.java b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/PhysicsLibrary.java index 2ff80e99..914f1613 100644 --- a/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/PhysicsLibrary.java +++ b/jme3-templates/src/com/jme3/gde/templates/gradledesktop/options/PhysicsLibrary.java @@ -75,7 +75,7 @@ public enum PhysicsLibrary implements TemplateLibrary { MINIE("Minie", NbBundle.getMessage(PhysicsLibrary.class, "physicslibrary.minie.description"), "com.github.stephengold", "Minie", - "5.0.0", false); + "8.2.0", false); /** * The name of the library. This will be displayed in the jComboBox in the diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/Bundle.properties b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/Bundle.properties new file mode 100644 index 00000000..53cf704a --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/Bundle.properties @@ -0,0 +1,16 @@ +LBL_DownloadProjectStep=Download project +LBL_CreateProjectStep=Name and Location +JaimesAscentPanelVisual.browseButton.text=Br&owse... +JaimesAscentPanelVisual.createdFolderLabel.text=Project &Folder: +JaimesAscentPanelVisual.projectLocationLabel.text=Project &Location: +JaimesAscentDownloadPanelVisual.downloadButton.text=Download project +JaimesAscentDownloadPanelVisual.downloadButton.actionCommand=DOWNLOAD +JaimesAscentPanelVisual.projectNameLabel.text=Project &Name: +JaimesAscentPanelVisual.browseButton.text=Browse +JaimesAscentPanelVisual.browseButton.actionCommand=BROWSE +JaimesAscentDownloadPanelVisual.jTextArea1.text=Pressing the button below will download the project from Github, to a temporary location from which it will be installed in the next step\n +JaimesAscentDownloadPanelVisual.statusField.text= +JaimesAscentDownloadPanelVisual.downloading=Downloading... Please wait +JaimesAscentDownloadPanelVisual.downloadSuccess=Download complete. Press 'next' to proceed. +JaimesAscentDownloadPanelVisual.downloadFailed=Download failed. +JaimesAscentDownloadPanelVisual.jLabel1.text= diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDescription.html b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDescription.html new file mode 100644 index 00000000..bd44c955 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDescription.html @@ -0,0 +1,13 @@ + + + + Jaimes Ascent + + + A sample application demonstrating a chase cam with mouse look,
+ physics, moving objects and animations. + + Easily extendable classes and architecture using AppStates and Controls.
+ Suitable for beginners.
+ + diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanel.java b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanel.java new file mode 100644 index 00000000..b2d9c627 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanel.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.jaimesascent; + +import java.awt.Component; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +/** + * Panel just asking for basic info. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class JaimesAscentDownloadPanel implements WizardDescriptor.Panel, + WizardDescriptor.ValidatingPanel, WizardDescriptor.FinishablePanel { + + private WizardDescriptor wizardDescriptor; + private JaimesAscentDownloadPanelVisual component; + + static String ZIP_NAME = "JaimesAscent.zip"; + static String DOWNLOAD_FOLDER = System.getProperty("java.io.tmpdir"); + + public JaimesAscentDownloadPanel() { + } + + public int doDownloadZip() { + return downloadFile("https://github.com/neph1/JaimesAscent/archive/refs/tags/v1.1.1.zip", DOWNLOAD_FOLDER, ZIP_NAME); + } + + private int downloadFile(String fileURL, String saveDir, String fileName) { + HttpURLConnection httpConn = null; + BufferedInputStream inputStream = null; + FileOutputStream fileOutputStream = null; + + final File outputFile = new File(saveDir, fileName); + + if (outputFile.exists()) { + return 1; + } + + try { + // Create URL object + URL url = new URL(fileURL); + httpConn = (HttpURLConnection) url.openConnection(); + + // Check HTTP response code + int responseCode = httpConn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + // Open input stream from the HTTP connection + inputStream = new BufferedInputStream(httpConn.getInputStream()); + + + + // Create output stream to save the file + fileOutputStream = new FileOutputStream(outputFile); + + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + fileOutputStream.write(buffer, 0, bytesRead); + } + + return 1; + } + } catch (IOException e) { + return 0; + } finally { + // Close resources + try { + if (inputStream != null) inputStream.close(); + if (fileOutputStream != null) fileOutputStream.close(); + if (httpConn != null) httpConn.disconnect(); + } catch (IOException ex) { + return 0; + } + } + return 0; + } + + @Override + public Component getComponent() { + if (component == null) { + component = new JaimesAscentDownloadPanelVisual(this); + component.setName(NbBundle.getMessage(JaimesAscentDownloadPanel.class, "LBL_DownloadProjectStep")); + } + return component; + } + + @Override + public HelpCtx getHelp() { + return new HelpCtx("sdk.download_project"); + } + + @Override + public boolean isValid() { + getComponent(); + return component.valid(wizardDescriptor); + } + + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 + + @Override + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + @Override + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + protected final void fireChangeEvent() { + Set ls; + synchronized (listeners) { + ls = new HashSet<>(listeners); + } + ChangeEvent ev = new ChangeEvent(this); + for (ChangeListener l : ls) { + l.stateChanged(ev); + } + } + + @Override + public void readSettings(Object settings) { + wizardDescriptor = (WizardDescriptor) settings; + component.read(wizardDescriptor); + } + + @Override + public void storeSettings(Object settings) { + WizardDescriptor d = (WizardDescriptor) settings; + component.store(d); + } + + @Override + public boolean isFinishPanel() { + return false; + } + + @Override + public void validate() throws WizardValidationException { + getComponent(); + component.validate(wizardDescriptor); + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanelVisual.form b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanelVisual.form new file mode 100644 index 00000000..9caac7e1 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanelVisual.form @@ -0,0 +1,120 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanelVisual.java b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanelVisual.java new file mode 100644 index 00000000..04f83bef --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentDownloadPanelVisual.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.jaimesascent; + +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; + +public class JaimesAscentDownloadPanelVisual extends JPanel implements DocumentListener { + + public static final String PROP_PROJECT_NAME = "projectName"; + private final JaimesAscentDownloadPanel panel; + + public JaimesAscentDownloadPanelVisual(JaimesAscentDownloadPanel panel) { + initComponents(); + this.panel = panel; + } + + /** 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + downloadButton = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + jTextArea1 = new javax.swing.JTextArea(); + statusField = new javax.swing.JTextField(); + jLabel1 = new javax.swing.JLabel(); + + org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.downloadButton.text")); // NOI18N + downloadButton.setActionCommand(org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.downloadButton.actionCommand")); // NOI18N + downloadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadButtonActionPerformed(evt); + } + }); + + jTextArea1.setEditable(false); + jTextArea1.setColumns(20); + jTextArea1.setLineWrap(true); + jTextArea1.setRows(5); + jTextArea1.setText(org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.jTextArea1.text")); // NOI18N + jTextArea1.setWrapStyleWord(true); + jTextArea1.setEnabled(false); + jScrollPane1.setViewportView(jTextArea1); + + statusField.setEditable(false); + statusField.setText(org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.statusField.text")); // NOI18N + statusField.setEnabled(false); + statusField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + statusFieldActionPerformed(evt); + } + }); + + jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/templates/jaimesascent/jaimesascent.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.jLabel1.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() + .addComponent(jLabel1) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 307, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(statusField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 313, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createSequentialGroup() + .addGap(99, 99, 99) + .addComponent(downloadButton))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(71, 71, 71) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(21, 21, 21) + .addComponent(downloadButton) + .addGap(18, 18, 18) + .addComponent(statusField, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed + statusField.setText(org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.downloading")); + final int result = this.panel.doDownloadZip(); + if (result == 1) { + statusField.setText(org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.downloadSuccess")); + } else { + statusField.setText(org.openide.util.NbBundle.getMessage(JaimesAscentDownloadPanelVisual.class, "JaimesAscentDownloadPanelVisual.downloadFailed")); + } + }//GEN-LAST:event_downloadButtonActionPerformed + + private void statusFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_statusFieldActionPerformed + + }//GEN-LAST:event_statusFieldActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + javax.swing.JButton downloadButton; + javax.swing.JLabel jLabel1; + javax.swing.JScrollPane jScrollPane1; + javax.swing.JTextArea jTextArea1; + javax.swing.JTextField statusField; + // End of variables declaration//GEN-END:variables + + @Override + public void addNotify() { + super.addNotify(); + } + + boolean valid(WizardDescriptor wizardDescriptor) { + + return true; + } + + void store(WizardDescriptor d) { + + } + + void read(WizardDescriptor settings) { + + } + + void validate(WizardDescriptor d) throws WizardValidationException { + // nothing to validate + } + + // Implementation of DocumentListener -------------------------------------- + @Override + public void changedUpdate(DocumentEvent e) { + + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateTexts(e); + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateTexts(e); + } + + /** Handles changes in the Project name and project directory, */ + private void updateTexts(DocumentEvent e) { + + panel.fireChangeEvent(); // Notify that the panel changed + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentPanelVisual.form b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentPanelVisual.form new file mode 100644 index 00000000..6451a2c5 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentPanelVisual.form @@ -0,0 +1,122 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentPanelVisual.java b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentPanelVisual.java new file mode 100644 index 00000000..79eb619c --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentPanelVisual.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.jaimesascent; + +import java.io.File; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import org.netbeans.spi.project.ui.support.ProjectChooser; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.filesystems.FileUtil; + +public class JaimesAscentPanelVisual extends JPanel implements DocumentListener { + + public static final String PROP_PROJECT_NAME = "projectName"; + static final String PROJECT_NAME = "JaimesAscent"; + private final JaimesAscentWizardPanel panel; + + public JaimesAscentPanelVisual(JaimesAscentWizardPanel panel) { + initComponents(); + this.panel = panel; + // Register listener on the textFields to make the automatic updates + projectNameTextField.getDocument().addDocumentListener(this); + projectLocationTextField.getDocument().addDocumentListener(this); + } + + public String getProjectName() { + return this.projectNameTextField.getText(); + } + + /** 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + projectNameLabel = new javax.swing.JLabel(); + projectNameTextField = new javax.swing.JTextField(); + projectLocationLabel = new javax.swing.JLabel(); + projectLocationTextField = new javax.swing.JTextField(); + browseButton = new javax.swing.JButton(); + createdFolderLabel = new javax.swing.JLabel(); + createdFolderTextField = new javax.swing.JTextField(); + + projectNameLabel.setLabelFor(projectNameTextField); + org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel, org.openide.util.NbBundle.getMessage(JaimesAscentPanelVisual.class, "JaimesAscentPanelVisual.projectNameLabel.text")); // NOI18N + + projectLocationLabel.setLabelFor(projectLocationTextField); + org.openide.awt.Mnemonics.setLocalizedText(projectLocationLabel, org.openide.util.NbBundle.getMessage(JaimesAscentPanelVisual.class, "JaimesAscentPanelVisual.projectLocationLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(JaimesAscentPanelVisual.class, "JaimesAscentPanelVisual.browseButton.text")); // NOI18N + browseButton.setActionCommand(org.openide.util.NbBundle.getMessage(JaimesAscentPanelVisual.class, "JaimesAscentPanelVisual.browseButton.actionCommand")); // NOI18N + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); + + createdFolderLabel.setLabelFor(createdFolderTextField); + org.openide.awt.Mnemonics.setLocalizedText(createdFolderLabel, org.openide.util.NbBundle.getMessage(JaimesAscentPanelVisual.class, "JaimesAscentPanelVisual.createdFolderLabel.text")); // NOI18N + + createdFolderTextField.setEditable(false); + + 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(projectNameLabel) + .addComponent(projectLocationLabel) + .addComponent(createdFolderLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(projectNameTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE) + .addComponent(projectLocationTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE) + .addComponent(createdFolderTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(projectNameLabel) + .addComponent(projectNameTextField, 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(projectLocationLabel) + .addComponent(projectLocationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(createdFolderLabel) + .addComponent(createdFolderTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(213, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + String command = evt.getActionCommand(); + if ("BROWSE".equals(command)) { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(null); + chooser.setDialogTitle("Select Project Location"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + String path = this.projectLocationTextField.getText(); + if (path.length() > 0) { + File f = new File(path); + if (f.exists()) { + chooser.setSelectedFile(f); + } + } + if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(this)) { + File projectDir = chooser.getSelectedFile(); + projectLocationTextField.setText(FileUtil.normalizeFile(projectDir).getAbsolutePath()); + } + panel.fireChangeEvent(); + } + + }//GEN-LAST:event_browseButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + javax.swing.JButton browseButton; + javax.swing.JLabel createdFolderLabel; + javax.swing.JTextField createdFolderTextField; + javax.swing.JLabel projectLocationLabel; + javax.swing.JTextField projectLocationTextField; + javax.swing.JLabel projectNameLabel; + javax.swing.JTextField projectNameTextField; + // End of variables declaration//GEN-END:variables + + @Override + public void addNotify() { + super.addNotify(); + //same problem as in 31086, initial focus on Cancel button + projectNameTextField.requestFocus(); + } + + boolean valid(WizardDescriptor wizardDescriptor) { + + if (projectNameTextField.getText().length() == 0) { + // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_ERROR_MESSAGE: + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Name is not a valid folder name."); + return false; // Display name not specified + } + File f = FileUtil.normalizeFile(new File(projectLocationTextField.getText()).getAbsoluteFile()); + if (!f.isDirectory()) { + String message = "Project Folder is not a valid path."; + wizardDescriptor.putProperty("WizardPanel_errorMessage", message); + return false; + } + final File destFolder = FileUtil.normalizeFile(new File(createdFolderTextField.getText()).getAbsoluteFile()); + + File projLoc = destFolder; + while (projLoc != null && !projLoc.exists()) { + projLoc = projLoc.getParentFile(); + } + if (projLoc == null || !projLoc.canWrite()) { + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Folder cannot be created."); + return false; + } + + if (FileUtil.toFileObject(projLoc) == null) { + String message = "Project Folder is not a valid path."; + wizardDescriptor.putProperty("WizardPanel_errorMessage", message); + return false; + } + + File[] kids = destFolder.listFiles(); + if (destFolder.exists() && kids != null && kids.length > 0) { + // Folder exists and is not empty + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Folder already exists and is not empty."); + return false; + } + wizardDescriptor.putProperty("WizardPanel_errorMessage", ""); + return true; + } + + void store(WizardDescriptor d) { + String name = projectNameTextField.getText().trim(); + String folder = createdFolderTextField.getText().trim(); + + d.putProperty("projdir", new File(folder)); + d.putProperty("name", name); + } + + void read(WizardDescriptor settings) { + File projectLocation = (File) settings.getProperty("projdir"); + if (projectLocation == null || projectLocation.getParentFile() == null || !projectLocation.getParentFile().isDirectory()) { + projectLocation = ProjectChooser.getProjectsFolder(); + } else { + projectLocation = projectLocation.getParentFile(); + } + this.projectLocationTextField.setText(projectLocation.getAbsolutePath()); + + String projectName = (String) settings.getProperty("name"); + if (projectName == null) { + projectName = PROJECT_NAME; + } + this.projectNameTextField.setText(projectName); + this.projectNameTextField.selectAll(); + } + + void validate(WizardDescriptor d) throws WizardValidationException { + // nothing to validate + } + + // Implementation of DocumentListener -------------------------------------- + @Override + public void changedUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + /** Handles changes in the Project name and project directory, */ + private void updateTexts(DocumentEvent e) { + + Document doc = e.getDocument(); + + if (doc == projectNameTextField.getDocument() || doc == projectLocationTextField.getDocument()) { + // Change in the project name + + String projectName = projectNameTextField.getText(); + String projectFolder = projectLocationTextField.getText(); + + //if (projectFolder.trim().length() == 0 || projectFolder.equals(oldName)) { + createdFolderTextField.setText(projectFolder + File.separatorChar + projectName); + //} + + } + panel.fireChangeEvent(); // Notify that the panel changed + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentWizardIterator.java b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentWizardIterator.java new file mode 100644 index 00000000..9dce2a72 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentWizardIterator.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.jaimesascent; + +import com.jme3.gde.templates.gradledesktop.options.CachedOptionsContainer; +import java.awt.Component; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import javax.swing.JComponent; +import javax.swing.event.ChangeListener; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.spi.project.ui.support.ProjectChooser; +import org.openide.WizardDescriptor; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.NbBundle; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class JaimesAscentWizardIterator implements WizardDescriptor.InstantiatingIterator { + + private int index; + private WizardDescriptor.Panel[] panels; + private WizardDescriptor wiz; + + final static String master = "JaimesAscent-1.1.1/"; + + public JaimesAscentWizardIterator() { + + // Initiate the options getting... + CachedOptionsContainer.getInstance(); + } + + public static JaimesAscentWizardIterator createIterator() { + return new JaimesAscentWizardIterator(); + } + + private WizardDescriptor.Panel[] createPanels() { + return new WizardDescriptor.Panel[]{ + new JaimesAscentDownloadPanel(), + new JaimesAscentWizardPanel() + }; + } + + private String[] createSteps() { + return new String[]{ + NbBundle.getMessage(JaimesAscentWizardIterator.class, "LBL_DownloadProjectStep"), + NbBundle.getMessage(JaimesAscentWizardIterator.class, "LBL_CreateProjectStep"), + }; + } + + @Override + public Set/**/ instantiate(/*ProgressHandle handle*/) throws IOException { + Set resultSet = new LinkedHashSet<>(); + File dirF = FileUtil.normalizeFile((File) wiz.getProperty("projdir")); + dirF.mkdirs(); + + FileObject template = FileUtil.toFileObject(new File( + JaimesAscentDownloadPanel.DOWNLOAD_FOLDER, + JaimesAscentDownloadPanel.ZIP_NAME)); + + FileObject dir = FileUtil.toFileObject(dirF); + unZipFile(template.getInputStream(), dir); + + // Always open top dir as a project: + resultSet.add(dir); + // Look for nested projects to open as well: + Enumeration e = dir.getFolders(true); + while (e.hasMoreElements()) { + FileObject subfolder = e.nextElement(); + if (ProjectManager.getDefault().isProject(subfolder)) { + resultSet.add(subfolder); + } + } + + File parent = dirF.getParentFile(); + if (parent != null && parent.exists()) { + ProjectChooser.setProjectsFolder(parent); + } + + return resultSet; + } + + @Override + public void initialize(WizardDescriptor wiz) { + this.wiz = wiz; + index = 0; + panels = createPanels(); + // Make sure list of steps is accurate. + String[] steps = createSteps(); + for (int i = 0; i < panels.length; i++) { + Component c = panels[i].getComponent(); + if (steps[i] == null) { + // Default step name to component name of panel. + // Mainly useful for getting the name of the target + // chooser to appear in the list of steps. + steps[i] = c.getName(); + } + if (c instanceof JComponent jc) { // Step #. + // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*: + jc.putClientProperty("WizardPanel_contentSelectedIndex", i); + // Step name (actually the whole list for reference). + jc.putClientProperty("WizardPanel_contentData", steps); + } + } + } + + @Override + public void uninitialize(WizardDescriptor wiz) { + this.wiz.putProperty("projdir", null); + this.wiz.putProperty("name", null); + this.wiz = null; + panels = null; + } + + @Override + public String name() { + return MessageFormat.format("{0} of {1}", + new Object[]{index + 1, panels.length}); + } + + @Override + public boolean hasNext() { + return index < panels.length - 1; + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public void nextPanel() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + index++; + } + + @Override + public void previousPanel() { + if (!hasPrevious()) { + throw new NoSuchElementException(); + } + index--; + } + + @Override + public WizardDescriptor.Panel current() { + return panels[index]; + } + + // If nothing unusual changes in the middle of the wizard, simply: + @Override + public final void addChangeListener(ChangeListener l) { + } + + @Override + public final void removeChangeListener(ChangeListener l) { + } + + private static void unZipFile(InputStream source, FileObject projectRoot) throws IOException { + try (source) { + ZipInputStream str = new ZipInputStream(source); + ZipEntry entry; + + while ((entry = str.getNextEntry()) != null) { + if (entry.getName().endsWith(master)) { + continue; + } + final String entryName = entry.getName().replace(master, ""); + if (entry.isDirectory()) { + FileUtil.createFolder(projectRoot, entryName); + } else { + FileObject fo = FileUtil.createData(projectRoot, entryName); + try (OutputStream out = fo.getOutputStream()) { + FileUtil.copy(str, out); + } + } + } + } + } + +} diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentWizardPanel.java b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentWizardPanel.java new file mode 100644 index 00000000..25db6a3f --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/JaimesAscentWizardPanel.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.jaimesascent; + +import java.awt.Component; +import java.util.HashSet; +import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +/** + * Panel just asking for basic info. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class JaimesAscentWizardPanel implements WizardDescriptor.Panel, + WizardDescriptor.ValidatingPanel, WizardDescriptor.FinishablePanel { + + private WizardDescriptor wizardDescriptor; + private JaimesAscentPanelVisual component; + + public JaimesAscentWizardPanel() { + } + + @Override + public Component getComponent() { + if (component == null) { + component = new JaimesAscentPanelVisual(this); + component.setName(NbBundle.getMessage(JaimesAscentWizardPanel.class, "LBL_CreateProjectStep")); + } + return component; + } + + @Override + public HelpCtx getHelp() { + return new HelpCtx("sdk.project_creation"); + } + + @Override + public boolean isValid() { + getComponent(); + return component.valid(wizardDescriptor); + } + + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 + + @Override + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + @Override + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + protected final void fireChangeEvent() { + Set ls; + synchronized (listeners) { + ls = new HashSet<>(listeners); + } + ChangeEvent ev = new ChangeEvent(this); + for (ChangeListener l : ls) { + l.stateChanged(ev); + } + } + + @Override + public void readSettings(Object settings) { + wizardDescriptor = (WizardDescriptor) settings; + component.read(wizardDescriptor); + } + + @Override + public void storeSettings(Object settings) { + WizardDescriptor d = (WizardDescriptor) settings; + component.store(d); + } + + @Override + public boolean isFinishPanel() { + return false; + } + + @Override + public void validate() throws WizardValidationException { + getComponent(); + component.validate(wizardDescriptor); + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/build.gradle.ftl b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/build.gradle.ftl new file mode 100644 index 00000000..f40ada91 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/build.gradle.ftl @@ -0,0 +1,65 @@ +plugins { + id 'java' + id 'application' +} + +group 'com.JaimesAscent' +version '1.0' + +mainClassName = "com.JaimesAscent.JaimesAscent" + +repositories { + mavenCentral() +} + +project.ext { + jmeVer = '3.7.0-stable' +} + +project(":assets") { + apply plugin: "java" + + buildDir = rootProject.file("build/assets") + + sourceSets { + main { + resources { + srcDir '.' + } + } + } + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +dependencies { + + implementation "org.jmonkeyengine:jme3-core:$jmeVer" + implementation "org.jmonkeyengine:jme3-desktop:$jmeVer" + implementation "org.jmonkeyengine:jme3-lwjgl:$jmeVer" + implementation "org.jmonkeyengine:jme3-lwjgl:$jmeVer" + implementation "com.github.stephengold:Heart:9.0.0" + implementation "com.github.stephengold:Minie:8.0.0" + implementation project("assets") + +} + +jar { + manifest { + attributes 'Main-Class': "$mainClassName" + } +} + +wrapper { + gradleVersion = '8.6' +} diff --git a/jme3-templates/src/com/jme3/gde/templates/jaimesascent/jaimesascent.png b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/jaimesascent.png new file mode 100644 index 00000000..aa686c8f Binary files /dev/null and b/jme3-templates/src/com/jme3/gde/templates/jaimesascent/jaimesascent.png differ diff --git a/jme3-templates/src/com/jme3/gde/templates/layer.xml b/jme3-templates/src/com/jme3/gde/templates/layer.xml index 001c24b8..e631ab51 100644 --- a/jme3-templates/src/com/jme3/gde/templates/layer.xml +++ b/jme3-templates/src/com/jme3/gde/templates/layer.xml @@ -25,6 +25,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/Bundle.properties b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/Bundle.properties new file mode 100644 index 00000000..8351f695 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/Bundle.properties @@ -0,0 +1,16 @@ +LBL_DownloadProjectStep=Download project +LBL_CreateProjectStep=Name and Location +MonkeyZonePanelVisual.browseButton.text=Br&owse... +MonkeyZoneDownloadPanelVisual.downloading=Downloading... Please wait +MonkeyZoneDownloadPanelVisual.downloadSuccess=Download complete. Press 'next' to proceed. +MonkeyZoneDownloadPanelVisual.downloadFailed=Download failed. +MonkeyZoneDownloadPanelVisual.downloadButton.actionCommand=DOWNLOAD +MonkeyZoneDownloadPanelVisual.downloadButton.text=Download project +MonkeyZoneDownloadPanelVisual.jLabel1.text= +MonkeyZoneDownloadPanelVisual.statusField.text= +MonkeyZoneDownloadPanelVisual.jTextArea1.text=Pressing the button below will download the project from Github, to a temporary location from which it will be installed in the next step\n +MonkeyZonePanelVisual.projectLocationLabel.text=Project &Location: +MonkeyZonePanelVisual.projectNameLabel.text=Project &Name: +MonkeyZonePanelVisual.createdFolderLabel.text=Project &Folder: +MonkeyZonePanelVisual.browseButton.actionCommand=BROWSE +MonkeyZonePanelVisual.browseButton.text=Browse diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDescription.html b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDescription.html new file mode 100644 index 00000000..cb9ab6f0 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDescription.html @@ -0,0 +1,13 @@ + + + + Monkey Zone + + + A networked multiplayer game by the jMonkeyEngine team.

+ + Inspired by the classic game BattleZone, this is a networked multiplayer
+ game with both on foot action and enterable vehicles.
+ This is not a beginner project. + + diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanel.java b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanel.java new file mode 100644 index 00000000..64f4802b --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanel.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.monkeyzone; + +import java.awt.Component; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +/** + * Panel just asking for basic info. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class MonkeyZoneDownloadPanel implements WizardDescriptor.Panel, + WizardDescriptor.ValidatingPanel, WizardDescriptor.FinishablePanel { + + private WizardDescriptor wizardDescriptor; + private MonkeyZoneDownloadPanelVisual component; + + static String ZIP_NAME = "MonkeyZone.zip"; + static String DOWNLOAD_FOLDER = System.getProperty("java.io.tmpdir"); + + public MonkeyZoneDownloadPanel() { + } + + public int doDownloadZip() { + return downloadFile("https://github.com/jMonkeyEngine/monkeyzone/archive/refs/heads/master.zip", DOWNLOAD_FOLDER, ZIP_NAME); + } + + private int downloadFile(String fileURL, String saveDir, String fileName) { + HttpURLConnection httpConn = null; + BufferedInputStream inputStream = null; + FileOutputStream fileOutputStream = null; + + final File outputFile = new File(saveDir, fileName); + + if (outputFile.exists()) { + return 1; + } + + try { + // Create URL object + URL url = new URL(fileURL); + httpConn = (HttpURLConnection) url.openConnection(); + + // Check HTTP response code + int responseCode = httpConn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + // Open input stream from the HTTP connection + inputStream = new BufferedInputStream(httpConn.getInputStream()); + + + + // Create output stream to save the file + fileOutputStream = new FileOutputStream(outputFile); + + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + fileOutputStream.write(buffer, 0, bytesRead); + } + + return 1; + } + } catch (IOException e) { + return 0; + } finally { + // Close resources + try { + if (inputStream != null) inputStream.close(); + if (fileOutputStream != null) fileOutputStream.close(); + if (httpConn != null) httpConn.disconnect(); + } catch (IOException ex) { + return 0; + } + } + return 0; + } + + @Override + public Component getComponent() { + if (component == null) { + component = new MonkeyZoneDownloadPanelVisual(this); + component.setName(NbBundle.getMessage(MonkeyZoneDownloadPanel.class, "LBL_DownloadProjectStep")); + } + return component; + } + + @Override + public HelpCtx getHelp() { + return new HelpCtx("sdk.download_project"); + } + + @Override + public boolean isValid() { + getComponent(); + return component.valid(wizardDescriptor); + } + + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 + + @Override + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + @Override + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + protected final void fireChangeEvent() { + Set ls; + synchronized (listeners) { + ls = new HashSet<>(listeners); + } + ChangeEvent ev = new ChangeEvent(this); + for (ChangeListener l : ls) { + l.stateChanged(ev); + } + } + + @Override + public void readSettings(Object settings) { + wizardDescriptor = (WizardDescriptor) settings; + component.read(wizardDescriptor); + } + + @Override + public void storeSettings(Object settings) { + WizardDescriptor d = (WizardDescriptor) settings; + component.store(d); + } + + @Override + public boolean isFinishPanel() { + return false; + } + + @Override + public void validate() throws WizardValidationException { + getComponent(); + component.validate(wizardDescriptor); + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanelVisual.form b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanelVisual.form new file mode 100644 index 00000000..57d50cb2 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanelVisual.form @@ -0,0 +1,120 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanelVisual.java b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanelVisual.java new file mode 100644 index 00000000..cdde5187 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneDownloadPanelVisual.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.monkeyzone; + +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; + +public class MonkeyZoneDownloadPanelVisual extends JPanel implements DocumentListener { + + public static final String PROP_PROJECT_NAME = "projectName"; + private final MonkeyZoneDownloadPanel panel; + + public MonkeyZoneDownloadPanelVisual(MonkeyZoneDownloadPanel panel) { + initComponents(); + this.panel = panel; + } + + /** 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + downloadButton = new javax.swing.JButton(); + jScrollPane1 = new javax.swing.JScrollPane(); + jTextArea1 = new javax.swing.JTextArea(); + statusField = new javax.swing.JTextField(); + jLabel1 = new javax.swing.JLabel(); + + org.openide.awt.Mnemonics.setLocalizedText(downloadButton, org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.downloadButton.text")); // NOI18N + downloadButton.setActionCommand(org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.downloadButton.actionCommand")); // NOI18N + downloadButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + downloadButtonActionPerformed(evt); + } + }); + + jTextArea1.setEditable(false); + jTextArea1.setColumns(20); + jTextArea1.setLineWrap(true); + jTextArea1.setRows(5); + jTextArea1.setText(org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.jTextArea1.text")); // NOI18N + jTextArea1.setWrapStyleWord(true); + jTextArea1.setEnabled(false); + jScrollPane1.setViewportView(jTextArea1); + + statusField.setEditable(false); + statusField.setText(org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.statusField.text")); // NOI18N + statusField.setEnabled(false); + statusField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + statusFieldActionPerformed(evt); + } + }); + + jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/templates/monkeyzone/monkeyzone.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.jLabel1.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() + .addComponent(jLabel1) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 307, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(statusField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 313, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createSequentialGroup() + .addGap(99, 99, 99) + .addComponent(downloadButton))) + .addContainerGap(14, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(71, 71, 71) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(21, 21, 21) + .addComponent(downloadButton) + .addGap(18, 18, 18) + .addComponent(statusField, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void downloadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed + statusField.setText(org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.downloading")); + final int result = this.panel.doDownloadZip(); + if (result == 1) { + statusField.setText(org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.downloadSuccess")); + } else { + statusField.setText(org.openide.util.NbBundle.getMessage(MonkeyZoneDownloadPanelVisual.class, "MonkeyZoneDownloadPanelVisual.downloadFailed")); + } + }//GEN-LAST:event_downloadButtonActionPerformed + + private void statusFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_statusFieldActionPerformed + + }//GEN-LAST:event_statusFieldActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + javax.swing.JButton downloadButton; + javax.swing.JLabel jLabel1; + javax.swing.JScrollPane jScrollPane1; + javax.swing.JTextArea jTextArea1; + javax.swing.JTextField statusField; + // End of variables declaration//GEN-END:variables + + @Override + public void addNotify() { + super.addNotify(); + } + + boolean valid(WizardDescriptor wizardDescriptor) { + + return true; + } + + void store(WizardDescriptor d) { + + } + + void read(WizardDescriptor settings) { + + } + + void validate(WizardDescriptor d) throws WizardValidationException { + // nothing to validate + } + + // Implementation of DocumentListener -------------------------------------- + @Override + public void changedUpdate(DocumentEvent e) { + + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateTexts(e); + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateTexts(e); + } + + /** Handles changes in the Project name and project directory, */ + private void updateTexts(DocumentEvent e) { + + panel.fireChangeEvent(); // Notify that the panel changed + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZonePanelVisual.form b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZonePanelVisual.form new file mode 100644 index 00000000..ddb652b7 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZonePanelVisual.form @@ -0,0 +1,122 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZonePanelVisual.java b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZonePanelVisual.java new file mode 100644 index 00000000..f4cc3e63 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZonePanelVisual.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.monkeyzone; + +import java.io.File; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import org.netbeans.spi.project.ui.support.ProjectChooser; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.filesystems.FileUtil; + +public class MonkeyZonePanelVisual extends JPanel implements DocumentListener { + + public static final String PROP_PROJECT_NAME = "projectName"; + static final String PROJECT_NAME = "MonkeyZone"; + private final MonkeyZoneWizardPanel panel; + + public MonkeyZonePanelVisual(MonkeyZoneWizardPanel panel) { + initComponents(); + this.panel = panel; + // Register listener on the textFields to make the automatic updates + projectNameTextField.getDocument().addDocumentListener(this); + projectLocationTextField.getDocument().addDocumentListener(this); + } + + public String getProjectName() { + return this.projectNameTextField.getText(); + } + + /** 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + projectNameLabel = new javax.swing.JLabel(); + projectNameTextField = new javax.swing.JTextField(); + projectLocationLabel = new javax.swing.JLabel(); + projectLocationTextField = new javax.swing.JTextField(); + browseButton = new javax.swing.JButton(); + createdFolderLabel = new javax.swing.JLabel(); + createdFolderTextField = new javax.swing.JTextField(); + + projectNameLabel.setLabelFor(projectNameTextField); + org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel, org.openide.util.NbBundle.getMessage(MonkeyZonePanelVisual.class, "MonkeyZonePanelVisual.projectNameLabel.text")); // NOI18N + + projectLocationLabel.setLabelFor(projectLocationTextField); + org.openide.awt.Mnemonics.setLocalizedText(projectLocationLabel, org.openide.util.NbBundle.getMessage(MonkeyZonePanelVisual.class, "MonkeyZonePanelVisual.projectLocationLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(MonkeyZonePanelVisual.class, "MonkeyZonePanelVisual.browseButton.text")); // NOI18N + browseButton.setActionCommand(org.openide.util.NbBundle.getMessage(MonkeyZonePanelVisual.class, "MonkeyZonePanelVisual.browseButton.actionCommand")); // NOI18N + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); + + createdFolderLabel.setLabelFor(createdFolderTextField); + org.openide.awt.Mnemonics.setLocalizedText(createdFolderLabel, org.openide.util.NbBundle.getMessage(MonkeyZonePanelVisual.class, "MonkeyZonePanelVisual.createdFolderLabel.text")); // NOI18N + + createdFolderTextField.setEditable(false); + + 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(projectNameLabel) + .addComponent(projectLocationLabel) + .addComponent(createdFolderLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(projectNameTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE) + .addComponent(projectLocationTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE) + .addComponent(createdFolderTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(projectNameLabel) + .addComponent(projectNameTextField, 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(projectLocationLabel) + .addComponent(projectLocationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(createdFolderLabel) + .addComponent(createdFolderTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(213, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + String command = evt.getActionCommand(); + if ("BROWSE".equals(command)) { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(null); + chooser.setDialogTitle("Select Project Location"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + String path = this.projectLocationTextField.getText(); + if (path.length() > 0) { + File f = new File(path); + if (f.exists()) { + chooser.setSelectedFile(f); + } + } + if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(this)) { + File projectDir = chooser.getSelectedFile(); + projectLocationTextField.setText(FileUtil.normalizeFile(projectDir).getAbsolutePath()); + } + panel.fireChangeEvent(); + } + + }//GEN-LAST:event_browseButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + javax.swing.JButton browseButton; + javax.swing.JLabel createdFolderLabel; + javax.swing.JTextField createdFolderTextField; + javax.swing.JLabel projectLocationLabel; + javax.swing.JTextField projectLocationTextField; + javax.swing.JLabel projectNameLabel; + javax.swing.JTextField projectNameTextField; + // End of variables declaration//GEN-END:variables + + @Override + public void addNotify() { + super.addNotify(); + //same problem as in 31086, initial focus on Cancel button + projectNameTextField.requestFocus(); + } + + boolean valid(WizardDescriptor wizardDescriptor) { + + if (projectNameTextField.getText().length() == 0) { + // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_ERROR_MESSAGE: + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Name is not a valid folder name."); + return false; // Display name not specified + } + File f = FileUtil.normalizeFile(new File(projectLocationTextField.getText()).getAbsoluteFile()); + if (!f.isDirectory()) { + String message = "Project Folder is not a valid path."; + wizardDescriptor.putProperty("WizardPanel_errorMessage", message); + return false; + } + final File destFolder = FileUtil.normalizeFile(new File(createdFolderTextField.getText()).getAbsoluteFile()); + + File projLoc = destFolder; + while (projLoc != null && !projLoc.exists()) { + projLoc = projLoc.getParentFile(); + } + if (projLoc == null || !projLoc.canWrite()) { + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Folder cannot be created."); + return false; + } + + if (FileUtil.toFileObject(projLoc) == null) { + String message = "Project Folder is not a valid path."; + wizardDescriptor.putProperty("WizardPanel_errorMessage", message); + return false; + } + + File[] kids = destFolder.listFiles(); + if (destFolder.exists() && kids != null && kids.length > 0) { + // Folder exists and is not empty + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Folder already exists and is not empty."); + return false; + } + wizardDescriptor.putProperty("WizardPanel_errorMessage", ""); + return true; + } + + void store(WizardDescriptor d) { + String name = projectNameTextField.getText().trim(); + String folder = createdFolderTextField.getText().trim(); + + d.putProperty("projdir", new File(folder)); + d.putProperty("name", name); + } + + void read(WizardDescriptor settings) { + File projectLocation = (File) settings.getProperty("projdir"); + if (projectLocation == null || projectLocation.getParentFile() == null || !projectLocation.getParentFile().isDirectory()) { + projectLocation = ProjectChooser.getProjectsFolder(); + } else { + projectLocation = projectLocation.getParentFile(); + } + this.projectLocationTextField.setText(projectLocation.getAbsolutePath()); + + String projectName = (String) settings.getProperty("name"); + if (projectName == null) { + projectName = PROJECT_NAME; + } + this.projectNameTextField.setText(projectName); + this.projectNameTextField.selectAll(); + } + + void validate(WizardDescriptor d) throws WizardValidationException { + // nothing to validate + } + + // Implementation of DocumentListener -------------------------------------- + @Override + public void changedUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + /** Handles changes in the Project name and project directory, */ + private void updateTexts(DocumentEvent e) { + + Document doc = e.getDocument(); + + if (doc == projectNameTextField.getDocument() || doc == projectLocationTextField.getDocument()) { + // Change in the project name + + String projectName = projectNameTextField.getText(); + String projectFolder = projectLocationTextField.getText(); + + //if (projectFolder.trim().length() == 0 || projectFolder.equals(oldName)) { + createdFolderTextField.setText(projectFolder + File.separatorChar + projectName); + //} + + } + panel.fireChangeEvent(); // Notify that the panel changed + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneWizardIterator.java b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneWizardIterator.java new file mode 100644 index 00000000..50d5200f --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneWizardIterator.java @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.monkeyzone; + +import com.jme3.gde.templates.gradledesktop.options.CachedOptionsContainer; +import java.awt.Component; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import javax.swing.JComponent; +import javax.swing.event.ChangeListener; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.spi.project.ui.support.ProjectChooser; +import org.openide.WizardDescriptor; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.NbBundle; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class MonkeyZoneWizardIterator implements WizardDescriptor.InstantiatingIterator { + + private int index; + private WizardDescriptor.Panel[] panels; + private WizardDescriptor wiz; + + + final static String master = "monkeyzone-master/"; + + + public MonkeyZoneWizardIterator() { + + // Initiate the options getting... + CachedOptionsContainer.getInstance(); + } + + public static MonkeyZoneWizardIterator createIterator() { + return new MonkeyZoneWizardIterator(); + } + + private WizardDescriptor.Panel[] createPanels() { + return new WizardDescriptor.Panel[]{ + new MonkeyZoneDownloadPanel(), + new MonkeyZoneWizardPanel() + }; + } + + private String[] createSteps() { + return new String[]{ + NbBundle.getMessage(MonkeyZoneWizardIterator.class, "LBL_DownloadProjectStep"), + NbBundle.getMessage(MonkeyZoneWizardIterator.class, "LBL_CreateProjectStep"), + }; + } + + @Override + public Set/**/ instantiate(/*ProgressHandle handle*/) throws IOException { + Set resultSet = new LinkedHashSet<>(); + File dirF = FileUtil.normalizeFile((File) wiz.getProperty("projdir")); + dirF.mkdirs(); + + FileObject template = FileUtil.toFileObject(new File( + MonkeyZoneDownloadPanel.DOWNLOAD_FOLDER, + MonkeyZoneDownloadPanel.ZIP_NAME)); + + FileObject dir = FileUtil.toFileObject(dirF); + unZipFile(template.getInputStream(), dir); + + // Always open top dir as a project: + resultSet.add(dir); + // Look for nested projects to open as well: + Enumeration e = dir.getFolders(true); + while (e.hasMoreElements()) { + FileObject subfolder = e.nextElement(); + if (ProjectManager.getDefault().isProject(subfolder)) { + resultSet.add(subfolder); + } + } + + File parent = dirF.getParentFile(); + if (parent != null && parent.exists()) { + ProjectChooser.setProjectsFolder(parent); + } + + return resultSet; + } + + @Override + public void initialize(WizardDescriptor wiz) { + this.wiz = wiz; + index = 0; + panels = createPanels(); + // Make sure list of steps is accurate. + String[] steps = createSteps(); + for (int i = 0; i < panels.length; i++) { + Component c = panels[i].getComponent(); + if (steps[i] == null) { + // Default step name to component name of panel. + // Mainly useful for getting the name of the target + // chooser to appear in the list of steps. + steps[i] = c.getName(); + } + if (c instanceof JComponent jc) { // Step #. + // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*: + jc.putClientProperty("WizardPanel_contentSelectedIndex", i); + // Step name (actually the whole list for reference). + jc.putClientProperty("WizardPanel_contentData", steps); + } + } + } + + @Override + public void uninitialize(WizardDescriptor wiz) { + this.wiz.putProperty("projdir", null); + this.wiz.putProperty("name", null); + this.wiz = null; + panels = null; + } + + @Override + public String name() { + return MessageFormat.format("{0} of {1}", + new Object[]{index + 1, panels.length}); + } + + @Override + public boolean hasNext() { + return index < panels.length - 1; + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public void nextPanel() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + index++; + } + + @Override + public void previousPanel() { + if (!hasPrevious()) { + throw new NoSuchElementException(); + } + index--; + } + + @Override + public WizardDescriptor.Panel current() { + return panels[index]; + } + + // If nothing unusual changes in the middle of the wizard, simply: + @Override + public final void addChangeListener(ChangeListener l) { + } + + @Override + public final void removeChangeListener(ChangeListener l) { + } + + private void createFileFromTemplate(File target, String templateResourcePath, Map tokens) throws IOException { + + // Create FreeMarker script engine + ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); + ScriptEngine engine = scriptEngineManager.getEngineByName("freemarker"); + Map bindings = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE); + bindings.putAll(tokens); + + // Process template + try { + FileObject targetFO = FileUtil.toFileObject(target); + try (Writer os = new BufferedWriter(new OutputStreamWriter(targetFO.getOutputStream(), StandardCharsets.UTF_8)); Reader is = new BufferedReader(new InputStreamReader(MonkeyZoneWizardIterator.class.getResourceAsStream("/" + templateResourcePath)));) { + engine.getContext().setWriter(os); + engine.eval(is); + } + } catch (IOException | ScriptException ex) { + throw new IOException(ex.getMessage(), ex); + } + } + + private static void unZipFile(InputStream source, FileObject projectRoot) throws IOException { + try (source) { + ZipInputStream str = new ZipInputStream(source); + ZipEntry entry; + while ((entry = str.getNextEntry()) != null) { + if (entry.getName().endsWith(master)) { + continue; + } + final String entryName = entry.getName().replace(master, ""); + if (entry.isDirectory()) { + FileUtil.createFolder(projectRoot, entryName); + } else { + FileObject fo = FileUtil.createData(projectRoot, entryName); + try (OutputStream out = fo.getOutputStream()) { + FileUtil.copy(str, out); + } + } + } + } + } + +} diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneWizardPanel.java b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneWizardPanel.java new file mode 100644 index 00000000..57dcb16f --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/MonkeyZoneWizardPanel.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.monkeyzone; + +import java.awt.Component; +import java.util.HashSet; +import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +/** + * Panel just asking for basic info. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class MonkeyZoneWizardPanel implements WizardDescriptor.Panel, + WizardDescriptor.ValidatingPanel, WizardDescriptor.FinishablePanel { + + private WizardDescriptor wizardDescriptor; + private MonkeyZonePanelVisual component; + + public MonkeyZoneWizardPanel() { + } + + @Override + public Component getComponent() { + if (component == null) { + component = new MonkeyZonePanelVisual(this); + component.setName(NbBundle.getMessage(MonkeyZoneWizardPanel.class, "LBL_CreateProjectStep")); + } + return component; + } + + @Override + public HelpCtx getHelp() { + return new HelpCtx("sdk.project_creation"); + } + + @Override + public boolean isValid() { + getComponent(); + return component.valid(wizardDescriptor); + } + + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 + + @Override + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + @Override + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + protected final void fireChangeEvent() { + Set ls; + synchronized (listeners) { + ls = new HashSet<>(listeners); + } + ChangeEvent ev = new ChangeEvent(this); + for (ChangeListener l : ls) { + l.stateChanged(ev); + } + } + + @Override + public void readSettings(Object settings) { + wizardDescriptor = (WizardDescriptor) settings; + component.read(wizardDescriptor); + } + + @Override + public void storeSettings(Object settings) { + WizardDescriptor d = (WizardDescriptor) settings; + component.store(d); + } + + @Override + public boolean isFinishPanel() { + return false; + } + + @Override + public void validate() throws WizardValidationException { + getComponent(); + component.validate(wizardDescriptor); + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/build.gradle.ftl b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/build.gradle.ftl new file mode 100644 index 00000000..8093c2a7 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/build.gradle.ftl @@ -0,0 +1,65 @@ +plugins { + id 'java' + id 'application' +} + +group 'com.monkeyzone' +version '1.0' + +mainClassName = "com.monkeyzone.MonkeyZone" + +repositories { + mavenCentral() +} + +project.ext { + jmeVer = '3.7.0-stable' +} + +project(":assets") { + apply plugin: "java" + + buildDir = rootProject.file("build/assets") + + sourceSets { + main { + resources { + srcDir '.' + } + } + } + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +dependencies { + + implementation "org.jmonkeyengine:jme3-core:$jmeVer" + implementation "org.jmonkeyengine:jme3-desktop:$jmeVer" + implementation "org.jmonkeyengine:jme3-lwjgl:$jmeVer" + implementation "org.jmonkeyengine:jme3-lwjgl:$jmeVer" + implementation "com.github.stephengold:Heart:9.0.0" + implementation "com.github.stephengold:Minie:8.0.0" + implementation project("assets") + +} + +jar { + manifest { + attributes 'Main-Class': "$mainClassName" + } +} + +wrapper { + gradleVersion = '8.6' +} diff --git a/jme3-templates/src/com/jme3/gde/templates/monkeyzone/monkeyzone.png b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/monkeyzone.png new file mode 100644 index 00000000..562a0d59 Binary files /dev/null and b/jme3-templates/src/com/jme3/gde/templates/monkeyzone/monkeyzone.png differ diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/Bundle.properties b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/Bundle.properties new file mode 100644 index 00000000..12750bdc --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/Bundle.properties @@ -0,0 +1,6 @@ +LBL_CreateProjectStep=Name and Location +RollingTheMonkeyPanelVisual.browseButton.text=Br&owse... +RollingTheMonkeyPanelVisual.createdFolderLabel.text=Project &Folder: +RollingTheMonkeyPanelVisual.projectNameLabel.text=Project &Name: +RollingTheMonkeyPanelVisual.projectLocationLabel.text=Project &Location: +RollingTheMonkeyPanelVisual.browseButton.actionCommand=BROWSE diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyDescription.html b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyDescription.html new file mode 100644 index 00000000..2ae5760e --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyDescription.html @@ -0,0 +1,14 @@ + + + + + + + A simple physics based marble game. Made by SkidRunner (Mark E. Picknell).

+ + Here are some ideas of how you can take it further:
+ 1. Add a timer and display the time it takes to pick up all the cubes
+ 2. Replace the texture of the sphere with one of your choosing.
+ 3. Change the physics of the sphere. + + diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyPanelVisual.form b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyPanelVisual.form new file mode 100644 index 00000000..1ec44697 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyPanelVisual.form @@ -0,0 +1,122 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyPanelVisual.java b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyPanelVisual.java new file mode 100644 index 00000000..90106282 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyPanelVisual.java @@ -0,0 +1,263 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.templates.rollingthemonkey; + +import java.io.File; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.Document; +import org.netbeans.spi.project.ui.support.ProjectChooser; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.filesystems.FileUtil; + +public class RollingTheMonkeyPanelVisual extends JPanel implements DocumentListener { + + public static final String PROP_PROJECT_NAME = "projectName"; + private final RollingTheMonkeyWizardPanel panel; + + public RollingTheMonkeyPanelVisual(RollingTheMonkeyWizardPanel panel) { + initComponents(); + this.panel = panel; + // Register listener on the textFields to make the automatic updates + projectNameTextField.getDocument().addDocumentListener(this); + projectLocationTextField.getDocument().addDocumentListener(this); + } + + public String getProjectName() { + return this.projectNameTextField.getText(); + } + + /** 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + projectNameLabel = new javax.swing.JLabel(); + projectNameTextField = new javax.swing.JTextField(); + projectLocationLabel = new javax.swing.JLabel(); + projectLocationTextField = new javax.swing.JTextField(); + browseButton = new javax.swing.JButton(); + createdFolderLabel = new javax.swing.JLabel(); + createdFolderTextField = new javax.swing.JTextField(); + + projectNameLabel.setLabelFor(projectNameTextField); + org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel, org.openide.util.NbBundle.getMessage(RollingTheMonkeyPanelVisual.class, "RollingTheMonkeyPanelVisual.projectNameLabel.text")); // NOI18N + + projectLocationLabel.setLabelFor(projectLocationTextField); + org.openide.awt.Mnemonics.setLocalizedText(projectLocationLabel, org.openide.util.NbBundle.getMessage(RollingTheMonkeyPanelVisual.class, "RollingTheMonkeyPanelVisual.projectLocationLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(RollingTheMonkeyPanelVisual.class, "RollingTheMonkeyPanelVisual.browseButton.text")); // NOI18N + browseButton.setActionCommand(org.openide.util.NbBundle.getMessage(RollingTheMonkeyPanelVisual.class, "RollingTheMonkeyPanelVisual.browseButton.actionCommand")); // NOI18N + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); + + createdFolderLabel.setLabelFor(createdFolderTextField); + org.openide.awt.Mnemonics.setLocalizedText(createdFolderLabel, org.openide.util.NbBundle.getMessage(RollingTheMonkeyPanelVisual.class, "RollingTheMonkeyPanelVisual.createdFolderLabel.text")); // NOI18N + + createdFolderTextField.setEditable(false); + + 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(projectNameLabel) + .addComponent(projectLocationLabel) + .addComponent(createdFolderLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(projectNameTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE) + .addComponent(projectLocationTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE) + .addComponent(createdFolderTextField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 191, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(projectNameLabel) + .addComponent(projectNameTextField, 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(projectLocationLabel) + .addComponent(projectLocationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(createdFolderLabel) + .addComponent(createdFolderTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(213, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + String command = evt.getActionCommand(); + if ("BROWSE".equals(command)) { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(null); + chooser.setDialogTitle("Select Project Location"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + String path = this.projectLocationTextField.getText(); + if (path.length() > 0) { + File f = new File(path); + if (f.exists()) { + chooser.setSelectedFile(f); + } + } + if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(this)) { + File projectDir = chooser.getSelectedFile(); + projectLocationTextField.setText(FileUtil.normalizeFile(projectDir).getAbsolutePath()); + } + panel.fireChangeEvent(); + } + + }//GEN-LAST:event_browseButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + javax.swing.JButton browseButton; + javax.swing.JLabel createdFolderLabel; + javax.swing.JTextField createdFolderTextField; + javax.swing.JLabel projectLocationLabel; + javax.swing.JTextField projectLocationTextField; + javax.swing.JLabel projectNameLabel; + javax.swing.JTextField projectNameTextField; + // End of variables declaration//GEN-END:variables + + @Override + public void addNotify() { + super.addNotify(); + //same problem as in 31086, initial focus on Cancel button + projectNameTextField.requestFocus(); + } + + boolean valid(WizardDescriptor wizardDescriptor) { + + if (projectNameTextField.getText().length() == 0) { + // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_ERROR_MESSAGE: + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Name is not a valid folder name."); + return false; // Display name not specified + } + File f = FileUtil.normalizeFile(new File(projectLocationTextField.getText()).getAbsoluteFile()); + if (!f.isDirectory()) { + String message = "Project Folder is not a valid path."; + wizardDescriptor.putProperty("WizardPanel_errorMessage", message); + return false; + } + final File destFolder = FileUtil.normalizeFile(new File(createdFolderTextField.getText()).getAbsoluteFile()); + + File projLoc = destFolder; + while (projLoc != null && !projLoc.exists()) { + projLoc = projLoc.getParentFile(); + } + if (projLoc == null || !projLoc.canWrite()) { + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Folder cannot be created."); + return false; + } + + if (FileUtil.toFileObject(projLoc) == null) { + String message = "Project Folder is not a valid path."; + wizardDescriptor.putProperty("WizardPanel_errorMessage", message); + return false; + } + + File[] kids = destFolder.listFiles(); + if (destFolder.exists() && kids != null && kids.length > 0) { + // Folder exists and is not empty + wizardDescriptor.putProperty("WizardPanel_errorMessage", + "Project Folder already exists and is not empty."); + return false; + } + wizardDescriptor.putProperty("WizardPanel_errorMessage", ""); + return true; + } + + void store(WizardDescriptor d) { + String name = projectNameTextField.getText().trim(); + String folder = createdFolderTextField.getText().trim(); + + d.putProperty("projdir", new File(folder)); + d.putProperty("name", name); + } + + void read(WizardDescriptor settings) { + File projectLocation = (File) settings.getProperty("projdir"); + if (projectLocation == null || projectLocation.getParentFile() == null || !projectLocation.getParentFile().isDirectory()) { + projectLocation = ProjectChooser.getProjectsFolder(); + } else { + projectLocation = projectLocation.getParentFile(); + } + this.projectLocationTextField.setText(projectLocation.getAbsolutePath()); + + String projectName = (String) settings.getProperty("name"); + if (projectName == null) { + projectName = "RollingTheMonkey"; + } + this.projectNameTextField.setText(projectName); + this.projectNameTextField.selectAll(); + } + + void validate(WizardDescriptor d) throws WizardValidationException { + // nothing to validate + } + + // Implementation of DocumentListener -------------------------------------- + @Override + public void changedUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateTexts(e); + if (this.projectNameTextField.getDocument() == e.getDocument()) { + firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText()); + } + } + + /** Handles changes in the Project name and project directory, */ + private void updateTexts(DocumentEvent e) { + + Document doc = e.getDocument(); + + if (doc == projectNameTextField.getDocument() || doc == projectLocationTextField.getDocument()) { + // Change in the project name + + String projectName = projectNameTextField.getText(); + String projectFolder = projectLocationTextField.getText(); + + //if (projectFolder.trim().length() == 0 || projectFolder.equals(oldName)) { + createdFolderTextField.setText(projectFolder + File.separatorChar + projectName); + //} + + } + panel.fireChangeEvent(); // Notify that the panel changed + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyWizardIterator.java b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyWizardIterator.java new file mode 100644 index 00000000..f3afe777 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyWizardIterator.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.rollingthemonkey; + +import com.jme3.gde.templates.gradledesktop.options.CachedOptionsContainer; +import java.awt.Component; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import javax.swing.JComponent; +import javax.swing.event.ChangeListener; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.spi.project.ui.support.ProjectChooser; +import org.netbeans.spi.project.ui.templates.support.Templates; +import org.openide.WizardDescriptor; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.util.NbBundle; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class RollingTheMonkeyWizardIterator implements WizardDescriptor./*Progress*/InstantiatingIterator { + + private int index; + private WizardDescriptor.Panel[] panels; + private WizardDescriptor wiz; + + private static final String TEMPLATE_SETTINGS = "com/jme3/gde/templates/files/freemarker/settings.gradle.ftl"; + private static final String BUILDFILE = "com/jme3/gde/templates/rollingthemonkey/build.gradle.ftl"; + + public RollingTheMonkeyWizardIterator() { + + // Initiate the options getting... + CachedOptionsContainer.getInstance(); + } + + public static RollingTheMonkeyWizardIterator createIterator() { + return new RollingTheMonkeyWizardIterator(); + } + + private WizardDescriptor.Panel[] createPanels() { + return new WizardDescriptor.Panel[]{ + new RollingTheMonkeyWizardPanel() + }; + } + + private String[] createSteps() { + return new String[]{ + NbBundle.getMessage(RollingTheMonkeyWizardIterator.class, "LBL_CreateProjectStep"), + }; + } + + @Override + public Set/**/ instantiate(/*ProgressHandle handle*/) throws IOException { + Set resultSet = new LinkedHashSet<>(); + File dirF = FileUtil.normalizeFile((File) wiz.getProperty("projdir")); + dirF.mkdirs(); + + FileObject template = Templates.getTemplate(wiz); + FileObject dir = FileUtil.toFileObject(dirF); + unZipFile(template.getInputStream(), dir); + + // Create settings.gradle from template + File gradleSettingsFile = new File(dirF, "settings.gradle"); + createFileFromTemplate(gradleSettingsFile, TEMPLATE_SETTINGS, + Collections.singletonMap("name", wiz.getProperty("name"))); + + // Create build.gradle from template + File gradleBuildFile = new File(dirF, "build.gradle"); + Map buildFileBindings = new HashMap<>(); + + createFileFromTemplate(gradleBuildFile, BUILDFILE, buildFileBindings); + + // Always open top dir as a project: + resultSet.add(dir); + // Look for nested projects to open as well: + Enumeration e = dir.getFolders(true); + while (e.hasMoreElements()) { + FileObject subfolder = e.nextElement(); + if (ProjectManager.getDefault().isProject(subfolder)) { + resultSet.add(subfolder); + } + } + + File parent = dirF.getParentFile(); + if (parent != null && parent.exists()) { + ProjectChooser.setProjectsFolder(parent); + } + + return resultSet; + } + + @Override + public void initialize(WizardDescriptor wiz) { + this.wiz = wiz; + index = 0; + panels = createPanels(); + // Make sure list of steps is accurate. + String[] steps = createSteps(); + for (int i = 0; i < panels.length; i++) { + Component c = panels[i].getComponent(); + if (steps[i] == null) { + // Default step name to component name of panel. + // Mainly useful for getting the name of the target + // chooser to appear in the list of steps. + steps[i] = c.getName(); + } + if (c instanceof JComponent) { // assume Swing components + JComponent jc = (JComponent) c; + // Step #. + // TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*: + jc.putClientProperty("WizardPanel_contentSelectedIndex", i); + // Step name (actually the whole list for reference). + jc.putClientProperty("WizardPanel_contentData", steps); + } + } + } + + @Override + public void uninitialize(WizardDescriptor wiz) { + this.wiz.putProperty("projdir", null); + this.wiz.putProperty("name", null); + this.wiz = null; + panels = null; + } + + @Override + public String name() { + return MessageFormat.format("{0} of {1}", + new Object[]{index + 1, panels.length}); + } + + @Override + public boolean hasNext() { + return index < panels.length - 1; + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public void nextPanel() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + index++; + } + + @Override + public void previousPanel() { + if (!hasPrevious()) { + throw new NoSuchElementException(); + } + index--; + } + + @Override + public WizardDescriptor.Panel current() { + return panels[index]; + } + + // If nothing unusual changes in the middle of the wizard, simply: + @Override + public final void addChangeListener(ChangeListener l) { + } + + @Override + public final void removeChangeListener(ChangeListener l) { + } + + private void createFileFromTemplate(File target, String templateResourcePath, Map tokens) throws IOException { + + // Create FreeMarker script engine + ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); + ScriptEngine engine = scriptEngineManager.getEngineByName("freemarker"); + Map bindings = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE); + bindings.putAll(tokens); + + // Process template + try { + FileObject targetFO = FileUtil.toFileObject(target); + try (Writer os = new BufferedWriter(new OutputStreamWriter(targetFO.getOutputStream(), StandardCharsets.UTF_8)); Reader is = new BufferedReader(new InputStreamReader(RollingTheMonkeyWizardIterator.class.getResourceAsStream("/" + templateResourcePath)));) { + engine.getContext().setWriter(os); + engine.eval(is); + } + } catch (IOException | ScriptException ex) { + throw new IOException(ex.getMessage(), ex); + } + } + + private static void unZipFile(InputStream source, FileObject projectRoot) throws IOException { + try (source) { + ZipInputStream str = new ZipInputStream(source); + ZipEntry entry; + while ((entry = str.getNextEntry()) != null) { + if (entry.isDirectory()) { + FileUtil.createFolder(projectRoot, entry.getName()); + } else { + FileObject fo = FileUtil.createData(projectRoot, entry.getName()); + try (OutputStream out = fo.getOutputStream()) { + FileUtil.copy(str, out); + } + } + } + } + } + +} diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyWizardPanel.java b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyWizardPanel.java new file mode 100644 index 00000000..207ee0de --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/RollingTheMonkeyWizardPanel.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.gde.templates.rollingthemonkey; + +import java.awt.Component; +import java.util.HashSet; +import java.util.Set; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import org.openide.WizardDescriptor; +import org.openide.WizardValidationException; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; + +/** + * Panel just asking for basic info. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class RollingTheMonkeyWizardPanel implements WizardDescriptor.Panel, + WizardDescriptor.ValidatingPanel, WizardDescriptor.FinishablePanel { + + private WizardDescriptor wizardDescriptor; + private RollingTheMonkeyPanelVisual component; + + public RollingTheMonkeyWizardPanel() { + } + + @Override + public Component getComponent() { + if (component == null) { + component = new RollingTheMonkeyPanelVisual(this); + component.setName(NbBundle.getMessage(RollingTheMonkeyWizardPanel.class, "LBL_CreateProjectStep")); + } + return component; + } + + @Override + public HelpCtx getHelp() { + return new HelpCtx("sdk.project_creation"); + } + + @Override + public boolean isValid() { + getComponent(); + return component.valid(wizardDescriptor); + } + + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 + + @Override + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + @Override + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + protected final void fireChangeEvent() { + Set ls; + synchronized (listeners) { + ls = new HashSet<>(listeners); + } + ChangeEvent ev = new ChangeEvent(this); + for (ChangeListener l : ls) { + l.stateChanged(ev); + } + } + + @Override + public void readSettings(Object settings) { + wizardDescriptor = (WizardDescriptor) settings; + component.read(wizardDescriptor); + } + + @Override + public void storeSettings(Object settings) { + WizardDescriptor d = (WizardDescriptor) settings; + component.store(d); + } + + @Override + public boolean isFinishPanel() { + return false; + } + + @Override + public void validate() throws WizardValidationException { + getComponent(); + component.validate(wizardDescriptor); + } +} diff --git a/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/build.gradle.ftl b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/build.gradle.ftl new file mode 100644 index 00000000..94e41ae1 --- /dev/null +++ b/jme3-templates/src/com/jme3/gde/templates/rollingthemonkey/build.gradle.ftl @@ -0,0 +1,65 @@ +plugins { + id 'java' + id 'application' +} + +group 'com.rollingthemonkey' +version '1.0' + +mainClassName = "com.rollingthemonkey.RollingTheMonkey" + +repositories { + mavenCentral() +} + +project.ext { + jmeVer = '3.7.0-stable' +} + +project(":assets") { + apply plugin: "java" + + buildDir = rootProject.file("build/assets") + + sourceSets { + main { + resources { + srcDir '.' + } + } + } + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +dependencies { + + implementation "org.jmonkeyengine:jme3-core:$jmeVer" + implementation "org.jmonkeyengine:jme3-desktop:$jmeVer" + implementation "org.jmonkeyengine:jme3-lwjgl:$jmeVer" + implementation "org.jmonkeyengine:jme3-lwjgl:$jmeVer" + implementation "com.github.stephengold:Heart:9.0.0" + implementation "com.github.stephengold:Minie:8.0.0" + implementation project("assets") + +} + +jar { + manifest { + attributes 'Main-Class': "$mainClassName" + } +} + +wrapper { + gradleVersion = '8.6' +}