diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8ViewConnection.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8ViewConnection.kt index 2a817d68..d5fded8c 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8ViewConnection.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8ViewConnection.kt @@ -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(), MeasurementListener { private val cryoView by lazy { CryoView() } - private val plotView by lazy { CryoPlotView() } internal val table = FXCollections.observableHashMap() - - val lastUpdateProperty = SimpleObjectProperty("NEVER") @@ -155,11 +151,7 @@ class PKT8ViewConnection : DeviceViewConnection(), 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 diff --git a/numass-control/msp/src/main/java/inr/numass/control/msp/MspDevice.java b/numass-control/msp/src/main/java/inr/numass/control/msp/MspDevice.java index ba7b5e67..a49f8494 100644 --- a/numass-control/msp/src/main/java/inr/numass/control/msp/MspDevice.java +++ b/numass-control/msp/src/main/java/inr/numass/control/msp/MspDevice.java @@ -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 implements PortHandler.PortController { public static final String MSP_DEVICE_TYPE = "msp"; @@ -104,11 +111,11 @@ public class MspDevice extends Sensor 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 { diff --git a/numass-control/msp/src/main/java/inr/numass/control/msp/MspDeviceFactory.java b/numass-control/msp/src/main/java/inr/numass/control/msp/MspDeviceFactory.java index 209ace94..6d517d70 100644 --- a/numass-control/msp/src/main/java/inr/numass/control/msp/MspDeviceFactory.java +++ b/numass-control/msp/src/main/java/inr/numass/control/msp/MspDeviceFactory.java @@ -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()); } } diff --git a/numass-control/msp/src/main/java/inr/numass/control/msp/fx/MspApp.java b/numass-control/msp/src/main/java/inr/numass/control/msp/fx/MspApp.java deleted file mode 100644 index 9d33ff99..00000000 --- a/numass-control/msp/src/main/java/inr/numass/control/msp/fx/MspApp.java +++ /dev/null @@ -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 { - - @Override - protected DeviceViewConnection 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"); - } - - -} diff --git a/numass-control/msp/src/main/java/inr/numass/control/msp/fx/MspView.java b/numass-control/msp/src/main/java/inr/numass/control/msp/fx/MspView.java deleted file mode 100644 index fd73a289..00000000 --- a/numass-control/msp/src/main/java/inr/numass/control/msp/fx/MspView.java +++ /dev/null @@ -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 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 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() { - @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 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() { - @Override - public void changed(ObservableValue 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); - } - } -} diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt new file mode 100644 index 00000000..85686bad --- /dev/null +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspApp.kt @@ -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() { + + override fun buildView(device: MspDevice): DeviceViewConnection { + 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" + } + + +} diff --git a/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspViewConnection.kt b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspViewConnection.kt new file mode 100644 index 00000000..32a25f01 --- /dev/null +++ b/numass-control/msp/src/main/kotlin/inr/numass/control/msp/MspViewConnection.kt @@ -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(), 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().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() + } + } +} diff --git a/numass-control/msp/src/main/resources/fxml/MspView.fxml b/numass-control/msp/src/main/resources/fxml/MspView.fxml index dc55355a..e970be6d 100644 --- a/numass-control/msp/src/main/resources/fxml/MspView.fxml +++ b/numass-control/msp/src/main/resources/fxml/MspView.fxml @@ -23,26 +23,28 @@ limitations under the License. - + - - + + - + - - - - - - - + + + + + + +
- +
diff --git a/numass-control/src/main/kotlin/inr/numass/control/DeviceViewConnection.kt b/numass-control/src/main/kotlin/inr/numass/control/DeviceViewConnection.kt index f5a93a3b..d95c2415 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/DeviceViewConnection.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/DeviceViewConnection.kt @@ -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 : DeviceConnection(), DeviceL } } + fun getBooleanStateBinding(state: String): ObservableValue{ + return getStateBinding(state).booleanBinding{it!!.booleanValue()} + } + /** * Bind existing boolean property to writable device state diff --git a/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt b/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt index 4f1e0a16..9dce4afe 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/FXExtensions.kt @@ -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) } } +