From ded77eeb6659679b31a5bf721a64246b717f9369 Mon Sep 17 00:00:00 2001 From: clfreville2 Date: Tue, 10 Jan 2023 16:58:56 +0100 Subject: [PATCH] Use a tree view --- resources/images/captor_icon.png | Bin 0 -> 2205 bytes resources/images/multi_captor_icon.png | Bin 0 -> 2035 bytes resources/windows/MainWindows.fxml | 5 +- .../uca/iut/clfreville2/gui/MainWindows.java | 61 +++++++++---- .../gui/image/SensorTypeImageSupplier.java | 24 +++++ .../clfreville2/gui/tree/SensorTreeCell.java | 31 +++++++ .../gui/tree/SensorTreeItemBridge.java | 82 ++++++++++++++++++ 7 files changed, 183 insertions(+), 20 deletions(-) create mode 100644 resources/images/captor_icon.png create mode 100644 resources/images/multi_captor_icon.png create mode 100644 src/fr/uca/iut/clfreville2/gui/image/SensorTypeImageSupplier.java create mode 100644 src/fr/uca/iut/clfreville2/gui/tree/SensorTreeCell.java create mode 100644 src/fr/uca/iut/clfreville2/gui/tree/SensorTreeItemBridge.java diff --git a/resources/images/captor_icon.png b/resources/images/captor_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6995fa231a75c2de034a28f1db7f37519c7e8963 GIT binary patch literal 2205 zcmV;O2x9k%P)Nj=+98^CY^A6b6hy}u(mEmb)rn-yFs&vt|hT}u=?ApqEg-UeVhfJFdGL1+{vSNJDzVZIlDJxeuTq01FqKoa)sgO)|X$K0HZf&Zml z74Tu(RRJHi+2%62o=PA&F>YZarOz*PjX4$2bMytg7f7_4BdF_`2OD%j69HsfM7WGFatLjl)AssJluZ(<^J z1cyeB`@HTGc?$@ILM2IqpN6_A8xu@_%9lIJ#kQH^rwQnd#VU!hLnTkU{a#n6?CS3yUDDm%U6hZIT-M#)T@;MR z7t21s$NdZlzmt7L{75Jix+b&#v{#4{v<1ZFlIwgiB_5PxdWYhlHOTn0-M;W&?+g#G zUA}bbxtYifoji>9PY+u-nVi@HX$-l)5UW$kq3ZNNor3)hchS^0y$xq98UwI;6jx{rV%KVgm8c3(!fmsF1U z)QkeAMz}n68X{GC$STfE06s6ZC&|ujCTL#&U?mH2kU`gF6F}ev%=DMlfvvY$MId$o zNTutjci3QYAR|rF$Gx`K6e74Ms%FEr8wpvodcI9Ts?Tl2cEr`o}& z%|>1_J4pO`RbYE505p0XAuwJ`H?yl}aHPRRjb29xz_8TcR-8=MO%nh%mMLWzqcRkN zZj`ZM(97oas=#(P!0YlLKb0D84Z1a!i0Bo$T@&>2j1D78I}3}e^gffaNDz@Cz#yuU zu^^)_UC_84vpn6Az#Zw_>0AI{2vn)TbV_MwVR20h07}&$Ls^`NxI)G{@U8{eaL$JO zWFNAoYhs+0n*^g$iKUEo!t^mRMwM6Y1LNj7lfwjK|30i~_;d9n^`B=TF`2Psh@TTq;4F&In$jU=kP1OG^MVDLX|X zwUZDWlraqPN%Qix<%`|`Fq@rfLK9?d)(E&&sm0W<5{7z^V%_3u39##i+6nM8v$d+0 z*>D(u_2@wS8EZGXbEm=J`yj2Vxr{+S{QK|Qh5#TMjh2G=4ypMPQe#I=(9?5f0iaIL zl(G#>6Hr_0i~`D|n?DeVUvC1J%XJB$!&1A`Hos!M2@dal@*oKJKw6Zt*sq)%+i8Mv z);41DJHjM6!asaIpLL_Od5KR$I#@9fuCI4kJkzrf5fkHxTuBFiPR7jKA!7nR9u9{W zn)uZ}wErB;w*d4C03(BV9}(aA>fZL&ef#$5z|`u`_?8@G81z%MrdXrY%;2c}-5nen z*~CP@ked5_9!CQa8B+p8FcN-^i53h;T{&of~Sm>x=8IRA*;)*l_+3}A)i zGEzdcBg1C=U>fNU0~nWF z*BB}44241k|4f=`Cr3xiK>D*#$&aOUb+$5XMgeuz)j=jan&G}FDT=>dAf8!m-h{CY zjE~AbBHD3nt!u`QT#+3+#`b}McgsIGval8ohZlA+ f&*}Gz{|oysoFe9_R>+~|00000NkvXXu0mjf;|&pW literal 0 HcmV?d00001 diff --git a/resources/images/multi_captor_icon.png b/resources/images/multi_captor_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9dc6b01ca77ae59a705e063a2424313ab4e28e GIT binary patch literal 2035 zcmVHfP}U>zCIuw9Y>vE3egX=PDegiAVNh(X-5SNARSD~qfKcZod}nE zVbTCCCC_`$S$-h*=A6rYA|cap&735A?e+MtbN1S6?H%}#lZ-b2fTgwTm#NC)zQKVl zt^2n1XQJyFD^MAb*svGTNqKoWeZbaCl#MY0l{PJS@<|Uc2|!e*WU4>z0sOD@p${N& z4s6_LRJL9EDk4>g^x9$L_eXbcZo7@x(xQZ4pz^KDyAXL1_&TcJGfb;>X-)lS#{z_^ zO`!dC0v#vHGu4e7Kvmtk<-p@H>}*@~xtjr)nuLk@1>{c3e?L>rxB=L<+@C;x?t_ng ze^RDSQjv&YW_dBaxx<<2#tlG3^AhjbYgx1lc)Krmwfp<`I+dC z>n>EevcU(&7NQ-2mPt74N150d*Gg=d%(fxR#Z=-Za%FA(3RSJR!X1rmO&g<2ZCnGm zHrRh^LT*k#VP=#m@|Re-Pt|P51?$fuc=P2-FR(o_H?B*lb>Fsr%Q9D>>;?X<%F~B; zJ@-PaTwZuM5AXt@_EhKGxHoen#qkR_tAASpXb%RbOIY`zQf!E^ylmE8Z{8}~NdpLn zhUj?hRczae@&?|&^ljkTbRGEp{@j5ue@A5=fUWkQ+Wh`S6-7mtZx*zZk_KRUvdH%p zV~4|0UU+!;8^XAOq_rm)=zvA?B7 zqg8ff=lQKuUJPA-P&H{DRz1GH9MNAybzt7$(9nj+IAs#gxo>G~RC^9L#XonecW4tT zp9D}?IOWcZKLj>KoqOfyI;`IUt}h*BR-r%mD6lsX2HT)iVqUa568VG^R*LBTZuk2TaBGO`DVEF+lGbvF13;6x%E zM|U)~0H2FDmoxy6H=BWuNTN32}Kv_{ySI4>FUX+z1tO=fes}k4`P*PGd*l{*^ z1c;umRpkC;0VJa_sRLrO$K}M(hh6i~;?~fzoAq@=0E?ff{|Hc>5S%1WIsnPiX6IOy zxvnu>bjf4PN{KW9xdNzK^;D79(&NC#5-BJ&E~#Dj>tsetXUqryVF#XroDK82t>l)^x zJg=fJRMs`jzafCi+JNT_7>5`iD^W#n26$s419o)Old0S$Z6q@mcR)nGfi0a&Af^n6N_&TO#JmefJ z_DSbhP@iio{3lc2Q4FJAB;)_q*cfpusDi84Hw@!|YhL96=U9}EOnpaaw2%q!0QY60 zY}(Qp%WL;vSR}SCbFg}cuU7^!!lY0iX8|}l^6NukF*_0X-VC>d7{$7=nD^t+6$VS8s8Z6YZX;BOv`x5 z1s-fw)}{j<;KW;R`^%A@5&EumHpe21Kr)-Im1TwHW7-lEYA}qB?T8#YyF?le*to)pVh^n RzI*@x002ovPDHLkV1lma(~ - @@ -13,10 +12,11 @@ +
- + @@ -34,6 +34,7 @@ + diff --git a/src/fr/uca/iut/clfreville2/gui/MainWindows.java b/src/fr/uca/iut/clfreville2/gui/MainWindows.java index 436bd66..cd32ddb 100644 --- a/src/fr/uca/iut/clfreville2/gui/MainWindows.java +++ b/src/fr/uca/iut/clfreville2/gui/MainWindows.java @@ -1,10 +1,12 @@ package fr.uca.iut.clfreville2.gui; 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.list.NameableListCell; import fr.uca.iut.clfreville2.gui.table.WeightSpinnerTableCell; 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.binding.ToBooleanBinding; import fr.uca.iut.clfreville2.model.sensor.ManualSensor; @@ -16,12 +18,15 @@ import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; -import javafx.scene.control.ListView; import javafx.scene.control.Slider; import javafx.scene.control.Spinner; +import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; 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.text.Text; import javafx.stage.Stage; @@ -30,11 +35,12 @@ public class MainWindows { private final SensorRegistry registry = new StubSensorRegistryLoader().load(); private final ImageSupplier imageSupplier = new StandardImageSupplier(); + private final ImageSupplier imageTypeSupplier = new SensorTypeImageSupplier(); private final Ticker ticker; private final ModalFactory modalFactory; @FXML - private ListView sensorsList; + private TreeView sensorTree; @FXML private Text sensorId; @@ -51,6 +57,9 @@ public class MainWindows { @FXML private TableView sourcesView; + @FXML + private TableColumn sourceIcon; + @FXML private TableColumn sourceWeight; @@ -105,26 +114,26 @@ public class MainWindows { @FXML private void initialize() { - bindSensorList(); + bindSensorTree(); bindActiveButtons(); bindSources(); bindUpdate(); } @FXML - private void bindSensorList() { - sensorsList.setCellFactory(list -> new NameableListCell<>()); - sensorsList.itemsProperty().bind(registry.sensorsProperty()); - sensorsList.getSelectionModel().selectedItemProperty().addListener((list, oldValue, newValue) -> { - if (oldValue != null) { - sensorName.textProperty().unbindBidirectional(oldValue.nameProperty()); + private void bindSensorTree() { + sensorTree.setCellFactory(tree -> new SensorTreeCell(imageTypeSupplier)); + sensorTree.setRoot(SensorTreeItemBridge.create(registry)); + sensorTree.getSelectionModel().selectedItemProperty().addListener((list, oldValue, newValue) -> { + if (oldValue != null && oldValue.getValue() != null) { + sensorName.textProperty().unbindBidirectional(oldValue.getValue().nameProperty()); sourcesView.itemsProperty().unbind(); sourcesView.setItems(FXCollections.emptyObservableList()); } - if (newValue != null) { - sensorId.textProperty().bind(newValue.displayNameExpression()); - sensorName.textProperty().bindBidirectional(newValue.nameProperty()); - if (newValue instanceof VirtualSensor virtual) { + if (newValue != null && newValue.getValue() != null) { + sensorId.textProperty().bind(newValue.getValue().displayNameExpression()); + sensorName.textProperty().bindBidirectional(newValue.getValue().nameProperty()); + if (newValue.getValue() instanceof VirtualSensor virtual) { sourcesView.itemsProperty().bind(virtual.sourcesProperty()); } } else { @@ -137,16 +146,28 @@ public class MainWindows { @FXML private void bindActiveButtons() { changeBtn.visibleProperty().bind(new ToBooleanBinding<>( - sensorsList.getSelectionModel().selectedItemProperty(), - treeItem -> treeItem instanceof ManualSensor + sensorTree.getSelectionModel().selectedItemProperty(), + treeItem -> treeItem != null && treeItem.getValue() instanceof ManualSensor )); - visualizeBtn.visibleProperty().bind(sensorsList.getSelectionModel().selectedItemProperty().isNotNull()); + visualizeBtn.visibleProperty().bind(sensorTree.getSelectionModel().selectedItemProperty().isNotNull()); } @FXML private void bindSources() { sourceWeight.setCellValueFactory(cell -> new SimpleObjectProperty<>(cell.getValue())); 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()); } @@ -157,6 +178,10 @@ public class MainWindows { } private Sensor getSelectedSensor() { - return sensorsList.getSelectionModel().getSelectedItem(); + TreeItem selected = sensorTree.getSelectionModel().getSelectedItem(); + if (selected == null) { + return null; + } + return selected.getValue(); } } diff --git a/src/fr/uca/iut/clfreville2/gui/image/SensorTypeImageSupplier.java b/src/fr/uca/iut/clfreville2/gui/image/SensorTypeImageSupplier.java new file mode 100644 index 0000000..eb76350 --- /dev/null +++ b/src/fr/uca/iut/clfreville2/gui/image/SensorTypeImageSupplier.java @@ -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; + } +} diff --git a/src/fr/uca/iut/clfreville2/gui/tree/SensorTreeCell.java b/src/fr/uca/iut/clfreville2/gui/tree/SensorTreeCell.java new file mode 100644 index 0000000..bca915a --- /dev/null +++ b/src/fr/uca/iut/clfreville2/gui/tree/SensorTreeCell.java @@ -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 { + + 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); + } + } +} diff --git a/src/fr/uca/iut/clfreville2/gui/tree/SensorTreeItemBridge.java b/src/fr/uca/iut/clfreville2/gui/tree/SensorTreeItemBridge.java new file mode 100644 index 0000000..8e6e000 --- /dev/null +++ b/src/fr/uca/iut/clfreville2/gui/tree/SensorTreeItemBridge.java @@ -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 create(Sensor sensor) { + TreeItem item = new TreeItem<>(sensor); + if (sensor instanceof VirtualSensor virtual) { + addChildren(virtual.sourcesProperty(), item); + virtual.sourcesProperty().addListener(new ListChangeListener() { + @Override + public void onChanged(Change 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 create(SensorRegistry registry) { + TreeItem root = new TreeItem<>(); + for (Sensor sensor : registry) { + root.getChildren().add(create(sensor)); + } + registry.sensorsProperty().addListener(new ListChangeListener() { + @Override + public void onChanged(Change 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 sensors, TreeItem item) { + for (Sensor sensor : sensors) { + item.getChildren().add(create(sensor)); + } + } + + private static void addChildren(Iterable sources, TreeItem item) { + for (VirtualSensor.DataSource source : sources) { + item.getChildren().add(create(source.sensor())); + } + } + + private static void removeChildren(Iterable sources, TreeItem item) { + for (VirtualSensor.DataSource source : sources) { + item.getChildren().removeIf(child -> child.getValue().equals(source.sensor())); + } + } + + private static void removeSensors(Iterable sensors, TreeItem item) { + for (Sensor sensor : sensors) { + item.getChildren().removeIf(child -> child.getValue().equals(sensor)); + } + } +}