[WIP] directory watcher
This commit is contained in:
parent
d683170a73
commit
f7d9aff838
@ -59,7 +59,28 @@ runtime {
|
||||
)
|
||||
jpackage {
|
||||
jvmArgs = addJvmArgs
|
||||
//imageOptions = listOf("--linux-deb-maintainer", "nozik.aa@mipt.ru", "--linux-menu-group", "Science")
|
||||
val currentOs = org.gradle.internal.os.OperatingSystem.current()
|
||||
installerOptions = installerOptions + listOf("--vendor", "MIPT-NPM lab")
|
||||
|
||||
if (currentOs.isWindows) {
|
||||
installerOptions = installerOptions + listOf(
|
||||
"--win-menu",
|
||||
"--win-menu-group", "Numass",
|
||||
"--win-dir-chooser",
|
||||
"--win-shortcut"
|
||||
)
|
||||
} else if (currentOs.isLinux) {
|
||||
installerType = "deb"
|
||||
installerOptions = installerOptions + listOf(
|
||||
"--linux-package-name", "numass-viewer",
|
||||
"--linux-shortcut"
|
||||
)
|
||||
imageOptions = listOf(
|
||||
"--linux-deb-maintainer", "nozik.aa@mipt.ru",
|
||||
"--linux-menu-group", "Science",
|
||||
"--linux-shortcut"
|
||||
)
|
||||
}
|
||||
}
|
||||
launcher {
|
||||
jvmArgs = addJvmArgs
|
||||
|
@ -56,7 +56,7 @@ class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = Imag
|
||||
var normalize by normalizeProperty
|
||||
|
||||
|
||||
private val container = PlotContainer(frame).apply {
|
||||
private val plotContainer = PlotContainer(frame).apply {
|
||||
val binningSelector: ChoiceBox<Int> = ChoiceBox(FXCollections.observableArrayList(1, 2, 8, 16, 32, 50)).apply {
|
||||
minWidth = 0.0
|
||||
selectionModel.selectLast()
|
||||
@ -71,7 +71,6 @@ class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = Imag
|
||||
|
||||
private val plotJobs: ObservableMap<String, Job> = FXCollections.observableHashMap()
|
||||
|
||||
val isEmpty = booleanBinding(data) { isEmpty() }
|
||||
|
||||
private val progress = object : DoubleBinding() {
|
||||
init {
|
||||
@ -102,7 +101,7 @@ class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = Imag
|
||||
replot()
|
||||
}
|
||||
|
||||
container.progressProperty.bind(progress)
|
||||
plotContainer.progressProperty.bind(progress)
|
||||
}
|
||||
|
||||
private fun replotOne(key: String, point: DataController.CachedPoint) {
|
||||
@ -159,6 +158,6 @@ class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = Imag
|
||||
}
|
||||
|
||||
override val root = borderpane {
|
||||
center = container.root
|
||||
center = plotContainer.root
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ class DataController : Controller() {
|
||||
|
||||
val voltage = point.voltage
|
||||
|
||||
val index = point.index
|
||||
|
||||
val meta = point.meta
|
||||
|
||||
val channelSpectra: Deferred<Map<Int, Table>> = context.async(Dispatchers.IO) {
|
||||
|
@ -0,0 +1,107 @@
|
||||
package inr.numass.viewer
|
||||
|
||||
import hep.dataforge.fx.dfIconView
|
||||
import hep.dataforge.io.envelopes.Envelope
|
||||
import inr.numass.data.NumassDataUtils
|
||||
import inr.numass.data.NumassEnvelopeType
|
||||
import inr.numass.data.storage.NumassDataLoader
|
||||
import javafx.beans.property.SimpleObjectProperty
|
||||
import javafx.collections.FXCollections
|
||||
import javafx.collections.MapChangeListener
|
||||
import javafx.scene.control.ContextMenu
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import tornadofx.*
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardWatchEventKinds.ENTRY_CREATE
|
||||
import java.nio.file.WatchKey
|
||||
|
||||
class DirectoryWatchView : View(title = "Numass storage", icon = dfIconView) {
|
||||
|
||||
val pathProperty = SimpleObjectProperty<Path>()
|
||||
private val dataController by inject<DataController>()
|
||||
|
||||
private val ampView: AmplitudeView by inject()
|
||||
private val timeView: TimeView by inject()
|
||||
|
||||
private var watcherProperty = pathProperty.objectBinding {
|
||||
it?.fileSystem?.newWatchService()
|
||||
}
|
||||
|
||||
private val files = FXCollections.observableArrayList<DataController.CachedPoint>()
|
||||
|
||||
private var watchJob: Job? = null
|
||||
|
||||
init {
|
||||
dataController.points.addListener(MapChangeListener { change ->
|
||||
if (change.wasAdded()) {
|
||||
files.add(change.valueAdded)
|
||||
} else if (change.wasRemoved()) {
|
||||
files.remove(change.valueRemoved)
|
||||
}
|
||||
})
|
||||
|
||||
watcherProperty.onChange { watchService ->
|
||||
watchJob?.cancel()
|
||||
if (watchService != null) {
|
||||
watchJob = app.context.launch(Dispatchers.IO) {
|
||||
val key: WatchKey = pathProperty.get().register(watchService, ENTRY_CREATE)
|
||||
coroutineContext[Job]?.invokeOnCompletion {
|
||||
key.cancel()
|
||||
}
|
||||
while (isActive) {
|
||||
try {
|
||||
key.pollEvents().forEach { event ->
|
||||
if (event.kind() == ENTRY_CREATE) {
|
||||
val path: Path = event.context() as Path
|
||||
if (path.fileName.toString().startsWith(NumassDataLoader.POINT_FRAGMENT_NAME)) {
|
||||
val envelope: Envelope = NumassEnvelopeType.infer(path)?.reader?.read(path)
|
||||
?: kotlin.error("Can't read point file")
|
||||
val point = NumassDataUtils.read(envelope)
|
||||
files.add(dataController.getCachedPoint(path.toString(), point))
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (x: Throwable) {
|
||||
app.context.logger.error("Error during dynamic point read", x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override val root = splitpane {
|
||||
listview(files) {
|
||||
multiSelect(true)
|
||||
cellFormat { value: DataController.CachedPoint ->
|
||||
text = "${value.voltage}[${value.index}]"
|
||||
graphic = null
|
||||
contextMenu = ContextMenu().apply {
|
||||
item("Info") {
|
||||
action {
|
||||
PointInfoView(value).openModal(escapeClosesWindow = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tabpane {
|
||||
tab("Amplitude spectra") {
|
||||
content = ampView.root
|
||||
isClosable = false
|
||||
//visibleWhen(ampView.isEmpty.not())
|
||||
}
|
||||
tab("Time spectra") {
|
||||
content = timeView.root
|
||||
isClosable = false
|
||||
//visibleWhen(ampView.isEmpty.not())
|
||||
}
|
||||
}
|
||||
setDividerPosition(0, 0.3);
|
||||
}
|
||||
}
|
@ -43,6 +43,17 @@ class MainView : View(title = "Numass viewer", icon = dfIconView) {
|
||||
|
||||
private val contentViewProperty = SimpleObjectProperty<UIComponent>()
|
||||
private var contentView: UIComponent? by contentViewProperty
|
||||
private val spectrumView by inject<SpectrumView>()
|
||||
private val amplitudeView by inject<AmplitudeView>()
|
||||
private val directoryWatchView by inject<DirectoryWatchView>()
|
||||
|
||||
init {
|
||||
contentViewProperty.onChange {
|
||||
root.center = it?.root
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override val root = borderpane {
|
||||
prefHeight = 600.0
|
||||
@ -72,10 +83,38 @@ class MainView : View(title = "Numass viewer", icon = dfIconView) {
|
||||
if (rootDir != null) {
|
||||
NumassProperties.setNumassProperty("numass.viewer.lastPath", rootDir.absolutePath)
|
||||
app.context.launch {
|
||||
dataController.clear()
|
||||
runLater {
|
||||
path = rootDir.toPath()
|
||||
contentView = null
|
||||
}
|
||||
if (Files.exists(path.resolve(NumassDataLoader.META_FRAGMENT_NAME))) {
|
||||
//build set view
|
||||
runGoal(app.context, "viewer.load.set[$path]", Dispatchers.IO) {
|
||||
title = "Load set ($path)"
|
||||
message = "Building numass set..."
|
||||
NumassDataLoader(app.context, null, path.fileName.toString(), path)
|
||||
} ui { loader: NumassDataLoader ->
|
||||
contentView = spectrumView
|
||||
dataController.addSet(loader.name, loader)
|
||||
|
||||
} except {
|
||||
alert(
|
||||
type = Alert.AlertType.ERROR,
|
||||
header = "Error during set loading",
|
||||
content = it.toString()
|
||||
).show()
|
||||
}
|
||||
} else {
|
||||
//build storage
|
||||
app.context.launch {
|
||||
val storageElement = NumassDirectory.INSTANCE.read(app.context, path) as Storage
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
contentView = storageView
|
||||
storageView.storageProperty.set(storageElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
load(rootDir.toPath())
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
@ -102,10 +141,69 @@ class MainView : View(title = "Numass viewer", icon = dfIconView) {
|
||||
NumassProperties.setNumassProperty("numass.viewer.lastPath",
|
||||
file.parentFile.absolutePath)
|
||||
app.context.launch {
|
||||
dataController.clear()
|
||||
runLater {
|
||||
path = file.toPath()
|
||||
contentView = null
|
||||
}
|
||||
//Reading individual file
|
||||
val envelope = try {
|
||||
NumassFileEnvelope(path)
|
||||
} catch (ex: Exception) {
|
||||
runLater {
|
||||
alert(
|
||||
type = Alert.AlertType.ERROR,
|
||||
header = "Can't load DF envelope from file $path",
|
||||
content = ex.toString()
|
||||
).show()
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
envelope?.let {
|
||||
//try to read as point
|
||||
val point = NumassDataUtils.read(it)
|
||||
runLater {
|
||||
contentView = amplitudeView
|
||||
dataController.addPoint(path.fileName.toString(), point)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
NumassProperties.setNumassProperty("numass.viewer.lastPath", null)
|
||||
error("Error", content = "Failed to laod file with message: ${ex.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button("Watch directory") {
|
||||
action {
|
||||
val chooser = DirectoryChooser()
|
||||
chooser.title = "Select directory to view"
|
||||
val homeDir = NumassProperties.getNumassProperty("numass.viewer.lastPath")
|
||||
try {
|
||||
if (homeDir == null) {
|
||||
chooser.initialDirectory = File(".").absoluteFile
|
||||
} else {
|
||||
val file = File(homeDir)
|
||||
if (file.isDirectory) {
|
||||
chooser.initialDirectory = file
|
||||
} else {
|
||||
chooser.initialDirectory = file.parentFile
|
||||
}
|
||||
}
|
||||
|
||||
val dir = chooser.showDialog(primaryStage.scene.window)
|
||||
|
||||
if (dir != null) {
|
||||
NumassProperties.setNumassProperty("numass.viewer.lastPath", dir.absolutePath)
|
||||
app.context.launch {
|
||||
dataController.clear()
|
||||
runLater {
|
||||
path = dir.toPath()
|
||||
contentView = null
|
||||
}
|
||||
load(file.toPath())
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
@ -131,72 +229,4 @@ class MainView : View(title = "Numass viewer", icon = dfIconView) {
|
||||
bottom = statusBar
|
||||
}
|
||||
|
||||
init {
|
||||
contentViewProperty.onChange {
|
||||
root.center = it?.root
|
||||
}
|
||||
}
|
||||
|
||||
private val spectrumView by inject<SpectrumView>()
|
||||
|
||||
private suspend fun load(path: Path) {
|
||||
runLater {
|
||||
contentView = null
|
||||
}
|
||||
dataController.clear()
|
||||
if (Files.isDirectory(path)) {
|
||||
if (Files.exists(path.resolve(NumassDataLoader.META_FRAGMENT_NAME))) {
|
||||
//build set view
|
||||
runGoal(app.context, "viewer.load.set[$path]", Dispatchers.IO) {
|
||||
title = "Load set ($path)"
|
||||
message = "Building numass set..."
|
||||
NumassDataLoader(app.context, null, path.fileName.toString(), path)
|
||||
} ui { loader: NumassDataLoader ->
|
||||
contentView = spectrumView
|
||||
dataController.addSet(loader.name, loader)
|
||||
|
||||
} except {
|
||||
alert(
|
||||
type = Alert.AlertType.ERROR,
|
||||
header = "Error during set loading",
|
||||
content = it.toString()
|
||||
).show()
|
||||
}
|
||||
} else {
|
||||
//build storage
|
||||
app.context.launch {
|
||||
val storageElement = NumassDirectory.INSTANCE.read(app.context, path) as Storage
|
||||
withContext(Dispatchers.JavaFx) {
|
||||
contentView = storageView
|
||||
storageView.storageProperty.set(storageElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Reading individual file
|
||||
val envelope = try {
|
||||
NumassFileEnvelope(path)
|
||||
} catch (ex: Exception) {
|
||||
runLater {
|
||||
alert(
|
||||
type = Alert.AlertType.ERROR,
|
||||
header = "Can't load DF envelope from file $path",
|
||||
content = ex.toString()
|
||||
).show()
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
envelope?.let {
|
||||
//try to read as point
|
||||
val point = NumassDataUtils.read(it)
|
||||
runLater {
|
||||
contentView = AmplitudeView().apply {
|
||||
dataController.addPoint(path.fileName.toString(), point)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,12 +33,6 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
|
||||
private val hvView: HVView by inject()
|
||||
private val scView: SlowControlView by inject()
|
||||
|
||||
// private var watcher: WatchService? = null
|
||||
|
||||
fun clear() {
|
||||
dataController.clear()
|
||||
}
|
||||
|
||||
private inner class Container(val id: String, val content: Any) {
|
||||
val checkedProperty = SimpleBooleanProperty(false)
|
||||
var checked by checkedProperty
|
||||
@ -102,38 +96,6 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
|
||||
|
||||
private var watchJob: Job? = null
|
||||
|
||||
// private fun toggleWatch(watch: Boolean) {
|
||||
// if (watch) {
|
||||
// if (watchJob != null && content is NumassDataLoader) {
|
||||
// watchJob = app.context.launch(Dispatchers.IO) {
|
||||
// val key: WatchKey = content.path.register(watcher!!, ENTRY_CREATE)
|
||||
// coroutineContext[Job]?.invokeOnCompletion {
|
||||
// key.cancel()
|
||||
// }
|
||||
// while (watcher != null && isActive) {
|
||||
// try {
|
||||
// key.pollEvents().forEach { event ->
|
||||
// if (event.kind() == ENTRY_CREATE) {
|
||||
// val path: Path = event.context() as Path
|
||||
// if (path.fileName.toString().startsWith(NumassDataLoader.POINT_FRAGMENT_NAME)) {
|
||||
// val envelope: Envelope = NumassEnvelopeType.infer(path)?.reader?.read(path)
|
||||
// ?: kotlin.error("Can't read point file")
|
||||
// val point = NumassDataUtils.read(envelope)
|
||||
// children!!.add(buildContainer(point, this@Container))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } catch (x: Throwable) {
|
||||
// app.context.logger.error("Error during dynamic point read", x)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// watchJob?.cancel()
|
||||
// watchJob = null
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
@ -141,7 +103,7 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
|
||||
treeview<Container> {
|
||||
//isShowRoot = false
|
||||
storageProperty.onChange { storage ->
|
||||
clear()
|
||||
dataController.clear()
|
||||
if (storage == null) return@onChange
|
||||
root = TreeItem(Container(storage.name, storage))
|
||||
root.isExpanded = true
|
||||
@ -150,12 +112,7 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
|
||||
}) {
|
||||
it.value.children
|
||||
}
|
||||
// watcher?.close()
|
||||
// watcher = if (storage is FileStorage) {
|
||||
// storage.path.fileSystem.newWatchService()
|
||||
// } else {
|
||||
// null
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
cellFormat { value: Container ->
|
||||
@ -198,11 +155,6 @@ class StorageView : View(title = "Numass storage", icon = dfIconView) {
|
||||
value.infoView.openModal(escapeClosesWindow = true)
|
||||
}
|
||||
}
|
||||
// if(value.content is NumassDataLoader) {
|
||||
// checkmenuitem("Watch") {
|
||||
// selectedProperty().bindBidirectional(value.watchedProperty)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user