forked from Apple-2-Tools/jace
Config screen hooked up to load/save/apply actions, tree state is now properly reflected and maintained. Also some settings editor widgets are working.
This commit is contained in:
parent
9a9649c961
commit
8959c412ed
@ -28,6 +28,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
@ -50,6 +51,8 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.TreeItem;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
|
||||
/**
|
||||
* Manages the configuration state of the emulator components.
|
||||
@ -91,6 +94,11 @@ public class Configuration implements Reconfigurable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImageView getChangedIcon() {
|
||||
InputStream imgStream = Configuration.class.getResourceAsStream("/jace/data/icon_exclaim.gif");
|
||||
return new ImageView(new Image(imgStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Configuration";
|
||||
@ -119,8 +127,8 @@ public class Configuration implements Reconfigurable {
|
||||
public transient ConfigNode parent;
|
||||
private ObservableList<ConfigNode> children;
|
||||
public transient Reconfigurable subject;
|
||||
public Map<String, Serializable> settings;
|
||||
public Map<String, String[]> hotkeys;
|
||||
public Map<String, Serializable> settings = new TreeMap<>();
|
||||
public Map<String, String[]> hotkeys = new TreeMap<>();;
|
||||
private boolean changed = true;
|
||||
|
||||
@Override
|
||||
@ -140,8 +148,6 @@ public class Configuration implements Reconfigurable {
|
||||
public ConfigNode(ConfigNode parent, Reconfigurable subject) {
|
||||
super();
|
||||
this.subject = subject;
|
||||
this.settings = new TreeMap<>();
|
||||
this.hotkeys = new TreeMap<>();
|
||||
this.children = getChildren();
|
||||
this.parent = parent;
|
||||
if (this.parent != null) {
|
||||
@ -151,7 +157,7 @@ public class Configuration implements Reconfigurable {
|
||||
}
|
||||
|
||||
public void setFieldValue(String field, Serializable value) {
|
||||
changed = true;
|
||||
setChanged(true);
|
||||
if (value != null) {
|
||||
if (value.equals(getFieldValue(field))) {
|
||||
return;
|
||||
@ -208,6 +214,15 @@ public class Configuration implements Reconfigurable {
|
||||
}
|
||||
children.add(index, newChild);
|
||||
}
|
||||
|
||||
private void setChanged(boolean b) {
|
||||
changed = b;
|
||||
if (!changed) {
|
||||
setGraphic(null);
|
||||
} else {
|
||||
setGraphic(getChangedIcon());
|
||||
}
|
||||
}
|
||||
}
|
||||
public static ConfigNode BASE;
|
||||
public static EmulatorUILogic ui = Emulator.logic;
|
||||
@ -512,7 +527,7 @@ public class Configuration implements Reconfigurable {
|
||||
Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
node.changed = false;
|
||||
node.setChanged(false);
|
||||
}
|
||||
|
||||
public static void applySettings(Map<String, String> settings) {
|
||||
|
@ -6,30 +6,33 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.HashSet;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.SplitPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.TreeItem;
|
||||
import javafx.scene.control.TreeView;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public class ConfigurationUIController {
|
||||
public static final String DELIMITER = "~!~";
|
||||
|
||||
@FXML
|
||||
private ResourceBundle resources;
|
||||
@ -53,23 +56,25 @@ public class ConfigurationUIController {
|
||||
private ScrollPane treeScroll;
|
||||
|
||||
@FXML
|
||||
void reloadConfig(ActionEvent event) {
|
||||
|
||||
void reloadConfig(MouseEvent event) {
|
||||
Configuration.loadSettings();
|
||||
resetDeviceTree();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void saveConfig(ActionEvent event) {
|
||||
|
||||
void saveConfig(MouseEvent event) {
|
||||
Configuration.saveSettings();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void applyConfig(ActionEvent event) {
|
||||
|
||||
void applyConfig(MouseEvent event) {
|
||||
Configuration.applySettings(Configuration.BASE);
|
||||
resetDeviceTree();
|
||||
}
|
||||
|
||||
@FXML
|
||||
void cancelConfig(ActionEvent event) {
|
||||
|
||||
void cancelConfig(MouseEvent event) {
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
@FXML
|
||||
@ -79,11 +84,67 @@ public class ConfigurationUIController {
|
||||
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);
|
||||
resetDeviceTree();
|
||||
deviceTree.getSelectionModel().selectedItemProperty().addListener(this::selectionChanged);
|
||||
deviceTree.maxWidthProperty().bind(treeScroll.widthProperty());
|
||||
}
|
||||
|
||||
private void resetDeviceTree() {
|
||||
Set<String> expanded = new HashSet<>();
|
||||
String current = getCurrentNodePath();
|
||||
getExpandedNodes("", deviceTree.getRoot(), expanded);
|
||||
deviceTree.setRoot(Configuration.BASE);
|
||||
setExpandedNodes("", deviceTree.getRoot(), expanded);
|
||||
setCurrentNodePath(current);
|
||||
}
|
||||
|
||||
private void getExpandedNodes(String prefix, TreeItem<ConfigNode> root, Set<String> expanded) {
|
||||
if (root == null) return;
|
||||
for (TreeItem item : root.getChildren()) {
|
||||
if (item.isExpanded()) {
|
||||
String name = prefix+item.toString();
|
||||
expanded.add(name);
|
||||
getExpandedNodes(name+DELIMITER, item, expanded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setExpandedNodes(String prefix, TreeItem<ConfigNode> root, Set<String> expanded) {
|
||||
if (root == null) return;
|
||||
root.getChildren().stream().forEach((item) -> {
|
||||
String name = prefix+item.toString();
|
||||
if (expanded.contains(name)) {
|
||||
item.setExpanded(true);
|
||||
}
|
||||
setExpandedNodes(name+DELIMITER, item, expanded);
|
||||
});
|
||||
}
|
||||
|
||||
private String getCurrentNodePath() {
|
||||
TreeItem<ConfigNode> current = deviceTree.getSelectionModel().getSelectedItem();
|
||||
if (current == null) return null;
|
||||
String out = current.toString();
|
||||
while (current.getParent() != null) {
|
||||
out = current.getParent().toString()+DELIMITER+current;
|
||||
current = current.getParent();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private void setCurrentNodePath(String value) {
|
||||
if (value == null) return;
|
||||
String[] parts = value.split(Pattern.quote(DELIMITER));
|
||||
TreeItem<ConfigNode> current = deviceTree.getRoot();
|
||||
for (String part : parts) {
|
||||
for (TreeItem child : current.getChildren()) {
|
||||
if (child.toString().equals(part)) {
|
||||
current = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
deviceTree.getSelectionModel().select(current);
|
||||
}
|
||||
|
||||
private void selectionChanged(
|
||||
ObservableValue<? extends TreeItem<ConfigNode>> observable,
|
||||
TreeItem<ConfigNode> oldValue,
|
||||
@ -97,6 +158,9 @@ public class ConfigurationUIController {
|
||||
}
|
||||
|
||||
private void buildForm(ConfigNode node) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
node.hotkeys.forEach((name, values) -> {
|
||||
settingsVbox.getChildren().add(buildKeyShortcutRow(node, name, values));
|
||||
});
|
||||
@ -168,11 +232,20 @@ public class ConfigurationUIController {
|
||||
}
|
||||
|
||||
private Node buildTextField(ConfigNode node, String settingName, Serializable value, String validationPattern) {
|
||||
return new TextField(String.valueOf(value));
|
||||
TextField widget = new TextField(String.valueOf(value));
|
||||
widget.textProperty().addListener((e) -> {
|
||||
node.setFieldValue(settingName, widget.getText());
|
||||
});
|
||||
return widget;
|
||||
}
|
||||
|
||||
private Node buildBooleanField(ConfigNode node, String settingName, Serializable value) {
|
||||
return new CheckBox();
|
||||
CheckBox widget = new CheckBox();
|
||||
widget.setSelected(value.equals(Boolean.TRUE));
|
||||
widget.selectedProperty().addListener((e) -> {
|
||||
node.setFieldValue(settingName, widget.isSelected());
|
||||
});
|
||||
return widget;
|
||||
}
|
||||
|
||||
private Node buildFileSelectionField(ConfigNode node, String settingName, Serializable value) {
|
||||
@ -182,7 +255,8 @@ public class ConfigurationUIController {
|
||||
private Node buildDynamicSelectComponent(ConfigNode node, String settingName, Serializable value) {
|
||||
try {
|
||||
DynamicSelection sel = (DynamicSelection) node.subject.getClass().getField(settingName).get(node.subject);
|
||||
ComboBox widget = new ComboBox(FXCollections.observableList(new ArrayList(sel.getSelections().keySet())));
|
||||
ChoiceBox widget = new ChoiceBox(FXCollections.observableList(new ArrayList(sel.getSelections().keySet())));
|
||||
widget.setMinWidth(175.0);
|
||||
widget.setConverter(new StringConverter() {
|
||||
@Override
|
||||
public String toString(Object object) {
|
||||
@ -191,9 +265,18 @@ public class ConfigurationUIController {
|
||||
|
||||
@Override
|
||||
public Object fromString(String string) {
|
||||
return null;
|
||||
return sel.findValueByMatch(string);
|
||||
}
|
||||
});
|
||||
Object selected = value == null ? null : widget.getConverter().fromString(String.valueOf(value));
|
||||
if (selected == null) {
|
||||
widget.getSelectionModel().selectFirst();
|
||||
} else {
|
||||
widget.setValue(selected);
|
||||
}
|
||||
widget.valueProperty().addListener((Observable e) -> {
|
||||
node.setFieldValue(settingName, widget.getConverter().toString(widget.getValue()));
|
||||
});
|
||||
return widget;
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
|
||||
Logger.getLogger(ConfigurationUIController.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
@ -45,18 +45,21 @@ public abstract class DynamicSelection<T> implements ISelection<T> {
|
||||
@Override
|
||||
public void setValue(T value) {currentValue = value;}
|
||||
|
||||
@Override
|
||||
public void setValueByMatch(String search) {
|
||||
setValue(findValueByMatch(search));
|
||||
}
|
||||
|
||||
public T findValueByMatch(String search) {
|
||||
Map<? extends T, String> selections = getSelections();
|
||||
String match = Utility.findBestMatch(search, selections.values());
|
||||
if (match != null) {
|
||||
for (T key : selections.keySet()) {
|
||||
if (selections.get(key).equals(match)) {
|
||||
setValue(key);
|
||||
return;
|
||||
return key;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setValue(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
BIN
src/main/resources/jace/data/icon_exclaim.gif
Normal file
BIN
src/main/resources/jace/data/icon_exclaim.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 171 B |
Loading…
Reference in New Issue
Block a user