Fix watcher view

This commit is contained in:
Alexander Nozik 2021-11-29 15:57:20 +03:00
parent 307d4cb18a
commit 48c7c27af4
11 changed files with 105 additions and 95 deletions

View File

@ -88,7 +88,7 @@ open class DefaultEnvelopeReader : EnvelopeReader {
val dataLength = tag.dataSize val dataLength = tag.dataSize
if (metaLength < 0 || dataLength < 0) { if (metaLength < 0 || dataLength < 0) {
LoggerFactory.getLogger(javaClass).error("Can't lazy read infinite data or meta. Returning non-lazy envelope") LoggerFactory.getLogger(javaClass).error("Can't lazy read infinite data or meta. Returning non-lazy envelope")
return read(file) return read(Files.newInputStream(file))
} }
val metaBuffer = ByteBuffer.allocate(metaLength) val metaBuffer = ByteBuffer.allocate(metaLength)

View File

@ -215,7 +215,7 @@ interface Name : Comparable<Name> {
return of(segments[0]) return of(segments[0])
} }
return of(Stream.of(*segments).filter { it -> !it.isEmpty() }.map<Name>{ of(it) }.toList()) return of(Stream.of(*segments).filter { it -> it.isNotEmpty() }.map { of(it) }.toList())
} }
fun joinString(vararg segments: String): String { fun joinString(vararg segments: String): String {

View File

@ -82,7 +82,7 @@ class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = Imag
init { init {
data.addListener(MapChangeListener { change -> data.addListener(MapChangeListener { change ->
val key = change.key val key = change.key.toString()
if (change.wasAdded()) { if (change.wasAdded()) {
replotOne(key, change.valueAdded) replotOne(key, change.valueAdded)
} else if (change.wasRemoved()) { } else if (change.wasRemoved()) {
@ -153,7 +153,7 @@ class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = Imag
plotJobs.clear() plotJobs.clear()
data.forEach { (key, point) -> data.forEach { (key, point) ->
replotOne(key, point) replotOne(key.toString(), point)
} }
} }

View File

@ -2,6 +2,7 @@ package inr.numass.viewer
import hep.dataforge.context.ContextAware import hep.dataforge.context.ContextAware
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.storage.tables.TableLoader import hep.dataforge.storage.tables.TableLoader
import hep.dataforge.tables.Adapters import hep.dataforge.tables.Adapters
import hep.dataforge.tables.ListTable import hep.dataforge.tables.ListTable
@ -20,13 +21,11 @@ import javafx.collections.ObservableList
import javafx.collections.ObservableMap import javafx.collections.ObservableMap
import kotlinx.coroutines.* import kotlinx.coroutines.*
import tornadofx.* import tornadofx.*
import java.nio.file.Files import java.nio.file.*
import java.nio.file.Path
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchKey
import java.nio.file.attribute.BasicFileAttributes import java.nio.file.attribute.BasicFileAttributes
import kotlin.math.floor import kotlin.math.floor
class DataController : Controller(), ContextAware { class DataController : Controller(), ContextAware {
override val context get() = app.context override val context get() = app.context
@ -45,11 +44,11 @@ class DataController : Controller(), ContextAware {
point.channels.mapValues { (_, value) -> analyzer.getAmplitudeSpectrum(value) } point.channels.mapValues { (_, value) -> analyzer.getAmplitudeSpectrum(value) }
} }
val spectrum: Deferred<Table> = context.async{ val spectrum: Deferred<Table> = context.async {
analyzer.getAmplitudeSpectrum(point) analyzer.getAmplitudeSpectrum(point)
} }
val timeSpectrum: Deferred<Table> = context.async{ val timeSpectrum: Deferred<Table> = context.async {
val cr = spectrum.await().sumOf { val cr = spectrum.await().sumOf {
it.getValue(NumassAnalyzer.COUNT_KEY).int it.getValue(NumassAnalyzer.COUNT_KEY).int
}.toDouble() / point.length.toMillis() * 1000 }.toDouble() / point.length.toMillis() * 1000
@ -76,19 +75,19 @@ class DataController : Controller(), ContextAware {
} }
} }
private val cache = Misc.getLRUCache<String, CachedPoint>(400) private val cache = Misc.getLRUCache<Name, CachedPoint>(400)
fun getCachedPoint(id: String, point: NumassPoint): CachedPoint = cache.getOrPut(id) { CachedPoint(point) } fun getCachedPoint(id: Name, point: NumassPoint): CachedPoint = cache.getOrPut(id) { CachedPoint(point) }
fun getSpectrumAsync(id: String, point: NumassPoint): Deferred<Table> = fun getSpectrumAsync(id: Name, point: NumassPoint): Deferred<Table> =
getCachedPoint(id, point).spectrum getCachedPoint(id, point).spectrum
suspend fun getChannelSpectra(id: String, point: NumassPoint): Map<Int, Table> = suspend fun getChannelSpectra(id: Name, point: NumassPoint): Map<Int, Table> =
getCachedPoint(id, point).channelSpectra.await() getCachedPoint(id, point).channelSpectra.await()
val sets: ObservableMap<String, NumassSet> = FXCollections.observableHashMap() val sets: ObservableMap<Name, NumassSet> = FXCollections.observableHashMap()
val points: ObservableMap<String, CachedPoint> = FXCollections.observableHashMap() val points: ObservableMap<Name, CachedPoint> = FXCollections.observableHashMap()
val sc: ObservableMap<String, TableLoader> = FXCollections.observableHashMap() val sc: ObservableMap<Name, TableLoader> = FXCollections.observableHashMap()
val files: ObservableList<Path> = FXCollections.observableArrayList() val files: ObservableList<Path> = FXCollections.observableArrayList()
@ -102,7 +101,8 @@ class DataController : Controller(), ContextAware {
if (watchPath != null) { if (watchPath != null) {
Files.list(watchPath).toList() Files.list(watchPath).toList()
.filter { .filter {
!Files.isDirectory(it) && it.fileName.toString().startsWith(NumassDataLoader.POINT_FRAGMENT_NAME) !Files.isDirectory(it) && it.fileName.toString()
.startsWith(NumassDataLoader.POINT_FRAGMENT_NAME)
} }
.sortedBy { file -> .sortedBy { file ->
val attr = Files.readAttributes(file, BasicFileAttributes::class.java) val attr = Files.readAttributes(file, BasicFileAttributes::class.java)
@ -117,26 +117,20 @@ class DataController : Controller(), ContextAware {
} }
} }
val watcher = watchPath.fileSystem.newWatchService() val watcher = watchPath.fileSystem.newWatchService()
watchJob = app.context.launch { watchJob = app.context.launch(Dispatchers.IO) {
watcher.use { watcher -> watcher.use { watcher ->
val key: WatchKey = watchPath.register(watcher, watchPath.register(watcher, StandardWatchEventKinds.ENTRY_CREATE)
StandardWatchEventKinds.ENTRY_CREATE)
coroutineContext[Job]?.invokeOnCompletion {
key.cancel()
}
while (isActive) { while (isActive) {
try { val key: WatchKey = watcher.take()
key.pollEvents().forEach { event -> for (event: WatchEvent<*> in key.pollEvents()) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
val path: Path = event.context() as Path val path: Path = event.context() as Path
runLater { runLater {
files.add(watchPath.resolve(path)) files.add(watchPath.resolve(path))
}
} }
} }
} catch (x: Throwable) {
app.context.logger.error("Error during dynamic point read", x)
} }
key.reset()
} }
} }
} }
@ -153,21 +147,21 @@ class DataController : Controller(), ContextAware {
} }
fun addPoint(id: String, point: NumassPoint): CachedPoint { fun addPoint(id: Name, point: NumassPoint): CachedPoint {
val newPoint = getCachedPoint(id, point) val newPoint = getCachedPoint(id, point)
points[id] = newPoint points[id] = newPoint
return newPoint return newPoint
} }
fun addSet(id: String, set: NumassSet) { fun addSet(id: Name, set: NumassSet) {
sets[id] = set sets[id] = set
} }
fun addSc(id: String, set: TableLoader) { fun addSc(id: Name, set: TableLoader) {
sc[id] = set sc[id] = set
} }
fun remove(id: String) { fun remove(id: Name) {
points.remove(id) points.remove(id)
sets.remove(id) sets.remove(id)
sc.remove(id) sc.remove(id)

View File

@ -1,12 +1,15 @@
package inr.numass.viewer package inr.numass.viewer
import hep.dataforge.asName
import hep.dataforge.fx.dfIconView import hep.dataforge.fx.dfIconView
import hep.dataforge.io.envelopes.Envelope import hep.dataforge.io.envelopes.Envelope
import hep.dataforge.names.AlphanumComparator
import hep.dataforge.names.Name
import inr.numass.data.NumassDataUtils import inr.numass.data.NumassDataUtils
import inr.numass.data.NumassEnvelopeType import inr.numass.data.NumassEnvelopeType
import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassPoint
import inr.numass.data.storage.NumassDataLoader import inr.numass.data.storage.NumassDataLoader
import javafx.scene.control.ContextMenu import kotlinx.coroutines.launch
import tornadofx.* import tornadofx.*
import java.nio.file.Path import java.nio.file.Path
@ -28,24 +31,46 @@ class DirectoryWatchView : View(title = "Numass storage", icon = dfIconView) {
return NumassDataUtils.read(envelope) return NumassDataUtils.read(envelope)
} }
//private class PointContainer(val path: Path, val checkedProperty: BooleanProperty = SimpleBooleanProperty())
override val root = splitpane { override val root = splitpane {
listview(dataController.files) { listview(dataController.files.sorted { l, r -> AlphanumComparator.compare(l.toString(), r.toString()) }) {
//multiSelect(true)
cellFormat { path: Path -> cellFormat { path: Path ->
text = path.fileName.toString()
graphic = null
if (path.fileName.toString().startsWith(NumassDataLoader.POINT_FRAGMENT_NAME)) { if (path.fileName.toString().startsWith(NumassDataLoader.POINT_FRAGMENT_NAME)) {
val point = readPointFile(path) val name = Name.of(path.map { it.toString().asName() })
val cachedPoint = dataController.addPoint(path.toString(), point) text = null
//val point = dataController.getCachedPoint(value.toString()) graphic = checkbox(path.fileName.toString()).apply {
contextMenu = ContextMenu().apply { isSelected = false
item("Info") { selectedProperty().onChange {
action { if (it) {
PointInfoView(cachedPoint).openModal(escapeClosesWindow = true) app.context.launch {
dataController.addPoint(name, readPointFile(path))
}
} else {
dataController.remove(name)
} }
} }
} }
// app.context.launch {
// val point = readPointFile(path)
// val cachedPoint = dataController.addPoint(path.toString().asName(), point)
//
// //val point = dataController.getCachedPoint(value.toString())
// withContext(Dispatchers.JavaFx) {
// contextMenu = ContextMenu().apply {
// item("Info") {
// action {
// PointInfoView(cachedPoint).openModal(escapeClosesWindow = true)
// }
// }
// }
// }
// }
} else { } else {
text = path.fileName.toString()
graphic = null
contextMenu = null contextMenu = null
} }
} }

View File

@ -13,7 +13,6 @@ import hep.dataforge.tables.Adapters
import inr.numass.data.api.NumassSet import inr.numass.data.api.NumassSet
import javafx.collections.MapChangeListener import javafx.collections.MapChangeListener
import javafx.scene.image.ImageView import javafx.scene.image.ImageView
import kotlinx.coroutines.Dispatchers
import tornadofx.* import tornadofx.*
@ -48,10 +47,10 @@ class HVView : View(title = "High voltage time plot", icon = ImageView(dfIcon))
val isEmpty = booleanBinding(data) { data.isEmpty() } val isEmpty = booleanBinding(data) { data.isEmpty() }
init { init {
data.addListener { change: MapChangeListener.Change<out String, out NumassSet> -> data.addListener { change: MapChangeListener.Change<out Name, out NumassSet> ->
isEmpty.invalidate() isEmpty.invalidate()
if (change.wasRemoved()) { if (change.wasRemoved()) {
frame.plots.remove(Name.ofSingle(change.key)) frame.plots.remove(change.key)
} }
if (change.wasAdded()) { if (change.wasAdded()) {
runLater { container.progress = -1.0 } runLater { container.progress = -1.0 }
@ -59,8 +58,8 @@ class HVView : View(title = "High voltage time plot", icon = ImageView(dfIcon))
change.valueAdded.getHvData() change.valueAdded.getHvData()
} ui { table -> } ui { table ->
if (table != null) { if (table != null) {
((frame[change.key] as? DataPlot) ((frame[change.key.toString()] as? DataPlot)
?: DataPlot(change.key, adapter = Adapters.buildXYAdapter("timestamp", "value")).also { frame.add(it) }) ?: DataPlot(change.key.toString(), adapter = Adapters.buildXYAdapter("timestamp", "value")).also { frame.add(it) })
.fillData(table) .fillData(table)
} }

View File

@ -1,5 +1,6 @@
package inr.numass.viewer package inr.numass.viewer
import hep.dataforge.asName
import hep.dataforge.fx.dfIconView import hep.dataforge.fx.dfIconView
import hep.dataforge.fx.except import hep.dataforge.fx.except
import hep.dataforge.fx.runGoal import hep.dataforge.fx.runGoal
@ -67,7 +68,7 @@ class MainView : View(title = "Numass viewer", icon = dfIconView) {
NumassDataLoader(app.context, null, path.fileName.toString(), path) NumassDataLoader(app.context, null, path.fileName.toString(), path)
} ui { loader: NumassDataLoader -> } ui { loader: NumassDataLoader ->
contentView = spectrumView contentView = spectrumView
dataController.addSet(loader.name, loader) dataController.addSet(loader.name.asName(), loader)
} except { } except {
alert( alert(
@ -116,7 +117,7 @@ class MainView : View(title = "Numass viewer", icon = dfIconView) {
val point = NumassDataUtils.read(it) val point = NumassDataUtils.read(it)
runLater { runLater {
contentView = amplitudeView contentView = amplitudeView
dataController.addPoint(path.fileName.toString(), point) dataController.addPoint(path.fileName.toString().asName(), point)
} }
} }
} }

View File

@ -5,6 +5,7 @@ import hep.dataforge.fx.dfIcon
import hep.dataforge.fx.plots.PlotContainer import hep.dataforge.fx.plots.PlotContainer
import hep.dataforge.fx.runGoal import hep.dataforge.fx.runGoal
import hep.dataforge.fx.ui import hep.dataforge.fx.ui
import hep.dataforge.names.Name
import hep.dataforge.plots.PlotGroup import hep.dataforge.plots.PlotGroup
import hep.dataforge.plots.data.DataPlot import hep.dataforge.plots.data.DataPlot
import hep.dataforge.plots.jfreechart.JFreeChartFrame import hep.dataforge.plots.jfreechart.JFreeChartFrame
@ -13,7 +14,6 @@ import hep.dataforge.storage.tables.asTable
import hep.dataforge.tables.Adapters import hep.dataforge.tables.Adapters
import javafx.collections.MapChangeListener import javafx.collections.MapChangeListener
import javafx.scene.image.ImageView import javafx.scene.image.ImageView
import kotlinx.coroutines.Dispatchers
import tornadofx.* import tornadofx.*
/** /**
@ -38,16 +38,16 @@ class SlowControlView : View(title = "Numass slow control view", icon = ImageVie
} }
init { init {
data.addListener { change: MapChangeListener.Change<out String, out TableLoader> -> data.addListener { change: MapChangeListener.Change<out Name, out TableLoader> ->
if (change.wasRemoved()) { if (change.wasRemoved()) {
plot.remove(change.key) plot.remove(change.key.toString())
} }
if (change.wasAdded()) { if (change.wasAdded()) {
runGoal(app.context,"loadTable[${change.key}]") { runGoal(app.context,"loadTable[${change.key}]") {
val plotData = change.valueAdded.asTable().await() val plotData = change.valueAdded.asTable().await()
val names = plotData.format.namesAsArray().filter { it != "timestamp" } val names = plotData.format.namesAsArray().filter { it != "timestamp" }
val group = PlotGroup(change.key) val group = PlotGroup(change.key.toString())
names.forEach { names.forEach {
val adapter = Adapters.buildXYAdapter("timestamp", it); val adapter = Adapters.buildXYAdapter("timestamp", it);

View File

@ -99,9 +99,9 @@ class SpectrumView : View(title = "Numass spectrum plot", icon = ImageView(dfIco
} }
init { init {
data.addListener { change: MapChangeListener.Change<out String, out NumassSet> -> data.addListener { change: MapChangeListener.Change<out Name, out NumassSet> ->
if (change.wasRemoved()) { if (change.wasRemoved()) {
frame.plots.remove(Name.ofSingle(change.key)) frame.plots.remove(Name.ofSingle(change.key.toString()))
} }
if (change.wasAdded()) { if (change.wasAdded()) {
@ -118,11 +118,11 @@ class SpectrumView : View(title = "Numass spectrum plot", icon = ImageView(dfIco
data.forEach { (name, set) -> data.forEach { (name, set) ->
val plot: DataPlot = val plot: DataPlot =
frame.plots[Name.ofSingle(name)] as DataPlot? ?: DataPlot(name).apply { frame.add(this) } frame.plots[name] as DataPlot? ?: DataPlot(name.toString()).apply { frame.add(this) }
app.context.launch { app.context.launch {
val points = set.points.map { val points = set.points.map {
dataController.getCachedPoint("$name/${it.voltage}[${it.index}]", it) dataController.getCachedPoint(Name.join("$name","${it.voltage}[${it.index}]"), it)
}.map { cachedPoint -> }.map { cachedPoint ->
val count = cachedPoint.spectrum.await().countInWindow(loChannel.toShort(), upChannel.toShort()) val count = cachedPoint.spectrum.await().countInWindow(loChannel.toShort(), upChannel.toShort())
val seconds = cachedPoint.length.toMillis() / 1000.0 val seconds = cachedPoint.length.toMillis() / 1000.0

View File

@ -1,10 +1,12 @@
package inr.numass.viewer package inr.numass.viewer
import hep.dataforge.asName
import hep.dataforge.fx.dfIconView import hep.dataforge.fx.dfIconView
import hep.dataforge.fx.meta.MetaViewer import hep.dataforge.fx.meta.MetaViewer
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.Metoid import hep.dataforge.meta.Metoid
import hep.dataforge.names.AlphanumComparator import hep.dataforge.names.AlphanumComparator
import hep.dataforge.names.Name
import hep.dataforge.storage.Storage import hep.dataforge.storage.Storage
import hep.dataforge.storage.files.FileTableLoader import hep.dataforge.storage.files.FileTableLoader
import hep.dataforge.storage.tables.TableLoader import hep.dataforge.storage.tables.TableLoader
@ -35,15 +37,15 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
private val hvView: HVView by inject() private val hvView: HVView by inject()
private val scView: SlowControlView by inject() private val scView: SlowControlView by inject()
private inner class Container(val id: String, val content: Any) { private inner class Container(val name: Name, val content: Any) {
val checkedProperty = SimpleBooleanProperty(false) val checkedProperty = SimpleBooleanProperty(false)
var checked by checkedProperty var checked by checkedProperty
val infoView: UIComponent by lazy { val infoView: UIComponent by lazy {
when (content) { when (content) {
is NumassPoint -> PointInfoView(dataController.getCachedPoint(id, content)) is NumassPoint -> PointInfoView(dataController.getCachedPoint(name, content))
is Metoid -> MetaViewer(content.meta, title = "Meta view: $id") is Metoid -> MetaViewer(content.meta, title = "Meta view: $name")
else -> MetaViewer(Meta.empty(), title = "Meta view: $id") else -> MetaViewer(Meta.empty(), title = "Meta view: $name")
} }
} }
@ -54,23 +56,23 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
when (content) { when (content) {
is NumassPoint -> { is NumassPoint -> {
if (selected) { if (selected) {
dataController.addPoint(id, content) dataController.addPoint(name, content)
} else { } else {
dataController.remove(id) dataController.remove(name)
} }
} }
is NumassSet -> { is NumassSet -> {
if (selected) { if (selected) {
dataController.addSet(id, content) dataController.addSet(name, content)
} else { } else {
dataController.remove(id) dataController.remove(name)
} }
} }
is TableLoader -> { is TableLoader -> {
if (selected) { if (selected) {
dataController.addSc(id, content) dataController.addSc(name, content)
} else { } else {
dataController.remove(id) dataController.remove(name)
} }
} }
} }
@ -95,7 +97,7 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
} else { } else {
buildContainer(it, this) buildContainer(it, this)
} }
}.sortedWith(Comparator.comparing({ it.id }, AlphanumComparator)).asObservable() }.sortedWith(Comparator.comparing({ it.name.toString() }, AlphanumComparator)).asObservable()
is NumassSet -> content.points is NumassSet -> content.points
.sortedBy { it.index } .sortedBy { it.index }
.map { buildContainer(it, this) } .map { buildContainer(it, this) }
@ -117,7 +119,7 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
storageProperty.onChange { storage -> storageProperty.onChange { storage ->
dataController.clear() dataController.clear()
if (storage == null) return@onChange if (storage == null) return@onChange
root = TreeItem(Container(storage.name, storage)) root = TreeItem(Container(storage.name.asName(), storage))
root.isExpanded = true root.isExpanded = true
lazyPopulate(leafCheck = { lazyPopulate(leafCheck = {
!it.value.hasChildren !it.value.hasChildren
@ -152,7 +154,7 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
} }
} }
else -> { else -> {
text = value.id text = value.name.toString()
graphic = null graphic = null
} }
} }
@ -210,19 +212,19 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
private fun buildContainer(content: Any, parent: Container): Container = private fun buildContainer(content: Any, parent: Container): Container =
when (content) { when (content) {
is Storage -> Container(content.fullName.toString(), content) is Storage -> Container(content.fullName, content)
is NumassSet -> { is NumassSet -> {
val id: String = if (content is NumassDataLoader) { val id: Name = if (content is NumassDataLoader) {
content.fullName.unescaped content.fullName
} else { } else {
content.name content.name.asName()
} }
Container(id, content) Container(id, content)
} }
is NumassPoint -> { is NumassPoint -> {
Container("${parent.id}/${content.voltage}[${content.index}]", content) Container("${parent.name}/${content.voltage}[${content.index}]".asName(), content)
} }
is FileTableLoader -> Container(content.path.toString(), content) is FileTableLoader -> Container(Name.of(content.path.map { it.toString().asName() }), content)
else -> throw IllegalArgumentException("Unknown content type: ${content::class.java}"); else -> throw IllegalArgumentException("Unknown content type: ${content::class.java}");
} }
} }

View File

@ -64,7 +64,7 @@ class TimeView : View(title = "Numass time spectrum plot", icon = ImageView(dfIc
init { init {
data.addListener(MapChangeListener { change -> data.addListener(MapChangeListener { change ->
val key = change.key val key = change.key.toString()
if (change.wasAdded()) { if (change.wasAdded()) {
replotOne(key, change.valueAdded) replotOne(key, change.valueAdded)
} else if(change.wasRemoved()){ } else if(change.wasRemoved()){
@ -105,16 +105,5 @@ class TimeView : View(title = "Numass time spectrum plot", icon = ImageView(dfIc
} }
} }
private fun replot() {
frame.plots.clear()
plotJobs.forEach { (_, job) -> job.cancel() }
plotJobs.clear()
data.forEach { (key, point) ->
replotOne(key, point)
}
}
} }