Skip to content

Commit

Permalink
privatized Registry.scene and added listener.
Browse files Browse the repository at this point in the history
  • Loading branch information
i-make-robots committed Dec 18, 2023
1 parent d9484ab commit 69e8d53
Show file tree
Hide file tree
Showing 12 changed files with 246 additions and 17 deletions.
25 changes: 24 additions & 1 deletion src/main/java/com/marginallyclever/ro3/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import com.marginallyclever.ro3.render.renderpasses.DrawPoses;
import com.marginallyclever.ro3.texture.TextureFactory;

import javax.swing.event.EventListenerList;

/**
* {@link Registry} is a place to store global variables.
*/
Expand All @@ -18,8 +20,9 @@ public class Registry {
public static final Factory<Node> nodeFactory = new Factory<>(Node.class);
public static ListWithEvents<RenderPass> renderPasses = new ListWithEvents<>();

public static Node scene = new Node("Scene");
private static Node scene = new Node("Scene");
public static ListWithEvents<Camera> cameras = new ListWithEvents<>();
public static EventListenerList listeners = new EventListenerList();

public static void start() {
Factory.Category<Node> nodule = new Factory.Category<>("Node", null);
Expand All @@ -38,4 +41,24 @@ public static void start() {
renderPasses.add(new DrawPoses());
renderPasses.add(new DrawCameras());
}

public static void addSceneChangeListener(SceneChangeListener listener) {
listeners.add(SceneChangeListener.class,listener);
}

public static void removeSceneChangeListener(SceneChangeListener listener) {
listeners.remove(SceneChangeListener.class,listener);
}

public static void setScene(Node newScene) {
scene = newScene;

for (SceneChangeListener listener : listeners.getListeners(SceneChangeListener.class)) {
listener.afterSceneChange(newScene);
}
}

public static Node getScene() {
return scene;
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/marginallyclever/ro3/SceneChangeListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.marginallyclever.ro3;

import com.marginallyclever.ro3.node.Node;

import java.util.EventListener;

public interface SceneChangeListener extends EventListener {
void beforeSceneChange(Node oldScene);
void afterSceneChange(Node newScene);
}
62 changes: 62 additions & 0 deletions src/main/java/com/marginallyclever/ro3/actions/ImportScene.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.marginallyclever.ro3.actions;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.robotoverlord.RobotOverlord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;

/**
* Load a Scene into the existing Scene.
*/
public class ImportScene extends AbstractAction {
private static final JFileChooser chooser = new JFileChooser();
private static final Logger logger = LoggerFactory.getLogger(ImportScene.class);

public ImportScene() {
super("Import Scene");
}

/**
* Invoked when an action occurs.
*
* @param e the event to be processed
*/
@Override
public void actionPerformed(ActionEvent e) {
chooser.setFileFilter(RobotOverlord.FILE_FILTER);

Component source = (Component) e.getSource();
JFrame parentFrame = (JFrame)SwingUtilities.getWindowAncestor(source);
if (chooser.showOpenDialog(parentFrame) == JFileChooser.APPROVE_OPTION) {
loadIntoScene(chooser.getSelectedFile());
}
}

private void loadIntoScene(File selectedFile) {
logger.info("Import scene from {}",selectedFile.getAbsolutePath());

// Create an ObjectMapper instance
ObjectMapper mapper = new ObjectMapper();

try {
// Read the JSON file and convert it into a Node object
Node loaded = mapper.readValue(selectedFile, Node.class);

// option 1: add the loaded scene to the current scene.
Registry.getScene().addChild(loaded);
// TODO option 2: copy the loaded scene into the currently selected Nodes of the NodeTreeView?
} catch (IOException e) {
logger.error("Error loading scene from JSON", e);
}

logger.error("Import scene not implemented yet.");
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/marginallyclever/ro3/actions/LoadScene.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.marginallyclever.ro3.actions;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.robotoverlord.RobotOverlord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -8,6 +11,7 @@
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;

public class LoadScene extends AbstractAction {
private static final JFileChooser chooser = new JFileChooser();
Expand Down Expand Up @@ -36,5 +40,18 @@ public void actionPerformed(ActionEvent e) {
private void loadAsNewScene(File selectedFile) {
logger.info("Load scene from {}",selectedFile.getAbsolutePath());
logger.error("Load Scene not implemented yet.");

// Create an ObjectMapper instance
ObjectMapper mapper = new ObjectMapper();

try {
// Read the JSON file and convert it into a Node object
Node loaded = mapper.readValue(selectedFile, Node.class);
Registry.setScene(loaded);
} catch (IOException e) {
logger.error("Error loading scene from JSON", e);
}

logger.info("done.");
}
}
17 changes: 16 additions & 1 deletion src/main/java/com/marginallyclever/ro3/actions/NewScene.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.marginallyclever.ro3.actions;

import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

public class NewScene extends AbstractAction {
private static final Logger logger = LoggerFactory.getLogger(NewScene.class);
Expand All @@ -20,6 +24,17 @@ public NewScene() {
*/
@Override
public void actionPerformed(ActionEvent e) {
logger.error("New Scene not implemented yet.");
logger.info("New scene");

// remove all children of the scene to make sure we're starting fresh.
Node oldScene = Registry.getScene();
List<Node> children = new ArrayList<>(oldScene.getChildren());
for(Node child : children) {
oldScene.removeChild(child);
}
// remove the scene and replace it completely.
Registry.setScene(new Node("Scene"));

logger.info("done.");
}
}
16 changes: 15 additions & 1 deletion src/main/java/com/marginallyclever/ro3/actions/SaveScene.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.marginallyclever.ro3.actions;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.robotoverlord.RobotOverlord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -8,6 +10,7 @@
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;

public class SaveScene extends AbstractAction {
private static final JFileChooser chooser = new JFileChooser();
Expand Down Expand Up @@ -49,6 +52,17 @@ public void actionPerformed(ActionEvent e) {

private void saveScene(String absolutePath) {
logger.info("Save scene to {}",absolutePath);
logger.error("Save Scene not implemented yet.");

// Create an ObjectMapper instance
ObjectMapper mapper = new ObjectMapper();

try {
// Write the Registry.scene to a JSON file
mapper.writeValue(new File(absolutePath), Registry.getScene());
} catch (IOException e) {
logger.error("Error saving scene to JSON", e);
}

logger.info("done.");
}
}
64 changes: 63 additions & 1 deletion src/main/java/com/marginallyclever/ro3/node/Node.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.marginallyclever.ro3.node;

import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.nodes.Pose;
import com.marginallyclever.robotoverlord.swing.CollapsiblePanel;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.event.EventListenerList;
Expand All @@ -15,10 +19,11 @@
* A node in a tree.
*/
public class Node {
private static final Logger logger = LoggerFactory.getLogger(Node.class);
private String name;
private final List<Node> children = new ArrayList<>();
private Node parent;
private final UUID nodeID;
private UUID nodeID;
private final EventListenerList listeners = new EventListenerList();

public Node() {
Expand Down Expand Up @@ -301,13 +306,26 @@ public boolean isNameUsedBySibling(String newName) {
return false;
}

/**
* A convenience method to add a label and component to a panel that is expected to be built with
* <code>new GridLayout(0, 2)</code>.
* @param pane the panel to add to
* @param labelText the text for the label
* @param component the component to add
*/
protected void addLabelAndComponent(JPanel pane, String labelText, JComponent component) {
JLabel label = new JLabel(labelText);
label.setLabelFor(component);
pane.add(label);
pane.add(component);
}

/**
* Find the first child of the given type.
* @param type the type of node to find
* @return the first sibling of the given type, or null if none found.
* @param <T> the type of node to find
*/
public <T extends Node> T findFirstChild(Class<T> type) {
for(Node child : children) {
if(type.isInstance(child)) {
Expand All @@ -317,6 +335,12 @@ public <T extends Node> T findFirstChild(Class<T> type) {
return null;
}

/**
* Find the first sibling of the given type.
* @param type the type of node to find
* @return the first sibling of the given type, or null if none found.
* @param <T> the type of node to find
*/
public <T extends Node> T findFirstSibling(Class<T> type) {
if(parent==null) return null;
for(Node child : parent.children) {
Expand All @@ -326,4 +350,42 @@ public <T extends Node> T findFirstSibling(Class<T> type) {
}
return null;
}

/**
* Serialize this node and its children to a JSON object and its children.
* Classes that override this method should call super.toJSON() first, then add to the object returned.
* @return the JSON object.
*/
public JSONObject toJSON() {
logger.info("Saving node {}.",getAbsolutePath());
JSONObject json = new JSONObject();
json.put("type",getClass().getSimpleName());
json.put("name",name);
json.put("nodeID",nodeID.toString());
json.put("children",children);
return json;
}

/**
* Deserialize this node and its children from a JSON object and its children.
* Classes that override this method should call super.fromJSON(). When they do it will trigger the creation of
* child nodes. The child nodes will then call their own fromJSON() methods.
* @param from the JSON object to read from.
*/
public void fromJSON(JSONObject from) {
name = from.getString("name");
logger.info("Loading node {}.",name);
nodeID = UUID.fromString(from.getString("nodeID"));
children.clear();
for (Object o : from.getJSONArray("children")) {
JSONObject child = (JSONObject) o;
Node n = Registry.nodeFactory.create(child.getString("type"));
if(n==null) {
logger.error("{}: Could not create type {}.",getAbsolutePath(),child.getString("type"));
n = new Node();
}
n.fromJSON(child);
addChild(n);
}
}
}
Loading

0 comments on commit 69e8d53

Please sign in to comment.