Using tasks in numass viewer

This commit is contained in:
Alexander Nozik 2015-12-27 18:04:05 +03:00
parent c8ad2a51bc
commit cbfbe27958
23 changed files with 1454 additions and 1277 deletions

View File

@ -89,7 +89,7 @@ public class PrepareDataAction extends OneToOneAction<NMFile, DataSet> {
double cr = point.getCountRate(a, b, deadTime); double cr = point.getCountRate(a, b, deadTime);
double crErr = point.getCountRateErr(a, b, deadTime); double crErr = point.getCountRateErr(a, b, deadTime);
Instant timestamp = point.getAbsouteTime().toInstant(ZoneOffset.UTC); Instant timestamp = point.getStartTime();
dataList.add(new MapDataPoint(parnames, new Object[]{Uset, Uread, time, total, wind, corr, cr, crErr, timestamp})); dataList.add(new MapDataPoint(parnames, new Object[]{Uset, Uread, time, total, wind, corr, cr, crErr, timestamp}));
} }

View File

@ -31,6 +31,8 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static java.lang.String.format; import static java.lang.String.format;
import static java.lang.String.format;
import static java.lang.String.format;
/** /**
* *

View File

@ -17,13 +17,13 @@ package inr.numass.data;
import hep.dataforge.data.DataPoint; import hep.dataforge.data.DataPoint;
import hep.dataforge.data.MapDataPoint; import hep.dataforge.data.MapDataPoint;
import java.time.LocalDateTime; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import static java.util.Arrays.sort;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static java.util.Arrays.sort;
/** /**
* *
@ -32,7 +32,7 @@ import java.util.Map;
public class NMPoint { public class NMPoint {
static final String[] dataNames = {"chanel", "count"}; static final String[] dataNames = {"chanel", "count"};
private LocalDateTime absouteTime; private Instant startTime;
// private MonitorCorrector corrector = null; // private MonitorCorrector corrector = null;
// private double deadTime; // private double deadTime;
@ -54,7 +54,7 @@ public class NMPoint {
this.pointLength = point.getLength(); this.pointLength = point.getLength();
this.uset = point.getUset(); this.uset = point.getUset();
this.uread = point.getUread(); this.uread = point.getUread();
this.absouteTime = point.getAbsouteTime(); this.startTime = point.getStartTime();
this.eventsCount = point.getEventsCount(); this.eventsCount = point.getEventsCount();
// this.point = point; // this.point = point;
spectrum = calculateSpectrum(point); spectrum = calculateSpectrum(point);
@ -106,8 +106,12 @@ public class NMPoint {
/** /**
* @return the absouteTime * @return the absouteTime
*/ */
public LocalDateTime getAbsouteTime() { public Instant getStartTime() {
return absouteTime; if (startTime == null) {
return Instant.EPOCH;
} else {
return startTime;
}
} }
public int getCountInChanel(int chanel) { public int getCountInChanel(int chanel) {

View File

@ -24,6 +24,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Scanner; import java.util.Scanner;
@ -227,7 +228,7 @@ public class NumassDataReader {
absoluteTime = absoluteTime.plusDays(1); absoluteTime = absoluteTime.plusDays(1);
} }
point.setAbsouteTime(absoluteTime); point.setStartTime(absoluteTime.toInstant(ZoneOffset.UTC));
rx = readBlock(4); rx = readBlock(4);
int Uread = rx[2] + 256 * rx[3]; int Uread = rx[2] + 256 * rx[3];

View File

@ -15,7 +15,7 @@
*/ */
package inr.numass.data; package inr.numass.data;
import java.time.LocalDateTime; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -27,9 +27,9 @@ import java.util.List;
public class RawNMPoint implements Cloneable { public class RawNMPoint implements Cloneable {
public static int MAX_CHANEL = 4095; public static int MAX_CHANEL = 4095;
private LocalDateTime absouteTime; private Instant startTime;
private final List<NMEvent> events; private final List<NMEvent> events;
private double t; private double length;
private double uread; private double uread;
private double uset; private double uset;
@ -38,21 +38,21 @@ public class RawNMPoint implements Cloneable {
this.uset = U; this.uset = U;
this.uread = U; this.uread = U;
this.events = events; this.events = events;
this.t = t; this.length = t;
} }
public RawNMPoint(double Uset, double Uread, List<NMEvent> events, double t) { public RawNMPoint(double Uset, double Uread, List<NMEvent> events, double t) {
this.uset = Uset; this.uset = Uset;
this.uread = Uread; this.uread = Uread;
this.events = events; this.events = events;
this.t = t; this.length = t;
} }
public RawNMPoint(double uset, double uread, List<NMEvent> events, double t, LocalDateTime absouteTime) { public RawNMPoint(double uset, double uread, List<NMEvent> events, double t, Instant absouteTime) {
this.uset = uset; this.uset = uset;
this.uread = uread; this.uread = uread;
this.t = t; this.length = t;
this.absouteTime = absouteTime; this.startTime = absouteTime;
this.events = events; this.events = events;
} }
@ -60,7 +60,7 @@ public class RawNMPoint implements Cloneable {
events = new ArrayList<>(); events = new ArrayList<>();
uset = 0; uset = 0;
uread = 0; uread = 0;
t = Double.NaN; length = Double.NaN;
} }
@Override @Override
@ -72,8 +72,8 @@ public class RawNMPoint implements Cloneable {
return new RawNMPoint(getUset(), getUread(), newevents, getLength()); return new RawNMPoint(getUset(), getUread(), newevents, getLength());
} }
public LocalDateTime getAbsouteTime() { public Instant getStartTime() {
return absouteTime; return startTime;
} }
public double getCR() { public double getCR() {
@ -100,10 +100,10 @@ public class RawNMPoint implements Cloneable {
* @return the tset * @return the tset
*/ */
public double getLength() { public double getLength() {
if (Double.isNaN(t)) { if (Double.isNaN(length)) {
throw new Error(); throw new Error();
} }
return t; return length;
} }
/** /**
@ -132,7 +132,7 @@ public class RawNMPoint implements Cloneable {
for (NMEvent newEvent : point.getEvents()) { for (NMEvent newEvent : point.getEvents()) {
res.putEvent(new NMEvent(newEvent.getChanel(), newEvent.getTime() + this.getLength())); res.putEvent(new NMEvent(newEvent.getChanel(), newEvent.getTime() + this.getLength()));
} }
res.t += point.getLength(); res.length += point.getLength();
res.uread = (this.uread + point.uread) / 2; res.uread = (this.uread + point.uread) / 2;
return res; return res;
} }
@ -153,15 +153,15 @@ public class RawNMPoint implements Cloneable {
return new RawNMPoint(getUset(), getUread(), res, getLength()); return new RawNMPoint(getUset(), getUread(), res, getLength());
} }
void setAbsouteTime(LocalDateTime absouteTime) { void setStartTime(Instant absouteTime) {
this.absouteTime = absouteTime; this.startTime = absouteTime;
} }
/** /**
* @param tset the tset to set * @param tset the tset to set
*/ */
void setLength(double tset) { void setLength(double tset) {
this.t = tset; this.length = tset;
} }
/** /**
@ -178,4 +178,5 @@ public class RawNMPoint implements Cloneable {
void setUset(double Uset) { void setUset(double Uset) {
this.uset = Uset; this.uset = Uset;
} }
} }

View File

@ -15,13 +15,14 @@
*/ */
package inr.numass.data; package inr.numass.data;
import hep.dataforge.data.DataAdapter;
import hep.dataforge.meta.Meta; import hep.dataforge.meta.Meta;
import hep.dataforge.data.DataPoint; import hep.dataforge.data.DataPoint;
import hep.dataforge.data.MapDataPoint; import hep.dataforge.data.MapDataPoint;
import hep.dataforge.data.XYDataAdapter; import hep.dataforge.data.XYDataAdapter;
import hep.dataforge.exceptions.DataFormatException; import hep.dataforge.exceptions.DataFormatException;
import hep.dataforge.exceptions.NameNotFoundException; import hep.dataforge.exceptions.NameNotFoundException;
import hep.dataforge.names.Names; import hep.dataforge.meta.MetaBuilder;
import hep.dataforge.values.Value; import hep.dataforge.values.Value;
/** /**
@ -30,54 +31,48 @@ import hep.dataforge.values.Value;
*/ */
public class SpectrumDataAdapter extends XYDataAdapter { public class SpectrumDataAdapter extends XYDataAdapter {
private static final String ANNOTATION_TIMENAME = "timeName"; private static final String POINT_LENGTH_NAME = "time";
private String timeName = "time";
public SpectrumDataAdapter() { public SpectrumDataAdapter() {
} }
public SpectrumDataAdapter(Meta aliasAnnotation) { public SpectrumDataAdapter(Meta meta) {
super(aliasAnnotation); super(meta);
this.timeName = aliasAnnotation.getString(ANNOTATION_TIMENAME, "X");
} }
public SpectrumDataAdapter(String xName, String yName, String yErrName, String timeTime) { public SpectrumDataAdapter(String xName, String yName, String yErrName, String measurementTime) {
super(xName, yName, yErrName); super(new MetaBuilder(DataAdapter.DATA_ADAPTER_ANNOTATION_NAME)
this.timeName = timeTime; .setValue(X_NAME, xName)
.setValue(Y_NAME, yName)
.setValue(Y_ERR_NAME, yErrName)
.setValue(POINT_LENGTH_NAME, measurementTime)
.build()
);
} }
public SpectrumDataAdapter(String xName, String yName, String timeTime) { public SpectrumDataAdapter(String xName, String yName, String measurementTime) {
super(xName, yName); super(new MetaBuilder(DataAdapter.DATA_ADAPTER_ANNOTATION_NAME)
this.timeName = timeTime; .setValue(X_NAME, xName)
.setValue(Y_NAME, yName)
.setValue(POINT_LENGTH_NAME, measurementTime)
.build()
);
} }
public double getTime(DataPoint point) { public double getTime(DataPoint point) {
if (point.names().contains(timeName)) { return this.getFrom(point, POINT_LENGTH_NAME, 1d).doubleValue();
return point.getDouble(timeName);
} else {
return 1d;
}
} }
public DataPoint buildSpectrumDataPoint(double x, long count, double t) { public DataPoint buildSpectrumDataPoint(double x, long count, double t) {
return new MapDataPoint(new String[]{xName,yName,timeName}, x,count,t); return new MapDataPoint(new String[]{getValueName(X_NAME), getValueName(Y_NAME),
getValueName(POINT_LENGTH_NAME)},
x, count, t);
} }
public DataPoint buildSpectrumDataPoint(double x, long count, double countErr, double t) { public DataPoint buildSpectrumDataPoint(double x, long count, double countErr, double t) {
return new MapDataPoint(new String[]{xName,yName,yErrName,timeName}, x,count,countErr,t); return new MapDataPoint(new String[]{getValueName(X_NAME), getValueName(Y_NAME),
} getValueName(Y_ERR_NAME), getValueName(POINT_LENGTH_NAME)},
x, count, countErr, t);
@Override
public Meta buildAnnotation() {
Meta res = super.buildAnnotation();
res.getBuilder().putValue(ANNOTATION_TIMENAME, timeName);
return res;
}
@Override
public Names getNames() {
return Names.of(xName,yName);
} }
@Override @Override
@ -85,23 +80,22 @@ public class SpectrumDataAdapter extends XYDataAdapter {
return true; return true;
} }
@Override @Override
public Value getYerr(DataPoint point) throws NameNotFoundException { public Value getYerr(DataPoint point) throws NameNotFoundException {
if (point.names().contains(yErrName)) { if (providesYError(point)) {
return Value.of(super.getYerr(point).doubleValue()/getTime(point)); return Value.of(super.getYerr(point).doubleValue() / getTime(point));
} else{ } else {
double y = super.getY(point).doubleValue(); double y = super.getY(point).doubleValue();
if(y<=0) throw new DataFormatException(); if (y <= 0) {
else { throw new DataFormatException();
return Value.of(Math.sqrt(y)/getTime(point)); } else {
return Value.of(Math.sqrt(y) / getTime(point));
} }
} }
} }
public long getCount(DataPoint point){ public long getCount(DataPoint point) {
return point.getValue(yName).numberValue().longValue(); return super.getY(point).numberValue().longValue();
} }
@Override @Override

View File

@ -27,6 +27,7 @@ import java.util.Iterator;
import org.apache.commons.math3.random.JDKRandomGenerator; import org.apache.commons.math3.random.JDKRandomGenerator;
import org.apache.commons.math3.random.RandomDataGenerator; import org.apache.commons.math3.random.RandomDataGenerator;
import org.apache.commons.math3.random.RandomGenerator; import org.apache.commons.math3.random.RandomGenerator;
import static java.lang.Double.isNaN;
/** /**
* Генератор наборов данных для спектров. На входе требуется набор данных, * Генератор наборов данных для спектров. На входе требуется набор данных,
@ -64,7 +65,7 @@ public class SpectrumGenerator implements Generator {
@Override @Override
public ListDataSet generateData(Iterable<DataPoint> config) { public ListDataSet generateData(Iterable<DataPoint> config) {
ListDataSet res = adapter.buildEmptyDataSet(""); ListDataSet res = new ListDataSet(adapter.getFormat());
for (Iterator<DataPoint> it = config.iterator(); it.hasNext();) { for (Iterator<DataPoint> it = config.iterator(); it.hasNext();) {
res.add(this.generateDataPoint(it.next())); res.add(this.generateDataPoint(it.next()));
} }

View File

@ -39,7 +39,7 @@ public class DebunchReportImpl implements DebunchReport {
DebunchReportImpl(RawNMPoint pointBefore, DebunchData debunchData) { DebunchReportImpl(RawNMPoint pointBefore, DebunchData debunchData) {
this.pointBefore = pointBefore; this.pointBefore = pointBefore;
pointAfter = new RawNMPoint(pointBefore.getUset(),pointBefore.getUread(), pointAfter = new RawNMPoint(pointBefore.getUset(),pointBefore.getUread(),
debunchData.getDebunchedEvents(), debunchData.getDebunchedLength(),pointBefore.getAbsouteTime()); debunchData.getDebunchedEvents(), debunchData.getDebunchedLength(),pointBefore.getStartTime());
this.bunches = debunchData.getBunches(); this.bunches = debunchData.getBunches();
} }

View File

@ -21,6 +21,9 @@ import static java.lang.Math.max;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static java.lang.Math.max;
import static java.lang.Math.max;
import static java.lang.Math.max;
/** /**
* *

View File

@ -23,8 +23,8 @@ import inr.numass.data.SpectrumDataAdapter;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.Locale; import java.util.Locale;
import static java.util.Locale.setDefault;
import java.util.Scanner; import java.util.Scanner;
import static java.util.Locale.setDefault;
/** /**
* *
@ -56,7 +56,7 @@ public class OldDataReader {
public static ListDataSet readData(String path, double Elow) { public static ListDataSet readData(String path, double Elow) {
SpectrumDataAdapter factory = new SpectrumDataAdapter(); SpectrumDataAdapter factory = new SpectrumDataAdapter();
ListDataSet res = factory.buildEmptyDataSet(""); ListDataSet res = new ListDataSet(factory.getFormat());
File file = GlobalContext.instance().io().getFile(path); File file = GlobalContext.instance().io().getFile(path);
double x; double x;
int count; int count;
@ -108,7 +108,7 @@ public class OldDataReader {
public static ListDataSet readDataAsGun(String path, double Elow) { public static ListDataSet readDataAsGun(String path, double Elow) {
SpectrumDataAdapter factory = new SpectrumDataAdapter(); SpectrumDataAdapter factory = new SpectrumDataAdapter();
ListDataSet res = factory.buildEmptyDataSet(""); ListDataSet res = new ListDataSet(factory.getFormat());
File file = GlobalContext.instance().io().getFile(path); File file = GlobalContext.instance().io().getFile(path);
double x; double x;
long count; long count;
@ -141,7 +141,7 @@ public class OldDataReader {
public static ListDataSet readSpectrumData(String path){ public static ListDataSet readSpectrumData(String path){
SpectrumDataAdapter factory = new SpectrumDataAdapter(); SpectrumDataAdapter factory = new SpectrumDataAdapter();
ListDataSet res = factory.buildEmptyDataSet(""); ListDataSet res = new ListDataSet(factory.getFormat());
File file = GlobalContext.instance().io().getFile(path); File file = GlobalContext.instance().io().getFile(path);
double x; double x;
double count; double count;

View File

@ -23,6 +23,8 @@ import static java.lang.Math.sqrt;
import org.apache.commons.math3.analysis.UnivariateFunction; import org.apache.commons.math3.analysis.UnivariateFunction;
import static java.lang.Math.abs; import static java.lang.Math.abs;
import static java.lang.Math.abs; import static java.lang.Math.abs;
import static java.lang.Math.abs;
import static java.lang.Math.abs;
/** /**
* *

View File

@ -19,7 +19,7 @@ import hep.dataforge.description.ActionDescriptor;
import hep.dataforge.description.DescriptorUtils; import hep.dataforge.description.DescriptorUtils;
import hep.dataforge.exceptions.NameNotFoundException; import hep.dataforge.exceptions.NameNotFoundException;
import hep.dataforge.fx.LogOutputPane; import hep.dataforge.fx.LogOutputPane;
import hep.dataforge.fx.MetaEditorComponent; import hep.dataforge.fx.MetaEditor;
import hep.dataforge.fx.MetaTreeItem; import hep.dataforge.fx.MetaTreeItem;
import hep.dataforge.io.IOManager; import hep.dataforge.io.IOManager;
import hep.dataforge.io.MetaFileReader; import hep.dataforge.io.MetaFileReader;
@ -67,8 +67,8 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
Context parentContext; Context parentContext;
MetaFactory<Context> contextFactory; MetaFactory<Context> contextFactory;
List<MetaEditorComponent> actionEditors = new ArrayList<>(); List<MetaEditor> actionEditors = new ArrayList<>();
MetaEditorComponent dataEditor; MetaEditor dataEditor;
Context context; Context context;
Configuration dataConfig; Configuration dataConfig;
@ -187,7 +187,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
} }
}); });
MetaEditorComponent contextEditor = MetaEditorComponent.build(contextValues, null); MetaEditor contextEditor = MetaEditor.build(contextValues, null);
contextEditor.geTable().setShowRoot(false); contextEditor.geTable().setShowRoot(false);
contextPane.setContent(contextEditor); contextPane.setContent(contextEditor);
@ -203,7 +203,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
} else { } else {
dataConfig = new Configuration("data"); dataConfig = new Configuration("data");
} }
dataEditor = MetaEditorComponent.build(dataConfig, dataEditor = MetaEditor.build(dataConfig,
DescriptorUtils.buildDescriptor( DescriptorUtils.buildDescriptor(
DescriptorUtils.findAnnotatedElement("method::hep.dataforge.data.DataManager.read") DescriptorUtils.findAnnotatedElement("method::hep.dataforge.data.DataManager.read")
)); ));
@ -219,7 +219,7 @@ public class NumassWorkbenchController implements Initializable, StagePaneHolder
actionsConfig.setNode("action", actions); actionsConfig.setNode("action", actions);
for (Configuration action : actions) { for (Configuration action : actions) {
MetaEditorComponent actionEditor = new MetaEditorComponent(); MetaEditor actionEditor = new MetaEditor();
MetaTreeItem rootItem = new MetaTreeItem(action, getDescriptorForAction(action.getString("type"))); MetaTreeItem rootItem = new MetaTreeItem(action, getDescriptorForAction(action.getString("type")));
//Freezing actions names //Freezing actions names

View File

@ -34,10 +34,14 @@ import java.net.URL;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -172,13 +176,26 @@ public class NumassDataLoader extends AbstractLoader implements BinaryLoader<Env
} }
// LocalDateTime startTime = envelope.meta().get // LocalDateTime startTime = envelope.meta().get
RawNMPoint raw = new RawNMPoint(envelope.meta().getDouble("external_meta.HV1_value", 0), double u = envelope.meta().getDouble("external_meta.HV1_value", 0);
RawNMPoint raw = new RawNMPoint(u, u,
events, events,
envelope.meta().getValue("external_meta.acquisition_time").doubleValue()); envelope.meta().getValue("external_meta.acquisition_time").doubleValue(),
readTime(envelope.meta()));
return transformation.apply(raw); return transformation.apply(raw);
} }
private static Instant readTime(Meta meta) {
if (meta.hasValue("date") && meta.hasValue("start_time")) {
LocalDate date = LocalDate.parse(meta.getString("date"), DateTimeFormatter.ofPattern("uuuu.MM.dd"));
LocalTime time = LocalTime.parse(meta.getString("start_time"));
LocalDateTime dateTime = LocalDateTime.of(date, time);
return dateTime.toInstant(ZoneOffset.UTC);
} else {
return Instant.EPOCH;
}
}
/** /**
* Read numass point without transformation * Read numass point without transformation
* *
@ -244,7 +261,7 @@ public class NumassDataLoader extends AbstractLoader implements BinaryLoader<Env
this.getPoints().stream().forEachOrdered((point) -> { this.getPoints().stream().forEachOrdered((point) -> {
res.add(readPoint(point)); res.add(readPoint(point));
}); });
// res.sort((NMPoint o1, NMPoint o2) -> o1.getAbsouteTime().compareTo(o2.getAbsouteTime())); // res.sort((NMPoint o1, NMPoint o2) -> o1.getStartTime().compareTo(o2.getStartTime()));
return res; return res;
} }
@ -287,13 +304,17 @@ public class NumassDataLoader extends AbstractLoader implements BinaryLoader<Env
@Override @Override
public Instant startTime() { public Instant startTime() {
//TODO read meta
return null; return null;
// List<NMPoint> points = getNMPoints();
// if(!points.isEmpty()){
// return points.get(0).getStartTime();
// } else {
// return null;
// }
} }
@Override @Override
public String getDescription() { public String getDescription() {
//TODO read from annotation return meta().getString("description", "").replace("\\n", "\n");
return "";
} }
} }

View File

@ -85,12 +85,12 @@ public class NumassStorage extends FileStorage {
} }
} }
public static NumassStorage buildRemoteNumassRoot(String uri) throws StorageException { public static NumassStorage buildNumassRoot(String uri, boolean readOnly, boolean monitor) throws StorageException {
try { try {
Meta meta = new MetaBuilder("storage") Meta meta = new MetaBuilder("storage")
.setValue("type", "file.numass") .setValue("type", "file.numass")
.setValue("readOnly", true) .setValue("readOnly", readOnly)
.setValue("monitor", false); .setValue("monitor", monitor);
return new NumassStorage(VFSUtils.getRemoteFile(uri), meta); return new NumassStorage(VFSUtils.getRemoteFile(uri), meta);
} catch (FileSystemException ex) { } catch (FileSystemException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);

View File

@ -5,7 +5,7 @@ if (!hasProperty('mainClass')) {
} }
mainClassName = mainClass mainClassName = mainClass
version = "0.2.2" version = "0.2.3"
description = "The viewer for numass data" description = "The viewer for numass data"

View File

@ -5,11 +5,12 @@
*/ */
package inr.numass.viewer; package inr.numass.viewer;
import javafx.concurrent.Task;
/** /**
* *
* @author Alexander Nozik <altavir@gmail.com> * @author Alexander Nozik <altavir@gmail.com>
*/ */
public interface ProgressUpdateCallback { public interface FXTaskManager {
void setProgressText(String text); void postTask(Task task);
void setProgress(double progress);
} }

View File

@ -24,10 +24,13 @@ import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.Optional; import java.util.Optional;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
@ -48,6 +51,7 @@ import javafx.scene.control.TreeTableView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import javafx.stage.DirectoryChooser; import javafx.stage.DirectoryChooser;
import javafx.util.Duration;
import javafx.util.Pair; import javafx.util.Pair;
import org.controlsfx.control.StatusBar; import org.controlsfx.control.StatusBar;
@ -56,7 +60,7 @@ import org.controlsfx.control.StatusBar;
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
public class MainViewerController implements Initializable, ProgressUpdateCallback { public class MainViewerController implements Initializable, FXTaskManager {
public static MainViewerController build(NumassStorage root) { public static MainViewerController build(NumassStorage root) {
MainViewerController res = new MainViewerController(); MainViewerController res = new MainViewerController();
@ -111,14 +115,14 @@ public class MainViewerController implements Initializable, ProgressUpdateCallba
// TabPaneDetacher.create().makeTabsDetachable(tabPane); // TabPaneDetacher.create().makeTabsDetachable(tabPane);
ConsoleDude.hookStdStreams(consoleArea); ConsoleDude.hookStdStreams(consoleArea);
SplitPaneDividerSlider slider = new SplitPaneDividerSlider(consoleSplit, 0, SplitPaneDividerSlider.Direction.DOWN); SplitPaneDividerSlider slider = new SplitPaneDividerSlider(consoleSplit, 0,
SplitPaneDividerSlider.Direction.DOWN, Duration.seconds(1));
consoleButton.selectedProperty().addListener((ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) -> { slider.aimContentVisibleProperty().bindBidirectional(consoleButton.selectedProperty());
slider.setAimContentVisible(t1);
});
slider.setAimContentVisible(false);
consoleButton.setSelected(false);
loadRemoteButton.setDisable(true); loadRemoteButton.setDisable(true);
mspController.setCallback(this);
} }
@FXML @FXML
@ -131,39 +135,72 @@ public class MainViewerController implements Initializable, ProgressUpdateCallba
final File rootDir = chooser.showDialog(((Node) event.getTarget()).getScene().getWindow()); final File rootDir = chooser.showDialog(((Node) event.getTarget()).getScene().getWindow());
if (rootDir != null) { if (rootDir != null) {
storagePathLabel.setText("Storage: " + rootDir.getAbsolutePath()); Task dirLoadTask = new DirectoryLoadTask(rootDir.toURI().toString());
setProgress(-1); postTask(dirLoadTask);
setProgressText("Building numass storage tree..."); Viewer.runTask(dirLoadTask);
new Thread(() -> { }
try {
NumassStorage root = NumassStorage.buildLocalNumassRoot(rootDir, true); }
setRootStorage(root);
} catch (StorageException ex) { private class DirectoryLoadTask extends Task<Void> {
setProgress(0);
setProgressText("Failed to load local storage"); private final String uri;
Logger.getLogger(MainViewerController.class.getName()).log(Level.SEVERE, null, ex);
} public DirectoryLoadTask(String uri) {
}, "loader thread").start(); this.uri = uri;
}
@Override
protected Void call() throws Exception {
updateTitle("Load storage ("+uri+")");
updateProgress(-1, 1);
updateMessage("Building numass storage tree...");
try {
NumassStorage root = NumassStorage.buildNumassRoot(uri, true, false);
setRootStorage(root);
Platform.runLater(() -> storagePathLabel.setText("Storage: " + uri));
} catch (StorageException ex) {
updateProgress(0, 1);
updateMessage("Failed to load storage " + uri);
Logger.getLogger(MainViewerController.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
} }
} }
@Override @Override
public void setProgress(double progress) { @SuppressWarnings("unchecked")
Platform.runLater(() -> statusBar.setProgress(progress)); public void postTask(Task task) {
//statusBar.setProgress(progress); task.setOnRunning((e) -> {
} statusBar.setText(task.getTitle() + ": " + task.getMessage());
statusBar.setProgress(task.getProgress());
});
@Override task.messageProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
public void setProgressText(String text) { statusBar.setText(task.getTitle() + ": " +newValue);
Platform.runLater(() -> statusBar.setText(text)); });
//statusBar.setText(text);
task.progressProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
statusBar.setProgress(newValue.doubleValue());
});
task.setOnSucceeded((e) -> {
statusBar.setText(task.getTitle() + ": Complete");
statusBar.setProgress(0);
});
task.setOnFailed((e) -> {
statusBar.setText(task.getTitle() + ": Failed");
statusBar.setProgress(0);
});
} }
public void setRootStorage(NumassStorage root) { public void setRootStorage(NumassStorage root) {
fillNumassStorageData(root); Task fillTask = new StorageDataFillTask(root);
postTask(fillTask);
Viewer.runTask(fillTask);
if (mspController != null) { if (mspController != null) {
mspController.setCallback(this); mspController.setCallback(this);
mspController.fillMspData(root); mspController.fillMspData(root);
@ -176,28 +213,46 @@ public class MainViewerController implements Initializable, ProgressUpdateCallba
} }
private void fillNumassStorageData(NumassStorage rootStorage) { private class StorageDataFillTask extends Task<Void> {
if (rootStorage != null) {
setProgress(-1);
setProgressText("Loading numass storage tree...");
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 { try {
new NumassLoaderTreeBuilder(MainViewerController.this).fillTree(numassLoaderDataTree, rootStorage, (NumassData loader) -> { treeBuilderTask.get();
NumassLoaderViewComponent component = NumassLoaderViewComponent.build(loader); this.updateProgress(0, 1);
numassLoaderViewContainer.getChildren().clear(); this.updateMessage("Numass storage tree loaded.");
numassLoaderViewContainer.getChildren().add(component); this.succeeded();
AnchorPane.setTopAnchor(component, 0.0); } catch (InterruptedException | ExecutionException ex) {
AnchorPane.setRightAnchor(component, 0.0); this.failed();
AnchorPane.setLeftAnchor(component, 0.0);
AnchorPane.setBottomAnchor(component, 0.0);
numassLoaderViewContainer.requestLayout();
});
setProgress(0);
setProgressText("Loaded");
} catch (StorageException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
return null;
} }
} }
@FXML @FXML
@ -230,7 +285,7 @@ public class MainViewerController implements Initializable, ProgressUpdateCallba
dialog.getDialogPane().setContent(grid); dialog.getDialogPane().setContent(grid);
// Request focus on the username field by default. // Request focus on the username field by default.
Platform.runLater(() -> storageText.requestFocus()); storageText.requestFocus();
// Convert the result to a username-password-pair when the login button is clicked. // Convert the result to a username-password-pair when the login button is clicked.
dialog.setResultConverter(dialogButton -> { dialog.setResultConverter(dialogButton -> {
@ -243,21 +298,9 @@ public class MainViewerController implements Initializable, ProgressUpdateCallba
Optional<Pair<String, String>> result = dialog.showAndWait(); Optional<Pair<String, String>> result = dialog.showAndWait();
if (result.isPresent()) { if (result.isPresent()) {
storagePathLabel.setText("Storage: remote/" + result.get().getValue()); Task dirLoadTask = new DirectoryLoadTask(result.get().getKey() + "/data/" + result.get().getValue());
postTask(dirLoadTask);
setProgress(-1); Viewer.runTask(dirLoadTask);
setProgressText("Building numass storage tree...");
new Thread(() -> {
try {
NumassStorage root = NumassStorage.buildRemoteNumassRoot(result.get().getKey() + "/data/" + result.get().getValue());
setRootStorage(root);
} catch (StorageException ex) {
setProgress(0);
setProgressText("Failed to load remote storage");
Logger.getLogger(MainViewerController.class.getName()).log(Level.SEVERE, null, ex);
}
}, "loader thread").start();
} }
} }
} }

View File

@ -22,7 +22,6 @@ package inr.numass.viewer;
*/ */
import hep.dataforge.data.DataPoint; import hep.dataforge.data.DataPoint;
import hep.dataforge.data.MapDataPoint; import hep.dataforge.data.MapDataPoint;
import hep.dataforge.exceptions.StorageException;
import hep.dataforge.storage.api.PointLoader; import hep.dataforge.storage.api.PointLoader;
import hep.dataforge.storage.api.Storage; import hep.dataforge.storage.api.Storage;
import hep.dataforge.values.Value; import hep.dataforge.values.Value;
@ -35,6 +34,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
@ -58,7 +58,7 @@ import org.slf4j.LoggerFactory;
*/ */
public class MspViewController implements Initializable { public class MspViewController implements Initializable {
private ProgressUpdateCallback callback; private FXTaskManager callback;
@FXML @FXML
private AnchorPane mspPlotPane; private AnchorPane mspPlotPane;
@ -119,86 +119,105 @@ public class MspViewController implements Initializable {
public void fillMspData(Storage rootStorage) { public void fillMspData(Storage rootStorage) {
if (rootStorage != null) { if (rootStorage != null) {
try { MspDataFillTask fillTask = new MspDataFillTask(rootStorage);
List<DataPoint> mspData = getMspData(rootStorage); if(callback!= null){
Map<String, XYSeries> series = new HashMap<>(); callback.postTask(fillTask);
}
Viewer.runTask(fillTask);
}
}
for (DataPoint point : mspData) { private class MspDataFillTask extends Task<Void> {
for (String name : point.names()) {
if (!name.equals("timestamp")) { private final Storage storage;
if (!series.containsKey(name)) {
series.put(name, new XYSeries(name)); public MspDataFillTask(Storage storage) {
} this.storage = storage;
long time = point.getValue("timestamp").timeValue().toEpochMilli(); }
double value = point.getDouble(name);
if (value > 0) { @Override
series.get(name).add(time, value); protected Void call() throws Exception {
} updateTitle("Fill msp data ("+storage.getName()+")");
MspDataLoadTask loadTask = new MspDataLoadTask(storage);
if(callback!= null){
callback.postTask(loadTask);
}
Viewer.runTask(loadTask);
List<DataPoint> mspData = loadTask.get();
Map<String, XYSeries> series = new HashMap<>();
for (DataPoint point : mspData) {
for (String name : point.names()) {
if (!name.equals("timestamp")) {
if (!series.containsKey(name)) {
series.put(name, new XYSeries(name));
}
long time = point.getValue("timestamp").timeValue().toEpochMilli();
double value = point.getDouble(name);
if (value > 0) {
series.get(name).add(time, value);
} }
} }
} }
XYSeriesCollection mspSeriesCollection = new XYSeriesCollection();
List<String> names = new ArrayList<>(series.keySet());
names.sort((String o1, String o2) -> {
try {
return Integer.valueOf(o1).compareTo(Integer.valueOf(o2));
} catch (Exception ex) {
return 0;
}
});
for (String name : names) {
mspSeriesCollection.addSeries(series.get(name));
}
updateMspPane(mspSeriesCollection);
} catch (StorageException ex) {
throw new RuntimeException(ex);
} }
} XYSeriesCollection mspSeriesCollection = new XYSeriesCollection();
} List<String> names = new ArrayList<>(series.keySet());
names.sort((String o1, String o2) -> {
private List<DataPoint> getMspData(Storage storage) throws StorageException { try {
List<DataPoint> mspData = new ArrayList<>(); return Integer.valueOf(o1).compareTo(Integer.valueOf(o2));
DataPoint last = null;
for (String loaderName : storage.loaders().keySet()) {
if (loaderName.startsWith("msp")) {
try (PointLoader mspLoader = (PointLoader) storage.getLoader(loaderName)) {
mspLoader.open();
updateProgress("Loading mass spectrometer data from " + mspLoader.getName());
updateProgress(-1);
for (DataPoint dp : mspLoader.asDataSet()) {
mspData.add(dp);
last = dp;
}
if (last != null) {
mspData.add(terminatorPoint(last));
}
} catch (Exception ex) { } catch (Exception ex) {
LoggerFactory.getLogger(getClass()).error("Can't read msp loader data", ex); return 0;
}
});
for (String name : names) {
mspSeriesCollection.addSeries(series.get(name));
}
updateMspPane(mspSeriesCollection);
return null;
}
}
private class MspDataLoadTask extends Task<List<DataPoint>> {
private final Storage storage;
public MspDataLoadTask(Storage storage) {
this.storage = storage;
}
@Override
protected List<DataPoint> call() throws Exception {
updateTitle("Load msp data ("+storage.getName()+")");
List<DataPoint> mspData = new ArrayList<>();
DataPoint last = null;
for (String loaderName : storage.loaders().keySet()) {
if (loaderName.startsWith("msp")) {
try (PointLoader mspLoader = (PointLoader) storage.getLoader(loaderName)) {
mspLoader.open();
updateMessage("Loading mass spectrometer data from " + mspLoader.getName());
updateProgress(-1, 1);
for (DataPoint dp : mspLoader.asDataSet()) {
mspData.add(dp);
last = dp;
}
if (last != null) {
mspData.add(terminatorPoint(last));
}
} catch (Exception ex) {
LoggerFactory.getLogger(getClass()).error("Can't read msp loader data", ex);
}
} }
} }
}
// for (String shelfName : storage.shelves().keySet()) {
// mspData.addAll(getMspData(storage.getShelf(shelfName)));
// }
updateProgress("Loading msp data finished"); updateMessage("Loading msp data finished");
updateProgress(0); updateProgress(0, 1);
return mspData; return mspData;
}
} }
private void updateProgress(String progress) { public void setCallback(FXTaskManager callback) {
if (callback != null) {
callback.setProgressText(progress);
}
}
private void updateProgress(double progress) {
if (callback != null) {
callback.setProgress(progress);
}
}
public void setCallback(ProgressUpdateCallback callback) {
this.callback = callback; this.callback = callback;
} }

View File

@ -26,6 +26,7 @@ import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.concurrent.Task;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn; import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView; import javafx.scene.control.TreeTableView;
@ -35,19 +36,23 @@ import javafx.scene.input.MouseEvent;
* *
* @author darksnake * @author darksnake
*/ */
public class NumassLoaderTreeBuilder implements ProgressUpdateCallback { public class NumassLoaderTreeBuilder extends Task<Void> {
ProgressUpdateCallback callback; private final TreeTableView<TreeItemValue> numassLoaderDataTree;
private final NumassStorage rootStorage;
private final Consumer<NumassData> numassViewBuilder;
public NumassLoaderTreeBuilder(ProgressUpdateCallback callback) { public NumassLoaderTreeBuilder(TreeTableView<TreeItemValue> numassLoaderDataTree, NumassStorage rootStorage, Consumer<NumassData> numassViewBuilder) {
this.callback = callback; this.numassLoaderDataTree = numassLoaderDataTree;
this.rootStorage = rootStorage;
this.numassViewBuilder = numassViewBuilder;
} }
public NumassLoaderTreeBuilder() {
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void fillTree(TreeTableView<TreeItemValue> numassLoaderDataTree, NumassStorage rootStorage, Consumer<NumassData> numassViewBuilder) throws StorageException { @Override
protected Void call() throws Exception {
updateTitle("Load numass data ("+rootStorage.getName()+")");
TreeItem<TreeItemValue> root = buildNode(rootStorage, numassViewBuilder); TreeItem<TreeItemValue> root = buildNode(rootStorage, numassViewBuilder);
root.setExpanded(true); root.setExpanded(true);
@ -81,6 +86,7 @@ public class NumassLoaderTreeBuilder implements ProgressUpdateCallback {
numassLoaderTimeColumn.setVisible(false); numassLoaderTimeColumn.setVisible(false);
nummassLoaderDescriptionColumn.setVisible(false); nummassLoaderDescriptionColumn.setVisible(false);
}); });
return null;
} }
private TreeItem<TreeItemValue> buildNode(NumassStorage storage, Consumer<NumassData> numassViewBuilder) throws StorageException { private TreeItem<TreeItemValue> buildNode(NumassStorage storage, Consumer<NumassData> numassViewBuilder) throws StorageException {
@ -99,12 +105,12 @@ public class NumassLoaderTreeBuilder implements ProgressUpdateCallback {
} }
} }
setProgressText("Building storage " + storage.getName()); updateMessage("Building storage " + storage.getName());
double counter = 0; double counter = 0;
for (Loader loader : storage.loaders().values()) { for (Loader loader : storage.loaders().values()) {
setProgressText("Building numass data loader " + loader.getName()); updateMessage("Building numass data loader " + loader.getName());
setProgress(counter / storage.loaders().size()); updateProgress(counter, storage.loaders().size());
if (loader instanceof NumassData) { if (loader instanceof NumassData) {
NumassData numassLoader = (NumassData) loader; NumassData numassLoader = (NumassData) loader;
@ -126,8 +132,8 @@ public class NumassLoaderTreeBuilder implements ProgressUpdateCallback {
//adding legacy data files //adding legacy data files
counter = 0; counter = 0;
for (NumassData legacyDat : storage.legacyFiles()) { for (NumassData legacyDat : storage.legacyFiles()) {
setProgressText("Loading numass DAT file " + legacyDat.getName()); updateMessage("Loading numass DAT file " + legacyDat.getName());
setProgress(counter / storage.loaders().size()); updateProgress(counter, storage.loaders().size());
TreeItem<TreeItemValue> numassLoaderTreeItem = new TreeItem<>(buildValue(legacyDat)); TreeItem<TreeItemValue> numassLoaderTreeItem = new TreeItem<>(buildValue(legacyDat));
list.add(numassLoaderTreeItem); list.add(numassLoaderTreeItem);
counter++; counter++;
@ -197,7 +203,7 @@ public class NumassLoaderTreeBuilder implements ProgressUpdateCallback {
@Override @Override
public String getTime() { public String getTime() {
Instant startTime = loader.startTime(); Instant startTime = loader.startTime();
if (startTime == null) { if (startTime == null || startTime.equals(Instant.EPOCH)) {
return ""; return "";
} else { } else {
return loader.startTime().toString(); return loader.startTime().toString();
@ -211,20 +217,6 @@ public class NumassLoaderTreeBuilder implements ProgressUpdateCallback {
}; };
} }
@Override
public void setProgress(double progress) {
if (callback != null) {
callback.setProgress(progress);
}
}
@Override
public void setProgressText(String text) {
if (callback != null) {
callback.setProgressText(text);
}
}
public interface TreeItemValue { public interface TreeItemValue {
public String getName(); public String getName();

View File

@ -22,6 +22,7 @@ package inr.numass.viewer;
*/ */
import hep.dataforge.data.DataPoint; import hep.dataforge.data.DataPoint;
import hep.dataforge.data.DataSet; import hep.dataforge.data.DataSet;
import hep.dataforge.data.ListDataSet;
import hep.dataforge.data.MapDataPoint; import hep.dataforge.data.MapDataPoint;
import hep.dataforge.io.ColumnedDataWriter; import hep.dataforge.io.ColumnedDataWriter;
import hep.dataforge.meta.Meta; import hep.dataforge.meta.Meta;
@ -41,11 +42,16 @@ import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.concurrent.Task;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
@ -63,6 +69,8 @@ import javafx.stage.FileChooser;
import javafx.util.converter.NumberStringConverter; import javafx.util.converter.NumberStringConverter;
import org.controlsfx.control.CheckListView; import org.controlsfx.control.CheckListView;
import org.controlsfx.control.RangeSlider; import org.controlsfx.control.RangeSlider;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -73,21 +81,7 @@ import org.slf4j.LoggerFactory;
*/ */
public class NumassLoaderViewComponent extends AnchorPane implements Initializable { public class NumassLoaderViewComponent extends AnchorPane implements Initializable {
public static NumassLoaderViewComponent build(NumassData numassLoader) { private FXTaskManager callback;
NumassLoaderViewComponent component = new NumassLoaderViewComponent();
FXMLLoader loader = new FXMLLoader(component.getClass().getResource("/fxml/NumassLoaderView.fxml"));
loader.setRoot(component);
loader.setController(component);
try {
loader.load();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
component.setData(numassLoader);
return component;
}
Logger logger = LoggerFactory.getLogger(NumassLoaderViewComponent.class); Logger logger = LoggerFactory.getLogger(NumassLoaderViewComponent.class);
private NumassData data; private NumassData data;
@ -120,15 +114,29 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
private CheckBox detectorNormalizeSwitch; private CheckBox detectorNormalizeSwitch;
@FXML @FXML
private Button detectorDataExportButton; private Button detectorDataExportButton;
@FXML @FXML
private TextField lowChannelField; private TextField lowChannelField;
@FXML @FXML
private TextField upChannelField; private TextField upChannelField;
@FXML @FXML
private RangeSlider channelSlider; private RangeSlider channelSlider;
@FXML
private Button spectrumExportButton;
@FXML
private TextField dTimeField;
public NumassLoaderViewComponent() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/NumassLoaderView.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
/** /**
* Initializes the controller class. * Initializes the controller class.
@ -138,9 +146,8 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
*/ */
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
// TODO detectorBinningSelector.setItems(FXCollections.observableArrayList(1, 2, 5, 10, 20, 50));
detectorBinningSelector.setItems(FXCollections.observableArrayList(1, 2, 5, 10, 20)); detectorBinningSelector.getSelectionModel().select(4);
detectorBinningSelector.getSelectionModel().selectLast();
detectorNormalizeSwitch.setSelected(true); detectorNormalizeSwitch.setSelected(true);
detectorPointListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); detectorPointListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@ -148,36 +155,83 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
lowChannelField.textProperty().bindBidirectional(channelSlider.lowValueProperty(), new NumberStringConverter()); lowChannelField.textProperty().bindBidirectional(channelSlider.lowValueProperty(), new NumberStringConverter());
upChannelField.textProperty().bindBidirectional(channelSlider.highValueProperty(), new NumberStringConverter()); upChannelField.textProperty().bindBidirectional(channelSlider.highValueProperty(), new NumberStringConverter());
channelSlider.setLowValue(300); channelSlider.setHighValue(1900d);
channelSlider.setHighValue(1900); channelSlider.setLowValue(300d);
ChangeListener<? super Number> rangeChangeListener = (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { ChangeListener<? super Number> rangeChangeListener = (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
updateSpectrumPane(); updateSpectrumPane(points);
}; };
dTimeField.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
updateSpectrumPane(points);
});
channelSlider.lowValueProperty().addListener(rangeChangeListener); channelSlider.lowValueProperty().addListener(rangeChangeListener);
channelSlider.highValueProperty().addListener(rangeChangeListener); channelSlider.highValueProperty().addListener(rangeChangeListener);
ValidationSupport validationSupport = new ValidationSupport();
Predicate<String> isNumber = (String t) -> {
try {
Double.parseDouble(t);
return true;
} catch (NumberFormatException | NullPointerException ex) {
return false;
}
};
validationSupport.registerValidator(dTimeField, Validator.createPredicateValidator(isNumber, "Must be number"));
} }
public NumassData getData() { public NumassData getData() {
return data; return data;
} }
public void setData(NumassData data) { public void setCallback(FXTaskManager callback) {
this.callback = callback;
}
public void loadData(NumassData data) {
this.data = data; this.data = data;
if (data != null) { if (data != null) {
points = data.getNMPoints(); LoadPointsTask task = new LoadPointsTask(data);
//setup detector data if (callback != null) {
setupDetectorPane(points); callback.postTask(task);
//setup spectrum plot }
updateSpectrumPane(); Viewer.runTask(task);
try {
setupInfo(data); this.points = task.get();
} catch (InterruptedException |ExecutionException ex) {
detectorTab.getTabPane().getSelectionModel().select(detectorTab); logger.error("Can't load spectrum data points", ex);
}
} else { } else {
logger.error("The data model is null"); logger.error("The data model is null");
} }
detectorTab.getTabPane().getSelectionModel().select(detectorTab);
}
private class LoadPointsTask extends Task<List<NMPoint>> {
private final NumassData loader;
public LoadPointsTask(NumassData loader) {
this.loader = loader;
}
@Override
protected List<NMPoint> call() throws Exception {
updateTitle("Load numass data (" + loader.getName() + ")");
List<NMPoint> points = loader.getNMPoints();
Platform.runLater(() -> {
//setup detector data
setupDetectorPane(points);
//setup spectrum plot
updateSpectrumPane(points);
setupInfo(data);
});
return points;
}
} }
/** /**
@ -192,11 +246,11 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
detectorBinningSelector.getSelectionModel().selectedItemProperty() detectorBinningSelector.getSelectionModel().selectedItemProperty()
.addListener((ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) -> { .addListener((ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) -> {
boolean norm = detectorNormalizeSwitch.isSelected(); boolean norm = detectorNormalizeSwitch.isSelected();
updateDetectorPane(fillDetectorData(points, newValue, norm)); updateDetectorPane(fillDetectorData(NumassLoaderViewComponent.this.points, newValue, norm));
}); });
detectorNormalizeSwitch.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> { detectorNormalizeSwitch.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
int bin = detectorBinningSelector.getValue(); int bin = detectorBinningSelector.getValue();
updateDetectorPane(fillDetectorData(points, bin, newValue)); updateDetectorPane(fillDetectorData(NumassLoaderViewComponent.this.points, bin, newValue));
}); });
detectorDataExportButton.setDisable(false); detectorDataExportButton.setDisable(false);
} }
@ -204,10 +258,10 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
private void setupInfo(NumassData loader) { private void setupInfo(NumassData loader) {
Meta info = loader.getInfo(); Meta info = loader.getInfo();
infoTextBox.setText(new JSONMetaWriter().writeString(info, null). infoTextBox.setText(new JSONMetaWriter().writeString(info, null).
replace("\\r", "\r").replace("\\n", "\n")); replace("\\r", "\r\t").replace("\\n", "\n\t"));
} }
private void updateSpectrumPane() { private void updateSpectrumPane(List<NMPoint> points) {
if (spectrumPlotFrame == null) { if (spectrumPlotFrame == null) {
Meta plotMeta = new MetaBuilder("plot") Meta plotMeta = new MetaBuilder("plot")
.setValue("xAxis.axisTitle", "U") .setValue("xAxis.axisTitle", "U")
@ -230,73 +284,66 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
spectrumData.clear(); spectrumData.clear();
} else { } else {
spectrumData.fillData(points.stream() spectrumData.fillData(points.stream()
.<DataPoint>map((NMPoint point) -> getSpectrumPoint(point, lowChannel, highChannel)) .<DataPoint>map((NMPoint point) -> getSpectrumPoint(point, lowChannel, highChannel, getDTime()))
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
} }
private DataPoint getSpectrumPoint(NMPoint point, int lowChannel, int highChannel) { private double getDTime() {
double u = point.getUread(); try {
double count = point.getCountInWindow(lowChannel, highChannel); return Double.parseDouble(dTimeField.getText()) * 1e-6;
double time = point.getLength(); } catch (NumberFormatException ex) {
double err = Math.sqrt(count); return 0;
return new MapDataPoint(new String[]{"x", "y", "yErr"}, u, count / time, err / time); }
}
private DataPoint getSpectrumPoint(NMPoint point, int lowChannel, int upChannel, double dTime) {
double u = point.getUread();
return new MapDataPoint(new String[]{"x", "y", "yErr"}, u,
point.getCountRate(lowChannel, upChannel, dTime),
point.getCountRateErr(lowChannel, upChannel, dTime));
} }
// private void setupSpectrumPane(List<NMPoint> points, int lowChannel, int upChannel) {
// updateSpectrumData(fillSpectrumData(points, (point) -> point.getCountInWindow(lowChannel, upChannel)));
// }
//
// private void updateSpectrumData(XYIntervalSeriesCollection data) {
// spectrumPlotPane.getChildren().clear();
// NumberAxis xAxis = new NumberAxis("HV");
// NumberAxis yAxis = new NumberAxis("count rate");
//
// xAxis.setAutoRangeIncludesZero(false);
// yAxis.setAutoRangeIncludesZero(false);
//
// XYPlot plot = new XYPlot(data, xAxis, yAxis, new XYErrorRenderer());
// JFreeChart spectrumPlot = new JFreeChart("spectrum", plot);
// displayPlot(spectrumPlotPane, spectrumPlot);
// }
/** /**
* update detector pane with new data * update detector pane with new data
*/ */
private void updateDetectorPane(List<XYPlottable> detectorData) { private void updateDetectorPane(List<XYPlottable> detectorData) {
if (detectorData == null) { Platform.runLater(() -> {
throw new IllegalArgumentException("Detector data not defined"); if (detectorData == null) {
} throw new IllegalArgumentException("Detector data not defined");
}
detectorPointListView.getItems().clear();//removing all checkboxes detectorPointListView.getItems().clear();//removing all checkboxes
detectorPlotPane.getChildren().clear();//removing plot detectorPlotPane.getChildren().clear();//removing plot
Meta frameMeta = new MetaBuilder("frame") Meta frameMeta = new MetaBuilder("frame")
.setValue("frameTitle", "Detector response plot") .setValue("frameTitle", "Detector response plot")
.setNode(new MetaBuilder("xAxis") .setNode(new MetaBuilder("xAxis")
.setValue("axisTitle", "ADC") .setValue("axisTitle", "ADC")
.setValue("axisUnits", "channels") .setValue("axisUnits", "channels")
.build()) .build())
.setNode(new MetaBuilder("yAxis") .setNode(new MetaBuilder("yAxis")
.setValue("axisTitle", "count rate") .setValue("axisTitle", "count rate")
.setValue("axisUnits", "Hz") .setValue("axisUnits", "Hz")
.build()) .build())
.build(); .build();
detectorPlotFrame = new JFreeChartFrame("detectorSignal", frameMeta, detectorPlotPane); detectorPlotFrame = new JFreeChartFrame("detectorSignal", frameMeta, detectorPlotPane);
for (XYPlottable pl : detectorData) { for (XYPlottable pl : detectorData) {
detectorPlotFrame.add(pl); detectorPlotFrame.add(pl);
detectorPointListView.getItems().add(pl.getName()); detectorPointListView.getItems().add(pl.getName());
} }
for (String plotName : detectorPointListView.getItems()) { for (String plotName : detectorPointListView.getItems()) {
BooleanProperty checked = detectorPointListView.getItemBooleanProperty(plotName); BooleanProperty checked = detectorPointListView.getItemBooleanProperty(plotName);
checked.set(true); checked.set(true);
checked.addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> { checked.addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
detectorPlotFrame.get(plotName).getConfig().setValue("visible", newValue); detectorPlotFrame.get(plotName).getConfig().setValue("visible", newValue);
}); });
} }
});
} }
private List<XYPlottable> fillDetectorData(List<NMPoint> points, int binning, boolean normalize) { private List<XYPlottable> fillDetectorData(List<NMPoint> points, int binning, boolean normalize) {
@ -317,27 +364,6 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
return plottables; return plottables;
} }
// /**
// * Fill spectrum with custom window calculator
// *
// * @param points
// * @param lowerBoundCalculator
// * @param upperBoundCalculator
// * @return
// */
// private XYIntervalSeriesCollection fillSpectrumData(List<NMPoint> points, Function<NMPoint, Number> calculator) {
// XYIntervalSeriesCollection collection = new XYIntervalSeriesCollection();
// XYIntervalSeries ser = new XYIntervalSeries("spectrum");
// for (NMPoint point : points) {
// double u = point.getUread();
// double count = calculator.apply(point).doubleValue();
// double time = point.getLength();
// double err = Math.sqrt(count);
// ser.add(u, u, u, count / time, (count - err) / time, (count + err) / time);
// }
// collection.addSeries(ser);
// return collection;
// }
@FXML @FXML
private void checkAllAction(ActionEvent event) { private void checkAllAction(ActionEvent event) {
detectorPointListView.getCheckModel().checkAll(); detectorPointListView.getCheckModel().checkAll();
@ -362,6 +388,49 @@ public class NumassLoaderViewComponent extends AnchorPane implements Initializab
} }
} }
@FXML
private void onSpectrumExportClick(ActionEvent event) {
if (points != null && !points.isEmpty()) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Choose text export destination");
fileChooser.setInitialFileName(data.getName() + "_spectrum.out");
File destination = fileChooser.showSaveDialog(spectrumPlotPane.getScene().getWindow());
if (destination != null) {
String[] names = new String[]{"Uset", "Uread", "Length", "Total", "Window", "CR", "CRerr", "Timestamp"};
int loChannel = (int) channelSlider.getLowValue();
int upChannel = (int) channelSlider.getHighValue();
double dTime = getDTime();
ListDataSet spectrumDataSet = new ListDataSet(names);
for (NMPoint point : points) {
spectrumDataSet.add(new MapDataPoint(names, new Object[]{
point.getUset(),
point.getUread(),
point.getLength(),
point.getEventsCount(),
point.getCountInWindow(loChannel, upChannel),
point.getCountRate(loChannel, upChannel, dTime),
point.getCountRateErr(loChannel, upChannel, dTime),
point.getStartTime()
}
));
}
try {
String comment = String.format("Numass data viewer spectrum data export for %s%n"
+ "Window: (%d, %d)%n"
+ "Dead time per event: %g%n",
data.getName(), loChannel, upChannel, dTime);
ColumnedDataWriter
.writeDataSet(destination, spectrumDataSet, comment, false);
} catch (IOException ex) {
LoggerFactory.getLogger(getClass()).error("Destination file not found", ex);
}
}
}
}
private void onExportButtonClick(ActionEvent event) { private void onExportButtonClick(ActionEvent event) {
FileChooser fileChooser = new FileChooser(); FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Choose text export destination"); fileChooser.setTitle("Choose text export destination");

View File

@ -36,7 +36,8 @@ public class TestDirectoryViewer extends Application {
NumassDataLoader reader = NumassDataLoader.fromLocalDir(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1\\")); 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")); // NumassLoader reader = NumassLoader.fromZip(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1.zip"));
NumassLoaderViewComponent comp = NumassLoaderViewComponent.build(reader); NumassLoaderViewComponent comp = new NumassLoaderViewComponent();
comp.loadData(reader);
// FXMLLoader fxml = new FXMLLoader(getClass().getResource("/fxml/DirectoryViewer.fxml")); // FXMLLoader fxml = new FXMLLoader(getClass().getResource("/fxml/DirectoryViewer.fxml"));
// //
// Parent parent = fxml.load(); // Parent parent = fxml.load();

View File

@ -19,6 +19,7 @@ import hep.dataforge.exceptions.StorageException;
import hep.dataforge.storage.commons.StoragePlugin; import hep.dataforge.storage.commons.StoragePlugin;
import java.io.IOException; import java.io.IOException;
import javafx.application.Application; import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
@ -34,7 +35,6 @@ public class Viewer extends Application {
public void start(Stage primaryStage) throws StorageException, IOException { public void start(Stage primaryStage) throws StorageException, IOException {
new StoragePlugin().startGlobal(); new StoragePlugin().startGlobal();
FXMLLoader fxml = new FXMLLoader(getClass().getResource("/fxml/MainView.fxml")); FXMLLoader fxml = new FXMLLoader(getClass().getResource("/fxml/MainView.fxml"));
Parent parent = fxml.load(); Parent parent = fxml.load();
@ -52,7 +52,11 @@ public class Viewer extends Application {
System.exit(0); System.exit(0);
} }
public static void runTask(Task task) {
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
/** /**
* @param args the command line arguments * @param args the command line arguments

View File

@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<?import org.controlsfx.control.textfield.*?>
<?import org.controlsfx.control.*?> <?import org.controlsfx.control.*?>
<?import javafx.geometry.*?> <?import javafx.geometry.*?>
<?import java.lang.*?> <?import java.lang.*?>
@ -24,9 +25,9 @@ limitations under the License.
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<fx:root id="AnchorPane" prefHeight="400.0" prefWidth="600.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1"> <fx:root id="AnchorPane" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children> <children>
<TabPane layoutX="200.0" layoutY="100.0" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <TabPane layoutX="200.0" layoutY="100.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<tabs> <tabs>
<Tab text="Info"> <Tab text="Info">
<content> <content>
@ -41,15 +42,10 @@ limitations under the License.
<content> <content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children> <children>
<BorderPane layoutX="200.0" layoutY="86.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <SplitPane dividerPositions="0.5" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<center> <items>
<AnchorPane fx:id="detectorPlotPane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" /> <AnchorPane fx:id="detectorPlotPane" minHeight="300.0" minWidth="300.0" prefHeight="200.0" prefWidth="200.0" />
</center> <VBox fx:id="detectorOptionsPane" maxWidth="250.0" prefWidth="200.0" spacing="2.0" style="-fx-border-color: blue;">
<right>
<VBox fx:id="detectorOptionsPane" minWidth="-Infinity" prefWidth="200.0" spacing="2.0" style="-fx-border-color: blue;" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<children> <children>
<Label text="Channels per bin"> <Label text="Channels per bin">
<VBox.margin> <VBox.margin>
@ -78,8 +74,8 @@ limitations under the License.
<padding> <padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" /> <Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</padding></VBox> </padding></VBox>
</right> </items>
</BorderPane> </SplitPane>
</children> </children>
</AnchorPane> </AnchorPane>
</content> </content>
@ -91,7 +87,7 @@ limitations under the License.
</Tab> </Tab>
<Tab fx:id="spectrumTab" text="Spectrum"> <Tab fx:id="spectrumTab" text="Spectrum">
<content> <content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <AnchorPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0">
<children> <children>
<BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<center> <center>
@ -100,9 +96,32 @@ limitations under the License.
<top> <top>
<ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER"> <ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<items> <items>
<TextField fx:id="lowChannelField" prefWidth="60.0" /> <VBox>
<RangeSlider fx:id="channelSlider" accessibleRole="SLIDER" highValue="1900.0" lowValue="300.0" majorTickUnit="500.0" max="4000.0" minorTickCount="5" prefHeight="38.0" prefWidth="336.0" showTickLabels="true" showTickMarks="true" /> <children>
<TextField fx:id="upChannelField" prefWidth="60.0" /> <Label text="Lo channel" />
<TextField fx:id="lowChannelField" prefWidth="60.0" />
</children>
</VBox>
<RangeSlider fx:id="channelSlider" accessibleRole="SLIDER" highValue="1900.0" lowValue="300.0" majorTickUnit="500.0" max="4000.0" minorTickCount="5" prefHeight="38.0" prefWidth="276.0" showTickLabels="true" showTickMarks="true">
<padding>
<Insets left="10.0" right="10.0" />
</padding></RangeSlider>
<VBox>
<children>
<Label text="Up channel" />
<TextField fx:id="upChannelField" prefWidth="60.0" />
</children>
</VBox>
<Separator orientation="VERTICAL" />
<VBox>
<children>
<Label text="Dead time (us)" />
<TextField fx:id="dTimeField" prefHeight="25.0" prefWidth="0.0" text="7.2" />
</children>
</VBox>
<Separator orientation="VERTICAL" />
<Pane minWidth="0.0" HBox.hgrow="ALWAYS" />
<Button fx:id="spectrumExportButton" mnemonicParsing="false" onAction="#onSpectrumExportClick" text="Export" />
</items> </items>
</ToolBar> </ToolBar>
</top> </top>