diff --git a/numass-core/src/main/java/inr/numass/data/api/NumassSet.java b/numass-core/src/main/java/inr/numass/data/api/NumassSet.java index b999ac14..17bb638e 100644 --- a/numass-core/src/main/java/inr/numass/data/api/NumassSet.java +++ b/numass-core/src/main/java/inr/numass/data/api/NumassSet.java @@ -76,7 +76,7 @@ public interface NumassSet extends Named, Metoid, Iterable, Provide * @param voltage * @return */ - default List listPoints(double voltage) { + default List getPoints(double voltage) { return getPoints().filter(it -> it.getVoltage() == voltage).collect(Collectors.toList()); } diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt index 468edd09..cf7f6f6e 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/AmplitudeView.kt @@ -70,6 +70,8 @@ class AmplitudeView( private val data: ObservableMap = FXCollections.observableHashMap() private val plots: ObservableMap> = FXCollections.observableHashMap() + val isEmpty = booleanBinding(data){data.isEmpty()} + private val progress = object : DoubleBinding() { init { bind(plots) @@ -111,11 +113,11 @@ class AmplitudeView( /** * Put or replace current plot with name `key` */ - fun putOne(key: String, point: NumassPoint) { + fun add(key: String, point: NumassPoint) { data.put(key, point) } - fun putAll(data: Map) { + fun addAll(data: Map) { this.data.putAll(data); } @@ -175,7 +177,7 @@ class AmplitudeView( data.keys.filter { !map.containsKey(it) }.forEach { remove(it) } - this.putAll(map); + this.addAll(map); } } diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/HVView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/HVView.kt index 5dbab74f..08cf7d28 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/HVView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/HVView.kt @@ -7,6 +7,8 @@ import hep.dataforge.plots.PlotFrame import hep.dataforge.plots.data.TimePlot import hep.dataforge.plots.jfreechart.JFreeChartFrame import inr.numass.data.api.NumassSet +import javafx.collections.FXCollections +import javafx.collections.ObservableList import javafx.scene.image.ImageView import tornadofx.* import java.util.concurrent.atomic.AtomicInteger @@ -28,39 +30,58 @@ class HVView : View(title = "High voltage time plot", icon = ImageView(dfIcon)) center = PlotContainer(frame).root } + private val data: ObservableList = FXCollections.observableArrayList() + val isEmpty = booleanBinding(data) { data.isEmpty() } - fun update(vararg sets: NumassSet) { - frame.plots.clear() - container.sideBarExpanded = false + init { + data.onChange { change -> + frame.plots.clear() + container.sideBarExpanded = false - val progress = AtomicInteger(0); - runLater { container.progress = -1.0 } + val progress = AtomicInteger(0); + runLater { container.progress = -1.0 } - sets.forEach { data -> - runAsync { - val res = data.hvData - runLater { container.progress = progress.incrementAndGet().toDouble() / sets.size } - res - } ui { hvData -> - hvData.ifPresent { - for (dp in it) { - val blockName = dp.getString("block", "default").replace(".", "_"); - //val opt = frame.opt(blockName) - val plot = frame.opt(blockName).orElseGet { - TimePlot(blockName).configure { - "connectionType" to "step" - "thickness" to 2 - "showLine" to true - "showSymbol" to false - "showErrors" to false - } - .apply { frame.add(this) } - } as TimePlot; - plot.put(dp.getValue("timestamp").timeValue(), dp.getValue("value")) + change.list.forEach { data -> + runAsync { + val res = data.hvData + runLater { container.progress = progress.incrementAndGet().toDouble() / change.list.size } + res + } ui { hvData -> + hvData.ifPresent { + for (dp in it) { + val blockName = dp.getString("block", "default").replace(".", "_"); + //val opt = frame.opt(blockName) + val plot = frame.opt(blockName).orElseGet { + TimePlot(blockName).configure { + "connectionType" to "step" + "thickness" to 2 + "showLine" to true + "showSymbol" to false + "showErrors" to false + } + .apply { frame.add(this) } + } as TimePlot; + plot.put(dp.getValue("timestamp").timeValue(), dp.getValue("value")) + } } + container.progress = 1.0; } - container.progress = 1.0; } } } + + + fun update(vararg sets: NumassSet) { + data.setAll(*sets) + } + + fun add(set: NumassSet) { + this.data.add(set) + } + + fun remove(set: NumassSet) { + this.data.remove(set); + } + + } diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt index a31e87a8..e9f61744 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/SpectrumView.kt @@ -14,6 +14,9 @@ import inr.numass.data.api.NumassAnalyzer import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassSet import javafx.beans.property.SimpleIntegerProperty +import javafx.collections.FXCollections +import javafx.collections.MapChangeListener +import javafx.collections.ObservableMap import javafx.geometry.Insets import javafx.geometry.Orientation import javafx.scene.image.ImageView @@ -55,7 +58,8 @@ class SpectrumView( private var upChannel by upChannelProperty - private val data: MutableMap = HashMap() + private val data: ObservableMap = FXCollections.observableHashMap(); + val isEmpty = booleanBinding(data) { data.isEmpty() } /* -> + if (change.wasRemoved()) { + frame.remove(change.key); + } + + updateView() + } + } + private fun getSpectrum(point: NumassPoint): Table { return cache.computeIfAbsent(point) { analyzer.getSpectrum(point, Meta.empty()) } @@ -173,15 +187,11 @@ class SpectrumView( } } - fun update(map: Map) { - synchronized(data) { - //Remove obsolete keys - data.keys.filter { !map.containsKey(it) }.forEach { - data.remove(it) - frame.remove(it); - } - this.data.putAll(map.mapValues { NumassDataCache(it.value) }); - updateView() - } + fun add(key: String, value: NumassSet) { + data.put(key, NumassDataCache(value)) + } + + fun remove(key: String) { + data.remove(key) } } diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/StorageView.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/StorageView.kt index 7126b224..8270ac89 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/StorageView.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/StorageView.kt @@ -5,16 +5,19 @@ import hep.dataforge.context.Global import hep.dataforge.exceptions.StorageException import hep.dataforge.kodex.fx.dfIcon import hep.dataforge.kodex.fx.runGoal +import hep.dataforge.storage.api.Loader import hep.dataforge.storage.api.Storage import hep.dataforge.storage.filestorage.FileStorageFactory import inr.numass.NumassProperties +import inr.numass.data.api.NumassPoint +import inr.numass.data.api.NumassSet +import inr.numass.data.storage.NumassDataLoader import inr.numass.data.storage.NumassStorage import javafx.application.Platform import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleStringProperty -import javafx.collections.FXCollections -import javafx.collections.ObservableList import javafx.geometry.Insets +import javafx.scene.control.TreeItem import javafx.scene.image.ImageView import javafx.scene.layout.Priority import javafx.scene.text.Font @@ -23,22 +26,26 @@ import org.controlsfx.control.StatusBar import tornadofx.* import java.io.File import java.net.URI +import kotlin.streams.toList -class StorageView : View(title = "Numass storage", icon = ImageView(dfIcon)) { +class StorageView(private val context: Context = Global.instance()) : View(title = "Numass storage", icon = ImageView(dfIcon)) { - val selected: ObservableList = FXCollections.observableArrayList(); - - private val context: Context - get() = Global.instance() val storageProperty = SimpleObjectProperty() var storage by storageProperty - val storageNameProperty = SimpleStringProperty("") - var storageName by storageNameProperty + private val storageNameProperty = SimpleStringProperty("") + private var storageName by storageNameProperty - val statusBar = StatusBar(); + private val statusBar = StatusBar(); + + private val ampView: AmplitudeView by inject(); + private val spectrumView: SpectrumView by inject(); + private val hvView: HVView by inject(); + private val scView: SlowControlView by inject(); + + private data class NamedPoint(val id: String, val point: NumassPoint) override val root = borderpane { top { @@ -67,25 +74,84 @@ class StorageView : View(title = "Numass storage", icon = ImageView(dfIcon)) { } } } - } - label(storageNameProperty) { - padding = Insets(0.0, 0.0, 0.0, 10.0); - font = Font.font("System Bold", 13.0); - } - pane { - hgrow = Priority.ALWAYS - } - togglebutton("Console") { + label(storageNameProperty) { + padding = Insets(0.0, 0.0, 0.0, 10.0); + font = Font.font("System Bold", 13.0); + } + pane { + hgrow = Priority.ALWAYS + } + togglebutton("Console") { + } } + } center { splitpane { - // treetableview { -// -// } + treeview { + storageProperty.onChange { + root = TreeItem(it) + populate { parent -> + val value = parent.value + when (value) { + is Storage -> value.shelves() + value.loaders() + is NumassSet -> value.points.map { point -> NamedPoint("${getSetName(value)}/${point.voltage}", point) }.toList() + else -> null + } + } + } + cellFormat { value -> + when (value) { + is Storage -> text = value.name + is NumassSet -> { + text = null + graphic = checkbox { + text = value.name + val setName = getSetName(value) + selectedProperty().onChange { selected -> + if (selected) { + spectrumView.add(setName, value) + hvView.add(value) + } else { + spectrumView.remove(setName) + hvView.remove(value) + } + } + } + } + is NamedPoint -> { + text = null + graphic = checkbox { + text = value.id + selectedProperty().onChange { selected -> + if (selected) { + ampView.add(value.id, value.point) + } else { + ampView.remove(id) + } + } + } + } + else -> { + text = (value as Loader).name + } + } + } + } tabpane { - + tab("Amplitude spectra", ampView.root) { + isClosable = false + visibleWhen(ampView.isEmpty.not()) + } + tab("HV", hvView.root) { + isClosable = false + visibleWhen(hvView.isEmpty.not()) + } + tab("Numass spectra", spectrumView.root) { + isClosable = false + visibleWhen(spectrumView.isEmpty.not()) + } } setDividerPosition(0, 0.3); } @@ -96,36 +162,46 @@ class StorageView : View(title = "Numass storage", icon = ImageView(dfIcon)) { } + private fun getSetName(value: NumassSet): String { + return if (value is NumassDataLoader) { + value.path + } else { + value.name + } + } + private fun loadDirectory(path: URI) { runGoal("loadDirectory[$path]") { - updateTitle("Load storage ($path)") - updateProgress(-1.0, -1.0); - updateMessage("Building numass storage tree...") + title = "Load storage ($path)" + progress = -1.0 + message = "Building numass storage tree..." val root = NumassStorage(context, FileStorageFactory.buildStorageMeta(path, true, true)); setRootStorage(root) Platform.runLater { storageName = "Storage: " + path } - updateProgress(1.0, 1.0) + progress = 1.0 } } fun setRootStorage(root: Storage) { runGoal("loadStorage[${root.name}]") { - updateTitle("Fill data to UI (" + root.name + ")") - updateProgress(-1.0, 1.0) - Platform.runLater { statusBar.progress = -1.0 } + title = "Fill data to UI (" + root.name + ")" + progress = -1.0 + runLater { statusBar.progress = -1.0 } - updateMessage("Loading numass storage tree...") + message = "Loading numass storage tree..." - try { - storageProperty.set(root) - } catch (ex: StorageException) { - context.logger.error("Could not load the storage", ex); + runLater { + try { + storageProperty.set(root) + } catch (ex: StorageException) { + context.logger.error("Could not load the storage", ex); + } } // callback.setProgress(1, 1); - Platform.runLater { statusBar.progress = 0.0 } - updateMessage("Numass storage tree loaded.") - updateProgress(1.0, 1.0) + runLater { statusBar.progress = 0.0 } + message = "Numass storage tree loaded." + progress = 1.0 } } } diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ViewerTest.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt similarity index 75% rename from numass-viewer/src/main/kotlin/inr/numass/viewer/test/ViewerTest.kt rename to numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt index 36fbb1a5..557b275e 100644 --- a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ViewerTest.kt +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/ComponentTest.kt @@ -15,9 +15,9 @@ import java.io.File import java.util.concurrent.ConcurrentHashMap import java.util.stream.Collectors -class ViewerTestApp : App(ViewerTest::class) +class ViewerComponentsTestApp : App(ViewerComponentsTest::class) -class ViewerTest : View(title = "Numass viewer test", icon = ImageView(dfIcon)) { +class ViewerComponentsTest : View(title = "Numass viewer test", icon = ImageView(dfIcon)) { //val rootDir = File("D:\\Work\\Numass\\data\\2017_05\\Fill_2") @@ -45,27 +45,21 @@ class ViewerTest : View(title = "Numass viewer test", icon = ImageView(dfIcon)) } center { tabpane { - tab("amplitude") { - content = amp.root - } - tab("spectrum") { - content = sp.root - } - tab("hv") { - content = hv.root - } + tab("amplitude", amp.root) + tab("spectrum", sp.root) + tab("hv", hv.root) } } } fun update(set: NumassSet) { amp.setAll(set.points.filter { it.voltage != 16000.0 }.collect(Collectors.toMap({ "point_${it.voltage}" }, { it }))); - sp.update(mapOf("test" to set)); + sp.add("test", set); hv.update(set) } } fun main(args: Array) { - Application.launch(ViewerTestApp::class.java, *args); + Application.launch(ViewerComponentsTestApp::class.java, *args); } \ No newline at end of file diff --git a/numass-viewer/src/main/kotlin/inr/numass/viewer/test/StorageViewTest.kt b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/StorageViewTest.kt new file mode 100644 index 00000000..0d181066 --- /dev/null +++ b/numass-viewer/src/main/kotlin/inr/numass/viewer/test/StorageViewTest.kt @@ -0,0 +1,11 @@ +package inr.numass.viewer.test + +import inr.numass.viewer.StorageView +import javafx.application.Application +import tornadofx.* + +class ViewerTestApp : App(StorageView::class) + +fun main(args: Array) { + Application.launch(ViewerTestApp::class.java, *args); +} \ No newline at end of file