vac to kotlin

This commit is contained in:
Alexander Nozik 2017-06-04 22:42:47 +03:00
parent 9241177d40
commit 04b3dc9fc2
18 changed files with 207 additions and 229 deletions

View File

@ -15,7 +15,6 @@
*/
package inr.numass.control.msp
import hep.dataforge.control.connections.Roles
import hep.dataforge.control.devices.DeviceFactory
import hep.dataforge.meta.Meta
import inr.numass.control.DeviceViewConnection
@ -28,9 +27,7 @@ import javafx.stage.Stage
class MspApp : NumassControlApplication<MspDevice>() {
override fun buildView(device: MspDevice): DeviceViewConnection<MspDevice> {
return MspViewConnection().apply {
device.connect(this, Roles.VIEW_ROLE)
}
return MspViewConnection()
}
override val deviceFactory: DeviceFactory = MspDeviceFactory()

View File

@ -33,19 +33,18 @@ import hep.dataforge.values.Value
import inr.numass.control.DeviceViewConnection
import inr.numass.control.deviceStateIndicator
import inr.numass.control.deviceStateToggle
import inr.numass.control.switch
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.collections.MapChangeListener
import javafx.geometry.Insets
import javafx.geometry.Orientation
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.control.Alert
import javafx.scene.control.ToggleButton
import javafx.scene.layout.Priority
import javafx.scene.layout.VBox
import javafx.scene.paint.Paint
import org.controlsfx.control.ToggleSwitch
import tornadofx.*
/**
@ -53,8 +52,7 @@ import tornadofx.*
* @author darksnake
*/
class MspViewConnection : DeviceViewConnection<MspDevice>(), DeviceListener, NamedValueListener {
private val mspView by lazy { MspView() }
class MspViewConnection() : DeviceViewConnection<MspDevice>(), DeviceListener, NamedValueListener {
private val table = FXCollections.observableHashMap<String, Value>()
@ -64,11 +62,8 @@ class MspViewConnection : DeviceViewConnection<MspDevice>(), DeviceListener, Nam
}
}
override fun getFXNode(): Node {
if (!isOpen) {
throw RuntimeException("Not connected!")
}
return mspView.root;
override fun buildView(): View {
return MspView();
}
override fun pushValue(valueName: String, value: Value) {
@ -144,12 +139,12 @@ class MspViewConnection : DeviceViewConnection<MspDevice>(), DeviceListener, Nam
disableProperty()
.bind(getBooleanStateBinding(PortSensor.CONNECTED_STATE).not())
}
add(ToggleSwitch().apply {
switch {
padding = Insets(5.0, 0.0, 0.0, 0.0)
disableProperty()
.bind(getStateBinding(PortSensor.CONNECTED_STATE).booleanBinding { !it!!.booleanValue() })
bindBooleanToState("filamentOn", selectedProperty())
})
}
deviceStateIndicator(this@MspViewConnection, "filamentStatus", false) {
when (it.stringValue()) {
"ON" -> Paint.valueOf("red")

View File

@ -14,6 +14,7 @@ import javafx.beans.binding.ObjectBinding
import javafx.beans.property.BooleanProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.geometry.Pos
import javafx.scene.Node
import javafx.scene.Parent
import javafx.scene.layout.HBox
import javafx.scene.layout.Priority
@ -23,24 +24,44 @@ import java.util.*
/**
* Created by darksnake on 14-May-17.
*/
abstract class DeviceViewConnection<D : Device> : Component(), Connection<D>, DeviceListener, FXObject {
abstract class DeviceViewConnection<D : Device>() : Component(), Connection<D>, DeviceListener, FXObject {
private val bindings = HashMap<String, ObjectBinding<Value>>()
val deviceProperty = SimpleObjectProperty<D>()
var device by deviceProperty
var device: D by singleAssign()
val viewProperty = SimpleObjectProperty<View>(this, "view", null)
var view: View? by viewProperty
override fun isOpen(): Boolean {
return this.device != null
return this.view != null
}
override fun open(device: D) {
if(!isOpen) {
this.device = device
this.view = buildView();
} else{
log.warning("Connection already opened")
}
}
override fun close() {
this.device = null
view?.close()
this.view = null
}
override fun getFXNode(): Node {
if (view == null) {
throw RuntimeException("Connection not opened");
} else {
return view!!.root;
}
}
abstract fun buildView(): View;
/**
* Get binding for a given device state
@ -53,7 +74,7 @@ abstract class DeviceViewConnection<D : Device> : Component(), Connection<D>, De
object : ObjectBinding<Value>() {
override fun computeValue(): Value {
if (isOpen) {
return device.getState(stateName)
return device!!.getState(stateName)
} else {
return Value.NULL
}
@ -82,7 +103,7 @@ abstract class DeviceViewConnection<D : Device> : Component(), Connection<D>, De
property.addListener { observable, oldValue, newValue ->
if (isOpen && oldValue != newValue) {
runAsync {
device.setState(state, newValue).get().booleanValue();
device!!.setState(state, newValue).get().booleanValue();
} ui {
property.set(it)
}
@ -107,7 +128,7 @@ abstract class DeviceViewConnection<D : Device> : Component(), Connection<D>, De
}
togglebutton("View") {
isSelected = false
FragmentWindow(FXFragment.buildFromNode(device.name) { fxNode }).bindTo(this)
FragmentWindow(FXFragment.buildFromNode(device?.name) { fxNode }).bindTo(this)
}
}
}

View File

@ -9,6 +9,7 @@ import javafx.scene.paint.Color
import javafx.scene.paint.Paint
import javafx.scene.shape.Circle
import javafx.scene.shape.StrokeType
import org.controlsfx.control.ToggleSwitch
import tornadofx.*
@ -97,6 +98,8 @@ fun EventTarget.deviceStateIndicator(connection: DeviceViewConnection<*>, state:
bind(connection, state, transform);
}
separator(Orientation.VERTICAL)
} else {
throw RuntimeException("Device does not support state $state");
}
}
@ -116,6 +119,12 @@ fun Node.deviceStateToggle(connection: DeviceViewConnection<*>, state: String, t
}
}
deviceStateIndicator(connection, state, false)
} else {
throw RuntimeException("Device does not support state $state");
}
}
fun EventTarget.switch(text: String = "", op: (ToggleSwitch.() -> Unit)? = null): ToggleSwitch {
val switch = ToggleSwitch(text)
return opcr(this, switch, op)
}

View File

@ -6,7 +6,6 @@ import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.DeviceFactory
import hep.dataforge.exceptions.ControlException
import hep.dataforge.meta.Meta
import javafx.application.Platform
import javafx.scene.Scene
import javafx.stage.Stage
import org.slf4j.LoggerFactory
@ -27,10 +26,9 @@ abstract class NumassControlApplication<D : Device> : App() {
device = setupDevice()
val controller = buildView(device)
device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE)
val scene = Scene(controller.pane)
stage.scene = scene
Platform.runLater { device.connect(controller, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE) }
stage.show()

View File

@ -3,7 +3,7 @@ apply plugin: 'application'
version = "0.5.0"
if (!hasProperty('mainClass')) {
ext.mainClass = 'inr.numass.readvac.fx.ReadVac'
ext.mainClass = 'inr.numass.readvac.ReadVac'
}
mainClassName = mainClass

View File

@ -6,7 +6,6 @@ import hep.dataforge.control.devices.Sensor;
import hep.dataforge.meta.Meta;
import inr.numass.control.DeviceViewConnection;
import inr.numass.control.DeviceViewFactory;
import inr.numass.control.readvac.fx.VacCollectorView;
import java.util.List;
import java.util.stream.Collectors;

View File

@ -1,47 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac.fx;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import org.controlsfx.control.ToggleSwitch;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
/**
* @author <a href="mailto:altavir@gmail.com">Alexander Nozik</a>
*/
public class PoweredVacuumeterView extends VacuumeterView {
@FXML
private ToggleSwitch powerSwitch;
@Override
public Node getComponent() {
if (node == null) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PoweredVacBox.fxml"));
loader.setController(this);
this.node = loader.load();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
return node;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location,resources);
unitLabel.setText(getDevice().meta().getString("units", "mbar"));
deviceNameLabel.setText(getDevice().getName());
bindBooleanToState("power", powerSwitch.selectedProperty());
}
}

View File

@ -1,137 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac.fx;
import hep.dataforge.control.devices.Device;
import hep.dataforge.control.devices.Sensor;
import hep.dataforge.control.measurements.Measurement;
import hep.dataforge.control.measurements.MeasurementListener;
import inr.numass.control.DeviceViewConnection;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import org.controlsfx.control.ToggleSwitch;
import java.io.IOException;
import java.net.URL;
import java.text.DecimalFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ResourceBundle;
import static hep.dataforge.control.devices.PortSensor.CONNECTED_STATE;
/**
* @author <a href="mailto:altavir@gmail.com">Alexander Nozik</a>
*/
public class VacuumeterView extends DeviceViewConnection<Sensor<Double>> implements MeasurementListener, Initializable {
private static final DecimalFormat FORMAT = new DecimalFormat("0.###E0");
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ISO_LOCAL_TIME;
Node node;
@FXML
private BorderPane root;
@FXML
Label deviceNameLabel;
@FXML
Label unitLabel;
@FXML
private Label valueLabel;
@FXML
private Label status;
@FXML
private ToggleSwitch disableButton;
@Override
public void evaluateDeviceException(Device device, String message, Throwable exception) {
Platform.runLater(() -> setStatus("ERROR: " + message));
}
public Node getComponent() {
if (node == null) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/VacBox.fxml"));
loader.setController(this);
this.node = loader.load();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
return node;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
Platform.runLater(() -> {
unitLabel.setText(getDevice().meta().getString("units", "mbar"));
deviceNameLabel.setText(getDevice().getName());
disableButton.setSelected(getDevice().optBooleanState(CONNECTED_STATE).orElse(false));
disableButton.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
getDevice().setState(CONNECTED_STATE, newValue);
if (!newValue) {
valueLabel.setText("---");
}
});
});
}
@Override
public void onMeasurementFailed(Measurement measurement, Throwable exception) {
Platform.runLater(() -> {
valueLabel.setText("Err");
// setStatus("Error: " + exception.getMessage());
});
}
private void setStatus(String text) {
status.setText(text);
}
@Override
public void onMeasurementProgress(Measurement measurement, String message) {
Platform.runLater(() -> status.setText(message));
}
@Override
public void onMeasurementProgress(Measurement measurement, double progress) {
// Platform.runLater(() -> status.setProgress(progress));
}
@Override
public void onMeasurementStarted(Measurement<?> measurement) {
getDevice().meta().optValue("color").ifPresent(colorValue -> valueLabel.setTextFill(Color.valueOf(colorValue.stringValue())));
}
@Override
public void onMeasurementResult(Measurement measurement, Object res, Instant time) {
Double result = Double.class.cast(res);
String resString = FORMAT.format(result);
Platform.runLater(() -> {
valueLabel.setText(resString);
setStatus("OK: " + TIME_FORMAT.format(LocalDateTime.ofInstant(time, ZoneOffset.UTC)));
});
}
String getTitle() {
return getDevice().meta().getString("title", getDevice().getName());
}
@Override
public Node getFXNode() {
return root;
}
}

View File

@ -1,4 +1,4 @@
package inr.numass.control.readvac.fx;
package inr.numass.control.readvac;
import hep.dataforge.control.devices.Sensor;
import org.apache.commons.cli.CommandLine;

View File

@ -0,0 +1,46 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac
import javafx.fxml.FXML
import javafx.fxml.FXMLLoader
import javafx.scene.Node
import org.controlsfx.control.ToggleSwitch
import java.io.IOException
import java.net.URL
import java.util.*
/**
* @author [Alexander Nozik](mailto:altavir@gmail.com)
*/
class PoweredVacuumeterViewConnection : VacuumeterViewConnection() {
@FXML
private val powerSwitch: ToggleSwitch? = null
val component: Node
get() {
if (getNode() == null) {
try {
val loader = FXMLLoader(javaClass.getResource("/fxml/PoweredVacBox.fxml"))
loader.setController(this)
this.setNode(loader.load<T>())
} catch (ex: IOException) {
throw RuntimeException(ex)
}
}
return getNode()
}
fun initialize(location: URL, resources: ResourceBundle) {
super.initialize(location, resources)
getUnitLabel().setText(device.meta().getString("units", "mbar"))
getDeviceNameLabel().setText(device.name)
bindBooleanToState("power", powerSwitch!!.selectedProperty())
}
}

View File

@ -3,14 +3,12 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac.fx;
package inr.numass.control.readvac;
import hep.dataforge.control.devices.DeviceFactory;
import hep.dataforge.meta.Meta;
import inr.numass.control.DeviceViewConnection;
import inr.numass.control.NumassControlApplication;
import inr.numass.control.readvac.VacCollectorDevice;
import inr.numass.control.readvac.VacDeviceFactory;
import javafx.stage.Stage;
import java.util.Objects;

View File

@ -3,12 +3,11 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac.fx;
package inr.numass.control.readvac;
import hep.dataforge.control.connections.Roles;
import hep.dataforge.control.devices.Sensor;
import hep.dataforge.control.virtual.Virtual;
import inr.numass.control.readvac.VacCollectorDevice;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;

View File

@ -3,7 +3,7 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac.fx;
package inr.numass.control.readvac;
import hep.dataforge.context.Context;
import hep.dataforge.control.connections.Roles;
@ -25,7 +25,6 @@ import hep.dataforge.plots.jfreechart.JFreeChartFrame;
import hep.dataforge.tables.DataPoint;
import hep.dataforge.values.Value;
import inr.numass.control.DeviceViewConnection;
import inr.numass.control.readvac.VacCollectorDevice;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
@ -76,7 +75,7 @@ public class VacCollectorView extends DeviceViewConnection<VacCollectorDevice> i
private final String[] intervalNames = {"1 sec", "5 sec", "10 sec", "30 sec", "1 min"};
private final int[] intervals = {1000, 5000, 10000, 30000, 60000};
private final List<VacuumeterView> views = new ArrayList<>();
private final List<VacuumeterViewConnection> views = new ArrayList<>();
private TimePlottableGroup plottables;
@FXML
@ -133,11 +132,11 @@ public class VacCollectorView extends DeviceViewConnection<VacCollectorDevice> i
public void open(VacCollectorDevice device) {
super.open(device);
device.getSensors().stream().map((sensor) -> {
VacuumeterView view;
VacuumeterViewConnection view;
if (sensor.hasState("power")) {
view = new PoweredVacuumeterView();
view = new PoweredVacuumeterViewConnection();
} else {
view = new VacuumeterView();
view = new VacuumeterViewConnection();
}
sensor.connect(view, Roles.VIEW_ROLE, Roles.DEVICE_LISTENER_ROLE);
return view;

View File

@ -0,0 +1,101 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package inr.numass.control.readvac
import hep.dataforge.control.devices.Device
import hep.dataforge.control.devices.PortSensor.CONNECTED_STATE
import hep.dataforge.control.devices.Sensor
import hep.dataforge.control.measurements.Measurement
import hep.dataforge.control.measurements.MeasurementListener
import inr.numass.control.DeviceViewConnection
import javafx.application.Platform
import javafx.beans.property.SimpleStringProperty
import javafx.scene.control.Label
import javafx.scene.layout.BorderPane
import javafx.scene.paint.Color
import org.controlsfx.control.ToggleSwitch
import tornadofx.*
import java.text.DecimalFormat
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
/**
* @author [Alexander Nozik](mailto:altavir@gmail.com)
*/
open class VacuumeterViewConnection : DeviceViewConnection<Sensor<Double>>(), MeasurementListener {
val statusProperty = SimpleStringProperty()
var status: String by statusProperty
val valueProperty = SimpleStringProperty()
var value: String by valueProperty
override fun buildView(): View {
return VacView();
}
override fun evaluateDeviceException(device: Device, message: String, exception: Throwable) {
if (!message.isEmpty()) {
Platform.runLater {
status = "ERROR: " + message
}
}
}
override fun onMeasurementFailed(measurement: Measurement<*>, exception: Throwable) {
Platform.runLater {
value = "Err"
}
}
override fun onMeasurementProgress(measurement: Measurement<*>, message: String) {
Platform.runLater {
status = message
}
}
override fun onMeasurementResult(measurement: Measurement<*>, res: Any, time: Instant) {
val result = Double::class.java.cast(res)
val resString = FORMAT.format(result)
Platform.runLater {
value = resString
status = "OK: " + TIME_FORMAT.format(LocalDateTime.ofInstant(time, ZoneOffset.UTC));
}
}
inner class VacView : View("Numass vacuumeter ${device.meta().getString("title", device.name)}") {
override val root: BorderPane by fxml()
val deviceNameLabel: Label by fxid()
val unitLabel: Label by fxid()
val valueLabel: Label by fxid()
val status: Label by fxid()
val disableButton: ToggleSwitch by fxid()
init {
status.textProperty().bind(statusProperty)
valueLabel.textProperty().bind(valueProperty)
unitLabel.text = device.meta().getString("units", "mbar")
deviceNameLabel.text = device.name
bindBooleanToState(CONNECTED_STATE, disableButton.selectedProperty());
disableButton.selectedProperty().addListener { _, _, newValue ->
if (!newValue) {
valueLabel.text = "---"
}
}
device.meta().optValue("color").ifPresent { colorValue -> valueLabel.textFill = Color.valueOf(colorValue.stringValue()) }
}
}
companion object {
private val FORMAT = DecimalFormat("0.###E0")
private val TIME_FORMAT = DateTimeFormatter.ISO_LOCAL_TIME
}
}

View File

@ -4,7 +4,7 @@
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<?import java.net.URL?>
<BorderPane fx:id="root" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.readvac.fx.VacCollectorView">
<BorderPane fx:id="root" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.readvac.VacCollectorView">
<stylesheets>
<URL value="@/fxml/vacstyles.css" />
</stylesheets>