Use a tree view
This commit is contained in:
BIN
resources/images/captor_icon.png
Normal file
BIN
resources/images/captor_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/images/multi_captor_icon.png
Normal file
BIN
resources/images/multi_captor_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
<?import javafx.scene.control.SplitPane?>
|
<?import javafx.scene.control.SplitPane?>
|
||||||
<?import javafx.scene.control.ListView?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.text.Text?>
|
<?import javafx.scene.text.Text?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
@@ -13,10 +12,11 @@
|
|||||||
<?import javafx.scene.control.Spinner?>
|
<?import javafx.scene.control.Spinner?>
|
||||||
<?import javafx.scene.control.TableView?>
|
<?import javafx.scene.control.TableView?>
|
||||||
<?import javafx.scene.control.TableColumn?>
|
<?import javafx.scene.control.TableColumn?>
|
||||||
|
<?import javafx.scene.control.TreeView?>
|
||||||
<BorderPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
|
<BorderPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
|
||||||
<center>
|
<center>
|
||||||
<SplitPane>
|
<SplitPane>
|
||||||
<ListView fx:id="sensorsList" />
|
<TreeView fx:id="sensorTree" />
|
||||||
<VBox alignment="TOP_CENTER">
|
<VBox alignment="TOP_CENTER">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0"/>
|
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0"/>
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
<TableView fx:id="sourcesView">
|
<TableView fx:id="sourcesView">
|
||||||
<columns>
|
<columns>
|
||||||
<TableColumn fx:id="sourceWeight" text="Weight" />
|
<TableColumn fx:id="sourceWeight" text="Weight" />
|
||||||
|
<TableColumn fx:id="sourceIcon" text="Icon" />
|
||||||
<TableColumn fx:id="sourceId" text="Id" />
|
<TableColumn fx:id="sourceId" text="Id" />
|
||||||
</columns>
|
</columns>
|
||||||
</TableView>
|
</TableView>
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
package fr.uca.iut.clfreville2.gui;
|
package fr.uca.iut.clfreville2.gui;
|
||||||
|
|
||||||
import fr.uca.iut.clfreville2.gui.image.ImageSupplier;
|
import fr.uca.iut.clfreville2.gui.image.ImageSupplier;
|
||||||
|
import fr.uca.iut.clfreville2.gui.image.SensorTypeImageSupplier;
|
||||||
import fr.uca.iut.clfreville2.gui.image.StandardImageSupplier;
|
import fr.uca.iut.clfreville2.gui.image.StandardImageSupplier;
|
||||||
import fr.uca.iut.clfreville2.gui.list.NameableListCell;
|
|
||||||
import fr.uca.iut.clfreville2.gui.table.WeightSpinnerTableCell;
|
import fr.uca.iut.clfreville2.gui.table.WeightSpinnerTableCell;
|
||||||
import fr.uca.iut.clfreville2.gui.thread.Ticker;
|
import fr.uca.iut.clfreville2.gui.thread.Ticker;
|
||||||
|
import fr.uca.iut.clfreville2.gui.tree.SensorTreeCell;
|
||||||
|
import fr.uca.iut.clfreville2.gui.tree.SensorTreeItemBridge;
|
||||||
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
||||||
import fr.uca.iut.clfreville2.model.binding.ToBooleanBinding;
|
import fr.uca.iut.clfreville2.model.binding.ToBooleanBinding;
|
||||||
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
|
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
|
||||||
@@ -16,12 +18,15 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ListView;
|
|
||||||
import javafx.scene.control.Slider;
|
import javafx.scene.control.Slider;
|
||||||
import javafx.scene.control.Spinner;
|
import javafx.scene.control.Spinner;
|
||||||
|
import javafx.scene.control.TableCell;
|
||||||
import javafx.scene.control.TableColumn;
|
import javafx.scene.control.TableColumn;
|
||||||
import javafx.scene.control.TableView;
|
import javafx.scene.control.TableView;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.control.TreeItem;
|
||||||
|
import javafx.scene.control.TreeView;
|
||||||
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
@@ -30,11 +35,12 @@ public class MainWindows {
|
|||||||
|
|
||||||
private final SensorRegistry registry = new StubSensorRegistryLoader().load();
|
private final SensorRegistry registry = new StubSensorRegistryLoader().load();
|
||||||
private final ImageSupplier imageSupplier = new StandardImageSupplier();
|
private final ImageSupplier imageSupplier = new StandardImageSupplier();
|
||||||
|
private final ImageSupplier imageTypeSupplier = new SensorTypeImageSupplier();
|
||||||
private final Ticker ticker;
|
private final Ticker ticker;
|
||||||
private final ModalFactory modalFactory;
|
private final ModalFactory modalFactory;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<Sensor> sensorsList;
|
private TreeView<Sensor> sensorTree;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Text sensorId;
|
private Text sensorId;
|
||||||
@@ -51,6 +57,9 @@ public class MainWindows {
|
|||||||
@FXML
|
@FXML
|
||||||
private TableView<VirtualSensor.DataSource> sourcesView;
|
private TableView<VirtualSensor.DataSource> sourcesView;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TableColumn<VirtualSensor.DataSource, Sensor> sourceIcon;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TableColumn<VirtualSensor.DataSource, VirtualSensor.DataSource> sourceWeight;
|
private TableColumn<VirtualSensor.DataSource, VirtualSensor.DataSource> sourceWeight;
|
||||||
|
|
||||||
@@ -105,26 +114,26 @@ public class MainWindows {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
bindSensorList();
|
bindSensorTree();
|
||||||
bindActiveButtons();
|
bindActiveButtons();
|
||||||
bindSources();
|
bindSources();
|
||||||
bindUpdate();
|
bindUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void bindSensorList() {
|
private void bindSensorTree() {
|
||||||
sensorsList.setCellFactory(list -> new NameableListCell<>());
|
sensorTree.setCellFactory(tree -> new SensorTreeCell(imageTypeSupplier));
|
||||||
sensorsList.itemsProperty().bind(registry.sensorsProperty());
|
sensorTree.setRoot(SensorTreeItemBridge.create(registry));
|
||||||
sensorsList.getSelectionModel().selectedItemProperty().addListener((list, oldValue, newValue) -> {
|
sensorTree.getSelectionModel().selectedItemProperty().addListener((list, oldValue, newValue) -> {
|
||||||
if (oldValue != null) {
|
if (oldValue != null && oldValue.getValue() != null) {
|
||||||
sensorName.textProperty().unbindBidirectional(oldValue.nameProperty());
|
sensorName.textProperty().unbindBidirectional(oldValue.getValue().nameProperty());
|
||||||
sourcesView.itemsProperty().unbind();
|
sourcesView.itemsProperty().unbind();
|
||||||
sourcesView.setItems(FXCollections.emptyObservableList());
|
sourcesView.setItems(FXCollections.emptyObservableList());
|
||||||
}
|
}
|
||||||
if (newValue != null) {
|
if (newValue != null && newValue.getValue() != null) {
|
||||||
sensorId.textProperty().bind(newValue.displayNameExpression());
|
sensorId.textProperty().bind(newValue.getValue().displayNameExpression());
|
||||||
sensorName.textProperty().bindBidirectional(newValue.nameProperty());
|
sensorName.textProperty().bindBidirectional(newValue.getValue().nameProperty());
|
||||||
if (newValue instanceof VirtualSensor virtual) {
|
if (newValue.getValue() instanceof VirtualSensor virtual) {
|
||||||
sourcesView.itemsProperty().bind(virtual.sourcesProperty());
|
sourcesView.itemsProperty().bind(virtual.sourcesProperty());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -137,16 +146,28 @@ public class MainWindows {
|
|||||||
@FXML
|
@FXML
|
||||||
private void bindActiveButtons() {
|
private void bindActiveButtons() {
|
||||||
changeBtn.visibleProperty().bind(new ToBooleanBinding<>(
|
changeBtn.visibleProperty().bind(new ToBooleanBinding<>(
|
||||||
sensorsList.getSelectionModel().selectedItemProperty(),
|
sensorTree.getSelectionModel().selectedItemProperty(),
|
||||||
treeItem -> treeItem instanceof ManualSensor
|
treeItem -> treeItem != null && treeItem.getValue() instanceof ManualSensor
|
||||||
));
|
));
|
||||||
visualizeBtn.visibleProperty().bind(sensorsList.getSelectionModel().selectedItemProperty().isNotNull());
|
visualizeBtn.visibleProperty().bind(sensorTree.getSelectionModel().selectedItemProperty().isNotNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void bindSources() {
|
private void bindSources() {
|
||||||
sourceWeight.setCellValueFactory(cell -> new SimpleObjectProperty<>(cell.getValue()));
|
sourceWeight.setCellValueFactory(cell -> new SimpleObjectProperty<>(cell.getValue()));
|
||||||
sourceWeight.setCellFactory(cell -> new WeightSpinnerTableCell());
|
sourceWeight.setCellFactory(cell -> new WeightSpinnerTableCell());
|
||||||
|
sourceIcon.setCellValueFactory(cell -> new SimpleObjectProperty<>(cell.getValue().sensor()));
|
||||||
|
sourceIcon.setCellFactory(cell -> new TableCell<>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Sensor item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (empty) {
|
||||||
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
setGraphic(new ImageView(imageTypeSupplier.apply(item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
sourceId.setCellValueFactory(cell -> cell.getValue().sensor().idProperty().asString());
|
sourceId.setCellValueFactory(cell -> cell.getValue().sensor().idProperty().asString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +178,10 @@ public class MainWindows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Sensor getSelectedSensor() {
|
private Sensor getSelectedSensor() {
|
||||||
return sensorsList.getSelectionModel().getSelectedItem();
|
TreeItem<Sensor> selected = sensorTree.getSelectionModel().getSelectedItem();
|
||||||
|
if (selected == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return selected.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
package fr.uca.iut.clfreville2.gui.image;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.VirtualSensor;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
|
||||||
|
public class SensorTypeImageSupplier implements ImageSupplier {
|
||||||
|
|
||||||
|
private final Image simpleIcon;
|
||||||
|
private final Image multiIcon;
|
||||||
|
|
||||||
|
public SensorTypeImageSupplier() {
|
||||||
|
simpleIcon = new Image("/images/captor_icon.png");
|
||||||
|
multiIcon = new Image("/images/multi_captor_icon.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Image apply(Sensor sensor) {
|
||||||
|
if (sensor instanceof VirtualSensor) {
|
||||||
|
return multiIcon;
|
||||||
|
}
|
||||||
|
return simpleIcon;
|
||||||
|
}
|
||||||
|
}
|
31
src/fr/uca/iut/clfreville2/gui/tree/SensorTreeCell.java
Normal file
31
src/fr/uca/iut/clfreville2/gui/tree/SensorTreeCell.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package fr.uca.iut.clfreville2.gui.tree;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.gui.image.ImageSupplier;
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||||
|
import javafx.scene.control.TreeCell;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
|
||||||
|
public class SensorTreeCell extends TreeCell<Sensor> {
|
||||||
|
|
||||||
|
private final ImageView imageView = new ImageView();
|
||||||
|
|
||||||
|
private final ImageSupplier imageSupplier;
|
||||||
|
|
||||||
|
public SensorTreeCell(ImageSupplier imageSupplier) {
|
||||||
|
this.imageSupplier = imageSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Sensor item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (empty || item == null) {
|
||||||
|
textProperty().unbind();
|
||||||
|
textProperty().setValue(null);
|
||||||
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
imageView.setImage(imageSupplier.apply(item));
|
||||||
|
textProperty().bind(item.displayNameExpression());
|
||||||
|
setGraphic(imageView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,82 @@
|
|||||||
|
package fr.uca.iut.clfreville2.gui.tree;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.VirtualSensor;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.scene.control.TreeItem;
|
||||||
|
|
||||||
|
public final class SensorTreeItemBridge {
|
||||||
|
|
||||||
|
private SensorTreeItemBridge() {}
|
||||||
|
|
||||||
|
public static TreeItem<Sensor> create(Sensor sensor) {
|
||||||
|
TreeItem<Sensor> item = new TreeItem<>(sensor);
|
||||||
|
if (sensor instanceof VirtualSensor virtual) {
|
||||||
|
addChildren(virtual.sourcesProperty(), item);
|
||||||
|
virtual.sourcesProperty().addListener(new ListChangeListener<VirtualSensor.DataSource>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(Change<? extends VirtualSensor.DataSource> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasPermutated()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
} else if (change.wasUpdated()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
} else {
|
||||||
|
addChildren(change.getAddedSubList(), item);
|
||||||
|
removeChildren(change.getRemoved(), item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TreeItem<Sensor> create(SensorRegistry registry) {
|
||||||
|
TreeItem<Sensor> root = new TreeItem<>();
|
||||||
|
for (Sensor sensor : registry) {
|
||||||
|
root.getChildren().add(create(sensor));
|
||||||
|
}
|
||||||
|
registry.sensorsProperty().addListener(new ListChangeListener<Sensor>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(Change<? extends Sensor> change) {
|
||||||
|
while (change.next()) {
|
||||||
|
if (change.wasPermutated()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
} else if (change.wasUpdated()) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
} else {
|
||||||
|
addSensors(change.getAddedSubList(), root);
|
||||||
|
removeSensors(change.getRemoved(), root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addSensors(Iterable<? extends Sensor> sensors, TreeItem<Sensor> item) {
|
||||||
|
for (Sensor sensor : sensors) {
|
||||||
|
item.getChildren().add(create(sensor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addChildren(Iterable<? extends VirtualSensor.DataSource> sources, TreeItem<Sensor> item) {
|
||||||
|
for (VirtualSensor.DataSource source : sources) {
|
||||||
|
item.getChildren().add(create(source.sensor()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeChildren(Iterable<? extends VirtualSensor.DataSource> sources, TreeItem<Sensor> item) {
|
||||||
|
for (VirtualSensor.DataSource source : sources) {
|
||||||
|
item.getChildren().removeIf(child -> child.getValue().equals(source.sensor()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeSensors(Iterable<? extends Sensor> sensors, TreeItem<Sensor> item) {
|
||||||
|
for (Sensor sensor : sensors) {
|
||||||
|
item.getChildren().removeIf(child -> child.getValue().equals(sensor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user