diff --git a/src/main/java/com/marginallyclever/ro3/SceneChangeListener.java b/src/main/java/com/marginallyclever/ro3/SceneChangeListener.java
index 80285554b..a8467edd4 100644
--- a/src/main/java/com/marginallyclever/ro3/SceneChangeListener.java
+++ b/src/main/java/com/marginallyclever/ro3/SceneChangeListener.java
@@ -4,7 +4,19 @@
import java.util.EventListener;
+/**
+ * A listener for scene changes.
+ */
public interface SceneChangeListener extends EventListener {
+ /**
+ * Called before the scene changes. This is a good time to unregister listeners.
+ * @param oldScene the scene that is about to be replaced.
+ */
void beforeSceneChange(Node oldScene);
+
+ /**
+ * Called after the scene changes. This is a good time to register listeners.
+ * @param newScene the scene that has just been added.
+ */
void afterSceneChange(Node newScene);
}
diff --git a/src/main/java/com/marginallyclever/ro3/apps/App.java b/src/main/java/com/marginallyclever/ro3/apps/App.java
index 90e5f7e78..432412395 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/App.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/App.java
@@ -4,7 +4,7 @@
import java.awt.*;
/**
- * Marker interface for all apps.
+ * All apps extend from App for Reflection.
*/
public class App extends JPanel {
public App() {
diff --git a/src/main/java/com/marginallyclever/ro3/apps/DockingPanel.java b/src/main/java/com/marginallyclever/ro3/apps/DockingPanel.java
index 43213efa2..78dc8af5c 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/DockingPanel.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/DockingPanel.java
@@ -30,6 +30,11 @@ public String getTabText() {
return tabText;
}
+ /**
+ * Refuse to wrap this {@link DockingPanel} in a {@link JScrollPane}. The panel is responsibile for scrolling,
+ * not the docking system.
+ * @return false
+ */
@Override
public boolean isWrappableInScrollpane() {
return false;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/FactoryPanel.java b/src/main/java/com/marginallyclever/ro3/apps/FactoryPanel.java
index 8f40a8e7f..a18d813b9 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/FactoryPanel.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/FactoryPanel.java
@@ -1,13 +1,11 @@
package com.marginallyclever.ro3.apps;
import com.marginallyclever.ro3.Factory;
-import com.marginallyclever.ro3.apps.nodetreeview.NodeTreeBranch;
import com.marginallyclever.ro3.apps.shared.SearchBar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
-import javax.swing.border.Border;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
@@ -136,7 +134,7 @@ private void addAllParents(List> matches) {
* @return a list of all categories that match the search criteria
*/
private List> findAllTypesMatching(Factory.Category root, String searchCriteria) {
- boolean isRegex = searchBar.isRegex();
+ boolean isRegex = searchBar.getRegex();
List> matches = new ArrayList<>();
List> toSearch = new ArrayList<>();
toSearch.add(root);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java b/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java
index 52ce6c77a..637571b9b 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java
@@ -12,7 +12,6 @@
import com.marginallyclever.communications.application.TextInterfaceToSessionLayer;
import com.marginallyclever.convenience.helpers.FileHelper;
import com.marginallyclever.ro3.RO3;
-import com.marginallyclever.ro3.UndoSystem;
import com.marginallyclever.ro3.apps.about.AboutPanel;
import com.marginallyclever.ro3.apps.actions.*;
import com.marginallyclever.ro3.apps.editorpanel.EditorPanel;
@@ -43,6 +42,10 @@
import java.util.Properties;
import java.util.prefs.Preferences;
+/**
+ * {@link RO3Frame} is the main frame for the Robot Overlord 3 application. It contains the menu bar and docking
+ * panels. It also maintains one instance of each {@link App}.
+ */
public class RO3Frame extends JFrame {
private static final Logger logger = LoggerFactory.getLogger(RO3Frame.class);
private final List windows = new ArrayList<>();
diff --git a/src/main/java/com/marginallyclever/ro3/apps/RO3FrameDropTarget.java b/src/main/java/com/marginallyclever/ro3/apps/RO3FrameDropTarget.java
index e692803bc..12fc3fd22 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/RO3FrameDropTarget.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/RO3FrameDropTarget.java
@@ -7,7 +7,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.swing.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
@@ -17,7 +16,8 @@
import java.util.List;
/**
- * Allows the user to drop Scenes and Meshes onto the main window. They will be imported to the existing scene.
+ * Allows the user to drop Scene or a supported mesh file onto the main window. They will be
+ * imported to the existing scene and appear at the world origin.
*/
public class RO3FrameDropTarget extends DropTargetAdapter {
private static final Logger logger = LoggerFactory.getLogger(RO3FrameDropTarget.class);
@@ -32,30 +32,32 @@ public void drop(DropTargetDropEvent event) {
try {
Transferable tr = event.getTransferable();
DataFlavor[] flavors = tr.getTransferDataFlavors();
+ int complete = 0;
for (DataFlavor flavor : flavors) {
logger.debug("Possible flavor: {}", flavor.getMimeType());
if (flavor.isFlavorJavaFileListType()) {
event.acceptDrop(DnDConstants.ACTION_COPY);
Object object = tr.getTransferData(flavor);
if (object instanceof List> list) {
- if (!list.isEmpty()) {
- object = list.get(0);
- if (object instanceof File file) {
- // drop a mesh
+ for(Object item : list) {
+ if (item instanceof File file) {
if(importMesh(file.getAbsolutePath())) {
- event.dropComplete(true);
- return;
- }
- // drop a scene
- if(importScene(file)) {
- event.dropComplete(true);
- return;
- }
+ // drop a mesh
+ complete++;
+ } else if(importScene(file)) {
+ // drop a scene
+ complete++;
+ } // else silently ignore
}
}
}
}
}
+ if(complete>0) {
+ logger.debug("Drop ok: {}", complete);
+ event.dropComplete(true);
+ return;
+ }
logger.debug("Drop failed: {}", event);
event.rejectDrop();
} catch (Exception e) {
diff --git a/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java b/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java
index bd9e38081..ff03dc03f 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java
@@ -11,7 +11,7 @@
import java.util.prefs.Preferences;
/**
- * A menu that keeps track of recently loaded files.
+ * {@link RecentFilesMenu} is a menu that keeps track of recently loaded files.
*/
public class RecentFilesMenu extends JMenu {
private static final Logger logger = LoggerFactory.getLogger(RecentFilesMenu.class);
diff --git a/src/main/java/com/marginallyclever/ro3/UndoSystem.java b/src/main/java/com/marginallyclever/ro3/apps/UndoSystem.java
similarity index 87%
rename from src/main/java/com/marginallyclever/ro3/UndoSystem.java
rename to src/main/java/com/marginallyclever/ro3/apps/UndoSystem.java
index 1efc9290c..b594da06b 100644
--- a/src/main/java/com/marginallyclever/ro3/UndoSystem.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/UndoSystem.java
@@ -1,4 +1,4 @@
-package com.marginallyclever.ro3;
+package com.marginallyclever.ro3.apps;
import com.marginallyclever.ro3.apps.actions.RedoAction;
import com.marginallyclever.ro3.apps.actions.UndoAction;
@@ -7,8 +7,7 @@
import javax.swing.undo.UndoManager;
/**
- * A singleton to manage undo/redo actions.
- * @author Dan Royer
+ * {@link UndoSystem} is a singleton to manage the undo/redo history and associated {@link javax.swing.AbstractAction}s.
*/
public class UndoSystem {
private static final UndoManager undoManager = new UndoManager();
diff --git a/src/main/java/com/marginallyclever/ro3/apps/about/AboutPanel.java b/src/main/java/com/marginallyclever/ro3/apps/about/AboutPanel.java
index 76244a866..80a938294 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/about/AboutPanel.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/about/AboutPanel.java
@@ -10,6 +10,9 @@
import java.io.BufferedInputStream;
import java.util.Objects;
+/**
+ * {@link AboutPanel} is a panel that displays the contents of the file "about.html" in the same package.
+ */
public class AboutPanel extends App {
private static final Logger logger = LoggerFactory.getLogger(AboutPanel.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java b/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java
index 5d15561ac..db14342be 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java
@@ -3,7 +3,7 @@
import com.marginallyclever.ro3.apps.FactoryPanel;
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import javax.swing.*;
import java.awt.*;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/CopyNode.java b/src/main/java/com/marginallyclever/ro3/apps/actions/CopyNode.java
index 65181454f..b95988c2c 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/CopyNode.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/CopyNode.java
@@ -1,7 +1,7 @@
package com.marginallyclever.ro3.apps.actions;
import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import javax.swing.*;
import java.awt.event.ActionEvent;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/CutNode.java b/src/main/java/com/marginallyclever/ro3/apps/actions/CutNode.java
index 5506db10a..2d8da0f85 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/CutNode.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/CutNode.java
@@ -1,12 +1,15 @@
package com.marginallyclever.ro3.apps.actions;
import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.Objects;
+/**
+ * {@link CutNode} is an action that cuts the selected node(s) from the scene.
+ */
public class CutNode extends AbstractAction {
public CutNode() {
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java b/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java
index 9f74e9ebb..d214fb2f2 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java
@@ -20,7 +20,7 @@
import java.util.zip.ZipOutputStream;
/**
- * Export the scene and all the assets used to a single file for sharing on another computer.
+ *
Export the scene and all the assets used to a single ZIP file for sharing on another computer.
* This is not the same as saving the scene.
*/
public class ExportScene extends AbstractAction {
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/ImportScene.java b/src/main/java/com/marginallyclever/ro3/apps/actions/ImportScene.java
index 8a3a6090d..dd61be767 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/ImportScene.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/ImportScene.java
@@ -1,25 +1,17 @@
package com.marginallyclever.ro3.apps.actions;
-import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.ro3.apps.RO3Frame;
-import com.marginallyclever.ro3.node.Node;
-import org.json.JSONObject;
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;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.security.InvalidParameterException;
import java.util.Objects;
/**
- * Load a Scene into the existing Scene.
+ * Load a Scene and insert it into the existing Scene.
*/
public class ImportScene extends AbstractAction {
private static final Logger logger = LoggerFactory.getLogger(ImportScene.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/LoadScene.java b/src/main/java/com/marginallyclever/ro3/apps/actions/LoadScene.java
index a4d93624f..228759a2c 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/LoadScene.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/LoadScene.java
@@ -1,11 +1,9 @@
package com.marginallyclever.ro3.apps.actions;
-import com.marginallyclever.convenience.helpers.FileHelper;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.ro3.apps.RecentFilesMenu;
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
-import com.marginallyclever.ro3.texture.TextureFactory;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/NewScene.java b/src/main/java/com/marginallyclever/ro3/apps/actions/NewScene.java
index a315feae0..3f09f5eb7 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/NewScene.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/NewScene.java
@@ -1,7 +1,7 @@
package com.marginallyclever.ro3.apps.actions;
import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.ro3.node.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/PasteNode.java b/src/main/java/com/marginallyclever/ro3/apps/actions/PasteNode.java
index 6bfa72ff9..1ffc60f74 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/PasteNode.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/PasteNode.java
@@ -2,23 +2,20 @@
import com.marginallyclever.convenience.helpers.JSONHelper;
import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
-import com.marginallyclever.ro3.node.Node;
-import org.json.JSONArray;
-import org.json.JSONObject;
+import com.marginallyclever.ro3.apps.UndoSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
-import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Objects;
+/**
+ * {@link PasteNode} is an action that pastes the selected node(s) from the clipboard.
+ */
public class PasteNode extends AbstractAction {
private final Logger logger = LoggerFactory.getLogger(PasteNode.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/RedoAction.java b/src/main/java/com/marginallyclever/ro3/apps/actions/RedoAction.java
index 9fa454183..fdca854ed 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/RedoAction.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/RedoAction.java
@@ -8,7 +8,7 @@
import java.util.Objects;
/**
- * go forward one step in the undo/redo history.
+ * Go forward one step in the undo/redo history.
* @author Dan Royer
*/
public class RedoAction extends AbstractAction {
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/RemoveNode.java b/src/main/java/com/marginallyclever/ro3/apps/actions/RemoveNode.java
index 133f3c546..d50ee119b 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/RemoveNode.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/RemoveNode.java
@@ -1,8 +1,7 @@
package com.marginallyclever.ro3.apps.actions;
import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
-import com.marginallyclever.ro3.apps.nodetreeview.NodeTreeView;
+import com.marginallyclever.ro3.apps.UndoSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,6 +10,9 @@
import java.util.ArrayList;
import java.util.Objects;
+/**
+ * {@link RemoveNode} is an action that removes the selected node(s) from the scene.
+ */
public class RemoveNode extends AbstractAction {
private final Logger logger = LoggerFactory.getLogger(RemoveNode.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/UndoAction.java b/src/main/java/com/marginallyclever/ro3/apps/actions/UndoAction.java
index 066fd4886..cddbee262 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/actions/UndoAction.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/actions/UndoAction.java
@@ -8,7 +8,7 @@
import java.util.Objects;
/**
- * go back one step in the undo/redo history.
+ * Go back one step in the undo/redo history.
* @author Dan Royer
*/
public class UndoAction extends AbstractAction {
diff --git a/src/main/java/com/marginallyclever/ro3/apps/dialogs/NodeSelectionDialog.java b/src/main/java/com/marginallyclever/ro3/apps/dialogs/NodeSelectionDialog.java
index d928682c9..6cc9184be 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/dialogs/NodeSelectionDialog.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/dialogs/NodeSelectionDialog.java
@@ -133,7 +133,7 @@ private void addAllParents(List matches) {
* @return a list of all nodes matching the search criteria
*/
private List findAllNodesMatching(Node rootNode, String searchCriteria) {
- boolean isRegex = searchBar.isRegex();
+ boolean isRegex = searchBar.getRegex();
List matches = new ArrayList<>();
List toSearch = new ArrayList<>();
toSearch.add(rootNode);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/editorpanel/LoadAction.java b/src/main/java/com/marginallyclever/ro3/apps/editorpanel/LoadAction.java
index 823285722..e79de26c1 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/editorpanel/LoadAction.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/editorpanel/LoadAction.java
@@ -13,6 +13,9 @@
import java.security.InvalidParameterException;
import java.util.Objects;
+/**
+ * Load a file into the {@link EditorPanel}
+ */
public class LoadAction extends AbstractAction {
private static final Logger logger = LoggerFactory.getLogger(LoadAction.class);
private final EditorPanel editorPanel;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/editorpanel/NewAction.java b/src/main/java/com/marginallyclever/ro3/apps/editorpanel/NewAction.java
index fb28e7200..2e7b9298c 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/editorpanel/NewAction.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/editorpanel/NewAction.java
@@ -4,6 +4,9 @@
import java.awt.event.ActionEvent;
import java.util.Objects;
+/**
+ * Clear the text area of the {@link EditorPanel}
+ */
public class NewAction extends AbstractAction {
private final EditorPanel editorPanel;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/editorpanel/SaveAction.java b/src/main/java/com/marginallyclever/ro3/apps/editorpanel/SaveAction.java
index 4a896c187..4901c7589 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/editorpanel/SaveAction.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/editorpanel/SaveAction.java
@@ -12,6 +12,9 @@
import java.io.IOException;
import java.util.Objects;
+/**
+ * Save the text area of the {@link EditorPanel} to a file.
+ */
public class SaveAction extends AbstractAction {
private static final Logger logger = LoggerFactory.getLogger(SaveAction.class);
private final EditorPanel editorPanel;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java b/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java
index c5bd2204b..26d9a45f2 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java
@@ -20,8 +20,8 @@
import java.util.*;
/**
- * {@link LogPanel} is a read-only panel that contains the log. It cannot be derived from {@link DockingPanel}
- * because it is created before {@link ModernDocking.app.Docking} is initialized.
+ * {@link LogPanel} is a read-only panel that contains the log and a button to open the log file location in the
+ * OS.
*/
public class LogPanel extends App {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(LogPanel.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java b/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java
index 9366aa00d..d5a14cf10 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java
@@ -14,6 +14,9 @@
import java.util.Iterator;
import java.util.Objects;
+/**
+ * {@link OpenLogFileLocation} is an {@link AbstractAction} that asks the OS to open the folder containing the log file.
+ */
public class OpenLogFileLocation extends AbstractAction {
private final org.slf4j.Logger logger = LoggerFactory.getLogger(OpenLogFileLocation.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeTransferHandler.java b/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeTransferHandler.java
index b517e0bbf..36aa2f555 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeTransferHandler.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeTransferHandler.java
@@ -1,7 +1,7 @@
package com.marginallyclever.ro3.apps.nodetreeview;
import com.marginallyclever.ro3.Registry;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.ro3.apps.commands.MoveNode;
import com.marginallyclever.ro3.node.Node;
import org.slf4j.Logger;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeView.java b/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeView.java
index 7b858a9f4..b66cb9425 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeView.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/nodetreeview/NodeTreeView.java
@@ -24,7 +24,7 @@
import java.util.function.Supplier;
/**
- * {@link NodeTreeView} is a panel that displays the node tree.
+ * {@link NodeTreeView} is a panel that displays the tree of nodes in the {@link Registry} scene.
*/
public class NodeTreeView extends App
implements NodeAttachListener, NodeDetachListener, NodeRenameListener,
diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java b/src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java
index 495b9f01a..9bbb3bda0 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java
@@ -13,7 +13,7 @@
import java.awt.*;
/**
- * {@link OpenGLPanel} is a {@link DockingPanel} that contains a {@link GLJPanel} and an {@link FPSAnimator}.
+ * {@link OpenGLPanel} manages a {@link GLJPanel} and an {@link FPSAnimator}.
*/
public class OpenGLPanel extends App implements GLEventListener, MouseListener, MouseMotionListener, MouseWheelListener {
private static final Logger logger = LoggerFactory.getLogger(OpenGLPanel.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java b/src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java
index eeebc6198..0653c28e0 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java
@@ -4,8 +4,9 @@
import com.marginallyclever.ro3.Registry;
/**
- * Classes which implement {@link RenderPass} are drawn on top of the 3D scene. They should be registered to the
- * {@link Registry}, which remembers the order in which they should be drawn.
+ * Classes which implement {@link RenderPass} are drawn as part of - or on top of - the 3D scene. They should be
+ * registered to the {@link Registry}. The order of registration controls the order in which they are rendered.
+ * They are rendered by the {@link Viewport}.
*/
public interface RenderPass extends GLEventListener {
int NEVER = 0;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/ShaderProgram.java b/src/main/java/com/marginallyclever/ro3/apps/render/ShaderProgram.java
index 732754150..79b0f3144 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/render/ShaderProgram.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/render/ShaderProgram.java
@@ -12,10 +12,8 @@
import java.security.InvalidParameterException;
/**
- * A wrapper for vertex and fragment shader pairs that provides a simple interface for setting uniforms.
- *
- * @author Dan Royer
- * @since 2.5.9
+ * {@link ShaderProgram} is a wrapper for vertex and fragment shader programs. It also provides a simple interface
+ * for setting uniforms.
*/
public class ShaderProgram {
private static final Logger logger = LoggerFactory.getLogger(ShaderProgram.class);
diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawHingeJoints.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawHingeJoints.java
index 0f3b651ce..1cee372df 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawHingeJoints.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawHingeJoints.java
@@ -23,6 +23,10 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * Draw a ring around each hinge joint to show the range of motion.
+ * Draw a line to show the current angle.
+ */
public class DrawHingeJoints extends AbstractRenderPass {
private static final Logger logger = LoggerFactory.getLogger(DrawHingeJoints.class);
private final Mesh currentAngleMesh = new Mesh();
diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/Compass3D.java b/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/Compass3D.java
index 393aa7757..3b6209a6c 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/Compass3D.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/Compass3D.java
@@ -22,6 +22,10 @@
import java.awt.event.MouseEvent;
import java.util.List;
+/**
+ * Draw a compass to show the orientation of the camera. If the user clicks on the handles for the compasss,
+ * orbit the camera to face that world axis.
+ */
public class Compass3D implements ViewportTool {
/**
* The viewport to which this tool is attached.
diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/SelectionTool.java b/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/SelectionTool.java
index 9305c03aa..dae335b31 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/SelectionTool.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/render/viewporttools/SelectionTool.java
@@ -22,6 +22,10 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * A selection tool allows the user to click on the 3D view and change the current {@link Registry#selection}.
+ * TODO add shift+ and ctrl+ modifiers to add/remove from selection.
+ */
public class SelectionTool extends MouseAdapter implements ViewportTool {
private static final Logger logger = LoggerFactory.getLogger(SelectionTool.class);
public static final String PICK_POINT_NAME = "pick point";
diff --git a/src/main/java/com/marginallyclever/ro3/apps/shared/PersistentJFileChooser.java b/src/main/java/com/marginallyclever/ro3/apps/shared/PersistentJFileChooser.java
index f7b76884c..bab5946ae 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/shared/PersistentJFileChooser.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/shared/PersistentJFileChooser.java
@@ -5,6 +5,10 @@
import java.util.prefs.Preferences;
import java.io.File;
+/**
+ * {@link PersistentJFileChooser} is a {@link JFileChooser} that uses {@link Preferences} to remember the last
+ * directory used. All instances share the same memory.
+ */
public class PersistentJFileChooser extends JFileChooser {
private static final String LAST_USED_DIR = "lastUsedDirectory";
private final Preferences prefs;
diff --git a/src/main/java/com/marginallyclever/ro3/apps/shared/SearchBar.java b/src/main/java/com/marginallyclever/ro3/apps/shared/SearchBar.java
index b413dfc9d..f85610380 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/shared/SearchBar.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/shared/SearchBar.java
@@ -7,13 +7,12 @@
import java.util.Objects;
/**
- * SearchBar is a text field with a magnifying glass icon.
- * When the text changes, it fires a property change event for the value "match" with the new text.
- * @since 2.7.0
- * @author Dan Royer
+ * {@link SearchBar} is a text field, a toggle for case-sensitive, and a toggle for regular expressions.
+ * When the text changes, it fires a property change event for the value "match" with the new text.
*/
public class SearchBar extends JPanel implements DocumentListener {
private final JTextField match = new JTextField();
+ private final JToggleButton isCaseSensitive = new JToggleButton("Aa");
private final JToggleButton isRegex = new JToggleButton(".*");
public SearchBar() {
@@ -26,8 +25,11 @@ public SearchBar(String text) {
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
var label = new JLabel(new ImageIcon(Objects.requireNonNull(getClass().getResource("icons8-search-16.png"))));
label.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
- add(label, BorderLayout.LINE_START);
- add(match, BorderLayout.CENTER);
+ JPanel inner = new JPanel(new BorderLayout());
+ inner.add(label, BorderLayout.LINE_START);
+ inner.add(match, BorderLayout.CENTER);
+ inner.add(isCaseSensitive, BorderLayout.LINE_END);
+ add(inner, BorderLayout.CENTER);
add(isRegex, BorderLayout.LINE_END);
match.setText(text);
@@ -54,11 +56,19 @@ public void fireTextChange() {
super.firePropertyChange("match", null, newValue);
}
- public boolean isRegex() {
+ public boolean getRegex() {
return isRegex.isSelected();
}
public void setRegex(boolean regex) {
isRegex.setSelected(regex);
}
+
+ public boolean getCaseSensitive() {
+ return isCaseSensitive.isSelected();
+ }
+
+ public void setCaseSensitive(boolean caseSensitive) {
+ isCaseSensitive.setSelected(caseSensitive);
+ }
}
diff --git a/src/main/java/com/marginallyclever/ro3/apps/webcampanel/WebCamPanel.java b/src/main/java/com/marginallyclever/ro3/apps/webcampanel/WebCamPanel.java
index 7aab8ac7a..beb4bca56 100644
--- a/src/main/java/com/marginallyclever/ro3/apps/webcampanel/WebCamPanel.java
+++ b/src/main/java/com/marginallyclever/ro3/apps/webcampanel/WebCamPanel.java
@@ -15,7 +15,7 @@
import java.util.concurrent.TimeoutException;
/**
- * A panel that displays the default USB web camera.
+ * {@link WebCamPanel} uses {@link Webcam} to display the default USB web camera.
*/
public class WebCamPanel extends App {
private static final Logger logger = LoggerFactory.getLogger(WebCamPanel.class);
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/Mesh.java b/src/main/java/com/marginallyclever/ro3/mesh/Mesh.java
index e839a1c0f..2a2616539 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/Mesh.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/Mesh.java
@@ -18,8 +18,9 @@
import java.util.List;
/**
- * {@link Mesh} contains the vertex, normal, maybe color, and maybe texture data for a 3D model.
- * It uses Vertex Buffer Objects to optimize rendering large collections of triangles.
+ * {@link Mesh} contains the vertex data for a 3D model. It may also contain normal, color, and texture data.
+ * It uses Vertex Array Objects and Vertex
+ * Buffer Objects to optimize rendering large collections of triangles.
* @author Dan Royer
*/
public class Mesh {
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/MeshNormalBuilder.java b/src/main/java/com/marginallyclever/ro3/mesh/MeshNormalBuilder.java
index 1dd63318e..b85cf86c9 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/MeshNormalBuilder.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/MeshNormalBuilder.java
@@ -6,7 +6,7 @@
import javax.vecmath.Vector3d;
/**
- * A tool to build normals for a mesh.
+ * {@link MeshNormalBuilder} is a tool to build normals for a {@link Mesh}.
*
* @author Dan Royer
* @since 1.7.1
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/MeshSmoother.java b/src/main/java/com/marginallyclever/ro3/mesh/MeshSmoother.java
index 1b37aec54..970ebd9ba 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/MeshSmoother.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/MeshSmoother.java
@@ -1,46 +1,16 @@
package com.marginallyclever.ro3.mesh;
-import com.marginallyclever.ro3.mesh.load.MeshFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
import java.util.ArrayList;
/**
- * Smooth STL models and save them back to disk. Meant for one time processing files.
- * @author dan royer
+ * {@link MeshSmoother} will smooth the normals of a {@link Mesh}.
+ * @author Dan Royer
*/
public class MeshSmoother {
private static final Logger logger = LoggerFactory.getLogger(MeshSmoother.class);
- /*
- public static void main(String[] argv) throws IllegalArgumentException, IOException {
- float vertexEpsilon = 0.1f;
- float normalEpsilon = 0.25f;
-
- if( argv.length == 0 ) throw new IllegalArgumentException("not enough parameters");
- if( argv.length % 2 != 0 ) throw new IllegalArgumentException("not enough parameters");
-
- int i;
- for(i=0;i{@link VertexProvider} is an interface for providing vertices and normals to a {@link Mesh}. Historically
+ * this has only been used for {@link com.marginallyclever.convenience.Ray} intersections.
+ */
public interface VertexProvider {
+ /**
+ * Provides a vertex at the given index.
+ * @param index the index of the vertex to provide
+ * @return the vertex at the given index
+ */
Vector3d provideVertex(int index);
+
+ /**
+ * Provides a normal at the given index.
+ * @param index the index of the vertex to provide
+ * @return the vertex at the given index
+ */
Vector3d provideNormal(int index);
+
+ /**
+ * @return the number of vertexes and normals available.
+ */
int provideCount();
}
\ No newline at end of file
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/load/Load3MF.java b/src/main/java/com/marginallyclever/ro3/mesh/load/Load3MF.java
index 941907e90..edb511fbc 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/load/Load3MF.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/load/Load3MF.java
@@ -16,8 +16,8 @@
import java.util.zip.ZipInputStream;
/**
- * https://en.wikipedia.org/wiki/3D_Manufacturing_Format
- * @author Dan Royer
+ * {@link Load3MF} is a {@link MeshLoader} that loads a
+ * 3MF into a {@link Mesh}.
*/
public class Load3MF implements MeshLoader {
private class ColorGroup {
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadAMF.java b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadAMF.java
index 289f79cee..f94e03834 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadAMF.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadAMF.java
@@ -14,9 +14,8 @@
import java.util.ArrayList;
/**
- * Load a 3D printing file (AMF).
- * See Wikipedia.
- *
+ * {@link LoadAMF} is a {@link MeshLoader} that loads an
+ * AMF into a {@link Mesh}.
* @author Dan Royer
* @since 2.5.0
*/
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadOBJ.java b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadOBJ.java
index 8922f7b56..a20049eb0 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadOBJ.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadOBJ.java
@@ -13,7 +13,8 @@
import java.util.ArrayList;
/**
- * Loads OBJ files into a Mesh.
+ * {@link LoadOBJ} is a {@link MeshLoader} that loads a
+ * OBJ files into a {@link Mesh}.
* @author Dan Royer
* @since 1.6.0
*/
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadPLY.java b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadPLY.java
index f3355cca7..f629acbce 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadPLY.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadPLY.java
@@ -9,9 +9,8 @@
import java.nio.charset.StandardCharsets;
/**
- * Load a mesh from a PLY file.
- * see Wikipedia
- *
+ * {@link LoadPLY} is a {@link MeshLoader} that loads a
+ * PLY file into a {@link Mesh}.
* @author Dan Royer
* @since 2.5.0
*/
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadSTL.java b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadSTL.java
index e15856f41..f34007a5d 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/load/LoadSTL.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/load/LoadSTL.java
@@ -13,7 +13,8 @@
/**
- * Loads STL files into a Mesh.
+ * {@link LoadSTL} is a {@link MeshLoader} that loads a
+ * STL files into a {@link Mesh}.
* @author Dan Royer
* @since 1.6.0
*/
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/load/MeshLoader.java b/src/main/java/com/marginallyclever/ro3/mesh/load/MeshLoader.java
index 614c2d27e..a09123ced 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/load/MeshLoader.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/load/MeshLoader.java
@@ -5,7 +5,8 @@
import java.io.BufferedInputStream;
/**
- * {@link MeshLoader} interface for all classes that load a {@link Mesh}. Call upon by {@link MeshFactory}
+ * {@link MeshLoader} interface for all classes that load a {@link Mesh}.
+ * All {@link MeshLoader} should be registered with the {@link MeshFactory}.
* @author Dan Royer
*
*/
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/save/MeshSaver.java b/src/main/java/com/marginallyclever/ro3/mesh/save/MeshSaver.java
index 800d63ab6..00da51f3e 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/save/MeshSaver.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/save/MeshSaver.java
@@ -5,7 +5,7 @@
import java.io.OutputStream;
/**
- * A MeshSaver is a script that saves a mesh to a file.
+ * {@link MeshSaver} saves a {@link Mesh} to a file.
*
* @author Dan Royer
* @since 2.5.0
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/save/SaveSTL.java b/src/main/java/com/marginallyclever/ro3/mesh/save/SaveSTL.java
index f65510a46..1f83c9406 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/save/SaveSTL.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/save/SaveSTL.java
@@ -8,7 +8,7 @@
import java.nio.ByteOrder;
/**
- * Save a mesh as an STL file.
+ * {@link SaveSTL} is a {@link MeshSaver} Save a mesh as an STL file.
*
* @author Dan Royer
* @since 2.5.0
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Box.java b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Box.java
index c3e33ca50..bbd8d5366 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Box.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Box.java
@@ -7,7 +7,7 @@
import javax.vecmath.Vector3d;
/**
- * A box with a width, height, and length of 1. It is centered around the origin.
+ * {@link Box} is a {@link Mesh} with a width, height, and length of 1. It is centered around the origin.
*/
public class Box extends Mesh {
public float width = 1.0f;
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/shapes/CircleXY.java b/src/main/java/com/marginallyclever/ro3/mesh/shapes/CircleXY.java
index 2dbefd604..bfc7d6ea6 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/shapes/CircleXY.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/shapes/CircleXY.java
@@ -3,6 +3,10 @@
import com.jogamp.opengl.GL3;
import com.marginallyclever.ro3.mesh.Mesh;
+/**
+ * {@link CircleXY} is a {@link Mesh} in the XY plane. The first vertex is the center so that it can be
+ * drawn as a triangle fan.
+ */
public class CircleXY extends Mesh {
public CircleXY() {
super();
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Cylinder.java b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Cylinder.java
index 3b5abdb79..9c3d97b5f 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Cylinder.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Cylinder.java
@@ -7,8 +7,8 @@
import javax.vecmath.Vector3d;
/**
- * A cylinder with a radius of 0.5 and a height of 2. It is centered at the
- * origin.
+ * {@link Cylinder} is a {@link Mesh}. It has a diameter of 1 and a height of 1.
+ * The origin is at the center of the cylinder.
*/
public class Cylinder extends Mesh {
public static final int RESOLUTION_CIRCULAR = 32;
@@ -16,7 +16,7 @@ public class Cylinder extends Mesh {
public float radius0 = 0.5f;
public float radius1 = 0.5f;
- public float height = 2;
+ public float height = 1;
public Cylinder() {
this(2, 0.5f, 0.5f);
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Decal.java b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Decal.java
index 8ae53a4f8..b63b1f2c2 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Decal.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Decal.java
@@ -7,7 +7,8 @@
import javax.vecmath.Vector3d;
/**
- * A 1x1 quad texture on both sides. the origin is in the center of the quad.
+ * {@link Decal} is a {@link Mesh}. It is a 1x1 quad texture on both sides. The origin is in the center of the
+ * quad.
* @author Dan Royer
*/
public class Decal extends Mesh {
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Grid.java b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Grid.java
index 9a71ff314..501bf524f 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Grid.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Grid.java
@@ -4,8 +4,7 @@
import com.marginallyclever.ro3.mesh.Mesh;
/**
- * Procedurally draws a grid on a plane. If the material for this Grid has lighting turned off then the
- * grid will be transparent at the edges.
+ * {@link Grid} is a {@link Mesh} displaying a grid on the XY plane. The origin is at the center of the grid.
*
* @author Dan Royer
*/
diff --git a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Sphere.java b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Sphere.java
index 1a15065f9..f941282f9 100644
--- a/src/main/java/com/marginallyclever/ro3/mesh/shapes/Sphere.java
+++ b/src/main/java/com/marginallyclever/ro3/mesh/shapes/Sphere.java
@@ -4,7 +4,7 @@
import com.marginallyclever.ro3.mesh.Mesh;
/**
- * A sphere with a radius of 1 centered around the local origin.
+ * {@link Sphere} is a {@link Mesh} with a radius of 1. The origin is at the center of the sphere.
*/
public class Sphere extends Mesh {
public float radius = 1.0f;
diff --git a/src/main/java/com/marginallyclever/ro3/node/Node.java b/src/main/java/com/marginallyclever/ro3/node/Node.java
index 1575ba9cf..caf727a1d 100644
--- a/src/main/java/com/marginallyclever/ro3/node/Node.java
+++ b/src/main/java/com/marginallyclever/ro3/node/Node.java
@@ -17,7 +17,29 @@
import java.util.UUID;
/**
- * A node in a tree.
+ * {@link Node} is the base class for all nodes in the scene tree.
+ * Each Node can have a parent and multiple children, forming a tree-like structure. This class provides several
+ * functionalities:
+ *
+ * - Nodes have a unique IDs and a name.
+ * - Nodes can be attached or detached from their parents.
+ * - Nodes can be renamed.
+ * - Nodes can be serialized to and from JSON format.
+ * - Nodes can be updated every frame, which is useful for animations or game logic.
+ * - Nodes can be searched by their name or type.
+ * - Nodes can be found by their absolute path in the tree.
+ * - Nodes can be checked if their name is used by a sibling.
+ * - Nodes can be found by their unique ID.
+ * - Nodes can be found by their path, which can be relative or absolute.
+ *
+ * This class also provides several events:
+ *
+ * - {@link NodeAttachListener}: called when a node is attached to a parent.
+ * - {@link NodeDetachListener}: called when a node is detached from a parent.
+ * - {@link NodeReadyListener}: called when a node is attached and all children are ready.
+ * - {@link NodeRenameListener}: called when a node is renamed.
+ *
+ * Nodes can be serialized to and from JSON.
*/
public class Node {
private static final Logger logger = LoggerFactory.getLogger(Node.class);
@@ -25,8 +47,8 @@ public class Node {
private final List children = new ArrayList<>();
private Node parent;
private UUID nodeID;
+
protected final EventListenerList listeners = new EventListenerList();
- public static DataFlavor flavor = new DataFlavor(Node.class, Node.class.getSimpleName());
public Node() {
this("Node");
diff --git a/src/main/java/com/marginallyclever/ro3/node/NodeAttachListener.java b/src/main/java/com/marginallyclever/ro3/node/NodeAttachListener.java
index a6ea64708..3feefe060 100644
--- a/src/main/java/com/marginallyclever/ro3/node/NodeAttachListener.java
+++ b/src/main/java/com/marginallyclever/ro3/node/NodeAttachListener.java
@@ -2,6 +2,13 @@
import java.util.EventListener;
+/**
+ * {@link NodeAttachListener} is an interface for listening to {@link Node} attach events.
+ */
public interface NodeAttachListener extends EventListener {
- void nodeAttached(Node source);
+ /**
+ * Called when a child is attached to a new parent.
+ * @param child the {@link Node} that was attached
+ */
+ void nodeAttached(Node child);
}
diff --git a/src/main/java/com/marginallyclever/ro3/node/NodeDetachListener.java b/src/main/java/com/marginallyclever/ro3/node/NodeDetachListener.java
index 9baed665d..650fd8fbd 100644
--- a/src/main/java/com/marginallyclever/ro3/node/NodeDetachListener.java
+++ b/src/main/java/com/marginallyclever/ro3/node/NodeDetachListener.java
@@ -2,6 +2,13 @@
import java.util.EventListener;
+/**
+ * {@link NodeDetachListener} is an interface for listening to node detach events.
+ */
public interface NodeDetachListener extends EventListener {
- void nodeDetached(Node source);
+ /**
+ * Called when a node is detached from its parent.
+ * @param child the node that was detached
+ */
+ void nodeDetached(Node child);
}
diff --git a/src/main/java/com/marginallyclever/ro3/node/NodePath.java b/src/main/java/com/marginallyclever/ro3/node/NodePath.java
index 5f38d2f67..4f1f8e3a1 100644
--- a/src/main/java/com/marginallyclever/ro3/node/NodePath.java
+++ b/src/main/java/com/marginallyclever/ro3/node/NodePath.java
@@ -3,7 +3,8 @@
import com.marginallyclever.convenience.PathCalculator;
/**
- * Stores the relative path to a node. Can be used to find a node in the scene graph.
+ * {@link NodePath} stores the path to a node. The path can be relative or absolute.
+ * Can be used to find a node in the scene graph.
* @param the type of node to find
*/
public class NodePath {
diff --git a/src/main/java/com/marginallyclever/ro3/node/NodeReadyListener.java b/src/main/java/com/marginallyclever/ro3/node/NodeReadyListener.java
index dc69b5aea..dc71e4cdb 100644
--- a/src/main/java/com/marginallyclever/ro3/node/NodeReadyListener.java
+++ b/src/main/java/com/marginallyclever/ro3/node/NodeReadyListener.java
@@ -2,6 +2,13 @@
import java.util.EventListener;
+/**
+ * {@link NodeReadyListener} is an interface for listening to node ready events.
+ */
public interface NodeReadyListener extends EventListener {
+ /**
+ * Called when a node is ready, after all it's children are ready.
+ * @param source the node that is ready
+ */
void nodeReady(Node source);
}
diff --git a/src/main/java/com/marginallyclever/ro3/node/NodeRenameListener.java b/src/main/java/com/marginallyclever/ro3/node/NodeRenameListener.java
index 44b821796..353107bdc 100644
--- a/src/main/java/com/marginallyclever/ro3/node/NodeRenameListener.java
+++ b/src/main/java/com/marginallyclever/ro3/node/NodeRenameListener.java
@@ -2,6 +2,13 @@
import java.util.EventListener;
+/**
+ * {@link NodeRenameListener} is an interface for listening to node rename events.
+ */
public interface NodeRenameListener extends EventListener {
+ /**
+ * Called when a node is renamed.
+ * @param node the node that was renamed
+ */
void nodeRenamed(Node node);
}
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java b/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java
index 4014876f7..5924f7472 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java
@@ -16,9 +16,22 @@
import java.util.List;
/**
- * A {@link Camera} is a {@link Pose} that can be used by a {@link Viewport} to
- * render the scene.
- * For perspective rendering it has a vertical field of view and a near and far clipping plane.
+ * The Camera class is a subclass of the Pose class and is used by a Viewport to render the scene in a 3D graphics or game engine. This class provides several functionalities:
+ *
+ * - It can be set to render in orthographic projection.
+ * - It has a vertical field of view, a near and far clipping plane for perspective rendering.
+ * - It can translate and rotate relative to its current orientation.
+ * - It can look at a specific point in the scene.
+ * - It can orbit around a point at a certain radius.
+ * - It can get the point it is orbiting around.
+ * - It can change the distance from itself to the orbit point.
+ * - It can get the distance from itself to the orbit point.
+ * - It can get the perspective frustum and orthographic matrix.
+ * - It can get the chosen projection matrix based on whether it is set to draw in orthographic or not.
+ * - It can get the view matrix.
+ * - It can build a Swing Component that represents itself.
+ *
+ *
*/
public class Camera extends Pose {
private boolean drawOrthographic = false;
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/DHParameter.java b/src/main/java/com/marginallyclever/ro3/node/nodes/DHParameter.java
index ef0909a15..fff77c120 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/DHParameter.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/DHParameter.java
@@ -21,6 +21,20 @@
* The DH parameters can be derived by finding the common normals between two consecutive Z axes. The new X axis
* points along the common normal. The intersection point of the two normals may be outside the physical structure
* being described.
+ * This class provides several functionalities:
+ *
+ * - It can convert a Pose to Denavit-Hartenberg parameters.
+ * - It can convert Denavit-Hartenberg parameters to a Pose.
+ * - It can adjust the local transformations of all MeshInstance siblings.
+ * - It can serialize and deserialize itself to and from JSON format.
+ *
+ * This class also provides several properties:
+ *
+ * - d: the distance along the previous z to the common normal.
+ * - r: the length of the common normal. Assuming a revolute joint, this is the radius about the previous z.
+ * - alpha: the angle about the common normal to align the previous z to the new z.
+ * - theta: the angle about the previous z for the common normal.
+ *
*/
public class DHParameter extends Node {
private static final Logger logger = LoggerFactory.getLogger(DHParameter.class);
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/HingeJoint.java b/src/main/java/com/marginallyclever/ro3/node/nodes/HingeJoint.java
index b281173d1..c3ae30fd8 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/HingeJoint.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/HingeJoint.java
@@ -17,6 +17,27 @@
* a {@link HingeJoint} is a joint that can rotate around the local Z axis.
* a {@link HingeJoint} should be attached to a child {@link Pose} referenced as the axle. In this way the axle's
* parent {@link Pose} can be thought of as the initial pose at zero degrees. This helps prevent drift over time.
+ *
+ * This class provides several functionalities:
+ *
+ * - It can set and get the angle of rotation.
+ * - It can set and get the minimum and maximum angles of rotation.
+ * - It can set and get the velocity of rotation.
+ * - It can set and get the acceleration of rotation.
+ * - It can set and get the axle {@link Pose}.
+ * - It can update the axle's location in space based on the angle of rotation.
+ * - It can serialize and deserialize itself to and from JSON format.
+ *
+ *
+ * This class also provides several properties:
+ *
+ * - {@code angle}: the angle of rotation in degrees.
+ * - {@code minAngle}: the minimum angle of rotation in degrees.
+ * - {@code maxAngle}: the maximum angle of rotation in degrees.
+ * - {@code velocity}: the velocity of rotation in degrees per second.
+ * - {@code acceleration}: the acceleration of rotation in degrees per second squared.
+ * - {@code axle}: the {@link Pose} that the {@link HingeJoint} is attached to.
+ *
*/
public class HingeJoint extends Node {
private double angle = 0; // degrees
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/LookAt.java b/src/main/java/com/marginallyclever/ro3/node/nodes/LookAt.java
index 3aef2766a..d1d0b0d99 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/LookAt.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/LookAt.java
@@ -14,10 +14,16 @@
import java.util.List;
/**
- * {@link LookAt} is a pose that always faces a target.
- * The target is another pose.
- * The target pose is not required to be a child of this pose.
- * The target pose can be anywhere in the scene graph.
+ * {@link LookAt} is a pose that always faces a target. The target is another {@link Pose}.
+ * The target is not required to be a child of this pose.
+ * The target can be anywhere in the scene graph.
+ *
+ * This class provides several functionalities:
+ *
+ * - It can set and get the target {@link Pose}.
+ * - It can update its own location in space based on the target's location.
+ * - It can serialize and deserialize itself to and from JSON format.
+ *
*/
public class LookAt extends Pose {
private final NodePath target = new NodePath<>(this,Pose.class);
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/Material.java b/src/main/java/com/marginallyclever/ro3/node/nodes/Material.java
index 1ed01f313..cf51f9e09 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/Material.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/Material.java
@@ -12,7 +12,19 @@
import java.util.List;
/**
- * {@link Material} contains properties for rendering a surface. The first use case is to apply a texture to a mesh.
+ * {@link Material} contains properties for rendering a surface. The first use case is to apply a texture to a
+ * {@link com.marginallyclever.ro3.mesh.Mesh}.
+ *
+ * This class provides several functionalities:
+ *
+ * - It can set and get the texture.
+ * - It can set and get the diffuse color.
+ * - It can set and get the specular color.
+ * - It can set and get the emission color.
+ * - It can set and get the shininess.
+ * - It can set and get the lit status.
+ * - It can serialize and deserialize itself to and from JSON format.
+ *
*/
public class Material extends Node {
private TextureWithMetadata texture;
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/RigidBody3D.java b/src/main/java/com/marginallyclever/ro3/node/nodes/RigidBody3D.java
index 43dde6574..cfe72ed2c 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/RigidBody3D.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/RigidBody3D.java
@@ -9,7 +9,7 @@
/**
* {@link RigidBody3D} is a {@link Node} that represents a rigid body.
*/
-public class RigidBody3D extends Node {
+public class RigidBody3D extends Pose {
public RigidBody3D() {
this("RigidBody3D");
}
diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/marlinrobotarm/ApproximateJacobian.java b/src/main/java/com/marginallyclever/ro3/node/nodes/marlinrobotarm/ApproximateJacobian.java
index 6bdb92a47..a263b75ec 100644
--- a/src/main/java/com/marginallyclever/ro3/node/nodes/marlinrobotarm/ApproximateJacobian.java
+++ b/src/main/java/com/marginallyclever/ro3/node/nodes/marlinrobotarm/ApproximateJacobian.java
@@ -4,8 +4,18 @@
import com.marginallyclever.convenience.helpers.StringHelper;
/**
- * This class is used to calculate the Jacobian
- * matrix for a robot arm. Each implementation can derive this class and fill in the jacobian matrix.
+ * {@link ApproximateJacobian} is used to calculate the
+ * Jacobian matrix for a robot arm.
+ * Each implementation can derive this class and fill in the jacobian matrix.
+ * This class provides several functionalities:
+ *
+ * - It can get the inverse Jacobian matrix.
+ * - It can get the joint velocity from the Cartesian velocity.
+ * - It can get the Cartesian velocity from the joint velocity.
+ * - It can get the Jacobian matrix.
+ * - It can get the time derivative of the Jacobian matrix.
+ * - It can get the Coriolis term.
+ *
* @author Dan Royer
*/
public abstract class ApproximateJacobian {
diff --git a/src/main/java/com/marginallyclever/ro3/view/View.java b/src/main/java/com/marginallyclever/ro3/view/View.java
new file mode 100644
index 000000000..3389273fe
--- /dev/null
+++ b/src/main/java/com/marginallyclever/ro3/view/View.java
@@ -0,0 +1,13 @@
+package com.marginallyclever.ro3.view;
+
+import java.lang.annotation.*;
+
+/**
+ * Classes annotated with this annotation are saying that they implement the {@link ViewProvider} interface for class
+ * 'of'.
+ */
+@Target(ElementType.TYPE) // or any other applicable target
+@Retention(RetentionPolicy.RUNTIME) // or SOURCE or CLASS depending on usage
+public @interface View {
+ Class> of();
+}
\ No newline at end of file
diff --git a/src/main/java/com/marginallyclever/ro3/view/ViewFinder.java b/src/main/java/com/marginallyclever/ro3/view/ViewFinder.java
new file mode 100644
index 000000000..f3079b776
--- /dev/null
+++ b/src/main/java/com/marginallyclever/ro3/view/ViewFinder.java
@@ -0,0 +1,47 @@
+package com.marginallyclever.ro3.view;
+
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Finds all classes annotated with {@link View} that are for the given target class.
+ */
+public class ViewFinder {
+ public static Set> findViews(Class> targetClass) {
+ Reflections reflections = new Reflections("com.marginallyclever", Scanners.TypesAnnotated);
+ Set> annotatedClasses = reflections.getTypesAnnotatedWith(View.class);
+
+ return annotatedClasses.stream()
+ .filter(cls -> isViewApplicableForClass(cls, targetClass))
+ .filter(ViewProvider.class::isAssignableFrom)
+ .map(cls -> {
+ try {
+ return (ViewProvider>) cls.getDeclaredConstructor().newInstance();
+ } catch (InstantiationException | IllegalAccessException |
+ NoSuchMethodException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .collect(Collectors.toSet());
+ }
+
+ private static boolean isViewApplicableForClass(Class> viewClass, Class> targetClass) {
+ Class> viewOfClass = viewClass.getAnnotation(View.class).of();
+ while (targetClass != null) {
+ if (viewOfClass.equals(targetClass)) {
+ return true;
+ }
+ for (Class> interfaceClass : targetClass.getInterfaces()) {
+ if (viewOfClass.equals(interfaceClass)) {
+ return true;
+ }
+ }
+ targetClass = targetClass.getSuperclass();
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/marginallyclever/ro3/view/ViewProvider.java b/src/main/java/com/marginallyclever/ro3/view/ViewProvider.java
new file mode 100644
index 000000000..86f403eb5
--- /dev/null
+++ b/src/main/java/com/marginallyclever/ro3/view/ViewProvider.java
@@ -0,0 +1,15 @@
+package com.marginallyclever.ro3.view;
+
+import javax.swing.*;
+
+/**
+ * Classes implementing this interface are saying that they can provide a Swing component that can be used to view
+ * or manipulate the given object.
+ */
+public interface ViewProvider {
+ /**
+ * @param object The object to be viewed or manipulated.
+ * @return A Swing component that can be used to view or manipulate the given object.
+ */
+ JComponent getView(T object);
+}
diff --git a/src/main/java/com/marginallyclever/ro3/view/package-info.java b/src/main/java/com/marginallyclever/ro3/view/package-info.java
new file mode 100644
index 000000000..ce30b0e5a
--- /dev/null
+++ b/src/main/java/com/marginallyclever/ro3/view/package-info.java
@@ -0,0 +1,14 @@
+package com.marginallyclever.ro3.view;
+/**
+ * Suppose there are one or more classes that provide different views of a model, in the sense of a
+ * model-view-controller design
+ * pattern.
+ * When class A provides a {@link com.marginallyclever.ro3.view.View} for model class B, A should be annotated
+ * View(of=B.class)
. A must also implement the {@link com.marginallyclever.ro3.view.ViewProvider}
+ * interface. {@link com.marginallyclever.ro3.view.ViewProvider} then empowers other systems to locate and
+ * build the Swing GUI for A.
+ * Annotating a {@link com.marginallyclever.ro3.view.View} and failing to implement the
+ * {@link com.marginallyclever.ro3.view.ViewProvider} interface will cause a test to fail.
+ *
+ * This system allows for modular and dynamic view creation for various data types in a Swing-based application.
+ */
\ No newline at end of file
diff --git a/src/main/java/com/marginallyclever/robotoverlord/MainMenu.java b/src/main/java/com/marginallyclever/robotoverlord/MainMenu.java
index 514e77c14..b621b3b90 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/MainMenu.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/MainMenu.java
@@ -2,7 +2,7 @@
import com.marginallyclever.convenience.helpers.PathHelper;
import com.marginallyclever.robotoverlord.preferences.RecentFiles;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.actions.*;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/MainWindowDropTarget.java b/src/main/java/com/marginallyclever/robotoverlord/MainWindowDropTarget.java
index d2ebfea34..22514a7c4 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/MainWindowDropTarget.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/MainWindowDropTarget.java
@@ -4,7 +4,7 @@
import com.marginallyclever.robotoverlord.components.ShapeComponent;
import com.marginallyclever.robotoverlord.components.shapes.MeshFromFile;
import com.marginallyclever.robotoverlord.entity.Entity;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.actions.ProjectImportAction;
import com.marginallyclever.robotoverlord.swing.edits.EntityAddEdit;
import com.marginallyclever.robotoverlord.systems.render.mesh.load.MeshFactory;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/RobotOverlord.java b/src/main/java/com/marginallyclever/robotoverlord/RobotOverlord.java
index 34a0d3934..f9886ad04 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/RobotOverlord.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/RobotOverlord.java
@@ -8,7 +8,7 @@
import com.marginallyclever.robotoverlord.preferences.InteractionPreferences;
import com.marginallyclever.robotoverlord.renderpanel.OpenGLRenderPanel;
import com.marginallyclever.robotoverlord.renderpanel.RenderPanel;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.actions.*;
import com.marginallyclever.robotoverlord.swing.componentmanagerpanel.ComponentManagerPanel;
import com.marginallyclever.robotoverlord.swing.entitytreepanel.EntityTreePanel;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/package-info.java b/src/main/java/com/marginallyclever/robotoverlord/package-info.java
new file mode 100644
index 000000000..2efaec7a5
--- /dev/null
+++ b/src/main/java/com/marginallyclever/robotoverlord/package-info.java
@@ -0,0 +1,5 @@
+package com.marginallyclever.robotoverlord;
+/**
+ * This package is deprecated. Use com.marginallyclever.ro3 instead.
+ * Some of the content is good and will be moved to the new package.
+ */
\ No newline at end of file
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementBoolean.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementBoolean.java
index c4518a1f4..eaa3c25f8 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementBoolean.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementBoolean.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.BooleanParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.BooleanParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementColor.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementColor.java
index 670e7ff1d..2f6991c6f 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementColor.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementColor.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.ColorParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.ro3.apps.shared.BackgroundPaintedButton;
import com.marginallyclever.robotoverlord.swing.edits.ColorParameterEdit;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementComboBox.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementComboBox.java
index beb16b89b..462e88a5b 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementComboBox.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementComboBox.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.IntParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.ComboBoxEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementDouble.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementDouble.java
index 8556a7403..8a36b7cdf 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementDouble.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementDouble.java
@@ -2,7 +2,7 @@
import com.marginallyclever.convenience.helpers.StringHelper;
import com.marginallyclever.robotoverlord.parameters.DoubleParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.DoubleParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementFilename.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementFilename.java
index 30fbd683c..aa301094c 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementFilename.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementFilename.java
@@ -2,7 +2,7 @@
import com.marginallyclever.convenience.helpers.PathHelper;
import com.marginallyclever.robotoverlord.parameters.StringParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.StringParameterEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementInt.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementInt.java
index f87602a82..83a12dcad 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementInt.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementInt.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.IntParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.IntParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementReference.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementReference.java
index 0a298e817..5cc33cc7e 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementReference.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementReference.java
@@ -3,7 +3,7 @@
import com.marginallyclever.robotoverlord.entity.Entity;
import com.marginallyclever.robotoverlord.entity.EntityManager;
import com.marginallyclever.robotoverlord.parameters.ReferenceParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.componentmanagerpanel.EntityChooser;
import com.marginallyclever.robotoverlord.swing.edits.StringParameterEdit;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSlider.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSlider.java
index 5f1bc14b0..a044a6b1a 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSlider.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSlider.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.IntParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.IntParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSliderDouble.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSliderDouble.java
index ff7412ad1..634f618eb 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSliderDouble.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementSliderDouble.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.DoubleParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.DoubleParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementString.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementString.java
index 6575874cf..d9d8dfd5e 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementString.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementString.java
@@ -1,7 +1,7 @@
package com.marginallyclever.robotoverlord.parameters.swing;
import com.marginallyclever.robotoverlord.parameters.StringParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.StringParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementVector3d.java b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementVector3d.java
index ec8a17bf4..ecb6d5ce8 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementVector3d.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/parameters/swing/ViewElementVector3d.java
@@ -2,7 +2,7 @@
import com.marginallyclever.convenience.helpers.StringHelper;
import com.marginallyclever.robotoverlord.parameters.Vector3DParameter;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.Vector3dParameterEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentAddAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentAddAction.java
index 9c467dcb5..f2fbdfaf9 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentAddAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentAddAction.java
@@ -7,7 +7,7 @@
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.componentmanagerpanel.ComponentManagerPanel;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.ComponentAddEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.slf4j.Logger;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentDeleteAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentDeleteAction.java
index b46344444..38d6df6c5 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentDeleteAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentDeleteAction.java
@@ -3,7 +3,7 @@
import com.marginallyclever.robotoverlord.components.Component;
import com.marginallyclever.robotoverlord.entity.Entity;
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.componentmanagerpanel.ComponentManagerPanel;
import com.marginallyclever.robotoverlord.swing.edits.ComponentDeleteEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentPasteAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentPasteAction.java
index b77da7910..313936eb2 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentPasteAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ComponentPasteAction.java
@@ -4,7 +4,7 @@
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.EditorAction;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.ComponentPasteEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityAddChildAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityAddChildAction.java
index d20f7d6c2..2584028b7 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityAddChildAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityAddChildAction.java
@@ -5,7 +5,7 @@
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.EditorAction;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.EntityAddEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.slf4j.Logger;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityDeleteAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityDeleteAction.java
index 7799c1c53..960a50b23 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityDeleteAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityDeleteAction.java
@@ -4,7 +4,7 @@
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.EditorAction;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.EntityDeleteEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityPasteAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityPasteAction.java
index 19153f6d5..15e4a8d7c 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityPasteAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityPasteAction.java
@@ -5,7 +5,7 @@
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.EditorAction;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.EntityPasteEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityRenameAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityRenameAction.java
index f58102c67..1e57c006a 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityRenameAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/EntityRenameAction.java
@@ -4,7 +4,7 @@
import com.marginallyclever.robotoverlord.entity.EntityManager;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.EditorAction;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.EntityRenameEdit;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.slf4j.Logger;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectClearAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectClearAction.java
index b45593cb0..b9579c9b6 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectClearAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectClearAction.java
@@ -6,7 +6,7 @@
import com.marginallyclever.robotoverlord.Project;
import com.marginallyclever.robotoverlord.components.shapes.Box;
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectImportAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectImportAction.java
index 0afa510a6..749411ffb 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectImportAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectImportAction.java
@@ -2,7 +2,7 @@
import com.marginallyclever.robotoverlord.*;
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectLoadAction.java b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectLoadAction.java
index 626b55c31..5f89ffe52 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectLoadAction.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/actions/ProjectLoadAction.java
@@ -3,7 +3,7 @@
import com.marginallyclever.robotoverlord.Project;
import com.marginallyclever.robotoverlord.RobotOverlord;
import com.marginallyclever.robotoverlord.swing.UnicodeIcon;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanel.java b/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanel.java
index 1c04da706..4e0f3eb3a 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanel.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanel.java
@@ -5,7 +5,7 @@
import com.marginallyclever.robotoverlord.entity.EntityManagerEvent;
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.swing.EditorAction;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.actions.*;
import com.marginallyclever.robotoverlord.swing.edits.SelectEdit;
import org.slf4j.Logger;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreeTransferHandler.java b/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreeTransferHandler.java
index 024014056..4d8e06564 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreeTransferHandler.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreeTransferHandler.java
@@ -2,7 +2,7 @@
import com.marginallyclever.robotoverlord.entity.Entity;
import com.marginallyclever.robotoverlord.entity.EntityManager;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.EntityReorganizeEdit;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/systems/robot/robotarm/EditArmPanel.java b/src/main/java/com/marginallyclever/robotoverlord/systems/robot/robotarm/EditArmPanel.java
index 332c81faa..296414c73 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/systems/robot/robotarm/EditArmPanel.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/systems/robot/robotarm/EditArmPanel.java
@@ -11,7 +11,7 @@
import com.marginallyclever.robotoverlord.parameters.swing.ViewElementDouble;
import com.marginallyclever.robotoverlord.parameters.swing.ViewElementFilename;
import com.marginallyclever.robotoverlord.robots.Robot;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import com.marginallyclever.robotoverlord.systems.OriginAdjustSystem;
import com.marginallyclever.robotoverlord.systems.render.mesh.load.MeshFactory;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/systems/vehicle/CreateVehiclePanel.java b/src/main/java/com/marginallyclever/robotoverlord/systems/vehicle/CreateVehiclePanel.java
index 89f27917d..b7e032372 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/systems/vehicle/CreateVehiclePanel.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/systems/vehicle/CreateVehiclePanel.java
@@ -6,7 +6,7 @@
import com.marginallyclever.robotoverlord.parameters.DoubleParameter;
import com.marginallyclever.robotoverlord.parameters.IntParameter;
import com.marginallyclever.robotoverlord.parameters.swing.ViewElementFactory;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.EntityAddEdit;
import javax.swing.*;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/tools/SelectionTool.java b/src/main/java/com/marginallyclever/robotoverlord/tools/SelectionTool.java
index 75a337a8a..c23c13cef 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/tools/SelectionTool.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/tools/SelectionTool.java
@@ -9,7 +9,7 @@
import com.marginallyclever.robotoverlord.components.PoseComponent;
import com.marginallyclever.robotoverlord.entity.Entity;
import com.marginallyclever.robotoverlord.entity.EntityManager;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.SelectEdit;
import com.marginallyclever.robotoverlord.systems.RayPickSystem;
import com.marginallyclever.robotoverlord.systems.render.ShaderProgram;
diff --git a/src/main/java/com/marginallyclever/robotoverlord/tools/move/EditorUtils.java b/src/main/java/com/marginallyclever/robotoverlord/tools/move/EditorUtils.java
index 93e4ab051..ffbe9950f 100644
--- a/src/main/java/com/marginallyclever/robotoverlord/tools/move/EditorUtils.java
+++ b/src/main/java/com/marginallyclever/robotoverlord/tools/move/EditorUtils.java
@@ -6,7 +6,7 @@
import com.marginallyclever.convenience.helpers.MatrixHelper;
import com.marginallyclever.robotoverlord.components.PoseComponent;
import com.marginallyclever.robotoverlord.entity.Entity;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.edits.PoseMoveEdit;
import com.marginallyclever.robotoverlord.systems.render.Viewport;
import com.marginallyclever.robotoverlord.tools.EditorTool;
diff --git a/src/test/java/com/marginallyclever/ro3/view/ViewProviderTest.java b/src/test/java/com/marginallyclever/ro3/view/ViewProviderTest.java
new file mode 100644
index 000000000..80f56364b
--- /dev/null
+++ b/src/test/java/com/marginallyclever/ro3/view/ViewProviderTest.java
@@ -0,0 +1,33 @@
+package com.marginallyclever.ro3.view;
+
+import org.junit.Test;
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+
+/**
+ * This test ensures that all classes annotated with {@link View} implement {@link ViewProvider}.
+ */
+public class ViewProviderTest {
+ private static final Logger logger = LoggerFactory.getLogger(ViewProviderTest.class);
+
+ @Test
+ public void testViewProviders() {
+ int count=0;
+ for (Class> cls : getAllClasses()) {
+ count++;
+ logger.info("View {}",cls.getSimpleName());
+ assert !ViewProvider.class.isAssignableFrom(cls) :
+ "Class " + cls.getName() + " must implement ViewProvider";
+ }
+ logger.info("Found {} views.",count);
+ }
+
+ private Set> getAllClasses() {
+ Reflections reflections = new Reflections("com.marginallyclever", Scanners.TypesAnnotated);
+ return reflections.getTypesAnnotatedWith(View.class);
+ }
+}
diff --git a/src/test/java/com/marginallyclever/robotoverlord/swing/actions/ComponentActionTests.java b/src/test/java/com/marginallyclever/robotoverlord/swing/actions/ComponentActionTests.java
index 8572911a4..a72479cef 100644
--- a/src/test/java/com/marginallyclever/robotoverlord/swing/actions/ComponentActionTests.java
+++ b/src/test/java/com/marginallyclever/robotoverlord/swing/actions/ComponentActionTests.java
@@ -4,7 +4,7 @@
import com.marginallyclever.robotoverlord.clipboard.Clipboard;
import com.marginallyclever.robotoverlord.components.Component;
import com.marginallyclever.robotoverlord.components.PoseComponent;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanelTest.java b/src/test/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanelTest.java
index c69d57686..38e91535b 100644
--- a/src/test/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanelTest.java
+++ b/src/test/java/com/marginallyclever/robotoverlord/swing/entitytreepanel/EntityTreePanelTest.java
@@ -2,7 +2,7 @@
import com.marginallyclever.robotoverlord.entity.EntityManager;
import com.marginallyclever.robotoverlord.entity.EntityManagerTest;
-import com.marginallyclever.ro3.UndoSystem;
+import com.marginallyclever.ro3.apps.UndoSystem;
import com.marginallyclever.robotoverlord.swing.translator.Translator;
import org.assertj.swing.core.BasicRobot;
import org.assertj.swing.core.Robot;