From 52a6e63eaa6112eb4169d50d1fb8f67de19d25e2 Mon Sep 17 00:00:00 2001 From: rickard Date: Sun, 29 Dec 2024 09:24:52 +0100 Subject: [PATCH 1/3] Allow node actions on multiple selected nodes (Delete, etc) --- .../SceneExplorerTopComponent.java | 88 ++++------ .../nodes/actions/MotionPathPopup.java | 18 +- .../SceneComposerTopComponent.java | 164 ++++++++---------- .../gde/scenecomposer/tools/SelectTool.java | 34 +++- .../tools/shortcuts/DuplicateShortcut.java | 66 ++++--- 5 files changed, 200 insertions(+), 170 deletions(-) diff --git a/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java b/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java index a9eb771bb..e79cc79dc 100644 --- a/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java +++ b/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2010 jMonkeyEngine + * Copyright (c) 2009-2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,11 +77,13 @@ public final class SceneExplorerTopComponent extends TopComponent implements Exp private static final Logger logger = Logger.getLogger(SceneExplorerTopComponent.class.getName()); private static SceneExplorerTopComponent instance; private static final String PREFERRED_ID = "SceneExplorerTopComponent"; -// private final Result nodeSelectionResult; - private AbstractSceneExplorerNode selectedSpatial; - private AbstractSceneExplorerNode lastSelected; - private Map materialChangeProviders = new HashMap(); - private Map> materialChangeListeners = new HashMap>(); + + private AbstractSceneExplorerNode[] selectedSpatials; + private AbstractSceneExplorerNode[] lastSelected; + private final Map materialChangeProviders = new HashMap<>(); + private final Map> materialChangeListeners = new HashMap<>(); + + private final transient ExplorerManager explorerManager = new ExplorerManager(); public SceneExplorerTopComponent() { initComponents(); @@ -90,8 +92,6 @@ public SceneExplorerTopComponent() { setToolTipText(NbBundle.getMessage(SceneExplorerTopComponent.class, "HINT_SceneExplorerTopComponent")); setIcon(IconList.jmeLogo.getImage()); associateLookup(ExplorerUtils.createLookup(explorerManager, getActionMap())); -// nodeSelectionResult = Utilities.actionsGlobalContext().lookupResult(AbstractSceneExplorerNode.class); -// nodeSelectionResult.addLookupListener(this); } private void initActions() { @@ -148,10 +148,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }// //GEN-END:initComponents private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - if (selectedSpatial == null) { + if (selectedSpatials == null) { return; } - selectedSpatial.refresh(false); + for (AbstractSceneExplorerNode node: selectedSpatials) { + node.refresh(false); + } + + }//GEN-LAST:event_jButton1ActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane explorerScrollPane; @@ -164,6 +168,7 @@ private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS * only, i.e. deserialization routines; otherwise you could get a * non-deserialized instance. To obtain the singleton instance, use * {@link #findInstance}. + * @return */ public static synchronized SceneExplorerTopComponent getDefault() { if (instance == null) { @@ -175,16 +180,17 @@ public static synchronized SceneExplorerTopComponent getDefault() { /** * Obtain the SceneExplorerTopComponent instance. Never call * {@link #getDefault} directly! + * @return */ public static synchronized SceneExplorerTopComponent findInstance() { - TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID); - if (win == null) { + TopComponent window = WindowManager.getDefault().findTopComponent(PREFERRED_ID); + if (window == null) { logger.warning( "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); return getDefault(); } - if (win instanceof SceneExplorerTopComponent) { - return (SceneExplorerTopComponent) win; + if (window instanceof SceneExplorerTopComponent sceneExplorerTopComponent) { + return sceneExplorerTopComponent; } logger.warning( "There seem to be multiple components with the '" + PREFERRED_ID @@ -216,27 +222,20 @@ public void componentClosed() { SceneApplication.getApplication().removeSceneListener(this); // TODO add custom code on component closing } - + void writeProperties(java.util.Properties p) { - // better to version settings since initial version as advocated at - // http://wiki.apidesign.org/wiki/PropertyFiles + // Required. Do not remove. p.setProperty("version", "1.0"); - // TODO store your settings } - + Object readProperties(java.util.Properties p) { + // Required. Do not remove. if (instance == null) { instance = this; } - instance.readPropertiesImpl(p); return instance; } - private void readPropertiesImpl(java.util.Properties p) { - String version = p.getProperty("version"); - // TODO read your settings according to their version - } - @Override protected String preferredID() { return PREFERRED_ID; @@ -246,46 +245,32 @@ protected String preferredID() { public UndoRedo getUndoRedo() { return Lookup.getDefault().lookup(UndoRedo.class); } - private transient ExplorerManager explorerManager = new ExplorerManager(); @Override public ExplorerManager getExplorerManager() { return explorerManager; } - public void setSelectedNode(AbstractSceneExplorerNode node) { - selectedSpatial = node; - if (node != null) { - lastSelected = node; + public void setSelectedNode(AbstractSceneExplorerNode[] nodes) { + selectedSpatials = nodes; + if (nodes != null) { + lastSelected = nodes; } try { - if (node != null) { - explorerManager.setSelectedNodes(new Node[]{node}); -// setActivatedNodes(new Node[]{node}); + if (nodes != null) { + explorerManager.setSelectedNodes(nodes); } else { explorerManager.setSelectedNodes(new Node[]{}); -// setActivatedNodes(new Node[]{}); } - } catch (Exception ex) { + } catch (PropertyVetoException ex) { Exceptions.printStackTrace(ex); } } -// public void resultChanged(LookupEvent ev) { -// Collection collection = nodeSelectionResult.allInstances(); -// for (Iterator it = collection.iterator(); it.hasNext();) { -// Object object = it.next(); -// if (object instanceof AbstractSceneExplorerNode) { -// return; -// } -// } -// selectedSpatial = null; -// } @Override public void sceneOpened(SceneRequest request) { final JmeNode node = request.getJmeNode(); - for (Iterator it = materialChangeProviders.values().iterator(); it.hasNext();) { - MaterialChangeProvider provider = (MaterialChangeProvider) it.next(); + for (MaterialChangeProvider provider : materialChangeProviders.values()) { provider.clearMaterialChangeListeners(); } if (node != null) { @@ -310,11 +295,11 @@ public void sceneClosed(SceneRequest request) { @Override public void previewCreated(PreviewRequest request) { } - + /** * @return the selectedSpatial */ - public AbstractSceneExplorerNode getLastSelected() { + public AbstractSceneExplorerNode[] getLastSelected() { return lastSelected; } @@ -339,7 +324,7 @@ public void addMaterialChangeListener(MaterialChangeListener listener) { logger.log(Level.FINE, "New material listener for : {0}", listener.getKey()); List listeners = materialChangeListeners.get(listener.getKey()); if (listeners == null) { - listeners = new ArrayList(); + listeners = new ArrayList<>(); materialChangeListeners.put(listener.getKey(), listeners); } listeners.add(listener); @@ -383,7 +368,7 @@ public void swapMaterialChangeListener(MaterialChangeListener listener, String o // assert newKey.equals(listener.getKey()); List listeners = materialChangeListeners.get(newKey); if (listeners == null) { - listeners = new ArrayList(); + listeners = new ArrayList<>(); materialChangeListeners.put(newKey, listeners); } listeners.add(listener); @@ -397,6 +382,7 @@ public void swapMaterialChangeListener(MaterialChangeListener listener, String o /** * Terrain has a LOD control that requires the camera to function. + * @param jmeRootNode */ protected void setTerrainLodCamera(JmeNode jmeRootNode) { Camera camera = SceneApplication.getApplication().getCamera(); diff --git a/jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/MotionPathPopup.java b/jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/MotionPathPopup.java index acf105080..3c8b60fbc 100644 --- a/jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/MotionPathPopup.java +++ b/jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/actions/MotionPathPopup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2010 jMonkeyEngine + * Copyright (c) 2009-2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -107,14 +107,20 @@ public void actionPerformed(ActionEvent e) { Vector3f pos; SceneToolController controller = SceneApplication.getApplication().getStateManager().getState(SceneToolController.class); - if (controller != null && (!controller.getCursorLocation().equals(Vector3f.ZERO))) { // Vector3f.ZERO means not yet clicked + // Vector3f.ZERO means not yet clicked + if (controller != null && (!controller.getCursorLocation().equals(Vector3f.ZERO))) { pos = controller.getCursorLocation().clone().addLocal(0, jmeMotionPath.getDebugBoxExtents() * 3f, 0); // Shifting up so a) Netbeans isn't merging Waypoints and b) it's visible } else { - AbstractSceneExplorerNode node = SceneExplorerTopComponent.findInstance().getLastSelected(); - if (node instanceof JmeVector3f) { // null instanceof JmeVector3f == false - pos = ((JmeVector3f)node).getVector3f().clone().addLocal(0, jmeMotionPath.getDebugBoxExtents() * 3f, 0); + AbstractSceneExplorerNode[] nodes = SceneExplorerTopComponent.findInstance().getLastSelected(); + if(nodes == null || nodes.length == 0) { + return; + } + final AbstractSceneExplorerNode node = nodes[0]; + if (node instanceof JmeVector3f jmeVector3f) { + pos = jmeVector3f.getVector3f().clone().addLocal(0, jmeMotionPath.getDebugBoxExtents() * 3f, 0); } else { - pos = new Vector3f(0f, 1.0f, 0f); // Default is a bit over the Center + // Default is a bit over the Center + pos = new Vector3f(0f, 1.0f, 0f); } } diff --git a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java index 1b827c890..5a5a152c6 100644 --- a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java +++ b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2023 jMonkeyEngine + * Copyright (c) 2009-2024 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1078,11 +1078,10 @@ private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRS // End of variables declaration//GEN-END:variables private void emit(Spatial root) { - if (root instanceof ParticleEmitter) { - ((ParticleEmitter) root).killAllParticles(); - ((ParticleEmitter) root).emitAllParticles(); - } else if (root instanceof Node) { - Node n = (Node) root; + if (root instanceof ParticleEmitter particleEmitter) { + particleEmitter.killAllParticles(); + particleEmitter.emitAllParticles(); + } else if (root instanceof Node n) { for (Spatial child : n.getChildren()) { emit(child); } @@ -1112,14 +1111,14 @@ public static synchronized SceneComposerTopComponent getDefault() { * @return */ public static synchronized SceneComposerTopComponent findInstance() { - TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID); - if (win == null) { + TopComponent window = WindowManager.getDefault().findTopComponent(PREFERRED_ID); + if (window == null) { Logger.getLogger(SceneComposerTopComponent.class.getName()).warning( "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); return getDefault(); } - if (win instanceof SceneComposerTopComponent) { - return (SceneComposerTopComponent) win; + if (window instanceof SceneComposerTopComponent sceneComposerTopComponent) { + return sceneComposerTopComponent; } Logger.getLogger(SceneComposerTopComponent.class.getName()).warning( "There seem to be multiple components with the '" + PREFERRED_ID @@ -1203,15 +1202,11 @@ protected String preferredID() { } private void setSelectedObjectText(final String text) { - java.awt.EventQueue.invokeLater(new Runnable() { - - @Override - public void run() { - if (text != null) { - ((TitledBorder) jPanel4.getBorder()).setTitle("Utilities - " + text); - } else { - ((TitledBorder) jPanel4.getBorder()).setTitle("Utilities - no spatial selected"); - } + java.awt.EventQueue.invokeLater(() -> { + if (text != null) { + ((TitledBorder) jPanel4.getBorder()).setTitle("Utilities - " + text); + } else { + ((TitledBorder) jPanel4.getBorder()).setTitle("Utilities - no spatial selected"); } }); } @@ -1255,15 +1250,15 @@ private void setSceneInfo(final JmeNode jmeNode, final FileObject file, final bo } } - public void openScene(Spatial spat, AssetDataObject file, ProjectAssetManager manager) { + public void openScene(Spatial spatial, AssetDataObject file, ProjectAssetManager manager) { cleanupControllers(); SceneApplication.getApplication().addSceneListener(this); Node node; - if (spat instanceof Node) { - node = (Node) spat; + if (spatial instanceof Node node1) { + node = node1; } else { node = new Node(); - node.attachChild(spat); + node.attachChild(spatial); } JmeNode jmeNode = NodeUtility.createNode(node, file, false); SceneRequest request = new SceneRequest(this, jmeNode, manager); @@ -1318,28 +1313,27 @@ public void resultChanged(LookupEvent ev) { return; } Collection items = (Collection) result.allInstances(); - for (AbstractSceneExplorerNode node : items) { - if (select(node)) { - return; - } - } + + AbstractSceneExplorerNode[] abstractNodes = new AbstractSceneExplorerNode[items.size()]; + SceneViewerTopComponent.findInstance().setActivatedNodes(items.toArray(org.openide.nodes.Node[]::new)); + items.toArray(abstractNodes); + select(abstractNodes); } - private boolean select(AbstractSceneExplorerNode node) { + private boolean select(AbstractSceneExplorerNode[] nodes) { + AbstractSceneExplorerNode first = nodes[0]; if (editorController != null) { - editorController.setSelectedExplorerNode(node); + editorController.setSelectedExplorerNode(first); } - if (node instanceof JmeSpatial) { - selectSpatial(((JmeSpatial) node).getLookup().lookup(Spatial.class)); - SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{node}); - SceneExplorerTopComponent.findInstance().setSelectedNode(node); + if (first instanceof JmeSpatial jmeSpatial) { + selectSpatial(jmeSpatial.getLookup().lookup(Spatial.class)); + SceneExplorerTopComponent.findInstance().setSelectedNode(nodes); return true; } else if (toolController != null) { - Spatial selectedGizmo = toolController.getMarker(node); + Spatial selectedGizmo = toolController.getMarker(first); if (selectedGizmo != null) { selectSpatial(selectedGizmo); - SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{node}); - SceneExplorerTopComponent.findInstance().setSelectedNode(node); + SceneExplorerTopComponent.findInstance().setSelectedNode(nodes); return true; } } @@ -1356,8 +1350,8 @@ private void selectSpatial(Spatial selection) { } else if (toolController != null) { toolController.updateSelection(selection); } - if (selection instanceof Node) { - setSelectedObjectText(((Node) selection).getName()); + if (selection instanceof Node node) { + setSelectedObjectText(node.getName()); } else if (selection instanceof Spatial) { setSelectedObjectText(selection.getName()); } else { @@ -1423,57 +1417,53 @@ public void sceneOpened(SceneRequest request) { editorController.setTerrainLodCamera(); final SpatialAssetDataObject dobj = ((SpatialAssetDataObject) currentRequest.getDataObject()); - listener = new ProjectAssetManager.ClassPathChangeListener() { - - @Override - public void classPathChanged(final ProjectAssetManager manager) { - if (dobj.isModified()) { - Confirmation msg = new NotifyDescriptor.Confirmation( - "Classes have been changed, save and reload scene?", - NotifyDescriptor.OK_CANCEL_OPTION, - NotifyDescriptor.INFORMATION_MESSAGE); - Object result = DialogDisplayer.getDefault().notify(msg); - if (!NotifyDescriptor.OK_OPTION.equals(result)) { - return; - } - try { - dobj.saveAsset(); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } + listener = (final ProjectAssetManager manager) -> { + if (dobj.isModified()) { + Confirmation msg = new NotifyDescriptor.Confirmation( + "Classes have been changed, save and reload scene?", + NotifyDescriptor.OK_CANCEL_OPTION, + NotifyDescriptor.INFORMATION_MESSAGE); + Object result1 = DialogDisplayer.getDefault().notify(msg); + if (!NotifyDescriptor.OK_OPTION.equals(result1)) { + return; + } + try { + dobj.saveAsset(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); } - Runnable call = new Runnable() { - - @Override - public void run() { - ProgressHandle progressHandle = ProgressHandle.createHandle("Reloading Scene.."); - progressHandle.start(); - try { - manager.clearCache(); - final Spatial asset = dobj.loadAsset(); - if (asset != null) { - java.awt.EventQueue.invokeLater(new Runnable() { - - @Override - public void run() { - SceneComposerTopComponent composer = SceneComposerTopComponent.findInstance(); - composer.openScene(asset, dobj, manager); - } - }); - } else { - Confirmation msg = new NotifyDescriptor.Confirmation( - "Error opening " + dobj.getPrimaryFile().getNameExt(), - NotifyDescriptor.OK_CANCEL_OPTION, - NotifyDescriptor.ERROR_MESSAGE); - DialogDisplayer.getDefault().notify(msg); - } - } finally { - progressHandle.finish(); + } + Runnable call = new Runnable() { + + @Override + public void run() { + ProgressHandle progressHandle = ProgressHandle.createHandle("Reloading Scene.."); + progressHandle.start(); + try { + manager.clearCache(); + final Spatial asset = dobj.loadAsset(); + if (asset != null) { + java.awt.EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + SceneComposerTopComponent composer = SceneComposerTopComponent.findInstance(); + composer.openScene(asset, dobj, manager); + } + }); + } else { + Confirmation msg = new NotifyDescriptor.Confirmation( + "Error opening " + dobj.getPrimaryFile().getNameExt(), + NotifyDescriptor.OK_CANCEL_OPTION, + NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notify(msg); } + } finally { + progressHandle.finish(); } - }; - new Thread(call).start(); - } + } + }; + new Thread(call).start(); }; // currentRequest.getManager().addClassPathEventListener(listener); } diff --git a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java index 4f435f3bf..64510788b 100644 --- a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java +++ b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java @@ -1,10 +1,38 @@ /* - * To change this template, choose Tools | Templates and open the template in - * the editor. + * Copyright (c) 2009-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.scenecomposer.tools; import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; +import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode; import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; @@ -98,7 +126,7 @@ private void doSelect() { JmeSpatial n = rootNode.getChild(selec); if (n != null) { SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{n}); - SceneExplorerTopComponent.findInstance().setSelectedNode(n); + SceneExplorerTopComponent.findInstance().setSelectedNode(new AbstractSceneExplorerNode[]{n}); } } }); diff --git a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java index 2f910a0f5..b0a6d3592 100644 --- a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java +++ b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/shortcuts/DuplicateShortcut.java @@ -1,12 +1,39 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Copyright (c) 2009-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.scenecomposer.tools.shortcuts; import com.jme3.asset.AssetManager; import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent; +import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode; import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; import com.jme3.gde.core.sceneviewer.SceneViewerTopComponent; import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; @@ -57,7 +84,11 @@ public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Sp private void duplicate() { Spatial selected = toolController.getSelectedSpatial(); - + + if(selected == null) { + return; + } + Spatial clone = selected.clone(); clone.move(1, 0, 1); @@ -67,28 +98,17 @@ private void duplicate() { final Spatial cloned = clone; final JmeNode rootNode = toolController.getRootNode(); refreshSelected(rootNode, selected.getParent()); - - java.awt.EventQueue.invokeLater(new Runnable() { - - @Override - public void run() { - if (cloned != null) { - SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)}); - SceneExplorerTopComponent.findInstance().setSelectedNode(rootNode.getChild(cloned)); - } - } + + java.awt.EventQueue.invokeLater(() -> { + SceneViewerTopComponent.findInstance().setActivatedNodes(new org.openide.nodes.Node[]{rootNode.getChild(cloned)}); + SceneExplorerTopComponent.findInstance().setSelectedNode(new AbstractSceneExplorerNode[]{rootNode.getChild(cloned)}); }); - toolController.updateSelection(selected); } private void refreshSelected(final JmeNode jmeRootNode, final Node parent) { - java.awt.EventQueue.invokeLater(new Runnable() { - - @Override - public void run() { - jmeRootNode.getChild(parent).refresh(false); - } + java.awt.EventQueue.invokeLater(() -> { + jmeRootNode.getChild(parent).refresh(false); }); } @@ -119,8 +139,8 @@ public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode root private class DuplicateUndo extends AbstractUndoableSceneEdit { - private Spatial spatial; - private Node parent; + private final Spatial spatial; + private final Node parent; DuplicateUndo(Spatial spatial, Node parent) { this.spatial = spatial; From b725941478b145ff4aae5fd33433e085539e5e25 Mon Sep 17 00:00:00 2001 From: rickard Date: Sun, 29 Dec 2024 20:14:58 +0100 Subject: [PATCH 2/3] fix merge conflicts --- .../jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java b/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java index e79cc79dc..682200564 100644 --- a/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java +++ b/jme3-core/src/com/jme3/gde/core/sceneexplorer/SceneExplorerTopComponent.java @@ -31,6 +31,7 @@ */ package com.jme3.gde.core.sceneexplorer; +import com.jme3.gde.core.assets.RefreshJmeSpatial; import com.jme3.gde.core.icons.IconList; import com.jme3.gde.core.scene.PreviewRequest; import com.jme3.gde.core.scene.SceneApplication; @@ -48,6 +49,7 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.SwingUtilities; import org.netbeans.api.settings.ConvertAsProperties; import org.openide.actions.CopyAction; import org.openide.actions.CutAction; From 10918e2ce7b2810b550dea05d57c7f50ecde4f13 Mon Sep 17 00:00:00 2001 From: rickard Date: Tue, 31 Dec 2024 09:48:21 +0100 Subject: [PATCH 3/3] check if selected nodes is empty --- .../com/jme3/gde/scenecomposer/SceneComposerTopComponent.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java index 5a5a152c6..2f9a021b6 100644 --- a/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java +++ b/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java @@ -1321,6 +1321,9 @@ public void resultChanged(LookupEvent ev) { } private boolean select(AbstractSceneExplorerNode[] nodes) { + if( nodes.length == 0) { + return false; + } AbstractSceneExplorerNode first = nodes[0]; if (editorController != null) { editorController.setSelectedExplorerNode(first);