From a6a1bf681ba1757cdbb91f7cd6d361ba6e894d74 Mon Sep 17 00:00:00 2001 From: Brendan Robert Date: Tue, 24 Feb 2015 00:30:11 -0600 Subject: [PATCH] Configuration tree is now completely visible in new JavaFX config dialog but things are showing as duplicated at the root level --- src/main/java/jace/EmulatorUILogic.java | 23 ++- src/main/java/jace/JaceApplication.java | 7 +- src/main/java/jace/JaceUIController.java | 3 - src/main/java/jace/config/Configuration.java | 143 +++++++----------- .../java/jace/config/ConfigurationPanel.form | 5 +- .../java/jace/config/ConfigurationPanel.java | 116 +++++++------- .../config/ConfigurationUIController.java | 66 ++++++++ src/main/resources/fxml/Configuration.fxml | 38 +++++ src/main/resources/styles/configuration.css | 7 + 9 files changed, 255 insertions(+), 153 deletions(-) create mode 100644 src/main/java/jace/config/ConfigurationUIController.java create mode 100644 src/main/resources/fxml/Configuration.fxml create mode 100644 src/main/resources/styles/configuration.css diff --git a/src/main/java/jace/EmulatorUILogic.java b/src/main/java/jace/EmulatorUILogic.java index 603fde7..2460cea 100644 --- a/src/main/java/jace/EmulatorUILogic.java +++ b/src/main/java/jace/EmulatorUILogic.java @@ -21,6 +21,7 @@ package jace; import jace.apple2e.MOS65C02; import jace.apple2e.RAM128k; import jace.apple2e.SoftSwitches; +import jace.config.ConfigurationUIController; import jace.config.InvokableAction; import jace.config.Reconfigurable; import jace.core.CPU; @@ -43,7 +44,11 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import javafx.embed.swing.SwingFXUtils; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; import javax.imageio.ImageIO; import javax.swing.JFileChooser; import javax.swing.JLabel; @@ -355,11 +360,19 @@ public class EmulatorUILogic implements Reconfigurable { alternatives = "Reconfigure,Preferences,Settings", defaultKeyMapping = {"f4","ctrl+shift+c"}) public static void showConfig() { -// if (Emulator.getFrame().getModalDialogUI(CONFIGURATION_DIALOG_NAME) == null) { -// JPanel ui = new ConfigurationPanel(); -// Emulator.getFrame().registerModalDialog(ui, CONFIGURATION_DIALOG_NAME, null, false); -// } -// Emulator.getFrame().showDialog(CONFIGURATION_DIALOG_NAME); + FXMLLoader fxmlLoader = new FXMLLoader(EmulatorUILogic.class.getResource("/fxml/Configuration.fxml")); + fxmlLoader.setResources(null); + try { + Stage configWindow = new Stage(); + AnchorPane node = (AnchorPane) fxmlLoader.load(); + ConfigurationUIController controller = fxmlLoader.getController(); + controller.initialize(); + Scene s = new Scene(node); + configWindow.setScene(s); + configWindow.show(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } } public static final String MEDIA_MANAGER_DIALOG_NAME = "Media Manager"; diff --git a/src/main/java/jace/JaceApplication.java b/src/main/java/jace/JaceApplication.java index 9999bf3..f969a9c 100644 --- a/src/main/java/jace/JaceApplication.java +++ b/src/main/java/jace/JaceApplication.java @@ -19,12 +19,13 @@ import javafx.stage.Stage; * @author blurry */ public class JaceApplication extends Application { - + static JaceApplication singleton; Stage primaryStage; JaceUIController controller; @Override public void start(Stage stage) throws Exception { + singleton = this; primaryStage = stage; FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/JaceUI.fxml")); fxmlLoader.setResources(null); @@ -53,6 +54,10 @@ public class JaceApplication extends Application { }); } + public static JaceApplication getApplication() { + return singleton; + } + /** * @param args the command line arguments */ diff --git a/src/main/java/jace/JaceUIController.java b/src/main/java/jace/JaceUIController.java index 603899f..4bb832c 100644 --- a/src/main/java/jace/JaceUIController.java +++ b/src/main/java/jace/JaceUIController.java @@ -7,9 +7,7 @@ package jace; import jace.core.Computer; -import jace.core.Video; import java.net.URL; -import java.util.ResourceBundle; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.image.ImageView; @@ -49,7 +47,6 @@ public class JaceUIController { rootPane.setFocusTraversable(true); rootPane.setOnKeyPressed(keyboardHandler); rootPane.setOnKeyReleased(keyboardHandler); -// rootPane.onKeyTypedProperty().setValue(keyboardHandler); rootPane.requestFocus(); } } diff --git a/src/main/java/jace/config/Configuration.java b/src/main/java/jace/config/Configuration.java index f1f9330..5db73d4 100644 --- a/src/main/java/jace/config/Configuration.java +++ b/src/main/java/jace/config/Configuration.java @@ -48,9 +48,8 @@ import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.event.TreeModelListener; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; +import javafx.collections.ObservableList; +import javafx.scene.control.TreeItem; /** * Manages the configuration state of the emulator components. @@ -82,68 +81,6 @@ public class Configuration implements Reconfigurable { public void reconfigure() { } - public static class ConfigTreeModel implements TreeModel { - - @Override - public Object getRoot() { - return BASE; - } - - @Override - public Object getChild(Object parent, int index) { - if (parent instanceof ConfigNode) { - ConfigNode n = (ConfigNode) parent; - return n.children.values().toArray()[index]; - } else { - return null; - } - } - - @Override - public int getChildCount(Object parent) { - if (parent instanceof ConfigNode) { - ConfigNode n = (ConfigNode) parent; - return n.children.size(); - } else { - return 0; - } - } - - @Override - public boolean isLeaf(Object node) { - return getChildCount(node) == 0; - } - - @Override - public void valueForPathChanged(TreePath path, Object newValue) { - // Do nothing... - } - - @Override - public int getIndexOfChild(Object parent, Object child) { - if (parent instanceof ConfigNode) { - ConfigNode n = (ConfigNode) parent; - ConfigNode[] c = (ConfigNode[]) n.children.values().toArray(new ConfigNode[0]); - for (int i = 0; i < c.length; i++) { - if (c[i].equals(child)) { - return i; - } - } - } - return -1; - } - - @Override - public void addTreeModelListener(TreeModelListener l) { - // Do nothing... - } - - @Override - public void removeTreeModelListener(TreeModelListener l) { - // Do nothing... - } - } - /** * Represents a serializable configuration node as part of a tree. The root * node should be a single instance (e.g. Computer) The child nodes should @@ -152,14 +89,14 @@ public class Configuration implements Reconfigurable { * configuration 2) Provide a simple persistence mechanism to load/store * configuration */ - public static class ConfigNode implements Serializable { + public static class ConfigNode extends TreeItem implements Serializable { public transient ConfigNode root; public transient ConfigNode parent; + private ObservableList children; public transient Reconfigurable subject; private Map settings; private Map hotkeys; - protected Map children; private boolean changed = true; @Override @@ -167,23 +104,26 @@ public class Configuration implements Reconfigurable { if (subject == null) { return "???"; } - return (changed ? "" : "") + subject.getName(); + return subject.getName(); } public ConfigNode(Reconfigurable subject) { this(null, subject); this.root = null; + this.setExpanded(true); } public ConfigNode(ConfigNode parent, Reconfigurable subject) { + super(); this.subject = subject; this.settings = new TreeMap<>(); this.hotkeys = new TreeMap<>(); - this.children = new TreeMap<>(); + this.children = getChildren(); this.parent = parent; if (this.parent != null) { this.root = this.parent.root != null ? this.parent.root : this.parent; } + setValue(toString()); } public void setFieldValue(String field, Serializable value) { @@ -211,6 +151,38 @@ public class Configuration implements Reconfigurable { public Set getAllSettingNames() { return settings.keySet(); } + + @Override + public ObservableList getChildren() { + return super.getChildren(); + } + + private boolean removeChild(String childName) { + ConfigNode child = findChild(childName); + return children.remove(child); + } + + private ConfigNode findChild(String childName) { + for (ConfigNode node : children) { + if (childName.equalsIgnoreCase(String.valueOf(node.getValue()))) { + return node; + } + } + return null; + } + + private void putChild(String childName, ConfigNode newChild) { + removeChild(childName); + int index = 0; + for (ConfigNode node : children) { + if (String.valueOf(node.getValue()).compareToIgnoreCase(childName) > 0) { + break; + } else { + index++; + } + } + children.add(index, newChild); + } } public final static ConfigNode BASE; public static EmulatorUILogic ui = Emulator.logic; @@ -241,7 +213,7 @@ public class Configuration implements Reconfigurable { } for (Field f : node.subject.getClass().getFields()) { -// System.out.println("Evaluating field " + f.getName()); + System.out.println("Evaluating field " + f.getName()); try { Object o = f.get(node.subject); if (/*o == null ||*/visited.contains(o)) { @@ -267,22 +239,22 @@ public class Configuration implements Reconfigurable { if (o instanceof Reconfigurable) { Reconfigurable r = (Reconfigurable) o; - ConfigNode child = node.children.get(f.getName()); + ConfigNode child = node.findChild(f.getName()); if (child == null || !child.subject.equals(o)) { child = new ConfigNode(node, r); - node.children.put(f.getName(), child); + node.putChild(f.getName(), child); } buildTree(child, visited); } else if (o.getClass().isArray()) { String fieldName = f.getName(); Class type = o.getClass().getComponentType(); -// System.out.println("Evaluating " + node.subject.getShortName() + "." + fieldName + "; type is " + type.toGenericString()); + System.out.println("Evaluating " + node.subject.getShortName() + "." + fieldName + "; type is " + type.toGenericString()); List children = new ArrayList<>(); if (!Reconfigurable.class.isAssignableFrom(type)) { -// System.out.println("Looking at type " + type.getName() + " to see if optional"); + System.out.println("Looking at type " + type.getName() + " to see if optional"); if (Optional.class.isAssignableFrom(type)) { Type genericTypes = f.getGenericType(); -// System.out.println("Looking at generic parmeters " + genericTypes.getTypeName() + " for reconfigurable class, type "+genericTypes.getClass().getName()); + System.out.println("Looking at generic parmeters " + genericTypes.getTypeName() + " for reconfigurable class, type "+genericTypes.getClass().getName()); if (genericTypes instanceof GenericArrayType) { GenericArrayType aType = (GenericArrayType) genericTypes; ParameterizedType pType = (ParameterizedType) aType.getGenericComponentType(); @@ -313,13 +285,13 @@ public class Configuration implements Reconfigurable { Reconfigurable child = children.get(i); String childName = fieldName + i; if (child == null) { - node.children.remove(childName); + node.removeChild(childName); continue; } - ConfigNode grandchild = node.children.get(childName); + ConfigNode grandchild = node.findChild(childName); if (grandchild == null || !grandchild.subject.equals(child)) { grandchild = new ConfigNode(node, child); - node.children.put(childName, grandchild); + node.putChild(childName, grandchild); } buildTree(grandchild, visited); } @@ -426,7 +398,7 @@ public class Configuration implements Reconfigurable { // Now that the object structure reflects the current configuration, // process reconfiguration from the children, etc. - for (ConfigNode child : node.children.values()) { + for (ConfigNode child : node.getChildren()) { hasChanged |= applySettings(child); } @@ -451,9 +423,10 @@ public class Configuration implements Reconfigurable { doApply(oldRoot); buildTree(oldRoot, new HashSet()); } - newRoot.children.keySet().stream().forEach((childName) -> { + newRoot.getChildren().stream().forEach((child) -> { + String childName = child.getValue().toString(); // System.out.println("Applying settings for " + childName); - applyConfigTree(newRoot.children.get(childName), oldRoot.children.get(childName)); + applyConfigTree(newRoot.findChild(childName), oldRoot.findChild(childName)); }); } @@ -568,8 +541,8 @@ public class Configuration implements Reconfigurable { private static void buildNodeMap(ConfigNode n, Map shortNames) { // System.out.println("Encountered " + n.subject.getShortName().toLowerCase()); shortNames.put(n.subject.getShortName().toLowerCase(), n); - n.children.entrySet().stream().forEach((c) -> { - buildNodeMap(c.getValue(), shortNames); + n.getChildren().stream().forEach((c) -> { + buildNodeMap(c, shortNames); }); } @@ -587,8 +560,8 @@ public class Configuration implements Reconfigurable { String sn = (f != null && !f.shortName().equals("")) ? f.shortName() : setting; System.out.println(prefix + ">>" + setting + " (" + n.subject.getShortName() + "." + sn + ")"); }); - n.children.entrySet().stream().forEach((c) -> { - printTree(c.getValue(), prefix + "." + c.getKey(), i + 1); + n.getChildren().stream().forEach((c) -> { + printTree(c, prefix + "." + c.toString(), i + 1); }); } } diff --git a/src/main/java/jace/config/ConfigurationPanel.form b/src/main/java/jace/config/ConfigurationPanel.form index 1d2b63f..5a3e491 100644 --- a/src/main/java/jace/config/ConfigurationPanel.form +++ b/src/main/java/jace/config/ConfigurationPanel.form @@ -62,12 +62,15 @@ - + + + + diff --git a/src/main/java/jace/config/ConfigurationPanel.java b/src/main/java/jace/config/ConfigurationPanel.java index 34ba6a0..058fb52 100644 --- a/src/main/java/jace/config/ConfigurationPanel.java +++ b/src/main/java/jace/config/ConfigurationPanel.java @@ -77,72 +77,72 @@ public class ConfigurationPanel extends javax.swing.JPanel { setPreferredSize(new java.awt.Dimension(650, 480)); - configTree.setModel(new Configuration.ConfigTreeModel()); - configTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() { - public void valueChanged(javax.swing.event.TreeSelectionEvent evt) { - configTreeValueChanged(evt); - } - }); - configTreeScrollPane.setViewportView(configTree); + configTree.setModel(null); //new Configuration.ConfigTreeModel()); + configTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() { + public void valueChanged(javax.swing.event.TreeSelectionEvent evt) { + configTreeValueChanged(evt); + } + }); + configTreeScrollPane.setViewportView(configTree); - settingsPanel.setAlignmentX(0.0F); - settingsPanel.setAlignmentY(0.0F); - settingsPanel.setPreferredSize(new java.awt.Dimension(375, 480)); - settingsPanel.setLayout(new java.awt.GridBagLayout()); + settingsPanel.setAlignmentX(0.0F); + settingsPanel.setAlignmentY(0.0F); + settingsPanel.setPreferredSize(new java.awt.Dimension(375, 480)); + settingsPanel.setLayout(new java.awt.GridBagLayout()); - applyButton.setText("Apply"); - applyButton.setToolTipText("Apply current changes without saving"); - applyButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - applyButtonActionPerformed(evt); - } - }); + applyButton.setText("Apply"); + applyButton.setToolTipText("Apply current changes without saving"); + applyButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + applyButtonActionPerformed(evt); + } + }); - saveButton.setText("Save"); - saveButton.setToolTipText("Apply settings and save"); - saveButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - saveButtonActionPerformed(evt); - } - }); + saveButton.setText("Save"); + saveButton.setToolTipText("Apply settings and save"); + saveButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + saveButtonActionPerformed(evt); + } + }); - revertButton.setText("Revert"); - revertButton.setToolTipText("Revert all settings to last saved values (hold SHIFT while clicking to revert to defaults)"); - revertButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - revertButtonActionPerformed(evt); - } - }); + revertButton.setText("Revert"); + revertButton.setToolTipText("Revert all settings to last saved values (hold SHIFT while clicking to revert to defaults)"); + revertButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + revertButtonActionPerformed(evt); + } + }); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(applyButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(saveButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(revertButton)) - .addComponent(configTreeScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 271, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(configTreeScrollPane) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() .addComponent(applyButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(saveButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(revertButton)) - .addContainerGap()) - .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE) - ); + .addComponent(configTreeScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 271, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(configTreeScrollPane) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(applyButton) + .addComponent(saveButton) + .addComponent(revertButton)) + .addContainerGap()) + .addComponent(settingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 0, Short.MAX_VALUE) + ); }// //GEN-END:initComponents ConfigNode currentNode = null; diff --git a/src/main/java/jace/config/ConfigurationUIController.java b/src/main/java/jace/config/ConfigurationUIController.java new file mode 100644 index 0000000..5c77691 --- /dev/null +++ b/src/main/java/jace/config/ConfigurationUIController.java @@ -0,0 +1,66 @@ +package jace.config; + +import jace.Emulator; +import jace.JaceApplication; +import java.net.URL; +import java.util.ResourceBundle; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.SplitPane; +import javafx.scene.control.TreeView; +import javafx.scene.layout.VBox; + +public class ConfigurationUIController { + + @FXML + private ResourceBundle resources; + + @FXML + private URL location; + + @FXML + private VBox settingsVbox; + + @FXML + private SplitPane splitPane; + + @FXML + private ScrollPane settingsScroll; + + @FXML + private TreeView deviceTree; + + @FXML + private ScrollPane treeScroll; + + @FXML + void reloadConfig(ActionEvent event) { + + } + + @FXML + void saveConfig(ActionEvent event) { + + } + + @FXML + void applyConfig(ActionEvent event) { + + } + + @FXML + void cancelConfig(ActionEvent event) { + + } + + @FXML + public void initialize() { + assert settingsVbox != null : "fx:id=\"settingsVbox\" was not injected: check your FXML file 'Configuration.fxml'."; + assert splitPane != null : "fx:id=\"splitPane\" was not injected: check your FXML file 'Configuration.fxml'."; + assert settingsScroll != null : "fx:id=\"settingsScroll\" was not injected: check your FXML file 'Configuration.fxml'."; + assert deviceTree != null : "fx:id=\"deviceTree\" was not injected: check your FXML file 'Configuration.fxml'."; + assert treeScroll != null : "fx:id=\"treeScroll\" was not injected: check your FXML file 'Configuration.fxml'."; + deviceTree.setRoot(Configuration.BASE); + } +} diff --git a/src/main/resources/fxml/Configuration.fxml b/src/main/resources/fxml/Configuration.fxml new file mode 100644 index 0000000..bac75dd --- /dev/null +++ b/src/main/resources/fxml/Configuration.fxml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + +