[no commit message]
This commit is contained in:
parent
10f98472a8
commit
b6323d2f90
@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class MagnetController implements PortHandler.PortController {
|
||||
|
||||
public static double CURRENT_PRECISION = 0.01;
|
||||
public static double CURRENT_PRECISION = 0.05;
|
||||
// public static double CURRENT_STEP = 0.05;
|
||||
public static int DEFAULT_DELAY = 1;
|
||||
public static int DEFAULT_MONITOR_DELAY = 2000;
|
||||
@ -353,10 +353,11 @@ public class MagnetController implements PortHandler.PortController {
|
||||
*/
|
||||
public void stopMonitorTask() {
|
||||
if (monitorTask != null) {
|
||||
monitorTask.cancel(false);
|
||||
monitorTask.cancel(true);
|
||||
if (listener != null) {
|
||||
listener.monitorTaskStateChanged(getName(), false);
|
||||
}
|
||||
monitorTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ import hep.dataforge.points.MapPoint;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.fx.ConsoleWindow;
|
||||
import hep.dataforge.fx.ConsoleFragment;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.meta.ConfigChangeListener;
|
||||
import hep.dataforge.meta.Configuration;
|
||||
@ -88,7 +88,7 @@ public class MspViewController implements Initializable, MspListener {
|
||||
|
||||
private final String mspName = "msp";
|
||||
|
||||
private ConsoleWindow logArea;
|
||||
private ConsoleFragment logArea;
|
||||
|
||||
private final ConfigChangeListener viewConfigObserver = new ConfigChangeListener() {
|
||||
|
||||
@ -131,7 +131,8 @@ public class MspViewController implements Initializable, MspListener {
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
logArea = new ConsoleWindow(consoleButton);
|
||||
logArea = new ConsoleFragment();
|
||||
logArea.bindTo(consoleButton);
|
||||
fillamentSelector.setItems(FXCollections.observableArrayList(1, 2));
|
||||
fillamentSelector.setConverter(new StringConverter<Integer>() {
|
||||
@Override
|
||||
|
@ -15,7 +15,7 @@ import hep.dataforge.control.measurements.Sensor;
|
||||
import hep.dataforge.points.DataPoint;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.MeasurementException;
|
||||
import hep.dataforge.fx.ConsoleWindow;
|
||||
import hep.dataforge.fx.ConsoleFragment;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.plots.PlotFrame;
|
||||
@ -80,8 +80,8 @@ public class VacCollectorController implements Initializable, DeviceListener, Me
|
||||
private DynamicPlottableSet plottables;
|
||||
private BiFunction<VacCollectorDevice, Storage, PointLoader> loaderFactory;
|
||||
|
||||
ConsoleWindow consoleWindow;
|
||||
|
||||
ConsoleFragment consoleWindow;
|
||||
|
||||
@FXML
|
||||
private AnchorPane plotHolder;
|
||||
@FXML
|
||||
@ -115,7 +115,8 @@ public class VacCollectorController implements Initializable, DeviceListener, Me
|
||||
}
|
||||
});
|
||||
|
||||
consoleWindow = new ConsoleWindow(logButton);
|
||||
consoleWindow = new ConsoleFragment();
|
||||
consoleWindow.bindTo(logButton);
|
||||
consoleWindow.hookStd();
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import hep.dataforge.fx.FXProcessManager;
|
||||
import hep.dataforge.fx.LogOutputPane;
|
||||
import hep.dataforge.fx.MetaEditor;
|
||||
import hep.dataforge.fx.MetaTreeItem;
|
||||
import hep.dataforge.fx.ProcessManagerFragment;
|
||||
import hep.dataforge.io.IOManager;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.meta.ConfigChangeListener;
|
||||
@ -49,16 +50,13 @@ import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Accordion;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TitledPane;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.controlsfx.control.StatusBar;
|
||||
|
||||
/**
|
||||
@ -80,8 +78,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
|
||||
|
||||
Map<String, StagePane> stages = new ConcurrentHashMap<>();
|
||||
|
||||
FXProcessManager processManager = new FXProcessManager();
|
||||
Stage processManagerStage;
|
||||
ProcessManagerFragment processWindow = new ProcessManagerFragment(new FXProcessManager());
|
||||
|
||||
@FXML
|
||||
private StatusBar statusBar;
|
||||
@ -94,7 +91,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
|
||||
@FXML
|
||||
private Accordion metaContainer;
|
||||
@FXML
|
||||
private Tab LogTab;
|
||||
private Tab logTab;
|
||||
|
||||
LogOutputPane logPane;
|
||||
@FXML
|
||||
@ -119,7 +116,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
logPane = new LogOutputPane();
|
||||
LogTab.setContent(logPane);
|
||||
logTab.setContent(logPane);
|
||||
ConsoleDude.hookStdStreams(consoleArea);
|
||||
}
|
||||
|
||||
@ -134,7 +131,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
|
||||
private void buildContext(Meta config) {
|
||||
this.context = this.contextFactory.build(parentContext, config);
|
||||
context.setIO(new WorkbenchIOManager(new NumassIO(), this));
|
||||
context.setProcessManager(processManager);
|
||||
processWindow = ProcessManagerFragment.attachToContext(context);
|
||||
buildContextPane();
|
||||
this.logPane.attachLog(context);
|
||||
context.getLogger().addAppender(logPane.getLoggerAppender());
|
||||
@ -144,19 +141,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
|
||||
((PlotsPlugin) context.provide("plots")).setPlotHolderDelegate(this);
|
||||
}
|
||||
|
||||
private void showTaskPane() {
|
||||
if (processManagerStage == null) {
|
||||
processManagerStage = new Stage();
|
||||
processManagerStage.setWidth(400);
|
||||
processManagerStage.setHeight(400);
|
||||
AnchorPane pane = new AnchorPane();
|
||||
processManager.show(pane);
|
||||
Scene scene = new Scene(pane, 400, 400);
|
||||
processManagerStage.setTitle("Task manager");
|
||||
processManagerStage.setScene(scene);
|
||||
}
|
||||
processManagerStage.show();
|
||||
}
|
||||
|
||||
|
||||
private Tab findTabWithName(TabPane pane, String name) {
|
||||
return pane.getTabs().stream().filter((t) -> t.getText().equals(name)).findFirst().orElse(null);
|
||||
@ -326,7 +311,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
|
||||
@SuppressWarnings("unchecked")
|
||||
public void runActions() {
|
||||
clearAllStages();
|
||||
showTaskPane();
|
||||
processWindow.show();
|
||||
new Thread(() -> {
|
||||
DataNode data = new FileDataFactory().build(getContext(), getDataConfiguration());
|
||||
if (data.isEmpty()) {
|
||||
|
@ -29,7 +29,7 @@ public class TextOutputTab extends OutputTab {
|
||||
super(name);
|
||||
// out = new DataOutputPane();
|
||||
out = new FXDataOutputPane();
|
||||
setContent(out);
|
||||
setContent(out.getHolder());
|
||||
setOnClosed((Event event) -> close());
|
||||
}
|
||||
|
||||
@ -43,8 +43,8 @@ public class TextOutputTab extends OutputTab {
|
||||
clear();
|
||||
}
|
||||
|
||||
public OutputStream getStream(OutputStream forward) {
|
||||
return out.getOutputStream(forward);
|
||||
public OutputStream getStream() {
|
||||
return out.getOutputStream();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import hep.dataforge.names.Name;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import org.apache.commons.io.output.TeeOutputStream;
|
||||
|
||||
/**
|
||||
* An IOManager wrapper that redirects output to appropriate FX components
|
||||
@ -53,7 +54,9 @@ public class WorkbenchIOManager implements IOManager {
|
||||
|
||||
@Override
|
||||
public OutputStream out(Name stage, Name name) {
|
||||
return holder.getStagePane(stage.toString()).buildTextOutput(name.toString()).getStream(manager.out(stage, name));
|
||||
OutputStream primary = holder.getStagePane(stage.toString()).buildTextOutput(name.toString()).getStream();
|
||||
OutputStream secondary = manager.out(stage, name);
|
||||
return new TeeOutputStream(primary, secondary);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,16 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package inr.numass.viewer;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik <altavir@gmail.com>
|
||||
*/
|
||||
public interface FXTaskManager {
|
||||
void postTask(Task task);
|
||||
}
|
@ -15,16 +15,19 @@
|
||||
*/
|
||||
package inr.numass.viewer;
|
||||
|
||||
import de.jensd.shichimifx.utils.ConsoleDude;
|
||||
import de.jensd.shichimifx.utils.SplitPaneDividerSlider;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.context.ProcessManager;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.fx.ConsoleFragment;
|
||||
import hep.dataforge.fx.ProcessManagerFragment;
|
||||
import inr.numass.data.NumassData;
|
||||
import inr.numass.storage.NumassStorage;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.application.Platform;
|
||||
@ -39,41 +42,35 @@ import javafx.scene.control.ButtonBar.ButtonData;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Dialog;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.SplitPane;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.control.TreeTableView;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import javafx.util.Duration;
|
||||
import javafx.util.Pair;
|
||||
import org.controlsfx.control.StatusBar;
|
||||
import org.controlsfx.control.TaskProgressView;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class MainViewerController implements Initializable, FXTaskManager {
|
||||
public class MainViewerController implements Initializable {
|
||||
|
||||
public static MainViewerController build(NumassStorage root) {
|
||||
MainViewerController res = new MainViewerController();
|
||||
res.setRootStorage(root);
|
||||
return res;
|
||||
}
|
||||
@FXML
|
||||
private TextArea consoleArea;
|
||||
|
||||
// private ConsoleFragment consoleFragment;
|
||||
// private ProcessManagerFragment processFragment = ProcessManagerFragment.attachToContext(GlobalContext.instance());
|
||||
@FXML
|
||||
private ToggleButton consoleButton;
|
||||
@FXML
|
||||
private SplitPane consoleSplit;
|
||||
@FXML
|
||||
private Button loadDirectoryButton;
|
||||
|
||||
private MspViewController mspController;
|
||||
@ -105,9 +102,7 @@ public class MainViewerController implements Initializable, FXTaskManager {
|
||||
@FXML
|
||||
private Label storagePathLabel;
|
||||
@FXML
|
||||
private ScrollPane taskPane;
|
||||
|
||||
private TaskProgressView progressView;
|
||||
private ToggleButton processManagerButton;
|
||||
|
||||
// private Popup progressPopup;
|
||||
/**
|
||||
@ -118,20 +113,10 @@ public class MainViewerController implements Initializable, FXTaskManager {
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
// TabPaneDetacher.create().makeTabsDetachable(tabPane);
|
||||
ConsoleDude.hookStdStreams(consoleArea);
|
||||
|
||||
SplitPaneDividerSlider slider = new SplitPaneDividerSlider(consoleSplit, 0,
|
||||
SplitPaneDividerSlider.Direction.DOWN, Duration.seconds(1));
|
||||
|
||||
slider.aimContentVisibleProperty().bindBidirectional(consoleButton.selectedProperty());
|
||||
|
||||
consoleButton.setSelected(false);
|
||||
// loadRemoteButton.setDisable(true);
|
||||
|
||||
progressView = new TaskProgressView();
|
||||
taskPane.setContent(progressView);
|
||||
// taskPane.setPrefWidth(510);
|
||||
ConsoleFragment consoleFragment = new ConsoleFragment();
|
||||
consoleFragment.hookStd();
|
||||
consoleFragment.bindTo(consoleButton);
|
||||
ProcessManagerFragment.attachToContext(GlobalContext.instance()).bindTo(processManagerButton);
|
||||
}
|
||||
|
||||
@FXML
|
||||
@ -144,11 +129,25 @@ public class MainViewerController implements Initializable, FXTaskManager {
|
||||
final File rootDir = chooser.showDialog(((Node) event.getTarget()).getScene().getWindow());
|
||||
|
||||
if (rootDir != null) {
|
||||
Task dirLoadTask = new DirectoryLoadTask(rootDir.toURI().toString());
|
||||
postTask(dirLoadTask);
|
||||
Viewer.runTask(dirLoadTask);
|
||||
loadDirectory(rootDir.toURI().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void loadDirectory(String path) {
|
||||
getContext().processManager().post("viewer.loadDirectory", (ProcessManager.Callback callback) -> {
|
||||
callback.updateTitle("Load storage (" + path + ")");
|
||||
callback.updateProgress(-1, 1);
|
||||
callback.updateMessage("Building numass storage tree...");
|
||||
try {
|
||||
NumassStorage root = NumassStorage.buildNumassRoot(path, true, false);
|
||||
setRootStorage(root);
|
||||
Platform.runLater(() -> storagePathLabel.setText("Storage: " + path));
|
||||
} catch (StorageException ex) {
|
||||
callback.updateProgress(0, 1);
|
||||
callback.updateMessage("Failed to load storage " + path);
|
||||
Logger.getLogger(MainViewerController.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class DirectoryLoadTask extends Task<Void> {
|
||||
@ -178,18 +177,42 @@ public class MainViewerController implements Initializable, FXTaskManager {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void postTask(Task task) {
|
||||
Platform.runLater(() -> progressView.getTasks().add(task));
|
||||
private Context getContext() {
|
||||
return GlobalContext.instance();
|
||||
}
|
||||
|
||||
public void setRootStorage(NumassStorage root) {
|
||||
Task fillTask = new StorageDataFillTask(root);
|
||||
postTask(fillTask);
|
||||
Viewer.runTask(fillTask);
|
||||
// Task fillTask = new StorageDataFillTask(root);
|
||||
// postTask(fillTask);
|
||||
// Viewer.runTask(fillTask);
|
||||
|
||||
mspController = new MspViewController(this, mspPlotPane);
|
||||
getContext().processManager().post("viewer.storage.load", new Consumer<ProcessManager.Callback>() {
|
||||
@Override
|
||||
public void accept(ProcessManager.Callback callback) {
|
||||
callback.updateTitle("Fill data to UI (" + root.getName() + ")");
|
||||
callback.updateProgress(-1, 1);
|
||||
callback.updateMessage("Loading numass storage tree...");
|
||||
|
||||
new NumassLoaderTreeBuilder().build(getContext(), numassLoaderDataTree, root, (NumassData loader) -> {
|
||||
NumassLoaderViewComponent component = new NumassLoaderViewComponent(getContext());
|
||||
component.loadData(loader);
|
||||
numassLoaderViewContainer.getChildren().clear();
|
||||
numassLoaderViewContainer.getChildren().add(component);
|
||||
AnchorPane.setTopAnchor(component, 0.0);
|
||||
AnchorPane.setRightAnchor(component, 0.0);
|
||||
AnchorPane.setLeftAnchor(component, 0.0);
|
||||
AnchorPane.setBottomAnchor(component, 0.0);
|
||||
numassLoaderViewContainer.requestLayout();
|
||||
});
|
||||
|
||||
callback.updateProgress(0, 1);
|
||||
callback.updateMessage("Numass storage tree loaded.");
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
mspController = new MspViewController(getContext(), mspPlotPane);
|
||||
mspController.fillMspData(root);
|
||||
|
||||
pressuresTab.getContent().setVisible(false);
|
||||
@ -197,48 +220,6 @@ public class MainViewerController implements Initializable, FXTaskManager {
|
||||
|
||||
}
|
||||
|
||||
private class StorageDataFillTask extends Task<Void> {
|
||||
|
||||
private final NumassStorage root;
|
||||
|
||||
public StorageDataFillTask(NumassStorage root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void call() throws Exception {
|
||||
updateTitle("Fill data to UI (" + root.getName() + ")");
|
||||
this.updateProgress(-1, 1);
|
||||
this.updateMessage("Loading numass storage tree...");
|
||||
|
||||
Task treeBuilderTask = new NumassLoaderTreeBuilder(numassLoaderDataTree, root, (NumassData loader) -> {
|
||||
NumassLoaderViewComponent component = new NumassLoaderViewComponent();
|
||||
component.loadData(loader);
|
||||
component.setCallback(MainViewerController.this);
|
||||
numassLoaderViewContainer.getChildren().clear();
|
||||
numassLoaderViewContainer.getChildren().add(component);
|
||||
AnchorPane.setTopAnchor(component, 0.0);
|
||||
AnchorPane.setRightAnchor(component, 0.0);
|
||||
AnchorPane.setLeftAnchor(component, 0.0);
|
||||
AnchorPane.setBottomAnchor(component, 0.0);
|
||||
numassLoaderViewContainer.requestLayout();
|
||||
});
|
||||
postTask(treeBuilderTask);
|
||||
Viewer.runTask(treeBuilderTask);
|
||||
try {
|
||||
treeBuilderTask.get();
|
||||
this.updateProgress(0, 1);
|
||||
this.updateMessage("Numass storage tree loaded.");
|
||||
this.succeeded();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
this.failed();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onLoadRemote(ActionEvent event) {
|
||||
// Create the custom dialog.
|
||||
@ -282,9 +263,8 @@ public class MainViewerController implements Initializable, FXTaskManager {
|
||||
Optional<Pair<String, String>> result = dialog.showAndWait();
|
||||
|
||||
if (result.isPresent()) {
|
||||
Task dirLoadTask = new DirectoryLoadTask(result.get().getKey() + "/data/" + result.get().getValue());
|
||||
postTask(dirLoadTask);
|
||||
Viewer.runTask(dirLoadTask);
|
||||
String path = result.get().getKey() + "/data/" + result.get().getValue();
|
||||
loadDirectory(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package inr.numass.viewer;
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.points.DataPoint;
|
||||
import hep.dataforge.points.MapPoint;
|
||||
import hep.dataforge.plots.PlotUtils;
|
||||
@ -45,12 +46,12 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class MspViewController {
|
||||
|
||||
private FXTaskManager callback;
|
||||
|
||||
private final AnchorPane mspPlotPane;
|
||||
private final Context context;
|
||||
|
||||
public MspViewController(FXTaskManager callback, AnchorPane mspPlotPane) {
|
||||
this.callback = callback;
|
||||
public MspViewController(Context context, AnchorPane mspPlotPane) {
|
||||
this.context = context;
|
||||
this.mspPlotPane = mspPlotPane;
|
||||
}
|
||||
|
||||
@ -168,9 +169,6 @@ public class MspViewController {
|
||||
|
||||
}
|
||||
|
||||
public void setCallback(FXTaskManager callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a null value point to terminate msp series
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package inr.numass.viewer;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.ProcessManager;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.storage.api.Loader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
@ -26,7 +28,6 @@ import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.control.TreeItem;
|
||||
import javafx.scene.control.TreeTableColumn;
|
||||
import javafx.scene.control.TreeTableView;
|
||||
@ -36,81 +37,89 @@ import javafx.scene.input.MouseEvent;
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class NumassLoaderTreeBuilder extends Task<Void> {
|
||||
public class NumassLoaderTreeBuilder {
|
||||
|
||||
private final TreeTableView<TreeItemValue> numassLoaderDataTree;
|
||||
private final NumassStorage rootStorage;
|
||||
private final Consumer<NumassData> numassViewBuilder;
|
||||
// private final TreeTableView<TreeItemValue> numassLoaderDataTree;
|
||||
// private final NumassStorage rootStorage;
|
||||
// private final Consumer<NumassData> numassViewBuilder;
|
||||
//
|
||||
// public NumassLoaderTreeBuilder(TreeTableView<TreeItemValue> numassLoaderDataTree, NumassStorage rootStorage, Consumer<NumassData> numassViewBuilder) {
|
||||
// this.numassLoaderDataTree = numassLoaderDataTree;
|
||||
// this.rootStorage = rootStorage;
|
||||
// this.numassViewBuilder = numassViewBuilder;
|
||||
// }
|
||||
public void build(Context context,
|
||||
TreeTableView<TreeItemValue> numassLoaderDataTree,
|
||||
NumassStorage rootStorage,
|
||||
Consumer<NumassData> numassViewBuilder) {
|
||||
|
||||
public NumassLoaderTreeBuilder(TreeTableView<TreeItemValue> numassLoaderDataTree, NumassStorage rootStorage, Consumer<NumassData> numassViewBuilder) {
|
||||
this.numassLoaderDataTree = numassLoaderDataTree;
|
||||
this.rootStorage = rootStorage;
|
||||
this.numassViewBuilder = numassViewBuilder;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Void call() throws Exception {
|
||||
updateTitle("Load numass data ("+rootStorage.getName()+")");
|
||||
TreeItem<TreeItemValue> root = buildNode(rootStorage, numassViewBuilder);
|
||||
root.setExpanded(true);
|
||||
context.processManager().post("viewer.storage.load.buildTree", (ProcessManager.Callback callback) -> {
|
||||
try {
|
||||
callback.updateTitle("Load numass data (" + rootStorage.getName() + ")");
|
||||
TreeItem<TreeItemValue> root = buildNode(rootStorage, numassViewBuilder, callback);
|
||||
root.setExpanded(true);
|
||||
|
||||
// numassLoaderDataTree.setShowRoot(true);
|
||||
Platform.runLater(() -> {
|
||||
numassLoaderDataTree.setRoot(root);
|
||||
Platform.runLater(() -> {
|
||||
numassLoaderDataTree.setRoot(root);
|
||||
|
||||
TreeTableColumn<TreeItemValue, String> numassLoaderNameColumn = new TreeTableColumn<>("name");
|
||||
TreeTableColumn<TreeItemValue, String> numassLoaderNameColumn = new TreeTableColumn<>("name");
|
||||
|
||||
numassLoaderNameColumn.setCellValueFactory(
|
||||
(TreeTableColumn.CellDataFeatures<TreeItemValue, String> param) -> new SimpleStringProperty(param.getValue().getValue().getName()));
|
||||
numassLoaderNameColumn.setCellValueFactory(
|
||||
(TreeTableColumn.CellDataFeatures<TreeItemValue, String> param) -> new SimpleStringProperty(param.getValue().getValue().getName()));
|
||||
|
||||
TreeTableColumn<TreeItemValue, String> numassLoaderTimeColumn = new TreeTableColumn<>("time");
|
||||
numassLoaderTimeColumn.setCellValueFactory(
|
||||
(TreeTableColumn.CellDataFeatures<TreeItemValue, String> param) -> new SimpleStringProperty(param.getValue().getValue().getTime()));
|
||||
TreeTableColumn<TreeItemValue, String> numassLoaderTimeColumn = new TreeTableColumn<>("time");
|
||||
numassLoaderTimeColumn.setCellValueFactory(
|
||||
(TreeTableColumn.CellDataFeatures<TreeItemValue, String> param) -> new SimpleStringProperty(param.getValue().getValue().getTime()));
|
||||
|
||||
TreeTableColumn<TreeItemValue, String> nummassLoaderDescriptionColumn = new TreeTableColumn<>("description");
|
||||
nummassLoaderDescriptionColumn.setCellValueFactory(
|
||||
(TreeTableColumn.CellDataFeatures<TreeItemValue, String> param) -> new SimpleStringProperty(param.getValue().getValue().getDescription()));
|
||||
TreeTableColumn<TreeItemValue, String> nummassLoaderDescriptionColumn = new TreeTableColumn<>("description");
|
||||
nummassLoaderDescriptionColumn.setCellValueFactory(
|
||||
(TreeTableColumn.CellDataFeatures<TreeItemValue, String> param) -> new SimpleStringProperty(param.getValue().getValue().getDescription()));
|
||||
|
||||
numassLoaderDataTree.getColumns().setAll(numassLoaderNameColumn, numassLoaderTimeColumn, nummassLoaderDescriptionColumn);
|
||||
numassLoaderDataTree.getColumns().setAll(numassLoaderNameColumn, numassLoaderTimeColumn, nummassLoaderDescriptionColumn);
|
||||
|
||||
numassLoaderDataTree.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> {
|
||||
if (e.getClickCount() == 2) {
|
||||
TreeItemValue value = numassLoaderDataTree.getFocusModel().getFocusedCell().getTreeItem().getValue();
|
||||
if (value.isLoader()) {
|
||||
numassViewBuilder.accept(value.getLoader());
|
||||
}
|
||||
}
|
||||
});
|
||||
numassLoaderTimeColumn.setVisible(false);
|
||||
nummassLoaderDescriptionColumn.setVisible(false);
|
||||
numassLoaderDataTree.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> {
|
||||
if (e.getClickCount() == 2) {
|
||||
TreeItemValue value = numassLoaderDataTree.getFocusModel().getFocusedCell().getTreeItem().getValue();
|
||||
if (value.isLoader()) {
|
||||
numassViewBuilder.accept(value.getLoader());
|
||||
}
|
||||
}
|
||||
});
|
||||
numassLoaderTimeColumn.setVisible(false);
|
||||
nummassLoaderDescriptionColumn.setVisible(false);
|
||||
});
|
||||
} catch (StorageException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private TreeItem<TreeItemValue> buildNode(NumassStorage storage, Consumer<NumassData> numassViewBuilder) throws StorageException {
|
||||
private TreeItem<TreeItemValue> buildNode(NumassStorage storage,
|
||||
Consumer<NumassData> numassViewBuilder, ProcessManager.Callback callback) throws StorageException {
|
||||
TreeItem<TreeItemValue> node = new TreeItem<>(buildValue(storage));
|
||||
node.getChildren().setAll(buildChildren(storage, numassViewBuilder));
|
||||
node.getChildren().setAll(buildChildren(storage, numassViewBuilder, callback));
|
||||
return node;
|
||||
}
|
||||
|
||||
private List<TreeItem<TreeItemValue>> buildChildren(NumassStorage storage, Consumer<NumassData> numassViewBuilder) throws StorageException {
|
||||
private List<TreeItem<TreeItemValue>> buildChildren(NumassStorage storage,
|
||||
Consumer<NumassData> numassViewBuilder, ProcessManager.Callback callback) throws StorageException {
|
||||
List<TreeItem<TreeItemValue>> list = new ArrayList<>();
|
||||
|
||||
for (Storage subStorage : storage.shelves().values()) {
|
||||
if (subStorage instanceof NumassStorage) {
|
||||
NumassStorage numassSubStorage = (NumassStorage) subStorage;
|
||||
list.add(buildNode(numassSubStorage, numassViewBuilder));
|
||||
list.add(buildNode(numassSubStorage, numassViewBuilder, callback));
|
||||
}
|
||||
}
|
||||
|
||||
updateMessage("Building storage " + storage.getName());
|
||||
callback.updateMessage("Building storage " + storage.getName());
|
||||
|
||||
double counter = 0;
|
||||
for (Loader loader : storage.loaders().values()) {
|
||||
updateMessage("Building numass data loader " + loader.getName());
|
||||
updateProgress(counter, storage.loaders().size());
|
||||
callback.updateMessage("Building numass data loader " + loader.getName());
|
||||
callback.updateProgress(counter, storage.loaders().size());
|
||||
|
||||
if (loader instanceof NumassData) {
|
||||
NumassData numassLoader = (NumassData) loader;
|
||||
@ -132,8 +141,8 @@ public class NumassLoaderTreeBuilder extends Task<Void> {
|
||||
//adding legacy data files
|
||||
counter = 0;
|
||||
for (NumassData legacyDat : storage.legacyFiles()) {
|
||||
updateMessage("Loading numass DAT file " + legacyDat.getName());
|
||||
updateProgress(counter, storage.loaders().size());
|
||||
callback.updateMessage("Loading numass DAT file " + legacyDat.getName());
|
||||
callback.updateProgress(counter, storage.loaders().size());
|
||||
TreeItem<TreeItemValue> numassLoaderTreeItem = new TreeItem<>(buildValue(legacyDat));
|
||||
list.add(numassLoaderTreeItem);
|
||||
counter++;
|
||||
|
@ -20,6 +20,8 @@ package inr.numass.viewer;
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.ProcessManager;
|
||||
import hep.dataforge.points.DataPoint;
|
||||
import hep.dataforge.points.ListPointSet;
|
||||
import hep.dataforge.points.MapPoint;
|
||||
@ -42,7 +44,6 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.application.Platform;
|
||||
@ -81,7 +82,7 @@ import hep.dataforge.points.PointSet;
|
||||
*/
|
||||
public class NumassLoaderViewComponent extends AnchorPane implements Initializable {
|
||||
|
||||
private FXTaskManager callback;
|
||||
private final Context context;
|
||||
|
||||
Logger logger = LoggerFactory.getLogger(NumassLoaderViewComponent.class);
|
||||
private NumassData data;
|
||||
@ -125,7 +126,8 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
|
||||
@FXML
|
||||
private TextField dTimeField;
|
||||
|
||||
public NumassLoaderViewComponent() {
|
||||
public NumassLoaderViewComponent(Context context) {
|
||||
this.context = context;
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/NumassLoaderView.fxml"));
|
||||
|
||||
loader.setRoot(this);
|
||||
@ -186,23 +188,30 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setCallback(FXTaskManager callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void loadData(NumassData data) {
|
||||
this.data = data;
|
||||
if (data != null) {
|
||||
LoadPointsTask task = new LoadPointsTask(data);
|
||||
if (callback != null) {
|
||||
callback.postTask(task);
|
||||
}
|
||||
Viewer.runTask(task);
|
||||
try {
|
||||
this.points = task.get();
|
||||
} catch (InterruptedException |ExecutionException ex) {
|
||||
logger.error("Can't load spectrum data points", ex);
|
||||
}
|
||||
context.processManager().<List<NMPoint>>post("viewer.numass.load", (ProcessManager.Callback callback) -> {
|
||||
callback.updateTitle("Load numass data (" + data.getName() + ")");
|
||||
points = data.getNMPoints();
|
||||
Platform.runLater(() -> {
|
||||
//setup detector data
|
||||
setupDetectorPane(points);
|
||||
//setup spectrum plot
|
||||
updateSpectrumPane(points);
|
||||
setupInfo(data);
|
||||
});
|
||||
});
|
||||
// LoadPointsTask task = new LoadPointsTask(data);
|
||||
// if (callback != null) {
|
||||
// callback.postTask(task);
|
||||
// }
|
||||
// Viewer.runTask(task);
|
||||
// try {
|
||||
// this.points = task.get();
|
||||
// } catch (InterruptedException | ExecutionException ex) {
|
||||
// logger.error("Can't load spectrum data points", ex);
|
||||
// }
|
||||
} else {
|
||||
logger.error("The data model is null");
|
||||
}
|
||||
@ -359,7 +368,7 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
|
||||
for (NMPoint point : points) {
|
||||
String seriesName = String.format("%d: %.2f (%.2f)", points.indexOf(point), point.getUset(), point.getUread());
|
||||
|
||||
PlottableData datum = PlottableData.plot(seriesName,new XYAdapter("chanel", "count"), point.getData(binning, normalize));
|
||||
PlottableData datum = PlottableData.plot(seriesName, new XYAdapter("chanel", "count"), point.getData(binning, normalize));
|
||||
datum.configure(plottableConfig);
|
||||
plottables.add(datum);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package inr.numass.viewer;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.storage.commons.StorageManager;
|
||||
import inr.numass.storage.NumassDataLoader;
|
||||
import java.io.File;
|
||||
@ -36,7 +37,7 @@ public class TestDirectoryViewer extends Application {
|
||||
NumassDataLoader reader = NumassDataLoader.fromLocalDir(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1\\"));
|
||||
// NumassLoader reader = NumassLoader.fromZip(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1.zip"));
|
||||
|
||||
NumassLoaderViewComponent comp = new NumassLoaderViewComponent();
|
||||
NumassLoaderViewComponent comp = new NumassLoaderViewComponent(GlobalContext.instance());
|
||||
comp.loadData(reader);
|
||||
// FXMLLoader fxml = new FXMLLoader(getClass().getResource("/fxml/DirectoryViewer.fxml"));
|
||||
//
|
||||
|
@ -49,14 +49,14 @@ public class Viewer extends Application {
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop();
|
||||
System.exit(0);
|
||||
// System.exit(0);
|
||||
}
|
||||
|
||||
public static void runTask(Task task) {
|
||||
Thread th = new Thread(task);
|
||||
th.setDaemon(true);
|
||||
th.start();
|
||||
}
|
||||
// public static void runTask(Task task) {
|
||||
// Thread th = new Thread(task);
|
||||
// th.setDaemon(true);
|
||||
// th.start();
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
|
@ -16,71 +16,24 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<?import javafx.geometry.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import org.controlsfx.control.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.SplitPane?>
|
||||
<?import javafx.scene.control.Tab?>
|
||||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.control.ToggleButton?>
|
||||
<?import javafx.scene.control.ToolBar?>
|
||||
<?import javafx.scene.control.TreeTableView?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<AnchorPane id="AnchorPane" prefHeight="768.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.viewer.MainViewerController">
|
||||
<AnchorPane id="AnchorPane" prefHeight="768.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.viewer.MainViewerController">
|
||||
<children>
|
||||
<BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<center>
|
||||
<SplitPane fx:id="consoleSplit" dividerPositions="0.8" orientation="VERTICAL" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<TabPane fx:id="tabPane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE">
|
||||
<tabs>
|
||||
<Tab fx:id="mainTab" closable="false" text="Main">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<children>
|
||||
<SplitPane dividerPositions="0.2984344422700587" layoutX="87.0" layoutY="82.0" prefHeight="160.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
|
||||
<children>
|
||||
<TreeTableView fx:id="numassLoaderDataTree" prefHeight="200.0" prefWidth="200.0" tableMenuButtonVisible="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columnResizePolicy>
|
||||
<TreeTableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TreeTableView>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane fx:id="numassLoaderViewContainer" minHeight="0.0" minWidth="0.0" prefHeight="737.0" prefWidth="689.0" />
|
||||
</items>
|
||||
</SplitPane>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="mspTab" closable="false" text="Mass-spectrum">
|
||||
<content>
|
||||
<AnchorPane fx:id="mspPlotPane" prefHeight="200.0" prefWidth="200.0" />
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="pressuresTab" closable="false" text="Pressures">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="temperaturesTab" closable="false" text="Temperatures">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
|
||||
</content>
|
||||
</Tab>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
<AnchorPane prefHeight="200.0" prefWidth="200.0">
|
||||
<children>
|
||||
<ScrollPane fx:id="taskPane" hbarPolicy="NEVER" minWidth="510.0" prefWidth="510.0" vmax="510.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
<TextArea fx:id="consoleArea" editable="false" minHeight="0.0" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="510.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
</center>
|
||||
<top>
|
||||
<ToolBar nodeOrientation="LEFT_TO_RIGHT" prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
@ -94,6 +47,7 @@ limitations under the License.
|
||||
<Insets left="10.0" />
|
||||
</padding></Label>
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<ToggleButton fx:id="processManagerButton" mnemonicParsing="false" text="ProcessManager" />
|
||||
<ToggleButton fx:id="consoleButton" contentDisplay="CENTER" mnemonicParsing="false" text="Console" />
|
||||
</items>
|
||||
</ToolBar>
|
||||
@ -101,6 +55,49 @@ limitations under the License.
|
||||
<bottom>
|
||||
<StatusBar fx:id="statusBar" BorderPane.alignment="CENTER" />
|
||||
</bottom>
|
||||
<center>
|
||||
<TabPane fx:id="tabPane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
|
||||
<tabs>
|
||||
<Tab fx:id="mainTab" closable="false" text="Main">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<children>
|
||||
<SplitPane dividerPositions="0.2984344422700587" layoutX="87.0" layoutY="82.0" prefHeight="160.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
|
||||
<children>
|
||||
<TreeTableView fx:id="numassLoaderDataTree" prefHeight="200.0" prefWidth="200.0" tableMenuButtonVisible="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<columnResizePolicy>
|
||||
<TreeTableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||
</columnResizePolicy>
|
||||
</TreeTableView>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane fx:id="numassLoaderViewContainer" minHeight="0.0" minWidth="0.0" prefHeight="737.0" prefWidth="689.0" />
|
||||
</items>
|
||||
</SplitPane>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="mspTab" closable="false" text="Mass-spectrum">
|
||||
<content>
|
||||
<AnchorPane fx:id="mspPlotPane" prefHeight="200.0" prefWidth="200.0" />
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="pressuresTab" closable="false" text="Pressures">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="temperaturesTab" closable="false" text="Temperatures">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
|
||||
</content>
|
||||
</Tab>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
</center>
|
||||
</BorderPane>
|
||||
</children>
|
||||
</AnchorPane>
|
||||
|
Loading…
Reference in New Issue
Block a user