Moving msp to kotlin
This commit is contained in:
parent
debd4a707d
commit
1d82ccf123
@ -28,7 +28,6 @@ import javafx.scene.layout.Priority
|
||||
import javafx.scene.layout.VBox
|
||||
import javafx.scene.text.Font
|
||||
import tornadofx.*
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
@ -36,11 +35,8 @@ import java.time.Instant
|
||||
*/
|
||||
class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListener {
|
||||
private val cryoView by lazy { CryoView() }
|
||||
private val plotView by lazy { CryoPlotView() }
|
||||
|
||||
internal val table = FXCollections.observableHashMap<String, PKT8Result>()
|
||||
|
||||
|
||||
val lastUpdateProperty = SimpleObjectProperty<String>("NEVER")
|
||||
|
||||
|
||||
@ -155,11 +151,7 @@ class PKT8ViewConnection : DeviceViewConnection<PKT8Device>(), MeasurementListen
|
||||
|
||||
var rawDataButton: ToggleButton by singleAssign()
|
||||
|
||||
val plottables: TimePlottableGroup by lazy {
|
||||
TimePlottableGroup().apply {
|
||||
setMaxAge(Duration.parse(plotFrameMeta.getString("maxAge", "PT2H")))
|
||||
}
|
||||
}
|
||||
val plottables: TimePlottableGroup = TimePlottableGroup()
|
||||
|
||||
override val root: Parent = borderpane {
|
||||
prefWidth = 800.0
|
||||
|
@ -28,6 +28,7 @@ import hep.dataforge.control.devices.StateDef;
|
||||
import hep.dataforge.control.measurements.AbstractMeasurement;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.control.ports.TcpPortHandler;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.events.EventBuilder;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.MeasurementException;
|
||||
@ -54,10 +55,16 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
@RoleDef(name = Roles.STORAGE_ROLE, objectType = StorageConnection.class)
|
||||
@RoleDef(name = Roles.VIEW_ROLE)
|
||||
@StateDef(name = PortSensor.CONNECTED_STATE, writable = true, info = "Connection with the device itself")
|
||||
@StateDef(name = "storing", writable = true, info = "Define if this device is currently writes to storage")
|
||||
@StateDef(name = "filamentOn", writable = true, info = "Mass-spectrometer filament on")
|
||||
@StateDef(name = "filamentStatus", info = "Filament status")
|
||||
@StateDef(
|
||||
value = @ValueDef(name = PortSensor.CONNECTED_STATE, info = "Connection with the device itself"),
|
||||
writable = true
|
||||
)
|
||||
@StateDef(
|
||||
value = @ValueDef(name = "storing", info = "Define if this device is currently writes to storage"),
|
||||
writable = true
|
||||
)
|
||||
@StateDef(value = @ValueDef(name = "filamentOn", info = "Mass-spectrometer filament on"), writable = true)
|
||||
@StateDef(@ValueDef(name = "filamentStatus", info = "Filament status"))
|
||||
public class MspDevice extends Sensor<DataPoint> implements PortHandler.PortController {
|
||||
public static final String MSP_DEVICE_TYPE = "msp";
|
||||
|
||||
@ -104,11 +111,11 @@ public class MspDevice extends Sensor<DataPoint> implements PortHandler.PortCont
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected PeakJumpMeasurement createMeasurement() throws MeasurementException{
|
||||
Meta measurementMeta =meta().getMeta("peakJump");
|
||||
protected PeakJumpMeasurement createMeasurement() throws MeasurementException {
|
||||
Meta measurementMeta = meta().getMeta("peakJump");
|
||||
String s = measurementMeta.getString("type", "peakJump");
|
||||
if (s.equals("peakJump")) {
|
||||
PeakJumpMeasurement measurement = new PeakJumpMeasurement(measurementMeta);
|
||||
PeakJumpMeasurement measurement = new PeakJumpMeasurement(measurementMeta);
|
||||
this.measurementDelegate = measurement;
|
||||
return measurement;
|
||||
} else {
|
||||
|
@ -5,7 +5,6 @@ import hep.dataforge.control.devices.Device;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import inr.numass.control.DeviceViewConnection;
|
||||
import inr.numass.control.DeviceViewFactory;
|
||||
import inr.numass.control.msp.fx.MspView;
|
||||
|
||||
/**
|
||||
* Created by darksnake on 09-May-17.
|
||||
@ -24,6 +23,6 @@ public class MspDeviceFactory implements DeviceViewFactory {
|
||||
|
||||
@Override
|
||||
public DeviceViewConnection buildView(Device device) {
|
||||
return MspView.build(device.getContext());
|
||||
return MspViewConnection.Companion.build(device.getContext());
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package inr.numass.control.msp.fx;
|
||||
|
||||
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.msp.MspDevice;
|
||||
import inr.numass.control.msp.MspDeviceFactory;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author darksnake
|
||||
*/
|
||||
public class MspApp extends NumassControlApplication<MspDevice> {
|
||||
|
||||
@Override
|
||||
protected DeviceViewConnection<MspDevice> buildView(MspDevice device) {
|
||||
return MspView.build(device.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DeviceFactory getDeviceFactory() {
|
||||
return new MspDeviceFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupStage(Stage stage, MspDevice device) {
|
||||
stage.setTitle("Numass mass-spectrometer view");
|
||||
stage.setMinHeight(400);
|
||||
stage.setMinWidth(600);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean acceptDevice(Meta meta) {
|
||||
return Objects.equals(meta.getString("name"), "msp");
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,269 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package inr.numass.control.msp.fx;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.NamedValueListener;
|
||||
import hep.dataforge.control.devices.Device;
|
||||
import hep.dataforge.control.devices.DeviceListener;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.fx.fragments.FragmentWindow;
|
||||
import hep.dataforge.fx.fragments.LogFragment;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.plots.data.TimePlottable;
|
||||
import hep.dataforge.plots.data.TimePlottableGroup;
|
||||
import hep.dataforge.plots.fx.PlotContainer;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import hep.dataforge.values.Value;
|
||||
import inr.numass.control.DeviceViewConnection;
|
||||
import inr.numass.control.msp.MspDevice;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.util.StringConverter;
|
||||
import org.controlsfx.control.ToggleSwitch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class MspView extends DeviceViewConnection<MspDevice> implements DeviceListener, Initializable, NamedValueListener {
|
||||
|
||||
public static MspView build(Context context) {
|
||||
try {
|
||||
FXMLLoader loader = new FXMLLoader(context.getClassLoader().getResource("fxml/MspView.fxml"));
|
||||
loader.setClassLoader(context.getClassLoader());
|
||||
loader.load();
|
||||
return loader.getController();
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final TimePlottableGroup plottables = new TimePlottableGroup();
|
||||
// private Configuration viewConfig;
|
||||
private JFreeChartFrame plot;
|
||||
private LogFragment logFragment;
|
||||
|
||||
@FXML
|
||||
private BorderPane root;
|
||||
@FXML
|
||||
private ToggleSwitch filamentButton;
|
||||
@FXML
|
||||
private Circle filamentIndicator;
|
||||
@FXML
|
||||
private ToggleButton measureButton;
|
||||
@FXML
|
||||
private BorderPane plotPane;
|
||||
@FXML
|
||||
public ToggleButton connectButton;
|
||||
@FXML
|
||||
private ToggleButton consoleButton;
|
||||
@FXML
|
||||
private ComboBox<Integer> filamentSelector;
|
||||
@FXML
|
||||
private ToggleButton storeButton;
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*
|
||||
* @param url
|
||||
* @param rb
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
logFragment = new LogFragment();
|
||||
new FragmentWindow(logFragment).bindTo(consoleButton);
|
||||
logFragment.addRootLogHandler();
|
||||
filamentSelector.setItems(FXCollections.observableArrayList(1, 2));
|
||||
filamentSelector.setConverter(new StringConverter<Integer>() {
|
||||
@Override
|
||||
public String toString(Integer object) {
|
||||
return "Filament " + object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer fromString(String string) {
|
||||
return Integer.parseInt(string.substring(9));
|
||||
}
|
||||
});
|
||||
|
||||
filamentSelector.getSelectionModel().select(0);
|
||||
filamentButton.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
|
||||
try {
|
||||
filamentSelector.setDisable(newValue);
|
||||
getDevice().setFilamentOn(newValue);
|
||||
} catch (PortException ex) {
|
||||
getDevice().getLogger().error("Failed to toggle filaments");
|
||||
}
|
||||
});
|
||||
|
||||
filamentButton.disableProperty().bind(connectButton.selectedProperty().not());
|
||||
measureButton.disableProperty().bind(filamentButton.selectedProperty().not());
|
||||
storeButton.disableProperty().bind(measureButton.selectedProperty().not());
|
||||
getStateBinding("filamentStatus").addListener(new ChangeListener<Value>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Value> observable, Value oldValue, Value newValue) {
|
||||
String filamentState = newValue.stringValue();
|
||||
Platform.runLater(() -> {
|
||||
switch (filamentState) {
|
||||
case "ON":
|
||||
filamentIndicator.setFill(Paint.valueOf("red"));
|
||||
break;
|
||||
case "OFF":
|
||||
filamentIndicator.setFill(Paint.valueOf("blue"));
|
||||
break;
|
||||
case "WARM-UP":
|
||||
case "COOL-DOWN":
|
||||
filamentIndicator.setFill(Paint.valueOf("yellow"));
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private Meta getViewConfig() {
|
||||
return getDevice().meta().getMeta("plotConfig", getDevice().getMeta());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void open(MspDevice device) throws Exception {
|
||||
super.open(device);
|
||||
updatePlot();
|
||||
|
||||
bindBooleanToState("connected", connectButton.selectedProperty());
|
||||
}
|
||||
|
||||
private void initPlot() {
|
||||
Meta plotConfig = new MetaBuilder("plotFrame")
|
||||
.setNode(new MetaBuilder("yAxis")
|
||||
.setValue("type", "log")
|
||||
.setValue("axisTitle", "partial pressure")
|
||||
.setValue("axisUnits", "mbar")
|
||||
)
|
||||
.setValue("xAxis.type", "time");
|
||||
|
||||
this.plot = new JFreeChartFrame(plotConfig);
|
||||
PlotContainer container = PlotContainer.centerIn(plotPane);
|
||||
container.setPlot(plot);
|
||||
}
|
||||
|
||||
private void updatePlot() {
|
||||
if (plot == null) {
|
||||
initPlot();
|
||||
}
|
||||
Meta config = getViewConfig();
|
||||
if (config.hasMeta("plotFrame")) {
|
||||
this.plot.configure(config.getMeta("plotFrame"));
|
||||
}
|
||||
if (config.hasMeta("peakJump.peak")) {
|
||||
for (Meta peakMeta : config.getMetaList("peakJump.peak")) {
|
||||
String mass = peakMeta.getString("mass");
|
||||
if (!this.plottables.has(mass)) {
|
||||
TimePlottable newPlottable = new TimePlottable(mass, mass);
|
||||
newPlottable.configure(peakMeta);
|
||||
newPlottable.setMaxItems(1000);
|
||||
newPlottable.setPrefItems(400);
|
||||
newPlottable.configureValue("titleBase",peakMeta.getString("title",mass));
|
||||
this.plottables.add(newPlottable);
|
||||
plot.add(newPlottable);
|
||||
} else {
|
||||
plottables.get(mass).configure(peakMeta);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showError("No peaks defined in config");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluateDeviceException(Device device, String message, Throwable exception) {
|
||||
Platform.runLater(() -> {
|
||||
logFragment.appendLine("ERROR: " + message);
|
||||
showError(message);
|
||||
});
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onPlotToggle(ActionEvent event) throws ControlException {
|
||||
if (measureButton.isSelected()) {
|
||||
getDevice().startMeasurement();
|
||||
} else {
|
||||
getDevice().stopMeasurement(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void showError(String message) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Error!");
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText(message);
|
||||
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
private void showInfo(String message) {
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onStoreButtonClick(ActionEvent event) {
|
||||
getDevice().setState("storing", storeButton.isSelected());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getFXNode() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushValue(String valueName, Value value) {
|
||||
TimePlottable pl = plottables.get(valueName);
|
||||
if (pl != null) {
|
||||
if (value.doubleValue() > 0) {
|
||||
pl.put(value);
|
||||
} else {
|
||||
pl.put(Value.NULL);
|
||||
}
|
||||
String titleBase = pl.getConfig().getString("titleBase");
|
||||
String title = String.format("%s (%.4g)", titleBase, value.doubleValue());
|
||||
pl.configureValue("title", title);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2015 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package inr.numass.control.msp
|
||||
|
||||
import hep.dataforge.control.devices.DeviceFactory
|
||||
import hep.dataforge.meta.Meta
|
||||
import inr.numass.control.DeviceViewConnection
|
||||
import inr.numass.control.NumassControlApplication
|
||||
import javafx.stage.Stage
|
||||
|
||||
/**
|
||||
* @author darksnake
|
||||
*/
|
||||
class MspApp : NumassControlApplication<MspDevice>() {
|
||||
|
||||
override fun buildView(device: MspDevice): DeviceViewConnection<MspDevice> {
|
||||
return MspViewConnection.build(device.context)
|
||||
}
|
||||
|
||||
override val deviceFactory: DeviceFactory = MspDeviceFactory()
|
||||
|
||||
|
||||
override fun setupStage(stage: Stage, device: MspDevice) {
|
||||
stage.title = "Numass mass-spectrometer view"
|
||||
stage.minHeight = 400.0
|
||||
stage.minWidth = 600.0
|
||||
}
|
||||
|
||||
override fun acceptDevice(meta: Meta): Boolean {
|
||||
return meta.getString("name") == "msp"
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2015 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package inr.numass.control.msp
|
||||
|
||||
import hep.dataforge.control.NamedValueListener
|
||||
import hep.dataforge.control.devices.Device
|
||||
import hep.dataforge.control.devices.DeviceListener
|
||||
import hep.dataforge.control.devices.PortSensor
|
||||
import hep.dataforge.control.devices.Sensor
|
||||
import hep.dataforge.control.devices.Sensor.MEASURING_STATE
|
||||
import hep.dataforge.fx.fragments.FragmentWindow
|
||||
import hep.dataforge.fx.fragments.LogFragment
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.plots.PlotUtils
|
||||
import hep.dataforge.plots.data.TimePlottable
|
||||
import hep.dataforge.plots.data.TimePlottableGroup
|
||||
import hep.dataforge.plots.fx.FXPlotFrame
|
||||
import hep.dataforge.plots.fx.PlotContainer
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import hep.dataforge.values.Value
|
||||
import inr.numass.control.DeviceViewConnection
|
||||
import inr.numass.control.deviceStateIndicator
|
||||
import javafx.application.Platform
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
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.*
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
|
||||
* @author darksnake
|
||||
*/
|
||||
class MspViewConnection : DeviceViewConnection<MspDevice>(), DeviceListener, NamedValueListener {
|
||||
private val mspView by lazy { MspView() }
|
||||
|
||||
override fun getBoardView(): Parent {
|
||||
return VBox().apply {
|
||||
this += super.getBoardView()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFXNode(): Node {
|
||||
if (!isOpen) {
|
||||
throw RuntimeException("Not connected!")
|
||||
}
|
||||
return mspView.root;
|
||||
}
|
||||
|
||||
override fun pushValue(valueName: String, value: Value) {
|
||||
val pl = plottables.get(valueName)
|
||||
if (pl != null) {
|
||||
if (value.doubleValue() > 0) {
|
||||
pl.put(value)
|
||||
} else {
|
||||
pl.put(Value.NULL)
|
||||
}
|
||||
val titleBase = pl.config.getString("titleBase")
|
||||
val title = String.format("%s (%.4g)", titleBase, value.doubleValue())
|
||||
pl.configureValue("title", title)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inner class MspView : View("Numass mass-spectrometer measurement") {
|
||||
val plotFrameMeta: Meta = device.meta().getMeta("plotConfig", device.meta)
|
||||
|
||||
val plotFrame: FXPlotFrame by lazy {
|
||||
val basePlotConfig = MetaBuilder("plotFrame")
|
||||
.setNode(MetaBuilder("yAxis")
|
||||
.setValue("type", "log")
|
||||
.setValue("axisTitle", "partial pressure")
|
||||
.setValue("axisUnits", "mbar")
|
||||
)
|
||||
.setValue("xAxis.type", "time")
|
||||
|
||||
|
||||
JFreeChartFrame(basePlotConfig).apply {
|
||||
PlotUtils.setXAxis(this, "timestamp", null, "time")
|
||||
configure(plotFrameMeta)
|
||||
}
|
||||
}
|
||||
val plottables: TimePlottableGroup = TimePlottableGroup()
|
||||
|
||||
private var logButton: ToggleButton by singleAssign()
|
||||
|
||||
private val logWindow = FragmentWindow(LogFragment().apply {
|
||||
addLogHandler(device.logger)
|
||||
})
|
||||
|
||||
val filamentProperty = SimpleObjectProperty<Int>().apply {
|
||||
addListener { _, oldValue, newValue ->
|
||||
if (newValue != oldValue) {
|
||||
device.selectFillament(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
minHeight = 400.0
|
||||
minWidth = 600.0
|
||||
top {
|
||||
toolbar {
|
||||
togglebutton("Connect") {
|
||||
isSelected = false
|
||||
bindBooleanToState(PortSensor.CONNECTED_STATE, selectedProperty())
|
||||
}
|
||||
combobox(filamentProperty, listOf(1, 2)) {
|
||||
cellFormat {
|
||||
text = "Filament $it"
|
||||
}
|
||||
selectionModel.selectFirst()
|
||||
disableProperty()
|
||||
.bind(getStateBinding(MEASURING_STATE).booleanBinding { it!!.booleanValue() })
|
||||
}
|
||||
add(ToggleSwitch().apply {
|
||||
padding = Insets(11.0, 0.0, 0.0, 0.0)
|
||||
disableProperty()
|
||||
.bind(getStateBinding(PortSensor.CONNECTED_STATE).booleanBinding { !it!!.booleanValue() })
|
||||
bindBooleanToState("filamentOn", selectedProperty())
|
||||
})
|
||||
deviceStateIndicator(this@MspViewConnection, "filamentStatus") {
|
||||
when (it.stringValue()) {
|
||||
"ON" -> Paint.valueOf("red")
|
||||
"OFF" -> Paint.valueOf("blue")
|
||||
"WARM-UP", "COOL-DOWN" -> Paint.valueOf("yellow")
|
||||
else -> error("Unknown filament state")
|
||||
|
||||
}
|
||||
}
|
||||
separator(Orientation.VERTICAL)
|
||||
|
||||
togglebutton("Measure") {
|
||||
isSelected = false
|
||||
disableProperty()
|
||||
.bind(getStateBinding(PortSensor.CONNECTED_STATE).booleanBinding { !it!!.booleanValue() })
|
||||
|
||||
bindBooleanToState(Sensor.MEASURING_STATE, selectedProperty())
|
||||
}
|
||||
togglebutton("Store") {
|
||||
isSelected = false
|
||||
disableProperty()
|
||||
.bind(getStateBinding(Sensor.MEASURING_STATE).booleanBinding { !it!!.booleanValue() })
|
||||
bindBooleanToState("storing", selectedProperty())
|
||||
}
|
||||
separator(Orientation.VERTICAL)
|
||||
pane {
|
||||
hgrow = Priority.ALWAYS
|
||||
}
|
||||
separator(Orientation.VERTICAL)
|
||||
|
||||
logButton = togglebutton("Log") {
|
||||
isSelected = false
|
||||
logWindow.bindTo(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
PlotContainer.centerIn(this).plot = plotFrame
|
||||
}
|
||||
|
||||
private var plot: JFreeChartFrame? = null
|
||||
private var logFragment: LogFragment? = null
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun open(device: MspDevice) {
|
||||
super.open(device)
|
||||
updatePlot()
|
||||
|
||||
bindBooleanToState("connected", connectButton!!.selectedProperty())
|
||||
}
|
||||
|
||||
private fun initPlot() {
|
||||
val plotConfig = MetaBuilder("plotFrame")
|
||||
.setNode(MetaBuilder("yAxis")
|
||||
.setValue("type", "log")
|
||||
.setValue("axisTitle", "partial pressure")
|
||||
.setValue("axisUnits", "mbar")
|
||||
)
|
||||
.setValue("xAxis.type", "time")
|
||||
|
||||
this.plot = JFreeChartFrame(plotConfig)
|
||||
val container = PlotContainer.centerIn(plotPane)
|
||||
container.plot = plot
|
||||
}
|
||||
|
||||
private fun updatePlot() {
|
||||
if (plot == null) {
|
||||
initPlot()
|
||||
}
|
||||
if (plotFrameMeta.hasMeta("plotFrame")) {
|
||||
this.plot!!.configure(plotFrameMeta.getMeta("plotFrame"))
|
||||
}
|
||||
if (plotFrameMeta.hasMeta("peakJump.peak")) {
|
||||
for (peakMeta in plotFrameMeta.getMetaList("peakJump.peak")) {
|
||||
val mass = peakMeta.getString("mass")
|
||||
if (!this.plottables.has(mass)) {
|
||||
val newPlottable = TimePlottable(mass, mass)
|
||||
newPlottable.configure(peakMeta)
|
||||
newPlottable.setMaxItems(1000)
|
||||
newPlottable.setPrefItems(400)
|
||||
newPlottable.configureValue("titleBase", peakMeta.getString("title", mass))
|
||||
this.plottables.add(newPlottable)
|
||||
plot!!.add(newPlottable)
|
||||
} else {
|
||||
plottables.get(mass).configure(peakMeta)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showError("No peaks defined in config")
|
||||
throw RuntimeException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun evaluateDeviceException(device: Device, message: String, exception: Throwable) {
|
||||
Platform.runLater {
|
||||
logFragment!!.appendLine("ERROR: " + message)
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showError(message: String) {
|
||||
val alert = Alert(Alert.AlertType.ERROR)
|
||||
alert.title = "Error!"
|
||||
alert.headerText = null
|
||||
alert.contentText = message
|
||||
|
||||
alert.showAndWait()
|
||||
}
|
||||
}
|
||||
}
|
@ -23,26 +23,28 @@ limitations under the License.
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import org.controlsfx.control.ToggleSwitch?>
|
||||
<BorderPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0" minWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.msp.fx.MspView">
|
||||
<BorderPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0" minWidth="600.0"
|
||||
xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"
|
||||
fx:controller="inr.numass.control.msp.MspViewConnection">
|
||||
<top>
|
||||
<ToolBar prefHeight="50.0" prefWidth="200.0">
|
||||
<ToggleButton fx:id="connectButton" mnemonicParsing="false" text="Connect" />
|
||||
<ComboBox fx:id="filamentSelector" promptText="Fillament 1" visibleRowCount="2" />
|
||||
<ToggleButton fx:id="connectButton" mnemonicParsing="false" text="Connect"/>
|
||||
<ComboBox fx:id="filamentSelector" promptText="Fillament 1" visibleRowCount="2"/>
|
||||
<ToggleSwitch fx:id="filamentButton" prefHeight="40.0" prefWidth="35.0">
|
||||
<padding>
|
||||
<Insets top="11.0" />
|
||||
<Insets top="11.0"/>
|
||||
</padding>
|
||||
</ToggleSwitch>
|
||||
<Circle fx:id="filamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE" />
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||
<ToggleButton fx:id="measureButton" mnemonicParsing="false" onAction="#onPlotToggle" text="Measure" />
|
||||
<ToggleButton fx:id="storeButton" mnemonicParsing="false" onAction="#onStoreButtonClick" text="Store" />
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<ToggleButton fx:id="consoleButton" mnemonicParsing="false" text="Console" />
|
||||
<Circle fx:id="filamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE"/>
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0"/>
|
||||
<ToggleButton fx:id="measureButton" mnemonicParsing="false" onAction="#onPlotToggle" text="Measure"/>
|
||||
<ToggleButton fx:id="storeButton" mnemonicParsing="false" onAction="#onStoreButtonClick" text="Store"/>
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0"/>
|
||||
<Pane HBox.hgrow="ALWAYS"/>
|
||||
<ToggleButton fx:id="consoleButton" mnemonicParsing="false" text="Console"/>
|
||||
</ToolBar>
|
||||
</top>
|
||||
<center>
|
||||
<BorderPane fx:id="plotPane" minHeight="400.0" minWidth="600.0" prefHeight="200.0" prefWidth="200.0" />
|
||||
<BorderPane fx:id="plotPane" minHeight="400.0" minWidth="600.0" prefHeight="200.0" prefWidth="200.0"/>
|
||||
</center>
|
||||
</BorderPane>
|
||||
|
@ -11,6 +11,7 @@ import hep.dataforge.fx.fragments.FragmentWindow
|
||||
import hep.dataforge.values.Value
|
||||
import javafx.beans.binding.ObjectBinding
|
||||
import javafx.beans.property.BooleanProperty
|
||||
import javafx.beans.value.ObservableValue
|
||||
import javafx.geometry.Pos
|
||||
import javafx.scene.Parent
|
||||
import javafx.scene.layout.HBox
|
||||
@ -45,6 +46,10 @@ abstract class DeviceViewConnection<D : Device> : DeviceConnection<D>(), DeviceL
|
||||
}
|
||||
}
|
||||
|
||||
fun getBooleanStateBinding(state: String): ObservableValue<Boolean>{
|
||||
return getStateBinding(state).booleanBinding{it!!.booleanValue()}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind existing boolean property to writable device state
|
||||
|
||||
|
@ -1,12 +1,9 @@
|
||||
package inr.numass.control
|
||||
|
||||
import hep.dataforge.fx.fragments.FXFragment
|
||||
import hep.dataforge.fx.fragments.FragmentWindow
|
||||
import hep.dataforge.values.Value
|
||||
import javafx.beans.value.ObservableValue
|
||||
import javafx.event.EventTarget
|
||||
import javafx.geometry.Orientation
|
||||
import javafx.scene.control.ToggleButton
|
||||
import javafx.scene.paint.Color
|
||||
import javafx.scene.paint.Paint
|
||||
import javafx.scene.shape.Circle
|
||||
@ -99,3 +96,4 @@ fun EventTarget.deviceStateIndicator(connection: DeviceViewConnection<*>, state:
|
||||
separator(Orientation.VERTICAL)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user