Add random temperature updates
This commit is contained in:
@@ -8,8 +8,7 @@
|
|||||||
<?import javafx.scene.control.TextField?>
|
<?import javafx.scene.control.TextField?>
|
||||||
<?import javafx.scene.layout.BorderPane?>
|
<?import javafx.scene.layout.BorderPane?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<SplitPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0"
|
<SplitPane xmlns:fx="http://javafx.com/fxml" prefHeight="400.0" prefWidth="600.0">
|
||||||
fx:controller="fr.uca.iut.clfreville2.gui.MainWindows">
|
|
||||||
<ListView fx:id="sensorsList" />
|
<ListView fx:id="sensorsList" />
|
||||||
<VBox alignment="TOP_CENTER">
|
<VBox alignment="TOP_CENTER">
|
||||||
<padding>
|
<padding>
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
package fr.uca.iut.clfreville2;
|
package fr.uca.iut.clfreville2;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.gui.FXMLUtils;
|
||||||
|
import fr.uca.iut.clfreville2.gui.MainWindows;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
@@ -10,7 +11,7 @@ public class MainApplication extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
Parent root = FXMLLoader.load(MainApplication.class.getResource("/windows/MainWindows.fxml"));
|
Parent root = FXMLUtils.load(MainApplication.class.getResource("/windows/MainWindows.fxml"), new MainWindows(primaryStage));
|
||||||
Scene scene = new Scene(root);
|
Scene scene = new Scene(root);
|
||||||
primaryStage.setScene(scene);
|
primaryStage.setScene(scene);
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
|
18
src/fr/uca/iut/clfreville2/gui/FXMLUtils.java
Normal file
18
src/fr/uca/iut/clfreville2/gui/FXMLUtils.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package fr.uca.iut.clfreville2.gui;
|
||||||
|
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public final class FXMLUtils {
|
||||||
|
|
||||||
|
private FXMLUtils() {}
|
||||||
|
|
||||||
|
public static Parent load(URL location, Object controller) throws IOException {
|
||||||
|
FXMLLoader loader = new FXMLLoader(location);
|
||||||
|
loader.setController(controller);
|
||||||
|
return loader.load();
|
||||||
|
}
|
||||||
|
}
|
@@ -3,25 +3,27 @@ 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.StandardImageSupplier;
|
import fr.uca.iut.clfreville2.gui.image.StandardImageSupplier;
|
||||||
import fr.uca.iut.clfreville2.gui.list.NameableListCell;
|
import fr.uca.iut.clfreville2.gui.list.NameableListCell;
|
||||||
|
import fr.uca.iut.clfreville2.gui.thread.Ticker;
|
||||||
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;
|
||||||
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||||
import fr.uca.iut.clfreville2.persistence.StubSensorRegistryLoader;
|
import fr.uca.iut.clfreville2.persistence.StubSensorRegistryLoader;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.control.Slider;
|
import javafx.scene.control.Slider;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
public class MainWindows {
|
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 ModalFactory modalFactory;
|
private final Ticker ticker;
|
||||||
|
private final ModalFactory modalFactory;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<Sensor> sensorsList;
|
private ListView<Sensor> sensorsList;
|
||||||
@@ -38,13 +40,20 @@ public class MainWindows {
|
|||||||
@FXML
|
@FXML
|
||||||
private Button visualizeBtn;
|
private Button visualizeBtn;
|
||||||
|
|
||||||
|
public MainWindows(Stage primaryStage) {
|
||||||
|
this.ticker = new Ticker(registry);
|
||||||
|
this.modalFactory = new ModalFactory(primaryStage);
|
||||||
|
primaryStage.setOnHidden((e) -> ticker.interrupt());
|
||||||
|
ticker.start();
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void onChangeClick() {
|
public void onChangeClick() {
|
||||||
Sensor selected = getSelectedSensor();
|
Sensor selected = getSelectedSensor();
|
||||||
if (!(selected instanceof ManualSensor sensor)) {
|
if (!(selected instanceof ManualSensor sensor)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getModalFactory().createModal(selected, root -> {
|
modalFactory.createModal(selected, root -> {
|
||||||
Slider slider = new Slider(-5, 30, sensor.getTemperature());
|
Slider slider = new Slider(-5, 30, sensor.getTemperature());
|
||||||
slider.setBlockIncrement(0.5);
|
slider.setBlockIncrement(0.5);
|
||||||
slider.setMajorTickUnit(0.5);
|
slider.setMajorTickUnit(0.5);
|
||||||
@@ -61,7 +70,7 @@ public class MainWindows {
|
|||||||
if (selected == null) {
|
if (selected == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getModalFactory().createModal(selected, root -> {
|
modalFactory.createModal(selected, root -> {
|
||||||
ImageView imageView = new ImageView();
|
ImageView imageView = new ImageView();
|
||||||
imageView.setPreserveRatio(true);
|
imageView.setPreserveRatio(true);
|
||||||
imageView.setFitHeight(200);
|
imageView.setFitHeight(200);
|
||||||
@@ -107,15 +116,4 @@ public class MainWindows {
|
|||||||
private Sensor getSelectedSensor() {
|
private Sensor getSelectedSensor() {
|
||||||
return sensorsList.getSelectionModel().getSelectedItem();
|
return sensorsList.getSelectionModel().getSelectedItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModalFactory getModalFactory() {
|
|
||||||
if (modalFactory == null) {
|
|
||||||
Scene scene = sensorsList.getScene();
|
|
||||||
if (scene == null) {
|
|
||||||
throw new IllegalStateException("No scene found");
|
|
||||||
}
|
|
||||||
modalFactory = new ModalFactory(scene.getWindow());
|
|
||||||
}
|
|
||||||
return modalFactory;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
40
src/fr/uca/iut/clfreville2/gui/thread/Ticker.java
Normal file
40
src/fr/uca/iut/clfreville2/gui/thread/Ticker.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package fr.uca.iut.clfreville2.gui.thread;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
|
||||||
|
public class Ticker extends Thread {
|
||||||
|
|
||||||
|
private final Tickable tickable;
|
||||||
|
private final IntegerProperty millisPerTick = new SimpleIntegerProperty(250);
|
||||||
|
|
||||||
|
public Ticker(Tickable tickable) {
|
||||||
|
this.tickable = tickable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(millisPerTick.getValue());
|
||||||
|
Platform.runLater(tickable::tick);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMillisPerTick() {
|
||||||
|
return millisPerTick.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMillisPerTick(int millisPerTick) {
|
||||||
|
this.millisPerTick.set(millisPerTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegerProperty millisPerTickProperty() {
|
||||||
|
return millisPerTick;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,10 @@
|
|||||||
package fr.uca.iut.clfreville2.model;
|
package fr.uca.iut.clfreville2.model;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||||
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
|
import fr.uca.iut.clfreville2.model.sensor.ManualSensor;
|
||||||
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
import fr.uca.iut.clfreville2.model.sensor.Sensor;
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
|
||||||
|
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||||
import javafx.beans.property.ListProperty;
|
import javafx.beans.property.ListProperty;
|
||||||
import javafx.beans.property.ReadOnlyListProperty;
|
import javafx.beans.property.ReadOnlyListProperty;
|
||||||
import javafx.beans.property.SimpleListProperty;
|
import javafx.beans.property.SimpleListProperty;
|
||||||
@@ -14,7 +17,7 @@ import java.util.function.IntSupplier;
|
|||||||
/**
|
/**
|
||||||
* A registry class to hold thermal sensors instances.
|
* A registry class to hold thermal sensors instances.
|
||||||
*/
|
*/
|
||||||
public class SensorRegistry implements Iterable<Sensor> {
|
public class SensorRegistry implements Tickable, Iterable<Sensor> {
|
||||||
|
|
||||||
private final IntSupplier nextIdSupplier = new SequenceIntSupplier();
|
private final IntSupplier nextIdSupplier = new SequenceIntSupplier();
|
||||||
private final ObservableList<Sensor> sensors = FXCollections.observableArrayList();
|
private final ObservableList<Sensor> sensors = FXCollections.observableArrayList();
|
||||||
@@ -30,6 +33,17 @@ public class SensorRegistry implements Iterable<Sensor> {
|
|||||||
return register(new ManualSensor(nextIdSupplier.getAsInt(), name));
|
return register(new ManualSensor(nextIdSupplier.getAsInt(), name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new auto sensor and add it to the registry.
|
||||||
|
*
|
||||||
|
* @param name The name of the sensor.
|
||||||
|
* @param strategy The strategy to update the sensor.
|
||||||
|
* @return The sensor created.
|
||||||
|
*/
|
||||||
|
public AutoSensor createAuto(String name, AutoUpdateStrategy strategy) {
|
||||||
|
return register(new AutoSensor(nextIdSupplier.getAsInt(), name, strategy));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new sensor to the registry.
|
* Add a new sensor to the registry.
|
||||||
*
|
*
|
||||||
@@ -60,6 +74,15 @@ public class SensorRegistry implements Iterable<Sensor> {
|
|||||||
return sensorsList;
|
return sensorsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
for (Sensor sensor : sensors) {
|
||||||
|
if (sensor instanceof Tickable tickable) {
|
||||||
|
tickable.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Sensor> iterator() {
|
public Iterator<Sensor> iterator() {
|
||||||
return getSensors().iterator();
|
return getSensors().iterator();
|
||||||
|
41
src/fr/uca/iut/clfreville2/model/sensor/AutoSensor.java
Normal file
41
src/fr/uca/iut/clfreville2/model/sensor/AutoSensor.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package fr.uca.iut.clfreville2.model.sensor;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.auto.AutoUpdateStrategy;
|
||||||
|
import fr.uca.iut.clfreville2.model.shared.Tickable;
|
||||||
|
import javafx.beans.property.DoubleProperty;
|
||||||
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||||
|
import javafx.beans.property.SimpleDoubleProperty;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sensor that automatically create new temperatures.
|
||||||
|
*/
|
||||||
|
public class AutoSensor extends Sensor implements Tickable {
|
||||||
|
|
||||||
|
private final DoubleProperty temperature = new SimpleDoubleProperty();
|
||||||
|
private AutoUpdateStrategy updateStrategy;
|
||||||
|
|
||||||
|
public AutoSensor(int id, String name, AutoUpdateStrategy updateStrategy) {
|
||||||
|
super(id, name);
|
||||||
|
this.updateStrategy = requireNonNull(updateStrategy, "update strategy");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
temperature.set(updateStrategy.nextValue(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReadOnlyDoubleProperty temperatureProperty() {
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoUpdateStrategy getUpdateStrategy() {
|
||||||
|
return updateStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateStrategy(AutoUpdateStrategy updateStrategy) {
|
||||||
|
this.updateStrategy = requireNonNull(updateStrategy, "update strategy");
|
||||||
|
}
|
||||||
|
}
|
@@ -2,16 +2,13 @@ package fr.uca.iut.clfreville2.model.sensor;
|
|||||||
|
|
||||||
import fr.uca.iut.clfreville2.model.shared.TemperatureHolder;
|
import fr.uca.iut.clfreville2.model.shared.TemperatureHolder;
|
||||||
import fr.uca.iut.clfreville2.model.shared.ObservableIdentifiable;
|
import fr.uca.iut.clfreville2.model.shared.ObservableIdentifiable;
|
||||||
import javafx.beans.binding.DoubleBinding;
|
|
||||||
import javafx.beans.binding.DoubleExpression;
|
import javafx.beans.binding.DoubleExpression;
|
||||||
import javafx.beans.binding.StringExpression;
|
import javafx.beans.binding.StringExpression;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
|
||||||
import javafx.beans.property.ReadOnlyIntegerProperty;
|
import javafx.beans.property.ReadOnlyIntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.beans.value.ObservableDoubleValue;
|
|
||||||
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
@@ -0,0 +1,15 @@
|
|||||||
|
package fr.uca.iut.clfreville2.model.sensor.auto;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface AutoUpdateStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the next value of the sensor.
|
||||||
|
*
|
||||||
|
* @param currentState The current state of the sensor.
|
||||||
|
* @return The next value of the sensor.
|
||||||
|
*/
|
||||||
|
double nextValue(AutoSensor currentState);
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.uca.iut.clfreville2.model.sensor.auto;
|
||||||
|
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.AutoSensor;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class RandomVariationStrategy implements AutoUpdateStrategy {
|
||||||
|
|
||||||
|
private final Random random;
|
||||||
|
private final int maxVariation;
|
||||||
|
|
||||||
|
public RandomVariationStrategy(int maxVariation) {
|
||||||
|
this(new Random(), maxVariation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RandomVariationStrategy(Random random, int maxVariation) {
|
||||||
|
this.random = random;
|
||||||
|
this.maxVariation = maxVariation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double nextValue(AutoSensor currentState) {
|
||||||
|
return currentState.getTemperature() + random.nextInt(maxVariation * 2) - maxVariation;
|
||||||
|
}
|
||||||
|
}
|
@@ -31,5 +31,12 @@ public interface ObservableIdentifiable extends Identifiable {
|
|||||||
* @return The display name.
|
* @return The display name.
|
||||||
* @see #getDisplayName()
|
* @see #getDisplayName()
|
||||||
*/
|
*/
|
||||||
StringExpression displayNameExpression();
|
default StringExpression displayNameExpression() {
|
||||||
|
return nameProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String getDisplayName() {
|
||||||
|
return displayNameExpression().get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
10
src/fr/uca/iut/clfreville2/model/shared/Tickable.java
Normal file
10
src/fr/uca/iut/clfreville2/model/shared/Tickable.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package fr.uca.iut.clfreville2.model.shared;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Tickable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick the current object.
|
||||||
|
*/
|
||||||
|
void tick();
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
package fr.uca.iut.clfreville2.persistence;
|
package fr.uca.iut.clfreville2.persistence;
|
||||||
|
|
||||||
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
import fr.uca.iut.clfreville2.model.SensorRegistry;
|
||||||
|
import fr.uca.iut.clfreville2.model.sensor.auto.RandomVariationStrategy;
|
||||||
|
|
||||||
public class StubSensorRegistryLoader implements SensorRegistryLoader {
|
public class StubSensorRegistryLoader implements SensorRegistryLoader {
|
||||||
@Override
|
@Override
|
||||||
@@ -8,7 +9,7 @@ public class StubSensorRegistryLoader implements SensorRegistryLoader {
|
|||||||
SensorRegistry registry = new SensorRegistry();
|
SensorRegistry registry = new SensorRegistry();
|
||||||
registry.createManual("Sensor 1");
|
registry.createManual("Sensor 1");
|
||||||
registry.createManual("Sensor 2");
|
registry.createManual("Sensor 2");
|
||||||
registry.createManual("Sensor 3");
|
registry.createAuto("Sensor 3", new RandomVariationStrategy(5));
|
||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user