+ * This may cause trouble in offline analysis if you want to make changes to the phone layout
+ * (for example changing a hydrophone separation).
+ */
+ public void createArrayData() {
+// DBControlUnit dbControl = DBControlUnit.findDatabaseControl();
+// DBProcess dbProcess = null;
+// if (dbControl != null) {
+// dbProcess = dbControl.getDbProcess();
+// }
+
+ long timeNow = PamCalendar.getTimeInMillis();
+
+ createDefaultStreamerUnits(timeNow);
+ createDefaultHydrophoneUnits(timeNow);
- }
-
- /**
- * @return the streamerDataBlock
- */
- protected StreamerDataBlock getStreamerDataBlock() {
- return streamerDataBlock;
- }
-
- /**
- * Save all the array data to the database. This get's called when
- * the array manager dialog has been called or when PAMGuard starts to ensure
- * that there is a database record of how the hydrophones were arranged.
- * This may cause trouble in offline analysis if you want to make changes to the phone layout
- * (for example changing a hydrophone separation).
- */
- public void createArrayData() {
- // DBControlUnit dbControl = DBControlUnit.findDatabaseControl();
- // DBProcess dbProcess = null;
- // if (dbControl != null) {
- // dbProcess = dbControl.getDbProcess();
- // }
-
- long timeNow = PamCalendar.getTimeInMillis();
-
- createDefaultStreamerUnits(timeNow);
- createDefaultHydrophoneUnits(timeNow);
-
- arrayDataSaved = true;
- }
- public int createDefaultStreamerUnits(long timeNow) {
-
- PamArray currentArray = arrayManager.getCurrentArray();
- if (currentArray == null) {
- return 0;
+ arrayDataSaved = true;
}
- int n = currentArray.getNumStreamers();
- Streamer s;
- StreamerDataUnit sdu;
- StreamerDataBlock sdb = arrayManager.getStreamerDatabBlock();
- for (int i = 0; i < n; i++) {
- if (sdb.getPreceedingUnit(timeNow,1<%s UID:%d, Database: %d %s ",
+ "GPS Data", getUID(), getDatabaseIndex(), PamCalendar.formatDBDateTime(getTimeMilliseconds(), true));
if (gpsData != null) {
str += gpsData.summaryString();
}
return str;
}
+ @Override
+ public double[] getFrequency() {
+ return null;
+ }
+
}
diff --git a/src/GPS/GpsLogger.java b/src/GPS/GpsLogger.java
index b02c32e6..f0f990c8 100644
--- a/src/GPS/GpsLogger.java
+++ b/src/GPS/GpsLogger.java
@@ -295,7 +295,8 @@ public class GpsLogger extends SQLLogging {
* time from the UTC column which is NOT the GpsData time which was the real GPS time.
*/
int gpsIntTimeVal = gpsTime.getIntegerValue();
- Object ts = getTableDefinition().getTimeStampItem().getValue();
+ PamTableDefinition pamTableDef = (PamTableDefinition) getTableDefinition();
+ Object ts = pamTableDef.getTimeStampItem().getValue();
long gpsDate = sqlTypes.millisFromTimeStamp(ts);
if (gpsDate%1000 == 0) {
// some databases may have stored the milliseconds, in which
diff --git a/src/IshmaelDetector/IshDetParams.java b/src/IshmaelDetector/IshDetParams.java
index d79b8d60..f8d4c2a9 100644
--- a/src/IshmaelDetector/IshDetParams.java
+++ b/src/IshmaelDetector/IshDetParams.java
@@ -17,6 +17,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.GroupedSourceParameters;
public class IshDetParams implements Serializable, Cloneable, ManagedParameters {
@@ -96,7 +97,7 @@ public class IshDetParams implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("inputDataSource");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/IshmaelDetector/IshDisplayParams.java b/src/IshmaelDetector/IshDisplayParams.java
index 609f9c2b..a0dea6aa 100644
--- a/src/IshmaelDetector/IshDisplayParams.java
+++ b/src/IshmaelDetector/IshDisplayParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Ishamel display parameters for the Spectrogram plug in.
@@ -42,7 +43,7 @@ public class IshDisplayParams implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/IshmaelDetector/IshLogger.java b/src/IshmaelDetector/IshLogger.java
index c9abdcfe..6bd47109 100644
--- a/src/IshmaelDetector/IshLogger.java
+++ b/src/IshmaelDetector/IshLogger.java
@@ -8,14 +8,13 @@ import java.sql.Types;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
-
+import generalDatabase.EmptyTableDefinition;
//import pamDatabase.SQLLogging;
//import PamguardMVC.RecyclingDataBlock;
import generalDatabase.PamDetectionLogging;
public class IshLogger extends PamDetectionLogging {
IshDetControl ishDetControl;
- PamTableDefinition tableDefinition;
PamTableItem systemDate, durationSecs, secSinceStart, peakHeight;
// Peak is more important than start time for matched filter & spectrogram correlation
PamTableItem peakSample, peakDelaySecs;
@@ -25,7 +24,7 @@ public class IshLogger extends PamDetectionLogging {
super(pamDataBlock, UPDATE_POLICY_WRITENEW);
this.ishDetControl = ishDetControl;
- tableDefinition = getTableDefinition();
+ EmptyTableDefinition tableDefinition = getTableDefinition();
// PamTableItem tableItem;
// setUpdatePolicy(UPDATE_POLICY_WRITENEW);
diff --git a/src/IshmaelLocator/IshLocSqlLogging.java b/src/IshmaelLocator/IshLocSqlLogging.java
index 0b95afe3..c43539d0 100644
--- a/src/IshmaelLocator/IshLocSqlLogging.java
+++ b/src/IshmaelLocator/IshLocSqlLogging.java
@@ -14,14 +14,13 @@ import IshmaelDetector.IshDetection;
import PamUtils.LatLong;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
-
+import generalDatabase.EmptyTableDefinition;
//import pamDatabase.SQLLogging;
//import PamguardMVC.RecyclingDataBlock;
import generalDatabase.PamDetectionLogging;
public class IshLocSqlLogging extends PamDetectionLogging {
IshLocControl ishLocControl;
- PamTableDefinition tableDefinition;
PamTableItem systemDate, durationSecs, secSinceStart, peakHeight;
private PamTableItem latitude, longitude, refLatitude, refLongitude, x, y, z;
@@ -30,7 +29,7 @@ public class IshLocSqlLogging extends PamDetectionLogging {
super(pamDataBlock, UPDATE_POLICY_WRITENEW);
this.ishLocControl = ishDetControl;
- tableDefinition = getTableDefinition();
+ EmptyTableDefinition tableDefinition = getTableDefinition();
tableDefinition.addTableItem(latitude = new PamTableItem("Latitude", Types.DOUBLE));
tableDefinition.addTableItem(longitude = new PamTableItem("Longitude", Types.DOUBLE));
tableDefinition.addTableItem(refLatitude = new PamTableItem("ReferenceLatitude", Types.DOUBLE));
diff --git a/src/KernelSmoothing/KernelSmoothingParameters.java b/src/KernelSmoothing/KernelSmoothingParameters.java
index 8b5f010c..6ddd593b 100644
--- a/src/KernelSmoothing/KernelSmoothingParameters.java
+++ b/src/KernelSmoothing/KernelSmoothingParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class KernelSmoothingParameters implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class KernelSmoothingParameters implements Serializable, Cloneable, Manag
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/Localiser/DelayMeasurementParams.java b/src/Localiser/DelayMeasurementParams.java
index dc92235d..4a232970 100644
--- a/src/Localiser/DelayMeasurementParams.java
+++ b/src/Localiser/DelayMeasurementParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import fftFilter.FFTFilterParams;
/**
@@ -157,7 +158,7 @@ public class DelayMeasurementParams implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java
index 19aae965..0eb58fcb 100644
--- a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java
+++ b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Paramters for running a Marklov chain Monte Carlo algorithm.
@@ -141,7 +142,7 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java b/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java
index bc3983b6..214f337c 100644
--- a/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java
+++ b/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class MCMCParams implements Serializable, Cloneable, ManagedParameters {
@@ -64,7 +65,7 @@ public class MCMCParams implements Serializable, Cloneable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java
index d7cdc11f..d012bfdb 100644
--- a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java
+++ b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
@@ -69,7 +70,7 @@ public class HyperbolicParams implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/Localiser/controls/RawOrFFTParams.java b/src/Localiser/controls/RawOrFFTParams.java
index 0545ea90..9df83a54 100644
--- a/src/Localiser/controls/RawOrFFTParams.java
+++ b/src/Localiser/controls/RawOrFFTParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import Spectrogram.WindowFunction;
/**
@@ -104,7 +105,7 @@ public class RawOrFFTParams implements Serializable, Cloneable, RawOrFFTParamsIn
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/Map/GebcoMapFile.java b/src/Map/GebcoMapFile.java
index befe7d3a..acb2112c 100644
--- a/src/Map/GebcoMapFile.java
+++ b/src/Map/GebcoMapFile.java
@@ -85,7 +85,15 @@ public class GebcoMapFile implements MapFileManager {
* @see Map.MapFile#readFileData(java.io.File)
*/
public boolean readFileData(File file) {
- return readMapFile(file, true);
+ try {
+ return readMapFile(file, true);
+ }
+ catch (Exception e) {
+ // trap error someone reported at end November 22. Suspect it was their corrupt map file causing problems.
+ String err = String.format("Map file %s is missing or corrupt and cannot be loaded", file.getName());
+ WarnOnce.showWarning("Map File Error", err, WarnOnce.OK_OPTION);
+ return false;
+ }
}
private boolean readMapFile(File gebcoFile, boolean readContours) {
diff --git a/src/Map/MapDetectionsParameters.java b/src/Map/MapDetectionsParameters.java
index a52aff72..bfc72e9b 100644
--- a/src/Map/MapDetectionsParameters.java
+++ b/src/Map/MapDetectionsParameters.java
@@ -7,6 +7,7 @@ import java.util.ListIterator;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* PArameters for MapDetectionsManager which
@@ -65,7 +66,7 @@ public class MapDetectionsParameters implements Serializable, Cloneable, Managed
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/Map/MapPanel.java b/src/Map/MapPanel.java
index e3122141..225f01ef 100644
--- a/src/Map/MapPanel.java
+++ b/src/Map/MapPanel.java
@@ -1096,6 +1096,7 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana
return;
}
ds = dataBlock.getDataSelector(simpleMapRef.getUnitName(), false, DATASELECTNAME);
+// ds = null;
ArrayList dataCopy = dataBlock.getDataCopy(earliestToPlot, now, true, ds);
duIterator = dataCopy.listIterator();
while (duIterator.hasNext()) {
diff --git a/src/Map/MapParameters.java b/src/Map/MapParameters.java
index b0eee649..11baeb07 100644
--- a/src/Map/MapParameters.java
+++ b/src/Map/MapParameters.java
@@ -27,6 +27,7 @@ import java.lang.reflect.Field;
import Array.Hydrophone;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class MapParameters implements Serializable, Cloneable, ManagedParameters {
@@ -301,7 +302,7 @@ public class MapParameters implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/Map/MapRectProjector.java b/src/Map/MapRectProjector.java
index dd402886..2c45a517 100644
--- a/src/Map/MapRectProjector.java
+++ b/src/Map/MapRectProjector.java
@@ -20,9 +20,15 @@
*/
package Map;
+import java.awt.Point;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;
+import java.util.ListIterator;
+import GPS.GPSControl;
+import GPS.GPSDataBlock;
+import GPS.GpsDataUnit;
+import PamController.PamController;
import PamUtils.Coordinate3d;
import PamUtils.LatLong;
import PamUtils.PamCoordinate;
@@ -385,6 +391,45 @@ public class MapRectProjector extends MapProjector {
return xTrans;
}
+ @Override
+ public String getHoverText(Point mousePoint, int ploNumberMatch) {
+ String text = super.getHoverText(mousePoint, ploNumberMatch);
+ if (text == null) {
+ return findGpsTrackText(mousePoint, ploNumberMatch);
+ }
+ else {
+ return text;
+ }
+ }
+
+ private String findGpsTrackText(Point mousePoint, int ploNumberMatch) {
+ GPSControl gpsControl = GPSControl.getGpsControl();
+ if (gpsControl == null || mousePoint == null) {
+ return null;
+ }
+ LatLong currentPos = getDataPosition(new Coordinate3d(mousePoint.x, mousePoint.y));
+ GPSDataBlock gpsDataBlock = gpsControl.getGpsDataBlock();
+ double dist = Double.MAX_VALUE;
+ GpsDataUnit closest = null;
+ ListIterator it = gpsDataBlock.getListIterator(0);
+ while (it.hasNext()) {
+ GpsDataUnit gpsUnit = it.next();
+ double r = gpsUnit.getGpsData().distanceToMetres(currentPos);
+ if (r < dist) {
+ dist = r;
+ closest = gpsUnit;
+ }
+ }
+ if (closest == null) {
+ return null;
+ }
+ double rPix = dist*this.pixelsPerMetre;
+ if (rPix > 20) {
+ return null;
+ }
+ return closest.getSummaryString();
+ }
+
}
diff --git a/src/Map/gridbaselayer/GridbaseParameters.java b/src/Map/gridbaselayer/GridbaseParameters.java
index 2af62e75..fe608b8d 100644
--- a/src/Map/gridbaselayer/GridbaseParameters.java
+++ b/src/Map/gridbaselayer/GridbaseParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class GridbaseParameters implements Cloneable, Serializable, ManagedParameters {
@@ -25,7 +26,7 @@ public class GridbaseParameters implements Cloneable, Serializable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/NMEA/NMEAParameters.java b/src/NMEA/NMEAParameters.java
index 42393be3..9da8c22c 100644
--- a/src/NMEA/NMEAParameters.java
+++ b/src/NMEA/NMEAParameters.java
@@ -24,6 +24,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import serialComms.jserialcomm.PJSerialComm;
public class NMEAParameters implements Serializable, Cloneable, ManagedParameters {
@@ -149,7 +150,7 @@ public class NMEAParameters implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/PamController/OfflineDataStore.java b/src/PamController/OfflineDataStore.java
index 52e64150..20a34041 100644
--- a/src/PamController/OfflineDataStore.java
+++ b/src/PamController/OfflineDataStore.java
@@ -33,6 +33,13 @@ public interface OfflineDataStore {
*/
public String getDataSourceName();
+ /**
+ * Get the data location. This may be a specific file, or might be a folder
+ * if data are in many files, a URI, etc.
+ * @return store locations
+ */
+ public String getDataLocation();
+
/**
* Load data for a given datablock between two time limits.
* @param dataBlock datablock owner of the data
diff --git a/src/PamController/PamControlledUnit.java b/src/PamController/PamControlledUnit.java
index f1962ca8..654bd715 100644
--- a/src/PamController/PamControlledUnit.java
+++ b/src/PamController/PamControlledUnit.java
@@ -23,6 +23,7 @@ package PamController;
import java.awt.Component;
import java.awt.Frame;
import java.util.ArrayList;
+import java.util.List;
import javax.swing.JFrame;
import javax.swing.JMenu;
@@ -30,16 +31,14 @@ import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
-import offlineProcessing.OfflineTask;
import offlineProcessing.OfflineTaskGroup;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
import PamController.status.ModuleStatus;
import PamController.status.ModuleStatusManager;
import PamController.status.ProcessCheck;
+import PamModel.PamModel;
import PamModel.PamModuleInfo;
+import PamModel.PamPluginInterface;
import PamView.ClipboardCopier;
import PamView.PamGui;
import PamView.PamSidePanel;
@@ -845,6 +844,16 @@ public abstract class PamControlledUnit implements SettingsNameProvider {
}
return worstStatus;
}
+
+ /**
+ * Get the offline state of this module. This can generally
+ * be idle, but can be a higher state when map making at startup
+ * and when running an offline task.
+ * @return
+ */
+ public int getOfflineState() {
+ return PamController.PAM_IDLE;
+ }
// /**
// * Get a list of available offline tasks for this module. This is mostly used for tasks that
@@ -880,6 +889,53 @@ public abstract class PamControlledUnit implements SettingsNameProvider {
public int getInstanceIndex() {
return instanceIndex;
}
+
+ /**
+ * Get detail if this is a plugin.
+ * @return plugin detail, or null if it's not a plugin.
+ */
+ public PamPluginInterface getPlugin() {
+ List pluginList = ((PamModel) PamController.getInstance().getModelInterface()).getPluginList();
+ if (pluginList == null) {
+ return null;
+ }
+ for (PamPluginInterface plugin : pluginList) {
+ if (plugin.getClassName().equals(this.getClass().getName())) {
+ return plugin;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * The PamConfiguration holds the master list of modules which form part of a
+ * configuration. It should be accessed to find list of datablocks, etc. rather than
+ * doing everything through PAMController whenever possible.
+ * @return the pamConfiguration
+ */
+ public PamConfiguration getPamConfiguration() {
+ if (pamConfiguration == null) {
+ pamConfiguration = PamController.getInstance().getPamConfiguration();
+ }
+ return pamConfiguration;
+ }
+
+ /**
+ * Is this module in the main configuration. If it isn't then it's probably a dummy config
+ * used in the batch processor or for importing / exporting configs, so it should be stopped from
+ * doing too much !
+ * @return
+ */
+ public boolean isInMainConfiguration() {
+ return pamConfiguration == PamController.getInstance().getPamConfiguration();
+ }
+
+ /**
+ * @param pamConfiguration the pamConfiguration to set
+ */
+ public void setPamConfiguration(PamConfiguration pamConfiguration) {
+ this.pamConfiguration = pamConfiguration;
+ }
/**
* The PamConfiguration holds the master list of modules which form part of a
diff --git a/src/PamController/PamControlledUnitSettings.java b/src/PamController/PamControlledUnitSettings.java
index ccdc18bf..4d8c1ecc 100644
--- a/src/PamController/PamControlledUnitSettings.java
+++ b/src/PamController/PamControlledUnitSettings.java
@@ -36,6 +36,7 @@ import org.apache.commons.io.input.ClassLoaderObjectInputStream;
import PamModel.PamModel;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.dialog.warn.WarnOnce;
@@ -398,8 +399,13 @@ public class PamControlledUnitSettings implements Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
+ @Override
+ public String toString() {
+ return String.format("Type %s; Name %s, Data ", getUnitType(), getUnitName()) + getSettings();
+ }
+
}
diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java
index 389015ae..dfa37f56 100644
--- a/src/PamController/PamController.java
+++ b/src/PamController/PamController.java
@@ -37,6 +37,7 @@ import javax.swing.ToolTipManager;
import com.jcraft.jsch.ConfigRepository.Config;
import com.sun.xml.bind.v2.TODO;
+import Acquisition.AcquisitionControl;
import Acquisition.AcquisitionProcess;
//import com.sun.org.apache.xerces.internal.dom.DocumentImpl;
@@ -57,6 +58,7 @@ import fftManager.FFTDataUnit;
import generalDatabase.DBControlUnit;
import javafx.application.Platform;
import javafx.stage.Stage;
+import metadata.MetaDataContol;
import Array.ArrayManager;
import PamController.command.MulticastController;
import PamController.command.NetworkController;
@@ -64,6 +66,7 @@ import PamController.command.TerminalController;
import PamController.command.WatchdogComms;
import PamController.fileprocessing.ReprocessManager;
import PamController.masterReference.MasterReferencePoint;
+import PamController.settings.BatchViewSettingsImport;
import PamController.settings.output.xml.PamguardXMLWriter;
import PamController.settings.output.xml.XMLWriterDialog;
import PamController.soundMedium.GlobalMediumManager;
@@ -123,6 +126,12 @@ public class PamController implements PamControllerInterface, PamSettings {
public static final int PAM_INITIALISING = 4;
public static final int PAM_STOPPING = 5;
public static final int PAM_COMPLETE = 6;
+ public static final int PAM_MAPMAKING = 7;
+ public static final int PAM_OFFLINETASK = 8;
+
+ public static final int BUTTON_START = 1;
+ public static final int BUTTON_STOP = 2;
+ private volatile int lastStartStopButton = 0;
// status' for RunMode = RUN_PAMVIEW
public static final int PAM_LOADINGDATA = 2;
@@ -156,7 +165,7 @@ public class PamController implements PamControllerInterface, PamSettings {
/**
* The current PAM status
*/
- private transient int pamStatus = PAM_IDLE;
+ private volatile int pamStatus = PAM_IDLE;
/**
* PamGuard view params.
@@ -186,6 +195,8 @@ public class PamController implements PamControllerInterface, PamSettings {
private static PamController uniqueController;
private Timer diagnosticTimer;
+
+ private boolean debugDumpBufferAtRestart = false;
private NetworkController networkController;
private int nNetPrepared;
@@ -234,6 +245,10 @@ public class PamController implements PamControllerInterface, PamSettings {
*/
private Thread statusCheckThread;
private WaitDetectorThread detectorEndThread;
+ private boolean firstDataLoadComplete;
+ // keep a track of the total number of times PAMGuard is started for debug purposes.
+ private int nStarts;
+ private RestartRunnable restartRunnable;
private PamController(int runMode, Object object) {
@@ -436,7 +451,7 @@ public class PamController implements PamControllerInterface, PamSettings {
// addModule(mi, "Temporary Database");
// }
- // Add a note to the putput console for the user to ignore the SLF4J warning (see http://www.slf4j.org/codes.html#StaticLoggerBinder
+ // Add a note to the output console for the user to ignore the SLF4J warning (see http://www.slf4j.org/codes.html#StaticLoggerBinder
// for details). I spent a few hours trying to get rid of this warning, but without any luck. If you do a google search
// there are a lot of forum suggestions on how to fix, but none seemed to work for me. Added both slf4j-nop and
// slf4j-simple to dependency list, neither made a difference. Changed order of dependencies, ran purges and updates,
@@ -452,6 +467,7 @@ public class PamController implements PamControllerInterface, PamSettings {
System.out.println("");
System.out.println("Note - ignore the following SLF4J warn/error messages, they are not applicable to this application");
ArrayManager.getArrayManager(); // create the array manager so that it get's it's settings
+ MetaDataContol.getMetaDataControl();
/**
* Check for archived files and unpack automatically.
@@ -490,17 +506,31 @@ public class PamController implements PamControllerInterface, PamSettings {
addView(guiFrameManager.initPrimaryView(this, pamModelInterface));
}
+ /**
+ * Calling this will cause a callback to this.restoreSettings which
+ * includes a list of modules which will then get created, and in turn
+ * load all of their own settings from the settings manager.
+ */
PamSettingManager.getInstance().registerSettings(this);
+
+ /**
+ * For offline batch processing a few funnies happen here. We'll be open
+ * in viewer mode, but it's likely a psf will have been passed as an input argument.
+ * We will therefore have to extract all the modules from that psfx as well and either
+ * add them as new modules, or get their settings and use those to update existing settings
+ * That should probably be done here before the final calls to setup processes, etc.
+ */
+ if (getRunMode() == RUN_PAMVIEW && PamSettingManager.remote_psf != null) {
+ loadOtherSettings(PamSettingManager.remote_psf);
+ }
+ /*
+ * Get any other required modules for this run mode.
+ */
pamModelInterface.startModel();
setupProcesses();
- // if (getRunMode() == RUN_PAMVIEW) {
- // createViewerStatusBar();
- // pamControlledUnits.add(new OfflineProcessingControlledUnit("OfflineProcessing"));
- // }
-
/*
* We are running as a remote application, start process straight away!
*/
@@ -571,6 +601,7 @@ public class PamController implements PamControllerInterface, PamSettings {
// });
}
+
/**
* Clear all data selectors and symbol managers. Required since some of these will have loaded as various modules were created,
* but may also require additional data selectors and symbol managers from super detections which were not availble.
@@ -583,6 +614,11 @@ public class PamController implements PamControllerInterface, PamSettings {
}
+ /**
+ * This gets called after other data initialisation tasks (such as data mapping).
+ * @author dg50
+ *
+ */
class DataInitialised implements Runnable {
@Override
public void run() {
@@ -1018,8 +1054,45 @@ public class PamController implements PamControllerInterface, PamSettings {
*/
public void restartPamguard() {
pamStop();
- startLater();
+
+ /*
+ * launch a restart thread, that won't do ANYTHING until
+ * PAMGuard is really idle and buffers are cleared. Can only
+ * have one of these at a time !
+ */
+ if (restartRunnable != null) {
+ System.out.println("Warning !!!! PAMGuard is already trying to restart!");
+ return;
+ }
+ restartRunnable = new RestartRunnable();
+ Thread restartThread = new Thread(restartRunnable, "RestartPAMGuard Thread");
+ restartThread.run();
}
+
+ private class RestartRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ long t1 = System.currentTimeMillis();
+ while (getPamStatus() != PAM_IDLE) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+
+ }
+ }
+ long t2 = System.currentTimeMillis();
+ restartRunnable = null;
+ System.out.printf("PAMGuard safe to restart after %d milliseconds\n", t2-t1);
+ startLater(false);
+
+ }
+
+ }
+
+
+
+
/**
* calls pamStart using the SwingUtilities
* invokeLater command to start PAMGAURD
@@ -1051,7 +1124,13 @@ public class PamController implements PamControllerInterface, PamSettings {
@Override
public void run() {
- pamStart(saveSettings);
+ /*
+ * do a final check that the stop button hasn't been pressed - can arrive a bit
+ * late if the system was continually restarting.
+ */
+ if (lastStartStopButton != BUTTON_STOP) {
+ pamStart(saveSettings);
+ }
}
}
@@ -1076,6 +1155,26 @@ public class PamController implements PamControllerInterface, PamSettings {
}
}
+ /**
+ * Called from the start button. A little book keeping
+ * to distinguish this from automatic starts / restarts
+ * @return true if started.
+ */
+ @Override
+ public boolean manualStart() {
+ lastStartStopButton = BUTTON_START;
+ return pamStart();
+ }
+
+ /**
+ * Called from the stop button. A little book keeping
+ * to distinguish this from automatic starts / restarts
+ */
+ @Override
+ public void manualStop() {
+ lastStartStopButton = BUTTON_STOP;
+ pamStop();
+ }
/**
* Start PAMGUARD. This function also gets called from the
@@ -1161,9 +1260,17 @@ public class PamController implements PamControllerInterface, PamSettings {
}
if (saveSettings) {
+ startTime = PamCalendar.getSessionStartTime();
+// System.out.printf("Saving settings for start time %s\n", PamCalendar.formatDBDateTime(startTime));
saveSettings(PamCalendar.getSessionStartTime());
}
+ if (++nStarts > 1 && debugDumpBufferAtRestart) {
+ // do this here - all processses should have reset buffers to start again by now.
+ String msg = String.format("Starting PAMGuard go %d", nStarts);
+ dumpBufferStatus(msg, false);
+ }
+
StorageOptions.getInstance().setBlockOptions();
t1 = System.currentTimeMillis();
@@ -1225,6 +1332,7 @@ public class PamController implements PamControllerInterface, PamSettings {
}
}
+ dumpBufferStatus("In stopping", false);
/*
* now launch another thread to wait for everything to have stopped, but
* leave this function so that AWT is released and graphics can update, the
@@ -1252,9 +1360,11 @@ public class PamController implements PamControllerInterface, PamSettings {
long t2 = System.currentTimeMillis();
if (t2 - t1 > 5000) {
System.out.printf("Stopping, but stuck in loop for CheckRunStatus for %3.1fs\n", (double) (t2-t1)/1000.);
+ dumpBufferStatus("Stopping stuck in loop", false);
+ break; // crap out anyway.
}
try {
- Thread.sleep(10);
+ Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
@@ -1265,19 +1375,43 @@ public class PamController implements PamControllerInterface, PamSettings {
}
+ /**
+ * Look in every data block, particularly threaded ones, and dump
+ * the buffer status. This will have to go via PamProcess so that
+ * additional information can be added from any processes that
+ * hold additional data in other internal buffers.
+ * @param message Message to print prior to dumping buffers for debug.
+ * @param sayEmpties dump info even if a buffer is empty (otherwise, only ones that have stuff still)
+ */
+ public void dumpBufferStatus(String message, boolean sayEmpties) {
+ if (debugDumpBufferAtRestart == false) return;
+
+ System.out.println("**** Dumping process buffer status: " + message);
+ ArrayList pamControlledUnits = pamConfiguration.getPamControlledUnits();
+ for (PamControlledUnit aUnit : pamControlledUnits) {
+ int numProcesses = aUnit.getNumPamProcesses();
+ for (int i=0; i pamControlledUnits = pamConfiguration.getPamControlledUnits();
if (PamModel.getPamModel().isMultiThread()) {
@@ -1298,7 +1434,7 @@ public class PamController implements PamControllerInterface, PamSettings {
pamControlledUnits.get(iU).flushDataBlockBuffers(2000);
}
}
- setPamStatus(PAM_IDLE);
+ dumpBufferStatus("In pamStopped, now idle", true);
// wait here until the status has changed to Pam_Idle, so that we know
// that we've really finished processing all data
@@ -1319,6 +1455,11 @@ public class PamController implements PamControllerInterface, PamSettings {
}
guiFrameManager.pamEnded();
+ long stopTime = PamCalendar.getTimeInMillis();
+ saveEndSettings(stopTime);
+
+ setPamStatus(PAM_IDLE);
+
// no good having this here since it get's called at the end of every file.
// if (GlobalArguments.getParam(PamController.AUTOEXIT) != null) {
//// can exit here, since we've auto started, can auto exit.
@@ -1437,6 +1578,26 @@ public class PamController implements PamControllerInterface, PamSettings {
pamConfiguration.saveSettings(timeNow);
}
+ /**
+ * Gets called in pamStart and may / will attempt to store all
+ * PAMGUARD settings via the database and binary storage modules.
+ */
+ private void saveEndSettings(long timeNow) {
+// System.out.printf("Updating settings with end time %s\n", PamCalendar.formatDBDateTime(timeNow));
+ ArrayList pamControlledUnits = pamConfiguration.getPamControlledUnits();
+ PamControlledUnit pcu;
+ PamSettingsSource settingsSource;
+ for (int iU = 0; iU < pamControlledUnits.size(); iU++) {
+ pcu = pamControlledUnits.get(iU);
+ if (PamSettingsSource.class.isAssignableFrom(pcu.getClass())) {
+ settingsSource = (PamSettingsSource) pcu;
+ settingsSource.saveEndSettings(timeNow);
+ }
+ }
+ }
+
+
+
/**
* Export configuration into an XML file
* @param parentFrame
@@ -1676,16 +1837,23 @@ public class PamController implements PamControllerInterface, PamSettings {
* Updates the entire datamap.
*/
public void updateDataMap(){
+ System.out.println("updateDataMap:");
if (DBControlUnit.findDatabaseControl()==null) return;
+
+ System.out.println("updateDataMap: 1");
ArrayList datablocks=getDataBlocks() ;
+ System.out.println("updateDataMap: 2");
+
DBControlUnit.findDatabaseControl().updateDataMap(datablocks);
- if (BinaryStore.findBinaryStoreControl()!=null) {
- BinaryStore.findBinaryStoreControl().getDatagramManager().updateDatagrams();
- }
+ System.out.println("updateDataMap: 3");
+
+ BinaryStore.findBinaryStoreControl().getDatagramManager().updateDatagrams();
+
+ System.out.println("updateDataMap: 4");
notifyModelChanged(PamControllerInterface.EXTERNAL_DATA_IMPORTED);
}
@@ -1758,6 +1926,10 @@ public class PamController implements PamControllerInterface, PamSettings {
if (moduleChange(changeType)) {
clearSelectorsAndSymbols();
}
+
+ if (changeType == DATA_LOAD_COMPLETE) {
+ firstDataLoadComplete = true;
+ }
}
@@ -1894,12 +2066,78 @@ public class PamController implements PamControllerInterface, PamSettings {
public void setPamStatus(int pamStatus) {
this.pamStatus = pamStatus;
+ /*
+ * This only get's called once when set idle at viewer mode startup.
+ */
+ if (debugDumpBufferAtRestart) {
+ System.out.printf("******* PamController.setPamStatus to %d, real status is %d set in thread %s\n",
+ pamStatus, getRealStatus(), Thread.currentThread().toString());
+ }
if (getRunMode() != RUN_PAMVIEW) {
TopToolBar.enableStartButton(pamStatus == PAM_IDLE);
TopToolBar.enableStopButton(pamStatus == PAM_RUNNING);
}
showStatusWarning(pamStatus);
}
+
+ /**
+ * This was within the StatusCommand class, but useful to have it here since it's needed
+ * in more than one place. In viewer mode at startup there are a number of things going on
+ * in different threads, such as the creation of datamaps, and this can (hopefully) handle those bespoke
+ * goings on.
+ * @return program status for multithreaded statup tasks.
+ */
+ public int getRealStatus() {
+ PamController pamController = PamController.getInstance();
+ if (pamController.isInitializationComplete() == false) {
+ return PamController.PAM_INITIALISING;
+ }
+ int runMode = PamController.getInstance().getRunMode();
+ if (runMode == PamController.RUN_NETWORKRECEIVER) {
+ return PamController.PAM_RUNNING;
+ }
+ int status = pamController.getPamStatus();
+ if (status == PamController.PAM_IDLE) {
+ status = PamController.PAM_IDLE;
+ }
+ else {
+ ArrayList daqs = PamController.getInstance().findControlledUnits(AcquisitionControl.unitType);
+ if (daqs != null) for (int i = 0; i < daqs.size(); i++) {
+ try {
+ AcquisitionControl daq = (AcquisitionControl) daqs.get(i);
+ if (daq.isStalled()) {
+ status = PamController.PAM_STALLED;
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ WatchdogComms watchdogComms = PamController.getInstance().getWatchdogComms();
+ status = watchdogComms.getModifiedWatchdogState(status);
+ /*
+ * This function is now being used in batch processing of offline data, where it may be necessary
+ * to get status information from many different modules, for example when executing offline tasks
+ * or just at startup while generating datamaps and datagrams.
+ * So go through all modules and get the highest state of any of them.
+ */
+ if (getRunMode() == RUN_PAMVIEW) {
+ if (firstDataLoadComplete == false) {
+ status = PAM_INITIALISING;
+ }
+ try {
+ for (PamControlledUnit aUnit : pamConfiguration.getPamControlledUnits()) {
+ status = Math.max(status, aUnit.getOfflineState());
+ }
+ }
+ catch (Exception e) {
+ //just incase there is a concurrent modification at startup.
+ }
+ }
+
+ return status;
+ }
/**
* show a warning when we're waiting for detectors to stop
@@ -1928,6 +2166,7 @@ public class PamController implements PamControllerInterface, PamSettings {
statusWarning.setWarningMessage(warningMessage);
statusWarning.setWarnignLevel(1);
warningSystem.addWarning(statusWarning);
+// System.out.println(warningMessage);
}
}
@@ -2184,6 +2423,31 @@ public class PamController implements PamControllerInterface, PamSettings {
private boolean manualStop;
+ /**
+ * Used when in viewer mode and planning batch processing with a modified
+ * configuration, i.e. the command line has been supplied a normal viewer mode
+ * database and also a psfx file. The settings from the database will already have
+ * been loaded, this will load any modules that weren't there and will override all the
+ * settings in other modules with these ones (except some specials such as data storage locations)
+ * @param psfxFile Name of additional psfx file.
+ */
+ private boolean loadOtherSettings(String psfxName) {
+
+ File psfxFile = new File(psfxName);
+ if (psfxFile.exists() == false) {
+ return false;
+ }
+
+ PamSettingsGroup settingsGroup = PSFXReadWriter.getInstance().loadFileSettings(psfxFile);
+ if (settingsGroup == null) {
+ return false;
+ }
+
+ BatchViewSettingsImport importer = new BatchViewSettingsImport(this, settingsGroup);
+ importer.importSettings();
+ return true;
+ }
+
/**
* Called to load a specific set of PAMGUARD settings in
* viewer mode, which were previously loaded in from a
@@ -2400,7 +2664,7 @@ public class PamController implements PamControllerInterface, PamSettings {
if (dbc == null) {
return null;
}
- return dbc.getDatabaseName();
+ return dbc.getLongDatabaseName();
}
return null;
}
diff --git a/src/PamController/PamControllerInterface.java b/src/PamController/PamControllerInterface.java
index d363f958..9cc416d8 100644
--- a/src/PamController/PamControllerInterface.java
+++ b/src/PamController/PamControllerInterface.java
@@ -458,6 +458,17 @@ public interface PamControllerInterface {
* Close all modules and free up resources.
*/
public void pamClose();
+
+ /**
+ * Start function called from button to do a bit of extra book keeping
+ * @return
+ */
+ public boolean manualStart();
+
+ /**
+ * Stop function called from button to do a bit of extra book keeping
+ */
+ public void manualStop();
//public void controllerAddFileMenuItem();
diff --git a/src/PamController/PamSensor.java b/src/PamController/PamSensor.java
new file mode 100644
index 00000000..03e51efe
--- /dev/null
+++ b/src/PamController/PamSensor.java
@@ -0,0 +1,20 @@
+package PamController;
+
+/**
+ * Interface to define modules which can be considered as sensors of some sort.
+ * e.g. depth and orientation modules and the SoundTrap clickdetecotr
+ * @author dg50
+ *
+ */
+public interface PamSensor {
+
+ public String getUnitName();
+
+ public String getUnitType();
+
+ public String getSensorDescription();
+
+ public String getSensorId();
+
+
+}
diff --git a/src/PamController/PamSettingManager.java b/src/PamController/PamSettingManager.java
index ddd15740..43d92d09 100644
--- a/src/PamController/PamSettingManager.java
+++ b/src/PamController/PamSettingManager.java
@@ -44,6 +44,7 @@ import javax.swing.plaf.FontUIResource;
import pamViewFX.fxNodes.utilsFX.PamUtilsFX;
import pamViewFX.fxSettingsPanes.SettingsFileDialogFX;
+import pamguard.GlobalArguments;
//XMLSettings
//import org.jdom.Document;
@@ -383,6 +384,8 @@ public class PamSettingManager {
boolean[] usedSettings, PamSettings user) {
if (settingsList == null) return null;
// go through the list and see if any match this module. Avoid repeats.
+// String unitName = user.getUnitName();
+// String unitType = user.getUnitType();
for (int i = 0; i < settingsList.size(); i++) {
if (usedSettings != null && usedSettings[i]) continue;
if (isSettingsUnit(user, settingsList.get(i))) {
@@ -392,6 +395,7 @@ public class PamSettingManager {
return settingsList.get(i);
}
}
+
/*
* To improve complex module loading where settings may be saved by multiple sub-modules, in
* July 2015 many modules which had fixed settings had their settings names and types changed !
@@ -476,7 +480,7 @@ public class PamSettingManager {
*/
public PamSettings findSettingsOwner(String unitType, String unitName, String unitClassName) {
for (PamSettings owner:owners) {
- if (owner.getClass() != null) {
+ if (owner.getClass() != null && unitClassName != null) {
if (owner.getClass().getName().equals(unitClassName) == false) {
continue;
}
@@ -492,7 +496,7 @@ public class PamSettingManager {
/**
* Call just before PAMGUARD exits to save the settings
* either to psf and / or database tables.
- * @return true if settings saved sucessfully.
+ * @return true if settings saved successfully.
*/
public boolean saveFinalSettings() {
int runMode = PamController.getInstance().getRunMode();
@@ -1029,8 +1033,9 @@ public class PamSettingManager {
loadingLocalSettings = true;
loadSettingsFileData();
+
- if (PamSettingManager.RUN_REMOTE == false) {
+ if (PamSettingManager.RUN_REMOTE == false && GlobalArguments.isBatch() == false) {
if (settingsFileData != null) {
TipOfTheDayManager.getInstance().setShowAtStart(settingsFileData.showTipAtStartup);
if (settingsFileData.showTipAtStartup) {
@@ -1480,11 +1485,20 @@ public class PamSettingManager {
if (settings.getUnitName() == null || settingsUser.getUnitName() == null) return false;
if (settings.getUnitType() == null || settingsUser.getUnitType() == null) return false;
-
- if (settings.getUnitName().equals(settingsUser.getUnitName())
- && settings.getUnitType().equals(settingsUser.getUnitType())
- && settings.versionNo == settingsUser.getSettingsVersion()){
- return true;
+ /*
+ * some of the settings names used in Viewer mode have become too long, notably
+ * in some data selectors which are using a datablocks long data name. This
+ * screws things up, so moving to a begins with rather than equals for the name.
+ */
+ String name = settingsUser.getUnitName();
+ String type = settingsUser.getUnitType();
+ long version = settingsUser.getSettingsVersion();
+
+ if (settings.getUnitType().equals(type)
+ && settings.versionNo == version){
+ if (name.startsWith(settings.getUnitName())) {
+ return true;
+ }
}
return false;
diff --git a/src/PamController/PamSettingsSource.java b/src/PamController/PamSettingsSource.java
index ed67807a..ba4079cc 100644
--- a/src/PamController/PamSettingsSource.java
+++ b/src/PamController/PamSettingsSource.java
@@ -20,6 +20,14 @@ public interface PamSettingsSource {
*/
public boolean saveStartSettings(long timeNow);
+ /**
+ * Save settings when processing ends.
+ * This may just be an update of the settings saves with saveStartSettings, e.g. an end time.
+ * @param timeNow
+ * @return true if saved correctly.
+ */
+ public boolean saveEndSettings(long timeNow);
+
/**
* Get the number of different settings
* within the settings source.
diff --git a/src/PamController/PamguardVersionInfo.java b/src/PamController/PamguardVersionInfo.java
index d46e0d2a..ddb47056 100644
--- a/src/PamController/PamguardVersionInfo.java
+++ b/src/PamController/PamguardVersionInfo.java
@@ -16,7 +16,7 @@ public class PamguardVersionInfo {
* @return release type
*/
static public ReleaseType getReleaseType() {
- return ReleaseType.CORE;
+ return ReleaseType.OTHER;
}
/**
@@ -31,12 +31,12 @@ public class PamguardVersionInfo {
* Version number, major version.minorversion.sub-release.
* Note: can't go higher than sub-release 'f'
*/
- static public final String version = "2.02.11b";
+ static public final String version = "2.02.10b";
/**
* Release date
*/
- static public final String date = "10 November 2023";
+ static public final String date = "2 March 2024";
// /**
// * Release type - Beta or Core
diff --git a/src/PamController/UsedModuleInfo.java b/src/PamController/UsedModuleInfo.java
index 88756866..1170027a 100644
--- a/src/PamController/UsedModuleInfo.java
+++ b/src/PamController/UsedModuleInfo.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Very simple class used in an ArrayList of used modules that
@@ -54,8 +55,16 @@ public class UsedModuleInfo implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
+ /**
+ * Get the unit name of the module being imported.
+ * @return
+ */
+ public String getUnitName() {
+ return unitName;
+ }
+
}
diff --git a/src/PamController/command/BatchStatusCommand.java b/src/PamController/command/BatchStatusCommand.java
index a58012b2..046dff3e 100644
--- a/src/PamController/command/BatchStatusCommand.java
+++ b/src/PamController/command/BatchStatusCommand.java
@@ -2,6 +2,7 @@ package PamController.command;
import Acquisition.AcquisitionControl;
import PamController.PamController;
+import offlineProcessing.OfflineTaskManager;
import pamViewFX.PamControlledGUIFX;
/**
@@ -21,6 +22,19 @@ public class BatchStatusCommand extends ExtCommand {
@Override
public String execute(String command) {
+ if (PamController.getInstance().getRunMode() == PamController.RUN_NORMAL) {
+ return getNormalModeStatus(command);
+ }
+ else {
+ return getViewerModeStatus(command);
+ }
+ }
+
+ private String getViewerModeStatus(String command) {
+ return OfflineTaskManager.getManager().getBatchStatus();
+ }
+
+ private String getNormalModeStatus(String command) {
AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
if (daqControl == null) {
return null;
diff --git a/src/PamController/command/StatusCommand.java b/src/PamController/command/StatusCommand.java
index 7d500e95..74acf77f 100644
--- a/src/PamController/command/StatusCommand.java
+++ b/src/PamController/command/StatusCommand.java
@@ -31,33 +31,7 @@ public class StatusCommand extends ExtCommand {
private int getRealStatus() {
PamController pamController = PamController.getInstance();
- if (pamController.isInitializationComplete() == false) {
- return PamController.PAM_INITIALISING;
- }
- int runMode = PamController.getInstance().getRunMode();
- if (runMode == PamController.RUN_NETWORKRECEIVER) {
- return PamController.PAM_RUNNING;
- }
- int status = pamController.getPamStatus();
- if (status == PamController.PAM_IDLE) {
- status = PamController.PAM_IDLE;
- }
- else {
- ArrayList daqs = PamController.getInstance().findControlledUnits(AcquisitionControl.unitType);
- if (daqs != null) for (int i = 0; i < daqs.size(); i++) {
- try {
- AcquisitionControl daq = (AcquisitionControl) daqs.get(i);
- if (daq.isStalled()) {
- status = PamController.PAM_STALLED;
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- WatchdogComms watchdogComms = PamController.getInstance().getWatchdogComms();
- return watchdogComms.getModifiedWatchdogState(status);
+ return pamController.getRealStatus();
}
diff --git a/src/PamController/settings/BatchViewSettingsImport.java b/src/PamController/settings/BatchViewSettingsImport.java
new file mode 100644
index 00000000..d9cb5b2a
--- /dev/null
+++ b/src/PamController/settings/BatchViewSettingsImport.java
@@ -0,0 +1,155 @@
+package PamController.settings;
+
+import java.util.ArrayList;
+
+import PamController.DataInputStore;
+import PamController.OfflineDataStore;
+import PamController.OfflineFileDataStore;
+import PamController.PamControlledUnit;
+import PamController.PamControlledUnitSettings;
+import PamController.PamController;
+import PamController.PamSettingManager;
+import PamController.PamSettings;
+import PamController.PamSettingsGroup;
+import PamController.UsedModuleInfo;
+import PamModel.PamModuleInfo;
+
+/**
+ * A set of functions to handle importing and overriding settings imported from a psfx during
+ * batch mode processing in viewer mode. Some of this is quite similar to code in SettingsImport
+ * but different enough that it's easier to have in a separate set of functions.
+ * @author dg50
+ *
+ */
+public class BatchViewSettingsImport {
+
+ private PamController pamController;
+ private PamSettingsGroup settingsGroup;
+ private SettingsImport settingsImport;
+
+ public BatchViewSettingsImport(PamController pamController, PamSettingsGroup settingsGroup) {
+ this.pamController = pamController;
+ this.settingsGroup = settingsGroup;
+ settingsImport = new SettingsImport(pamController);
+ }
+
+ public boolean importSettings() {
+
+ // first organise by controlled unit
+ ArrayList moduleGroups = settingsImport.organiseSettingsGroups(settingsGroup.getUnitSettings());
+ // can now go through those modules and see which exist and which need to be added. Not asking questions, just doing it!
+ for (SettingsImportGroup moduleGroup : moduleGroups) {
+ UsedModuleInfo moduleInfo = moduleGroup.getUsedModuleInfo();
+ PamControlledUnit exModule = pamController.findControlledUnit(moduleInfo.getUnitType(), moduleInfo.getUnitName());
+ boolean existingStore = false;
+ if (exModule != null) {
+ existingStore = isDataStore(exModule);
+ System.out.printf("Module %s:%s already exists in model (data store: %s)\n", moduleInfo.getUnitType(), moduleInfo.getUnitName(), Boolean.valueOf(existingStore));
+ }
+ else {
+ System.out.printf("Module %s:%s will be added to model\n", moduleInfo.getUnitType(), moduleInfo.getUnitName());
+ // add the module. No questions asked.
+ PamModuleInfo pamModuleInfo = moduleGroup.getPamModuleInfo();
+ if (pamModuleInfo == null) {
+ System.out.printf("Module %s:%s is not available to this PAMGuard installation\n", moduleInfo.getUnitType(), moduleInfo.getUnitName());
+ continue;
+ }
+ exModule = pamController.addModule(pamModuleInfo, moduleInfo.getUnitName());
+ }
+ // set the settings for that module, but only if it's NOT a data storage module.
+ if (exModule == null) {
+ continue;
+ }
+// if (exModule.getUnitName().contains("Noise")) {
+// System.out.printf("restoring settings for %s, %s\n", exModule.getUnitType(), exModule.getUnitName());
+//
+// }
+ if (isDataStore(exModule)) {
+ System.out.printf("Skip restoring settings for %s, %s\n", exModule.getUnitType(), exModule.getUnitName());
+ continue;
+ }
+ restoreSettings(moduleGroup.getMainSettings());
+ ArrayList subSets = moduleGroup.getSubSettings();
+ if (subSets != null) {
+ for (PamControlledUnitSettings aSet : subSets) {
+ restoreSettings(aSet);
+ }
+ }
+// exModule.notifyModelChanged(PamController.INITIALIZATION_COMPLETE);
+// if (exModule.getTabPanel() != null) {
+//// exModule.getTabPanel()
+// }
+ }
+ /*
+ * Don't need to call this here since it get's called shortly
+ * from PAMController once all modules are in place.
+ */
+// pamController.notifyModelChanged(PamController.INITIALIZATION_COMPLETE);
+
+ // send out an initialisation complete to help restore settings
+// ArrayList allSettings = settingsGroup.getUnitSettings();
+// for (PamControlledUnitSettings aSet : allSettings) {
+// PamSettings owner = PamSettingManager.getInstance().findSettingsOwner(aSet.getUnitType(), aSet.getUnitName(), null);
+// if (owner == null) {
+// System.out.printf("Cannot find owner for %s, %s, %s\n", aSet.getUnitType(), aSet.getUnitName(), aSet.getOwnerClassName());
+// }
+// else {
+// owner.restoreSettings(aSet);
+// }
+// }
+
+ return true;
+ }
+
+ /**
+ * Find the owner of these settings and send it it's new settings.
+ * @param aSet
+ * @return true if found and set sucessfully.
+ */
+ private boolean restoreSettings(PamControlledUnitSettings aSet) {
+ PamSettings owner = PamSettingManager.getInstance().findSettingsOwner(aSet.getUnitType(), aSet.getUnitName(), null);
+ if (owner == null) {
+ System.out.printf("Cannot find owner for %s, %s, %s\n", aSet.getUnitType(), aSet.getUnitName(), aSet.getOwnerClassName());
+ return false;
+ }
+ else {
+ try {
+ owner.restoreSettings(aSet);
+ }
+ catch (Exception e) {
+ System.out.printf("Exception restoring settings %s, %s, %s\n", aSet.getUnitType(), aSet.getUnitName(), aSet.getOwnerClassName());
+ e.printStackTrace();
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+ /**
+ * Is the module a data store. If it is, we probably won't want to copy over it's settings.
+ * @param controlledUnit PAMGuard module
+ * @return true if it's data output or input.
+ */
+ private boolean isDataStore(PamControlledUnit controlledUnit) {
+ return isDataStore(controlledUnit.getClass());
+ }
+
+ /**
+ * Is the class a data store. If it is, we probably won't want to copy over it's settings.
+ * @param moduleClass module class
+ * @return true if it's data output or input.
+ */
+ private boolean isDataStore(Class extends PamControlledUnit> moduleClass) {
+ //OfflineFileDataStore, DataInputStore
+ if (OfflineDataStore.class.isAssignableFrom(moduleClass)) {
+ return true;
+ }
+ if (DataInputStore.class.isAssignableFrom(moduleClass)) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/PamController/settings/SettingsImport.java b/src/PamController/settings/SettingsImport.java
index 0c52fb31..e5ed64d6 100644
--- a/src/PamController/settings/SettingsImport.java
+++ b/src/PamController/settings/SettingsImport.java
@@ -29,7 +29,10 @@ import PamView.dialog.warn.WarnOnce;
*/
public class SettingsImport {
+ private PamController pamController;
+
public SettingsImport(PamController pamController) {
+ this.pamController = pamController;
}
/**
@@ -116,14 +119,16 @@ public class SettingsImport {
*/
private PamControlledUnit importReplace(SettingsImportGroup importGroup, String replaceModule) {
PamControlledUnitSettings mainSet = importGroup.getMainSettings();
- PamControlledUnit unit = PamController.getInstance().findControlledUnit(mainSet.getUnitType(), replaceModule);
+ UsedModuleInfo importInfo = importGroup.getUsedModuleInfo();
+ PamControlledUnit unit = PamController.getInstance().findControlledUnit(importInfo.getUnitType(), replaceModule);
if (unit == null) {
- System.out.println("Unable to find " + mainSet.getUnitType() + " " + mainSet.getUnitName() + " for settings replacement");
+ System.out.println("Unable to find " + importInfo.getUnitType() + " " + importInfo.getUnitName() + " for settings replacement");
return null;
}
// check we can cast it to PamSettings
- if (PamSettings.class.isAssignableFrom(unit.getClass())) {
+ if (PamSettings.class.isAssignableFrom(unit.getClass()) && mainSet != null) {
try {
+ mainSet.setUnitName(replaceModule);
((PamSettings) unit).restoreSettings(mainSet);
}
catch (Exception e) {
@@ -132,7 +137,7 @@ public class SettingsImport {
System.err.println(e.getMessage());
}
}
- loadSubUnitSettings(importGroup, mainSet.getUnitName());
+ loadSubUnitSettings(importGroup, replaceModule);
return unit;
}
@@ -149,7 +154,15 @@ public class SettingsImport {
}
PamSettingManager setManager = PamSettingManager.getInstance();
for (PamControlledUnitSettings pamSettings:subSets) {
- PamSettings owner = setManager.findSettingsOwner(pamSettings.getUnitType(), unitName, pamSettings.getOwnerClassName());
+ /*
+ * class name in pamSettings is no longer correct, so cannot use pamSettings.getOwnerClassName().
+ * but the classnames of all the sub modules are unknown (and will be different form the unit class name
+ * which can be got from importGroup.getPamModuleInfo().getClassName
+ * so will have to do this only on the unit type and name and hope for no conflicts (catch exception).
+ */
+// PamModuleInfo moduleInfo = importGroup.getPamModuleInfo();
+// String className = moduleInfo.getClassName();
+ PamSettings owner = setManager.findSettingsOwner(pamSettings.getUnitType(), unitName, null);
if (owner == null) {
System.out.println(String.format("Cannot find settings owner for %s %s in current model", pamSettings.getUnitType(), unitName));
continue;
@@ -168,7 +181,8 @@ public class SettingsImport {
private PamControlledUnit importNew(SettingsImportGroup importGroup) {
PamControlledUnitSettings mainSet = importGroup.getMainSettings();
- String moduleName = mainSet.getUnitName();
+ UsedModuleInfo importInfo = importGroup.getUsedModuleInfo();
+ String moduleName = importInfo.unitName;
// check we've got a name that doesnt' exist and replace it if if does.
// int startChar = 0;
@@ -199,11 +213,11 @@ public class SettingsImport {
PamControlledUnit unit = PamController.getInstance().addModule(PamController.getMainFrame(), moduleInfo);
if (unit == null) {
- System.out.println("Unable to find " + mainSet.getUnitType() + " " + mainSet.getUnitName() + " for settings replacement");
+ System.out.println("Unable to find " + importInfo.getUnitType() + " " + importInfo.getUnitName() + " for settings replacement");
return null;
}
// check we can cast it to PamSettings
- if (PamSettings.class.isAssignableFrom(unit.getClass())) {
+ if (PamSettings.class.isAssignableFrom(unit.getClass()) && mainSet != null) {
try {
mainSet.setUnitName(unit.getUnitName()); // need to force the unit name for some modules.
((PamSettings) unit).restoreSettings(mainSet);
@@ -224,7 +238,7 @@ public class SettingsImport {
* @param settings
* @return
*/
- ArrayList organiseSettingsGroups(ArrayList settings) {
+ public ArrayList organiseSettingsGroups(ArrayList settings) {
/**
* this needs rewriting for psfx files which are organised differently. first we need to find
* a list of PAMGuard modules by finding the settings group of the PAMController.
diff --git a/src/PamController/settings/SettingsImportDialog.java b/src/PamController/settings/SettingsImportDialog.java
index 6f6621e6..4241a0cf 100644
--- a/src/PamController/settings/SettingsImportDialog.java
+++ b/src/PamController/settings/SettingsImportDialog.java
@@ -195,12 +195,14 @@ public class SettingsImportDialog extends PamDialog {
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
SettingsImportGroup set = groupedSettings.get(rowIndex);
- PamControlledUnitSettings mainSet = set.getMainSettings();
+// PamControlledUnitSettings mainSet = set.getMainSettings();
switch (columnIndex) {
case 0:
- return mainSet.getUnitType();
+ return set.getUsedModuleInfo().getUnitType();
+// return mainSet.getUnitType();
case 1:
- return mainSet.getUnitName();
+ return set.getUsedModuleInfo().unitName;
+// return mainSet.getUnitName();
case 2:
// return choiceBoxes[rowIndex].getSelectedItem().toString();
return set.getImportChoice().toString();
diff --git a/src/PamController/settings/SettingsImportGroup.java b/src/PamController/settings/SettingsImportGroup.java
index a74a6885..98bf1e4f 100644
--- a/src/PamController/settings/SettingsImportGroup.java
+++ b/src/PamController/settings/SettingsImportGroup.java
@@ -82,8 +82,10 @@ public class SettingsImportGroup {
try {
ownerClass = Class.forName(usedModuleInfo.className);
} catch (ClassNotFoundException e) {
+
+ System.out.println("Unknown class in loaded settings: " + usedModuleInfo.className);
// TODO Auto-generated catch block
- e.printStackTrace();
+// e.printStackTrace();
}
ArrayList existingModules =
PamController.getInstance().findControlledUnits(ownerClass);
diff --git a/src/PamController/settings/output/xml/PamguardXMLWriter.java b/src/PamController/settings/output/xml/PamguardXMLWriter.java
index 6b42c4e7..f74edce0 100644
--- a/src/PamController/settings/output/xml/PamguardXMLWriter.java
+++ b/src/PamController/settings/output/xml/PamguardXMLWriter.java
@@ -29,6 +29,7 @@ import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
import com.sun.javafx.runtime.VersionInfo;
@@ -42,12 +43,14 @@ import PamController.PamguardVersionInfo;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterData;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamCalendar;
import PamUtils.XMLUtils;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import PamguardMVC.PamProcess;
import binaryFileStorage.BinaryStore;
+import tethys.TethysControl;
/**
* Class for writing XML configuration output to a file.
@@ -62,6 +65,8 @@ public class PamguardXMLWriter implements PamSettings {
private static final Set> WRAPPER_TYPES = getWrapperTypes();
private XMLWriterSettings writerSettings = new XMLWriterSettings();
+ private boolean excludeDisplaySettings;
+// private String xmlNameSpace;
private static PamguardXMLWriter singleInstance;
@@ -83,6 +88,19 @@ public class PamguardXMLWriter implements PamSettings {
}
return singleInstance;
}
+
+ /**
+ * Recursively walk the tree and add a namespace to every
+ * single element.
+ * @param doc
+ * @param nameSpace
+ * @return
+ */
+ public boolean addNameSpaceToElements(Document doc, Element el, String nameSpace) {
+// el.setAttributeNS(nameSpace, nameSpace, nameSpace);
+ NamedNodeMap attributes = el.getAttributes();
+ return true;
+ }
/**
* Make a document with the options specified in writerSettings.
@@ -371,6 +389,32 @@ public class PamguardXMLWriter implements PamSettings {
* @return xml content as a a string.
*/
public String getAsString(Document doc) {
+ return getAsString(doc, true);
+// try {
+// DOMSource domSource = new DOMSource(doc);
+// StringWriter writer = new StringWriter();
+// StreamResult result = new StreamResult(writer);
+// TransformerFactory tf = TransformerFactory.newInstance();
+// Transformer transformer = tf.newTransformer();
+// transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+// transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
+//// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+// transformer.transform(domSource, result);
+// return writer.toString();
+// } catch (TransformerException e) {
+// e.printStackTrace();
+// return null;
+// }
+ }
+ /**
+ * Get the xml document as a String.
+ * @param doc xml document
+ * @param indent Indent / format the document.
+ * @return xml content as a a string.
+ */
+ public String getAsString(Document doc, boolean indent) {
try {
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
@@ -380,7 +424,7 @@ public class PamguardXMLWriter implements PamSettings {
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(domSource, result);
return writer.toString();
@@ -411,8 +455,7 @@ public class PamguardXMLWriter implements PamSettings {
* @param pamSettingsUnit
* @return xml element
*/
- private Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit) {
-
+ public Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit) {
int[] settingInds = findSettings(null, pamSettingsUnit.getUnitName());
PamSettings[] settingsObjects = null;
if (settingInds != null) {
@@ -436,7 +479,7 @@ public class PamguardXMLWriter implements PamSettings {
* can be temporary settings objects when writing temporary settings from dialogs.
* @return new XML element.
*/
- private Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit, PamSettings[] toWrite) {
+ public Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit, PamSettings[] toWrite) {
Element moduleData = doc.createElement("MODULE");
moduleData.setAttribute("Java.class", pamSettingsUnit.getClass().getName());
moduleData.setAttribute("UnitType", pamSettingsUnit.getUnitType());
@@ -457,6 +500,9 @@ public class PamguardXMLWriter implements PamSettings {
Element settingEl = doc.createElement("CONFIGURATION");
moduleData.appendChild(settingEl);
for (int i = 0; i < toWrite.length; i++) {
+ if (wantObject(toWrite[i]) == false) {
+ continue;
+ }
Element setEl = writeSettings(doc, toWrite[i], new ArrayList());
if (setEl != null) {
settingEl.appendChild(setEl);
@@ -467,6 +513,32 @@ public class PamguardXMLWriter implements PamSettings {
return moduleData;
}
+ /**
+ * USed by the Tethys writer to avoid writing display settings.
+ * @param pamSettings
+ * @return
+ */
+ private boolean wantObject(PamSettings pamSettings) {
+ if (excludeDisplaySettings == false) {
+ return true;
+ }
+ Object obj = pamSettings.getSettingsReference();
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof ManagedParameters) {
+ ManagedParameters managedParams = (ManagedParameters) obj;
+ PamParameterSet paramSet = managedParams.getParameterSet();
+ if (paramSet == null) {
+ return false;
+ }
+ if (paramSet.getParameterSetType() == ParameterSetType.DISPLAY && excludeDisplaySettings) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Write settings for a settings object, using the standard retreived object
* from the settings.
@@ -478,6 +550,14 @@ public class PamguardXMLWriter implements PamSettings {
private Element writeSettings(Document doc, PamSettings pamSettings, ArrayList objectHierarchy) {
return writeSettings(doc, pamSettings, pamSettings.getSettingsReference(), objectHierarchy);
}
+
+ public Document writeOneObject(Object data) {
+ Document doc = XMLUtils.createBlankDoc();
+ Element el = doc.createElement("Settings");
+ Element newel = writeObjectData(doc, el, data, new ArrayList());
+ doc.appendChild(newel);
+ return doc;
+ }
/**
* Write settings using an object of choice instead of the standard one from PamSettings.
@@ -489,6 +569,7 @@ public class PamguardXMLWriter implements PamSettings {
* @return
*/
private Element writeSettings(Document doc, PamSettings pamSettings, Object data, ArrayList objectHierarchy) {
+
Element el = doc.createElement("SETTINGS");
el.setAttribute("Type", pamSettings.getUnitType());
el.setAttribute("Name", pamSettings.getUnitName());
@@ -500,10 +581,13 @@ public class PamguardXMLWriter implements PamSettings {
return el;
}
- private Element writeObjectData(Document doc, Element el, Object data, ArrayList objectHierarchy) {
+ public Element writeObjectData(Document doc, Element el, Object data, ArrayList objectHierarchy) {
if (data == null) {
return null;
}
+ if (objectHierarchy == null) {
+ objectHierarchy = new ArrayList<>();
+ }
if (objectHierarchy.contains(data)) {
// just write the reference, but nothing else or we'll end up in an infinite loop of objects.
Element e = doc.createElement("Object");
@@ -525,8 +609,10 @@ public class PamguardXMLWriter implements PamSettings {
if (parameterSet == null) {
return null;
}
-
- objectHierarchy.add(data);
+
+ if (objectHierarchy != null) {
+ objectHierarchy.add(data);
+ }
for (PamParameterData pamParam:parameterSet.getParameterCollection()) {
try {
Object paramData = pamParam.getData();
@@ -765,9 +851,10 @@ public class PamguardXMLWriter implements PamSettings {
processData.setAttribute("Name", process.getProcessName());
PamDataBlock source = process.getParentDataBlock();
if (source != null) {
- Element inputEl = doc.createElement("Input");
- inputEl.setAttribute("Name", source.getLongDataName());
- inputEl.setAttribute("Channels", String.format("0x%X", source.getChannelMap()));
+ Element inputEl = source.getDataBlockXML(doc);
+// Element inputEl = doc.createElement("Input");
+// inputEl.setAttribute("Name", source.getLongDataName());
+// inputEl.setAttribute("Channels", String.format("0x%X", source.getChannelMap()));
processData.appendChild(inputEl);
}
int nOut = process.getNumOutputDataBlocks();
@@ -798,7 +885,16 @@ public class PamguardXMLWriter implements PamSettings {
*/
private int[] findSettings(String type, String name) {
if (settingsSets == null) {
- return null;
+ makeSettingsList();
+ if (settingsSets == null) {
+ return null;
+ }
+ }
+ if (usedSettingsSets == null) {
+ usedSettingsSets = new boolean[settingsSets.size()];
+ }
+ else if (usedSettingsSets.length < settingsSets.size()) {
+ usedSettingsSets = Arrays.copyOf(usedSettingsSets, settingsSets.size());
}
int[] found = new int[settingsSets.size()];
int nFound = 0;
@@ -818,7 +914,7 @@ public class PamguardXMLWriter implements PamSettings {
return Arrays.copyOf(found, nFound);
}
- private ArrayList makeSettingsList() {
+ public ArrayList makeSettingsList() {
PamSettingManager settingsManager = PamSettingManager.getInstance();
settingsSets = settingsManager.getOwners();
if (settingsSets == null) {
@@ -850,6 +946,14 @@ public class PamguardXMLWriter implements PamSettings {
return doc;
}
+ /**
+ * Is this element a writable type ? Basically, this means
+ * that it's a primitive of some sort. Otherwise it's
+ * probably an object and may even be a list in which case
+ * it will need treating differently.
+ * @param clazz
+ * @return
+ */
public static boolean isWritableType(Class> clazz)
{
if (clazz.isEnum()) return true;
@@ -940,5 +1044,23 @@ public class PamguardXMLWriter implements PamSettings {
return true;
}
+ /**
+ * @return the excludeDisplaySettings
+ */
+ public boolean isExcludeDisplaySettings() {
+ return excludeDisplaySettings;
+ }
+
+ /**
+ * @param excludeDisplaySettings the excludeDisplaySettings to set
+ */
+ public void setExcludeDisplaySettings(boolean excludeDisplaySettings) {
+ this.excludeDisplaySettings = excludeDisplaySettings;
+ }
+
+// public void setStaticNameSpace(String xmlNameSpace) {
+// this.xmlNameSpace = xmlNameSpace;
+// }
+
}
diff --git a/src/PamController/settings/output/xml/XMLWriterSettings.java b/src/PamController/settings/output/xml/XMLWriterSettings.java
index 8e5d0969..dcd60b83 100644
--- a/src/PamController/settings/output/xml/XMLWriterSettings.java
+++ b/src/PamController/settings/output/xml/XMLWriterSettings.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class XMLWriterSettings implements Serializable, Cloneable, ManagedParameters {
@@ -34,7 +35,7 @@ public class XMLWriterSettings implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/PamController/soundMedium/GlobalMediumParams.java b/src/PamController/soundMedium/GlobalMediumParams.java
index 0a52ac83..8bf10f27 100644
--- a/src/PamController/soundMedium/GlobalMediumParams.java
+++ b/src/PamController/soundMedium/GlobalMediumParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamController.soundMedium.GlobalMedium.SoundMedium;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Stores parameters for the current medium.
@@ -41,7 +42,7 @@ public class GlobalMediumParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/PamModel/PamModel.java b/src/PamModel/PamModel.java
index bc475091..4c0e0c1a 100644
--- a/src/PamModel/PamModel.java
+++ b/src/PamModel/PamModel.java
@@ -23,6 +23,7 @@ package PamModel;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.Serializable;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
@@ -44,11 +45,15 @@ import whistlesAndMoans.AbstractWhistleDataUnit;
import fftManager.FFTDataUnit;
import fftManager.PamFFTControl;
import group3dlocaliser.Group3DLocaliserControl;
+import metadata.MetaDataContol;
import meygenturbine.MeygenTurbine;
import printscreen.PrintScreenControl;
import rockBlock.RockBlockControl;
+import tethys.TethysControl;
import turbineops.TurbineOperationControl;
import GPS.GpsDataUnit;
+import Map.MapController;
+import Map.gridbaselayer.GridbaseControl;
import NMEA.NMEADataUnit;
import PamController.PamControlledUnitSettings;
import PamController.PamController;
@@ -62,6 +67,7 @@ import PamguardMVC.PamDataBlock;
import analogarraysensor.ArraySensorControl;
import backupmanager.BackupManager;
import beamformer.continuous.BeamFormerControl;
+import beamformer.localiser.BeamFormLocaliserControl;
import bearinglocaliser.BearingLocaliserControl;
import binaryFileStorage.SecondaryBinaryStore;
import cepstrum.CepstrumControl;
@@ -454,6 +460,20 @@ final public class PamModel implements PamSettings {
mi.setToolTipText("Manage automated data backups");
mi.setModulesMenuGroup(utilitiesGroup);
mi.setMaxNumber(1);
+
+
+// mi = PamModuleInfo.registerControlledUnit(MetaDataContol.class.getName(), MetaDataContol.unitType);
+// mi.setToolTipText("Project Meta Data");
+// mi.setModulesMenuGroup(utilitiesGroup);
+// mi.setMaxNumber(1);
+
+ if (isViewer) {
+ mi = PamModuleInfo.registerControlledUnit(TethysControl.class.getName(), TethysControl.defaultName);
+ mi.setToolTipText("Interface to Tethys Database");
+ mi.setModulesMenuGroup(utilitiesGroup);
+ mi.setMaxNumber(1);
+ mi.setHidden(SMRUEnable.isEnable() == false);
+ }
/*
* ************* End Utilities Group *******************
@@ -928,14 +948,17 @@ final public class PamModel implements PamSettings {
}
- /* (non-Javadoc)
- * @see PamModel.PamModelInterface#startModel()
+
+
+ /**
+ * Add any remaining REQUIRED modules.
+ * this get's called after the PamController has loaded it's main settings.
+ * So at this point, go through all the PamModuleInfo's and check that
+ * all have at least the minimum number required
+ * @return true
*/
public synchronized boolean startModel() {
/*
- * this get's called after the PamController has loaded it's main settings.
- * So at this point, go through all the PamModuleInfo's and check that
- * all have at least the minimum number required
*/
PamSettingManager.getInstance().registerSettings(this);
@@ -952,11 +975,11 @@ final public class PamModel implements PamSettings {
// writeModuleList();
- return false;
+ return true;
}
/**
- * Really just debu goutput to make a list of all modules ...
+ * Really just debug output to make a list of all modules ...
*/
private void writeModuleList() {
ArrayList moduleInfoList = PamModuleInfo.getModuleList();
@@ -1063,7 +1086,7 @@ final public class PamModel implements PamSettings {
// clear the current list
pluginList.clear();
daqList.clear();
-
+
/*
* If developing a new PAMPlugin in eclipse, the easiest way to do it is to make a new
* Eclipse project for your plugin code. Within that project, copy this PamModel class
@@ -1078,6 +1101,8 @@ final public class PamModel implements PamSettings {
* When you export the code for your plugin to a jar file, remember to NOT inlcude the copy of
* PamModel !
*/
+
+// pluginList.add(new MorlaisWP1aPlugin());
// Load up whatever default classloader was used to create this class. Must use the same classloader
// for all plugins, or else we will not be able to create proper dependencies between them or be able
@@ -1145,11 +1170,30 @@ final public class PamModel implements PamSettings {
// to add that URL to the default classloader path.
URL newURL = jarList.get(i).toURI().toURL();
+ // original method
+// Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+// method.setAccessible(true);
+// method.invoke(cl, newURL);
+
+ // first fix attempt - create a brand new URLClassLoader. As expected, we get a ClassCastException when trying
+ // to load the parameters so we can't save params using this method
+// URL[] newURLArray = new URL[1];
+// newURLArray[0] = newURL;
+// cl = new URLClassLoader(newURLArray);
// second attempt - custom class loader with the system app loader specified as the parent. Loads controlled unit, but
// as before it doesn't load the parameters
classLoader.addURL(newURL);
+ // third attempt
+// Class> genericClass = cl.getClass();
+// Method method = genericClass.getSuperclass().getDeclaredMethod("addURL", new Class[] {URL.class});
+// method.setAccessible(true);
+// method.invoke(cl, new Object[] {newURL});
+
+
+
+
// Save the name of the class to the global pluginBeingLoaded variable, and load the class.
this.setPluginBeingLoaded(className);
// Class c = cl.loadClass(className);
@@ -1171,13 +1215,15 @@ final public class PamModel implements PamSettings {
if (intf[j].getName().equals("PamModel.PamPluginInterface")) {
// create an instance of the interface class.
- PamPluginInterface pf = (PamPluginInterface) c.newInstance();
+ Constructor constructor = c.getDeclaredConstructor(null);
+ PamPluginInterface pf = (PamPluginInterface) constructor.newInstance(null);
if (getPluginBeingLoaded()==null) {
continue;
}
// Let the user know which valid plugins have been found
- System.out.println(" Creating instance of " + pf.getDefaultName() + ": " + pf.getClassName());
+ System.out.printf(" Loading plugin interface for %s : %s version %s\n",
+ pf.getDefaultName(), pf.getClassName(), pf.getVersion());
if (getPluginBeingLoaded()==null) {
continue;
}
@@ -1193,7 +1239,7 @@ final public class PamModel implements PamSettings {
pluginList.add(pf); // add it to the list
} else {
- System.out.println(" Error: "+pf.getDefaultName()+" cannot run in this mode. Skipping module.");
+ System.out.println(" Error: " + pf.getDefaultName()+" cannot run in this mode. Skipping module.");
}
if (getPluginBeingLoaded()==null) {
continue;
@@ -1202,12 +1248,16 @@ final public class PamModel implements PamSettings {
// now check for interfaces that implement DaqSystemInterface
if (intf[j].getName().equals("Acquisition.DaqSystemInterface")) {
- DaqSystemInterface pf = (DaqSystemInterface) c.newInstance(); // create an instance of the interface class
+ Constructor constructor = c.getDeclaredConstructor(null);
+ DaqSystemInterface pf = (DaqSystemInterface) constructor.newInstance(null);
+// DaqSystemInterface pf = (DaqSystemInterface) c.newInstance(); // create an instance of the interface class
if (getPluginBeingLoaded()==null) {
continue;
}
-
- System.out.println(" Creating instance of " + pf.getDefaultName() + ": " + className);
+
+ System.out.printf(" Loading daq plugin interface for %s version %s\n",
+ pf.getDefaultName(), pf.getVersion());
+// System.out.println(" Creating instance of " + pf.getDefaultName() + ": " + className);
if (getPluginBeingLoaded()==null) {
continue;
}
@@ -1230,8 +1280,9 @@ final public class PamModel implements PamSettings {
"for help." +
"This plug-in will not be available for loading";
String help = null;
- int ans = WarnOnce.showWarning(PamController.getInstance().getGuiFrameManager().getFrame(0), title, msg, WarnOnce.WARNING_MESSAGE, help, e1);
+ int ans = WarnOnce.showWarning(PamController.getMainFrame(), title, msg, WarnOnce.WARNING_MESSAGE, help, e1);
System.err.println("Exception while loading " + className);
+ System.err.println(e1.getMessage());
continue;
}
}
@@ -1244,7 +1295,7 @@ final public class PamModel implements PamSettings {
"for help.
" +
"This plug-in will not be available for loading";
String help = null;
- int ans = WarnOnce.showWarning(PamController.getInstance().getGuiFrameManager().getFrame(0), title, msg, WarnOnce.WARNING_MESSAGE, help, ex);
+ int ans = WarnOnce.showWarning(PamController.getMainFrame(), title, msg, WarnOnce.WARNING_MESSAGE, help, ex);
System.err.println("Exception while loading " + jarList.get(i).getName());
continue;
}
@@ -1269,7 +1320,7 @@ final public class PamModel implements PamSettings {
// instantiate the plugin control class using the custom class loader
try {
-// File classFile = new File(pf.getJarFile());
+ File classFile = new File(pf.getJarFile());
//URLClassLoader cl = new URLClassLoader(new URL[]{classFile.toURI().toURL()});
// mi = PamModuleInfo.registerControlledUnit(pf.getClassName(), pf.getDescription(),cl);
mi = PamModuleInfo.registerControlledUnit(pf.getClassName(), pf.getDescription(),classLoader);
@@ -1335,7 +1386,7 @@ final public class PamModel implements PamSettings {
"for help.
" +
"This plug-in will not be available for loading";
String help = null;
- int ans = WarnOnce.showWarning(PamController.getInstance().getGuiFrameManager().getFrame(0), title, msg, WarnOnce.WARNING_MESSAGE, help, e1);
+ int ans = WarnOnce.showWarning(PamController.getMainFrame(), title, msg, WarnOnce.WARNING_MESSAGE, help, e1);
System.err.println("Exception while loading " + pf.getDefaultName());
pluginList.remove(pf);
continue;
diff --git a/src/PamModel/PamModelSettings.java b/src/PamModel/PamModelSettings.java
index 9e4b0632..667747b8 100644
--- a/src/PamModel/PamModelSettings.java
+++ b/src/PamModel/PamModelSettings.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class PamModelSettings implements Cloneable, Serializable, ManagedParameters {
@@ -74,7 +75,7 @@ public class PamModelSettings implements Cloneable, Serializable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/PamModel/parametermanager/PamParameterData.java b/src/PamModel/parametermanager/PamParameterData.java
index a15a3c15..79944a90 100644
--- a/src/PamModel/parametermanager/PamParameterData.java
+++ b/src/PamModel/parametermanager/PamParameterData.java
@@ -34,6 +34,11 @@ abstract public class PamParameterData {
*/
private String postTitle;
+ /**
+ * field length for automatic dialogs.
+ */
+ private int fieldLength;
+
/**
* @param parentObject
@@ -45,6 +50,21 @@ abstract public class PamParameterData {
this.field = field;
}
+ /**
+ * @param parentObject
+ * @param field
+ * @param shortName
+ * @param toolTip
+ * @param fieldLength length of text in automatic dialogs.
+ */
+ public PamParameterData(Object parentObject, Field field, String shortName, String toolTip, int fieldLength) {
+ super();
+ this.field = field;
+ this.shortName = shortName;
+ this.toolTip = toolTip;
+ this.fieldLength = fieldLength;
+ }
+
/**
* @param parentObject
* @param field
@@ -58,7 +78,6 @@ abstract public class PamParameterData {
this.toolTip = toolTip;
}
-
/**
* @param shortName the shortName to set
*/
@@ -66,6 +85,20 @@ abstract public class PamParameterData {
this.shortName = shortName;
}
+ /**
+ * Set info about a parameter
+ * @param shortName short name, e.g. to use in a dialog
+ * @param postTitle post title, e.g. text coming after a data entry field in a dialog
+ * @param toolTip tool tip to display over the component in a dialog.
+ * @param fieldLength length of text in automatic dialogs.
+ */
+ public void setInfo(String shortName, String postTitle, String toolTip, int fieldLength) {
+ this.shortName = shortName;
+ this.postTitle = postTitle;
+ this.toolTip = toolTip;
+ this.fieldLength = fieldLength;
+ }
+
/**
* Set info about a parameter
* @param shortName short name, e.g. to use in a dialog
@@ -136,6 +169,9 @@ abstract public class PamParameterData {
* @return a short name for the field, suitable for use in dialogs.
*/
public String getShortName() {
+ if (shortName == null) {
+ return getFieldName();
+ }
return shortName;
}
@@ -166,5 +202,19 @@ abstract public class PamParameterData {
return String.format("Param %s class %s", getFieldName(), getDataClass());
}
+ /**
+ * @return the fieldLength
+ */
+ public int getFieldLength() {
+ return fieldLength;
+ }
+
+ /**
+ * @param fieldLength the fieldLength to set
+ */
+ public void setFieldLength(int fieldLength) {
+ this.fieldLength = fieldLength;
+ }
+
}
diff --git a/src/PamModel/parametermanager/PamParameterDataGetter.java b/src/PamModel/parametermanager/PamParameterDataGetter.java
index 3947f2dc..9a3e99b0 100644
--- a/src/PamModel/parametermanager/PamParameterDataGetter.java
+++ b/src/PamModel/parametermanager/PamParameterDataGetter.java
@@ -59,9 +59,12 @@ public class PamParameterDataGetter extends PrivatePamParameterData {
if (setter == null) {
return false;
}
+ // need to convert the type
+ Object convObj = convertStringType(data);
try {
- setter.invoke(getParentObject(), data);
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ Object parentObj = getParentObject();
+ setter.invoke(parentObj, convObj);
+ } catch (InvocationTargetException e) {
e.printStackTrace();
return false;
}
diff --git a/src/PamModel/parametermanager/PamParameterSet.java b/src/PamModel/parametermanager/PamParameterSet.java
index 751f3d27..2425b2e7 100644
--- a/src/PamModel/parametermanager/PamParameterSet.java
+++ b/src/PamModel/parametermanager/PamParameterSet.java
@@ -10,7 +10,6 @@ import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
-import binaryFileStorage.BinaryStoreSettings;
/**
* Description of the parameters within a class. Primarily holds a list
@@ -29,6 +28,9 @@ public class PamParameterSet {
private static boolean printDebug = false;
+ public enum ParameterSetType {DETECTOR, DISPLAY};
+
+ private ParameterSetType parameterSetType;
/**
* Standard modifiers to exclude. This is important for many classes which will tend to
* do crazy things such as incorporate ALL of their final fields, e.g. when a Color
@@ -55,8 +57,21 @@ public class PamParameterSet {
* in the STANDARD_MODIFIER_EXCLUSIONS list (FINAL or STATIC).
* @return Created parameter set.
*/
+ @Deprecated
public static PamParameterSet autoGenerate(Object parentObject) {
- return autoGenerate(parentObject, STANDARD_MODIFIER_EXCLUSIONS);
+ return autoGenerate(parentObject, ParameterSetType.DETECTOR);
+ }
+ /**
+ * Automatically generate a parameter set for a class. Will include all public fields and
+ * any private or protected fields for which a getter can be found that has a similar enough name
+ * @param parentObject class to generate description for. Exception is anything that's listed
+ * in the STANDARD_MODIFIER_EXCLUSIONS list (FINAL or STATIC).
+ * @return Created parameter set.
+ */
+ public static PamParameterSet autoGenerate(Object parentObject, ParameterSetType parameterSetType) {
+ PamParameterSet paramSet = autoGenerate(parentObject, STANDARD_MODIFIER_EXCLUSIONS);
+ paramSet.setParameterSetType(parameterSetType);
+ return paramSet;
}
/**
@@ -286,4 +301,19 @@ public class PamParameterSet {
public PamParameterData removeParameterData(String paramName) {
return parameterDatas.remove(paramName);
}
+
+ /**
+ * @return the parameterSetType
+ */
+ public ParameterSetType getParameterSetType() {
+ return parameterSetType;
+ }
+
+ /**
+ * @param parameterSetType the parameterSetType to set
+ */
+ public void setParameterSetType(ParameterSetType parameterSetType) {
+ this.parameterSetType = parameterSetType;
+ }
+
}
diff --git a/src/PamModel/parametermanager/ParameterSetManager.java b/src/PamModel/parametermanager/ParameterSetManager.java
new file mode 100644
index 00000000..3420a7c4
--- /dev/null
+++ b/src/PamModel/parametermanager/ParameterSetManager.java
@@ -0,0 +1,73 @@
+package PamModel.parametermanager;
+
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JMenuItem;
+
+import PamModel.parametermanager.swing.ManagedParameterDialog;
+import generalDatabase.parameterstore.ParameterDatabaseStore;
+
+/**
+ * Just about everything giving overall control of some managed parameters.
+ * May be a bit too specific on first cut and need to be abstracted.
+ * Testing on 'Deployment' data.
+ * @author dg50
+ *
+ * @param
+ */
+public class ParameterSetManager {
+
+ private T managedParams;
+ private String name;
+
+ public ParameterSetManager(T defaultParams, String name) {
+ setManagedParams(defaultParams);
+ this.name = name;
+// if (managedParams == null) {
+// managedParams = new T();
+// }
+ }
+
+ /**
+ * @return the managedParams
+ */
+ public T getManagedParams() {
+ return managedParams;
+ }
+
+ /**
+ * @param managedParams the managedParams to set
+ */
+ public void setManagedParams(T managedParams) {
+ this.managedParams = managedParams;
+ }
+
+ public JMenuItem getMenuItem(Window parent) {
+ if (managedParams == null) {
+ return null;
+ }
+ JMenuItem menuItem = new JMenuItem(name + " ...");
+ menuItem.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ showDialog(parent);
+ }
+ });
+
+ return menuItem;
+ }
+
+ protected void showDialog(Window parent) {
+ ManagedParameterDialog dialog = new ManagedParameterDialog(parent, name, managedParams);
+ T newParams = dialog.showDialog(parent, name, managedParams);
+
+ if (newParams != null) {
+ ParameterDatabaseStore paramDatabase = new ParameterDatabaseStore("MetaData");
+ paramDatabase.saveParameterSet(newParams);
+ }
+ }
+
+}
diff --git a/src/PamModel/parametermanager/PrivatePamParameterData.java b/src/PamModel/parametermanager/PrivatePamParameterData.java
index e3fed547..6b29d9cd 100644
--- a/src/PamModel/parametermanager/PrivatePamParameterData.java
+++ b/src/PamModel/parametermanager/PrivatePamParameterData.java
@@ -1,6 +1,7 @@
package PamModel.parametermanager;
import java.lang.reflect.Field;
+import java.lang.reflect.Type;
/**
* Abstract instance of PamParameterDataInterface which implements everything
@@ -36,9 +37,48 @@ public abstract class PrivatePamParameterData extends PamParameterData {
* This should really be implemented in every concrete class, but no time to do that now. Aim to delete
* this function here, then go through and implement everywhere ...
*/
- return false;
+// return false;
+ Object convData = convertStringType(data);
+ getField().set(this, convData);
+
+ return true;
}
+ /**
+ * convert a string type to a different type appropriate for the field in
+ * question.
+ * @param value
+ * @return
+ */
+ public Object convertStringType(Object value) {
+ if (value == null) {
+ return null;
+ }
+ if (value instanceof String == false) {
+ return value;
+ }
+ String str = (String) value;
+ Type type = getField().getGenericType();
+ Class> cls = getField().getType();
+ String clsName = cls.getName();
+ switch (clsName) {
+ case "int":
+ case "Integer":
+ return Integer.valueOf(str);
+ case "double":
+ case "Double":
+ return Double.valueOf(str);
+ case "float":
+ case "Float":
+ return Float.valueOf(str);
+ case "short":
+ case "Short":
+ return Short.valueOf(str);
+
+ }
+
+ return value;
+ }
}
diff --git a/src/PamModel/parametermanager/swing/ManagedParameterDialog.java b/src/PamModel/parametermanager/swing/ManagedParameterDialog.java
new file mode 100644
index 00000000..9a3aa995
--- /dev/null
+++ b/src/PamModel/parametermanager/swing/ManagedParameterDialog.java
@@ -0,0 +1,49 @@
+package PamModel.parametermanager.swing;
+
+import java.awt.Window;
+
+import PamModel.parametermanager.ManagedParameters;
+import PamView.dialog.PamDialog;
+
+public class ManagedParameterDialog extends PamDialog {
+
+ private T params;
+
+ private ManagedParameterPanel parameterPanel;
+
+ public ManagedParameterDialog(Window parentFrame, String title, T params) {
+ super(parentFrame, title, false);
+ parameterPanel = new ManagedParameterPanel(params);
+ setDialogComponent(parameterPanel.getPanel());
+ }
+
+ public T showDialog(Window parentFrame, String title, T parameters) {
+// ManagedParameterDialog dialog = new ManagedParameterDialog<>(parentFrame, title, parameters);
+ setParams(parameters);
+ setVisible(true);
+
+ return params;
+ }
+
+ private void setParams(T params) {
+ this.params = params;
+ this.parameterPanel.setParams(params);
+ }
+
+ @Override
+ public boolean getParams() {
+ return parameterPanel.getParams(params);
+ }
+
+ @Override
+ public void cancelButtonPressed() {
+ params = null;
+ }
+
+ @Override
+ public void restoreDefaultSettings() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/PamModel/parametermanager/swing/ManagedParameterPanel.java b/src/PamModel/parametermanager/swing/ManagedParameterPanel.java
new file mode 100644
index 00000000..416bef77
--- /dev/null
+++ b/src/PamModel/parametermanager/swing/ManagedParameterPanel.java
@@ -0,0 +1,149 @@
+package PamModel.parametermanager.swing;
+
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.Collection;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.text.JTextComponent;
+
+import PamModel.parametermanager.FieldNotFoundException;
+import PamModel.parametermanager.ManagedParameters;
+import PamModel.parametermanager.PamParameterData;
+import PamModel.parametermanager.PamParameterSet;
+import PamView.dialog.PamDialog;
+import PamView.dialog.PamGridBagContraints;
+
+public class ManagedParameterPanel {
+
+ private JPanel mainPanel;
+ private Collection parameterSet;
+
+ private static final int DEFAULT_TEXT_LENGTH = 6;
+ private static final int MAX_SINGLE_LINE_LENGTH = 40;
+
+ private JTextComponent[] textComponents;
+
+ public ManagedParameterPanel(T parameterExample) {
+
+ mainPanel = new JPanel(new GridBagLayout());
+ GridBagConstraints c = new PamGridBagContraints();
+ PamParameterSet exampleSet = parameterExample.getParameterSet();
+ parameterSet = exampleSet.getParameterCollection();
+ int n = parameterSet.size();
+ textComponents = new JTextComponent[n];
+ int i = 0;
+ for (PamParameterData paramData : parameterSet) {
+ textComponents[i] = createComponent(paramData);
+ c.gridx = 0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.NORTHEAST;
+ mainPanel.add(new JLabel(paramData.getShortName(), JLabel.RIGHT), c);
+ c.gridx++;
+ if (textComponents[i] instanceof JTextArea) {
+ c.fill = GridBagConstraints.HORIZONTAL;
+ }
+ else {
+ c.fill = GridBagConstraints.NONE;
+ }
+ c.anchor = GridBagConstraints.WEST;
+ mainPanel.add(textComponents[i], c);
+
+ textComponents[i].setToolTipText(getTipText(paramData));
+
+ c.gridy++;
+ i++;
+ }
+ }
+
+ private String getTipText(PamParameterData paramData) {
+ String tip = paramData.getToolTip();
+ if (tip != null) {
+ return tip;
+ }
+ else {
+ return paramData.getFieldName();
+ }
+ }
+
+ private JTextComponent createComponent(PamParameterData paramData) {
+ int textLen = paramData.getFieldLength();
+ if (textLen == 0) {
+ textLen = DEFAULT_TEXT_LENGTH;
+ }
+ if (textLen <= MAX_SINGLE_LINE_LENGTH) {
+ return new JTextField(textLen);
+ }
+ else {
+ JTextField dummyField = new JTextField(2);
+// dummyField.getBorder().
+ JTextArea textArea = new JTextArea(textLen/MAX_SINGLE_LINE_LENGTH+1, MAX_SINGLE_LINE_LENGTH);
+ textArea.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
+ return textArea;
+ }
+ }
+
+ public JComponent getPanel() {
+ return mainPanel;
+ }
+
+ public void setParams(T params) {
+ int i = 0;
+ PamParameterData newParamData = null;
+ Object data = null;
+ for (PamParameterData paramData : this.parameterSet) {
+ // find the parameter in the new parameters (parameterSet is just a formatting placeholder)
+ try {
+ newParamData = params.getParameterSet().findParameterData(paramData.getFieldName());
+ } catch (FieldNotFoundException e) {
+ e.printStackTrace();
+ }
+ try {
+ data = newParamData.getData();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ if (data != null) {
+ textComponents[i].setText(data.toString());
+ }
+ else {
+ textComponents[i].setText(null);
+ }
+ i++;
+ }
+ }
+
+ public boolean getParams(T params) {
+ int i = 0;
+ PamParameterData newParamData = null;
+ Object data = null;
+ for (PamParameterData paramData : this.parameterSet) {
+ // find the parameter in the new parameters (parameterSet is just a formatting placeholder)
+ try {
+ newParamData = params.getParameterSet().findParameterData(paramData.getFieldName());
+ } catch (FieldNotFoundException e) {
+ e.printStackTrace();
+ }
+ String txt = textComponents[i].getText();
+ try {
+ newParamData.setData(txt);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ String msg = "Invalid parameter. Data type should be " + paramData.getField().getType().getName();
+ return PamDialog.showWarning(null, newParamData.getShortName(), msg);
+ }
+
+ i++;
+ }
+
+ return true;
+ }
+
+}
diff --git a/src/PamUtils/Coordinate3d.java b/src/PamUtils/Coordinate3d.java
index 57a859f4..a8b6d156 100644
--- a/src/PamUtils/Coordinate3d.java
+++ b/src/PamUtils/Coordinate3d.java
@@ -26,6 +26,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Class definition for a x,y coordinate number type.
@@ -168,7 +169,7 @@ public class Coordinate3d implements Serializable , Cloneable, PamCoordinate, Ma
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/PamUtils/LatLong.java b/src/PamUtils/LatLong.java
index 6b8f9df9..6d465ee6 100644
--- a/src/PamUtils/LatLong.java
+++ b/src/PamUtils/LatLong.java
@@ -15,6 +15,7 @@ import java.text.NumberFormat;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.PamConstants;
import net.sf.geographiclib.Geodesic;
import net.sf.geographiclib.PolygonArea;
@@ -833,7 +834,7 @@ public class LatLong implements Serializable, Cloneable, Transferable, PamCoordi
*/
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("height");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/PamUtils/PamCalendar.java b/src/PamUtils/PamCalendar.java
index 79e2fd8e..2e1388f9 100644
--- a/src/PamUtils/PamCalendar.java
+++ b/src/PamUtils/PamCalendar.java
@@ -47,10 +47,7 @@ public class PamCalendar {
public static TimeZone defaultTimeZone = TimeZone.getTimeZone("UTC");
- /*
- * Not used: all now handled in PamCalendar.
- */
-// private static TimeZone localTimeZone = defaultTimeZone;// TimeZone.getDefault();
+ private static TimeZone localTimeZone = defaultTimeZone;// TimeZone.getDefault();
public static final long millisPerDay = 1000L*24L*3600L;
@@ -63,7 +60,7 @@ public class PamCalendar {
private static boolean soundFile;
/**
- * time from the start of the file to the current moment.
+ * time from the start of the file to the currentmoment.
* This is updated every time data re read from the file, so is
* accurate to about 1/10 second.
* For accurate timing within detectors, always try to use sample number
@@ -180,44 +177,8 @@ public class PamCalendar {
public static TimeZone getDisplayTimeZone(boolean useLocal) {
// return TimeZone.getTimeZone("UTC");
- return useLocal ? CalendarControl.getInstance().getChosenTimeZone() : defaultTimeZone;
-// return useLocal ? localTimeZone : defaultTimeZone;
- }
-
- /**
- * Get the display time zone offset in milliseconds.
- * @param useLocal
- * @return
- */
- public static long getDisplayTimeZoneOffest(boolean useLocal) {
- TimeZone tz = getDisplayTimeZone(useLocal);
- return tz.getOffset(getTimeInMillis());
- }
-
- /**
- * Get a short string describing the time zone. This should be less than
- * 10 characters. So if the full name of the TZ is long, then write it
- * in the format "UTC+..."
- * @param useLocal
- * @return
- */
- public static String getShortDisplayTimeZoneString(boolean useLocal) {
- TimeZone tz = getDisplayTimeZone(useLocal);
- String str = tz.getDisplayName();
- str = CalendarControl.getInstance().getTZCode(true);
- if (str.length() <= 10) {
- return str;
- }
- // otherwise make up a string.
- long offset = getDisplayTimeZoneOffest(useLocal) / 1000;
- boolean isInt = offset % 3600 == 0;
- if (isInt) {
- str = String.format("UTC%+d", offset/3600);
- }
- else {
- str = String.format("UTC%+3.1f", (double) offset/3600.);
- }
- return str;
+// return useLocal ? CalendarControl.getInstance().getChosenTimeZone() : defaultTimeZone;
+ return useLocal ? localTimeZone : defaultTimeZone;
}
public static String formatDateTime(Date date) {
@@ -430,13 +391,8 @@ public class PamCalendar {
public static String formatDBStyleTime(long timeInMillis, boolean showMillis, boolean useLocal) {
Calendar c = Calendar.getInstance();
- TimeZone tz = getDisplayTimeZone(useLocal);
-// if (tz != null) {
-// long offs = tz.getOffset(timeInMillis);
-// timeInMillis += tz.getOffset(timeInMillis);
-// }
c.setTimeInMillis(timeInMillis);
- c.setTimeZone(tz);
+ c.setTimeZone(getDisplayTimeZone(useLocal));
DateFormat df;
if (showMillis) {
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -444,7 +400,7 @@ public class PamCalendar {
else {
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
- df.setTimeZone(tz);
+ df.setTimeZone(getDisplayTimeZone(useLocal));
Date d = c.getTime();
// return String.format("%tY-% implements PamWorkWrapper result) {
oldFileList = result;
+ sortFiles(result);
fileListUser.newFileList(result);
}
diff --git a/src/PamView/ColourArray.java b/src/PamView/ColourArray.java
index edbdb61d..51f6c531 100644
--- a/src/PamView/ColourArray.java
+++ b/src/PamView/ColourArray.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* A series of functions for creating arrays of colours
@@ -410,7 +411,7 @@ public class ColourArray implements Cloneable, Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/PamView/GeneralProjector.java b/src/PamView/GeneralProjector.java
index b9aa21e4..5329d10c 100644
--- a/src/PamView/GeneralProjector.java
+++ b/src/PamView/GeneralProjector.java
@@ -265,6 +265,11 @@ public abstract class GeneralProjector {
JComponent toolTipComponent;
+ /**
+ * Gets an adapter that can provide tooltips automatically based on plotted data units.
+ * @param component
+ * @return
+ */
public MouseHoverAdapter getMouseHoverAdapter(JComponent component) {
ToolTipManager tt = ToolTipManager.sharedInstance();
tt.registerComponent(component);
@@ -384,7 +389,9 @@ public abstract class GeneralProjector {
}
String hintText = dataBlock.getHoverText(this, hoveredDataUnit, hoverData.get(unitIndex).getAmbiguity());
- if (hintText == null) return null;
+ if (hintText == null) {
+ return null;
+ }
// System.out.println(hintText);
return hintText;
}
diff --git a/src/PamView/GroupedSourceParameters.java b/src/PamView/GroupedSourceParameters.java
index f26cdafd..fb0b7509 100644
--- a/src/PamView/GroupedSourceParameters.java
+++ b/src/PamView/GroupedSourceParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamUtils;
import PamView.dialog.GroupedSourcePanel;
@@ -210,7 +211,7 @@ public class GroupedSourceParameters implements Serializable, Cloneable, Managed
*/
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/PamView/GuiFrameSettings.java b/src/PamView/GuiFrameSettings.java
index d367c1e3..3445c790 100644
--- a/src/PamView/GuiFrameSettings.java
+++ b/src/PamView/GuiFrameSettings.java
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import PamController.PamControlledUnit;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
/**
@@ -55,7 +56,7 @@ public class GuiFrameSettings implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("unitFrameInfo");
ps.put(new PrivatePamParameterData(this, field) {
@@ -89,7 +90,7 @@ public class GuiFrameSettings implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("guiFrame");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/PamView/PamGui.java b/src/PamView/PamGui.java
index 0ebec8a3..ac51f1bc 100644
--- a/src/PamView/PamGui.java
+++ b/src/PamView/PamGui.java
@@ -61,6 +61,7 @@ import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
+import javax.swing.JRootPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
@@ -73,6 +74,7 @@ import javax.swing.event.MenuListener;
import Acquisition.DaqSystemInterface;
import annotation.tasks.AnnotationManager;
+import metadata.MetaDataContol;
import performanceTests.PerformanceDialog;
import tipOfTheDay.TipOfTheDayManager;
import Array.ArrayManager;
@@ -601,17 +603,17 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
fileMenu.add(menuItem);
}
- if (SMRUEnable.isEnable()) {
- menuItem = new JMenuItem("Import PAMGuard Modules");
- menuItem.setToolTipText("Import module settings from a different PAMGuard configuration (psfx files only");
- menuItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- importSettings();
- }
- });
- fileMenu.add(menuItem);
- }
+ // if (SMRUEnable.isEnable()) {
+ menuItem = new JMenuItem("Import PAMGuard Modules");
+ menuItem.setToolTipText("Import module settings from a different PAMGuard configuration (psfx files only");
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ importSettings();
+ }
+ });
+ fileMenu.add(menuItem);
+// }
fileMenu.addSeparator();
@@ -761,6 +763,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
//for changing "hydrophones" to "microphone" and vice versa if medium changes.
menu.addMenuListener(new SettingsMenuListener());
+ menu.add(MetaDataContol.getMetaDataControl().createMenu(frame));
menu.addSeparator();
@@ -1265,7 +1268,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
class menuPamStart implements ActionListener {
public void actionPerformed(ActionEvent ev){
- pamControllerInterface.pamStart();
+ pamControllerInterface.manualStart();
}
}
@@ -1282,7 +1285,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
class menuPamStop implements ActionListener {
public void actionPerformed(ActionEvent ev){
- pamControllerInterface.pamStop();
+ pamControllerInterface.manualStop();
// enableLoggingMenu();
}
}
@@ -1666,10 +1669,10 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
protected void getGuiParameters() {
guiParameters.extendedState = frame.getExtendedState();
guiParameters.state = frame.getState();
- if (guiParameters.state != Frame.MAXIMIZED_BOTH) {
+// if (guiParameters.state != Frame.MAXIMIZED_BOTH) {
guiParameters.size = frame.getSize();
guiParameters.bounds = frame.getBounds();
- }
+// }
}
/**
@@ -1984,6 +1987,30 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
public PamTabbedPane getTabbedPane() {
return this.mainTab;
}
+
+ /**
+ * find a parent window for a JComponent. This can be useful in
+ * finding windows to open child dialogs when the object holding
+ * the component may not have a direct reference back to it's dialog.
+ * @param component any Swing component
+ * @return parent Window (or frame) if it can be found
+ */
+ public static Window findComponentWindow(JComponent component) {
+ if (component == null) {
+ return null;
+ }
+ JRootPane root = component.getRootPane();
+ if (root == null) {
+ return null;
+ }
+ Container rootP = root.getParent();
+ if (rootP instanceof Window) {
+ return (Window) rootP;
+ }
+ else {
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/PamView/PamSymbol.java b/src/PamView/PamSymbol.java
index 00c471f6..2a4f4061 100644
--- a/src/PamView/PamSymbol.java
+++ b/src/PamView/PamSymbol.java
@@ -38,6 +38,7 @@ import javax.swing.JPanel;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.PamColors.PamColor;
import PamView.symbol.SymbolData;
@@ -808,7 +809,7 @@ public class PamSymbol extends PamSymbolBase implements Serializable, Icon, Clon
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/PamView/dialog/warn/WarnOnce.java b/src/PamView/dialog/warn/WarnOnce.java
index 93ed4618..cd7ad08d 100644
--- a/src/PamView/dialog/warn/WarnOnce.java
+++ b/src/PamView/dialog/warn/WarnOnce.java
@@ -48,6 +48,7 @@ public class WarnOnce implements PamSettings {
int ans = showWarning(parent, "Warning Messages", "Show all PAMGuard warning messages", WarnOnce.OK_CANCEL_OPTION);
if (ans == WarnOnce.CANCEL_OPTION) return;
singleInstance.warnOnceList.clearList();
+ singleInstance.showThisSess.clear();
}
@Override
diff --git a/src/PamView/panel/SplitPanePositionData.java b/src/PamView/panel/SplitPanePositionData.java
new file mode 100644
index 00000000..b7207e6e
--- /dev/null
+++ b/src/PamView/panel/SplitPanePositionData.java
@@ -0,0 +1,62 @@
+package PamView.panel;
+
+import java.io.Serializable;
+
+public class SplitPanePositionData implements Serializable {
+
+
+ public static final long serialVersionUID = 1L;
+ private int position;
+ private double propPosition;
+ private int height;
+
+
+ public SplitPanePositionData(int position, double propPosition, int height) {
+ super();
+ this.position = position;
+ this.setHeight(height);
+ this.setPropPosition(propPosition);
+ }
+
+ /**
+ * @return the position
+ */
+ public int getPosition() {
+ return position;
+ }
+
+ /**
+ * @param position the position to set
+ */
+ public void setPosition(int position) {
+ this.position = position;
+ }
+
+ /**
+ * @return the propPosition
+ */
+ public double getPropPosition() {
+ return propPosition;
+ }
+
+ /**
+ * @param propPosition the propPosition to set
+ */
+ public void setPropPosition(double propPosition) {
+ this.propPosition = propPosition;
+ }
+
+ /**
+ * @return the height
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * @param height the height to set
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+}
diff --git a/src/PamView/panel/SplitPanePositioner.java b/src/PamView/panel/SplitPanePositioner.java
new file mode 100644
index 00000000..f6bc4190
--- /dev/null
+++ b/src/PamView/panel/SplitPanePositioner.java
@@ -0,0 +1,95 @@
+package PamView.panel;
+
+import java.io.Serializable;
+
+import javax.swing.JSplitPane;
+import javax.swing.SwingUtilities;
+
+import PamController.PamControlledUnitSettings;
+import PamController.PamSettingManager;
+import PamController.PamSettings;
+
+/**
+ * Class that will remember and reset the position of a split pane. Any split pane.
+ * Just call this constructor with a unique name and the splitPane and a default
+ * between 0 and 1 and it will register itself automatically with PamSettings.
+ * @author dg50
+ *
+ */
+public class SplitPanePositioner implements PamSettings {
+
+ private static final String unitType = "Split Pane Position";
+
+ private String unitName;
+
+ private JSplitPane splitPane;
+
+ /**
+ * Constructor for split pane positioner. Just call this constructor for each
+ * split pane, then forget about it. This will have been registered with
+ * PamSettings and will handle everything, restoring the split pane position
+ * when PAMGuard is restarted.
+ * @param unitName A unique name for the split pane.
+ * @param splitPane reference to an existing split pane.
+ * @param proportionalDefault default position (0 < position < 1).
+ */
+ public SplitPanePositioner(String unitName, JSplitPane splitPane, double proportionalDefault) {
+ super();
+ this.splitPane = splitPane;
+ this.unitName = unitName;
+ boolean exists = PamSettingManager.getInstance().registerSettings(this);
+ if (exists == false) {
+ // use the default
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ splitPane.setDividerLocation(proportionalDefault);
+ }
+ });
+ }
+ }
+
+ @Override
+ public String getUnitName() {
+ return unitName;
+ }
+
+ @Override
+ public String getUnitType() {
+ return unitType;
+ }
+
+ @Override
+ public Serializable getSettingsReference() {
+// System.out.printf("Save split position %s as %d out of %d\n", unitName, splitPane.getDividerLocation(), splitPane.getHeight());
+ double propPosition = (double) splitPane.getDividerLocation() / (double) splitPane.getHeight();
+ SplitPanePositionData posData = new SplitPanePositionData(splitPane.getDividerLocation(), propPosition, splitPane.getHeight());
+ return posData;
+ }
+
+ @Override
+ public long getSettingsVersion() {
+ return SplitPanePositionData.serialVersionUID;
+ }
+
+ @Override
+ public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
+
+ SplitPanePositionData posData = (SplitPanePositionData) pamControlledUnitSettings.getSettings();
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ int newPos = posData.getPosition() + splitPane.getHeight() - posData.getHeight();
+// System.out.printf("Set split %s position to %d or %3.3f of %d\n", unitName,
+// posData.getPosition(), posData.getPropPosition(), splitPane.getHeight());
+ splitPane.setDividerLocation(posData.getPosition());
+ }
+ });
+ return true;
+ }
+
+
+
+}
diff --git a/src/PamView/paneloverlay/OverlayDataInfo.java b/src/PamView/paneloverlay/OverlayDataInfo.java
index 3c3ed86b..fd590d82 100644
--- a/src/PamView/paneloverlay/OverlayDataInfo.java
+++ b/src/PamView/paneloverlay/OverlayDataInfo.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class OverlayDataInfo implements Serializable, Cloneable, ManagedParameters {
@@ -31,7 +32,7 @@ public class OverlayDataInfo implements Serializable, Cloneable, ManagedParamete
*/
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java b/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java
index f6c8d446..ae081fc1 100644
--- a/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java
+++ b/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java
@@ -6,6 +6,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamguardMVC.PamDataBlock;
@@ -73,7 +74,7 @@ public class MarkDataSelectorParams implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("overlayChoices");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/PamView/symbol/ManagedSymbolData.java b/src/PamView/symbol/ManagedSymbolData.java
index 23bb555d..19789f61 100644
--- a/src/PamView/symbol/ManagedSymbolData.java
+++ b/src/PamView/symbol/ManagedSymbolData.java
@@ -3,7 +3,11 @@ package PamView.symbol;
import java.io.Serializable;
import java.util.Hashtable;
-public class ManagedSymbolData implements Cloneable, Serializable {
+import PamModel.parametermanager.ManagedParameters;
+import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
+
+public class ManagedSymbolData implements Cloneable, Serializable, ManagedParameters {
public static final long serialVersionUID = 1L;
@@ -34,5 +38,10 @@ public class ManagedSymbolData implements Cloneable, Serializable {
return symbolOptions;
}
+ @Override
+ public PamParameterSet getParameterSet() {
+ return PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
+ }
+
}
diff --git a/src/PamView/wizard/PamWizard.java b/src/PamView/wizard/PamWizard.java
new file mode 100644
index 00000000..9ba67e01
--- /dev/null
+++ b/src/PamView/wizard/PamWizard.java
@@ -0,0 +1,160 @@
+package PamView.wizard;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Component;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import PamView.dialog.PamDialog;
+import tethys.swing.export.ExportStreamInfoPanel;
+import tethys.swing.export.ExportWizardCard;
+
+abstract public class PamWizard extends PamDialog {
+
+ private static final long serialVersionUID = 1L;
+
+ private JPanel cardPanel;
+
+ private CardLayout cardLayout;
+
+ private JPanel mainPanel;
+
+ private JButton prevButton;
+
+ private ArrayList wizardCards = new ArrayList();
+
+ public PamWizard(Window parentFrame, String title) {
+ super(parentFrame, title, false);
+
+ cardLayout = new CardLayout();
+ mainPanel = new JPanel(new BorderLayout());
+ cardPanel = new JPanel(cardLayout);
+ mainPanel.add(BorderLayout.CENTER, cardPanel);
+
+ setDialogComponent(mainPanel);
+
+ getOkButton().setText("Finish");
+ prevButton = new JButton("Previous");
+ getButtonPanel().add(prevButton, 0);
+ prevButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ previousButton();
+ }
+ });
+
+ setResizable(true);
+ }
+
+ public void addCard(PamWizardCard wizPanel) {
+ cardPanel.add(wizPanel, wizPanel.getTitle());
+ wizardCards.add(wizPanel);
+ }
+
+ /**
+ * Get the main panel. This is the main dialog panel and uses a borderlayout
+ * with the cards in the CENTER of the panel. Additional information panels
+ * (generally fixed and not changing with the dialog) can be added NORTH, SOUTH, WEST and EAST.
+ * @return main Panel.
+ */
+ public JPanel getMainPanel() {
+ return mainPanel;
+ }
+
+ /**
+ * Called when 'previous' button is clicked.
+ */
+ protected void previousButton() {
+ cardLayout.previous(cardPanel);
+ enableControls();
+ }
+
+ public void enableControls() {
+ int iCard = getCardIndex();
+ prevButton.setEnabled(iCard > 0);
+ boolean isLast = iCard == wizardCards.size()-1;
+// getOkButton().setEnabled(!isLast);
+ getOkButton().setText(isLast ? "Finish" : "Next");
+ }
+
+ private boolean checkCurrentCard() {
+ int iCard = getCardIndex();
+ if (iCard < 0) {
+ return true;
+ }
+ return getCardParams(wizardCards.get(iCard));
+ }
+
+ abstract public void setCardParams(PamWizardCard wizardCard);
+
+ abstract public boolean getCardParams(PamWizardCard wizardCard);
+
+ public int getCardIndex() {
+ for (int i = 0; i < cardPanel.getComponentCount(); i++) {
+ Component component = cardPanel.getComponent(i);
+ if (component.isVisible()) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public JButton getPreviousButton() {
+ return prevButton;
+ }
+
+ public void setParams() {
+ for (PamWizardCard wizCard : wizardCards) {
+ setCardParams(wizCard);
+ }
+ enableControls();
+ }
+
+ @Override
+ public boolean getParams() {
+ /**
+ * This is the OK button, so we need to NOT return OK, which would close the
+ * dialog until we're on the last card.
+ */
+ if (checkCurrentCard() == false) {
+ return false;
+ }
+ int iCard = getCardIndex();
+ if (iCard < wizardCards.size()-1) {
+ cardLayout.next(cardPanel);
+ enableControls();
+ return false;
+ }
+
+ return true;
+ }
+
+
+
+ @Override
+ public void restoreDefaultSettings() {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * Move to the first card in the stack
+ */
+ public void moveFirst() {
+ cardLayout.first(cardPanel);
+ }
+
+ /**
+ * Move to the last card in the stack
+ */
+ public void moveLast() {
+ cardLayout.last(cardPanel);
+ }
+
+}
diff --git a/src/PamView/wizard/PamWizardCard.java b/src/PamView/wizard/PamWizardCard.java
new file mode 100644
index 00000000..7d4fa88c
--- /dev/null
+++ b/src/PamView/wizard/PamWizardCard.java
@@ -0,0 +1,43 @@
+package PamView.wizard;
+
+import javax.swing.JPanel;
+
+
+/**
+ * Base class for PAMGuard wizard cards.
+ * @author dg50
+ *
+ * @param class type for parameters to set and get.
+ */
+abstract public class PamWizardCard extends JPanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private String title;
+
+ private PamWizard pamWizard;
+
+ /**
+ * @param title
+ */
+ public PamWizardCard(PamWizard pamWizard, String title) {
+ this.pamWizard = pamWizard;
+ this.title = title;
+ }
+
+ public abstract boolean getParams(T cardParams);
+
+ public abstract void setParams(T cardParams);
+
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * @return the pamWizard
+ */
+ public PamWizard getPamWizard() {
+ return pamWizard;
+ }
+
+}
diff --git a/src/PamguardMVC/AcousticDataBlock.java b/src/PamguardMVC/AcousticDataBlock.java
index ec7477c1..f7fb5c8e 100644
--- a/src/PamguardMVC/AcousticDataBlock.java
+++ b/src/PamguardMVC/AcousticDataBlock.java
@@ -1,5 +1,8 @@
package PamguardMVC;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
import PamController.PamControllerInterface;
import PamguardMVC.nanotime.NanosFromSamples;
@@ -90,5 +93,12 @@ abstract public class AcousticDataBlock extends PamD
return parentSourceData;
}
+ @Override
+ public Element getDataBlockXML(Document doc) {
+ Element el = super.getDataBlockXML(doc);
+ el.setAttribute("SampleRate", String.format("%3.1f", getSampleRate()));
+ return el;
+ }
+
}
diff --git a/src/PamguardMVC/DataAutomation.java b/src/PamguardMVC/DataAutomation.java
new file mode 100644
index 00000000..cd424c60
--- /dev/null
+++ b/src/PamguardMVC/DataAutomation.java
@@ -0,0 +1,29 @@
+package PamguardMVC;
+
+/**
+ * @author dg50
+ * Levels of automation for the various datas in PAMGuard.
+ * Should be used within DataAutomationInfo to perhaps combine with other info in the future.
+ *
+ */
+public enum DataAutomation {
+
+ AUTOMATIC, MANUAL, MANUALANDAUTOMATIC;
+
+ @Override
+ public String toString() {
+ switch (this) {
+ case AUTOMATIC:
+ return "Automatic";
+ case MANUAL:
+ return "Manual";
+ case MANUALANDAUTOMATIC:
+ return "Manual and automatic";
+ default:
+ break;
+
+ }
+ return null;
+ }
+
+}
diff --git a/src/PamguardMVC/DataAutomationInfo.java b/src/PamguardMVC/DataAutomationInfo.java
new file mode 100644
index 00000000..42c7e42d
--- /dev/null
+++ b/src/PamguardMVC/DataAutomationInfo.java
@@ -0,0 +1,44 @@
+package PamguardMVC;
+
+/**
+ * Returned by datablocks, though default is null, to give information on how
+ * automatic the process was.
+ * @author dg50
+ *
+ */
+public class DataAutomationInfo {
+
+
+ private DataAutomation automation;
+
+ /**
+ * @param automation
+ */
+ public DataAutomationInfo(DataAutomation automation) {
+ this.setAutomation(automation);
+ }
+
+ /**
+ * @return the automation
+ */
+ public DataAutomation getAutomation() {
+ return automation;
+ }
+
+ /**
+ * @param automation the automation to set
+ */
+ public void setAutomation(DataAutomation automation) {
+ this.automation = automation;
+ }
+
+ @Override
+ public String toString() {
+ if (automation == null) {
+ return "Unknown data automation";
+ }
+ return automation.toString();
+ }
+
+
+}
diff --git a/src/PamguardMVC/DataBlock2D.java b/src/PamguardMVC/DataBlock2D.java
index beae1e15..89eb0ec9 100644
--- a/src/PamguardMVC/DataBlock2D.java
+++ b/src/PamguardMVC/DataBlock2D.java
@@ -1,5 +1,8 @@
package PamguardMVC;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
import dataPlotsFX.data.DataTypeInfo;
abstract public class DataBlock2D extends AcousticDataBlock {
@@ -39,4 +42,18 @@ abstract public class DataBlock2D extends AcousticDat
* @return data type information.
*/
abstract public DataTypeInfo getScaleInfo();
+
+ public Element getDataBlockXML(Document doc) {
+ Element el = super.getDataBlockXML(doc);
+ DataTypeInfo dti = getScaleInfo();
+ if (dti != null) {
+ if (dti.dataType != null) {
+ el.setAttribute("DataType", dti.dataType.toString());
+ }
+ if (dti.dataUnits != null) {
+ el.setAttribute("DataUnits", dti.dataUnits.toString());
+ }
+ }
+ return el;
+ }
}
diff --git a/src/PamguardMVC/PamDataBlock.java b/src/PamguardMVC/PamDataBlock.java
index 97bd709c..3bcce61a 100644
--- a/src/PamguardMVC/PamDataBlock.java
+++ b/src/PamguardMVC/PamDataBlock.java
@@ -44,10 +44,16 @@ import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import org.springframework.core.GenericTypeResolver;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import Acquisition.AcquisitionControl;
import Acquisition.AcquisitionProcess;
import pamScrollSystem.ViewLoadObserver;
+import tethys.TethysControl;
+import tethys.pamdata.AutoTethysProvider;
+import tethys.pamdata.TethysDataProvider;
+import tethys.species.DataBlockSpeciesManager;
import dataGram.DatagramProvider;
import dataMap.BespokeDataMapGraphic;
import dataMap.OfflineDataMap;
@@ -62,6 +68,7 @@ import PamController.PamController;
import PamController.PamControllerInterface;
import PamDetection.LocContents;
import PamDetection.LocalisationInfo;
+import PamDetection.PamDetection;
import PamUtils.PamCalendar;
import PamUtils.PamUtils;
import PamView.symbol.PamSymbolManager;
@@ -69,8 +76,10 @@ import PamguardMVC.background.BackgroundDataBlock;
import PamguardMVC.background.BackgroundManager;
import PamguardMVC.dataOffline.OfflineDataLoadInfo;
import PamguardMVC.dataOffline.OfflineDataLoading;
+import PamguardMVC.dataSelector.DataSelectParams;
import PamguardMVC.dataSelector.DataSelector;
import PamguardMVC.dataSelector.DataSelectorCreator;
+import PamguardMVC.dataSelector.DataSelectorSettings;
import PamguardMVC.dataSelector.NullDataSelectorCreator;
import PamguardMVC.datamenus.DataMenuParent;
import PamguardMVC.nanotime.NanoTimeCalculator;
@@ -2155,7 +2164,7 @@ public class PamDataBlock extends PamObservable {
*/
@Override
public String toString() {
- return getDataName();
+ return getLongDataName();
}
/**
@@ -2833,7 +2842,7 @@ public class PamDataBlock extends PamObservable {
* @return temporary copy of the data
*/
public ArrayList getDataCopy(long t1, long t2, boolean assumeOrder, DataSelector dataSelector) {
- if (dataSelector == null) {
+ if (dataSelector == null || dataSelector.getParams().getCombinationFlag() == DataSelectParams.DATA_SELECT_DISABLE) {
return getDataCopy(t1, t2, assumeOrder);
}
else {
@@ -2865,6 +2874,7 @@ public class PamDataBlock extends PamObservable {
private SQLLogging logging;
private JSONObjectDataSource jsonDataSource;
+
public Vector getProcessAnnotations() {
return processAannotations;
@@ -3074,6 +3084,34 @@ public class PamDataBlock extends PamObservable {
public SQLLogging getLogging() {
return logging;
}
+
+ /**
+ * Gets a data provider for Tethys. These will probably need
+ * to be bespoke, but for now will autogenerate based on the SQLLogging information.
+ * @return the tethysDataProvider
+ */
+ public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) {
+ return null;
+ }
+
+ /**
+ * Get the level of automation employed by the generation of these data.
+ * Should ideally be completed for everything providing data to Tethys.
+ * @return level of automation for this data block.
+ */
+ public DataAutomationInfo getDataAutomationInfo() {
+ return null;
+ }
+
+ /**
+ * Get information about species types that may occur within this data
+ * block. Primarily for conversion into Tethys compatible data, but may
+ * prove to have other uses.
+ * @return Types of species information available within this datablock.
+ */
+ public DataBlockSpeciesManager getDatablockSpeciesManager() {
+ return null;
+ }
final public boolean getCanLog() {
return (logging != null);
@@ -4229,4 +4267,42 @@ public class PamDataBlock extends PamObservable {
public void setBackgroundManager(BackgroundManager backgroundManager) {
this.backgroundManager = backgroundManager;
}
+
+ /**
+ * Get a brief summary of datablock to include in XML descriptions.
+ * Basic output is very simple. Expect other datablock to extend this by
+ * adding additional attributes.
+ * @param doc
+ * @return XML element with description of data.
+ */
+ public Element getDataBlockXML(Document doc) {
+ Element inputEl = doc.createElement("Input");
+ if (getParentProcess() != null && getParentProcess().getPamControlledUnit() != null) {
+ PamControlledUnit pcu = getParentProcess().getPamControlledUnit();
+ inputEl.setAttribute("ModuleType", pcu.getUnitType());
+ inputEl.setAttribute("ModuleName", pcu.getUnitName());
+ }
+ inputEl.setAttribute("Name", getLongDataName());
+ inputEl.setAttribute("Channels", String.format("0x%X", getChannelMap()));
+ return inputEl;
+ }
+
+ /**
+ * Look in every data block, particularly threaded ones, and dump
+ * the buffer status. This will have to go via PamProcess so that
+ * additional information can be added from any processes that
+ * hold additional data in other internal buffers.
+ * @param message Message to print prior to dumping buffers for debug.
+ * @param sayEmpties dump info even if a buffer is empty (otherwise, only ones that have stuff still)
+ */
+ public void dumpBufferStatus(String message, boolean sayEmpties) {
+ int nObs = countObservers();
+ for (int i = 0; i < nObs; i++) {
+ PamObserver obs = getPamObserver(i);
+ if (obs instanceof ThreadedObserver) {
+ ThreadedObserver tObs = (ThreadedObserver) obs;
+ tObs.dumpBufferStatus(message, sayEmpties);
+ }
+ }
+ }
}
diff --git a/src/PamguardMVC/PamDataUnit.java b/src/PamguardMVC/PamDataUnit.java
index 3295381f..8630a7d1 100644
--- a/src/PamguardMVC/PamDataUnit.java
+++ b/src/PamguardMVC/PamDataUnit.java
@@ -974,8 +974,13 @@ abstract public class PamDataUnit
// add frequency and amplitude information
- str += "Frequency: " + FrequencyFormat.formatFrequencyRange(this.getFrequency(), true) + " ";
- str += String.format("Amplitude: %3.1fdB ", getAmplitudeDB());
+ double[] frequency = this.getFrequency();
+ if (frequency != null) {
+ str += "Frequency: " + FrequencyFormat.formatFrequencyRange(this.getFrequency(), true) + " ";
+ }
+ if (getAmplitudeDB() != 0) {
+ str += String.format("Amplitude: %3.1fdB ", getAmplitudeDB());
+ }
if (getSignalSPL() != null) {
str += String.format("SPL: %3.1fdBre1uPa ",linAmplitudeToDB(getSignalSPL()));
}
diff --git a/src/PamguardMVC/PamObservable.java b/src/PamguardMVC/PamObservable.java
index 0d693c99..46d149d9 100644
--- a/src/PamguardMVC/PamObservable.java
+++ b/src/PamguardMVC/PamObservable.java
@@ -208,6 +208,14 @@ public class PamObservable {//extends PanelOverlayDraw {
if (System.currentTimeMillis() - startTime > timeOutms) {
// have taken too long, so return that we've failed.
System.out.println("Wait timeout in threaded observer");
+ // and clear everything that's left.
+ for (int i = 0; i < pamObservers.size(); i++) {
+ pamObserver = pamObservers.get(i);
+ if (pamObserver.getClass() == ThreadedObserver.class) {
+ threadedObserver = (ThreadedObserver) pamObserver;
+ threadedObserver.clearEverything();
+ }
+ }
return false;
}
try {
diff --git a/src/PamguardMVC/PamProcess.java b/src/PamguardMVC/PamProcess.java
index 3d43f05b..e6321207 100644
--- a/src/PamguardMVC/PamProcess.java
+++ b/src/PamguardMVC/PamProcess.java
@@ -767,7 +767,7 @@ abstract public class PamProcess implements PamObserver, ProcessAnnotator {
}
});
- private int lastSourceNotificationType;
+ private volatile int lastSourceNotificationType;
private Object lastSourceNotificationObject;
@@ -1065,4 +1065,24 @@ abstract public class PamProcess implements PamObserver, ProcessAnnotator {
return lastSourceNotificationObject;
}
+ /**
+ * Say the status of any buffers, particularly in output buffers of
+ * data blocks, but can add bespoke info for other internal buffers
+ * for some processes.
+ * @param message
+ * @param sayEmpties include info even if a buffer is empty.
+ */
+ public void dumpBufferStatus(String message, boolean sayEmpties) {
+ ArrayList outputs = getOutputDataBlocks();
+ try {
+ for (PamDataBlock output : outputs) {
+ output.dumpBufferStatus(message, sayEmpties);
+ }
+ }
+ catch (Exception e) {
+ System.err.println("Error dumping buffer data from process " + getProcessName());
+ e.printStackTrace();
+ }
+ }
+
}
diff --git a/src/PamguardMVC/PamRawDataBlock.java b/src/PamguardMVC/PamRawDataBlock.java
index eda2bb30..f1246242 100644
--- a/src/PamguardMVC/PamRawDataBlock.java
+++ b/src/PamguardMVC/PamRawDataBlock.java
@@ -145,6 +145,17 @@ public class PamRawDataBlock extends AcousticDataBlock {
}
}
+ /**
+ * Reset data integrity checking counters.
+ */
+ public void reset() {
+ prevChannelSample = new long[PamConstants.MAX_CHANNELS];
+ summaryTotals = new double[PamConstants.MAX_CHANNELS];
+ summaryTotals2 = new double[PamConstants.MAX_CHANNELS];
+ summaryMaxVal = new double[PamConstants.MAX_CHANNELS];
+ summaryCount = new int[PamConstants.MAX_CHANNELS];
+ }
+
@Override
public void addPamData(RawDataUnit pamDataUnit) {
/*
diff --git a/src/PamguardMVC/RawDataDisplayOptions.java b/src/PamguardMVC/RawDataDisplayOptions.java
index 9ed8355c..6ff49562 100644
--- a/src/PamguardMVC/RawDataDisplayOptions.java
+++ b/src/PamguardMVC/RawDataDisplayOptions.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class RawDataDisplayOptions implements Serializable, Cloneable, ManagedParameters {
@@ -13,7 +14,7 @@ public class RawDataDisplayOptions implements Serializable, Cloneable, ManagedPa
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/PamguardMVC/RawDataUnavailableException.java b/src/PamguardMVC/RawDataUnavailableException.java
index 581f981d..37e4275a 100644
--- a/src/PamguardMVC/RawDataUnavailableException.java
+++ b/src/PamguardMVC/RawDataUnavailableException.java
@@ -61,7 +61,7 @@ public class RawDataUnavailableException extends Exception {
return String.format("Samples %d length %d requested from %s have not yet arrived",
startSample, duration, rawDataBlock.getDataName());
case INVALID_CHANNEL_LIST:
- return String.format("Samples %d length %d requested from %s do not contain the reqeusted channels %s",
+ return String.format("Samples %d length %d requested from %s do not contain the reqeusted channels",
startSample, duration, rawDataBlock.getDataName());
case NEGATIVE_DURATION:
return String.format("Negative data duration request for %d samples" , duration);
diff --git a/src/PamguardMVC/ThreadedObserver.java b/src/PamguardMVC/ThreadedObserver.java
index 806cf607..83713af0 100644
--- a/src/PamguardMVC/ThreadedObserver.java
+++ b/src/PamguardMVC/ThreadedObserver.java
@@ -444,6 +444,7 @@ public class ThreadedObserver implements PamObserver {
else {
emptyRead = false;
int lc=0;
+ ObservedObject observedObject;
while (!toDoList.isEmpty()) {
// if (stopFlag) {
@@ -458,11 +459,21 @@ public class ThreadedObserver implements PamObserver {
// get the first object, send it for processing and then remove from the list
- ObservedObject observedObject = toDoList.get(0);
- performAction(observedObject);
synchronized(synchLock) {
- toDoList.remove(0);
+ if (toDoList.size() > 0) {
+ observedObject = toDoList.remove(0);
+ }
+ else {
+ break;
+ }
}
+ // need to do this bit outside of the synch block.
+ performAction(observedObject);
+// synchronized(synchLock) {
+// if (toDoList.size() > 0) { // list may have been cleared during a shut down.
+// toDoList.remove(0);
+// }
+// }
}
}
}
@@ -525,4 +536,21 @@ public class ThreadedObserver implements PamObserver {
}
}
+
+ public void clearEverything() {
+ synchronized (synchLock) {
+ System.out.printf("Clearing %d objects from todo list in %s\n", toDoList.size(), singleThreadObserver.getObserverName());
+ toDoList.clear();
+ }
+ }
+
+ public void dumpBufferStatus(String message, boolean sayEmpties) {
+ int n = toDoList.size();
+ if (sayEmpties == false && n == 0) {
+ return;
+ }
+ String name = singleThreadObserver.getObserverName();
+ System.out.printf("Threaded observer %s has %d objects in queue\n", name, n);
+ }
+
}
diff --git a/src/PamguardMVC/blockprocess/PamBlockParams.java b/src/PamguardMVC/blockprocess/PamBlockParams.java
index 249d98e1..aaaed713 100644
--- a/src/PamguardMVC/blockprocess/PamBlockParams.java
+++ b/src/PamguardMVC/blockprocess/PamBlockParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import gpl.GPLParameters;
/**
@@ -44,7 +45,7 @@ public class PamBlockParams implements Cloneable, Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/PamguardMVC/dataSelector/CompoundParams.java b/src/PamguardMVC/dataSelector/CompoundParams.java
index d63f1957..6f80972e 100644
--- a/src/PamguardMVC/dataSelector/CompoundParams.java
+++ b/src/PamguardMVC/dataSelector/CompoundParams.java
@@ -19,4 +19,10 @@ public class CompoundParams extends DataSelectParams {
public DataSelectParams getSelectorParams(DataSelector dataSelector) {
return selectorParams.get(dataSelector.getLongSelectorName());
}
+
+ @Override
+ public int getCombinationFlag() {
+ return DATA_SELECT_AND;
+ }
+
}
diff --git a/src/PamguardMVC/dataSelector/DataSelectParams.java b/src/PamguardMVC/dataSelector/DataSelectParams.java
index da0f5e74..0d4af3fb 100644
--- a/src/PamguardMVC/dataSelector/DataSelectParams.java
+++ b/src/PamguardMVC/dataSelector/DataSelectParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Data select parameters.
@@ -53,7 +54,7 @@ abstract public class DataSelectParams implements Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/PamguardMVC/dataSelector/DataSelector.java b/src/PamguardMVC/dataSelector/DataSelector.java
index 0503479f..b033976c 100644
--- a/src/PamguardMVC/dataSelector/DataSelector.java
+++ b/src/PamguardMVC/dataSelector/DataSelector.java
@@ -9,7 +9,10 @@ import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenuItem;
+import org.w3c.dom.Document;
+
import PamController.PamController;
+import PamController.settings.output.xml.PamguardXMLWriter;
import PamView.dialog.PamDialogPanel;
import PamView.dialog.SettingsButton;
import PamguardMVC.PamDataBlock;
@@ -39,7 +42,7 @@ public abstract class DataSelector {
private String selectorTitle;
private boolean allowScores;
-
+
/**
* Create a data selector for a DataBlock. If allowScores is
* true, then the selector MAY (but may not) offer a more complicated
@@ -104,18 +107,8 @@ public abstract class DataSelector {
if (parentFrame == null) {
parentFrame = PamController.getMainFrame();
}
- Window localWin = parentFrame;
- DataSelectorChangeListener localChangeListener = changeListener;
JMenuItem menuItem = new JMenuItem("Data selection ...");
- menuItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- boolean ok = showSelectDialog(localWin);
- if (ok && changeListener != null) {
- changeListener.selectorChange(DataSelector.this);
- }
- }
- });
+ menuItem.addActionListener(new ShowSettingsButton(parentFrame, changeListener));
return menuItem;
}
@@ -129,6 +122,24 @@ public abstract class DataSelector {
return ok;
}
+ /**
+ * Get descriptive text about the data selector which can be
+ * added to dialogs and other information panels.
+ * @return descriptive text. Default is a xml dump of params.
+ */
+ public String getDescription() {
+ if (getParams() == null) {
+ return null;
+ }
+ PamguardXMLWriter xmlWriter = PamguardXMLWriter.getXMLWriter();
+ Document doc = xmlWriter.writeOneObject(getParams());
+ if (doc != null) {
+ String str = xmlWriter.getAsString(doc, true);
+ return str;
+ }
+ return null;
+ }
+
/**
* Score a PAMDataUnit. this is used in preference
* to a boolean select function so that the user can add different
@@ -228,25 +239,40 @@ public abstract class DataSelector {
* @param parentWindow
*/
public JButton getDialogButton(Window parentWindow) {
+ return getDialogButton(parentWindow, null);
+ }
+ /**
+ * Create a settings type button that can be inserted into a
+ * larger dialog.
+ * @param parentWindow
+ */
+
+ public JButton getDialogButton(Window parentWindow, DataSelectorChangeListener changeListener) {
JButton button = new SettingsButton();
- button.addActionListener(new ShowSettingsButton(parentWindow));
+ button.addActionListener(new ShowSettingsButton(parentWindow, changeListener));
button.setToolTipText("Data selection options for " + getSelectorTitle());
return button;
}
private class ShowSettingsButton implements ActionListener {
private Window parentWindow;
+ private DataSelectorChangeListener changeListener;
/**
* @param parentWindow
+ * @param changeListener
*/
- public ShowSettingsButton(Window parentWindow) {
+ public ShowSettingsButton(Window parentWindow, DataSelectorChangeListener changeListener) {
super();
this.parentWindow = parentWindow;
+ this.changeListener = changeListener;
}
@Override
public void actionPerformed(ActionEvent e) {
- showSelectDialog(parentWindow);
+ boolean ok = showSelectDialog(parentWindow);
+ if (ok && changeListener != null) {
+ changeListener.selectorChange(DataSelector.this);
+ }
}
}
diff --git a/src/PamguardMVC/dataSelector/DataSelectorCreator.java b/src/PamguardMVC/dataSelector/DataSelectorCreator.java
index 77e199b5..25dde7c1 100644
--- a/src/PamguardMVC/dataSelector/DataSelectorCreator.java
+++ b/src/PamguardMVC/dataSelector/DataSelectorCreator.java
@@ -200,7 +200,14 @@ public abstract class DataSelectorCreator implements PamSettings {
return allSelectors.get(0);
}
else {
- return new CompoundDataSelector(pamDataBlock, allSelectors, selectorName, allowScores, selectorType);
+ CompoundDataSelector selector = new CompoundDataSelector(pamDataBlock, allSelectors, selectorName, allowScores, selectorType);
+ // not needed since it get's done after this call anyway.
+// DataSelectParams params = dataSelectorSettings.getParams(selectorName);
+// if (params instanceof CompoundParams) {
+// selector.setParams(params);
+// }
+
+ return selector;
}
}
diff --git a/src/PamguardMVC/dataSelector/DataSelectorSettings.java b/src/PamguardMVC/dataSelector/DataSelectorSettings.java
index f29c8103..df66d20e 100644
--- a/src/PamguardMVC/dataSelector/DataSelectorSettings.java
+++ b/src/PamguardMVC/dataSelector/DataSelectorSettings.java
@@ -7,6 +7,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DataSelectorSettings implements Serializable, ManagedParameters {
@@ -42,7 +43,7 @@ public class DataSelectorSettings implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("selectorParams");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/PamguardMVC/datakeeper/DataKeeperSettings.java b/src/PamguardMVC/datakeeper/DataKeeperSettings.java
index 446669c6..3765ef72 100644
--- a/src/PamguardMVC/datakeeper/DataKeeperSettings.java
+++ b/src/PamguardMVC/datakeeper/DataKeeperSettings.java
@@ -7,6 +7,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DataKeeperSettings implements Serializable, Cloneable, ManagedParameters {
@@ -51,7 +52,7 @@ public class DataKeeperSettings implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("keepTimeData");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/PamguardMVC/toad/GenericTOADSourceParams.java b/src/PamguardMVC/toad/GenericTOADSourceParams.java
index e0c2237c..cd12140a 100644
--- a/src/PamguardMVC/toad/GenericTOADSourceParams.java
+++ b/src/PamguardMVC/toad/GenericTOADSourceParams.java
@@ -6,6 +6,7 @@ import Localiser.DelayMeasurementParams;
import Localiser.controls.RawOrFFTParams;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* General parameters for detection TOAD measurement. Is split
@@ -67,7 +68,7 @@ public class GenericTOADSourceParams implements Cloneable, Serializable, Managed
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java b/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java
index c08a3f68..3b7546c2 100644
--- a/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java
+++ b/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java
@@ -218,7 +218,7 @@ public class RWEBinaryDataSource extends BinaryDataSource {
binaryObjectData.getDataUnitBaseData().setSampleDuration(duration);
// rweDataUnit = new RWEDataUnit(aSound.timeMilliseconds, channelMap,
// startSample, duration, aSound);
- rweDataUnit = new RWEDataUnit(binaryObjectData.getDataUnitBaseData(), aSound);
+ rweDataUnit = new RWEDataUnit(rweProcess, binaryObjectData.getDataUnitBaseData(), aSound);
rweDataUnit.setSequenceBitmap(sequenceMap);
double f[] = new double[2];
f[0] = aSound.minFreq * rweDataBlock.getSampleRate()/rweDataBlock.getFftLength();
diff --git a/src/RightWhaleEdgeDetector/RWEDataBlock.java b/src/RightWhaleEdgeDetector/RWEDataBlock.java
index 1969bca0..90c9a616 100644
--- a/src/RightWhaleEdgeDetector/RWEDataBlock.java
+++ b/src/RightWhaleEdgeDetector/RWEDataBlock.java
@@ -2,19 +2,29 @@ package RightWhaleEdgeDetector;
import PamView.GroupedDataSource;
import PamView.GroupedSourceParameters;
+import PamguardMVC.DataAutomation;
+import PamguardMVC.DataAutomationInfo;
import PamguardMVC.PamProcess;
import PamguardMVC.dataOffline.OfflineDataLoadInfo;
import PamguardMVC.dataSelector.DataSelectorCreator;
import RightWhaleEdgeDetector.datasel.RWDataSelCreator;
+import RightWhaleEdgeDetector.species.RWSpeciesManager;
+import RightWhaleEdgeDetector.species.RWTethysDataProvider;
import pamScrollSystem.ViewLoadObserver;
+import tethys.TethysControl;
+import tethys.pamdata.TethysDataProvider;
+import tethys.species.DataBlockSpeciesManager;
import whistlesAndMoans.AbstractWhistleDataBlock;
-public class RWEDataBlock extends AbstractWhistleDataBlock implements GroupedDataSource {
+public class RWEDataBlock extends AbstractWhistleDataBlock implements GroupedDataSource {
private double[] rwFreqRange = {50., 250.};
private RWEControl rweControl;
private RWEProcess rweProcess;
private RWDataSelCreator dataSelCreator;
+
+ private RWSpeciesManager rwSpeciesManager;
+ private RWTethysDataProvider rwTethysDataProvider;
public RWEDataBlock(RWEControl rweControl, String dataName,
RWEProcess rweProcess, int channelMap) {
@@ -53,4 +63,25 @@ public class RWEDataBlock extends AbstractWhistleDataBlock implements GroupedDat
return dataSelCreator;
}
+ @Override
+ public DataBlockSpeciesManager getDatablockSpeciesManager() {
+ if (rwSpeciesManager == null) {
+ rwSpeciesManager = new RWSpeciesManager(this);
+ }
+ return rwSpeciesManager;
+ }
+
+ @Override
+ public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) {
+ if (rwTethysDataProvider == null) {
+ rwTethysDataProvider = new RWTethysDataProvider(tethysControl, rweProcess.getRweDataBlock());
+ }
+ return rwTethysDataProvider;
+ }
+
+ @Override
+ public DataAutomationInfo getDataAutomationInfo() {
+ return new DataAutomationInfo(DataAutomation.AUTOMATIC);
+ }
+
}
diff --git a/src/RightWhaleEdgeDetector/RWEDataUnit.java b/src/RightWhaleEdgeDetector/RWEDataUnit.java
index 226e0f64..c3144ebf 100644
--- a/src/RightWhaleEdgeDetector/RWEDataUnit.java
+++ b/src/RightWhaleEdgeDetector/RWEDataUnit.java
@@ -6,26 +6,31 @@ import whistlesAndMoans.AbstractWhistleDataUnit;
public class RWEDataUnit extends AbstractWhistleDataUnit {
public RWESound rweSound;
+ private RWEProcess rweProcess;
- public RWEDataUnit(long timeMilliseconds, int channelBitmap,
+ public RWEDataUnit(RWEProcess rweProcess, long timeMilliseconds, int channelBitmap,
long startSample, long duration, RWESound rweSound) {
super(timeMilliseconds, channelBitmap, startSample, duration);
this.rweSound = rweSound;
+ this.rweProcess = rweProcess;
// TODO Auto-generated constructor stub
}
- public RWEDataUnit(DataUnitBaseData basicData, RWESound rweSound) {
+ public RWEDataUnit(RWEProcess rweProcess, DataUnitBaseData basicData, RWESound rweSound) {
super(basicData);
this.rweSound = rweSound;
+ this.rweProcess = rweProcess;
}
- double[] freqsHz;
@Override
public double[] getFreqsHz() {
- if (freqsHz == null) {
- freqsHz = new double[rweSound.sliceCount];
+ double[] f = new double[rweSound.sliceCount];
+ RWEDataBlock rweDataBlock = rweProcess.getRweDataBlock();
+ double binToHz = rweDataBlock.getSampleRate() / rweDataBlock.getFftLength();
+ for (int i = 0; i < f.length; i++) {
+ f[i] = (double) rweSound.peakFreq[i] * binToHz;
}
- return null;
+ return f;
}
@Override
@@ -35,8 +40,16 @@ public class RWEDataUnit extends AbstractWhistleDataUnit {
@Override
public double[] getTimesInSeconds() {
- // TODO Auto-generated method stub
- return null;
+ if (rweSound == null) {
+ return null;
+ }
+ double[] t = new double[rweSound.sliceCount];
+ RWEDataBlock rweDataBlock = rweProcess.getRweDataBlock();
+ double binToT = rweDataBlock.getFftHop() / rweDataBlock.getSampleRate();
+ for (int i = 0; i < t.length; i++) {
+ t[i] = (double) rweSound.sliceList[i] * binToT;
+ }
+ return t;
}
@Override
diff --git a/src/RightWhaleEdgeDetector/RWEParameters.java b/src/RightWhaleEdgeDetector/RWEParameters.java
index 8bb661a4..4b179378 100644
--- a/src/RightWhaleEdgeDetector/RWEParameters.java
+++ b/src/RightWhaleEdgeDetector/RWEParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class RWEParameters implements Serializable, Cloneable, ManagedParameters {
@@ -41,7 +42,7 @@ public class RWEParameters implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/RightWhaleEdgeDetector/RWEProcess.java b/src/RightWhaleEdgeDetector/RWEProcess.java
index ccc766bb..081489c9 100644
--- a/src/RightWhaleEdgeDetector/RWEProcess.java
+++ b/src/RightWhaleEdgeDetector/RWEProcess.java
@@ -42,6 +42,10 @@ public class RWEProcess extends PamProcess {
private FFTDataBlock sourceDataBlock;
private RWEDataBlock rweDataBlock;
+ public RWEDataBlock getRweDataBlock() {
+ return rweDataBlock;
+ }
+
private Hashtable bearingLocalisers;
private StandardSymbolManager symbolManager;
/**
@@ -212,7 +216,7 @@ public class RWEProcess extends PamProcess {
// System.out.println(String.format("Detected sound type %d on channel %d",
// soundType, this.iChannel));
duration = sourceDataBlock.getFftHop() * aSound.duration;
- rweDataUnit = new RWEDataUnit(aSound.timeMilliseconds,
+ rweDataUnit = new RWEDataUnit(RWEProcess.this, aSound.timeMilliseconds,
1< {
+
+ private RWSpeciesTypes rwSpeciesTypes = new RWSpeciesTypes();
+
+ public RWSpeciesManager(PamDataBlock dataBlock) {
+ super(dataBlock);
+ setDefaultDefaultSpecies(new SpeciesMapItem(RWSpeciesTypes.eubalaena, RWSpeciesTypes.onlyType, RWSpeciesTypes.defaultName));
+ }
+
+ @Override
+ public DataBlockSpeciesCodes getSpeciesCodes() {
+ return null;
+ }
+
+ @Override
+ public String getSpeciesCode(RWEDataUnit dataUnit) {
+ return RWSpeciesTypes.defaultName;
+ }
+
+}
diff --git a/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java b/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java
new file mode 100644
index 00000000..654fe24c
--- /dev/null
+++ b/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java
@@ -0,0 +1,17 @@
+package RightWhaleEdgeDetector.species;
+
+import tethys.species.DataBlockSpeciesCodes;
+
+public class RWSpeciesTypes extends DataBlockSpeciesCodes {
+
+ public static final String onlyType = "Up call";
+
+ public static final int eubalaena = 180536;
+
+ public static final String defaultName = "Right Whale";
+
+ public RWSpeciesTypes() {
+ super(eubalaena, defaultName, onlyType);
+ }
+
+}
diff --git a/src/RightWhaleEdgeDetector/species/RWTethysDataProvider.java b/src/RightWhaleEdgeDetector/species/RWTethysDataProvider.java
new file mode 100644
index 00000000..3577bd12
--- /dev/null
+++ b/src/RightWhaleEdgeDetector/species/RWTethysDataProvider.java
@@ -0,0 +1,37 @@
+package RightWhaleEdgeDetector.species;
+
+import PamguardMVC.PamDataBlock;
+import PamguardMVC.PamDataUnit;
+import RightWhaleEdgeDetector.RWEDataUnit;
+import nilus.Detection;
+import nilus.Detection.Parameters;
+import tethys.TethysControl;
+import tethys.output.StreamExportParams;
+import tethys.output.TethysExportParams;
+import tethys.pamdata.AutoTethysProvider;
+
+public class RWTethysDataProvider extends AutoTethysProvider {
+
+ public RWTethysDataProvider(TethysControl tethysControl, PamDataBlock pamDataBlock) {
+ super(tethysControl, pamDataBlock);
+ }
+
+ @Override
+ public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams,
+ StreamExportParams streamExportParams) {
+ Detection detection = super.createDetection(dataUnit, tethysExportParams, streamExportParams);
+ if (detection == null) {
+ return null;
+ }
+
+ RWEDataUnit rweDataUnit = (RWEDataUnit) dataUnit;
+
+ Parameters parameters = detection.getParameters();
+ parameters.setScore((double) rweDataUnit.rweSound.soundType);
+ double snr = 20.*Math.log10(rweDataUnit.rweSound.signal/rweDataUnit.rweSound.noise);
+ parameters.setSNRDB(snr);
+
+ return detection;
+ }
+
+}
diff --git a/src/SoundRecorder/RecorderSettings.java b/src/SoundRecorder/RecorderSettings.java
index 72c9576d..4fcd6eec 100644
--- a/src/SoundRecorder/RecorderSettings.java
+++ b/src/SoundRecorder/RecorderSettings.java
@@ -16,6 +16,7 @@ import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterData;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamUtils;
import PamguardMVC.PamRawDataBlock;
import SoundRecorder.trigger.RecorderTrigger;
@@ -443,7 +444,7 @@ public class RecorderSettings implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("channelBitmap");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/SoundRecorder/trigger/RecorderTriggerData.java b/src/SoundRecorder/trigger/RecorderTriggerData.java
index 2192afc9..9b0cb32c 100644
--- a/src/SoundRecorder/trigger/RecorderTriggerData.java
+++ b/src/SoundRecorder/trigger/RecorderTriggerData.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Information for triggered recordings to tell each recorder how long
@@ -271,7 +272,7 @@ public class RecorderTriggerData implements Serializable, Cloneable, ManagedPara
*/
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("lastTriggerStart");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/Spectrogram/SpectrogramDisplay.java b/src/Spectrogram/SpectrogramDisplay.java
index dd2536d6..08a7bf2d 100644
--- a/src/Spectrogram/SpectrogramDisplay.java
+++ b/src/Spectrogram/SpectrogramDisplay.java
@@ -77,6 +77,7 @@ import pamScrollSystem.PamScrollerData;
import pamScrollSystem.RangeSpinner;
import pamScrollSystem.RangeSpinnerListener;
import pamScrollSystem.jumping.ScrollJumper;
+import pamguard.GlobalArguments;
import soundPlayback.PlaybackControl;
import soundPlayback.PlaybackProgressMonitor;
import userDisplay.UserDisplayControl;
@@ -274,7 +275,8 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett
// this should result in settings being loaded if they exist.
PamSettingManager.getInstance().registerSettings(this); // always need to register, even if we're using old parameters
// }
- if (spectrogramParameters == null) {
+ boolean isBatch = GlobalArguments.getParam("-batch") != null;
+ if (spectrogramParameters == null && isBatch == false) {
this.spectrogramParameters = new SpectrogramParameters();
PamView view = userDisplayControl.getPamView();
if (view != null) {
@@ -285,6 +287,14 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett
}
}
}
+ if (spectrogramParameters == null) {
+ /*
+ * this can happen in batch mode if a display was added.
+ * Hopefully not a problem, but may need to set some parameters to
+ * set display up correctly.
+ */
+ spectrogramParameters = new SpectrogramParameters();
+ }
spectrogramDisplay = this;
@@ -1642,6 +1652,9 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett
return;
}
long t1 = dataUnit.getTimeMilliseconds()-viewerScroller.getValueMillis();
+ if (timeAxis == null) {
+ return;
+ }
int x1 = (int) Math.floor(timeAxis.getPosition(t1/1000));
int x2 = x1;
if (dataUnit.getDurationInMilliseconds() != null) {
diff --git a/src/alarm/AlarmParameters.java b/src/alarm/AlarmParameters.java
index df89b940..0694adfc 100644
--- a/src/alarm/AlarmParameters.java
+++ b/src/alarm/AlarmParameters.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class AlarmParameters implements Serializable, Cloneable, ManagedParameters {
@@ -103,7 +104,7 @@ public class AlarmParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("hadHold");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/alarm/actions/email/SendEmailSettings.java b/src/alarm/actions/email/SendEmailSettings.java
index dcd4dc0b..da558c85 100644
--- a/src/alarm/actions/email/SendEmailSettings.java
+++ b/src/alarm/actions/email/SendEmailSettings.java
@@ -28,6 +28,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import alarm.actions.serial.AlarmSerialSettings;
/**
@@ -158,7 +159,7 @@ public class SendEmailSettings implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/alarm/actions/serial/AlarmSerialSettings.java b/src/alarm/actions/serial/AlarmSerialSettings.java
index b14e785c..801cc765 100644
--- a/src/alarm/actions/serial/AlarmSerialSettings.java
+++ b/src/alarm/actions/serial/AlarmSerialSettings.java
@@ -8,6 +8,7 @@ import com.fazecast.jSerialComm.SerialPort;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import serialComms.SerialPortConstants;
import serialComms.jserialcomm.PJSerialComm;
@@ -68,7 +69,7 @@ public class AlarmSerialSettings implements Serializable, Cloneable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/alarm/actions/sound/PlaySoundParams.java b/src/alarm/actions/sound/PlaySoundParams.java
index c9f97970..6481e41d 100644
--- a/src/alarm/actions/sound/PlaySoundParams.java
+++ b/src/alarm/actions/sound/PlaySoundParams.java
@@ -6,6 +6,7 @@ import java.util.Arrays;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import alarm.AlarmParameters;
public class PlaySoundParams implements Cloneable, Serializable, ManagedParameters {
@@ -33,7 +34,7 @@ public class PlaySoundParams implements Cloneable, Serializable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/alarm/actions/udp/AlarmUDPParams.java b/src/alarm/actions/udp/AlarmUDPParams.java
index 10728bb2..7a7bfa61 100644
--- a/src/alarm/actions/udp/AlarmUDPParams.java
+++ b/src/alarm/actions/udp/AlarmUDPParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class AlarmUDPParams implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class AlarmUDPParams implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/amplifier/AmpParameters.java b/src/amplifier/AmpParameters.java
index 98e52a63..89aac38c 100644
--- a/src/amplifier/AmpParameters.java
+++ b/src/amplifier/AmpParameters.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamguardMVC.PamConstants;
@@ -41,7 +42,7 @@ public class AmpParameters implements Cloneable, Serializable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("rawDataSource");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/analogarraysensor/ArraySensorLogging.java b/src/analogarraysensor/ArraySensorLogging.java
index e4eba2e9..ca13752a 100644
--- a/src/analogarraysensor/ArraySensorLogging.java
+++ b/src/analogarraysensor/ArraySensorLogging.java
@@ -56,7 +56,8 @@ public class ArraySensorLogging extends SQLLogging {
AnalogSensorData aData = new AnalogSensorData(rawValue, calValue);
sensorData[i] = aData;
}
- int chanMap = getTableDefinition().getChannelBitmap().getIntegerValue();
+ PamTableDefinition pamTableDef = (PamTableDefinition) getTableDefinition();
+ int chanMap = pamTableDef.getChannelBitmap().getIntegerValue();
int streamer = PamUtils.getSingleChannel(chanMap);
if (streamer < 0) streamer = 0;
AnalogArraySensorDataUnit asdu = new AnalogArraySensorDataUnit(timeMilliseconds, streamer, sensorData);
diff --git a/src/analogarraysensor/ArraySensorParams.java b/src/analogarraysensor/ArraySensorParams.java
index c59d31eb..b84081a6 100644
--- a/src/analogarraysensor/ArraySensorParams.java
+++ b/src/analogarraysensor/ArraySensorParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import Array.sensors.ArrayDisplayParameters;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class ArraySensorParams implements Serializable, Cloneable, ManagedParameters {
@@ -47,7 +48,7 @@ public class ArraySensorParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/analoginput/AnalogDeviceParams.java b/src/analoginput/AnalogDeviceParams.java
index 1b43c7b9..cae97232 100644
--- a/src/analoginput/AnalogDeviceParams.java
+++ b/src/analoginput/AnalogDeviceParams.java
@@ -6,6 +6,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import analoginput.calibration.CalibrationData;
@@ -63,7 +64,7 @@ public class AnalogDeviceParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("calibrationTable");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/analoginput/AnalogInputParams.java b/src/analoginput/AnalogInputParams.java
index acd041e4..a64d51ba 100644
--- a/src/analoginput/AnalogInputParams.java
+++ b/src/analoginput/AnalogInputParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class AnalogInputParams implements Serializable, Cloneable, ManagedParameters {
@@ -13,7 +14,7 @@ public class AnalogInputParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/analoginput/AnalogRangeData.java b/src/analoginput/AnalogRangeData.java
index 00043994..7a7d7109 100644
--- a/src/analoginput/AnalogRangeData.java
+++ b/src/analoginput/AnalogRangeData.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class AnalogRangeData implements Serializable, Cloneable, Comparable, ManagedParameters {
@@ -119,7 +120,7 @@ public class AnalogRangeData implements Serializable, Cloneable, Comparable 0) {
diff --git a/src/annotation/timestamp/TimestampSQLLogging.java b/src/annotation/timestamp/TimestampSQLLogging.java
index fd1d7be6..2f6b0728 100644
--- a/src/annotation/timestamp/TimestampSQLLogging.java
+++ b/src/annotation/timestamp/TimestampSQLLogging.java
@@ -3,6 +3,7 @@ package annotation.timestamp;
import java.sql.Types;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -22,12 +23,12 @@ public class TimestampSQLLogging implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(timestamp);
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
TimestampAnnotation timestampAnnotation = (TimestampAnnotation) pamDataUnit.findDataAnnotation(TimestampAnnotation.class,
timestampAnnotationType.getAnnotationName());
if (timestampAnnotation == null) {
@@ -40,7 +41,7 @@ public class TimestampSQLLogging implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
try {
TimestampAnnotation timestampAnnotation = new TimestampAnnotation(timestampAnnotationType);
Long note = sqlTypes.millisFromTimeStamp(timestamp.getValue());
diff --git a/src/annotation/userforms/UserFormSQLAddon.java b/src/annotation/userforms/UserFormSQLAddon.java
index fb5a20f0..8156bfda 100644
--- a/src/annotation/userforms/UserFormSQLAddon.java
+++ b/src/annotation/userforms/UserFormSQLAddon.java
@@ -3,6 +3,7 @@ package annotation.userforms;
import java.util.ArrayList;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -32,7 +33,7 @@ public class UserFormSQLAddon implements SQLLoggingAddon {
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
loggerTableItems.clear();
FormDescription formDescription = userFormAnnotationType.findFormDescription();
if (formDescription == null) {
@@ -58,7 +59,7 @@ public class UserFormSQLAddon implements SQLLoggingAddon {
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
if (pamDataUnit == null) {
clearTableItems();
return false;
@@ -103,7 +104,7 @@ public class UserFormSQLAddon implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
FormDescription formDescription = userFormAnnotationType.findFormDescription();
if (formDescription == null) {
return false;
diff --git a/src/annotationMark/spectrogram/SpectrogramMarkParams.java b/src/annotationMark/spectrogram/SpectrogramMarkParams.java
index 0d65e6e4..89540c01 100644
--- a/src/annotationMark/spectrogram/SpectrogramMarkParams.java
+++ b/src/annotationMark/spectrogram/SpectrogramMarkParams.java
@@ -5,6 +5,7 @@ import java.util.List;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import annotation.DataAnnotationType;
import annotation.handler.AnnotationChoices;
@@ -31,7 +32,7 @@ public class SpectrogramMarkParams implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/backupmanager/FileLocation.java b/src/backupmanager/FileLocation.java
index 1508125a..6557821d 100644
--- a/src/backupmanager/FileLocation.java
+++ b/src/backupmanager/FileLocation.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Information on a file path or folder path that can be used with the
@@ -42,7 +43,7 @@ public class FileLocation implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/backupmanager/settings/BackupSettings.java b/src/backupmanager/settings/BackupSettings.java
index 71b90fda..bc9ac14c 100644
--- a/src/backupmanager/settings/BackupSettings.java
+++ b/src/backupmanager/settings/BackupSettings.java
@@ -6,6 +6,7 @@ import java.util.List;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public abstract class BackupSettings implements Serializable, Cloneable, ManagedParameters {
@@ -40,7 +41,7 @@ public abstract class BackupSettings implements Serializable, Cloneable, Managed
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/beamformer/BeamAlgorithmParams.java b/src/beamformer/BeamAlgorithmParams.java
index 7cde91b4..eabdb943 100644
--- a/src/beamformer/BeamAlgorithmParams.java
+++ b/src/beamformer/BeamAlgorithmParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import beamformer.algorithms.basicFreqDomain.BasicFreqDomParams;
/*
@@ -336,7 +337,7 @@ public abstract class BeamAlgorithmParams implements Serializable, Cloneable, Ma
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/beamformer/BeamFormerParams.java b/src/beamformer/BeamFormerParams.java
index f5cc3f5d..d6082a1d 100644
--- a/src/beamformer/BeamFormerParams.java
+++ b/src/beamformer/BeamFormerParams.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamUtils.DeepCloner;
import PamView.GroupedSourceParameters;
@@ -325,7 +326,7 @@ public class BeamFormerParams implements Cloneable, Serializable, ManagedParamet
*/
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("algorithmParamsTable");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/beamformer/annotation/BFAnnotationLogging.java b/src/beamformer/annotation/BFAnnotationLogging.java
index 83d7641a..ba9bed54 100644
--- a/src/beamformer/annotation/BFAnnotationLogging.java
+++ b/src/beamformer/annotation/BFAnnotationLogging.java
@@ -6,6 +6,7 @@ import PamDetection.LocContents;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import beamformer.loc.BeamFormerLocalisation;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -29,7 +30,7 @@ public class BFAnnotationLogging implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(bfPhones);
pamTableDefinition.addTableItem(bfArrayType);
pamTableDefinition.addTableItem(bfContents);
@@ -38,7 +39,7 @@ public class BFAnnotationLogging implements SQLLoggingAddon {
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
bfPhones.setValue(null);
bfArrayType.setValue(null);
bfContents.setValue(null);
@@ -64,7 +65,7 @@ public class BFAnnotationLogging implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
Float[] Angles = new Float[2];
for (int i = 0; i < 2; i++) {
Angles[i] = (Float) angle[i].getFloatValue();
diff --git a/src/bearinglocaliser/BearingLocaliserParams.java b/src/bearinglocaliser/BearingLocaliserParams.java
index 277c8e5d..d697781c 100644
--- a/src/bearinglocaliser/BearingLocaliserParams.java
+++ b/src/bearinglocaliser/BearingLocaliserParams.java
@@ -8,6 +8,7 @@ import java.util.HashMap;
import Localiser.controls.RawOrFFTParamsInterface;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamView.GroupedSourceParameters;
import bearinglocaliser.algorithms.BearingAlgorithmParams;
@@ -188,7 +189,7 @@ public class BearingLocaliserParams implements Serializable, Cloneable, RawOrFFT
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("algorithmParamsTable");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java b/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java
index 3b6c0bed..cea3e25f 100644
--- a/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java
+++ b/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class BearingAlgorithmParams implements Serializable, Cloneable, ManagedParameters {
@@ -60,7 +61,7 @@ public class BearingAlgorithmParams implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/bearinglocaliser/annotation/BearingAnnotationSQL.java b/src/bearinglocaliser/annotation/BearingAnnotationSQL.java
index bc4b88bb..d56e8be7 100644
--- a/src/bearinglocaliser/annotation/BearingAnnotationSQL.java
+++ b/src/bearinglocaliser/annotation/BearingAnnotationSQL.java
@@ -4,6 +4,7 @@ import java.sql.Types;
import PamguardMVC.PamDataUnit;
import bearinglocaliser.BearingLocalisation;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -34,7 +35,7 @@ public class BearingAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(algoName);
pamTableDefinition.addTableItem(bfPhones);
pamTableDefinition.addTableItem(bfArrayType);
@@ -48,7 +49,7 @@ public class BearingAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
algoName.setValue(null);
bfPhones.setValue(null);
bfArrayType.setValue(null);
@@ -96,7 +97,7 @@ public class BearingAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
Float[] Angles = new Float[2];
int nNans = 0;
for (int i = 0; i < 2; i++) {
diff --git a/src/binaryFileStorage/BinaryFooter.java b/src/binaryFileStorage/BinaryFooter.java
index 98142a16..f410998b 100644
--- a/src/binaryFileStorage/BinaryFooter.java
+++ b/src/binaryFileStorage/BinaryFooter.java
@@ -7,6 +7,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamCalendar;
public class BinaryFooter implements Serializable, ManagedParameters {
@@ -230,7 +231,7 @@ public class BinaryFooter implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/binaryFileStorage/BinaryHeader.java b/src/binaryFileStorage/BinaryHeader.java
index b27652ec..b1d7a986 100644
--- a/src/binaryFileStorage/BinaryHeader.java
+++ b/src/binaryFileStorage/BinaryHeader.java
@@ -9,6 +9,7 @@ import java.lang.reflect.Field;
import PamController.PamguardVersionInfo;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamUtils.PamCalendar;
@@ -289,7 +290,7 @@ public class BinaryHeader implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("pamguard");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/binaryFileStorage/BinaryOutputStream.java b/src/binaryFileStorage/BinaryOutputStream.java
index 1e474686..67307c12 100644
--- a/src/binaryFileStorage/BinaryOutputStream.java
+++ b/src/binaryFileStorage/BinaryOutputStream.java
@@ -49,7 +49,7 @@ public class BinaryOutputStream {
private DataOutputStream noiseOutputStream;
- private int storedObjects;
+ private int storedObjects, storedNoiseCount;
private String mainFileName, indexFileName;
@@ -219,6 +219,7 @@ public class BinaryOutputStream {
else {
noiseOutputStream = null;
}
+ storedNoiseCount = 0;
return true;
}
@@ -450,6 +451,7 @@ public class BinaryOutputStream {
footer.setHighestUID(parentDataBlock.getUidHandler().getCurrentUID());
boolean ok = footer.writeFooter(dataOutputStream, BinaryStore.getCurrentFileFormat());
if (noiseOutputStream != null) {
+// footer.setnObjects(storedNoiseCount);
ok &= footer.writeFooter(noiseOutputStream, BinaryStore.getCurrentFileFormat());
}
lastObjectType = BinaryTypes.FILE_FOOTER;
@@ -487,12 +489,20 @@ public class BinaryOutputStream {
// }
public synchronized boolean storeData(int objectId, DataUnitBaseData baseData, BinaryObjectData binaryObjectData) {
+ boolean ok;
if (objectId == BinaryTypes.BACKGROUND_DATA & noiseOutputStream != null) {
- return storeData(noiseOutputStream, objectId, baseData, binaryObjectData);
+ ok = storeData(noiseOutputStream, objectId, baseData, binaryObjectData);
+ if (ok) {
+ storedNoiseCount++;
+ }
}
else {
- return storeData(dataOutputStream, objectId, baseData, binaryObjectData);
+ ok = storeData(dataOutputStream, objectId, baseData, binaryObjectData);
+ if (ok) {
+ storedObjects++;
+ }
}
+ return ok;
}
/**
* Writes data to a file. Note that the length of data may be greater than
@@ -505,7 +515,9 @@ public class BinaryOutputStream {
*/
public synchronized boolean storeData(DataOutputStream outputStream, int objectId, DataUnitBaseData baseData, BinaryObjectData binaryObjectData) {
if (lastObjectType == BinaryTypes.MODULE_FOOTER) {
- System.out.printf("Storing binary object type %d in file %s with no module header\n", objectId, outputStream == null ? null : outputStream.toString());
+ System.out.printf("Storing binary object at %s from %s in file %s with no module header\n",
+ PamCalendar.formatDBDateTime(baseData.getTimeMilliseconds()),
+ parentDataBlock.getDataName(), outputStream == null ? null : outputStream.toString());
}
byte[] data = binaryObjectData.getData();
int objectLength = binaryObjectData.getDataLength();
@@ -562,7 +574,6 @@ public class BinaryOutputStream {
return false;
}
- storedObjects++;
return true;
diff --git a/src/binaryFileStorage/BinarySettingsStorage.java b/src/binaryFileStorage/BinarySettingsStorage.java
index 48278c1d..c59992d8 100644
--- a/src/binaryFileStorage/BinarySettingsStorage.java
+++ b/src/binaryFileStorage/BinarySettingsStorage.java
@@ -110,6 +110,12 @@ public class BinarySettingsStorage implements PamSettingsSource {
return false;*/
}
+ @Override
+ public boolean saveEndSettings(long timeNow) {
+ // do nothing at the end of a run with binary store.
+ return true;
+ }
+
// private boolean writeData(DataOutputStream dos, int objectId, byte[] data) {
// int totalLen = data.length + 16;
// int dataLen = data.length;
diff --git a/src/binaryFileStorage/BinaryStore.java b/src/binaryFileStorage/BinaryStore.java
index 98b6dc84..67453533 100644
--- a/src/binaryFileStorage/BinaryStore.java
+++ b/src/binaryFileStorage/BinaryStore.java
@@ -155,6 +155,8 @@ PamSettingsSource, DataOutputStore {
private PamControlledGUISwing binaryStoreGUISwing;
private BackupInformation backupInformation;
+
+ private BinaryDataMapMaker dataMapMaker;
public static int getCurrentFileFormat() {
return CURRENT_FORMAT;
@@ -424,6 +426,25 @@ PamSettingsSource, DataOutputStore {
}
return true;
}
+
+ public boolean checkCommandLine() {
+ /*
+ * check to see if there is a command line override of the currently stored folder name.
+ */
+ String globFolder = GlobalArguments.getParam(GlobalFolderArg);
+ if (globFolder == null) {
+ return false;
+ }
+ boolean ok = checkGlobFolder(globFolder);
+ if (ok) {
+ binaryStoreSettings.setStoreLocation(globFolder); // remember it.
+ return true;
+ }
+ else {
+ System.err.println("Unable to set binary storage folder " + globFolder);
+ return false;
+ }
+ }
/**
* Set and create if necessary the global folder.
@@ -540,6 +561,12 @@ PamSettingsSource, DataOutputStore {
return binarySettingsStorage.saveStartSettings(timeNow);
}
+ @Override
+ public boolean saveEndSettings(long timeNow) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
@Override
public int getNumSettings() {
if (binarySettingsStorage == null) {
@@ -595,7 +622,8 @@ PamSettingsSource, DataOutputStore {
// this first operation should be fast enough that it doesn't
// need rethreading.
- if (isViewer()) {
+ boolean hasCommandLine = checkCommandLine();
+ if (isViewer() && !hasCommandLine) {
BinaryStoreSettings newSettings = null;
if (PamGUIManager.isSwing()) {
//open the swing dialog.
@@ -784,8 +812,8 @@ PamSettingsSource, DataOutputStore {
* updates to the dialog to display progress, then close the
* dialog.
*/
- BinaryDataMapMaker bdmm = new BinaryDataMapMaker(this);
- AWTScheduler.getInstance().scheduleTask(bdmm);
+ dataMapMaker = new BinaryDataMapMaker(this);
+ AWTScheduler.getInstance().scheduleTask(dataMapMaker);
}
@@ -917,6 +945,7 @@ PamSettingsSource, DataOutputStore {
}
PamController.getInstance().notifyModelChanged(PamControllerInterface.CHANGED_OFFLINE_DATASTORE);
// System.out.println("BinaryDataMapMaker really done " + this);
+ dataMapMaker = null;
}
@Override
@@ -2547,5 +2576,22 @@ PamSettingsSource, DataOutputStore {
BinaryStoreDeleter storeDeleter = new BinaryStoreDeleter(this);
return storeDeleter.deleteDataFrom(timeMillis);
}
+ @Override
+ public int getOfflineState() {
+ int state = super.getOfflineState();
+ if (dataMapMaker != null) {
+ System.out.println("Binary store is map making");
+ state = Math.max(state, PamController.PAM_MAPMAKING);
+ }
+ if (datagramManager != null & datagramManager.getStatus()) {
+ state = Math.max(state, PamController.PAM_MAPMAKING);
+ System.out.println("Binary store is creating datagram");
+ }
+ return state;
+ }
+
+ public String getDataLocation() {
+ return binaryStoreSettings.getStoreLocation();
+ }
}
diff --git a/src/binaryFileStorage/BinaryStoreSettings.java b/src/binaryFileStorage/BinaryStoreSettings.java
index 441baddd..78c42e99 100644
--- a/src/binaryFileStorage/BinaryStoreSettings.java
+++ b/src/binaryFileStorage/BinaryStoreSettings.java
@@ -6,6 +6,7 @@ import java.io.Serializable;
import PamController.PamFolders;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class BinaryStoreSettings implements Serializable, Cloneable, ManagedParameters {
@@ -90,7 +91,7 @@ public class BinaryStoreSettings implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/cepstrum/CepstrumParams.java b/src/cepstrum/CepstrumParams.java
index a24fab3a..59f6fbb9 100644
--- a/src/cepstrum/CepstrumParams.java
+++ b/src/cepstrum/CepstrumParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class CepstrumParams implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class CepstrumParams implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/clickDetector/BTDisplayParameters.java b/src/clickDetector/BTDisplayParameters.java
index 143b3eab..bf9604f7 100644
--- a/src/clickDetector/BTDisplayParameters.java
+++ b/src/clickDetector/BTDisplayParameters.java
@@ -6,6 +6,7 @@ import java.util.Arrays;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import clickDetector.tdPlots.ClickSymbolOptions;
@@ -137,7 +138,7 @@ public class BTDisplayParameters implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("showSpeciesList");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/BasicClickIdParameters.java b/src/clickDetector/BasicClickIdParameters.java
index feeefb67..6cc5925c 100644
--- a/src/clickDetector/BasicClickIdParameters.java
+++ b/src/clickDetector/BasicClickIdParameters.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
@@ -83,7 +84,7 @@ public class BasicClickIdParameters implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickDetector/ClickAlarm.java b/src/clickDetector/ClickAlarm.java
index f9459296..515945ab 100644
--- a/src/clickDetector/ClickAlarm.java
+++ b/src/clickDetector/ClickAlarm.java
@@ -33,6 +33,7 @@ import javax.sound.sampled.Clip;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
/**
@@ -209,7 +210,7 @@ public class ClickAlarm implements Comparable, Serializable, Cloneab
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("fileIsLoaded");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/ClickBinaryModuleFooter.java b/src/clickDetector/ClickBinaryModuleFooter.java
index 35718e17..f24ed53c 100644
--- a/src/clickDetector/ClickBinaryModuleFooter.java
+++ b/src/clickDetector/ClickBinaryModuleFooter.java
@@ -12,6 +12,7 @@ import PamController.PamController;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import binaryFileStorage.BinaryHeader;
import binaryFileStorage.BinaryObjectData;
import binaryFileStorage.ModuleFooter;
@@ -128,7 +129,7 @@ public class ClickBinaryModuleFooter extends ModuleFooter implements ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("clickDetectorName");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/ClickBinaryModuleHeader.java b/src/clickDetector/ClickBinaryModuleHeader.java
index 1cb7f8d8..f36f7854 100644
--- a/src/clickDetector/ClickBinaryModuleHeader.java
+++ b/src/clickDetector/ClickBinaryModuleHeader.java
@@ -2,6 +2,7 @@ package clickDetector;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import binaryFileStorage.BinaryHeader;
import binaryFileStorage.BinaryObjectData;
import binaryFileStorage.ModuleHeader;
@@ -28,7 +29,7 @@ public class ClickBinaryModuleHeader extends ModuleHeader implements ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java
new file mode 100644
index 00000000..bb7528bf
--- /dev/null
+++ b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java
@@ -0,0 +1,52 @@
+package clickDetector.ClickClassifiers;
+
+import clickDetector.ClickControl;
+import clickDetector.ClickDataBlock;
+import clickDetector.ClickDetection;
+import tethys.species.DataBlockSpeciesManager;
+import tethys.species.DataBlockSpeciesCodes;
+import tethys.species.ITISTypes;
+import tethys.species.SpeciesMapItem;
+
+public class ClickBlockSpeciesManager extends DataBlockSpeciesManager {
+
+ private ClickControl clickControl;
+
+ public ClickBlockSpeciesManager(ClickControl clickControl, ClickDataBlock clickDataBlock) {
+ super(clickDataBlock);
+ this.clickControl = clickControl;
+ setDefaultDefaultSpecies(new SpeciesMapItem(ITISTypes.OTHER, "Unknown", "Unknown"));
+ setDefaultSpeciesCode("Unknown");
+ }
+
+ @Override
+ public DataBlockSpeciesCodes getSpeciesCodes() {
+ ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager();
+ if (masterManager == null) {
+ return null;
+ }
+ String[] speciesList = masterManager.getSpeciesList();
+ // add the default
+ String[] fullList = new String[speciesList.length+1];
+ fullList[0] = getDefaultSpeciesCode();
+ for (int i = 0; i < speciesList.length; i++) {
+ fullList[i+1] = speciesList[i];
+ }
+
+ return new DataBlockSpeciesCodes("Click", fullList);
+ }
+
+ @Override
+ public String getSpeciesCode(ClickDetection dataUnit) {
+ ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager();
+ if (masterManager == null) {
+ return null;
+ }
+ int listIndex = masterManager.codeToListIndex(dataUnit.getClickType());
+ if (listIndex < 0) {
+ return null;
+ }
+ return masterManager.getSpeciesList()[listIndex];
+ }
+
+}
diff --git a/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java b/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java
index d937b164..78b56316 100644
--- a/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java
+++ b/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java
@@ -28,6 +28,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Superclass for click parameters, including the ClickTypeParms and
@@ -191,7 +192,7 @@ abstract public class ClickTypeCommonParams implements Cloneable, Serializable,
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java b/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java
index baa057ac..840d2086 100644
--- a/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java
+++ b/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java
@@ -3,6 +3,7 @@ package clickDetector.ClickClassifiers.annotation;
import java.sql.Types;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -33,12 +34,12 @@ public class ClickAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(classifierSetTable);
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
ClickClassifierAnnotation clickAnnotation = (ClickClassifierAnnotation) pamDataUnit.findDataAnnotation(ClickClassificationType.class);
//create a comma delimited string
@@ -53,7 +54,7 @@ public class ClickAnnotationSQL implements SQLLoggingAddon {
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
String array = classifierSetTable.getDeblankedStringValue();
//read in the classification set. This a list of all the classifiers the clicks passed.
diff --git a/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java b/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java
index 9c925607..6cc4f1b5 100644
--- a/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java
+++ b/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java
@@ -7,6 +7,7 @@ import java.util.Vector;
import PamModel.SMRUEnable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class SweepClassifierParameters implements Serializable, Cloneable, ManagedParameters {
@@ -72,7 +73,7 @@ public class SweepClassifierParameters implements Serializable, Cloneable, Manag
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("classifierSets");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/ClickControl.java b/src/clickDetector/ClickControl.java
index e03b73a7..9787c59f 100644
--- a/src/clickDetector/ClickControl.java
+++ b/src/clickDetector/ClickControl.java
@@ -26,6 +26,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.List;
import java.util.ListIterator;
import javax.swing.JMenu;
@@ -1071,7 +1072,7 @@ public class ClickControl extends PamControlledUnit implements PamSettings {
subDet.removeSuperDetection(event);
}
}
- clickDetector.getOfflineEventDataBlock().remove(event);
+ clickDetector.getOfflineEventDataBlock().remove(event, true);
}
@Override
@@ -1168,6 +1169,31 @@ public class ClickControl extends PamControlledUnit implements PamSettings {
return targetMotionLocaliser;
}
+ /**
+ * Remove clicks from existing events, if they have any. They may not.
+ * This is called whenever clicks are assigned to a new event to make
+ * sure that they don't end up in two events.
+ * @param markedClicks
+ */
+ public void removeFromEvents(List markedClicks) {
+ if (markedClicks == null) {
+ return;
+ }
+ for (PamDataUnit dataUnit : markedClicks) {
+ OfflineEventDataUnit anEvent = (OfflineEventDataUnit) dataUnit.getSuperDetection(OfflineEventDataUnit.class);
+ if (anEvent == null) {
+ continue;
+ }
+ anEvent.removeSubDetection(dataUnit);
+ if (anEvent.getSubDetectionsCount() == 0) {
+ deleteEvent(anEvent);
+ }
+ else {
+ anEvent.updateDataUnit(System.currentTimeMillis());
+ }
+ }
+
+ }
/**
* Reassign all the clicks on one event to a different event
@@ -1199,7 +1225,7 @@ public class ClickControl extends PamControlledUnit implements PamSettings {
}
clickEvent.setComment(clickEvent.getComment() + " Clicks reassigned to event " + reassignEvent.getEventId());
offlineEventDataBlock.updatePamData(clickEvent, PamCalendar.getTimeInMillis());
- offlineEventDataBlock.remove(clickEvent);
+ offlineEventDataBlock.remove(clickEvent, true);
reassignEvent.sortSubDetections();
offlineEventDataBlock.updatePamData(reassignEvent, now);
if (ClickTrainDetection.class.isAssignableFrom(reassignEvent.getClass())) {
diff --git a/src/clickDetector/ClickDataBlock.java b/src/clickDetector/ClickDataBlock.java
index 3e650b85..5536aa79 100644
--- a/src/clickDetector/ClickDataBlock.java
+++ b/src/clickDetector/ClickDataBlock.java
@@ -3,6 +3,9 @@ package clickDetector;
import java.util.ListIterator;
import pamScrollSystem.ViewLoadObserver;
+import tethys.TethysControl;
+import tethys.pamdata.TethysDataProvider;
+import tethys.species.DataBlockSpeciesManager;
//import staticLocaliser.StaticLocaliserControl;
//import staticLocaliser.StaticLocaliserProvider;
//import staticLocaliser.panels.AbstractLocaliserControl;
@@ -10,8 +13,10 @@ import pamScrollSystem.ViewLoadObserver;
import alarm.AlarmCounterProvider;
import alarm.AlarmDataSource;
import binaryFileStorage.BinaryStore;
+import clickDetector.ClickClassifiers.ClickBlockSpeciesManager;
import clickDetector.dataSelector.ClickDataSelectCreator;
import clickDetector.offlineFuncs.OfflineClickLogging;
+import clickDetector.tethys.ClickTethysDataProvider;
import clickDetector.toad.ClickTOADCalculator;
import dataMap.OfflineDataMap;
import fftManager.fftorganiser.FFTDataOrganiser;
@@ -24,6 +29,8 @@ import PamUtils.PamUtils;
import PamView.GroupedDataSource;
import PamView.GroupedSourceParameters;
import PamguardMVC.AcousticDataBlock;
+import PamguardMVC.DataAutomation;
+import PamguardMVC.DataAutomationInfo;
import PamguardMVC.FFTDataHolderBlock;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
@@ -41,6 +48,8 @@ public class ClickDataBlock extends AcousticDataBlock implement
private boolean isViewer;
+ private ClickBlockSpeciesManager clickBlockSpeciesManager;
+
public ClickDataBlock(ClickControl clickControl, PamProcess parentProcess, int channelMap) {
@@ -65,6 +74,8 @@ public class ClickDataBlock extends AcousticDataBlock implement
private ClickTOADCalculator clickTOADCalculator;
+ private ClickTethysDataProvider clickTethysDataProvider;
+
/**
* Click detector loading has to be a bit different to normal - first
* data are loaded from the binary store, then a subset of these data
@@ -304,5 +315,26 @@ public class ClickDataBlock extends AcousticDataBlock implement
}
}
+ @Override
+ public DataBlockSpeciesManager getDatablockSpeciesManager() {
+ if (clickBlockSpeciesManager == null) {
+ clickBlockSpeciesManager = new ClickBlockSpeciesManager(clickControl, this);
+ }
+ return clickBlockSpeciesManager;
+ }
+
+ @Override
+ public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) {
+ if (clickTethysDataProvider == null) {
+ clickTethysDataProvider = new ClickTethysDataProvider(tethysControl, this);
+ }
+ return clickTethysDataProvider;
+ }
+
+ @Override
+ public DataAutomationInfo getDataAutomationInfo() {
+ return new DataAutomationInfo(DataAutomation.AUTOMATIC);
+ }
+
}
diff --git a/src/clickDetector/ClickDisplayManager.java b/src/clickDetector/ClickDisplayManager.java
index f46aeca8..2329bb4a 100644
--- a/src/clickDetector/ClickDisplayManager.java
+++ b/src/clickDetector/ClickDisplayManager.java
@@ -28,6 +28,7 @@ import PamController.PamSettingManager;
import PamController.PamSettings;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamView.MenuItemEnabler;
@@ -302,7 +303,7 @@ public class ClickDisplayManager implements PamSettings {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("className");
ps.put(new PrivatePamParameterData(this, field) {
@@ -406,8 +407,13 @@ public class ClickDisplayManager implements PamSettings {
public Serializable getSettingsReference() {
cdmp.countEverything(this);
+ cdmp.saveDisplayLocations(getWindowList());
return cdmp;
}
+
+ public void restoreWindowSizes() {
+ cdmp.restoreWindowSizes(getWindowList());
+ }
public int countDisplays(Class displayType) {
int count = 0;
diff --git a/src/clickDetector/ClickDisplayManagerParameters2.java b/src/clickDetector/ClickDisplayManagerParameters2.java
index 86ccbca6..6bcc110a 100644
--- a/src/clickDetector/ClickDisplayManagerParameters2.java
+++ b/src/clickDetector/ClickDisplayManagerParameters2.java
@@ -1,14 +1,20 @@
package clickDetector;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Rectangle;
import java.io.Serializable;
import java.lang.reflect.Field;
+import java.util.ArrayList;
+import Layout.PamInternalFrame;
import clickDetector.IDI_Display.IDIHistogramImage;
import PamController.PamController;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class ClickDisplayManagerParameters2 implements Cloneable, Serializable, ManagedParameters {
@@ -34,6 +40,10 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable,
private boolean initialised = false;
+ private boolean manualWindowSizes = false;
+
+ private ArrayList windowSizes = new ArrayList();
+
public ClickDisplayManagerParameters2() {
setDefaults();
}
@@ -158,6 +168,11 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable,
return null;
}
+ /**
+ * This populates the serialised settings with lists of how many displays of
+ * each type there are.
+ * @param clickDisplayManager
+ */
public void countEverything(ClickDisplayManager clickDisplayManager) {
lastMode = PamController.getInstance().getRunMode();
if (lastMode >= NMODES) lastMode = 0;
@@ -181,7 +196,7 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable,
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("initialised");
ps.put(new PrivatePamParameterData(this, field) {
@@ -207,4 +222,101 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable,
return ps;
}
+ /**
+ * Save windows sizes in an array list.
+ * @param windowList
+ */
+ public void saveDisplayLocations(ArrayList windowList) {
+ if (windowList == null) {
+ return;
+ }
+ getWindowSizes(); // make sure the array is created
+ windowSizes.clear();
+ for (ClickDisplay disp : windowList) {
+ Point loc = disp.getFrame().getLocation();
+ Dimension sz = disp.getFrame().getSize();
+ String cls = disp.getClass().toString();
+ windowSizes.add(new WindowSizeData(cls, loc, sz));
+ }
+ }
+
+ /**
+ * Try to restore window locations and sizes from a stored list.
+ * @param windowList
+ * @return
+ */
+ public boolean restoreWindowSizes(ArrayList windowList){
+ if (windowSizes == null || windowList == null) {
+ return false;
+ }
+ int resized = 0;
+ for (ClickDisplay disp : windowList) {
+ PamInternalFrame frame = disp.getFrame();
+ String cls = disp.getClass().toString();
+ // find an element in the list with that class.
+ WindowSizeData sizeData = null;
+ for (int i = 0; i < windowSizes.size(); i++) {
+ if (windowSizes.get(i).windowClass.equals(cls)) {
+ sizeData = windowSizes.remove(i);
+ break;
+ }
+ }
+ if (sizeData != null) {
+ frame.setLocation(sizeData.location);
+ frame.setSize(sizeData.size);
+ resized ++;
+ }
+ }
+ return resized > 0;
+ }
+
+
+
+ /**
+ * @return the windowSizes
+ */
+ public ArrayList getWindowSizes() {
+ if (windowSizes == null) {
+ windowSizes = new ArrayList<>();
+ }
+ return windowSizes;
+ }
+
+
+
+ /**
+ * @return the manualWindowSizes
+ */
+ public boolean isManualWindowSizes() {
+ return manualWindowSizes;
+ }
+
+ /**
+ * @param manualWindowSizes the manualWindowSizes to set
+ */
+ public void setManualWindowSizes(boolean manualWindowSizes) {
+ this.manualWindowSizes = manualWindowSizes;
+ }
+
+
+
+ private class WindowSizeData implements Serializable {
+
+ static public final long serialVersionUID = 1;
+
+ protected String windowClass;
+
+ public WindowSizeData(String windowClass, Point location, Dimension size) {
+ super();
+ this.windowClass = windowClass;
+ this.location = location;
+ this.size = size;
+ }
+
+ protected Point location;
+
+ protected Dimension size;
+
+ }
+
}
diff --git a/src/clickDetector/ClickParameters.java b/src/clickDetector/ClickParameters.java
index 3146b0e4..118eaf21 100644
--- a/src/clickDetector/ClickParameters.java
+++ b/src/clickDetector/ClickParameters.java
@@ -38,6 +38,7 @@ import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterData;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.GroupedSourceParameters;
import PamView.dialog.GroupedSourcePanel;
import PamView.paneloverlay.overlaymark.MarkDataSelectorParams;
@@ -441,7 +442,7 @@ public class ClickParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
PamParameterData param = ps.findParameterData("dbThreshold");
param.setShortName("Detection Threshold");
diff --git a/src/clickDetector/ClickSpectrumParams.java b/src/clickDetector/ClickSpectrumParams.java
index 6784c9fa..d18927e3 100644
--- a/src/clickDetector/ClickSpectrumParams.java
+++ b/src/clickDetector/ClickSpectrumParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class ClickSpectrumParams implements Serializable, Cloneable, ManagedParameters {
@@ -38,7 +39,7 @@ public class ClickSpectrumParams implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/clickDetector/ClickSpectrumTemplateParams.java b/src/clickDetector/ClickSpectrumTemplateParams.java
index ff156b0e..caad2b6e 100644
--- a/src/clickDetector/ClickSpectrumTemplateParams.java
+++ b/src/clickDetector/ClickSpectrumTemplateParams.java
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
@@ -39,7 +40,7 @@ public class ClickSpectrumTemplateParams implements Serializable, Cloneable, Man
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("clickTemplateArray");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/ClickTabPanel.java b/src/clickDetector/ClickTabPanel.java
index cf32c245..d969b5ca 100644
--- a/src/clickDetector/ClickTabPanel.java
+++ b/src/clickDetector/ClickTabPanel.java
@@ -72,9 +72,19 @@ public class ClickTabPanel extends JDesktopPane implements ComponentListener {
public void componentMoved(ComponentEvent e) {
}
+ /**
+ * This get's called during startup when the window is created and will
+ * automatically resize everything. IT may get called 2 or 3 times at startup
+ * as components such as the side bar sort themselves out.
+ */
public void componentResized(ComponentEvent e) {
// if (++resizeCount < 5) {
- arrangeWindows();
+ if (clickTabPanelControl.clickDisplayManager.cdmp.isManualWindowSizes() == false) {
+ arrangeWindows();
+ }
+ else {
+ clickTabPanelControl.clickDisplayManager.restoreWindowSizes();
+ }
// }
}
diff --git a/src/clickDetector/ClickTabPanelControl.java b/src/clickDetector/ClickTabPanelControl.java
index 4880521e..5e8f6491 100644
--- a/src/clickDetector/ClickTabPanelControl.java
+++ b/src/clickDetector/ClickTabPanelControl.java
@@ -26,6 +26,7 @@ import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
@@ -117,11 +118,29 @@ public class ClickTabPanelControl implements PamTabPanel {
menu.add(clickDisplayManager.getModulesMenu());
- menuItem = new JMenuItem("Arrange Windows ...");
+ menu.add(clickControl.angleVetoes.getDisplayMenuItem(parentFrame));
+
+ menu.addSeparator();
+
+ JCheckBoxMenuItem autoArrange = new JCheckBoxMenuItem("Auto arrange windows");
+ autoArrange.setSelected(clickDisplayManager.cdmp.isManualWindowSizes() == false);
+ autoArrange.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ clickDisplayManager.cdmp.setManualWindowSizes(autoArrange.isSelected() == false);
+ if (autoArrange.isSelected()) {
+ clickPanel.arrangeWindows();
+ }
+ }
+ });
+ autoArrange.setToolTipText("Automatically arrange windows in a standard layout whenever the display dimensions change");
+ menu.add(autoArrange);
+
+ menuItem = new JMenuItem("Arrange Windows Now");
menuItem.addActionListener(new ArrangeWindows(parentFrame));
+ menuItem.setToolTipText("Automatically arrange windows in a standard layout");
menu.add(menuItem);
- menu.add(clickControl.angleVetoes.getDisplayMenuItem(parentFrame));
return menu;
}
diff --git a/src/clickDetector/ConcatenatedSpectParams.java b/src/clickDetector/ConcatenatedSpectParams.java
index 6bf67108..db3f6a0b 100644
--- a/src/clickDetector/ConcatenatedSpectParams.java
+++ b/src/clickDetector/ConcatenatedSpectParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.ColourArray.ColourArrayType;
public class ConcatenatedSpectParams implements Serializable, Cloneable, ManagedParameters {
@@ -44,7 +45,7 @@ public class ConcatenatedSpectParams implements Serializable, Cloneable, Manage
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/clickDetector/IDI_DisplayParams.java b/src/clickDetector/IDI_DisplayParams.java
index 0198fe92..e7641768 100644
--- a/src/clickDetector/IDI_DisplayParams.java
+++ b/src/clickDetector/IDI_DisplayParams.java
@@ -29,6 +29,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
/**
@@ -270,7 +271,7 @@ public class IDI_DisplayParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("saveOutput");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/TrackedClickGroupLogging.java b/src/clickDetector/TrackedClickGroupLogging.java
index 6016f704..90e7af9a 100644
--- a/src/clickDetector/TrackedClickGroupLogging.java
+++ b/src/clickDetector/TrackedClickGroupLogging.java
@@ -1,5 +1,6 @@
package clickDetector;
+import generalDatabase.PamTableDefinition;
import generalDatabase.SQLTypes;
import PamguardMVC.PamDataUnit;
import clickDetector.offlineFuncs.OfflineEventDataUnit;
@@ -30,7 +31,8 @@ public class TrackedClickGroupLogging extends ClickGroupLogging {
boolean isUpdate = true;
// Timestamp ts = (Timestamp) getTableDefinition().getTimeStampItem().getValue();
// long t = PamCalendar.millisFromTimeStamp(ts);
- int updateIndex = (Integer) getTableDefinition().getUpdateReference().getValue();
+ PamTableDefinition tableDef = (PamTableDefinition) getTableDefinition();
+ int updateIndex = (Integer) tableDef.getUpdateReference().getValue();
if (updateIndex > 0) {
tcg = this.clickGroupDataBlock.findByDatabaseIndex(updateIndex);
}
diff --git a/src/clickDetector/WignerPlotOptions.java b/src/clickDetector/WignerPlotOptions.java
index 0ef46f2e..e05640a6 100644
--- a/src/clickDetector/WignerPlotOptions.java
+++ b/src/clickDetector/WignerPlotOptions.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class WignerPlotOptions implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class WignerPlotOptions implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/clickDetector/alarm/ClickAlarmParameters.java b/src/clickDetector/alarm/ClickAlarmParameters.java
index 3cc714b2..8bed53c6 100644
--- a/src/clickDetector/alarm/ClickAlarmParameters.java
+++ b/src/clickDetector/alarm/ClickAlarmParameters.java
@@ -7,6 +7,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamguardMVC.dataSelector.DataSelectParams;
@@ -127,7 +128,7 @@ public class ClickAlarmParameters extends DataSelectParams implements Cloneable,
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("eventTypes");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/clicktrains/ClickTrainIdParams.java b/src/clickDetector/clicktrains/ClickTrainIdParams.java
index 9f9b03c2..c6d4746f 100644
--- a/src/clickDetector/clicktrains/ClickTrainIdParams.java
+++ b/src/clickDetector/clicktrains/ClickTrainIdParams.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
/**
@@ -59,7 +60,7 @@ public class ClickTrainIdParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("dataVersion");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java b/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java
index 668fec3e..a8cc198c 100644
--- a/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java
+++ b/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java
@@ -8,6 +8,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamguardMVC.dataSelector.DataSelectParams;
@@ -91,7 +92,7 @@ public class ClickTrainDataSelect2Params extends DataSelectParams implements Clo
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("wantType");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/dataSelector/ClickTrainDataSelector2.java b/src/clickDetector/dataSelector/ClickTrainDataSelector2.java
index 0520b4fb..9bde5123 100644
--- a/src/clickDetector/dataSelector/ClickTrainDataSelector2.java
+++ b/src/clickDetector/dataSelector/ClickTrainDataSelector2.java
@@ -82,7 +82,7 @@ public class ClickTrainDataSelector2 extends DataSelector {
}
SQLLogging logging = getPamDataBlock().getLogging();
if (logging == null) return null; //cannot happen!
- PamTableDefinition tableDef = logging.getTableDefinition();
+ EmptyTableDefinition tableDef = logging.getTableDefinition();
if (params.isIncludeUnclassified()) {
return null;
}
diff --git a/src/clickDetector/dataSelector/ClickTrainSelectParameters.java b/src/clickDetector/dataSelector/ClickTrainSelectParameters.java
index 3cfc5189..75462778 100644
--- a/src/clickDetector/dataSelector/ClickTrainSelectParameters.java
+++ b/src/clickDetector/dataSelector/ClickTrainSelectParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.dataSelector.DataSelectParams;
import clickDetector.ClickParameters;
@@ -32,7 +33,7 @@ public class ClickTrainSelectParameters extends DataSelectParams implements Seri
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickDetector/echoDetection/JamieEchoParams.java b/src/clickDetector/echoDetection/JamieEchoParams.java
index ec00df42..e3cbadb5 100644
--- a/src/clickDetector/echoDetection/JamieEchoParams.java
+++ b/src/clickDetector/echoDetection/JamieEchoParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class JamieEchoParams implements Serializable, Cloneable, ManagedParameters {
@@ -31,7 +32,7 @@ public static final long serialVersionUID = 3L;
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickDetector/echoDetection/SimpleEchoParams.java b/src/clickDetector/echoDetection/SimpleEchoParams.java
index fe5eae8e..eb6095a1 100644
--- a/src/clickDetector/echoDetection/SimpleEchoParams.java
+++ b/src/clickDetector/echoDetection/SimpleEchoParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class SimpleEchoParams implements Serializable, Cloneable, ManagedParameters {
@@ -26,7 +27,7 @@ public class SimpleEchoParams implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickDetector/localisation/ClickLocParams.java b/src/clickDetector/localisation/ClickLocParams.java
index fcfaaff6..6a597258 100644
--- a/src/clickDetector/localisation/ClickLocParams.java
+++ b/src/clickDetector/localisation/ClickLocParams.java
@@ -7,6 +7,7 @@ import java.util.Arrays;
import Localiser.detectionGroupLocaliser.DetectionGroupOptions;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class ClickLocParams implements Serializable, Cloneable, DetectionGroupOptions, ManagedParameters {
@@ -110,7 +111,7 @@ public class ClickLocParams implements Serializable, Cloneable, DetectionGroupOp
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("internalVersion");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/clickDetector/offlineFuncs/ClicksOffline.java b/src/clickDetector/offlineFuncs/ClicksOffline.java
index 6628595e..4eff23ae 100644
--- a/src/clickDetector/offlineFuncs/ClicksOffline.java
+++ b/src/clickDetector/offlineFuncs/ClicksOffline.java
@@ -632,6 +632,7 @@ public class ClicksOffline {
OfflineEventDataUnit newUnit = new OfflineEventDataUnit(null, getNextEventColourIndex(), null);
newUnit = OfflineEventDialog.showDialog(win, clickControl, newUnit);
if (newUnit != null) {
+ clickControl.removeFromEvents(markedClicks);
newUnit.addSubDetections(markedClicks);
offlineEventDataBlock.addPamData(newUnit);
clickControl.setLatestOfflineEvent(newUnit);
diff --git a/src/clickDetector/offlineFuncs/DatabaseChecks.java b/src/clickDetector/offlineFuncs/DatabaseChecks.java
index 38bfe6a5..585bbf50 100644
--- a/src/clickDetector/offlineFuncs/DatabaseChecks.java
+++ b/src/clickDetector/offlineFuncs/DatabaseChecks.java
@@ -102,16 +102,17 @@ public class DatabaseChecks {
long resultTime;
long firstTime = Long.MAX_VALUE;
long lastTime = Long.MIN_VALUE;
+ PamTableDefinition pamTableDef = (PamTableDefinition) clickLogging.getTableDefinition();
try {
Statement stmt = con.getConnection().createStatement();
ResultSet result = stmt.executeQuery(sqlStr);
while (result.next()) {
nClicks++;
clickLogging.transferDataFromResult(sqlTypes, result);
- ts = clickLogging.getTableDefinition().getTimeStampItem().getValue();
+ ts = pamTableDef.getTimeStampItem().getValue();
resultTime = sqlTypes.millisFromTimeStamp(ts);
if (resultTime%1000 == 0) {
- resultTime += clickLogging.getTableDefinition().getTimeStampMillis().getIntegerValue();
+ resultTime += pamTableDef.getTimeStampMillis().getIntegerValue();
}
firstTime = Math.min(firstTime, resultTime);
lastTime = Math.max(lastTime, resultTime);
@@ -188,7 +189,7 @@ public class DatabaseChecks {
eventDataBlock.addPamData(event);
PamConnection con = DBControlUnit.findConnection();
// now find a cursor and save it.
- PamTableDefinition eventTableDef = eventDataBlock.getLogging().getTableDefinition();
+ PamTableDefinition eventTableDef = (PamTableDefinition) eventDataBlock.getLogging().getTableDefinition();
PamCursor cursor = eventDataBlock.getLogging().getViewerCursorFinder().getCursor(con, eventTableDef);
cursor.immediateInsert(con);
int newId = event.getDatabaseIndex();
diff --git a/src/clickDetector/offlineFuncs/LabelClicksDialog.java b/src/clickDetector/offlineFuncs/LabelClicksDialog.java
index 0e25b495..113f7864 100644
--- a/src/clickDetector/offlineFuncs/LabelClicksDialog.java
+++ b/src/clickDetector/offlineFuncs/LabelClicksDialog.java
@@ -146,6 +146,7 @@ public class LabelClicksDialog extends PamDialog {
* @param thenClose option to close dialog
*/
private void addClicksToEvent(OfflineEventDataUnit event, boolean thenClose) {
+ removeFromOldEvent(markedClicks);
event.addSubDetections(markedClicks);
offlineEventListPanel.tableDataChanged();
clickControl.setLatestOfflineEvent(event);
@@ -154,6 +155,15 @@ public class LabelClicksDialog extends PamDialog {
}
}
+ /**
+ * clicks may have already been part of an event, so need to remove them from that
+ * event first, and if there is nothing left in that event, delete the event.
+ * @param markedClicks2
+ */
+ private void removeFromOldEvent(List markedClicks) {
+ clickControl.removeFromEvents(markedClicks);
+ }
+
@Override
public void restoreDefaultSettings() {
// TODO Auto-generated method stub
diff --git a/src/clickDetector/offlineFuncs/OfflineClickLogging.java b/src/clickDetector/offlineFuncs/OfflineClickLogging.java
index a75897f7..43a73fea 100644
--- a/src/clickDetector/offlineFuncs/OfflineClickLogging.java
+++ b/src/clickDetector/offlineFuncs/OfflineClickLogging.java
@@ -51,7 +51,7 @@ public class OfflineClickLogging extends SQLLogging {
tableDef.addTableItem(clickNumber = new PamTableItem("ClickNo", Types.INTEGER));
tableDef.addTableItem(amplitude = new PamTableItem("Amplitude", Types.DOUBLE));
tableDef.addTableItem(channelNumbers = new PamTableItem("Channels", Types.INTEGER));
- tableDef.setUseCheatIndexing(true);
+ tableDef.setUseCheatIndexing(false);
setTableDefinition(tableDef);
}
@@ -277,13 +277,14 @@ public class OfflineClickLogging extends SQLLogging {
Integer millis;
Object ts;
SQLTypes sqlTypes = dbControl.getConnection().getSqlTypes();
+ PamTableDefinition tableDef = (PamTableDefinition) getTableDefinition();
try {
while (resultSet.next()) {
transferDataFromResult(sqlTypes, resultSet);
- ts = getTableDefinition().getTimeStampItem().getValue();
+ ts = tableDef.getTimeStampItem().getValue();
long m = SQLTypes.millisFromTimeStamp(ts);
if (m%1000 == 0) {
- millis = (Integer) getTableDefinition().getTimeStampMillis().getValue();
+ millis = (Integer) tableDef.getTimeStampMillis().getValue();
if (millis != null) {
m += millis;
}
diff --git a/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java b/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java
index 4af5872b..afc60ec7 100644
--- a/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java
+++ b/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java
@@ -16,6 +16,10 @@ import PamController.PamViewParameters;
import PamUtils.PamCalendar;
import PamView.symbol.StandardSymbolManager;
import pamScrollSystem.ViewLoadObserver;
+import tethys.TethysControl;
+import tethys.pamdata.TethysDataProvider;
+import tethys.species.DataBlockSpeciesManager;
+import clickDetector.ClickDetection;
//import staticLocaliser.StaticLocaliserControl;
//import staticLocaliser.StaticLocaliserProvider;
//import staticLocaliser.panels.AbstractLocaliserControl;
@@ -23,7 +27,12 @@ import pamScrollSystem.ViewLoadObserver;
import clickDetector.ClickDetector;
import clickDetector.ClickTrainDetection;
import clickDetector.dataSelector.ClickTrainDataSelectorCreator;
+import clickDetector.tethys.ClickEventSpeciesManager;
+import clickDetector.tethys.ClickEventTethysDataProvider;
+import clickDetector.tethys.ClickTethysDataProvider;
import dataMap.OfflineDataMap;
+import PamguardMVC.DataAutomation;
+import PamguardMVC.DataAutomationInfo;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import PamguardMVC.dataOffline.OfflineDataLoadInfo;
@@ -49,6 +58,8 @@ public class OfflineEventDataBlock extends SuperDetDataBlock getDatablockSpeciesManager() {
+ if (eventSpeciesManager == null) {
+ eventSpeciesManager = new ClickEventSpeciesManager(clickDetector, this);
+ }
+ return eventSpeciesManager;
+ }
+
+ @Override
+ public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) {
+ if (eventTethysDataProvider == null) {
+ eventTethysDataProvider = new ClickEventTethysDataProvider(tethysControl, this);
+ }
+ return eventTethysDataProvider;
+ }
+
+ @Override
+ public DataAutomationInfo getDataAutomationInfo() {
+ return new DataAutomationInfo(DataAutomation.MANUALANDAUTOMATIC);
+ }
+
}
diff --git a/src/clickDetector/offlineFuncs/OfflineParameters.java b/src/clickDetector/offlineFuncs/OfflineParameters.java
index 2ab82962..0c4b2c71 100644
--- a/src/clickDetector/offlineFuncs/OfflineParameters.java
+++ b/src/clickDetector/offlineFuncs/OfflineParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class OfflineParameters implements Serializable, Cloneable, ManagedParameters {
@@ -28,7 +29,7 @@ public class OfflineParameters implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java b/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java
index d4fb6fb2..0b9b0996 100644
--- a/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java
+++ b/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java
@@ -148,7 +148,7 @@ public class RainbowDatabseConverter {
ClickDataBlock clickDataBlock = clickControl.getClickDataBlock();
clickLogging = new ClickImportLogging(clickControl);
- PamTableDefinition tableDef = clickLogging.getTableDefinition();
+ PamTableDefinition tableDef = (PamTableDefinition) clickLogging.getTableDefinition();
boolean ok = checkTable(pamConnection, tableDef);
if (!ok) {
System.out.println("Error in Pamguard clicks table");
@@ -156,7 +156,7 @@ public class RainbowDatabseConverter {
}
eventLogging = new OfflineEventLogging(clickControl, clickControl.getClickDetector().getOfflineEventDataBlock());
- tableDef = eventLogging.getTableDefinition();
+ tableDef = (PamTableDefinition) eventLogging.getTableDefinition();
ok = checkTable(pamConnection, tableDef);
if (!ok) {
System.out.println("Error in Pamguard events table");
diff --git a/src/clickDetector/tethys/ClickEventSpeciesManager.java b/src/clickDetector/tethys/ClickEventSpeciesManager.java
new file mode 100644
index 00000000..c0ee92fd
--- /dev/null
+++ b/src/clickDetector/tethys/ClickEventSpeciesManager.java
@@ -0,0 +1,57 @@
+package clickDetector.tethys;
+
+import java.util.Vector;
+
+import PamguardMVC.PamDataUnit;
+import clickDetector.ClickControl;
+import clickDetector.ClickDetector;
+import clickDetector.offlineFuncs.ClicksOffline;
+import clickDetector.offlineFuncs.OfflineEventDataBlock;
+import clickDetector.offlineFuncs.OfflineEventDataUnit;
+import generalDatabase.lookupTables.LookUpTables;
+import generalDatabase.lookupTables.LookupItem;
+import generalDatabase.lookupTables.LookupList;
+import tethys.species.DataBlockSpeciesCodes;
+import tethys.species.DataBlockSpeciesManager;
+
+public class ClickEventSpeciesManager extends DataBlockSpeciesManager {
+
+ private OfflineEventDataBlock eventDataBlock;
+ private ClickDetector clickDetector;
+ private ClickControl clickControl;
+ private ClicksOffline clicksOffline;
+
+ public ClickEventSpeciesManager(ClickDetector clickDetector, OfflineEventDataBlock eventDataBlock) {
+ super(eventDataBlock);
+ this.clickDetector = clickDetector;
+ this.eventDataBlock = eventDataBlock;
+ clickControl = clickDetector.getClickControl();
+ clicksOffline = clickControl.getClicksOffline();
+ }
+
+ @Override
+ public DataBlockSpeciesCodes getSpeciesCodes() {
+ LookupList lutList = LookUpTables.getLookUpTables().getLookupList(ClicksOffline.ClickTypeLookupName);
+ if (lutList == null || lutList.getLutList().size() == 0) {
+ return new DataBlockSpeciesCodes("Unknown");
+ }
+ Vector spList = lutList.getLutList();
+ String[] spNames = new String[spList.size()];
+ int i = 0;
+ for (LookupItem lItem : spList) {
+ spNames[i++] = lItem.getCode();
+ }
+ return new DataBlockSpeciesCodes("Unknown", spNames);
+ }
+
+ @Override
+ public String getSpeciesCode(PamDataUnit dataUnit) {
+ OfflineEventDataUnit eventDataUnit = (OfflineEventDataUnit) dataUnit;
+ String eventType = eventDataUnit.getEventType();
+ if (eventType == null) {
+ eventType = "Unknown";
+ }
+ return eventType;
+ }
+
+}
diff --git a/src/clickDetector/tethys/ClickEventTethysDataProvider.java b/src/clickDetector/tethys/ClickEventTethysDataProvider.java
new file mode 100644
index 00000000..bbc5d1fd
--- /dev/null
+++ b/src/clickDetector/tethys/ClickEventTethysDataProvider.java
@@ -0,0 +1,72 @@
+package clickDetector.tethys;
+
+import java.math.BigInteger;
+
+import PamguardMVC.PamDataUnit;
+import clickDetector.offlineFuncs.OfflineEventDataBlock;
+import clickDetector.offlineFuncs.OfflineEventDataUnit;
+import nilus.Detection;
+import nilus.GranularityEnumType;
+import nilus.Detection.Parameters;
+import nilus.Detection.Parameters.UserDefined;
+import tethys.TethysControl;
+import tethys.output.StreamExportParams;
+import tethys.output.TethysExportParams;
+import tethys.pamdata.AutoTethysProvider;
+import tethys.swing.export.ExportWizardCard;
+import tethys.swing.export.GranularityCard;
+
+public class ClickEventTethysDataProvider extends AutoTethysProvider {
+
+ private OfflineEventDataBlock eventDataBlock;
+
+ public ClickEventTethysDataProvider(TethysControl tethysControl, OfflineEventDataBlock eventDataBlock) {
+ super(tethysControl, eventDataBlock);
+ this.eventDataBlock = eventDataBlock;
+ }
+
+ @Override
+ public GranularityEnumType[] getAllowedGranularities() {
+ GranularityEnumType[] allowed = {GranularityEnumType.GROUPED};
+ return allowed;
+ }
+ @Override
+ public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams,
+ StreamExportParams streamExportParams) {
+ Detection detection = super.createDetection(dataUnit, tethysExportParams, streamExportParams);
+ if (detection == null) {
+ return null;
+ }
+ OfflineEventDataUnit eventDataUnit = (OfflineEventDataUnit) dataUnit;
+ detection.setCount(BigInteger.valueOf(eventDataUnit.getSubDetectionsCount()));
+ String comment = eventDataUnit.getComment();
+ if (comment != null && comment.length() > 0) {
+ detection.setComment(comment);
+ }
+ Parameters params = detection.getParameters();
+ addUserNumber(params, "MinNumber", eventDataUnit.getMinNumber());
+ addUserNumber(params, "BestNumber", eventDataUnit.getBestNumber());
+ addUserNumber(params, "MaxNumber", eventDataUnit.getMaxNumber());
+
+
+ return detection;
+ }
+
+ private void addUserNumber(Parameters params, String numName, Short number) {
+ if (number == null) {
+ return;
+ }
+ addUserDefined(params, numName, number.toString());
+ }
+
+ @Override
+ public boolean wantExportDialogCard(ExportWizardCard wizPanel) {
+ if (wizPanel.getClass() == GranularityCard.class) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+}
diff --git a/src/clickDetector/tethys/ClickTethysDataProvider.java b/src/clickDetector/tethys/ClickTethysDataProvider.java
new file mode 100644
index 00000000..44e1c8c8
--- /dev/null
+++ b/src/clickDetector/tethys/ClickTethysDataProvider.java
@@ -0,0 +1,22 @@
+package clickDetector.tethys;
+
+import clickDetector.ClickDataBlock;
+import nilus.GranularityEnumType;
+import tethys.TethysControl;
+import tethys.pamdata.AutoTethysProvider;
+
+public class ClickTethysDataProvider extends AutoTethysProvider {
+
+ private ClickDataBlock clickDataBlock;
+
+ public ClickTethysDataProvider(TethysControl tethysControl, ClickDataBlock clickDataBlock) {
+ super(tethysControl, clickDataBlock);
+ this.clickDataBlock = clickDataBlock;
+ }
+
+ @Override
+ public GranularityEnumType[] getAllowedGranularities() {
+ return GranularityEnumType.values(); // everything !
+ }
+
+}
diff --git a/src/clickTrainDetector/ClickTrainParams.java b/src/clickTrainDetector/ClickTrainParams.java
index 1200883d..0a3663b9 100644
--- a/src/clickTrainDetector/ClickTrainParams.java
+++ b/src/clickTrainDetector/ClickTrainParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamUtils;
import clickTrainDetector.classification.CTClassifierParams;
import clickTrainDetector.classification.simplechi2classifier.Chi2ThresholdParams;
@@ -127,7 +128,7 @@ public class ClickTrainParams implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickTrainDetector/classification/CTClassifierParams.java b/src/clickTrainDetector/classification/CTClassifierParams.java
index 91d4e8a7..64fa96e9 100644
--- a/src/clickTrainDetector/classification/CTClassifierParams.java
+++ b/src/clickTrainDetector/classification/CTClassifierParams.java
@@ -5,6 +5,7 @@ import java.util.UUID;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
@@ -68,7 +69,7 @@ public class CTClassifierParams implements Cloneable, Serializable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java b/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java
index 83a326c8..b3e26d12 100644
--- a/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java
+++ b/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
*
@@ -53,7 +54,7 @@ public class SpectrumTemplateParams implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java
index 499fee9f..046c6478 100644
--- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java
+++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Parameters class must extend this.
@@ -38,7 +39,7 @@ public class MHTChi2Params implements Cloneable, Serializable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java
index 43b58860..bf312d7e 100644
--- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java
+++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java
@@ -45,6 +45,7 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings
public static final String MHT_NAME = "MHT detector";
+
/**
* Reference to the click train control.
*/
@@ -354,6 +355,7 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings
TrackBitSet trackBitSet;
TrackDataUnits trackUnits;
if (nTracks>0) Debug.out.println("-------------------Grab Done Trains---------------");
+ try {
for (int i =0; i0) Debug.out.println("-------------------------------------------------");
@@ -415,12 +421,19 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings
return mhtGUI;
}
+ Thread previousThread = null;
/**
* Update the algorithm
* @param flag- flag indicating the update type.
*/
- public void update(int flag, Object info) {
+ public synchronized void update(int flag, Object info) {
+ if (Thread.currentThread() != previousThread) {
+ // see flag id constants in ClickTrianControl
+ System.out.printf("Thread change to %s in MHTClicktrainAlgorithm.update flag %d, object %s\n",
+ Thread.currentThread().toString(), flag, info);
+ previousThread = Thread.currentThread();
+ }
switch (flag) {
case ClickTrainControl.PROCESSING_START:
//make sure the kernel is cleared before processing
diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java
index 9666a3c2..585d5d39 100644
--- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java
+++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java
@@ -3,6 +3,7 @@ package clickTrainDetector.clickTrainAlgorithms.mht;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
+import java.util.Comparator;
import PamUtils.PamArrayUtils;
import PamguardMVC.debug.Debug;
@@ -285,28 +286,39 @@ public class MHTKernel {
BitSet currentBitSet;
MHTChi2 mhtChi2;
int index;
- for (int i=0; i {
//first sort the tracks by increasing chi2 values.
//sort the possible tracks by chi2 values
//now sort the chi2 values so they correspond to the track list.
- Collections.sort(newPossibleTracks, (left, right)->{
- //Note- this is definitely in the correct order
- return Double.compare(left.chi2Track.getChi2(), right.chi2Track.getChi2());
- });
+// Collections.sort(newPossibleTracks, (left, right)->{
+// //Note- this is definitely in the correct order
+// return Double.compare(left.chi2Track.getChi2(), right.chi2Track.getChi2());
+// });
+ try {
+ Collections.sort(newPossibleTracks, new Comparator() {
+ @Override
+ public int compare(TrackBitSet left, TrackBitSet right) {
+ return Double.compare(left.chi2Track.getChi2(), right.chi2Track.getChi2());
+ }
+ });
+ }
+ catch (Exception e) {
+ System.out.printf("Handled MHTKernel Exception %s in pruneProbMatrix: %s\n", e.getClass().getSimpleName(), e.getMessage());
+ }
// for (int i=0; i checkAllDatagrams() {
ArrayList grammedDataBlocks = getDataBlocks();
ArrayList updateBlocks = new ArrayList();
+ boolean isBatch = GlobalArguments.getParam("-batch") != null;
/**
* Check to see if any of the blocks have an existing datagram
*/
- if (datagramSettings.validDatagramSettings == false) {
+ if (datagramSettings.validDatagramSettings == false && isBatch == false) {
/*
* this is the first time this has been run, so ask
* the user what datagram size they want.
@@ -169,6 +171,8 @@ public class DatagramManager {
private volatile DatagramProgressDialog datagramProgressDialog;
+ private volatile DatagramCreator datagramCreator;
+
/**
* update a list of datagrams. This should be done in a
@@ -176,9 +180,17 @@ public class DatagramManager {
* @param updateList
*/
public void updateDatagrams(ArrayList updateList) {
- DatagramCreator datagramCreator = new DatagramCreator(updateList);
+ datagramCreator = new DatagramCreator(updateList);
AWTScheduler.getInstance().scheduleTask(datagramCreator);
}
+
+ /**
+ * Get true if the datagram worker is running.
+ * @return
+ */
+ public boolean getStatus() {
+ return datagramCreator != null;
+ }
class DatagramCreatorTask extends Task {
@@ -542,6 +554,7 @@ public class DatagramManager {
publish(new DatagramProgress(PamTaskUpdate.STATUS_DONE, 1, 1));
}
+ datagramCreator = null;
}
@Override
diff --git a/src/dataGram/DatagramSettings.java b/src/dataGram/DatagramSettings.java
index e466d55d..a3b5a4df 100644
--- a/src/dataGram/DatagramSettings.java
+++ b/src/dataGram/DatagramSettings.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DatagramSettings implements Serializable, Cloneable, ManagedParameters {
@@ -33,7 +34,7 @@ public class DatagramSettings implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataMap/DataMapParameters.java b/src/dataMap/DataMapParameters.java
index 22eed747..cd714199 100644
--- a/src/dataMap/DataMapParameters.java
+++ b/src/dataMap/DataMapParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DataMapParameters implements Cloneable, Serializable, ManagedParameters {
@@ -36,7 +37,7 @@ public class DataMapParameters implements Cloneable, Serializable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataMap/DataStreamPanel.java b/src/dataMap/DataStreamPanel.java
index 957eadfd..275be1f5 100644
--- a/src/dataMap/DataStreamPanel.java
+++ b/src/dataMap/DataStreamPanel.java
@@ -747,11 +747,20 @@ public class DataStreamPanel extends JPanel implements DataMapObserver {
String tipText;
if (startTimeArrow != null && startTimeArrow.contains(me.getPoint())) {
- tipText = "Data Start: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataStart(), true);
+ tipText = "Data Start: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataStart(), false);
} else if (endTimeArrow != null && endTimeArrow.contains(me.getPoint())) {
- tipText = "Data End: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataEnd(), true);
+ tipText = "Data End: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataEnd(), false);
} else {
- tipText = "Cursor: " + PamCalendar.formatDateTime(tm, true);
+ OfflineDataMap dMap = dataBlock.getPrimaryDataMap();
+ if (dMap != null) {
+ tipText = String.format("%s Data from%s to %s
Cursor: %s", dataBlock.getDataName(),
+ PamCalendar.formatDateTime(dMap.getFirstDataTime(), false),
+ PamCalendar.formatDateTime(dMap.getLastDataTime(), false),
+ PamCalendar.formatDateTime(tm, true));
+ }
+ else {
+ tipText = "Cursor: " + PamCalendar.formatDateTime(tm, true);
+ }
}
// tipText += " Panel height = " + getHeight();
diff --git a/src/dataMap/OfflineDataMap.java b/src/dataMap/OfflineDataMap.java
index 2295af01..d51ee120 100644
--- a/src/dataMap/OfflineDataMap.java
+++ b/src/dataMap/OfflineDataMap.java
@@ -84,6 +84,8 @@ abstract public class OfflineDataMap {
public static final int POINT_END = 0x8; // 8
public static final int IN_DATA = 0x10; // 16
public static final int NO_DATA = 0x20; // 32
+
+ private static final long oneDayInMillis = 3600L*24L*1000L;
public OfflineDataMap(OfflineDataStore offlineDataStore, PamDataBlock parentDataBlock) {
super();
@@ -145,10 +147,10 @@ abstract public class OfflineDataMap {
*/
synchronized public void addDataPoint(TmapPoint mapPoint) {
boolean first = (mapPoints.size() == 0);
- if (mapPoint.getStartTime() > 0) {
+ if (mapPoint.getStartTime() > oneDayInMillis) {
firstDataTime = Math.min(firstDataTime, mapPoint.getStartTime());
}
- if (mapPoint.getEndTime() > 0) {
+ if (mapPoint.getEndTime() > oneDayInMillis) {
lastDataTime = Math.max(lastDataTime, mapPoint.getEndTime());
// if (mapPoint.getEndTime() > System.currentTimeMillis()) {
// System.out.println("Stupid large data time in " + mapPoint.getName());
@@ -273,10 +275,10 @@ abstract public class OfflineDataMap {
while (it.hasNext()) {
aPoint = it.next();
- if (aPoint.getStartTime() > 0) {
+ if (aPoint.getStartTime() > oneDayInMillis) {
firstDataTime = Math.min(firstDataTime, aPoint.getStartTime());
}
- if (aPoint.getEndTime() > 0) {
+ if (aPoint.getEndTime() > oneDayInMillis) {
lastDataTime = Math.max(lastDataTime, aPoint.getEndTime());
}
n = aPoint.getNDatas();
@@ -361,6 +363,28 @@ abstract public class OfflineDataMap {
}
}
+ /**
+ * Get the start time of the first datamap point or Long.minval
+ * @return
+ */
+ public long getMapStartTime() {
+ if (mapPoints == null || mapPoints.size() == 0) {
+ return Long.MIN_VALUE;
+ }
+ return mapPoints.get(0).getStartTime();
+ }
+
+ /**
+ * Get the start time of the first datamap point or Long.minval
+ * @return
+ */
+ public long getMapEndTime() {
+ if (mapPoints == null || mapPoints.size() == 0) {
+ return Long.MIN_VALUE;
+ }
+ return mapPoints.get(mapPoints.size()-1).getEndTime();
+ }
+
/**
* @return the lowestPoint
*/
diff --git a/src/dataMap/OfflineDataMapPoint.java b/src/dataMap/OfflineDataMapPoint.java
index af9e1910..d1e8917c 100644
--- a/src/dataMap/OfflineDataMapPoint.java
+++ b/src/dataMap/OfflineDataMapPoint.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamCalendar;
/**
@@ -251,7 +252,7 @@ abstract public class OfflineDataMapPoint implements Comparable impl
// TODO Auto-generated method stub
return "Sound Files";
}
+
+ @Override
+ public String getDataLocation() {
+ getOfflineFileParameters();
+ return offlineFileParameters.folderName;
+ }
public TmapPoint findFirstMapPoint(Iterator mapIterator, long startMillis, long endMillis) {
TmapPoint mapPoint, prevMapPoint = null;
diff --git a/src/dataPlots/TDParameters.java b/src/dataPlots/TDParameters.java
index 80d67871..bb7f14db 100644
--- a/src/dataPlots/TDParameters.java
+++ b/src/dataPlots/TDParameters.java
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import dataPlots.layout.GraphParameters;
import pamScrollSystem.PamScroller;
@@ -45,7 +46,7 @@ public class TDParameters implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataPlots/layout/DataListInfo.java b/src/dataPlots/layout/DataListInfo.java
index 05edd3f8..d506fe64 100644
--- a/src/dataPlots/layout/DataListInfo.java
+++ b/src/dataPlots/layout/DataListInfo.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* TDDataInfo objects can't be serialised since they contain
@@ -44,7 +45,7 @@ public class DataListInfo implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataPlots/layout/GraphParameters.java b/src/dataPlots/layout/GraphParameters.java
index f505422e..5fc3fe2a 100644
--- a/src/dataPlots/layout/GraphParameters.java
+++ b/src/dataPlots/layout/GraphParameters.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import dataPlots.data.TDDataInfo;
@@ -41,7 +42,7 @@ public class GraphParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("dataListInfos");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/dataPlotsFX/TDGraphParametersFX.java b/src/dataPlotsFX/TDGraphParametersFX.java
index c4d6de46..f3f6c691 100644
--- a/src/dataPlotsFX/TDGraphParametersFX.java
+++ b/src/dataPlotsFX/TDGraphParametersFX.java
@@ -8,6 +8,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.GeneralProjector.ParameterType;
import PamView.GeneralProjector.ParameterUnits;
import javafx.scene.paint.Color;
@@ -137,7 +138,7 @@ public class TDGraphParametersFX implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("channels");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/dataPlotsFX/TDParametersFX.java b/src/dataPlotsFX/TDParametersFX.java
index c87320bc..8b614dcc 100644
--- a/src/dataPlotsFX/TDParametersFX.java
+++ b/src/dataPlotsFX/TDParametersFX.java
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import javafx.geometry.Orientation;
import userDisplayFX.UserDisplayNodeParams;
@@ -122,7 +123,7 @@ public class TDParametersFX implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataPlotsFX/data/TDScaleInfoData.java b/src/dataPlotsFX/data/TDScaleInfoData.java
index a0d54dba..9cd2ea3c 100644
--- a/src/dataPlotsFX/data/TDScaleInfoData.java
+++ b/src/dataPlotsFX/data/TDScaleInfoData.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamguardMVC.PamConstants;
@@ -105,7 +106,7 @@ public class TDScaleInfoData implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("autoDivisor");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java b/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java
index 388ea462..ec6a1030 100644
--- a/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java
+++ b/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamController.PamController;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType;
@@ -48,7 +49,7 @@ public class FFTPlotSettings implements ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java b/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java
index c39aeb96..de80f049 100644
--- a/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java
+++ b/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import dataPlotsFX.scrollingPlot2D.StandardPlot2DColours;
import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType;
@@ -55,7 +56,7 @@ public class TDAcousticScrollerParams implements Cloneable, Serializable, Manage
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java b/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java
index 159fa2ad..40aed7c7 100644
--- a/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java
+++ b/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamController.PamController;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.paint.Color;
@@ -156,7 +157,7 @@ public class PlotParams2D implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java b/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java
index 7aafc8ad..a8f2faa2 100644
--- a/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java
+++ b/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import dataPlotsFX.scrollingPlot2D.PlotParams2D;
import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType;
import javafx.beans.property.DoubleProperty;
@@ -125,7 +126,7 @@ public class SpectrogramParamsFX extends PlotParams2D implements Serializable,
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dbht/DbHtDisplayParams.java b/src/dbht/DbHtDisplayParams.java
index 61e8386c..fb7cab16 100644
--- a/src/dbht/DbHtDisplayParams.java
+++ b/src/dbht/DbHtDisplayParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DbHtDisplayParams implements Serializable, Cloneable, ManagedParameters {
@@ -40,7 +41,7 @@ public class DbHtDisplayParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/dbht/DbHtParameters.java b/src/dbht/DbHtParameters.java
index 7ef321f7..2e32bb3e 100644
--- a/src/dbht/DbHtParameters.java
+++ b/src/dbht/DbHtParameters.java
@@ -9,6 +9,7 @@ import PamModel.parametermanager.FieldNotFoundException;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterData;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class DbHtParameters implements Serializable, Cloneable, ManagedParameters {
@@ -186,7 +187,7 @@ public class DbHtParameters implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("frequencyPoints");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/dbht/alarm/DbHtAlarmParameters.java b/src/dbht/alarm/DbHtAlarmParameters.java
index beb98589..5023e1ae 100644
--- a/src/dbht/alarm/DbHtAlarmParameters.java
+++ b/src/dbht/alarm/DbHtAlarmParameters.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class DbHtAlarmParameters implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class DbHtAlarmParameters implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("returnedMeasure");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/dbht/offline/DbHtSummaryParams.java b/src/dbht/offline/DbHtSummaryParams.java
index b77adf17..34c4951a 100644
--- a/src/dbht/offline/DbHtSummaryParams.java
+++ b/src/dbht/offline/DbHtSummaryParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DbHtSummaryParams implements Serializable, Cloneable, ManagedParameters {
@@ -23,7 +24,7 @@ public class DbHtSummaryParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/decimator/DecimatorControl.java b/src/decimator/DecimatorControl.java
index 9be3d77b..4b09dc29 100644
--- a/src/decimator/DecimatorControl.java
+++ b/src/decimator/DecimatorControl.java
@@ -202,6 +202,15 @@ public class DecimatorControl extends PamControlledUnit implements PamSettings,
}
return offlineFileServer.getDataSourceName();
}
+
+ @Override
+ public String getDataLocation() {
+ if (offlineFileServer == null) {
+ return getUnitName();
+ }
+ return offlineFileServer.getDataLocation();
+ }
+
@Override
public boolean loadData(PamDataBlock dataBlock, OfflineDataLoadInfo offlineDataLoadInfo, ViewLoadObserver loadObserver) {
if (offlineFileServer == null) {
diff --git a/src/decimator/DecimatorParams.java b/src/decimator/DecimatorParams.java
index 6f37fbf8..21e29ce4 100644
--- a/src/decimator/DecimatorParams.java
+++ b/src/decimator/DecimatorParams.java
@@ -26,6 +26,7 @@ import Filters.FilterBand;
import Filters.FilterParams;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DecimatorParams implements Serializable, Cloneable, ManagedParameters {
@@ -102,7 +103,7 @@ public class DecimatorParams implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/decimator/DecimatorProcessW.java b/src/decimator/DecimatorProcessW.java
index 3ade7634..e99260bb 100644
--- a/src/decimator/DecimatorProcessW.java
+++ b/src/decimator/DecimatorProcessW.java
@@ -41,8 +41,10 @@ public class DecimatorProcessW extends PamProcess {
@Override
public void pamStart() {
- // TODO Auto-generated method stub
-
+ outputDataBlock.reset();
+ if (decimatorWorker != null) {
+ decimatorWorker.reset();
+ }
}
@Override
diff --git a/src/decimator/DecimatorWorker.java b/src/decimator/DecimatorWorker.java
index db3b4104..21908a12 100644
--- a/src/decimator/DecimatorWorker.java
+++ b/src/decimator/DecimatorWorker.java
@@ -77,6 +77,13 @@ public class DecimatorWorker {
createFilters();
}
+ /**
+ * Reset all counters and output buffers.
+ */
+ public void reset() {
+ createFilters();
+ }
+
/**
* Make the decimator filters. If reducing frequency, then the filter
* is applied before decimation (obviously!) so is set up based on the
diff --git a/src/depthReadout/DepthParameters.java b/src/depthReadout/DepthParameters.java
index 1e40df4e..99dcdd25 100644
--- a/src/depthReadout/DepthParameters.java
+++ b/src/depthReadout/DepthParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DepthParameters implements Serializable, Cloneable, ManagedParameters {
@@ -37,7 +38,7 @@ public class DepthParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/depthReadout/MccDepthParameters.java b/src/depthReadout/MccDepthParameters.java
index 7859a1a7..d027670a 100644
--- a/src/depthReadout/MccDepthParameters.java
+++ b/src/depthReadout/MccDepthParameters.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import mcc.MccJniInterface;
import mcc.mccjna.MCCConstants;
@@ -44,7 +45,7 @@ public class MccDepthParameters implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
@@ -62,7 +63,7 @@ public class MccDepthParameters implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("mccSensorParameters");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/detectionPlotFX/plots/FFTPlotParams.java b/src/detectionPlotFX/plots/FFTPlotParams.java
index 483f9051..3b8a428d 100644
--- a/src/detectionPlotFX/plots/FFTPlotParams.java
+++ b/src/detectionPlotFX/plots/FFTPlotParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamController.PamController;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType;
public class FFTPlotParams implements Serializable, Cloneable, ManagedParameters {
@@ -98,7 +99,7 @@ public class FFTPlotParams implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/detectionPlotFX/plots/SpectrumPlotParams.java b/src/detectionPlotFX/plots/SpectrumPlotParams.java
index 36d1807e..c0790a9a 100644
--- a/src/detectionPlotFX/plots/SpectrumPlotParams.java
+++ b/src/detectionPlotFX/plots/SpectrumPlotParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class SpectrumPlotParams implements Serializable, Cloneable, ManagedParameters {
@@ -38,7 +39,7 @@ public class SpectrumPlotParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/detectionPlotFX/plots/WaveformPlotParams.java b/src/detectionPlotFX/plots/WaveformPlotParams.java
index 0c631272..fefc68b5 100644
--- a/src/detectionPlotFX/plots/WaveformPlotParams.java
+++ b/src/detectionPlotFX/plots/WaveformPlotParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import depthReadout.DepthParameters;
import fftFilter.FFTFilterParams;
@@ -63,7 +64,7 @@ public class WaveformPlotParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/detectionPlotFX/plots/WignerPlotParams.java b/src/detectionPlotFX/plots/WignerPlotParams.java
index 0dece899..15f38498 100644
--- a/src/detectionPlotFX/plots/WignerPlotParams.java
+++ b/src/detectionPlotFX/plots/WignerPlotParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType;
@@ -51,7 +52,7 @@ public class WignerPlotParams implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/detectiongrouplocaliser/DetectionGroupProcess.java b/src/detectiongrouplocaliser/DetectionGroupProcess.java
index 3c5158fb..587b3719 100644
--- a/src/detectiongrouplocaliser/DetectionGroupProcess.java
+++ b/src/detectiongrouplocaliser/DetectionGroupProcess.java
@@ -458,6 +458,7 @@ public class DetectionGroupProcess extends PamProcess {
detectionGroupDataBlock.saveViewerData();
int nUpdates = 0;
int nOK = 0;
+ int consecutiveOK = 0;
System.out.printf("Checking %d data units in %s ", detectionGroupDataBlock.getUnitsCount(), detectionGroupDataBlock.getDataName());
synchronized (detectionGroupDataBlock.getSynchLock()) {
ListIterator it = detectionGroupDataBlock.getListIterator(0);
@@ -466,11 +467,16 @@ public class DetectionGroupProcess extends PamProcess {
boolean ok = checkDataIntegrity(du, false);
if (ok) {
nUpdates++;
+ consecutiveOK = 0;
}
else {
nOK++;
+ consecutiveOK++;
}
System.out.printf(".");
+ if (consecutiveOK % 80 == 0) {
+ System.out.printf("\n");
+ }
}
}
System.out.printf("\n%s: %d out of %d data units required corrections\n", detectionGroupDataBlock.getDataName(), nUpdates, nUpdates+nOK);
@@ -486,7 +492,7 @@ public class DetectionGroupProcess extends PamProcess {
subTabLogging = detectionGroupLogging.getSubLogging();
PamConnection con = DBControlUnit.findConnection();
String desc = String.format("Detection group UID %d at %s", du.getUID(), PamCalendar.formatDBDateTime(du.getTimeMilliseconds()));
- String idList = "( " + du.getUID() + " )";
+ String idList = "( " + du.getDatabaseIndex() + " )";
ArrayList stData = subTabLogging.loadSubtableData(con, detectionGroupLogging, idList, null);
if (stData == null) {
System.out.println("Error loading sub table data for event uid " + du.getUID());
diff --git a/src/detectiongrouplocaliser/DetectionGroupSettings.java b/src/detectiongrouplocaliser/DetectionGroupSettings.java
index 318d2b8c..3bc28816 100644
--- a/src/detectiongrouplocaliser/DetectionGroupSettings.java
+++ b/src/detectiongrouplocaliser/DetectionGroupSettings.java
@@ -6,6 +6,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamView.paneloverlay.overlaymark.OverlayMarkDataInfo;
import annotation.handler.AnnotationChoices;
@@ -109,7 +110,7 @@ public class DetectionGroupSettings implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("overlayMarkInfo");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/difar/DifarParameters.java b/src/difar/DifarParameters.java
index c54774e9..b8b8dc8c 100644
--- a/src/difar/DifarParameters.java
+++ b/src/difar/DifarParameters.java
@@ -15,6 +15,7 @@ import Filters.FilterType;
import PamController.PamController;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamUtils.PamCalendar;
import PamView.PamGui;
@@ -588,7 +589,7 @@ public class DifarParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
@@ -659,7 +660,7 @@ public class DifarParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
@@ -773,7 +774,7 @@ public class DifarParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("groupList");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/difar/beamforming/BeamformControl.java b/src/difar/beamforming/BeamformControl.java
index edf3507b..bf04ea05 100644
--- a/src/difar/beamforming/BeamformControl.java
+++ b/src/difar/beamforming/BeamformControl.java
@@ -88,6 +88,16 @@ public class BeamformControl extends PamControlledUnit implements PamSettings, O
return DifarParameters.serialVersionUID;
}
+ @Override
+ public String getDataLocation() {
+ if (offlineFileServer != null) {
+ return offlineFileServer.getDataLocation();
+ }
+ else {
+ return null;
+ }
+ }
+
@Override
public boolean restoreSettings(
PamControlledUnitSettings pamControlledUnitSettings) {
diff --git a/src/difar/beamforming/BeamformParameters.java b/src/difar/beamforming/BeamformParameters.java
index 6688d309..2d65e576 100644
--- a/src/difar/beamforming/BeamformParameters.java
+++ b/src/difar/beamforming/BeamformParameters.java
@@ -5,6 +5,8 @@ import Filters.FilterParams;
import Filters.FilterType;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
+import PamUtils.DeepCloner;
import PamUtils.PamUtils;
public class BeamformParameters implements Serializable, Cloneable, ManagedParameters {
@@ -110,7 +112,7 @@ public class BeamformParameters implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/difar/dataSelector/DifarSelectParameters.java b/src/difar/dataSelector/DifarSelectParameters.java
index bc9814ad..af1c703e 100644
--- a/src/difar/dataSelector/DifarSelectParameters.java
+++ b/src/difar/dataSelector/DifarSelectParameters.java
@@ -6,6 +6,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamUtils;
import PamguardMVC.dataSelector.DataSelectParams;
@@ -61,7 +62,7 @@ public class DifarSelectParameters extends DataSelectParams implements Cloneable
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/difar/demux/GreenridgeParams.java b/src/difar/demux/GreenridgeParams.java
index d86fa2da..470357df 100644
--- a/src/difar/demux/GreenridgeParams.java
+++ b/src/difar/demux/GreenridgeParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class GreenridgeParams implements Serializable, Cloneable, ManagedParameters {
@@ -144,7 +145,7 @@ public class GreenridgeParams implements Serializable, Cloneable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/difar/trackedGroups/TrackedGroupSqlLogging.java b/src/difar/trackedGroups/TrackedGroupSqlLogging.java
index 54bd708b..e3b8b15b 100644
--- a/src/difar/trackedGroups/TrackedGroupSqlLogging.java
+++ b/src/difar/trackedGroups/TrackedGroupSqlLogging.java
@@ -125,7 +125,7 @@ public class TrackedGroupSqlLogging extends SQLLogging {
*/
protected void updateData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) {
- PamTableDefinition tableDef = getTableDefinition();
+ PamTableDefinition tableDef = (PamTableDefinition) getTableDefinition();
PamTableItem tableItem;
tableDef.getIndexItem().setValue(pamDataUnit.getDatabaseIndex());
diff --git a/src/effortmonitor/EffortParams.java b/src/effortmonitor/EffortParams.java
index fcd5bcb5..d19d3e36 100644
--- a/src/effortmonitor/EffortParams.java
+++ b/src/effortmonitor/EffortParams.java
@@ -5,6 +5,7 @@ import java.util.LinkedList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class EffortParams implements Cloneable, Serializable, ManagedParameters {
@@ -100,7 +101,7 @@ public class EffortParams implements Cloneable, Serializable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/effortmonitor/swing/EffortDialog.java b/src/effortmonitor/swing/EffortDialog.java
index 4f4d8b7f..6850415f 100644
--- a/src/effortmonitor/swing/EffortDialog.java
+++ b/src/effortmonitor/swing/EffortDialog.java
@@ -43,7 +43,7 @@ public class EffortDialog extends PamDialog {
mainPanel.add(new JLabel("Observer name or initials"), c);
c.gridx++;
mainPanel.add(observer = new JComboBox(), c);
- outerOnly = new JRadioButton("Log uter scroll only");
+ outerOnly = new JRadioButton("Log outer scroll only");
allActions = new JRadioButton("Log all scroll actions");
ButtonGroup bg = new ButtonGroup();
bg.add(allActions);
diff --git a/src/envelopeTracer/EnvelopeParams.java b/src/envelopeTracer/EnvelopeParams.java
index 09b427f9..6076deb9 100644
--- a/src/envelopeTracer/EnvelopeParams.java
+++ b/src/envelopeTracer/EnvelopeParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import Filters.FilterParams;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class EnvelopeParams implements Serializable, Cloneable, ManagedParameters {
@@ -34,7 +35,7 @@ public class EnvelopeParams implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/fftFilter/FFTFilterParams.java b/src/fftFilter/FFTFilterParams.java
index dd4d8ab0..bae3a3b6 100644
--- a/src/fftFilter/FFTFilterParams.java
+++ b/src/fftFilter/FFTFilterParams.java
@@ -8,6 +8,7 @@ import org.w3c.dom.Element;
import Filters.FilterBand;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.FrequencyFormat;
public class FFTFilterParams implements Serializable, Cloneable, ManagedParameters {
@@ -62,7 +63,7 @@ public class FFTFilterParams implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/fftManager/Complex.java b/src/fftManager/Complex.java
index 25b53edd..e2e13ded 100644
--- a/src/fftManager/Complex.java
+++ b/src/fftManager/Complex.java
@@ -25,6 +25,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Class definition for a Complex number type.
@@ -349,7 +350,7 @@ public class Complex implements Cloneable, Serializable, Comparable, Ma
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/fftManager/FFTDataBlock.java b/src/fftManager/FFTDataBlock.java
index db04f8d6..3bf0b7b1 100644
--- a/src/fftManager/FFTDataBlock.java
+++ b/src/fftManager/FFTDataBlock.java
@@ -4,6 +4,9 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
import PamView.GeneralProjector.ParameterType;
import PamView.GeneralProjector.ParameterUnits;
import PamguardMVC.DataBlock2D;
@@ -186,6 +189,13 @@ public class FFTDataBlock extends DataBlock2D {
public DataTypeInfo getScaleInfo() {
return dataTypeInfo;
}
+ @Override
+ public Element getDataBlockXML(Document doc) {
+ Element el = super.getDataBlockXML(doc);
+ el.setAttribute("FFTLength", String.format("%d", getFftLength()));
+ el.setAttribute("FFTHop", String.format("%d", getFftHop()));
+ return el;
+ }
diff --git a/src/fftManager/FFTDataDisplayOptions.java b/src/fftManager/FFTDataDisplayOptions.java
index a6d17619..969a7a81 100644
--- a/src/fftManager/FFTDataDisplayOptions.java
+++ b/src/fftManager/FFTDataDisplayOptions.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class FFTDataDisplayOptions implements Serializable, Cloneable, ManagedParameters {
@@ -45,7 +46,7 @@ public class FFTDataDisplayOptions implements Serializable, Cloneable, ManagedPa
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("maxVal");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/fftManager/PamFFTProcess.java b/src/fftManager/PamFFTProcess.java
index 34b45371..1d8cbb56 100644
--- a/src/fftManager/PamFFTProcess.java
+++ b/src/fftManager/PamFFTProcess.java
@@ -124,6 +124,7 @@ public class PamFFTProcess extends PamProcess {
public synchronized void setupFFT() {
+ System.out.println("In call to setupFFT in " + getProcessName());
// need to find the existing source data block and remove from observing it.
// then find the new one and subscribe to that instead.
channelCounts = new int[PamConstants.MAX_CHANNELS];
@@ -390,28 +391,32 @@ public class PamFFTProcess extends PamProcess {
}
}
}
+ TempOutputStore[] oldStores = tempStores;
if (iChan == PamUtils.getHighestChannel(fftParameters.channelMap)) {
// time to empty the stores - assume they all have the same
// amount of data
int[] chanList = PamUtils.getChannelArray(fftParameters.channelMap);
try {
- int n = tempStores[iChan].getN();
- for (int iF = 0; iF < n; iF++) {
- for (int iC = 0; iC < chanList.length; iC++) {
-// pu = tempStores[chanList[iC]].get(iF);
- try {
- outputData.addPamData(tempStores[chanList[iC]].get(iF));
+ int n = tempStores[iChan].getN();
+ for (int iF = 0; iF < n; iF++) {
+ for (int iC = 0; iC < chanList.length; iC++) {
+ // pu = tempStores[chanList[iC]].get(iF);
+ try {
+ outputData.addPamData(tempStores[chanList[iC]].get(iF));
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ // e.printStackTrace();
+ System.err.printf("%s.newData: %s Store %s (was %s) iC: %d of %d iF: %d of %d\n",
+ this.getPamControlledUnit().getUnitName(), e.getMessage(),
+ tempStores[chanList[iC]], oldStores[chanList[iC]],
+ iC, chanList.length, iF, n);
+ }
+ // outputData.addPamData(null);
}
- catch (ArrayIndexOutOfBoundsException e) {
-// e.printStackTrace();
- System.err.println("PAMFFTProcess.newData: " + e.getMessage() + " " + this.getPamControlledUnit().getUnitName() + " iC: " + iC + " iF: " + iF);
- }
-// outputData.addPamData(null);
}
- }
- for (int iC = 0; iC < chanList.length; iC++) {
- tempStores[chanList[iC]].clearStore();
- }
+ for (int iC = 0; iC < chanList.length; iC++) {
+ tempStores[chanList[iC]].clearStore();
+ }
}
catch (Exception e) {
e.printStackTrace();
@@ -539,6 +544,25 @@ public class PamFFTProcess extends PamProcess {
return new ArrayList>(Arrays.asList(RawDataUnit.class));
}
+ @Override
+ public synchronized void dumpBufferStatus(String message, boolean sayEmpties) {
+
+ super.dumpBufferStatus(message, sayEmpties);
+ int nTemp = 0;
+ if (tempStores != null) {
+ nTemp = tempStores.length;
+ }
+ for (int i = 0; i < nTemp; i++) {
+ if (tempStores[i] == null) {
+ continue;
+ }
+ int n = tempStores[i].tempUnits.size();
+ if (n > 0 || sayEmpties) {
+ System.out.printf("FFT %s temp store %d has %d datas\n", getProcessName(), i, n);
+ }
+ }
+ }
+
// @Override
// public boolean requestOfflineData(PamDataBlock dataBlock, long startMillis,
// long endMillis) {
diff --git a/src/fileOfflineData/OfflineFileControl.java b/src/fileOfflineData/OfflineFileControl.java
index cb408652..45998aaf 100644
--- a/src/fileOfflineData/OfflineFileControl.java
+++ b/src/fileOfflineData/OfflineFileControl.java
@@ -54,6 +54,11 @@ public abstract class OfflineFileControl extends PamControlledUnit implements Of
}
+ @Override
+ public String getDataLocation() {
+ return fileParams.offlineFolder;
+ }
+
/* (non-Javadoc)
* @see PamController.PamControlledUnit#notifyModelChanged(int)
*/
diff --git a/src/fileOfflineData/OfflineFileParams.java b/src/fileOfflineData/OfflineFileParams.java
index b31d547b..82e4d61a 100644
--- a/src/fileOfflineData/OfflineFileParams.java
+++ b/src/fileOfflineData/OfflineFileParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class OfflineFileParams implements Serializable, Cloneable, ManagedParameters {
@@ -28,7 +29,7 @@ public class OfflineFileParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/generalDatabase/DBControl.java b/src/generalDatabase/DBControl.java
index 7e229fee..70e0d549 100644
--- a/src/generalDatabase/DBControl.java
+++ b/src/generalDatabase/DBControl.java
@@ -30,6 +30,7 @@ import org.apache.commons.io.FilenameUtils;
import offlineProcessing.DataCopyTask;
import offlineProcessing.OLProcessDialog;
import offlineProcessing.OfflineTaskGroup;
+import pamguard.GlobalArguments;
import warnings.PamWarning;
import warnings.WarningSystem;
import PamController.PamConfiguration;
@@ -577,10 +578,16 @@ PamSettingsSource {
*/
@Override
public boolean saveStartSettings(long timeNow) {
- return dbProcess.saveStartSettings();
+ return dbProcess.saveStartSettings(timeNow);
}
+ @Override
+ public boolean saveEndSettings(long timeNow) {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
@Override
public int getNumSettings() {
if (dbSettingsStore == null) {
@@ -698,9 +705,17 @@ PamSettingsSource {
*/
public boolean selectDatabase(Frame frame, String selectTitle) {
+
//this is a bit messy but difficult to figure this out in controller framework because
//this is called before the controller has initialised properly.
- if (PamGUIManager.getGUIType()==PamGUIManager.FX) {
+ // also have to allow for the database being passed as a command line option, in which case
+ // we don't want to open the dialog.
+ String currentDB = null;
+ DBParameters newParams = checkPassedDatabase();
+ if (newParams != null) {
+
+ }
+ else if (PamGUIManager.getGUIType()==PamGUIManager.FX) {
//open FX
return ((DBGuiFX) getGUI(PamGUIManager.FX)).selectDatabase(PamController.getMainStage(), selectTitle, true);
}
@@ -711,12 +726,13 @@ PamSettingsSource {
// object and retrieving the name of the first database in the recently-used list. Double-check the connection
// field - if it's null, it means we don't actually have the database loaded so just clear the name and continue
// (this happens when starting Viewer mode)
- String currentDB = databaseSystems.get(dbParameters.getDatabaseSystem()).getDatabaseName();
+ currentDB = databaseSystems.get(dbParameters.getDatabaseSystem()).getDatabaseName();
if (connection==null) {
currentDB = null;
}
- DBParameters newParams = DBDialog.showDialog(this, frame, dbParameters, selectTitle);
+ newParams = DBDialog.showDialog(this, frame, dbParameters, selectTitle);
+ }
if (newParams != null) {
// first, check if there is a Lookup table. If so, make sure to copy the contents over before
// we lose the reference to the old database
@@ -757,9 +773,29 @@ PamSettingsSource {
PamController.getInstance().getUidManager().runStartupChecks(); // if we've loaded a new database, synch the datablocks with the UID info
return true;
}
- }
return false;
}
+
+ /**
+ * Check to see if a database has been passed to PAMGuard as a parameter from the command line.
+ * @return
+ */
+ DBParameters checkPassedDatabase() {
+ String passedDatabase = GlobalArguments.getParam(DBControl.GlobalDatabaseNameArg);
+ if (passedDatabase != null) {
+ /*
+ * assume it's a file based database. Anything else is going to get more complicated and will require
+ * a fair amount of type checing, connecint to servers, etc.
+ */
+ if (passedDatabase.endsWith(".sqlite3")) {
+ DBParameters newParams = dbParameters;
+ newParams.setDatabaseName(passedDatabase);
+ newParams.setDatabaseSystem(0);
+ return newParams;
+ }
+ }
+ return null;
+ }
/**
* Set dB paramaters
diff --git a/src/generalDatabase/DBControlUnit.java b/src/generalDatabase/DBControlUnit.java
index f3bc4b37..0b4239b8 100644
--- a/src/generalDatabase/DBControlUnit.java
+++ b/src/generalDatabase/DBControlUnit.java
@@ -50,6 +50,7 @@ public class DBControlUnit extends DBControl implements DataOutputStore {
private boolean initialisationComplete;
private BackupInformation backupInformation;
+ private CreateDataMap createDataMap;
public DBControlUnit(String unitName) {
this(null, unitName);
@@ -188,8 +189,8 @@ public class DBControlUnit extends DBControl implements DataOutputStore {
pamDataBlocks.get(i).removeOfflineDataMap(THIS);
updateDataBlocks.add(pamDataBlocks.get(i));
}
-
- AWTScheduler.getInstance().scheduleTask(new CreateDataMap(updateDataBlocks));
+ createDataMap = new CreateDataMap(updateDataBlocks);
+ AWTScheduler.getInstance().scheduleTask(createDataMap);
}
@@ -258,6 +259,7 @@ public class DBControlUnit extends DBControl implements DataOutputStore {
*/
public CreateDataMap(ArrayList loggingBlocks) {
super();
+ createDataMap = this;
this.loggingBlocks = loggingBlocks;
}
@@ -379,6 +381,7 @@ public class DBControlUnit extends DBControl implements DataOutputStore {
PamController.getInstance().notifyTaskProgress(new CreateMapInfo(PamTaskUpdate.STATUS_DONE));
PamController.getInstance().notifyModelChanged(PamControllerInterface.CHANGED_OFFLINE_DATASTORE);
// System.out.println("Create datamap point: DONE2");
+ createDataMap = null;
}
/* (non-Javadoc)
@@ -408,6 +411,11 @@ public class DBControlUnit extends DBControl implements DataOutputStore {
return getUnitName();
}
+ @Override
+ public String getDataLocation() {
+ return getDatabaseName();
+ }
+
@Override
public boolean loadData(PamDataBlock dataBlock, OfflineDataLoadInfo offlineDataLoadInfo, ViewLoadObserver loadObserver) {
SQLLogging logging = dataBlock.getLogging();
@@ -508,5 +516,13 @@ public class DBControlUnit extends DBControl implements DataOutputStore {
return getDbProcess().deleteDataFrom(timeMillis);
}
+ @Override
+ public int getOfflineState() {
+ int state = super.getOfflineState();
+ if (createDataMap != null) {
+ state = Math.max(state, PamController.PAM_MAPMAKING);
+ }
+ return state;
+ }
}
diff --git a/src/generalDatabase/DBParameters.java b/src/generalDatabase/DBParameters.java
index ce8103d7..ab06c212 100644
--- a/src/generalDatabase/DBParameters.java
+++ b/src/generalDatabase/DBParameters.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class DBParameters implements Cloneable, Serializable, ManagedParameters {
@@ -75,7 +76,7 @@ public class DBParameters implements Cloneable, Serializable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
if (databaseName != null) {
try {
Field field = this.getClass().getDeclaredField("databaseName");
diff --git a/src/generalDatabase/DBProcess.java b/src/generalDatabase/DBProcess.java
index 167d49f5..597b1a10 100644
--- a/src/generalDatabase/DBProcess.java
+++ b/src/generalDatabase/DBProcess.java
@@ -102,6 +102,8 @@ public class DBProcess extends PamProcess {
dbSpecials.add(logSettings = new LogSettings(databaseControll, "Pamguard Settings", false));
dbSpecials.add(logLastSettings = new LogSettings(databaseControll, "Pamguard Settings Last", true));
dbSpecials.add(logViewerSettings = new LogSettings(databaseControll, "Pamguard Settings Viewer", true));
+
+ dbSpecials.add(new LogXMLSettings(databaseControll));
}
@@ -113,9 +115,13 @@ public class DBProcess extends PamProcess {
}
}
- protected boolean saveStartSettings() {
+ protected boolean saveStartSettings(long timeNow) {
PamConnection con = databaseControll.getConnection();
if (con != null) {
+ /**
+ * This first one is the 'old' pre 2022 method which saves a serialised lump of all
+ * the settings in the database. It ain't broke, so not fixing it.
+ */
for (int i = 0; i < dbSpecials.size(); i++) {
dbSpecials.get(i).pamStart(con);
}
@@ -124,6 +130,11 @@ public class DBProcess extends PamProcess {
return false;
}
+ protected boolean saveEndSettings(long timeNow) {
+
+ return true;
+ }
+
@Override
public void pamStop() {
PamConnection con = databaseControll.getConnection();
@@ -212,7 +223,7 @@ public class DBProcess extends PamProcess {
}
dataBlocks = PamController.getInstance().getDataBlocks();
- PamTableDefinition tableDefinition;
+ EmptyTableDefinition tableDefinition;
SQLLogging logging;
// for each datablock, check that the process can log (ignoring GPS process)
diff --git a/src/generalDatabase/DBSchemaWriter.java b/src/generalDatabase/DBSchemaWriter.java
index f602ad5c..a29a90b5 100644
--- a/src/generalDatabase/DBSchemaWriter.java
+++ b/src/generalDatabase/DBSchemaWriter.java
@@ -48,7 +48,7 @@ public class DBSchemaWriter {
}
- PamTableDefinition tableDef = logging.getTableDefinition();
+ EmptyTableDefinition tableDef = logging.getTableDefinition();
tableDef = logging.getBaseTableDefinition();
if (tableDef instanceof PamTableDefinition) {
@@ -63,13 +63,14 @@ public class DBSchemaWriter {
return true;
}
- private void exportDatabaseSchema(File outputFolder, PamDataBlock dataBlock, SQLLogging logging, PamTableDefinition tableDef) {
-
- /**
- * write a parent item, e.g. if tableDef is a sub class of PamTableDefinition
- */
- // String parentName = writeParentTableSchema(outputFolder, dataBlock, tableDef);
-
+ /**
+ * Generate an xml schema for a datablock.
+ * @param dataBlock
+ * @param logging
+ * @param tableDef
+ * @return
+ */
+ public Document generateDatabaseSchema(PamDataBlock dataBlock, SQLLogging logging, EmptyTableDefinition tableDef) {
String tableName = tableDef.getTableName();
Document doc = PamUtils.XMLUtils.createBlankDoc();
Element schemaEl = doc.createElement("xs:schema");
@@ -95,7 +96,20 @@ public class DBSchemaWriter {
}
}
}
+ return doc;
+ }
+
+ private void exportDatabaseSchema(File outputFolder, PamDataBlock dataBlock, SQLLogging logging, EmptyTableDefinition tableDef) {
+ /**
+ * write a parent item, e.g. if tableDef is a sub class of PamTableDefinition
+ */
+ // String parentName = writeParentTableSchema(outputFolder, dataBlock, tableDef);
+
+ Document doc = generateDatabaseSchema(dataBlock, logging, tableDef);
+
+ String tableName = tableDef.getTableName();
+
try {
File outputFile = new File(outputFolder, tableName+".xsd");
XMLUtils.writeToFile(doc, outputFile);
diff --git a/src/generalDatabase/DbSpecial.java b/src/generalDatabase/DbSpecial.java
index 05400f7a..401eac1a 100644
--- a/src/generalDatabase/DbSpecial.java
+++ b/src/generalDatabase/DbSpecial.java
@@ -9,7 +9,7 @@ import PamguardMVC.PamDataUnit;
* @author Doug Gillespie
*
*/
-abstract public class DbSpecial extends SQLLogging{
+abstract public class DbSpecial extends SQLLogging {
private DBControl dbControl;
diff --git a/src/generalDatabase/EmptyTableDefinition.java b/src/generalDatabase/EmptyTableDefinition.java
index 9e10753e..53cfd1fb 100644
--- a/src/generalDatabase/EmptyTableDefinition.java
+++ b/src/generalDatabase/EmptyTableDefinition.java
@@ -300,7 +300,7 @@ public class EmptyTableDefinition implements Cloneable {
* @param tableName
* @return reference to the database deinition if it exists, or null
*/
- static PamTableDefinition findTableDefinition(String tableName) {
+ static EmptyTableDefinition findTableDefinition(String tableName) {
String searchName = EmptyTableDefinition.deblankString(tableName);
SQLLogging log = SQLLogging.findLogger(searchName);
if (log == null) return null;
@@ -389,6 +389,15 @@ public class EmptyTableDefinition implements Cloneable {
this.updatePolicy = updatePolicy;
}
+ public PamConnection getCheckedConnection() {
+ return checkedConnection;
+ }
+
+ public void setCheckedConnection(PamConnection checkedConnection) {
+ this.checkedConnection = checkedConnection;
+ }
+
+
@Override
protected EmptyTableDefinition clone() {
try {
diff --git a/src/generalDatabase/LogSettings.java b/src/generalDatabase/LogSettings.java
index af5305e9..23b713be 100644
--- a/src/generalDatabase/LogSettings.java
+++ b/src/generalDatabase/LogSettings.java
@@ -23,7 +23,7 @@ import PamUtils.PamCalendar;
import PamguardMVC.PamDataUnit;
/**
- * Functions for writing Pamguard Settings into any database as character data
+ * Functions for writing serialised Pamguard Settings into any database as character data
* Runs at DAQ start, goes through the settings manager list and for each
* set of settings, it serialises the settings data into a binary array, this
* is then converted from binary data to 6 bit ascii data (using the character set
@@ -185,6 +185,7 @@ public class LogSettings extends DbSpecial {
DeserialisationWarning dsWarning = new DeserialisationWarning(getDbControl().getDatabaseName());
SQLTypes sqlTypes = con.getSqlTypes();
+
boolean haveData;
if (result != null) try {
haveData = result.next();
@@ -193,7 +194,7 @@ public class LogSettings extends DbSpecial {
// transfer data back into the tableItems store.
transferDataFromResult(sqlTypes, result);
- tableItem = getTableDefinition().getTimeStampItem();
+ tableItem = tableDef.getTimeStampItem();
// timestamp = (Timestamp) tableItem.getTimestampValue();
timeMillis = sqlTypes.millisFromTimeStamp(tableItem.getValue());
diff --git a/src/generalDatabase/LogXMLDataUnit.java b/src/generalDatabase/LogXMLDataUnit.java
new file mode 100644
index 00000000..63189784
--- /dev/null
+++ b/src/generalDatabase/LogXMLDataUnit.java
@@ -0,0 +1,75 @@
+package generalDatabase;
+
+import PamController.PamSettings;
+import PamguardMVC.PamDataUnit;
+
+/**
+ * simple data unit for use with the LogXMLSettings class
+ * @author dg50
+ *
+ */
+public class LogXMLDataUnit extends PamDataUnit {
+
+ private long processTime;
+ private PamSettings pamSettings;
+ private String xml;
+ private Long dataEnd, processEnd;
+
+ public LogXMLDataUnit(long timeMilliseconds, long processTime, PamSettings pamSettings, String xml) {
+ super(timeMilliseconds);
+ this.processTime = processTime;
+ this.pamSettings = pamSettings;
+ this.xml = xml;
+ }
+
+ /**
+ * @return the dataEnd
+ */
+ public Long getDataEnd() {
+ return dataEnd;
+ }
+
+ /**
+ * @param dataEnd the dataEnd to set
+ */
+ public void setDataEnd(Long dataEnd) {
+ this.dataEnd = dataEnd;
+ }
+
+ /**
+ * @return the processEnd
+ */
+ public Long getProcessEnd() {
+ return processEnd;
+ }
+
+ /**
+ * @param processEnd the processEnd to set
+ */
+ public void setProcessEnd(Long processEnd) {
+ this.processEnd = processEnd;
+ }
+
+ /**
+ * @return the processTime
+ */
+ public long getProcessTime() {
+ return processTime;
+ }
+
+ /**
+ * @return the pamSettings
+ */
+ public PamSettings getPamSettings() {
+ return pamSettings;
+ }
+
+ /**
+ * @return the xml
+ */
+ public String getXml() {
+ return xml;
+ }
+
+
+}
diff --git a/src/generalDatabase/LogXMLSettings.java b/src/generalDatabase/LogXMLSettings.java
new file mode 100644
index 00000000..3f33c188
--- /dev/null
+++ b/src/generalDatabase/LogXMLSettings.java
@@ -0,0 +1,123 @@
+package generalDatabase;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+import org.w3c.dom.Document;
+
+import PamController.PamControlledUnit;
+import PamController.PamController;
+import PamController.PamSettings;
+import PamController.PamguardVersionInfo;
+import PamController.settings.output.xml.PamguardXMLWriter;
+import PamUtils.PamCalendar;
+import PamguardMVC.PamDataUnit;
+/**
+ * 2022 Additional way of saving settings for each module into the database in more human readable
+ * XML format.
+ * In other ways, similar to LogSettings which saves serialised Java. This will write a line
+ * per module. A main difference is that on pamStop it will update the end time for each line, so
+ * that we have a record of analysis effort for each module. Will therefore need to store the last
+ * index of the entry for each module, so that we can update the appropriate row.
+ * @author dg50
+ *
+ */
+public class LogXMLSettings extends DbSpecial {
+
+ private XMLSettingsTableDefinition xmlTableDef;
+
+ private HashMap moduleRows;
+
+ private PamguardXMLWriter xmlWriter;
+
+ public LogXMLSettings(DBControl dbControl) {
+ super(dbControl);
+ xmlTableDef = new XMLSettingsTableDefinition("Module Effort");
+ setTableDefinition(xmlTableDef);
+ moduleRows = new HashMap<>();
+ xmlWriter = PamguardXMLWriter.getXMLWriter();
+ }
+
+ @Override
+ public void pamStart(PamConnection con) {
+ long time = PamCalendar.getTimeInMillis();
+ saveModuleSettings(con, time);
+ }
+
+ @Override
+ public void pamStop(PamConnection con) {
+ long time = PamCalendar.getTimeInMillis();
+ updateModuleSettings(con, time);
+ }
+
+ private void saveModuleSettings(PamConnection con, long dataTime) {
+ int n = PamController.getInstance().getNumControlledUnits();
+ long now = System.currentTimeMillis();
+ for (int i = 0; i < n; i++) {
+ saveModuleSettings(con, dataTime, now, PamController.getInstance().getControlledUnit(i));
+ }
+
+ }
+
+ private void saveModuleSettings(PamConnection con, long dataTime, long now, PamControlledUnit controlledUnit) {
+ if (controlledUnit instanceof PamSettings == false) {
+ return;
+ }
+ PamSettings pamSettings = (PamSettings) controlledUnit;
+ Serializable settings = pamSettings.getSettingsReference();
+ Document doc = xmlWriter.writeOneModule(pamSettings, dataTime);
+ String xmlString = xmlWriter.getAsString(doc, true);
+ LogXMLDataUnit logXMLDataUnit = new LogXMLDataUnit(dataTime, now, pamSettings, xmlString);
+
+ logData(logXMLDataUnit);
+ int dbIndex = logXMLDataUnit.getDatabaseIndex();
+ moduleRows.put(getModuleHash(pamSettings), logXMLDataUnit);
+ }
+
+ private void updateModuleSettings(PamConnection con, long dataTime) {
+ int n = PamController.getInstance().getNumControlledUnits();
+ long now = System.currentTimeMillis();
+ for (int i = 0; i < n; i++) {
+ updateModuleSettings(con, dataTime, now, PamController.getInstance().getControlledUnit(i));
+ }
+
+ }
+
+ private void updateModuleSettings(PamConnection con, long dataTime, long now, PamControlledUnit controlledUnit) {
+ if (controlledUnit instanceof PamSettings == false) {
+ return;
+ }
+ PamSettings pamSettings = (PamSettings) controlledUnit;
+ LogXMLDataUnit logXMLDataUnit = moduleRows.get(getModuleHash(pamSettings));
+ if (logXMLDataUnit == null) {
+ return;
+ }
+ logXMLDataUnit.setDataEnd(dataTime);
+ logXMLDataUnit.setProcessEnd(now);
+ reLogData(con, logXMLDataUnit);
+ }
+
+ private String getModuleHash(PamSettings pamSettings) {
+ if (pamSettings == null) {
+ return null;
+ }
+ return pamSettings.getUnitName()+pamSettings.getUnitType();
+ }
+
+ @Override
+ public void setTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) {
+ LogXMLDataUnit logXMLDataUnit = (LogXMLDataUnit) pamDataUnit;
+ PamSettings pamSettings = logXMLDataUnit.getPamSettings();
+
+ xmlTableDef.getDataStart().setValue(sqlTypes.getTimeStamp(pamDataUnit.getTimeMilliseconds()));
+ xmlTableDef.getDataEnd().setValue(sqlTypes.getTimeStamp(logXMLDataUnit.getDataEnd()));
+ xmlTableDef.getProcessStart().setValue(sqlTypes.getTimeStamp(logXMLDataUnit.getProcessTime()));
+ xmlTableDef.getProcessEnd().setValue(sqlTypes.getTimeStamp(logXMLDataUnit.getProcessEnd()));
+ xmlTableDef.getName().setValue(pamSettings.getUnitName());
+ xmlTableDef.getType().setValue(pamSettings.getUnitType());
+ xmlTableDef.getPamGuardVersion().setValue(PamguardVersionInfo.version);
+ xmlTableDef.getSettingsVersion().setValue(pamSettings.getSettingsVersion());
+ xmlTableDef.getXmlSettings().setValue(logXMLDataUnit.getXml());
+ }
+
+}
diff --git a/src/generalDatabase/MySQLParameters.java b/src/generalDatabase/MySQLParameters.java
index 9491a6da..cadd498f 100644
--- a/src/generalDatabase/MySQLParameters.java
+++ b/src/generalDatabase/MySQLParameters.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class MySQLParameters implements Cloneable, Serializable, ManagedParameters {
@@ -37,7 +38,7 @@ public class MySQLParameters implements Cloneable, Serializable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("databaseName");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/generalDatabase/PamSubtableDefinition.java b/src/generalDatabase/PamSubtableDefinition.java
index 0aa20215..ec3780b0 100644
--- a/src/generalDatabase/PamSubtableDefinition.java
+++ b/src/generalDatabase/PamSubtableDefinition.java
@@ -51,6 +51,7 @@ public class PamSubtableDefinition extends PamTableDefinition {
addTableItem(parentUID = new PamTableItem(PARENTUIDNAME, Types.BIGINT));
addTableItem(longName = new PamTableItem(LONGDATANAME, Types.CHAR, DATANAME_LENGTH));
addTableItem(binaryFilename = new PamTableItem(BINARYFILE, Types.CHAR, BINARY_FILE_NAME_LENGTH));
+ setUseCheatIndexing(false);
}
public PamTableItem getParentID() {
diff --git a/src/generalDatabase/PamTableDefinition.java b/src/generalDatabase/PamTableDefinition.java
index e8a2b5dc..8424b683 100644
--- a/src/generalDatabase/PamTableDefinition.java
+++ b/src/generalDatabase/PamTableDefinition.java
@@ -192,14 +192,7 @@ public class PamTableDefinition extends EmptyTableDefinition implements Cloneabl
public PamTableItem getUidItem() {
return uid;
}
- public PamConnection getCheckedConnection() {
- return checkedConnection;
- }
-
- public void setCheckedConnection(PamConnection checkedConnection) {
- this.checkedConnection = checkedConnection;
- }
-
+
public PamTableItem getUpdateReference() {
return updateReference;
}
diff --git a/src/generalDatabase/PamTableItem.java b/src/generalDatabase/PamTableItem.java
index 2a046623..e73772e8 100644
--- a/src/generalDatabase/PamTableItem.java
+++ b/src/generalDatabase/PamTableItem.java
@@ -377,7 +377,7 @@ public class PamTableItem implements Cloneable {
* column for use in cross referencing.
*/
public static PamTableItem findTableItem(String tableName, String columnName) {
- PamTableDefinition tableDef = EmptyTableDefinition.
+ EmptyTableDefinition tableDef = EmptyTableDefinition.
findTableDefinition(EmptyTableDefinition.deblankString(tableName));
if (tableDef == null) return null;
return tableDef.findTableItem(EmptyTableDefinition.deblankString(columnName));
diff --git a/src/generalDatabase/SQLLogging.java b/src/generalDatabase/SQLLogging.java
index e9c094ed..905ee28f 100644
--- a/src/generalDatabase/SQLLogging.java
+++ b/src/generalDatabase/SQLLogging.java
@@ -190,7 +190,7 @@ public abstract class SQLLogging {
ArrayList blockList = PamController.getInstance()
.getDataBlocks();
SQLLogging logger;
- PamTableDefinition tableDef;
+ EmptyTableDefinition tableDef;
for (int i = 0; i < blockList.size(); i++) {
if ((logger = blockList.get(i).getLogging()) != null) {
tableDef = logger.getTableDefinition();
@@ -293,37 +293,42 @@ public abstract class SQLLogging {
* @param superDetection
*/
protected void fillTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit, PamDataUnit superDetection) {
+
+ EmptyTableDefinition emptyTableDef = getTableDefinition();
- PamTableDefinition tableDef = getTableDefinition();
PamTableItem tableItem;
- tableDef.getIndexItem().setValue(pamDataUnit.getDatabaseIndex());
- /*
- * All tables have a timestamp near the front of the table. And all data
- * units have a time in milliseconds, so always fill this in !
- */
- tableDef.getTimeStampItem().setValue(
- sqlTypes.getTimeStamp(pamDataUnit.getTimeMilliseconds()));
+ emptyTableDef.getIndexItem().setValue(pamDataUnit.getDatabaseIndex());
+
+ if (emptyTableDef instanceof PamTableDefinition) {
+ PamTableDefinition tableDef = (PamTableDefinition) emptyTableDef;
+ /*
+ * All tables have a timestamp near the front of the table. And all data
+ * units have a time in milliseconds, so always fill this in !
+ */
+ tableDef.getTimeStampItem().setValue(
+ sqlTypes.getTimeStamp(pamDataUnit.getTimeMilliseconds()));
- tableDef.getTimeStampMillis().setValue((int) (pamDataUnit.getTimeMilliseconds()%1000));
+ tableDef.getTimeStampMillis().setValue((int) (pamDataUnit.getTimeMilliseconds()%1000));
- tableDef.getLocalTimeItem().setValue(sqlTypes.getLocalTimeStamp(pamDataUnit.getTimeMilliseconds()));
+ tableDef.getLocalTimeItem().setValue(sqlTypes.getLocalTimeStamp(pamDataUnit.getTimeMilliseconds()));
- tableDef.getPCTimeItem().setValue(sqlTypes.getTimeStamp(System.currentTimeMillis()));
+ tableDef.getPCTimeItem().setValue(sqlTypes.getTimeStamp(System.currentTimeMillis()));
- tableDef.getUidItem().setValue(pamDataUnit.getUID());
+ tableDef.getUidItem().setValue(pamDataUnit.getUID());
- tableDef.getChannelBitmap().setValue(pamDataUnit.getChannelBitmap());
+ tableDef.getChannelBitmap().setValue(pamDataUnit.getChannelBitmap());
- tableDef.getSequenceBitmap().setValue(pamDataUnit.getSequenceBitmapObject());
+ tableDef.getSequenceBitmap().setValue(pamDataUnit.getSequenceBitmapObject());
- if (tableDef.getUpdateReference() != null) {
- tableDef.getUpdateReference().setValue(pamDataUnit.getDatabaseIndex());
+ if (tableDef.getUpdateReference() != null) {
+ tableDef.getUpdateReference().setValue(pamDataUnit.getDatabaseIndex());
+ }
}
- for (int i = 0; i < tableDef.getTableItemCount(); i++) {
+ for (int i = 0; i < emptyTableDef.getTableItemCount(); i++) {
- tableItem = tableDef.getTableItem(i);
+ tableItem = emptyTableDef.getTableItem(i);
// if (tableItem.isCounter()) {
// tableItem.setValue(1);
// }
@@ -333,8 +338,8 @@ public abstract class SQLLogging {
}
}
- if (tableDef instanceof PamSubtableDefinition) {
- PamSubtableDefinition subTableDef = (PamSubtableDefinition) tableDef;
+ if (emptyTableDef instanceof PamSubtableDefinition) {
+ PamSubtableDefinition subTableDef = (PamSubtableDefinition) emptyTableDef;
fillSubTableData(subTableDef, pamDataUnit, superDetection);
}
@@ -525,7 +530,7 @@ public abstract class SQLLogging {
}
// now put some sql into the statement
// if (resultSet == null) {
- PamTableDefinition tableDef = getTableDefinition();
+ EmptyTableDefinition tableDef = getTableDefinition();
String sqlString = tableDef.getSQLSelectString(con.getSqlTypes());
// sqlString = "select \"comment\" from userinput";
try {
@@ -546,6 +551,71 @@ public abstract class SQLLogging {
// }
return resultSet;
}
+
+ /**
+ * Find the data point which is closest in time to that given, or null
+ * returning whatever type of data unit this deals with.
+ * @param timeMillis
+ * @return
+ */
+ public PamDataUnit findClosestDataPoint(PamConnection con, long timeMillis) {
+
+ PamCursor pamCursor = loggingCursorFinder.getCursor(con, pamTableDefinition);
+
+ // can't really do any math with the string based dates, so will have to query from
+ // a few s before the time we want.
+ PamDataUnit[] beforeNafter = new PamDataUnit[2];
+
+ SQLTypes sqlTypes = con.getSqlTypes();
+
+ for (int i = 0; i < 2; i++) {
+ String clause;
+
+ if (i == 0) {
+ clause = String.format("WHERE UTC <= %s ORDER BY UTC DESC", sqlTypes.formatDBDateTimeQueryString(timeMillis));
+ }
+ else {
+ clause = String.format("WHERE UTC >= %s ORDER BY UTC ASC", sqlTypes.formatDBDateTimeQueryString(timeMillis));
+ }
+
+ ResultSet result = pamCursor.openReadOnlyCursor(con, clause);
+ if (result==null) {
+ return null;
+ }
+
+ PamTableItem tableItem;
+ try {
+ if (result.next()) {
+ // for (int i = 0; i < pamTableDefinition.getTableItemCount(); i++) {
+ // tableItem = pamTableDefinition.getTableItem(i);
+ // tableItem.setValue(result.getObject(i + 1));
+ // }
+ // return true;
+ boolean ok = transferDataFromResult(con.getSqlTypes(), result);
+ result.close();
+ beforeNafter[i] = createDataUnit(sqlTypes, lastTime, lastLoadIndex);
+ }
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ continue;
+ }
+ }
+ // now pick the closest
+ if (beforeNafter[0] == null) {
+ return beforeNafter[1];
+ }
+ if (beforeNafter[1] == null) {
+ return beforeNafter[0];
+ }
+ long t1 = timeMillis-beforeNafter[0].getTimeMilliseconds();
+ long t2 = beforeNafter[1].getTimeMilliseconds()-timeMillis;
+ if (t1 < t2) {
+ return beforeNafter[0];
+ }
+ else {
+ return beforeNafter[1];
+ }
+ }
/**
* Called when a new database is connected to read the last values back in
@@ -1079,7 +1149,7 @@ public abstract class SQLLogging {
public boolean transferDataFromResult(SQLTypes sqlTypes, ResultSet resultSet) {
- PamTableDefinition tableDef = getTableDefinition();
+ EmptyTableDefinition tableDef = getTableDefinition();
PamTableItem tableItem;
try {
for (int i = 0; i < tableDef.getTableItemCount(); i++) {
@@ -1090,17 +1160,20 @@ public abstract class SQLLogging {
// Timestamp ts = (Timestamp) getTableDefinition().getTimeStampItem().getValue();
// Timestamp ts = getTableDefinition().getTimeStampItem().getTimestampValue();
// lastTime = sqlTypes.millisFromTimeStamp(ts);
- lastTime = sqlTypes.millisFromTimeStamp(getTableDefinition().getTimeStampItem().getValue());
- if (lastTime%1000 == 0) {
- // some databases may have stored the milliseconds, in which
- // case this next bit is redundant.
- lastTime += getTableDefinition().getTimeStampMillis().getIntegerValue();
- }
-
lastLoadIndex = getTableDefinition().getIndexItem().getIntegerValue();
- lastLoadUID = getTableDefinition().getUidItem().getLongObject();
- lastChannelBitmap = getTableDefinition().getChannelBitmap().getIntegerValue();
- lastSequenceBitmap = getTableDefinition().getSequenceBitmap().getIntegerObject();
+ if (tableDef instanceof PamTableDefinition) {
+ PamTableDefinition pamTableDef = (PamTableDefinition) tableDef;
+ lastTime = sqlTypes.millisFromTimeStamp(pamTableDef.getTimeStampItem().getValue());
+ if (lastTime%1000 == 0) {
+ // some databases may have stored the milliseconds, in which
+ // case this next bit is redundant.
+ lastTime += pamTableDef.getTimeStampMillis().getIntegerValue();
+ }
+
+ lastLoadUID = pamTableDef.getUidItem().getLongObject();
+ lastChannelBitmap = pamTableDef.getChannelBitmap().getIntegerValue();
+ lastSequenceBitmap = pamTableDef.getSequenceBitmap().getIntegerObject();
+ }
return true;
} catch (SQLException ex) {
@@ -1929,7 +2002,7 @@ public abstract class SQLLogging {
*
* @param con database connection
* @param parentLogging super detection logging instance.
- * @param uidList list of UID's in the parent data that have been loaded.
+ * @param idList list of ID's in the parent data that have been loaded. Note Id, NOT UID
* @return list of all PamSubtableData items
*/
public ArrayList loadSubtableData(PamConnection con, SQLLogging parentLogging, String idList, ViewLoadObserver loadObserver) {
@@ -1961,6 +2034,13 @@ public abstract class SQLLogging {
return loadSubtableData(con, subtableResults, loadObserver);
}
+ /**
+ * Get a sub table result set. Note that this is based on ID, not UID
+ * @param con connection
+ * @param parentLogging parent logging system
+ * @param parentIdList ParentID list. Note that this is ID, not UID, i.e. the query is WHERE ParentID IN ...
+ * @return child table result set
+ */
private ResultSet createSubTableResultSet(PamConnection con, SQLLogging parentLogging,
String parentIdList) {
String clause = String.format(" WHERE ParentID IN %s ORDER BY UTC, UTCMilliseconds", parentIdList);
diff --git a/src/generalDatabase/SQLLoggingAddon.java b/src/generalDatabase/SQLLoggingAddon.java
index 6d347fb4..ff8bd561 100644
--- a/src/generalDatabase/SQLLoggingAddon.java
+++ b/src/generalDatabase/SQLLoggingAddon.java
@@ -15,7 +15,7 @@ public interface SQLLoggingAddon {
* Add a load of columns to an existing table definition
* @param pamTableDefinition
*/
- public void addTableItems(PamTableDefinition pamTableDefinition);
+ public void addTableItems(EmptyTableDefinition pamTableDefinition);
/**
* Save data - that is transfer data from the pamDataUnit to the data objects
@@ -24,7 +24,7 @@ public interface SQLLoggingAddon {
* @param pamDataUnit data unit
* @return true if successful
*/
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit);
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit);
/**
* Load data - that is read data from the table definition and turn it into something sensible
@@ -33,7 +33,7 @@ public interface SQLLoggingAddon {
* @param pamDataUnit data unit
* @return true if successful
*/
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit);
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit);
/**
* Get a name for the SQLLogging Addon. this is used
diff --git a/src/generalDatabase/SQLTypes.java b/src/generalDatabase/SQLTypes.java
index a81edd89..fd8ccb56 100644
--- a/src/generalDatabase/SQLTypes.java
+++ b/src/generalDatabase/SQLTypes.java
@@ -387,6 +387,7 @@ public class SQLTypes {
return timestamp.getTime() + tz.getOffset(timestamp.getTime());
}
else if (timeValue instanceof String) {
+ timeValue = ((String) timeValue).replace("'", "");
return PamCalendar.millisFromDateString((String) timeValue, false);
}
if (timeValue instanceof Long) {
diff --git a/src/generalDatabase/XMLSettingsTableDefinition.java b/src/generalDatabase/XMLSettingsTableDefinition.java
new file mode 100644
index 00000000..8d40bc55
--- /dev/null
+++ b/src/generalDatabase/XMLSettingsTableDefinition.java
@@ -0,0 +1,94 @@
+package generalDatabase;
+
+import java.sql.Types;
+
+import PamguardMVC.PamConstants;
+
+public class XMLSettingsTableDefinition extends PamTableDefinition {
+
+ private PamTableItem dataStart, dataEnd, processStart, processEnd, type, name, pamGuardVersion, settingsVersion, xmlSettings;
+
+ public XMLSettingsTableDefinition(String tableName) {
+ super(tableName, SQLLogging.UPDATE_POLICY_WRITENEW);
+ pamTableItems.add(dataStart = new PamTableItem("Data Start", Types.TIMESTAMP, "Data start time"));
+ pamTableItems.add(dataEnd = new PamTableItem("Data End", Types.TIMESTAMP, "Data end time"));
+ pamTableItems.add(processStart = new PamTableItem("Process Start", Types.TIMESTAMP, "Process start time"));
+ pamTableItems.add(processEnd = new PamTableItem("Process End", Types.TIMESTAMP, "Process end time"));
+ addTableItem(type = new PamTableItem("unitType", Types.CHAR, PamConstants.MAX_ITEM_NAME_LENGTH));
+ addTableItem(name = new PamTableItem("unitName", Types.CHAR, PamConstants.MAX_ITEM_NAME_LENGTH));
+ addTableItem(pamGuardVersion = new PamTableItem("PAMGuardVersion", Types.INTEGER));
+ addTableItem(settingsVersion = new PamTableItem("SettingsVersion", Types.INTEGER));
+ addTableItem(xmlSettings = new PamTableItem("XMLSettings", Types.VARCHAR));
+ setUseCheatIndexing(false);
+ }
+
+
+ /**
+ * @return the dataStart
+ */
+ public PamTableItem getDataStart() {
+ return dataStart;
+ }
+
+
+ /**
+ * @return the dataEnd
+ */
+ public PamTableItem getDataEnd() {
+ return dataEnd;
+ }
+
+
+ /**
+ * @return the processStart
+ */
+ public PamTableItem getProcessStart() {
+ return processStart;
+ }
+
+
+ /**
+ * @return the processEnd
+ */
+ public PamTableItem getProcessEnd() {
+ return processEnd;
+ }
+
+
+ /**
+ * @return the type
+ */
+ public PamTableItem getType() {
+ return type;
+ }
+
+ /**
+ * @return the name
+ */
+ public PamTableItem getName() {
+ return name;
+ }
+
+ /**
+ * @return the pamGuardVersion
+ */
+ public PamTableItem getPamGuardVersion() {
+ return pamGuardVersion;
+ }
+
+ /**
+ * @return the settingsVersion
+ */
+ public PamTableItem getSettingsVersion() {
+ return settingsVersion;
+ }
+
+ /**
+ * @return the xmlSettings
+ */
+ public PamTableItem getXmlSettings() {
+ return xmlSettings;
+ }
+
+
+}
diff --git a/src/generalDatabase/dataExport/ValueFilterParams.java b/src/generalDatabase/dataExport/ValueFilterParams.java
index 15ffdfbd..52c57cfd 100644
--- a/src/generalDatabase/dataExport/ValueFilterParams.java
+++ b/src/generalDatabase/dataExport/ValueFilterParams.java
@@ -6,6 +6,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Abstract class for ValueFilters for filtering database data tables.
@@ -110,7 +111,7 @@ public abstract class ValueFilterParams implements Cloneable, Serializable, Mana
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/generalDatabase/lookupTables/LookUpTables.java b/src/generalDatabase/lookupTables/LookUpTables.java
index daea762f..bd095eba 100644
--- a/src/generalDatabase/lookupTables/LookUpTables.java
+++ b/src/generalDatabase/lookupTables/LookUpTables.java
@@ -3,10 +3,13 @@ package generalDatabase.lookupTables;
import java.awt.Color;
import java.awt.Window;
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.ListIterator;
+import java.util.Vector;
import PamController.PamController;
import PamView.dialog.warn.WarnOnce;
@@ -101,9 +104,101 @@ public class LookUpTables {
checkedTableConnection = null;
if (dbControlUnit.getDbProcess().checkTable(lutTableDef)) {
checkedTableConnection = con;
- return true;
}
- return false;
+
+ checkTableRepeats(con, lutTableDef);
+
+ return checkedTableConnection != null;
+ }
+
+ /**
+ * for some reason some repeats have got into the LUT and need to be removed
+ * or it really messes stuff up. So check it automatically.
+ * @param con
+ * @param lutTableDef2
+ */
+ private boolean checkTableRepeats(PamConnection con, EmptyTableDefinition lutTableDef) {
+ /*
+ * first get a list of unique topics, then check them one at a time.
+ */
+ ArrayList topics = getTopicList(con, lutTableDef);
+ if (topics == null) {
+ return false;
+ }
+
+ for (String topic : topics) {
+ checkTopicRepeats(con, lutTableDef, topic);
+ }
+ return true;
+ }
+
+ private void checkTopicRepeats(PamConnection con, EmptyTableDefinition lutTableDef2, String topic) {
+ LookupList lutList = getLookupList(topic);
+ Vector list = lutList.getList();
+ int n = list.size();
+ boolean[] isRepeat = new boolean[n];
+ int nRepeat = 0;
+ // search for repeats.
+ for (int i = 0; i < n-1; i++) {
+ String code = list.get(i).getCode().trim();
+ for (int j = i+1; j < n; j++) {
+ String code2 = list.get(j).getCode().trim();
+ if (code.equals(code2)) {
+ isRepeat[j] = true;
+ nRepeat++;
+ }
+ }
+ }
+ if (nRepeat == 0) {
+ return;
+ }
+ // make a clause to delete the repeats.
+ String sql = null;
+ for (int i = 0; i < n; i++) {
+ if (isRepeat[i] == false) {
+ continue;
+ }
+ if (sql == null) {
+ sql = String.format("DELETE FROM %s WHERE Id IN (%d", lutTableDef.getTableName(), list.get(i).getDatabaseId());
+ }
+ else {
+ sql = sql + String.format(",%d", list.get(i).getDatabaseId());
+ }
+ }
+ sql += ")";
+ boolean ok = false;
+ try {
+ Statement stmt = con.getConnection().createStatement();
+ ok = stmt.execute(sql);
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private ArrayList getTopicList(PamConnection con, EmptyTableDefinition lutTableDef) {
+ if (con == null) {
+ return null;
+ }
+ ArrayList topics = new ArrayList<>();
+ String qStr = "SELECT DISTINCT Topic FROM " + lutTableDef.getTableName();
+ try {
+ Statement stmt = con.getConnection().createStatement();
+ boolean ok = stmt.execute(qStr);
+ if (ok == false) {
+ return null;
+ }
+ ResultSet results = stmt.getResultSet();
+ while (results.next()) {
+ String topic = results.getString(1);
+ topics.add(topic);
+ }
+ } catch (SQLException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ return topics;
}
public LookupList createLookupList(PamCursor resultSet, String topic) {
diff --git a/src/generalDatabase/lookupTables/LookupItem.java b/src/generalDatabase/lookupTables/LookupItem.java
index 7115406e..9ee05094 100644
--- a/src/generalDatabase/lookupTables/LookupItem.java
+++ b/src/generalDatabase/lookupTables/LookupItem.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.PamSymbol;
import PamView.PamSymbolType;
@@ -232,7 +233,7 @@ public class LookupItem implements Cloneable, Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/generalDatabase/lookupTables/LookupList.java b/src/generalDatabase/lookupTables/LookupList.java
index 8e0a0e0c..7714cdd3 100644
--- a/src/generalDatabase/lookupTables/LookupList.java
+++ b/src/generalDatabase/lookupTables/LookupList.java
@@ -7,6 +7,7 @@ import java.util.Vector;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Handles information for a single list from the look up table
@@ -253,7 +254,7 @@ public class LookupList implements Cloneable, Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/generalDatabase/parameterstore/ParameterDatabaseStore.java b/src/generalDatabase/parameterstore/ParameterDatabaseStore.java
new file mode 100644
index 00000000..29c740eb
--- /dev/null
+++ b/src/generalDatabase/parameterstore/ParameterDatabaseStore.java
@@ -0,0 +1,187 @@
+package generalDatabase.parameterstore;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.Collection;
+
+import PamModel.parametermanager.ManagedParameters;
+import PamModel.parametermanager.PamParameterData;
+import PamModel.parametermanager.PamParameterSet;
+import generalDatabase.DBControlUnit;
+import generalDatabase.EmptyTableDefinition;
+import generalDatabase.PamConnection;
+import generalDatabase.PamTableItem;
+import generalDatabase.SQLTypes;
+
+/**
+ * Store parameters from a managed parameter set in the PAMGuard database. These go into a dead simple table, which has
+ * two columns. The first is a name, the second a string value. Each parameter can only appear once.
+ * This works with ManagedParameters using the same names and field names that go into the xml output.
+ * @author dg50
+ *
+ */
+public class ParameterDatabaseStore {
+
+
+ private EmptyTableDefinition tableDef;
+ private PamTableItem nameItem, dataItem;
+
+ public ParameterDatabaseStore(String tableName) {
+ tableDef = new EmptyTableDefinition(tableName);
+ tableDef.addTableItem(nameItem = new PamTableItem("ParameterName", Types.VARCHAR));
+ tableDef.addTableItem(dataItem = new PamTableItem("Value", Types.VARCHAR));
+ }
+
+ public boolean saveParameterSet(ManagedParameters managedParameters) {
+ if (managedParameters == null) {
+ return false;
+ }
+ return saveParameterSet(managedParameters.getClass().getSimpleName(), managedParameters);
+ }
+
+ private boolean saveParameterSet(String name, ManagedParameters managedParameters) {
+ DBControlUnit dbControl = DBControlUnit.findDatabaseControl();
+ if (dbControl == null) {
+ return false;
+ }
+ PamConnection con = dbControl.getConnection();
+ if (checkTable(con) == false) {
+ return false;
+ }
+
+ String prefix;
+ if (name == null) {
+ prefix = "";
+ }
+ else {
+ prefix = name + ".";
+ }
+ PamParameterSet paramSet = managedParameters.getParameterSet();
+ Collection params = paramSet.getParameterCollection();
+ for (PamParameterData paramData : params) {
+ String paramName = paramData.getFieldName();
+ paramName = prefix + paramName;
+ Object data = null;
+ try {
+ data = paramData.getData();// .getField().get(managedParameters);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+// System.out.printf("Store param \"%s\" as \"%s\"\n", paramName, data);
+ saveToDatabase(con, paramName, data);
+ }
+ dbControl.commitChanges();
+
+ return true;
+ }
+
+ private boolean saveToDatabase(PamConnection con, String name, Object data) {
+ int[] existing = findExistingRows(con, name);
+ boolean ok = true;
+ if (existing == null || existing.length == 0) {
+ ok |= newRecord(con, name, data);
+ }
+ else {
+ ok |= updateRecord(con, existing[0], name, data);
+ if (existing.length > 1) {
+ for (int i = 1; i < existing.length; i++) {
+ ok |= deleteDuplicateRow(con, existing[i]);
+ }
+ }
+ }
+ return true;
+ }
+
+ private int[] findExistingRows(PamConnection con, String name) {
+ /**
+ * Find existing rows with that name.
+ */
+ int[] rows = new int[0];
+ if (con == null) {
+ return rows;
+ }
+ String qStr = String.format("SELECT Id FROM %s WHERE %s='%s'", tableDef.getTableName(), nameItem.getName(), name);
+ try {
+ Statement stmt = con.getConnection().createStatement();
+ ResultSet res = stmt.executeQuery(qStr);
+ while (res.next()) {
+ int rowId = res.getInt(1);
+ rows = Arrays.copyOf(rows, rows.length+1);
+ rows[rows.length-1] = rowId;
+ }
+ res.close();
+ stmt.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return rows;
+ }
+
+ private boolean newRecord(PamConnection con, String name, Object data) {
+
+ String insertStr = tableDef.getSQLInsertString(con.getSqlTypes());
+ try {
+ PreparedStatement stmt = con.getConnection().prepareStatement(insertStr);
+ stmt.setString(1, name);
+ if (data == null) {
+ stmt.setNull(2, Types.VARCHAR);
+ }
+ else {
+ stmt.setString(2, data.toString());
+ }
+ stmt.executeUpdate();
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean updateRecord(PamConnection con, int iRow, String name, Object data) {
+ SQLTypes st = con.getSqlTypes();
+ String updateString = String.format("UPDATE %s SET %s = '%s' WHERE Id = %d", tableDef.getTableName(),
+ st.formatColumnName(dataItem.getName()), data, iRow);
+
+ try {
+ PreparedStatement stmt = con.getConnection().prepareStatement(updateString);
+ stmt.executeUpdate();
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean deleteDuplicateRow(PamConnection con, int rowId) {
+
+ String delStr = String.format("DELETE FROM %s WHERE Id=%d", tableDef.getTableName(), rowId);
+
+ try {
+ PreparedStatement stmt = con.getConnection().prepareStatement(delStr);
+ stmt.executeUpdate();
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkTable(PamConnection con) {
+ DBControlUnit dbControl = DBControlUnit.findDatabaseControl();
+ if (dbControl == null) {
+ return false;
+ }
+ dbControl.commitChanges();
+ return dbControl.getDbProcess().checkTable(tableDef);
+ }
+
+}
diff --git a/src/generalDatabase/sqlite/SqliteSQLTypes.java b/src/generalDatabase/sqlite/SqliteSQLTypes.java
index 580c8c5e..4f2baf73 100644
--- a/src/generalDatabase/sqlite/SqliteSQLTypes.java
+++ b/src/generalDatabase/sqlite/SqliteSQLTypes.java
@@ -10,7 +10,7 @@ import PamUtils.PamCalendar;
public class SqliteSQLTypes extends SQLTypes {
- protected static final SQLiteConfig.DateClass dateClass = SQLiteConfig.DateClass.TEXT;
+ public static final SQLiteConfig.DateClass dateClass = SQLiteConfig.DateClass.TEXT;
@Override
public String typeToString(int sqlType, int length, boolean counter) {
diff --git a/src/generalDatabase/ucanAccess/UCanAccessSystem.java b/src/generalDatabase/ucanAccess/UCanAccessSystem.java
index 8f754aac..3937cf17 100644
--- a/src/generalDatabase/ucanAccess/UCanAccessSystem.java
+++ b/src/generalDatabase/ucanAccess/UCanAccessSystem.java
@@ -153,7 +153,7 @@ public class UCanAccessSystem extends BaseAccessSystem implements PamSettings {
String conStr = "jdbc:ucanaccess://"
+ fl.getAbsolutePath() + passwordEntry+noMem;
System.out.println("UCanAccess connection string = " + conStr);
- conn = DriverManager.getConnection(conStr);
+ conn = DriverManager.getConnection(conStr,"","");
conn.setAutoCommit(false);
} catch (Exception e) {
e.printStackTrace();
diff --git a/src/gpl/GPLParameters.java b/src/gpl/GPLParameters.java
index 666c559e..fcda34d9 100644
--- a/src/gpl/GPLParameters.java
+++ b/src/gpl/GPLParameters.java
@@ -6,6 +6,7 @@ import java.io.Serializable;
import PamModel.parametermanager.FieldNotFoundException;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.blockprocess.PamBlockParams;
import gpl.contour.ContourMerge;
@@ -198,7 +199,7 @@ public class GPLParameters implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
ps.findParameterData("minPeakGap").setInfo("Minimum gap", "bins", "Minimum gap between peaks (FFT time bins)");
ps.findParameterData("minCallLengthSeconds").setInfo("Minimum length", "bins", "Minimum length of a detection in seconds");
diff --git a/src/gpl/io/GPLLogging.java b/src/gpl/io/GPLLogging.java
index d8817bdc..c407193f 100644
--- a/src/gpl/io/GPLLogging.java
+++ b/src/gpl/io/GPLLogging.java
@@ -5,6 +5,7 @@ import java.sql.Types;
import PamDetection.AcousticSQLLogging;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLTypes;
@@ -22,7 +23,7 @@ public class GPLLogging extends AcousticSQLLogging {
super(gplDetectionBlock, gplControlledUnit.getUnitName() + " Detections");
this.gplControlledUnit = gplControlledUnit;
- PamTableDefinition pamTable = getTableDefinition();
+ EmptyTableDefinition pamTable = getTableDefinition();
pamTable.addTableItem(peakValue = new PamTableItem("PeakValue", Types.REAL));
pamTable.addTableItem(contourArea = new PamTableItem("ContourArea", Types.REAL));
}
diff --git a/src/group3dlocaliser/Group3DParams.java b/src/group3dlocaliser/Group3DParams.java
index fbf75743..6467a9ad 100644
--- a/src/group3dlocaliser/Group3DParams.java
+++ b/src/group3dlocaliser/Group3DParams.java
@@ -6,6 +6,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamView.GroupedSourceParameters;
import group3dlocaliser.algorithm.LocaliserAlgorithm3D;
@@ -126,7 +127,7 @@ public class Group3DParams implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("algorithmSpecificParams");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java b/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java
index 7f7e1371..735d70f1 100644
--- a/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java
+++ b/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class MFPGridSearchParams implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class MFPGridSearchParams implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("fftLength");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java b/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java
index 6f2a0fb2..8c845ffe 100644
--- a/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java
+++ b/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import group3dlocaliser.grids.SphericalGrid;
import pamMaths.PamVector;
@@ -49,7 +50,7 @@ public class TOADGridParams implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("gridType");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java b/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java
index 1aa70f8a..b0e11190 100644
--- a/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java
+++ b/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Parameters that apply to all TOAD based localisers.
@@ -117,7 +118,7 @@ public class TOADBaseParams implements Cloneable, Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java b/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java
index 879eae8b..86e2397d 100644
--- a/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java
+++ b/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.dataSelector.DataSelectParams;
public class Group3DDataSelectParams extends DataSelectParams implements Serializable, Cloneable, ManagedParameters {
@@ -28,7 +29,7 @@ public class Group3DDataSelectParams extends DataSelectParams implements Seriali
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/group3dlocaliser/grids/SphericalGridParams.java b/src/group3dlocaliser/grids/SphericalGridParams.java
index f323ee53..5ece7b39 100644
--- a/src/group3dlocaliser/grids/SphericalGridParams.java
+++ b/src/group3dlocaliser/grids/SphericalGridParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class SphericalGridParams implements Serializable, Cloneable, ManagedParameters {
@@ -88,7 +89,7 @@ public class SphericalGridParams implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/group3dlocaliser/grouper/DetectionGrouperParams.java b/src/group3dlocaliser/grouper/DetectionGrouperParams.java
index fc8ea979..b3e40163 100644
--- a/src/group3dlocaliser/grouper/DetectionGrouperParams.java
+++ b/src/group3dlocaliser/grouper/DetectionGrouperParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class DetectionGrouperParams implements Serializable, Cloneable, ManagedParameters {
@@ -52,7 +53,7 @@ public class DetectionGrouperParams implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/help/JavaHelpSearch/DOCS b/src/help/JavaHelpSearch/DOCS
index aece1f43..0ed73b13 100644
Binary files a/src/help/JavaHelpSearch/DOCS and b/src/help/JavaHelpSearch/DOCS differ
diff --git a/src/help/JavaHelpSearch/DOCS.TAB b/src/help/JavaHelpSearch/DOCS.TAB
index fcb0be96..47fba810 100644
Binary files a/src/help/JavaHelpSearch/DOCS.TAB and b/src/help/JavaHelpSearch/DOCS.TAB differ
diff --git a/src/help/JavaHelpSearch/OFFSETS b/src/help/JavaHelpSearch/OFFSETS
index 7aeaea18..6dd107ae 100644
Binary files a/src/help/JavaHelpSearch/OFFSETS and b/src/help/JavaHelpSearch/OFFSETS differ
diff --git a/src/help/JavaHelpSearch/POSITIONS b/src/help/JavaHelpSearch/POSITIONS
index 168a00c2..b960a5dc 100644
Binary files a/src/help/JavaHelpSearch/POSITIONS and b/src/help/JavaHelpSearch/POSITIONS differ
diff --git a/src/help/JavaHelpSearch/SCHEMA b/src/help/JavaHelpSearch/SCHEMA
index f1bcbb62..a7d9a08c 100644
--- a/src/help/JavaHelpSearch/SCHEMA
+++ b/src/help/JavaHelpSearch/SCHEMA
@@ -1,2 +1,2 @@
JavaSearch 1.0
-TMAP bs=2048 rt=1 fl=-1 id1=6700 id2=1
+TMAP bs=2048 rt=1 fl=-1 id1=6882 id2=1
diff --git a/src/help/JavaHelpSearch/TMAP b/src/help/JavaHelpSearch/TMAP
index 0f4d546b..b0102e13 100644
Binary files a/src/help/JavaHelpSearch/TMAP and b/src/help/JavaHelpSearch/TMAP differ
diff --git a/src/help/Map.jhm b/src/help/Map.jhm
index 176022cb..69065281 100644
--- a/src/help/Map.jhm
+++ b/src/help/Map.jhm
@@ -54,6 +54,8 @@
+
+
@@ -138,6 +140,8 @@
+
+
@@ -198,6 +202,8 @@
+
+
@@ -288,6 +294,8 @@
+
+
@@ -386,6 +394,8 @@
+
+
@@ -454,6 +464,8 @@
+
+
@@ -528,6 +540,8 @@
+
+
@@ -588,6 +602,8 @@
+
+
@@ -644,6 +660,8 @@
+
+
diff --git a/src/help/PAMGUARDHelpProject.xml b/src/help/PAMGUARDHelpProject.xml
index 69b52d84..fe06f32b 100644
--- a/src/help/PAMGUARDHelpProject.xml
+++ b/src/help/PAMGUARDHelpProject.xml
@@ -6,7 +6,7 @@
PAMGUARD
- C:\Users\dg50\source\repos\PAMGuardDG\src\help
+ C:\Users\dg50\source\repos\PAMGuardDG_2\src\help
index.html
diff --git a/src/help/PAMGUARDIndex.xml b/src/help/PAMGUARDIndex.xml
index 18d93123..7e8ea629 100644
--- a/src/help/PAMGUARDIndex.xml
+++ b/src/help/PAMGUARDIndex.xml
@@ -2,6 +2,12 @@
+
+
+
+
+
+
diff --git a/src/help/PAMGUARDTOC.xml b/src/help/PAMGUARDTOC.xml
index 73590bca..e668ab2c 100644
--- a/src/help/PAMGUARDTOC.xml
+++ b/src/help/PAMGUARDTOC.xml
@@ -195,6 +195,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/help/pamHelpStylesheet.css b/src/help/pamHelpStylesheet.css
index e2174daf..6cfd22db 100644
--- a/src/help/pamHelpStylesheet.css
+++ b/src/help/pamHelpStylesheet.css
@@ -52,7 +52,17 @@ ol {
FONT-SIZE: 14;
}
+
img.wrap {float: left}
+img.wrapright {float: right}
+img.wrapcenter {float: center}
+
+.center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ width: 85%;
+}
table, th, td {
border: 1px solid black;
@@ -63,4 +73,4 @@ th, td {
}
tr {
text-align: center;
-}
\ No newline at end of file
+}
diff --git a/src/help/utilities/tethys/docs/calibrations.html b/src/help/utilities/tethys/docs/calibrations.html
new file mode 100644
index 00000000..619d33e4
--- /dev/null
+++ b/src/help/utilities/tethys/docs/calibrations.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+Instrument Calibration Information
+
+
+
+
+
+
+ Instrument calibration information
+
+
+ Most of the calibration data is taken from the array manager and
+ from the sound acquisition module. However, PAMGuard will ask a
+ few questions about HOW the instrument was calibrated, when it was
+ done and who is responsible.
+
+
+ There are two dialogs associated with calibration. The first
+ asks for a calibration method and has the following fields:
+
+
+
+
+ Method: Must be one of the following options:
+
+ Reference hydrophone
+ Manufacturer’s specification
+ Piston phone
+ Other calibrated source
+ Unknown
+
+
+
+
+ Serial number: Hydrophone serial number
+
+
+
+ Quality: Quality assurance value:
+
+ unverified: The calibration has not been verified
+ valid: The calibration has been validated as per the quality assurance process
+ invalid: The calibration was found to be invalid during quality assurance
+
+
+
+
+ QA Comment: Textual description of the quality assurance
+ process.
+
+
+
+
+ Calibration method: Textual description of the Method.
+
+
+
+
+ The second calibrations dialog asks for:
+
+
+
+
+ Calibration date: Date the calibration was performed.
+
+
+
+ Update frequency: Must be one of the following:
+
+
+ as-needed: No updates are planned, but if a change is needed the calibration will be updated (defaul)t
+
+
+ unplanned: There are no plans to ever update the record.
+
+
+ yearly: A yearly review will be conducted to ensure that the record is valid.
+
+
+
+
+
+ Technical Person / Data Manager: These two types of data have
+ the same fields and detail who was responsible for the
+ calibration and who is responsible for maintaining the record
+ of the calibration. In many cases, this may be the same
+ person and copy buttons allow the fields to be duplicated.
+
+
+
+ Name: Responsible party’s naem
+
+
+ Organisation: Organisation to which the party reports
+
+
+ Position: Responsible party’s title
+
+
+ Email: Email contact information
+
+
+
+
+
+
+
+ Fill in as much information as you can!
+ If the export is successful, a record will show for each
+ hydrophone (or sensor) in your instrument array in the
+ calibration information table:
+
+
+
+
+
+
+
+
+
+ Previous: Module overview
+ Next: Instrument deployments
+
+
+
+
+
+
diff --git a/src/help/utilities/tethys/docs/connection.html b/src/help/utilities/tethys/docs/connection.html
new file mode 100644
index 00000000..7dc8b75e
--- /dev/null
+++ b/src/help/utilities/tethys/docs/connection.html
@@ -0,0 +1,121 @@
+
+
+
+
+Tethys Connection and Project Details
+
+
+
+
+ Connection and Project Details
+
+
+ Make sure you have a Tethys Server running. The PAMGuard interface will
+ only work with Tethys
+ 3 or later. The section below specifies how to set the
+ address of Tethys server address as well as determine if
+ PAMGuard can communicate successfully with Tethys. (The top
+ panel will be orange if communication is not working.
+
+
+ Tethys Server
+
+
+
+ The Tethys Server field next to the picture of the goddess Tethys
+ indicates the address of the Tehtys server. To change this field,
+ click on the gear icon. You will be prompted to provide a computer
+ address (URL) and a port. The address should start with http://
+ followed by the machine name or internet protocol address unless
+ the Tethys server has been configured to use an encrypted
+ connection. In this case, start the address with https://.
+
+
+
+ By default, PAMGuard will use http://localhost:9779 which
+ assumes that your Tethys server is running on the same computer as
+ PAMGuard and that it expects communication on port 9779, the
+ default port (administrators may change this).
+
+
+
+ If PAMGuard can communicate with the Tethys server, the
+ Connection and Project panel will be light grey. If
+ communication is not possible, the panel will be colored
+ orange. Likely causes for communication failure are:
+
+
+
+ The server address or port is incorrect.
+
+
+
+ Tethys has not been started on the server machine. One of the
+ main reasons that we see this is when the administrator has
+ not configured Tethys to run automatically as a service. In
+ that case, when a machine reboots (e.g., for automatic
+ operaing system updates) the server will not start
+ automatically. The Tethys manual explains how to configure
+ Tethys as a service that starts automatically when the machine
+ boots.
+
+
+
+ Firewall rules do not permit traffic between the machine
+ executing PAMGuard and the one hosting Tethys on the selected
+ port. If you do not have adminstrative privileges, you will
+ need to contact your support team for help.
+
+
+
+ Project and Instrument Information
+
+
+ Projects are names used by Tethys to help track work that should
+ be considered together, such as a series of deployments designed
+ to answer a specific question or funded under a specific
+ grant. If you do not already have a project defined in your
+ PAMGuard database, you can click the "New Project" button in the
+ "Connection and Project details" section of the Tethys
+ module. This will start a dialog that asks for a case-sensitive
+ project name and a geographic region. The geographic region is
+ for convenience, PAMGuard and Tethys track information by
+ longitude and latitude, but sometimes it is helpful to query for
+ information with respect to a geographic name such as Channel
+
+ Islands National Marine Sanctuary.
+
+
+
+ The array instrumentation is selected from a drop-down menu next
+ to the Instruments label. A dropdown menu next to the label
+ “Instruments” shows the list of hydrophone arrays. These are
+ likely to have been previously established prior to starting
+ analysis of your data by using the menu Settings -> Hydrophone
+ Array.
+
+
+
+
+ If you are a long-time user of PAMGuard, you will notice
+ additional fields are required for instrumentation: Instrument
+ Type and Instrument Id. The type indicates what type of
+ instrument is being used and may be generic such as a mooring or
+ array or denote a specific instrument such as a HARP, Rock
+ Hopper, SoundTrap, etc. The Id is a unique identifier for the
+ instrument such as a serial number. Note that if you are using
+ an older PAMGuard database, you may see a blank entry in the
+ instruments list as these new fields will not have been
+ populated. Press new/edit to access the instrument settings
+ from the Tethys module page.
+
+
+
+
+ Previous:
+ Tethys module
+ Next: Instrument calibrations
+
+
+
diff --git a/src/help/utilities/tethys/docs/deployments.html b/src/help/utilities/tethys/docs/deployments.html
new file mode 100644
index 00000000..afde0149
--- /dev/null
+++ b/src/help/utilities/tethys/docs/deployments.html
@@ -0,0 +1,143 @@
+
+
+
+
+
+Deployments
+
+
+
+
+
+ Deployments
+
+
+ Tethys uses deployment records to register information about
+ when instruments have been deployed as well as their
+ characteristics. Examples of characteristics that are recorded
+ include sample rate and the number of quantization bits,
+ description of duty cycles (if applicable), hydrophone geometry,
+ and enough details to be able find calibration data for specific
+ hydrophones.
+
+
+
+ PAMGuard will examine the
+ PAMGuard
+ database
+ and
+ binary Store to determine what records should be generated for
+ your instrumentation.
+
+
+
+ Where data were collected continuously or on a regular duty
+ cycle, PAMGuard will create a single deployment record. If data
+ were collected on a more "ad-hoc" basis, where the instrument
+ has been deployed multiple times or has irregular recording,
+ PAMGuard will generate a deployment record for each period of
+ recording.
+
+
+
+ The figure below shows an example of ad-hoc recording periods
+ identified by PAMGuard:
+
+
+
+
+
+
+ Occasionally, there may be short recording periods (e.g. while
+ you were testing kit on deck) that you do not want to export. Use
+ the select checkbox to pick all of the rows that you wish to
+ export, or right click on the table and "Select All."
+
+
+
+ When one or more deployment records are selected, the
+ "Export..." button will become available. Selecting the export
+ button will start a dialog that asks for additional information
+ about the deployments and then write records to Tethys.
+
+
+ The first page of the dialog asks for the project and geographic
+ region which will be automatically populated if they have been
+ previously specified. In addition, the following fields are
+ requested:
+
+
+ Cruise name - Optional name of the deployment cruise
+ Site - Case-sensitive name for the deployment site,
+ e.g. "Tanner Banks" or a letter designation "T". This can
+ provide a simple way to identify multiple deployments at the
+ same general location.
+
+ Responsible Party - A set of fields describing who was
+ responsible for the deployment and how they may be
+ contacted.
+
+
+
+
+ The next page of the dialog asks whether you would like to
+ export a single deployment document or multiple deployments.
+ todo: add more detail here
+
+
+
+
+ Finally, you are prompted to provide optional textual descriptions of:
+
+ Objectives - What were your objectives when deploying the
+ instrument? Example: Determine population estimates for
+ critically endangered populations of vaquita (Phocoena
+ sinus ).
+
+ Abstract - A textual description of the deployment.
+ Example: A set of high frequency recorders were deployed across the
+ northern portion of the Sea of Cortez in the historical range
+ of the vaquita (Phocoena sinus ). These recordings will
+ support detection and density estimation efforts.
+
+
+ Method - A description of the methods used. Example:
+ Small boat deployment of bottom moored SoundTrap recorders
+ with acoustic releases.
+
+
+
+ Press Finish to export the records. Once the
+ document(s) have been successuflly exported, the document name
+ associated with each recording period will be shown in the
+ Tethys Deployment column.
+
+
+
+
+
+
+
+
+ Previous: Calibrations
+
+
+ Next: Detections & Localizations
+
+
+
diff --git a/src/help/utilities/tethys/docs/detect_localize.html b/src/help/utilities/tethys/docs/detect_localize.html
new file mode 100644
index 00000000..a79be4e5
--- /dev/null
+++ b/src/help/utilities/tethys/docs/detect_localize.html
@@ -0,0 +1,161 @@
+
+
+
+
+
+Detections/Localizations
+
+
+
+
+
+ Exporting Detections/Localizations (PAMGuard data blocks)
+
+
+ The bottom left panel of the Tethys module shows a list of
+ different types of PAMGuard data that can be exported. The data
+ in this list correspond to the various PAMGuard modules that have
+ been configured. See the
+
+ data model viewer
+ help for an example of how PAMGuard might be configured.
+
+
+ Species information
+
+
+ Some of these data represent detections of specific species or
+ phenomena that must be translated to Tethys. A context menu
+ (right-click on most computers) will show the option "Species
+ info..." that will allow you to specify the
+ translation of events
+ to species identifiers and call/sound types. If you try to export
+ without having done this, the species info dialog will be started
+ automatically prior to export.
+
+
+ Selecting data blocks for import
+
+
+ In the sample data blocks below, four modules have been
+ configured, but only one of them has been run. Column "N Pam
+ Data" indicates the number of data records that have been
+ produced, and "PAMGuard Time" tells us when the data were
+ processed. "Tethys Documents" indicates how many Tethys records
+ have been produced, and should be 0 until the data are exported.
+
+
+
+
+
+
+
+ Select the data blocks to be exported by clicking on them.
+ Multiple lines can be selected by using keyboard modifiers such as
+ holding the shift while clicking to select all data blocks between
+ the last clicked block and where you click. Holding the alternate
+ (ALT) key will allow selection or de-selection of a single item
+ without affecting the selection state of other blocks.
+
+
+
+
+ SUGGESTION: It looks like we have to highlight these by clicking
+ on them. As we use select boxes for recording periods, we might
+ want to do the same thing here... We might want to rename
+ N PAM Datas to N PAM Data as data are already plural.
+
+
+
+ Exporting data blocks
+
+
+ Once the data blocks have been selected, press export. A series
+ of dialogs will guide you through the export process. The first
+ set of dialogs simply display a summary of information about what
+ will be exported.
+
+
+
+
+
+
+
+ There is nothing to change in this summary. Press Next once you
+ have reviewed it. The second panel allows specification of your
+ objectives, abstract, and method. Many modules will have
+ pre-populated the method for you. While it is recommended to populate
+ the objectives and abstract, these fields are optional.
+
+
+
+ Press Next to proceed to the next step of the dialog. You will be asked
+ what details you wish to store within the parameters that were used to
+ produce these data. Your must select one of the following:
+
+
+
+
+ None - Do not report any of parameters used to produce these
+ detections. This option is not recommended as
+ it severely limits your ability to reproduce your results at a
+ later date or know whether or not the results of different
+ studies can be used together.
+
+ Data selector only - not sure what this is
+
+ Module only - Report the parameters that were set with this
+ module. Only parameters associated with the specific module
+ will be reported. Examples include score and duration thresholds
+ as well as any other type of criterion used to determine whether
+ or not an event is associated with a specific phenomenon or species.
+
+
+ Full process chain (default) - This is the most verbose option. It includes the module
+ parameters as well as anything else that is part of the signal processing chain that leads
+ to the module. As an example, a module only setting would not report the parameters that were
+ used to generate a spectrogram that was presented to a module for classification, but the
+ full process chain would record these details as well. Use this option will dramatically
+ increase the potential to reproduce your results, but it will generate a large amount of data
+ about the signal processing chain, much of which might not be useful.
+
+
+
+
+ The final page of the dialog has an "Export data" button. Press
+ this to export the data. The system will begin generating the
+ Tethys document and the "Export data" button will be relabeled "Export complete"
+ once it is done. At this point, you can press "Finish" to close
+ the dialog.
+
+ Would it make more sense to export when the user presses
+ Finish (or change the Finish button Export)?
+
+
+
+
+ Previous: Deployments
+
+
+ Translating species to
+ taxonomic serial numbers (species encoding)
+
+
+
+
diff --git a/src/help/utilities/tethys/docs/images/Tethys-200.png b/src/help/utilities/tethys/docs/images/Tethys-200.png
new file mode 100644
index 00000000..19e3c48f
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/Tethys-200.png differ
diff --git a/src/help/utilities/tethys/docs/images/TethysGUI_1.png b/src/help/utilities/tethys/docs/images/TethysGUI_1.png
new file mode 100644
index 00000000..4a6f1adc
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/TethysGUI_1.png differ
diff --git a/src/help/utilities/tethys/docs/images/calibration_information.png b/src/help/utilities/tethys/docs/images/calibration_information.png
new file mode 100644
index 00000000..234ff348
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/calibration_information.png differ
diff --git a/src/help/utilities/tethys/docs/images/data_blocks.png b/src/help/utilities/tethys/docs/images/data_blocks.png
new file mode 100644
index 00000000..ee80ccff
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/data_blocks.png differ
diff --git a/src/help/utilities/tethys/docs/images/deploymentspanel.png b/src/help/utilities/tethys/docs/images/deploymentspanel.png
new file mode 100644
index 00000000..8516c96b
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/deploymentspanel.png differ
diff --git a/src/help/utilities/tethys/docs/images/species_codes.png b/src/help/utilities/tethys/docs/images/species_codes.png
new file mode 100644
index 00000000..db8ce2ae
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/species_codes.png differ
diff --git a/src/help/utilities/tethys/docs/images/species_search.png b/src/help/utilities/tethys/docs/images/species_search.png
new file mode 100644
index 00000000..73b2c36f
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/species_search.png differ
diff --git a/src/help/utilities/tethys/docs/images/stream_algo_info.png b/src/help/utilities/tethys/docs/images/stream_algo_info.png
new file mode 100644
index 00000000..d9480428
Binary files /dev/null and b/src/help/utilities/tethys/docs/images/stream_algo_info.png differ
diff --git a/src/help/utilities/tethys/docs/tethys_module.html b/src/help/utilities/tethys/docs/tethys_module.html
new file mode 100644
index 00000000..e21ce748
--- /dev/null
+++ b/src/help/utilities/tethys/docs/tethys_module.html
@@ -0,0 +1,92 @@
+
+
+
+Tethys Module Overview
+
+
+
+ Tethys Module Overview
+
+
+ It is assumed that you are familiar with PAMGuard and have some
+ knowledge about Tethys.
+ Documentation
+ and tutorials
+ are available at the Tethys
+ web site .
+
+
+ Launch PAMGuard in viewer mode
+
+ Tethys export is only available in
+ PAMGuard
+ Viewer mode
+ and is used to archive project data to a centralised
+ database. It is NOT a replacement for the
+ existing PAMGuard
+ database . Open the PAMGuard database that you wish to use
+ in viewer mode.
+
+
+ PAMGuard Tethys Module
+
+
+ Add a Tethys module to PAMGuard from the File / Add Modules /
+ Utilities menu. A new tab panel will show the Tethys interface
+
+
+
+
+
+
+
+ The tab shows a number of panes for the connection to the server
+ and the various types of data that will be output to the
+ database. Some of these panes summarize information on what's in
+ the current PAMGuard dataset (consisting of your PAMGuard
+ database and binary store), others may be empty until you start
+ to export to Tethys.
+
+
+
+ The Tethys module consists of several panels:
+
+
+
+ Connection and Project Details -
+ Specifies the location of the Tethys server and metadata about
+ the project.
+
+
+ Data Export - There are several panes that are responsible
+ for exporting information about instrument deployments, their
+ calibrations, and what they detected/localized.
+
+
+
+
+
+
+ Previous: Overview
+ Next: Connection
+ & Project Details
+
+
+
diff --git a/src/help/utilities/tethys/docs/tethys_overview.html b/src/help/utilities/tethys/docs/tethys_overview.html
new file mode 100644
index 00000000..6e9e6515
--- /dev/null
+++ b/src/help/utilities/tethys/docs/tethys_overview.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+Tethys Module Overview
+
+
+
+ Tethys Interface
+
+ Overview
+
+
+
+
+
+
+ PAMGuard is compatible
+ with Tethys 3.0 or
+ later.
+ Tethys is a freely
+ available open source temporal-spatial database for metadata
+ related to acoustic recordings. The database is intended to house
+ the metadata from marine mammal detection and localization
+ studies, allowing the user to perform meta analyses or to
+ aggregate data from many experimental efforts based on a common
+ attribute. This resulting database can then be queried based on
+ time, space, or any desired attribute and the results can be
+ integrated with external datasets such as NASA's Ocean Color,
+ lunar illumination, etc. in a consistent manner. While Tethys is
+ designed primarily for acoustic metadata from marine mammals, the
+ design is general enough to permit use in other areas as well.
+
+
+
+
+ The Tethys database is not a replacement for the existing
+ PAMGuard
+ Database. Where the PAMGuard database only contains data from
+ a single instrument or cruise, the Tethys database contains data
+ from many cruises and projects and can be used to hold a summary
+ of all data from a lab or organisation. PAMGuard's Tethys module
+ provides an interface for exporting detailed or summary
+ information about acoustic detections to the Tethys database.
+
+
+
+ Before using the module in PAMGuard, you should install the Tethys
+ Server. While clients that communicate with Tethys can run on a
+ variety of computer operating systems, there are a small number of
+ dependencies on Microsoft technologies that require the server to
+ be installed on a Microsoft Windows machine.
+ Instructions
+ for installing the Tethys Server can be found here.
+
+
+
+
+ Module help:
+
+
+ The Tethys module (start here)
+ The Connecting to Tethys
+ The Instrument calibrations
+ The Instrument deployments
+ The Detections & Localizations
+ Guide to specifying species names
+
+
+
+
+
diff --git a/src/help/utilities/tethys/docs/tethys_server.html b/src/help/utilities/tethys/docs/tethys_server.html
new file mode 100644
index 00000000..b9330ed2
--- /dev/null
+++ b/src/help/utilities/tethys/docs/tethys_server.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+ Tethys Module Overview
+
+
+ Tethys Interface
+ Tethys Server
+
+ Tethys is ...
+
+
+
+
+ Previous: Quick Start
+
+
+
+
+
diff --git a/src/help/utilities/tethys/docs/tethys_speciescodes.html b/src/help/utilities/tethys/docs/tethys_speciescodes.html
new file mode 100644
index 00000000..d3b63a50
--- /dev/null
+++ b/src/help/utilities/tethys/docs/tethys_speciescodes.html
@@ -0,0 +1,192 @@
+
+
+
+Species coding
+
+
+
+
+ Species and Call Type Names
+
+ When exporting data from PAMGuard to Tethys, some PAMGuard records
+ will require additional information indicating what type of animal
+ or phenomena were detected. If a specific call-type was detected,
+ e.g. "Clicks" or "Whistles", these should be noted as well.
+
+ Species Names
+
+ Tethys uses the Integrated Taxonomic
+ Information System (ITIS) to encode species names as taxonomic
+ serial numbers (TSNs), unique numeric identifiers for species.
+ These data conform with several international coding systems which
+ are described on the ITIS
+ standards page.
+
+
+
+ It is not uncommon to be unable to describe a call to the genus
+ level. In such cases, one can use a higher taxonomic level. For
+ example, beaked whale echolocation clicks are distinctive from the
+ clicks of other toothed whales as their pulses have a
+ frequency-modulated component. While they can frequently be
+ associated with the family Hyperodontidae, it is not always
+ possible to associate a click to a specific species as many of the
+ at least twenty-two species remain understudied. In such a case,
+ we would use the TSN for Hyperodontidae, 770799. While not
+ currently supported by PAMGuard, each species identifier has an
+ optional Group attribute that can be used in an ad-hoc manner to
+ provide additional information. This can be used to add
+ population markers, tentative genus groups, etc.
+
+
+
+ ITIS does not describe abiotic sounds, Tethys records such sounds as follows:
+
+
+ For anthropogenic signals, the Tethys convention is to
+ use Homo sapiens , TSN 180092, for the species code
+ and describe the human-generated signal via a call type,
+ e.g. ship, mid-frequency active sonar, etc.
+
+
+ Tethys reserves the TSN -10 for geophonic signals.
+ The call type is used to describe the source. Examples
+ include ambient sound, earthquake, rain, etc. Note that negative TSNs
+ are not part of the ITIS standard.
+
+
+
+
+ Note that in general, you do not have to worry about remembering
+ TSNs. Tethys uses TSNs internally, but will translate TSNs to/from
+ Latin names or user-defined abbreviations both when querying and
+ presenting results.
+
+ Call types
+
+
+ Some detectors identify specific call types. When this is the
+ case, users will need to specify the call type name. While
+ species names are standardized in Tethys, call names do not have a
+ well-defined standard and experts frequently use different names
+ for the same type of call. Consequently, Tethys does not provide a
+ standard coding for call types and users are free to choose the call
+ type names with which they feel most comfortable.
+
+
+
+ That said, the authors of Tethys do however provide a list of recommend call
+ types for many species. These recommendations can be accessed in the
+
+ supplemental information of the open access article "Management of acoustic metadata
+ for bioacoustics," Roch et al. (2016),
+ (DOI:10.1016/j.ecoinf.2015.12.002 ).
+
+
+
+ Export dialog
+
+
+
+ During export of records that are species-specific, a dialog will
+ appear that lists the types of events that were found by PAMGuard
+ modules. This dialog permits users to specify how the ad-hoc species
+ species/call encoding scheme used by PAMGuard modules can be systematically
+ translated to the TSNs and call types are stored in Tethys.
+
+
+
+ PAMGuard events typically are a short name that represents the
+ species and/or potentially a call. Knowledge of the PAMGuard
+ modules that were run and the data on which they executed will let
+ a user infer what should be recorded.
+
+ The dialog below shows a sample set of events produced by one or more PAMGuard modules
+ using the names: HP, DO, SON, KW, UNK, and PHP:
+
+
+
+
+
+ The dialog above was produced from detections on data that were
+ recorded near the mouth of the River Tay in Scotland. Consequently,
+ we can infer that the harbour porpoise that is denoted by "HP" is
+ Phocena phocena , the only harbour porpoise endemic to
+ Scottish waters.
+
+
+ An ITIS code and call/sound type can be associated with each event. The dialog lists:
+
+
+
+ Once all species names and call/sound types have been identified, press the Okay button.
+
+
+
+
+
+ Searching for ITIS Taxonomic Serial Numbers (TSNs)
+
+
+ As noted above, pressing Find without typing a TSN will bring up a
+ search dialog:
+
+
+
+
+
+
+
+ The top of this dialog has a search box where one can enter either
+ a Latin name or the common name for a species. The Tethys server
+ will search for all species that match the search-box contents.
+ For many species, there are common name entries in languages
+ other than English, and these are searched as well.
+
+
+ Once you press the search button, a list will appear with all
+ matches for your search term. If there are too many, a scroll bar
+ will permit you to look through the list. Select the entry that
+ you wish and press OK. The TSN on the species dialog will be
+ populated along with the Latin name and common names from the ITIS
+ database.
+
+
+
+
+
+
+
+ Previous: Detections & Localizations
+
+
+ Returrn to overview
+
+
+
diff --git a/src/landMarks/LandmarkData.java b/src/landMarks/LandmarkData.java
index 2be20e55..ef0cb561 100644
--- a/src/landMarks/LandmarkData.java
+++ b/src/landMarks/LandmarkData.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamController.masterReference.MasterReferencePoint;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.LatLong;
import PamView.PamSymbol;
@@ -49,7 +50,7 @@ public class LandmarkData extends Object implements Serializable, Cloneable, Man
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/landMarks/LandmarkDatas.java b/src/landMarks/LandmarkDatas.java
index d4cd386d..73fb4785 100644
--- a/src/landMarks/LandmarkDatas.java
+++ b/src/landMarks/LandmarkDatas.java
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class LandmarkDatas implements Serializable, Cloneable, ManagedParameters {
@@ -76,7 +77,7 @@ public class LandmarkDatas implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/levelMeter/LevelMeterParams.java b/src/levelMeter/LevelMeterParams.java
index dd1b6752..c25860dc 100644
--- a/src/levelMeter/LevelMeterParams.java
+++ b/src/levelMeter/LevelMeterParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class LevelMeterParams implements Cloneable, Serializable, ManagedParameters {
@@ -35,7 +36,7 @@ public class LevelMeterParams implements Cloneable, Serializable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/likelihoodDetectionModule/AcquisitionSettings.java b/src/likelihoodDetectionModule/AcquisitionSettings.java
index abf61481..10033395 100644
--- a/src/likelihoodDetectionModule/AcquisitionSettings.java
+++ b/src/likelihoodDetectionModule/AcquisitionSettings.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* The AcquisitionSettings class provides a module-local storage object for holding
@@ -48,7 +49,7 @@ public class AcquisitionSettings implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/likelihoodDetectionModule/ConfigurationDialogSettings.java b/src/likelihoodDetectionModule/ConfigurationDialogSettings.java
index 6856e501..9011ffbd 100644
--- a/src/likelihoodDetectionModule/ConfigurationDialogSettings.java
+++ b/src/likelihoodDetectionModule/ConfigurationDialogSettings.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* The Class ConfigurationDialogSettings holds parameters about the
@@ -28,7 +29,7 @@ public class ConfigurationDialogSettings implements Serializable, ManagedParamet
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("expandedState");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/likelihoodDetectionModule/GuardBand.java b/src/likelihoodDetectionModule/GuardBand.java
index ccd9a6c0..cb07df7b 100644
--- a/src/likelihoodDetectionModule/GuardBand.java
+++ b/src/likelihoodDetectionModule/GuardBand.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Represents the parameters that make up a guard band, used as
@@ -106,7 +107,7 @@ public class GuardBand implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java b/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java
index 9c405cdd..9481c26c 100644
--- a/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java
+++ b/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java
@@ -11,6 +11,7 @@ import java.util.Iterator;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* The Class LikelihoodDetectionParameters provides the standard PamGuard
@@ -271,7 +272,7 @@ public class LikelihoodDetectionParameters implements Serializable, Cloneable, M
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/likelihoodDetectionModule/LikelihoodFFTParameters.java b/src/likelihoodDetectionModule/LikelihoodFFTParameters.java
index e90e51c8..13b85fda 100644
--- a/src/likelihoodDetectionModule/LikelihoodFFTParameters.java
+++ b/src/likelihoodDetectionModule/LikelihoodFFTParameters.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import fftManager.FFTParameters;
import Spectrogram.WindowFunction;
@@ -270,7 +271,7 @@ public class LikelihoodFFTParameters implements Serializable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("sourceNumber");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/likelihoodDetectionModule/SignalBand.java b/src/likelihoodDetectionModule/SignalBand.java
index 00e7af96..3b3150d6 100644
--- a/src/likelihoodDetectionModule/SignalBand.java
+++ b/src/likelihoodDetectionModule/SignalBand.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Represents the parameters that make up a signal band, used as
@@ -151,7 +152,7 @@ public class SignalBand implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/likelihoodDetectionModule/TargetConfiguration.java b/src/likelihoodDetectionModule/TargetConfiguration.java
index 29c82890..0cc0e398 100644
--- a/src/likelihoodDetectionModule/TargetConfiguration.java
+++ b/src/likelihoodDetectionModule/TargetConfiguration.java
@@ -5,6 +5,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import likelihoodDetectionModule.normalizer.NormalizerProcess.NormalizerAlgorithm;
/**
@@ -453,7 +454,7 @@ public class TargetConfiguration implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/loc3d_Thode/TowedArray3DSQLLogging.java b/src/loc3d_Thode/TowedArray3DSQLLogging.java
index c5a8b1f7..95bc98e6 100644
--- a/src/loc3d_Thode/TowedArray3DSQLLogging.java
+++ b/src/loc3d_Thode/TowedArray3DSQLLogging.java
@@ -1,5 +1,6 @@
package loc3d_Thode;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamDetectionLogging;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
@@ -17,7 +18,6 @@ public class TowedArray3DSQLLogging extends PamDetectionLogging {
TowedArray3DController towedArray3DController;
- PamTableDefinition tableDefinition;
PamTableItem dateItem, range_boat_Item, range_f_Item, range_r_Item, depthItem, azi_boat_Item,azi_f_Item, azi_r_Item, tdd_Item,
bearing_f_Item,bearing_r_Item, tds_f_Item, tds_r_Item, za_f_Item, za_r_Item;
@@ -34,7 +34,7 @@ public class TowedArray3DSQLLogging extends PamDetectionLogging {
this.towedArray3DController = towedArray3DController;
// create the table definition.
- tableDefinition = createTableDefinition();
+ PamTableDefinition tableDefinition = createTableDefinition();
}
public PamTableDefinition createTableDefinition() {
diff --git a/src/loggerForms/FormDescription.java b/src/loggerForms/FormDescription.java
index b3d55501..a212b94d 100644
--- a/src/loggerForms/FormDescription.java
+++ b/src/loggerForms/FormDescription.java
@@ -38,6 +38,14 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
+import Array.streamerOrigin.GPSOriginMethod;
+import Array.streamerOrigin.GPSOriginSystem;
+import Array.streamerOrigin.HydrophoneOriginMethod;
+import Array.streamerOrigin.HydrophoneOriginMethods;
+import Array.streamerOrigin.OriginIterator;
+import Array.streamerOrigin.StaticOriginSystem;
+import GPS.GpsData;
+
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@@ -49,6 +57,7 @@ import pamScrollSystem.ScrollPaneAddon;
import PamView.PamTabPanel;
import PamView.panel.PamPanel;
import PamView.symbol.StandardSymbolManager;
+import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import PamController.PamControlledUnitSettings;
import PamController.PamController;
@@ -1589,7 +1598,9 @@ public class FormDescription implements Cloneable, Comparable {
normalForm.destroyForm();
}
if (hiddenForm != null) {
- normalForm.destroyForm();
+ if (normalForm != null) {
+ normalForm.destroyForm();
+ }
}
if (subtabForms != null) {
for (LoggerForm aForm:subtabForms) {
@@ -2021,4 +2032,32 @@ public class FormDescription implements Cloneable, Comparable {
public void setNeedsUDFSave(boolean needsUDFSave) {
this.needsUDFSave = needsUDFSave;
}
+
+ public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) {
+ GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit);
+ if (gps != null) {
+ return gps;
+ }
+ gps = getOrigin(StaticOriginSystem.class, formsDataUnit);
+ return gps;
+ }
+
+ private GpsData getOrigin(Class originClass, FormsDataUnit formsDataUnit) {
+ HydrophoneOriginMethods origins = HydrophoneOriginMethods.getInstance();
+ HydrophoneOriginMethod origin = origins.getMethod(GPSOriginMethod.class, null, null);
+ if (origin == null) {
+ return null;
+ }
+ OriginIterator gpsIter = origin.getGpsDataIterator(PamDataBlock.ITERATOR_END);
+ GpsData prev = null;
+ while (gpsIter.hasPrevious()) {
+ prev = gpsIter.previous();
+ if (prev.getTimeInMillis() < formsDataUnit.getTimeMilliseconds()) {
+ break;
+ }
+ }
+ return prev;
+ }
+
+
}
diff --git a/src/loggerForms/FormPlotOptions.java b/src/loggerForms/FormPlotOptions.java
index 8f55f828..9763d8ba 100644
--- a/src/loggerForms/FormPlotOptions.java
+++ b/src/loggerForms/FormPlotOptions.java
@@ -6,6 +6,7 @@ import java.util.Arrays;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
/**
@@ -95,7 +96,7 @@ public class FormPlotOptions implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("controlChoices");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/loggerForms/FormSettings.java b/src/loggerForms/FormSettings.java
index 199edfe4..f7553e13 100644
--- a/src/loggerForms/FormSettings.java
+++ b/src/loggerForms/FormSettings.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Manage a bit of persistent data for a single Logger form description.
@@ -32,7 +33,7 @@ public class FormSettings implements Cloneable, Serializable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/loggerForms/FormsControl.java b/src/loggerForms/FormsControl.java
index e88c1343..94cf9112 100644
--- a/src/loggerForms/FormsControl.java
+++ b/src/loggerForms/FormsControl.java
@@ -614,6 +614,32 @@ public class FormsControl extends PamControlledUnit {
return new ModuleStatus(ModuleStatus.STATUS_OK);
}
+
+ /**
+ * Some things that are meant to be boolean are coming out as int or string so
+ * need to do some type checking.
+ * @param value
+ * @return
+ */
+ public static Boolean checkBadBoolean(Object value) {
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+ if (value == null) {
+ return null;
+ }
+ if (value instanceof String) {
+ String str = (String) value;
+ str = str.strip();
+ return str.equals("1") || str.toLowerCase().equals("false");
+ }
+ if (value instanceof Integer) {
+ int val = (Integer) value;
+ return val != 0;
+ }
+
+ return null;
+ }
// @Override
// public Serializable getSettingsReference() {
// return (Serializable) dummyParams;
diff --git a/src/loggerForms/FormsDataDisplayTable.java b/src/loggerForms/FormsDataDisplayTable.java
index f30316fe..1300fc79 100644
--- a/src/loggerForms/FormsDataDisplayTable.java
+++ b/src/loggerForms/FormsDataDisplayTable.java
@@ -208,7 +208,15 @@ public class FormsDataDisplayTable {
Object[] fd = pamDataUnit.getFormData();
int ctIndex = columnIndex-extraColumns.length;
ControlDescription ctrlDescription = formDescription.getInputControlDescriptions().get(ctIndex);
- return ctrlDescription.formatDataItem(fd[ctIndex]);
+ Object value = ctrlDescription.formatDataItem(fd[ctIndex]);
+ if (value == null) return null;
+ if (getColumnClass(columnIndex) == Boolean.class) {
+ if (value instanceof Boolean == false) {
+// System.out.println("Bad boolean value: " + value);
+ return FormsControl.checkBadBoolean(value);
+ }
+ }
+ return value;
// return fd[ctIndex];
}
catch (Exception e) {
@@ -252,6 +260,8 @@ public class FormsDataDisplayTable {
}
+
+
/**
* Called when data have changed in the datablock.
*/
diff --git a/src/loggerForms/FormsDataUnit.java b/src/loggerForms/FormsDataUnit.java
index 963c6374..32ab905d 100644
--- a/src/loggerForms/FormsDataUnit.java
+++ b/src/loggerForms/FormsDataUnit.java
@@ -87,7 +87,9 @@ public class FormsDataUnit extends PamDataUnit {
* we want to as a reference, etc.
*/
if (recalculate || formOriginLatLong == null) {
- formOriginLatLong = loggerForm.getOriginLatLong(this);
+ if (formDescription != null) {
+ formOriginLatLong = formDescription.getOriginLatLong(this);
+ }
}
return formOriginLatLong;
}
diff --git a/src/loggerForms/FormsLogging.java b/src/loggerForms/FormsLogging.java
index 5420f3a9..64e0d8e6 100644
--- a/src/loggerForms/FormsLogging.java
+++ b/src/loggerForms/FormsLogging.java
@@ -112,7 +112,7 @@ public class FormsLogging extends SQLLogging {
// }
// }
-
+// formDescription.getf
FormsDataUnit formsDataUnit = new FormsDataUnit(null, timeMilliseconds, formDescription, formData);
formsDataUnit.setDatabaseIndex(databaseIndex);
diff --git a/src/loggerForms/LoggerForm.java b/src/loggerForms/LoggerForm.java
index 11f562a7..b31ae9a8 100644
--- a/src/loggerForms/LoggerForm.java
+++ b/src/loggerForms/LoggerForm.java
@@ -21,6 +21,7 @@ import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
+import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.Timer;
@@ -104,7 +105,7 @@ public class LoggerForm{
private CounterControl counter;
- private HydrophoneOriginMethods origins = HydrophoneOriginMethods.getInstance();
+// private HydrophoneOriginMethods origins = HydrophoneOriginMethods.getInstance();
/**
* @return the hasCounter
@@ -529,7 +530,10 @@ public class LoggerForm{
innerCenterPanel.add(currentRow);
currentRow = new LoggerFormPanel(this, new FlowLayout(FlowLayout.LEFT));
}else{
- currentRow.add(c.makeComponent(this));
+ JPanel component = c.makeComponent(this);
+ if (component != null) {
+ currentRow.add(component);
+ }
}
}
@@ -911,30 +915,30 @@ public class LoggerForm{
return saveButton;
}
- public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) {
- GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit);
- if (gps != null) {
- return gps;
- }
- gps = getOrigin(StaticOriginSystem.class, formsDataUnit);
- return gps;
- }
-
- private GpsData getOrigin(Class originClass, FormsDataUnit formsDataUnit) {
- HydrophoneOriginMethod origin = origins.getMethod(GPSOriginMethod.class, null, null);
- if (origin == null) {
- return null;
- }
- OriginIterator gpsIter = origin.getGpsDataIterator(PamDataBlock.ITERATOR_END);
- GpsData prev = null;
- while (gpsIter.hasPrevious()) {
- prev = gpsIter.previous();
- if (prev.getTimeInMillis() < formsDataUnit.getTimeMilliseconds()) {
- break;
- }
- }
- return prev;
- }
+// public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) {
+// GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit);
+// if (gps != null) {
+// return gps;
+// }
+// gps = getOrigin(StaticOriginSystem.class, formsDataUnit);
+// return gps;
+// }
+//
+// private GpsData getOrigin(Class originClass, FormsDataUnit formsDataUnit) {
+// HydrophoneOriginMethod origin = origins.getMethod(GPSOriginMethod.class, null, null);
+// if (origin == null) {
+// return null;
+// }
+// OriginIterator gpsIter = origin.getGpsDataIterator(PamDataBlock.ITERATOR_END);
+// GpsData prev = null;
+// while (gpsIter.hasPrevious()) {
+// prev = gpsIter.previous();
+// if (prev.getTimeInMillis() < formsDataUnit.getTimeMilliseconds()) {
+// break;
+// }
+// }
+// return prev;
+// }
// /**
diff --git a/src/loggerForms/controls/CheckboxControl.java b/src/loggerForms/controls/CheckboxControl.java
index 3be6dd8f..a0ec06e0 100644
--- a/src/loggerForms/controls/CheckboxControl.java
+++ b/src/loggerForms/controls/CheckboxControl.java
@@ -9,6 +9,7 @@ import NMEA.NMEADataBlock;
import NMEA.NMEADataUnit;
import PamView.dialog.PamCheckBox;
import PamView.dialog.PamLabel;
+import loggerForms.FormsControl;
import loggerForms.LoggerForm;
import loggerForms.controlDescriptions.ControlDescription;
@@ -41,7 +42,7 @@ public class CheckboxControl extends LoggerControl {
return;
}
try {
- checkBox.setSelected((Boolean) data);
+ checkBox.setSelected(FormsControl.checkBadBoolean(data));
}
catch(ClassCastException e) {
e.printStackTrace();
diff --git a/src/loggerForms/dataselect/FormDataSelector.java b/src/loggerForms/dataselect/FormDataSelector.java
index de627d29..926e68cb 100644
--- a/src/loggerForms/dataselect/FormDataSelector.java
+++ b/src/loggerForms/dataselect/FormDataSelector.java
@@ -70,7 +70,7 @@ public class FormDataSelector extends DataSelector {
@Override
public double scoreData(PamDataUnit pamDataUnit) {
if (controlDataSelector == null) {
- return 0;
+ return 1;
}
Object[] formData = null;
if (pamDataUnit instanceof FormsDataUnit) {
diff --git a/src/loggerForms/monitor/FormsSelectorParams.java b/src/loggerForms/monitor/FormsSelectorParams.java
index d691af0c..d1797798 100644
--- a/src/loggerForms/monitor/FormsSelectorParams.java
+++ b/src/loggerForms/monitor/FormsSelectorParams.java
@@ -7,6 +7,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.dataSelector.DataSelectParams;
public class FormsSelectorParams extends DataSelectParams implements Cloneable, Serializable, ManagedParameters {
@@ -30,7 +31,7 @@ public class FormsSelectorParams extends DataSelectParams implements Cloneable,
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("formSelection");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/ltsa/LtsaModuleHeader.java b/src/ltsa/LtsaModuleHeader.java
index 0b5d888e..50c1034d 100644
--- a/src/ltsa/LtsaModuleHeader.java
+++ b/src/ltsa/LtsaModuleHeader.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import binaryFileStorage.BinaryHeader;
import binaryFileStorage.BinaryObjectData;
import binaryFileStorage.ModuleHeader;
@@ -37,7 +38,7 @@ public class LtsaModuleHeader extends ModuleHeader implements ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("fftLength");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/ltsa/LtsaParameters.java b/src/ltsa/LtsaParameters.java
index 2dfd9a62..dbf62ec0 100644
--- a/src/ltsa/LtsaParameters.java
+++ b/src/ltsa/LtsaParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class LtsaParameters implements Cloneable, Serializable, ManagedParameters {
@@ -35,7 +36,7 @@ public class LtsaParameters implements Cloneable, Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/mapgrouplocaliser/MapGrouperSettings.java b/src/mapgrouplocaliser/MapGrouperSettings.java
index 955542dc..440700b7 100644
--- a/src/mapgrouplocaliser/MapGrouperSettings.java
+++ b/src/mapgrouplocaliser/MapGrouperSettings.java
@@ -7,6 +7,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.paneloverlay.OverlayDataInfo;
import PamView.paneloverlay.overlaymark.MarkDataSelectorParams;
import PamView.paneloverlay.overlaymark.OverlayMarkDataInfo;
@@ -64,7 +65,7 @@ public class MapGrouperSettings implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("markDataSelectorParams");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/matchedTemplateClassifer/MatchTemplate.java b/src/matchedTemplateClassifer/MatchTemplate.java
index 7f758ddf..0990a22d 100644
--- a/src/matchedTemplateClassifer/MatchTemplate.java
+++ b/src/matchedTemplateClassifer/MatchTemplate.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.RawDataHolder;
import PamguardMVC.RawDataTransforms;
@@ -51,7 +52,7 @@ public class MatchTemplate implements RawDataHolder, Serializable, Cloneable, Ma
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/matchedTemplateClassifer/MatchedTemplateParams.java b/src/matchedTemplateClassifer/MatchedTemplateParams.java
index 05f8b107..edd2b912 100644
--- a/src/matchedTemplateClassifer/MatchedTemplateParams.java
+++ b/src/matchedTemplateClassifer/MatchedTemplateParams.java
@@ -8,6 +8,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamView.PamSymbolType;
import PamView.symbol.SymbolData;
import fftFilter.FFTFilterParams;
@@ -150,7 +151,7 @@ public class MatchedTemplateParams implements Serializable, Cloneable, ManagedPa
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("fftFilterParams");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java b/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java
index acf38f67..3b248ea9 100644
--- a/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java
+++ b/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java
@@ -7,6 +7,7 @@ import java.util.List;
import PamUtils.PamArrayUtils;
import PamguardMVC.PamDataUnit;
import PamguardMVC.debug.Debug;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -49,7 +50,7 @@ public class MatchedClickAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(typeTable);
pamTableDefinition.addTableItem(mtThresholdsTable);
pamTableDefinition.addTableItem(mtMatchCorrsTable);
@@ -58,7 +59,7 @@ public class MatchedClickAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
MatchedClickAnnotation clickAnnotation =
(MatchedClickAnnotation) pamDataUnit.findDataAnnotation(MatchedClickAnnotation.class);
@@ -95,7 +96,7 @@ public class MatchedClickAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
String threshold = mtThresholdsTable.getDeblankedStringValue();
String mtMatchCorrs = mtMatchCorrsTable.getDeblankedStringValue();
diff --git a/src/mcc/mccacquisition/MCCDaqParams.java b/src/mcc/mccacquisition/MCCDaqParams.java
index f1fc3450..ba44c99e 100644
--- a/src/mcc/mccacquisition/MCCDaqParams.java
+++ b/src/mcc/mccacquisition/MCCDaqParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import Acquisition.DaqSystemXMLManager;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import analoginput.AnalogRangeData;
import simulatedAcquisition.SimProcess;
@@ -51,7 +52,7 @@ public class MCCDaqParams implements Serializable, Cloneable, ManagedParameters
return null;
}
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/metadata/MetaDataContol.java b/src/metadata/MetaDataContol.java
new file mode 100644
index 00000000..98093b08
--- /dev/null
+++ b/src/metadata/MetaDataContol.java
@@ -0,0 +1,114 @@
+package metadata;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.Serializable;
+
+import javax.swing.JFrame;
+import javax.swing.JMenuItem;
+
+import PamController.PamControlledUnit;
+import PamController.PamControlledUnitSettings;
+import PamController.PamController;
+import PamController.PamSettingManager;
+import PamController.PamSettings;
+import metadata.swing.MetaDataDialog;
+
+/**
+ * Class to handle Project MetaData. Am making this a PAMControlledUnit, but may never
+ * register it with the model ? Will see what advantages and disadvantages there are.
+ * @author dg50
+ *
+ */
+public class MetaDataContol extends PamControlledUnit implements PamSettings {
+
+ public static final String unitType = "Meta Data";
+
+ private static MetaDataContol singleInstance;
+
+ private PamguardMetaData pamguardMetaData = new PamguardMetaData();
+
+// private ParameterSetManager deploymentSetManager;
+
+
+ private MetaDataContol(String unitName) {
+ super(unitType, unitName);
+// deploymentSetManager = new ParameterSetManager(deploymentData, "Deployment Data");
+ PamSettingManager.getInstance().registerSettings(this);
+ }
+
+ /**
+ * Easy getter for singleton MetaData controller.
+ * @return meta data controller
+ */
+ public static MetaDataContol getMetaDataControl() {
+ if (singleInstance == null) {
+ singleInstance = new MetaDataContol(unitType);
+ // add this line to add it to the main modules list. Then it will get menu's, etc.
+ PamController.getInstance().addControlledUnit(singleInstance);
+ }
+ return singleInstance;
+ }
+
+ /**
+ * Get PAMGuard Metadata. This contains a nilus Deployment object wrapped up
+ * so that it can be serialised into other PAMGuard settings.
+ * @return PAMGuard meta data
+ */
+ public PamguardMetaData getMetaData() {
+ return pamguardMetaData;
+ }
+
+ /**
+ * Set the meta data object.
+ * @param metaData
+ */
+ public void setMetaData(PamguardMetaData metaData) {
+ this.pamguardMetaData = metaData;
+ }
+
+ @Override
+ public Serializable getSettingsReference() {
+ pamguardMetaData.checkSerialisation();
+ return pamguardMetaData;
+ }
+
+ @Override
+ public long getSettingsVersion() {
+ return PamguardMetaData.serialVersionUID;
+ }
+
+ @Override
+ public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
+ Object obj = pamControlledUnitSettings.getSettings();
+ if (obj instanceof PamguardMetaData) {
+ pamguardMetaData = (PamguardMetaData) obj;
+ return true;
+ }
+ return false;
+ }
+
+// @Override
+ public JMenuItem createMenu(JFrame parentFrame) {
+ JMenuItem menuItem = new JMenuItem("Project information ...");
+ menuItem.setToolTipText("General project objectives, region, etc.");
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ showDialog(parentFrame);
+ }
+ });
+ return menuItem;
+ }
+
+ protected void showDialog(JFrame parentFrame) {
+ PamguardMetaData newData = MetaDataDialog.showDialog(parentFrame, pamguardMetaData);
+ if (newData != null) {
+ this.pamguardMetaData = newData;
+ // send around a notification ?
+ }
+ }
+
+
+
+}
diff --git a/src/metadata/PamguardMetaData.java b/src/metadata/PamguardMetaData.java
new file mode 100644
index 00000000..ae4064ab
--- /dev/null
+++ b/src/metadata/PamguardMetaData.java
@@ -0,0 +1,111 @@
+package metadata;
+
+import java.io.Serializable;
+
+import PamUtils.LatLong;
+import nilus.ContactInfo;
+import nilus.Deployment;
+import nilus.DeploymentRecoveryDetails;
+import nilus.DescriptionType;
+import nilus.Helper;
+import nilus.MetadataInfo;
+import nilus.ResponsibleParty;
+import tethys.niluswraps.NilusSettingsWrapper;
+
+/**
+ * Meta data for a PAMGuard data set. This is based around serialisable versions of
+ * nilus classes to be compliant with both Tethys and PAMGuard settings files. May only
+ * need a Deployment object, but scope for adding others / other fields if it's useful.
+ * @author dg50
+ *
+ */
+public class PamguardMetaData implements Serializable {
+
+ public static final long serialVersionUID = 1L;
+
+ private NilusSettingsWrapper deploymentWrapper;
+
+ public boolean useAudioForDeploymentTimes = true;
+
+// /**
+// * Deployment time (used if different
+// */
+// private Long deploymentMillis;
+//
+// private Long recoverMillis;
+//
+// private LatLong recoverLatLong;
+
+ /**
+ * Get the deployment data
+ * @return nilus deployment
+ */
+ public Deployment getDeployment() {
+ if (deploymentWrapper == null) {
+ deploymentWrapper = new NilusSettingsWrapper<>();
+ }
+ Deployment deployment = deploymentWrapper.getNilusObject(Deployment.class);
+ if (deployment == null) {
+ deployment = new Deployment();
+ try {
+ Helper.createRequiredElements(deployment);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ e.printStackTrace();
+ }
+ deploymentWrapper.setNilusObject(deployment);
+ }
+ // check some fields we know we'll need that the Helper may not have managed.
+ if (deployment.getDescription() == null) {
+ deployment.setDescription(new DescriptionType());
+ }
+ if (deployment.getMetadataInfo() == null) {
+ deployment.setMetadataInfo(new MetadataInfo());
+ }
+ if (deployment.getMetadataInfo().getContact() == null) {
+ deployment.getMetadataInfo().setContact(new ResponsibleParty());
+ }
+ if (deployment.getMetadataInfo().getContact().getContactInfo() == null) {
+ deployment.getMetadataInfo().getContact().setContactInfo(new ContactInfo());
+ }
+
+ if (deployment.getDeploymentDetails() == null) {
+ deployment.setDeploymentDetails(new DeploymentRecoveryDetails());
+ }
+ if (deployment.getRecoveryDetails() == null) {
+ deployment.setRecoveryDetails(new DeploymentRecoveryDetails());
+ }
+ return deployment;
+ }
+
+ /**
+ * Set the deployment data.
+ * @param deployment nilus deployment
+ */
+ public void setDeployment(Deployment deployment) {
+ if (deploymentWrapper == null) {
+ deploymentWrapper = new NilusSettingsWrapper<>();
+ }
+ deploymentWrapper.setNilusObject(deployment);
+ }
+
+ /**
+ * @return the deploymentWrapper
+ */
+ public NilusSettingsWrapper getDeploymentWrapper() {
+ if (deploymentWrapper == null) {
+ deploymentWrapper = new NilusSettingsWrapper<>();
+ }
+ return deploymentWrapper;
+ }
+
+ public void checkSerialisation() {
+ // check that all wrappers have their xml up to date.
+ if (deploymentWrapper == null) {
+ deploymentWrapper = new NilusSettingsWrapper<>();
+ }
+ deploymentWrapper.reSerialise();
+ }
+
+
+
+}
diff --git a/src/metadata/swing/MetaDataDialog.java b/src/metadata/swing/MetaDataDialog.java
new file mode 100644
index 00000000..9f744391
--- /dev/null
+++ b/src/metadata/swing/MetaDataDialog.java
@@ -0,0 +1,121 @@
+package metadata.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Window;
+
+import javax.swing.BoxLayout;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.border.TitledBorder;
+
+import PamController.PamController;
+import PamView.dialog.PamDialog;
+import PamView.panel.PamNorthPanel;
+import PamView.panel.WestAlignedPanel;
+import metadata.PamguardMetaData;
+import nilus.Deployment;
+import tethys.TethysControl;
+import tethys.TethysState;
+import tethys.TethysState.StateType;
+import tethys.deployment.swing.ProjectInformationPanel;
+import tethys.swing.export.DeploymentPeriodPanel;
+import tethys.swing.export.DescriptionTypePanel;
+import tethys.swing.export.ResponsiblePartyPanel;
+
+public class MetaDataDialog extends PamDialog {
+
+ private static MetaDataDialog singleInstance;
+
+ private PamguardMetaData pamguardMetaData;
+
+ private DescriptionTypePanel descriptionPanel;
+
+ private ProjectInformationPanel projectInformationPanel;
+
+ private DeploymentPeriodPanel deploymentPeriodPanel;
+
+ private ResponsiblePartyPanel responsiblePanel;
+
+ private TethysControl tethysControl;
+
+ private MetaDataDialog(Window parentFrame) {
+ super(parentFrame, "Project information", false);
+
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BorderLayout());
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ tethysControl = (TethysControl) PamController.getInstance().findControlledUnit(TethysControl.unitType);
+
+ projectInformationPanel = new ProjectInformationPanel(parentFrame, null);
+ descriptionPanel = new DescriptionTypePanel(null, false, false, false);
+ deploymentPeriodPanel = new DeploymentPeriodPanel(parentFrame);
+ descriptionPanel.getMainPanel().setPreferredSize(new Dimension(400,300));
+
+ responsiblePanel = new ResponsiblePartyPanel();
+ JPanel northPanel = new JPanel();
+ WestAlignedPanel wp;
+ northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.Y_AXIS));
+
+ northPanel.add(wp = new WestAlignedPanel(projectInformationPanel.getMainPanel()));
+ wp.setBorder(new TitledBorder("General project information"));
+ northPanel.add(wp = new WestAlignedPanel(responsiblePanel.getMainPanel()));
+ wp.setBorder(new TitledBorder("Contact information"));
+
+ JPanel dpPanel = new WestAlignedPanel(deploymentPeriodPanel.getMainPanel());
+ dpPanel.setBorder(new TitledBorder("Deployment period"));
+
+ mainPanel.add(tabbedPane, BorderLayout.CENTER);
+ tabbedPane.add(northPanel, "General");
+ tabbedPane.add(descriptionPanel.getMainPanel(), "Description");
+ tabbedPane.add(dpPanel, "Deployment");
+
+ setResizable(true);
+
+ setDialogComponent(mainPanel);
+ }
+
+
+
+
+ public static PamguardMetaData showDialog(Window frame, PamguardMetaData pamguardMetaData) {
+ singleInstance = new MetaDataDialog(frame);
+ singleInstance.setParams(pamguardMetaData);
+ singleInstance.setVisible(true);
+ return singleInstance.pamguardMetaData;
+ }
+
+ private void setParams(PamguardMetaData pamguardMetaData) {
+ this.pamguardMetaData = pamguardMetaData;
+ Deployment deployment = pamguardMetaData.getDeployment();
+ projectInformationPanel.setParams(deployment);
+ descriptionPanel.setParams(deployment.getDescription());
+ responsiblePanel.setParams(deployment.getMetadataInfo().getContact());
+ deploymentPeriodPanel.setParams(pamguardMetaData);
+ }
+
+ @Override
+ public boolean getParams() {
+ Deployment deployment = pamguardMetaData.getDeployment();
+ boolean ok = descriptionPanel.getParams(deployment.getDescription());
+ ok &= responsiblePanel.getParams(deployment.getMetadataInfo().getContact());
+ ok &= deploymentPeriodPanel.getParams(pamguardMetaData);
+
+ if (tethysControl != null) {
+ tethysControl.sendStateUpdate(new TethysState(StateType.NEWPROJECTSELECTION));
+ }
+ return ok;
+ }
+
+ @Override
+ public void cancelButtonPressed() {
+ pamguardMetaData = null;
+ }
+
+ @Override
+ public void restoreDefaultSettings() {
+
+ }
+
+}
diff --git a/src/networkTransfer/emulator/EmulatorParams.java b/src/networkTransfer/emulator/EmulatorParams.java
index e4fe0f74..3f38266a 100644
--- a/src/networkTransfer/emulator/EmulatorParams.java
+++ b/src/networkTransfer/emulator/EmulatorParams.java
@@ -8,6 +8,7 @@ import PamController.PamControlledUnitSettings;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.LatLong;
public class EmulatorParams implements Cloneable, Serializable, ManagedParameters {
@@ -50,7 +51,7 @@ public class EmulatorParams implements Cloneable, Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("circleRadius");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/networkTransfer/receive/BuoyStatusData.java b/src/networkTransfer/receive/BuoyStatusData.java
index 6b17a6ad..8138f4bf 100644
--- a/src/networkTransfer/receive/BuoyStatusData.java
+++ b/src/networkTransfer/receive/BuoyStatusData.java
@@ -5,6 +5,7 @@ import java.util.Hashtable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamCalendar;
/**
@@ -140,7 +141,7 @@ public class BuoyStatusData implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/networkTransfer/receive/BuoyStatusValue.java b/src/networkTransfer/receive/BuoyStatusValue.java
index d73a5acd..a42ea7ff 100644
--- a/src/networkTransfer/receive/BuoyStatusValue.java
+++ b/src/networkTransfer/receive/BuoyStatusValue.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamUtils.PamCalendar;
public class BuoyStatusValue implements Serializable, ManagedParameters {
@@ -53,7 +54,7 @@ public class BuoyStatusValue implements Serializable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/networkTransfer/receive/NetworkReceiveParams.java b/src/networkTransfer/receive/NetworkReceiveParams.java
index f067c789..488899c5 100644
--- a/src/networkTransfer/receive/NetworkReceiveParams.java
+++ b/src/networkTransfer/receive/NetworkReceiveParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class NetworkReceiveParams implements Cloneable, Serializable, ManagedParameters {
@@ -40,7 +41,7 @@ public class NetworkReceiveParams implements Cloneable, Serializable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/networkTransfer/send/NetworkSendParams.java b/src/networkTransfer/send/NetworkSendParams.java
index 9e0024d8..87e25b0c 100644
--- a/src/networkTransfer/send/NetworkSendParams.java
+++ b/src/networkTransfer/send/NetworkSendParams.java
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamguardMVC.PamDataBlock;
public class NetworkSendParams implements Serializable, Cloneable, ManagedParameters {
@@ -108,7 +109,7 @@ public class NetworkSendParams implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("selectedDataBlocks");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/nidaqdev/networkdaq/NIDaqLogging.java b/src/nidaqdev/networkdaq/NIDaqLogging.java
index dc12309b..75022e5c 100644
--- a/src/nidaqdev/networkdaq/NIDaqLogging.java
+++ b/src/nidaqdev/networkdaq/NIDaqLogging.java
@@ -3,6 +3,7 @@ package nidaqdev.networkdaq;
import java.sql.Types;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -20,12 +21,12 @@ public class NIDaqLogging implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(crioTemperature);
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
Double lastTemp = niNetworkDaq.getLastTemperature();
if (lastTemp == null) {
crioTemperature.setValue(null);
@@ -38,7 +39,7 @@ public class NIDaqLogging implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
// TODO Auto-generated method stub
return false;
}
diff --git a/src/nidaqdev/networkdaq/NINetworkDaqParams.java b/src/nidaqdev/networkdaq/NINetworkDaqParams.java
index 7458739e..a7f67845 100644
--- a/src/nidaqdev/networkdaq/NINetworkDaqParams.java
+++ b/src/nidaqdev/networkdaq/NINetworkDaqParams.java
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import Acquisition.DaqSystemXMLManager;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class NINetworkDaqParams implements Serializable, Cloneable, ManagedParameters {
@@ -169,7 +170,7 @@ public class NINetworkDaqParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
if (DaqSystemXMLManager.isSelected(NINetworkDaq.systemName)) {
- return PamParameterSet.autoGenerate(this);
+ return PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
}
return null;
}
diff --git a/src/nmeaEmulator/NMEAEmulatorParams.java b/src/nmeaEmulator/NMEAEmulatorParams.java
index 1889ca17..d7b89529 100644
--- a/src/nmeaEmulator/NMEAEmulatorParams.java
+++ b/src/nmeaEmulator/NMEAEmulatorParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class NMEAEmulatorParams implements Serializable, Cloneable, ManagedParameters {
@@ -23,7 +24,7 @@ public class NMEAEmulatorParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/noiseBandMonitor/NoiseBandSettings.java b/src/noiseBandMonitor/NoiseBandSettings.java
index d905c536..8f00571c 100644
--- a/src/noiseBandMonitor/NoiseBandSettings.java
+++ b/src/noiseBandMonitor/NoiseBandSettings.java
@@ -7,6 +7,7 @@ import Filters.FilterType;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class NoiseBandSettings implements Serializable, Cloneable, ManagedParameters {
@@ -59,7 +60,7 @@ public class NoiseBandSettings implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("showStandard");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/noiseMonitor/NoiseControl.java b/src/noiseMonitor/NoiseControl.java
index 9a50ea6f..e1fbce42 100644
--- a/src/noiseMonitor/NoiseControl.java
+++ b/src/noiseMonitor/NoiseControl.java
@@ -13,6 +13,7 @@ import org.w3c.dom.Element;
import PamController.PamControlledUnit;
import PamController.PamControlledUnitSettings;
+import PamController.PamController;
import PamController.PamSettingManager;
import PamController.PamSettings;
import PamView.PamTabPanel;
@@ -298,4 +299,15 @@ public class NoiseControl extends PamControlledUnit implements PamSettings {
public NoiseSettings getNoiseSettings() {
return noiseSettings;
}
+
+ @Override
+ public void notifyModelChanged(int changeType) {
+ super.notifyModelChanged(changeType);
+ switch (changeType) {
+ case PamController.INITIALIZATION_COMPLETE:
+ noiseProcess.setupProcess();
+ sortBandEdges();
+ }
+ }
+
}
diff --git a/src/noiseMonitor/NoiseDataBlock.java b/src/noiseMonitor/NoiseDataBlock.java
index b5e7f628..effbd591 100644
--- a/src/noiseMonitor/NoiseDataBlock.java
+++ b/src/noiseMonitor/NoiseDataBlock.java
@@ -2,11 +2,18 @@ package noiseMonitor;
import noiseMonitor.alarm.NoiseAlarmCounter;
import noiseMonitor.alarm.NoiseAlarmProvider;
+import noiseMonitor.species.TethysNoiseDataProvider;
+import tethys.TethysControl;
+import tethys.pamdata.TethysDataProvider;
+import tethys.species.DataBlockSpeciesManager;
+import tethys.species.FixedSpeciesManager;
import alarm.AlarmCounter;
import alarm.AlarmCounterProvider;
import alarm.AlarmDataSource;
import PamUtils.FrequencyFormat;
import PamUtils.PamUtils;
+import PamguardMVC.DataAutomation;
+import PamguardMVC.DataAutomationInfo;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamProcess;
@@ -32,13 +39,15 @@ public class NoiseDataBlock extends PamDataBlock implements Alarm
private NoiseAlarmProvider noiseAlarmCounter;
/**
- * These are the names used in the database columns, so dont' change them on pain of
+ * These are the names used in the database columns, so don't change them on pain of
* nothing ever working ever again !
*/
public static final String[] measureNames = {"mean", "median", "low95", "high95", "Min", "Max", "Peak"};
public static final String[] displayNames = {"Mean", "Median", "Lower 95%", "Upper 95%", "Minimum", "Maximim", "Peak"};
private int statisticTypes;
+ private TethysNoiseDataProvider tethysNoiseDataProvider;
+ private FixedSpeciesManager fixedSpeciesManager;
public NoiseDataBlock(String dataName,
PamProcess parentProcess, int channelMap) {
@@ -244,6 +253,27 @@ public class NoiseDataBlock extends PamDataBlock implements Alarm
}
return noiseAlarmCounter;
}
+
+ @Override
+ public DataAutomationInfo getDataAutomationInfo() {
+ return new DataAutomationInfo(DataAutomation.AUTOMATIC);
+ }
+
+ @Override
+ public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) {
+ if (tethysNoiseDataProvider == null) {
+ tethysNoiseDataProvider = new TethysNoiseDataProvider(tethysControl, this);
+ }
+ return tethysNoiseDataProvider;
+ }
+
+ @Override
+ public DataBlockSpeciesManager getDatablockSpeciesManager() {
+ if (fixedSpeciesManager == null) {
+ fixedSpeciesManager = new FixedSpeciesManager(this, -10, "anthropogenic", "noise");
+ }
+ return fixedSpeciesManager;
+ }
}
diff --git a/src/noiseMonitor/NoiseDisplaySettings.java b/src/noiseMonitor/NoiseDisplaySettings.java
index 7ef4f5de..b70db3ac 100644
--- a/src/noiseMonitor/NoiseDisplaySettings.java
+++ b/src/noiseMonitor/NoiseDisplaySettings.java
@@ -6,6 +6,7 @@ import java.util.Arrays;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class NoiseDisplaySettings implements Serializable, Cloneable, ManagedParameters {
@@ -70,7 +71,7 @@ public class NoiseDisplaySettings implements Serializable, Cloneable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("displayLengthSeconds");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/noiseMonitor/NoiseLogging.java b/src/noiseMonitor/NoiseLogging.java
index 4bbc0cfd..a3a62d61 100644
--- a/src/noiseMonitor/NoiseLogging.java
+++ b/src/noiseMonitor/NoiseLogging.java
@@ -116,5 +116,27 @@ public class NoiseLogging extends SQLLogging {
}
}
}
+
+ private long lastTime;
+
+ @Override
+ protected PamDataUnit createDataUnit(SQLTypes sqlTypes, long timeMilliseconds, int databaseIndex) {
+ int chan = channelNumber.getIntegerValue();
+ int nBands = noiseDataBlock.getBandLoEdges().length;
+ int nMeasures = noiseDataBlock.getUsedMeasureNames().length;
+ if (nMeasures * nBands != bandItems.length) {
+ return null;
+ }
+ double[][] bandData = new double[nBands][nMeasures];
+ for (int iBand = 0, iCol = 0; iBand < nBands; iBand++) {
+ for (int iMeasure = 0; iMeasure < nMeasures; iMeasure++, iCol++) {
+ bandData[iBand][iMeasure] = bandItems[iCol].getDoubleValue();
+ }
+ }
+
+ NoiseDataUnit noiseDataUnit = new NoiseDataUnit(timeMilliseconds, 1< i) {
diff --git a/src/noiseMonitor/alarm/NoiseAlarmParameters.java b/src/noiseMonitor/alarm/NoiseAlarmParameters.java
index d2f7ec60..551d430c 100644
--- a/src/noiseMonitor/alarm/NoiseAlarmParameters.java
+++ b/src/noiseMonitor/alarm/NoiseAlarmParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class NoiseAlarmParameters implements Serializable, Cloneable, ManagedParameters {
@@ -26,7 +27,7 @@ public class NoiseAlarmParameters implements Serializable, Cloneable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
}
diff --git a/src/noiseMonitor/species/TethysNoiseDataProvider.java b/src/noiseMonitor/species/TethysNoiseDataProvider.java
new file mode 100644
index 00000000..eea8d6d3
--- /dev/null
+++ b/src/noiseMonitor/species/TethysNoiseDataProvider.java
@@ -0,0 +1,105 @@
+package noiseMonitor.species;
+
+import java.util.List;
+
+import PamUtils.PamUtils;
+import PamguardMVC.PamDataBlock;
+import PamguardMVC.PamDataUnit;
+import nilus.Detection;
+import nilus.Detection.Parameters;
+import nilus.DetectionEffortKind;
+import nilus.GranularityEnumType;
+import nilus.Helper;
+import noiseMonitor.NoiseDataBlock;
+import noiseMonitor.NoiseDataUnit;
+import tethys.TethysControl;
+import tethys.niluswraps.PDeployment;
+import tethys.output.StreamExportParams;
+import tethys.output.TethysExportParams;
+import tethys.pamdata.AutoTethysProvider;
+import tethys.swing.export.ExportWizardCard;
+import tethys.swing.export.GranularityCard;
+
+public class TethysNoiseDataProvider extends AutoTethysProvider {
+
+ private NoiseDataBlock noiseDataBlock;
+
+ public TethysNoiseDataProvider(TethysControl tethysControl, NoiseDataBlock noiseDataBlock) {
+ super(tethysControl, noiseDataBlock);
+ this.noiseDataBlock = noiseDataBlock;
+ }
+
+ @Override
+ public GranularityEnumType[] getAllowedGranularities() {
+ GranularityEnumType[] allowed = {GranularityEnumType.CALL};
+ return allowed;
+ }
+
+ @Override
+ public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams,
+ StreamExportParams streamExportParams) {
+ Detection detection = super.createDetection(dataUnit, tethysExportParams, streamExportParams);
+ NoiseDataUnit noiseDataUnit = (NoiseDataUnit) dataUnit;
+ /*
+ * Now all the noise measurements, noting there may be several types.
+ */
+ int statTypes = noiseDataBlock.getStatisticTypes();
+ int nTypes = PamUtils.getNumChannels(statTypes);
+ Parameters params = detection.getParameters();
+ List measurements = params.getFrequencyMeasurementsDB();
+ double[][] noiseData = noiseDataUnit.getNoiseBandData();
+ int meanIndex = -1;
+ for (int i = 0; i < nTypes; i++) {
+ int type = PamUtils.getNthChannel(i, statTypes);
+ String name = noiseDataBlock.getMeasureName(type);
+ if (1< effortKinds,
+ StreamExportParams exportParams) {
+ super.getEffortKinds(pDeployment, effortKinds, exportParams);
+ DetectionEffortKind kind = effortKinds.get(0);
+ nilus.DetectionEffortKind.Parameters params = kind.getParameters();
+ if (params == null) {
+ params = new nilus.DetectionEffortKind.Parameters();
+ try {
+ Helper.createRequiredElements(params);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ kind.setParameters(params);
+ }
+ List fMeasures = params.getFrequencyMeasurementsHz();
+ double[] loEdges = noiseDataBlock.getBandLoEdges();
+ double[] hiEdges = noiseDataBlock.getBandHiEdges();
+ // put lot mean into the array
+ for (int i = 0; i < loEdges.length; i++) {
+ fMeasures.add(roundSignificantFigures(Math.sqrt(loEdges[i]*hiEdges[i]), 4));
+ }
+ }
+
+ @Override
+ public boolean wantExportDialogCard(ExportWizardCard wizPanel) {
+ if (wizPanel.getClass() == GranularityCard.class) {
+ return false;
+ }
+ return super.wantExportDialogCard(wizPanel);
+ }
+
+}
diff --git a/src/noiseOneBand/OneBandAlarmParameters.java b/src/noiseOneBand/OneBandAlarmParameters.java
index 90a1659c..3e4e5a69 100644
--- a/src/noiseOneBand/OneBandAlarmParameters.java
+++ b/src/noiseOneBand/OneBandAlarmParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class OneBandAlarmParameters implements Serializable, Cloneable, ManagedParameters {
@@ -37,7 +38,7 @@ public class OneBandAlarmParameters implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/noiseOneBand/OneBandDisplayParams.java b/src/noiseOneBand/OneBandDisplayParams.java
index 04cf01d7..fe9b7a82 100644
--- a/src/noiseOneBand/OneBandDisplayParams.java
+++ b/src/noiseOneBand/OneBandDisplayParams.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
public class OneBandDisplayParams implements Serializable, Cloneable, ManagedParameters {
@@ -61,7 +62,7 @@ public class OneBandDisplayParams implements Serializable, Cloneable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("displayChannels");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/noiseOneBand/OneBandParameters.java b/src/noiseOneBand/OneBandParameters.java
index b35e4f68..ea2f3320 100644
--- a/src/noiseOneBand/OneBandParameters.java
+++ b/src/noiseOneBand/OneBandParameters.java
@@ -10,6 +10,7 @@ import Filters.FilterType;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class OneBandParameters implements Serializable, Cloneable, ManagedParameters {
@@ -235,7 +236,7 @@ public class OneBandParameters implements Serializable, Cloneable, ManagedParame
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("filterParams");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/noiseOneBand/offline/OneBandSummaryParams.java b/src/noiseOneBand/offline/OneBandSummaryParams.java
index 7565c6e7..14e71708 100644
--- a/src/noiseOneBand/offline/OneBandSummaryParams.java
+++ b/src/noiseOneBand/offline/OneBandSummaryParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class OneBandSummaryParams implements Serializable, Cloneable, ManagedParameters {
@@ -23,7 +24,7 @@ public class OneBandSummaryParams implements Serializable, Cloneable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/offlineProcessing/OfflineTask.java b/src/offlineProcessing/OfflineTask.java
index dab50a6b..ec63f39b 100644
--- a/src/offlineProcessing/OfflineTask.java
+++ b/src/offlineProcessing/OfflineTask.java
@@ -123,6 +123,16 @@ public abstract class OfflineTask {
}
}
+ /**
+ * Get a uniquely identifyng name for the task which consists of the
+ * pamControlledUnit type and name as well as the tasks shorter name from getName();
+ * @return a long name which should be unique within a configuration.
+ */
+ public String getLongName() {
+ PamControlledUnit tcu = getTaskControlledUnit();
+ String str = String.format("%s:%s:%s", tcu.getUnitType(), tcu.getUnitName(), getName());
+ return str;
+ }
/**
*
* @return a name for the task, to be displayed in the dialog.
diff --git a/src/offlineProcessing/OfflineTaskManager.java b/src/offlineProcessing/OfflineTaskManager.java
index a88bfd1a..9c6485ce 100644
--- a/src/offlineProcessing/OfflineTaskManager.java
+++ b/src/offlineProcessing/OfflineTaskManager.java
@@ -17,6 +17,10 @@ public class OfflineTaskManager {
private ArrayList globalTaskList = new ArrayList();
+ public static final String commandFlag = "-offlinetask";
+
+ public ArrayList commandLineTasks = new ArrayList();
+
public static OfflineTaskManager getManager() {
if (singleInstance == null) {
singleInstance = new OfflineTaskManager();
@@ -116,8 +120,9 @@ public class OfflineTaskManager {
* @param offlineTask
* @return matching task or null.
*/
+ @SuppressWarnings("rawtypes")
public OfflineTask findOfflineTask(OfflineTask offlineTask) {
- return findOfflineTask(offlineTask.getUnitType(), offlineTask.getUnitName(), offlineTask.getName());
+ return findOfflineTask(offlineTask.getLongName());
}
/**
@@ -128,6 +133,7 @@ public class OfflineTaskManager {
* @param taskName
* @return matching task or null.
*/
+ @SuppressWarnings("rawtypes")
public OfflineTask findOfflineTask(String unitType, String unitName, String taskName) {
// could possibly also do a check on class type ????
for (OfflineTask aTask : globalTaskList) {
@@ -143,4 +149,51 @@ public class OfflineTaskManager {
}
return null;
}
+
+ /**
+ * Another way of finding offline tasks based on their long name. This is basically
+ * the three names unitType, unitName and taskName concatenated together. Get's used
+ * for some task management such as passing batch processing instructions.
+ * @param taskLongName
+ * @return matching task or null.
+ */
+ @SuppressWarnings("rawtypes")
+ public OfflineTask findOfflineTask(String taskLongName) {
+ for (OfflineTask aTask : globalTaskList) {
+ if (aTask.getLongName().equals(taskLongName)) {
+ return aTask;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add a task listed in the command line when PAMGuard was started.
+ * @param taskLongName
+ */
+ public void addCommandLineTask(String taskLongName) {
+ commandLineTasks.add(taskLongName);
+ }
+
+ /**
+ * The list of tasks from the command line.
+ * @return the commandLineTasks
+ */
+ public ArrayList getCommandLineTasks() {
+ return commandLineTasks;
+ }
+
+ /**
+ * Get the status of jobs to pass back to the batch process controller.
+ * @return
+ */
+ public String getBatchStatus() {
+ /**
+ * this needs to largely follow the format of the data in folderinputsystem:
+ * String bs = String.format("%d,%d,%d,%s", nFiles,currentFile,generalStatus,currFile);
+ */
+ int generalStatus = PamController.getInstance().getRealStatus();
+ String bs = String.format("%d,%d,%d,%s", commandLineTasks.size(), 0, generalStatus, "Processing");
+ return bs;
+ }
}
diff --git a/src/offlineProcessing/TaskGroupParams.java b/src/offlineProcessing/TaskGroupParams.java
index 25497c24..c04a88cc 100644
--- a/src/offlineProcessing/TaskGroupParams.java
+++ b/src/offlineProcessing/TaskGroupParams.java
@@ -8,6 +8,7 @@ import java.util.Arrays;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Parameter control for offline task groups.
@@ -137,7 +138,7 @@ public class TaskGroupParams implements Cloneable, Serializable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("taskSelection");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/pamScrollSystem/DataLoadQueData.java b/src/pamScrollSystem/DataLoadQueData.java
index 77c143ab..93ed656c 100644
--- a/src/pamScrollSystem/DataLoadQueData.java
+++ b/src/pamScrollSystem/DataLoadQueData.java
@@ -1,5 +1,6 @@
package pamScrollSystem;
+import PamUtils.PamCalendar;
import PamguardMVC.PamDataBlock;
/**
@@ -68,6 +69,14 @@ public class DataLoadQueData {
public void setDataEnd(long dataEnd) {
this.dataEnd = dataEnd;
}
+
+
+ @Override
+ public String toString() {
+ String str = String.format("%s %s - %s", pamDataBlock.getLongDataName(),
+ PamCalendar.formatDBDateTime(dataStart),PamCalendar.formatDBDateTime(dataEnd));
+ return str;
+ }
}
diff --git a/src/pamguard/GlobalArguments.java b/src/pamguard/GlobalArguments.java
index 4f601911..eea82ec8 100644
--- a/src/pamguard/GlobalArguments.java
+++ b/src/pamguard/GlobalArguments.java
@@ -9,6 +9,11 @@ import java.util.HashMap;
*
*/
public class GlobalArguments {
+
+ /**
+ * Put some common flags here for convenience.
+ */
+ public static final String BATCHFLAG = "-batch";
static HashMap globalFlags = new HashMap<>();
@@ -43,4 +48,12 @@ public class GlobalArguments {
return Integer.valueOf(val);
}
+ /**
+ * Is the batch flag set ?
+ * @return
+ */
+ public static boolean isBatch() {
+ return getParam(BATCHFLAG) != null;
+ }
+
}
diff --git a/src/pamguard/Pamguard.java b/src/pamguard/Pamguard.java
index a80c16cc..33009522 100644
--- a/src/pamguard/Pamguard.java
+++ b/src/pamguard/Pamguard.java
@@ -44,6 +44,7 @@ import binaryFileStorage.BinaryStore;
import dataPlotsFX.JamieDev;
import generalDatabase.DBControl;
import networkTransfer.send.NetworkSender;
+import offlineProcessing.OfflineTaskManager;
import rocca.RoccaDev;
import java.io.BufferedReader;
@@ -154,6 +155,7 @@ public class Pamguard {
} catch (Exception e) {
e.printStackTrace();
}
+ boolean showSplash = true;
if (args != null) {
int nArgs = args.length;
int iArg = 0;
@@ -172,6 +174,14 @@ public class Pamguard {
runMode = PamController.RUN_NETWORKRECEIVER;
System.out.println("PAMGUARD Network Reciever Mode");
}
+ else if (anArg.equalsIgnoreCase("-nosplash")) {
+ showSplash = false;
+ }
+ else if (anArg.equalsIgnoreCase(GlobalArguments.BATCHFLAG)) {
+ // flag to say we're in batch processing mode. Can be used
+ // to avoid one or two dialogs that pop up in Viewer mode.
+ GlobalArguments.setParam(GlobalArguments.BATCHFLAG, Boolean.TRUE.toString());
+ }
// removed SEICHE switch when the two SEICHE modules were converted to plugins
// else if (anArg.equalsIgnoreCase("-seiche")) {
@@ -240,6 +250,10 @@ public class Pamguard {
pamBuoyGlobals.setMultiportConfig(mAddr, mPort);
System.out.printf("Setting multicast control addr %s port %d\n", mAddr, mPort);
}
+ else if (anArg.equalsIgnoreCase(OfflineTaskManager.commandFlag)) {
+ String taskName = args[iArg++];
+ OfflineTaskManager.getManager().addCommandLineTask(taskName);
+ }
else if (anArg.equalsIgnoreCase("-nolog")) {
System.out.println("Disabling log file from command line switch...");
ProxyPrintStream.disableLogFile();
@@ -383,7 +397,7 @@ public class Pamguard {
if(runMode == PamController.RUN_REMOTE) {
spashTime = 0;
}
- if (spashTime > 0 && (PamGUIManager.getGUIType() != PamGUIManager.NOGUI)) {
+ if (showSplash && spashTime > 0 && (PamGUIManager.getGUIType() != PamGUIManager.NOGUI)) {
new Splash(spashTime, chosenRunMode);
}
//
@@ -717,6 +731,47 @@ public class Pamguard {
}
}
}
+ /*
+ * Some bits that need added to Maven POM.
+ *
+
+
+ org.eclipse.persistence
+ org.eclipse.persistence.moxy
+ 2.5.0
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.4.0-b180830.0359
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ 2.4.0-b180830.0438
+
+
+ org.glassfish.jaxb
+ jaxb-xjc
+ 2.4.0-b180830.0438
+
+
+
+ */
}
diff --git a/src/quickAnnotation/QuickAnnotationParameters.java b/src/quickAnnotation/QuickAnnotationParameters.java
index fd8ed2a7..65e3b05b 100644
--- a/src/quickAnnotation/QuickAnnotationParameters.java
+++ b/src/quickAnnotation/QuickAnnotationParameters.java
@@ -9,6 +9,7 @@ import PamController.PamSettingManager;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import difar.DifarControl;
import difar.DifarParameters;
import generalDatabase.lookupTables.LookupItem;
@@ -96,7 +97,7 @@ public class QuickAnnotationParameters implements Serializable, Cloneable, Manag
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("exportClips");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java b/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java
index 7ad1ffb9..41ef495e 100644
--- a/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java
+++ b/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java
@@ -3,6 +3,7 @@ package rawDeepLearningClassifier.dataPlotFX;
import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import javafx.scene.paint.Color;
/**
@@ -25,7 +26,7 @@ public class DLPredDisplayParams implements Serializable, Cloneable, ManagedPara
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java b/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java
index 72761199..b046b27b 100644
--- a/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java
+++ b/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java
@@ -1,6 +1,7 @@
package rawDeepLearningClassifier.logging;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.SQLLoggingAddon;
import generalDatabase.SQLTypes;
@@ -12,19 +13,19 @@ public class DLAnnotationSQL implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
// TODO Auto-generated method stub
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
// TODO Auto-generated method stub
return false;
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) {
// TODO Auto-generated method stub
return false;
}
diff --git a/src/rocca/RoccaParameters.java b/src/rocca/RoccaParameters.java
index bec1fecb..c7db4aae 100644
--- a/src/rocca/RoccaParameters.java
+++ b/src/rocca/RoccaParameters.java
@@ -30,6 +30,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Parameters for Rocca
@@ -856,7 +857,7 @@ public class RoccaParameters implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("runAncCalcs4Clicks");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/seismicVeto/VetoParameters.java b/src/seismicVeto/VetoParameters.java
index 0ca08357..e41907f7 100644
--- a/src/seismicVeto/VetoParameters.java
+++ b/src/seismicVeto/VetoParameters.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class VetoParameters implements Serializable, Cloneable, ManagedParameters {
@@ -40,7 +41,7 @@ public class VetoParameters implements Serializable, Cloneable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("backgroundConstant");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/serialComms/SerialPortParameters.java b/src/serialComms/SerialPortParameters.java
index bb9d699c..373852fd 100644
--- a/src/serialComms/SerialPortParameters.java
+++ b/src/serialComms/SerialPortParameters.java
@@ -29,6 +29,7 @@ import com.fazecast.jSerialComm.SerialPort;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* @author David McLaren, Paul Redmond
@@ -166,7 +167,7 @@ public class SerialPortParameters implements Serializable, Cloneable, ManagedPar
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/simulatedAcquisition/SimObject.java b/src/simulatedAcquisition/SimObject.java
index 053c8a9b..335139fb 100644
--- a/src/simulatedAcquisition/SimObject.java
+++ b/src/simulatedAcquisition/SimObject.java
@@ -5,6 +5,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import simulatedAcquisition.movement.MovementModel;
import simulatedAcquisition.movement.MovementModels;
@@ -150,7 +151,7 @@ public class SimObject implements Serializable, Cloneable, ManagedParameters {
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
try {
Field field = this.getClass().getDeclaredField("depth");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/simulatedAcquisition/movement/CircularMovementParams.java b/src/simulatedAcquisition/movement/CircularMovementParams.java
index 4fe63e95..c956209e 100644
--- a/src/simulatedAcquisition/movement/CircularMovementParams.java
+++ b/src/simulatedAcquisition/movement/CircularMovementParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class CircularMovementParams implements Serializable, Cloneable, ManagedParameters {
@@ -84,7 +85,7 @@ public class CircularMovementParams implements Serializable, Cloneable, ManagedP
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/simulatedAcquisition/movement/GridMovementParams.java b/src/simulatedAcquisition/movement/GridMovementParams.java
index 210ac943..72ae6cb2 100644
--- a/src/simulatedAcquisition/movement/GridMovementParams.java
+++ b/src/simulatedAcquisition/movement/GridMovementParams.java
@@ -6,6 +6,7 @@ import java.lang.reflect.Field;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class GridMovementParams implements Serializable, Cloneable, ManagedParameters {
@@ -42,7 +43,7 @@ public class GridMovementParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("distRangeMetres");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/soundPlayback/PlaybackParameters.java b/src/soundPlayback/PlaybackParameters.java
index 08c1e56a..2d7d22d1 100644
--- a/src/soundPlayback/PlaybackParameters.java
+++ b/src/soundPlayback/PlaybackParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
/**
* Parameters controlling sound playback
@@ -165,7 +166,7 @@ public class PlaybackParameters implements Cloneable, Serializable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/soundPlayback/preprocess/EnvelopeParams.java b/src/soundPlayback/preprocess/EnvelopeParams.java
index b3e0587c..7dd143e9 100644
--- a/src/soundPlayback/preprocess/EnvelopeParams.java
+++ b/src/soundPlayback/preprocess/EnvelopeParams.java
@@ -7,6 +7,7 @@ import Filters.FilterParams;
import Filters.FilterType;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class EnvelopeParams implements Cloneable, Serializable, ManagedParameters {
@@ -87,7 +88,7 @@ public class EnvelopeParams implements Cloneable, Serializable, ManagedParameter
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY);
return ps;
}
diff --git a/src/soundtrap/STClickControl.java b/src/soundtrap/STClickControl.java
index 203357fe..8e7ca7b0 100644
--- a/src/soundtrap/STClickControl.java
+++ b/src/soundtrap/STClickControl.java
@@ -37,6 +37,7 @@ import javax.swing.JSeparator;
import org.pamguard.x3.sud.SUDClickDetectorInfo;
import Acquisition.AcquisitionControl;
+import PamController.PamSensor;
import PamController.PamControlledUnitSettings;
import PamController.PamController;
import PamController.PamSettingManager;
@@ -54,7 +55,7 @@ import soundtrap.sud.SudFileDWVHandler;
* @author mo55
*
*/
-public class STClickControl extends ClickControl {
+public class STClickControl extends ClickControl implements PamSensor {
private SUDClickDetectorInfo sudClickDetectorInfo;
@@ -229,6 +230,17 @@ public class STClickControl extends ClickControl {
public void setSudClickDetectorInfo(SUDClickDetectorInfo sudClickDetectorInfo) {
this.sudClickDetectorInfo = sudClickDetectorInfo;
}
+
+ @Override
+ public String getSensorDescription() {
+ String desc = String.format("SoundTrap Click Detector at %dHz", (int) getClickDataBlock().getSampleRate());
+ return desc;
+ }
+
+ @Override
+ public String getSensorId() {
+ return null;
+ }
/**
* Class to handle SoundTrap click detector settings without messing up
diff --git a/src/soundtrap/STToolsParams.java b/src/soundtrap/STToolsParams.java
index 722c6fb6..514b96d6 100644
--- a/src/soundtrap/STToolsParams.java
+++ b/src/soundtrap/STToolsParams.java
@@ -5,6 +5,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class STToolsParams implements Serializable, Cloneable, ManagedParameters {
@@ -62,7 +63,7 @@ public class STToolsParams implements Serializable, Cloneable, ManagedParameters
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java b/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java
index 0931c963..9cfa3765 100644
--- a/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java
+++ b/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java
@@ -7,6 +7,7 @@ import java.util.ArrayList;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
import PamModel.parametermanager.PrivatePamParameterData;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class SpectrogramNoiseSettings implements Serializable, Cloneable, ManagedParameters {
@@ -79,7 +80,7 @@ public class SpectrogramNoiseSettings implements Serializable, Cloneable, Manage
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
try {
Field field = this.getClass().getDeclaredField("runMethod");
ps.put(new PrivatePamParameterData(this, field) {
diff --git a/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java b/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java
index 23e9f1f7..18f1811e 100644
--- a/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java
+++ b/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class AverageSubtractionParameters implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class AverageSubtractionParameters implements Serializable, Cloneable, Ma
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java b/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java
index fe91beba..c24aed99 100644
--- a/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java
+++ b/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class MedianFilterParams implements Serializable, Cloneable, ManagedParameters {
@@ -25,7 +26,7 @@ public class MedianFilterParams implements Serializable, Cloneable, ManagedParam
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/spectrogramNoiseReduction/threshold/ThresholdParams.java b/src/spectrogramNoiseReduction/threshold/ThresholdParams.java
index 8842e6e0..5674d577 100644
--- a/src/spectrogramNoiseReduction/threshold/ThresholdParams.java
+++ b/src/spectrogramNoiseReduction/threshold/ThresholdParams.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
import PamModel.parametermanager.ManagedParameters;
import PamModel.parametermanager.PamParameterSet;
+import PamModel.parametermanager.PamParameterSet.ParameterSetType;
public class ThresholdParams implements Serializable, Cloneable, ManagedParameters {
@@ -27,7 +28,7 @@ public class ThresholdParams implements Serializable, Cloneable, ManagedParamete
@Override
public PamParameterSet getParameterSet() {
- PamParameterSet ps = PamParameterSet.autoGenerate(this);
+ PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR);
return ps;
}
diff --git a/src/targetMotionOld/TargetMotionSQLLogging.java b/src/targetMotionOld/TargetMotionSQLLogging.java
index 6017a12b..4f4f133e 100644
--- a/src/targetMotionOld/TargetMotionSQLLogging.java
+++ b/src/targetMotionOld/TargetMotionSQLLogging.java
@@ -15,6 +15,7 @@ import PamDetection.AbstractLocalisation;
import PamDetection.LocContents;
import PamUtils.LatLong;
import PamguardMVC.PamDataUnit;
+import generalDatabase.EmptyTableDefinition;
import generalDatabase.PamTableDefinition;
import generalDatabase.PamTableItem;
import generalDatabase.SQLLoggingAddon;
@@ -119,7 +120,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon {
}
@Override
- public void addTableItems(PamTableDefinition pamTableDefinition) {
+ public void addTableItems(EmptyTableDefinition pamTableDefinition) {
pamTableDefinition.addTableItem(modelName);
@@ -146,7 +147,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon {
}
@Override
- public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition,
+ public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition,
PamDataUnit pamDataUnit) {
AbstractLocalisation tmResult = pamDataUnit.getLocalisation();
clearEverything();
@@ -218,7 +219,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon {
return true;
}
- private boolean saveGroupLocalisation(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition,
+ private boolean saveGroupLocalisation(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition,
PamDataUnit pamDataUnit, GroupLocalisation groupLocalisation) {
int nAmbiguities = groupLocalisation.getAmbiguityCount();
@@ -239,7 +240,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon {
return true;
}
- private boolean saveGroupLocalisation(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition,
+ private boolean saveGroupLocalisation(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition,
PamDataUnit pamDataUnit, int resultIndex, GroupLocResult tmResult) {
@@ -323,7 +324,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon {
}
@Override
- public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition,
+ public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition,
PamDataUnit pamDataUnit) {
GroupLocalisation tml = new GroupLocalisation(pamDataUnit, null);
@@ -341,7 +342,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon {
return true;
}
- private GroupLocResult loadLocResult(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition,
+ private GroupLocResult loadLocResult(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition,
PamDataUnit pamDataUnit, GroupLocalisation tml, int resultIndex) {
double latVal, longVal;
diff --git a/src/tethys/Collection.java b/src/tethys/Collection.java
new file mode 100644
index 00000000..93a6acb2
--- /dev/null
+++ b/src/tethys/Collection.java
@@ -0,0 +1,136 @@
+package tethys;
+
+/**
+ * Names of Tethys Collections. These are the plural names, though contain functionality
+ * to get the document names, which are generally the singular of the enum
+ * @author dg50
+ *
+ */
+public enum Collection {
+
+ Deployments, Detections, Calibrations, Localizations, SpeciesAbbreviations, Ensembles, SourceMaps, ITIS, ITIS_ranks, OTHER;
+
+ /**
+ * A list of the main collections in the database, i.e. ones the user will
+ * possibly want to interract with through the GUI.
+ * @return list of main collections.
+ */
+ public static Collection[] mainList() {
+ Collection[] cs = {Deployments, Detections, Calibrations, Localizations, SpeciesAbbreviations, Ensembles};
+ return cs;
+ }
+ /**
+ * Get the name of a document in this collection, this is generally the singular
+ * of the collection name.
+ * @return Document name, e.g. Detection for Detections
+ */
+ public String documentName() {
+ switch (this) {
+ case Calibrations:
+ return "Calibration";
+ case Deployments:
+ return "Deployment";
+ case Detections:
+ return "Detections"; // this one is plural !
+ case Localizations:
+ return "Localize";
+ case SpeciesAbbreviations:
+ return "SpeciesAbbreviation";
+ case Ensembles:
+ return "Ensemble";
+ default:
+ break;
+ }
+ return null;
+ }
+
+ public String collectionName() {
+ return this.toString();
+ }
+
+ /**
+ * Find a collection for the given name. This does
+ * a bit more than the simple 'valueof' since it also
+ * allows the user to input a documentname in place, which
+ * is just the collection name without the plural 's' on the end
+ * @param name Collection name.
+ * @return Collection or null.
+ */
+ public static Collection fromName(String name) {
+ Collection c = Collection.valueOf(name);
+ if (c != null) {
+ return c;
+ }
+ /**
+ * Otherwise, may need to do a longer search to see if the user has passed
+ * the singular document name.
+ */
+ if (name.endsWith("s") == false) {
+ c = Collection.valueOf(name+"s");
+ if (c != null) {
+ return c;
+ }
+ }
+ return null;
+ }
+ /**
+ * get Tethys collection name from nilus collection objects
+ * @param className nilus object Class Name
+ * @return name of Tethys collection
+ */
+ public static Collection fromClass(Class nilusClass) {
+ String className = nilusClass.getName();
+ switch(className) {
+ case "nilus.Deployment":
+ return Deployments;
+ case "nilus.Detections":
+ return Detections;
+ case "nilus.Calibration":
+ return Calibrations;
+ case "nilus.Ensemble":
+ return Ensembles;
+ case "nilus.Localization":
+ return Localizations;
+ case "nilus.SpeciesAbbreviation":
+ return SpeciesAbbreviations;
+ case "nilus.SourceMap":
+ return SourceMaps;
+ case "nilus.ITIS":
+ return ITIS;
+ case "nilus.ranks":
+ return ITIS_ranks;
+ default:
+ return null;
+ }
+ }
+// /**
+// * get Tethys collection name from nilus collection objects
+// * @param className nilus object Class Name
+// * @return name of Tethys collection
+// */
+// public static String getCollection(Class nilusClass) {
+// String className = nilusClass.getName();
+// switch(className) {
+// case "nilus.Deployment":
+// return "Deployments";
+// case "nilus.Detections":
+// return "Detections";
+// case "nilus.Calibration":
+// return "Calibrations";
+// case "nilus.Ensemble":
+// return "Ensembles";
+// case "nilus.Localization":
+// return "Localizations";
+// case "nilus.SpeciesAbbreviation":
+// return "SpeciesAbbreviations";
+// case "nilus.SourceMap":
+// return "SourceMaps";
+// case "nilus.ITIS":
+// return "ITIS";
+// case "nilus.ranks":
+// return "ITIS_ranks";
+// default:
+// return "";
+// }
+// }
+}
diff --git a/src/tethys/DocumentInfo.java b/src/tethys/DocumentInfo.java
new file mode 100644
index 00000000..7ad2d750
--- /dev/null
+++ b/src/tethys/DocumentInfo.java
@@ -0,0 +1,49 @@
+package tethys;
+
+/**
+ * Basic information about a document that can be used to
+ * make document lists.
+ * @author dg50
+ *
+ */
+public class DocumentInfo implements Comparable {
+
+ private Collection collection;
+ private String documentName;
+ private String documentId;
+
+ /**
+ * @param collection
+ * @param documentName
+ * @param documentId
+ */
+ public DocumentInfo(Collection collection, String documentName, String documentId) {
+ this.collection = collection;
+ this.documentName = documentName;
+ this.documentId = documentId;
+ }
+ @Override
+ public int compareTo(DocumentInfo o) {
+ return this.documentName.compareTo(o.documentName);
+ }
+ /**
+ * @return the collection
+ */
+ public Collection getCollection() {
+ return collection;
+ }
+ /**
+ * @return the documentName
+ */
+ public String getDocumentName() {
+ return documentName;
+ }
+ /**
+ * @return the documentId
+ */
+ public String getDocumentId() {
+ return documentId;
+ }
+
+
+}
diff --git a/src/tethys/DocumentNilusObject.java b/src/tethys/DocumentNilusObject.java
new file mode 100644
index 00000000..c6b5a402
--- /dev/null
+++ b/src/tethys/DocumentNilusObject.java
@@ -0,0 +1,32 @@
+package tethys;
+
+/**
+ * information about a document AND the nilus object to go with it.
+ * @author dg50
+ *
+ * @param
+ */
+public class DocumentNilusObject extends DocumentInfo {
+
+ private T nilusObject;
+
+ public DocumentNilusObject(Collection collection, String documentName, String documentId, T nilusObject) {
+ super(collection, documentName, documentId);
+ this.nilusObject = nilusObject;
+ }
+
+ /**
+ * @return the nilusObject
+ */
+ public T getNilusObject() {
+ return nilusObject;
+ }
+
+ /**
+ * @param nilusObject the nilusObject to set
+ */
+ public void setNilusObject(T nilusObject) {
+ this.nilusObject = nilusObject;
+ }
+
+}
diff --git a/src/tethys/TethysControl.java b/src/tethys/TethysControl.java
new file mode 100644
index 00000000..83e445b7
--- /dev/null
+++ b/src/tethys/TethysControl.java
@@ -0,0 +1,722 @@
+package tethys;
+
+import java.awt.Desktop;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+
+import PamController.PamControlledUnit;
+import PamController.PamControlledUnitSettings;
+import PamController.PamController;
+import PamController.PamControllerInterface;
+import PamController.PamFolders;
+import PamController.PamSettingManager;
+import PamController.PamSettings;
+import PamUtils.PamFileChooser;
+import PamUtils.PamFileFilter;
+import PamView.PamTabPanel;
+import PamView.dialog.warn.WarnOnce;
+import PamguardMVC.PamDataBlock;
+import metadata.MetaDataContol;
+import metadata.PamguardMetaData;
+import nilus.Deployment;
+import tethys.TethysState.StateType;
+import tethys.calibration.CalibrationHandler;
+import tethys.dbxml.DBXMLConnect;
+import tethys.dbxml.DBXMLQueries;
+import tethys.dbxml.ServerStatus;
+import tethys.dbxml.TethysException;
+import tethys.dbxml.TethysQueryException;
+import tethys.deployment.DeploymentHandler;
+import tethys.detection.DetectionsHandler;
+import tethys.niluswraps.PDeployment;
+import tethys.output.DatablockSynchInfo;
+import tethys.output.TethysExportParams;
+import tethys.species.ITISFunctions;
+import tethys.species.SpeciesMapManager;
+import tethys.swing.ProjectDeploymentsDialog;
+import tethys.swing.TethysTabPanel;
+import tethys.swing.XMLStringView;
+import tethys.swing.documents.TethysDocumentsFrame;
+
+/**
+ * Quick play with a simple system for outputting data to Tethys. At it's start
+ * this is simply going to offer a dialog and have a few functions which show how
+ * to access data within PAMGuard.
+ * @author dg50
+ *
+ */
+public class TethysControl extends PamControlledUnit implements PamSettings, TethysStateObserver {
+
+ public static final String unitType = "Tethys Interface";
+ public static String defaultName = "Tethys";
+ public static String xmlNameSpace = "http://tethys.sdsu.edu/schema/1.0";
+
+ private TethysExportParams tethysExportParams = new TethysExportParams();
+
+ private DBXMLConnect dbxmlConnect;
+
+ private TethysTabPanel tethysTabPanel;
+
+ private DBXMLQueries dbxmlQueries;
+
+ private ArrayList stateObservers;
+
+ private Timer serverCheckTimer;
+
+ private ServerStatus lastServerStatus;
+
+ private ArrayList dataBlockSynchInfos;
+
+ private DeploymentHandler deploymentHandler;
+ private DetectionsHandler detectionsHandler;
+ private CalibrationHandler calibrationHandler;
+
+ private ITISFunctions itisFunctions;
+
+ public TethysControl(String unitName) {
+ super(unitType, unitName);
+ stateObservers = new ArrayList();
+ dbxmlConnect = new DBXMLConnect(this);
+ dbxmlQueries = new DBXMLQueries(this, dbxmlConnect);
+ deploymentHandler = new DeploymentHandler(this);
+ detectionsHandler = new DetectionsHandler(this);
+ calibrationHandler = new CalibrationHandler(this);
+
+ serverCheckTimer = new Timer(10000, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ checkServer();
+ }
+ });
+ serverCheckTimer.setInitialDelay(0);
+ PamSettingManager.getInstance().registerSettings(this);
+ addStateObserver(this);
+
+ if (PamController.getInstance().isInitializationComplete()) {
+ // must be adding module later on ...
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ initializationStuff();
+ }
+ });
+ }
+ }
+
+ /**
+ * Get DBXML Connector. This class contains all the functions that are needed
+ * to talk to the database.
+ * @return DBXML functions.
+ */
+ public DBXMLConnect getDbxmlConnect() {
+ return dbxmlConnect;
+ }
+ @Override
+ public JMenuItem createDetectionMenu(Frame parentFrame) {
+ return createTethysMenu(parentFrame);
+ }
+
+ @Override
+ public JMenuItem createFileMenu(JFrame parentFrame) {
+ // TODO Auto-generated method stub
+ return super.createFileMenu(parentFrame);
+ }
+
+ /**
+ * Make a menu. Can go either in File or Settings. TBD.
+ * @param parentFrame
+ * @return
+ */
+ public JMenuItem createTethysMenu(Frame parentFrame) {
+ JMenu tethysMenu = new JMenu("Tethys");
+// JMenuItem tethysExport = new JMenuItem("Export ...");
+// tethysMenu.add(tethysExport);
+// tethysExport.addActionListener(new ActionListener() {
+// @Override
+// public void actionPerformed(ActionEvent e) {
+// tethysExport(parentFrame);
+// }
+// });
+ JMenuItem menuItem;
+ menuItem = new JMenuItem("Open client in browser");
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ openTethysClient();
+ }
+ });
+
+ tethysMenu.add(menuItem);
+ menuItem = new JMenuItem("Open temp document folder");
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ openTempDocuments();
+ }
+ });
+ tethysMenu.add(menuItem);
+
+
+ JMenuItem collections = new JMenu("Collections");
+ Collection[] mainCollections = Collection.mainList();
+ for (int i = 0; i < mainCollections.length; i++) {
+ Collection col = mainCollections[i];
+ menuItem = new JMenuItem("Open " + col.collectionName() + " collection in browser");
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ openTethysCollection(col);
+ }
+ });
+ collections.add(menuItem);
+ }
+
+ tethysMenu.add(collections);
+ tethysMenu.addSeparator();
+ JMenuItem showDeps = new JMenuItem("Show project deployments");
+ showDeps.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ showProjectDeploymentsDialog();
+ }
+ });
+ tethysMenu.add(showDeps);
+
+ JMenuItem cals = new JMenuItem("Export calibrations");
+ cals.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ calibrationHandler.exportAllCalibrations();
+ }
+ });
+ tethysMenu.add(cals);
+
+ tethysMenu.addSeparator();
+ JMenuItem mapItem = new JMenuItem("Export species maps ...");
+ mapItem.setToolTipText("Export all species maps (PAMGuard codes to ITIS codes to file for import into other configurations");
+ mapItem.addActionListener(SpeciesMapManager.getInstance().getExportAction(parentFrame));
+ tethysMenu.add(mapItem);
+
+ mapItem = new JMenuItem("Import species maps ...");
+ mapItem.setToolTipText("Import species maps (PAMGuard codes to ITIS codes to file for import into other configurations");
+ mapItem.addActionListener(SpeciesMapManager.getInstance().getImportAction(parentFrame));
+ tethysMenu.add(mapItem);
+
+ return tethysMenu;
+ }
+
+ protected void openTempDocuments() {
+ File tempFolder = dbxmlConnect.checkTempFolder();
+ if (tempFolder == null) {
+ WarnOnce.showWarning("Tethys Error", "Unable to obtain a temporary folder name", WarnOnce.WARNING_MESSAGE);
+ return;
+ }
+ try {
+// String cmd = "explorer.exe /select," + tempFolder.getAbsolutePath() + File.separator;
+// Runtime.getRuntime().exec(cmd);
+ Desktop.getDesktop().open(tempFolder);
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void showProjectDeploymentsDialog() {
+ ProjectDeploymentsDialog.showDialog(getGuiFrame(), this);
+ }
+
+ public ArrayList getExportableDataBlocks() {
+ ArrayList sets = new ArrayList<>();
+ ArrayList allDataBlocks = PamController.getInstance().getDataBlocks();
+ for (PamDataBlock aDataBlock : allDataBlocks) {
+ if (aDataBlock.getTethysDataProvider(this) != null) {
+ sets.add(aDataBlock);
+ }
+ }
+ return sets;
+ }
+
+ /**
+ * Get the synchronisation info for all datablocks.
+ * This list should be static, but check it in case something has been
+ * added or removed.
+ * @return
+ */
+ public ArrayList getSynchronisationInfos() {
+ if (dataBlockSynchInfos == null) {
+ dataBlockSynchInfos = new ArrayList<>();
+ }
+ ArrayList dataBlocks = getExportableDataBlocks();
+ // check all datablocks are in there ...
+ for (PamDataBlock aBlock : dataBlocks) {
+ if (findDatablockSynchInfo(aBlock) == null) {
+ dataBlockSynchInfos.add(new DatablockSynchInfo(this, aBlock));
+ }
+ }
+ // and remove any which are no longer there.
+ for (DatablockSynchInfo synchInfo : dataBlockSynchInfos) {
+ if (!dataBlocks.contains(synchInfo.getDataBlock())) {
+ dataBlockSynchInfos.remove(synchInfo);
+ }
+ }
+
+ return dataBlockSynchInfos;
+ }
+
+ public DatablockSynchInfo findDatablockSynchInfo(PamDataBlock dataBlock) {
+ if (dataBlockSynchInfos == null) {
+ return null;
+ }
+ for (DatablockSynchInfo synchInfo : dataBlockSynchInfos) {
+ if (synchInfo.getDataBlock() == dataBlock) {
+ return synchInfo;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * open client in the default web browser
+ */
+ public void openTethysClient() {
+// String urlString = tethysExportParams.getFullServerName() + "/Client";
+// System.out.println("Opening url " + urlString);
+// URL url = null;
+// try {
+// url = new URL(urlString);
+// } catch (MalformedURLException e) {
+// e.printStackTrace();
+// }
+// if (url == null) {
+// return;
+// }
+// try {
+// Desktop.getDesktop().browse(url.toURI());
+// } catch (IOException e) {
+// e.printStackTrace();
+// } catch (URISyntaxException e) {
+// e.printStackTrace();
+// }
+ openCollectionInBrowser("Client");
+ }
+ /**
+ * open client in the default web browser
+ */
+ public void openTethysCollection(Collection collection) {
+ if (collection == null) {
+ return;
+ }
+ if (getTethysExportParams().listDocsInPamguard) {
+ openCollectionInPAMGuard(collection);
+ }
+ else {
+ openCollectionInBrowser(collection.collectionName());
+ }
+ }
+ public void openCollectionInPAMGuard(Collection collection) {
+ TethysDocumentsFrame.showTable(getGuiFrame(), this, collection);
+ }
+
+ public void openCollectionInBrowser(String collectionName) {
+ String urlString = tethysExportParams.getFullServerName() + "/" + collectionName;
+// System.out.println("Opening url " + urlString);
+ URL url = null;
+ try {
+ url = new URL(urlString);
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ if (url == null) {
+ return;
+ }
+ try {
+ Desktop.getDesktop().browse(url.toURI());
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public PamTabPanel getTabPanel() {
+ if (tethysTabPanel == null) {
+ tethysTabPanel = new TethysTabPanel(this);
+ }
+ return tethysTabPanel;
+ }
+
+ /**
+ * @return the tethysExportParams
+ */
+ public TethysExportParams getTethysExportParams() {
+ return tethysExportParams;
+ }
+
+// /**
+// * We'll probably want to
+// * @param parentFrame
+// */
+// protected void tethysExport(JFrame parentFrame) {
+// TethysExportParams newExportParams = TethysExportDialog.showDialog(parentFrame, this);
+// if (newExportParams != null) {
+// // dialog returns null if cancel was pressed.
+// tethysExportParams = newExportParams;
+// exportTethysData(tethysExportParams);
+// }
+// }
+//
+// /**
+// * We'll arrive here if the dialog has been opened and we want to export Tethys data.
+// * @param tethysExportParams2
+// */
+// private void exportTethysData(TethysExportParams tethysExportParams) {
+// TethysExporter tethysExporter = new TethysExporter(this, tethysExportParams);
+// tethysExporter.doExport();
+//
+// sendStateUpdate(new TethysState(StateType.TRANSFERDATA));
+// countProjectDetections();
+// sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION));
+// }
+
+ /**
+ * Get global deployment data. This is a bit of a mess, trying to use a separate module
+ * so that the rest of PAMGuard can use it, but creating the
+ * @return
+ */
+ public Deployment getGlobalDeplopymentData() {
+
+ MetaDataContol metaControl = MetaDataContol.getMetaDataControl();
+ PamguardMetaData metaData = metaControl.getMetaData();
+ return metaData.getDeployment();
+// Deployment deploymentData = metaControl != null ? metaData.getDeployment() : getTethysProjectData();
+//
+//// deploymentData.setProject("thisIsAProject");
+////// deploymentData.setPlatform("Yay a platform");
+//// deploymentData.setCruise("cruisey");
+//// deploymentData.setDeploymentId(142536);
+////// deploymentData.setInstrumentId("super instrument");
+//// deploymentData.setSite("in the ocean somewhere");
+//// deploymentData.setRegion("ocean water");
+////// deploymentData.setInstrumentType("sensor of sorts");
+//
+// return deploymentData;
+ }
+
+ /**
+ * Add a new state observer.
+ * @param stateObserver
+ */
+ public void addStateObserver(TethysStateObserver stateObserver) {
+ stateObservers.add(stateObserver);
+ }
+
+ /**
+ * Remove a state observer.
+ * @param stateObserver
+ * @return true if it existed.
+ */
+ public boolean removeStateObserver(TethysStateObserver stateObserver) {
+ return stateObservers.remove(stateObserver);
+ }
+
+ /**
+ * Send state updates around to all state observers.
+ * @param tethysState
+ */
+ public void sendStateUpdate(TethysState tethysState) {
+ for (TethysStateObserver stateObserver : this.stateObservers) {
+ stateObserver.updateState(tethysState);
+ }
+ }
+ /**
+ * A name for any deta selectors.
+ * @return
+ */
+ public String getDataSelectName() {
+ return getUnitName();
+ }
+
+ public DBXMLQueries getDbxmlQueries() {
+ return dbxmlQueries;
+ }
+
+ @Override
+ public void notifyModelChanged(int changeType) {
+ super.notifyModelChanged(changeType);
+ switch (changeType) {
+ case PamControllerInterface.INITIALIZE_LOADDATA:
+// case PamControllerInterface.INITIALIZATION_COMPLETE:
+ initializationStuff();
+ break;
+ }
+ }
+
+ /**
+ * Stuff to do on initial load (initialization complete or addition of
+ * a Tethys module after initialisation).
+ */
+ private void initializationStuff() {
+ deploymentHandler.createPamguardOverview();
+ serverCheckTimer.start();
+ sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION));
+ }
+
+ /**
+ * Check the server. This will send around a notification if the state
+ * has changed since the last call to this function, so it's unlikely you'll
+ * need to use the return value
+ * @return server status.
+ */
+ public ServerStatus checkServer() {
+ ServerStatus serverState = dbxmlConnect.pingServer();
+ if (lastServerStatus == null || lastServerStatus.ok != serverState.ok) {
+ lastServerStatus = serverState; // set before sending notification!
+ sendStateUpdate(new TethysState(StateType.UPDATESERVER));
+ }
+// lastServerStatus = serverState;
+ return serverState;
+ }
+
+ @Override
+ public Serializable getSettingsReference() {
+ return tethysExportParams;
+ }
+
+ @Override
+ public long getSettingsVersion() {
+ return TethysExportParams.serialVersionUID;
+ }
+
+ @Override
+ public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
+ tethysExportParams = (TethysExportParams) pamControlledUnitSettings.getSettings();
+ return true;
+ }
+
+ @Override
+ public void updateState(TethysState tethysState) {
+ switch (tethysState.stateType) {
+ case NEWPROJECTSELECTION:
+ case EXPORTRDATA:
+ case DELETEDATA:
+ countProjectDetections();
+ break;
+ }
+ }
+
+ private void countProjectDetections() {
+ if (dataBlockSynchInfos == null) {
+ return;
+ }
+ Deployment deplData = getGlobalDeplopymentData();
+ String[] dataPrefixes = new String[dataBlockSynchInfos.size()];
+ int i = 0;
+ ArrayList matchedDeployments = deploymentHandler.getMatchedDeployments();
+ for (DatablockSynchInfo synchInfo : dataBlockSynchInfos) {
+// dataPrefixes[i] = DetectionsHandler.getDetectionsDocIdPrefix(deplData.getProject(), synchInfo.getDataBlock());
+ int detectionCount = 0;
+ int documentCount = 0;
+ for (PDeployment pDepl : matchedDeployments) {
+ detectionCount += dbxmlQueries.countData(synchInfo.getDataBlock(), pDepl.deployment.getId());
+ ArrayList detectionsNames = getDbxmlQueries().getDetectionsDocuments(synchInfo.getDataBlock(), pDepl.deployment.getId());
+ if (detectionsNames != null) {
+ documentCount += detectionsNames.size();
+ }
+ }
+ synchInfo.setDataCount(detectionCount);
+ synchInfo.setDetectionDocumentCount(documentCount);
+
+ i++;
+ }
+// int[] counts = dbxmlQueries.countDataForProject(deplData.getProject(), dataPrefixes);
+// if (counts != null) {
+// for ( i = 0; i < counts.length; i++ ) {
+// dataBlockSynchInfos.get(i).setDataCount(counts[i]);
+// }
+// }
+ }
+
+ /**
+ * One stop place to get Deployment information. Will provide
+ * both information on record periods in PAMGuard and also Deployment docs in Tethys.
+ * @return set of functions for handling deployments.
+ */
+ public DeploymentHandler getDeploymentHandler() {
+ return deploymentHandler;
+ }
+
+ public DetectionsHandler getDetectionsHandler() {
+ return detectionsHandler;
+ }
+
+ public void showException(TethysException tethysException) {
+ String title = tethysException.getMessage();
+ StackTraceElement[] stack = tethysException.getStackTrace();
+ String msg = "";
+ if (stack != null) {
+ msg = "Caused in";
+ for (int i = 0; i < Math.min(stack.length, 3); i++) {
+ msg += " " + stack[i].getClassName() + "." + stack[i].getMethodName();
+ }
+ }
+ if (tethysException instanceof TethysQueryException) {
+ TethysQueryException tqe = (TethysQueryException) tethysException;
+// msg += tqe.
+ }
+
+ String xml = tethysException.getXmlError();
+ if (xml != null) {
+ /**
+ * html can't handle the < and > in xml without getting very confused
+ * but it seems to work fine if they are replaced with their html codes.
+ */
+ xml = xml.replace("<", "<");
+ xml = xml.replace(">", ">");
+ xml = xml.replace("\n", " ");
+ msg += ""+xml+" ";
+ }
+ WarnOnce.showWarning(title, msg, WarnOnce.WARNING_MESSAGE);
+ }
+
+ public void displayDocument(DocumentInfo docInfo) {
+ String collectionName = docInfo.getCollection().collectionName();
+ String docId = docInfo.getDocumentName();
+ displayDocument(collectionName, docId);
+ }
+ /**
+ * Load a document from the database and display it in a popup window
+ * @param collection
+ * @param documentId
+ */
+ public void displayDocument(String collection, String documentId) {
+ String doc = getDbxmlQueries().getDocument(collection, documentId);
+ if (doc == null | doc.length() == 0) {
+ doc = String.format("Unable to retrieve document %s/%s from database\n", collection, documentId);
+
+ }
+ XMLStringView.showDialog(getGuiFrame(), collection, documentId, doc);
+ }
+
+ /**
+ * Load a document from the database and write to a file selected by the user
+ * @param collection
+ * @param documentId
+ */
+ public void exportDocument(String collection, String documentId) {
+ String doc = getDbxmlQueries().getDocument(collection, documentId);
+ if (doc == null | doc.length() == 0) {
+ String msg = String.format("Unable to retrieve document %s/%s from database\n", collection, documentId);
+ WarnOnce.showWarning("Error", msg, WarnOnce.WARNING_MESSAGE);
+ }
+
+ PamFileFilter fileFilter = new PamFileFilter("XML documents", ".xml");
+// fileFilter
+ JFileChooser fileChooser = new JFileChooser();
+ fileChooser.setFileFilter(fileFilter);
+ fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ // make a default name based on the document id and the dataset directory.
+ String defFolder = PamFolders.getDefaultProjectFolder();
+ File defFile = null;
+ if (defFolder != null) {
+ defFolder = String.format("%s%s%s_%s.xml", defFolder,File.separator,collection,documentId);
+ defFile = new File(defFolder);
+ fileChooser.setAcceptAllFileFilterUsed(true);
+ fileChooser.setSelectedFile(defFile);
+
+// fileChooser.setSelectedFile(new File(String.format("%s.xml", documentId)));
+// fileChooser.set
+ }
+ int state = fileChooser.showSaveDialog(getGuiFrame());
+ if (state != JFileChooser.APPROVE_OPTION) return;
+ File newFile = fileChooser.getSelectedFile();
+ if (newFile == null) return;
+ newFile = PamFileFilter.checkFileEnd(newFile, "xml", true);
+ if (newFile == null) {
+ return;
+ }
+ if (newFile.exists()) {
+ int ans2 = WarnOnce.showWarning(newFile.getAbsolutePath(),
+ "The file already exists. Do you want to overwrite it ?", WarnOnce.OK_CANCEL_OPTION);
+ if (ans2 == WarnOnce.CANCEL_OPTION) {
+ return;
+ }
+ }
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
+ bos.write(doc.getBytes());
+ bos.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @return the itisFunctions
+ */
+ public ITISFunctions getItisFunctions() {
+ if (itisFunctions == null) {
+ itisFunctions = new ITISFunctions(this);
+ }
+ return itisFunctions;
+ }
+
+ /**
+ * Called when a detections document has been exported.
+ * @param dataBlock
+ */
+ public void exportedDetections(PamDataBlock dataBlock) {
+ sendStateUpdate(new TethysState(StateType.EXPORTRDATA, Collection.Detections));
+ countProjectDetections();
+ sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION, Collection.Detections));
+ }
+
+ /**
+ * @return the calibrationHandler
+ */
+ public CalibrationHandler getCalibrationHandler() {
+ return calibrationHandler;
+ }
+
+ /**
+ * @return the lastServerStatus
+ */
+ public ServerStatus getLastServerStatus() {
+ return lastServerStatus;
+ }
+
+ /**
+ * Quick way for any controls to see that the server is probably OK
+ * without actually pinging it.
+ * @return true if last ping of server was OK
+ */
+ public boolean isServerOk() {
+ if (lastServerStatus == null) {
+ return false;
+ }
+ return lastServerStatus.ok;
+ }
+
+}
diff --git a/src/tethys/TethysLocationFuncs.java b/src/tethys/TethysLocationFuncs.java
new file mode 100644
index 00000000..dbfa68d8
--- /dev/null
+++ b/src/tethys/TethysLocationFuncs.java
@@ -0,0 +1,83 @@
+package tethys;
+
+import Array.ArrayManager;
+import Array.HydrophoneLocator;
+import Array.PamArray;
+import Array.Streamer;
+import GPS.GPSControl;
+import GPS.GpsDataUnit;
+import PamUtils.LatLong;
+import PamUtils.PamUtils;
+import generalDatabase.DBControlUnit;
+import generalDatabase.PamConnection;
+import nilus.Deployment;
+import nilus.DeploymentRecoveryDetails;
+
+/**
+ * Function(s) to get location information for Tethys in the required format.
+ * @author dg50
+ *
+ */
+public class TethysLocationFuncs {
+
+
+ /**
+ * Get everything we need for a deployment document including the track #
+ * and the deployment / recovery information. Basically this means we
+ * have to load the GPS data, then potentially filter it. Slight risk this
+ * may all be too much for memory, but give it a go by loading GPS data for
+ * the deployment times.
+ * @param deployment
+ */
+ public static void getTrackAndPositionData(Deployment deployment) {
+ long start = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp());
+ long end = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getAudioTimeStamp());
+ /*
+ * Need to load data for GPS, Hydrophones and Streamers datablocks for this time period. Can then use
+ * the snapshot geomentry classes to do the rest from the array manager ?
+ */
+ boolean ok = true;
+ ok &= addPositionData(deployment.getDeploymentDetails());
+ ok &= addPositionData(deployment.getRecoveryDetails());
+
+ }
+
+ /**
+ * Add position data to DeploymentRecoveryDetails.
+ * @param drd
+ * @return
+ */
+ public static boolean addPositionData(DeploymentRecoveryDetails drd) {
+ long timeMillis = TethysTimeFuncs.millisFromGregorianXML(drd.getAudioTimeStamp());
+ LatLong pos = getLatLongData(timeMillis);
+ if (pos == null) {
+ return false;
+ }
+ drd.setLongitude(PamUtils.constrainedAngle(pos.getLongitude(), 360));
+ drd.setLatitude(pos.getLatitude());
+ drd.setElevationInstrumentM(pos.getHeight());
+ drd.setDepthInstrumentM(-pos.getHeight());
+ return true;
+ }
+
+ public static LatLong getLatLongData(long timeMillis) {
+ // check the array time.
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ Streamer aStreamer = array.getStreamer(0);
+ GPSControl gpsControl = GPSControl.getGpsControl();
+ PamConnection con = DBControlUnit.findConnection();
+ if (gpsControl != null) {
+// check GPS data are loaded for times around this.
+ GpsDataUnit gpsData = (GpsDataUnit) gpsControl.getGpsDataBlock().getLogging().findClosestDataPoint(con, timeMillis);
+ if (gpsData != null) {
+ return gpsData.getGpsData();
+ }
+ }
+ HydrophoneLocator hydrophoneLocator = aStreamer.getHydrophoneLocator();
+ if (hydrophoneLocator == null) {
+ return null;
+ }
+ return hydrophoneLocator.getStreamerLatLong(timeMillis);
+ }
+
+}
diff --git a/src/tethys/TethysMenuActions.java b/src/tethys/TethysMenuActions.java
new file mode 100644
index 00000000..625096a9
--- /dev/null
+++ b/src/tethys/TethysMenuActions.java
@@ -0,0 +1,70 @@
+package tethys;
+
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import tethys.dbxml.TethysException;
+import tethys.niluswraps.PDeployment;
+
+/*
+ * Some standard meny dirven functions which we may want to call from
+ * a few different places.
+ */
+public class TethysMenuActions {
+
+ private TethysControl tethysControl;
+
+ public TethysMenuActions(TethysControl tethysControl) {
+ super();
+ this.tethysControl = tethysControl;
+ }
+
+ public void deploymentMouseActions(MouseEvent e, PDeployment pDeployment) {
+ ArrayList detDocNames = tethysControl.getDbxmlQueries().getDetectionsDocuments(pDeployment.deployment.getId());
+// System.out.println("Detections for deployment " + pDeployment.deployment.getId());
+// for (String detName : detDocNames) {
+// System.out.println(detName);
+// }
+ JPopupMenu menu = new JPopupMenu();
+ if (detDocNames.size() == 0) {
+ JMenuItem menuItem = new JMenuItem("Delete deployment " + pDeployment.deployment.getId());
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ deleteDeployment(pDeployment);
+ } catch (TethysException e1) {
+ tethysControl.showException(e1);
+ }
+ }
+ });
+ menu.add(menuItem);
+ }
+ else {
+ String str = String.format("Delete deployment %s and %d Detections documents", pDeployment.deployment.getId(), detDocNames.size());
+ JMenuItem menuItem = new JMenuItem(str);
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ try {
+ deleteDeployment(pDeployment);
+ } catch (TethysException e1) {
+ tethysControl.showException(e1);
+ }
+ }
+ });
+ menu.add(menuItem);
+ }
+ menu.show(e.getComponent(), e.getX(), e.getY());
+ }
+
+ protected void deleteDeployment(PDeployment pDeployment) throws TethysException {
+ tethysControl.getDbxmlConnect().deleteDeployment(pDeployment.deployment.getId());
+ }
+}
diff --git a/src/tethys/TethysState.java b/src/tethys/TethysState.java
new file mode 100644
index 00000000..ea2f2746
--- /dev/null
+++ b/src/tethys/TethysState.java
@@ -0,0 +1,54 @@
+package tethys;
+
+/**
+ * Basis for a message system which will get passed around whenever something happens in
+ * Tethys, whether it be a new connection, progress during data output, etc.
+ * @author dg50
+ *
+ */
+public class TethysState {
+
+ public enum StateType {UPDATESERVER, // Server connection or status has changed
+ EXPORTRDATA, // data have been transferred from PAMGuard to Tethys
+ NEWPROJECTSELECTION, // a new Tethys project has been selected in the GUI
+ NEWPAMGUARDSELECTION, // new PAMGuard data are available (called once on first load)
+ UPDATEMETADATA, // META Data being prepared for output have changed (so may be able to enable output!)
+ EXPORTING, // currently exporting data. may be a while ...
+ DELETEDATA // data were deleted
+ }
+
+ public StateType stateType;
+
+ public Collection collection;
+
+ public TethysState(StateType stateType) {
+ super();
+ this.stateType = stateType;
+ collection = Collection.OTHER;
+ }
+
+ public TethysState(StateType stateType, Collection collection) {
+ this.stateType = stateType;
+ this.collection = collection;
+ if (this.collection == null) {
+ this.collection = Collection.OTHER;
+ }
+ }
+
+ /**
+ * @return the collection associated with this notification. Note that there is
+ * an OTHER category in Collections which is used for server / project updates, making
+ * it easier to switch on the collection type when notifications are received.
+ */
+ public Collection getCollection() {
+ return collection;
+ }
+
+ /**
+ * @return the stateType
+ */
+ public StateType getStateType() {
+ return stateType;
+ }
+
+}
diff --git a/src/tethys/TethysStateObserver.java b/src/tethys/TethysStateObserver.java
new file mode 100644
index 00000000..33a9de5c
--- /dev/null
+++ b/src/tethys/TethysStateObserver.java
@@ -0,0 +1,13 @@
+package tethys;
+
+public interface TethysStateObserver {
+
+ /**
+ * Receive state updates when Tethys has done something (made a connection, moved some data, etc.)
+ * Note that this is for RECEIVING state updates, not for sending them. To avoid infinite notifications
+ * loops, use tethysControl.sendStateUpdate(TethysState) to send out state notifications.
+ * @param tethysState
+ */
+ public void updateState(TethysState tethysState);
+
+}
diff --git a/src/tethys/TethysTimeFuncs.java b/src/tethys/TethysTimeFuncs.java
new file mode 100644
index 00000000..70d11704
--- /dev/null
+++ b/src/tethys/TethysTimeFuncs.java
@@ -0,0 +1,90 @@
+package tethys;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import PamUtils.PamCalendar;
+
+public class TethysTimeFuncs {
+
+ private static TimeZone timeZone = TimeZone.getTimeZone("UTC");
+
+ /*
+ * Copied from http://www.java2s.com/Code/Java/Development-Class/ConvertsagiventimeinmillisecondsintoaXMLGregorianCalendarobject.htm
+ */
+ public static XMLGregorianCalendar xmlGregCalFromMillis(long millis) {
+ try {
+ final GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTimeZone(timeZone);
+ calendar.setTimeInMillis(millis);
+ return DatatypeFactory.newInstance().newXMLGregorianCalendar(
+ calendar);
+ }
+ catch (final DatatypeConfigurationException ex) {
+ System.out.println("Unable to convert date '%s' to an XMLGregorianCalendar object");
+ return null;
+ }
+ }
+
+ /**
+ * Convert a Gregorian calendar value back to milliseconds.
+ * @param xmlGregorian
+ * @return
+ */
+ public static Long millisFromGregorianXML(XMLGregorianCalendar xmlGregorian) {
+ if (xmlGregorian == null) {
+ return null;
+ }
+ GregorianCalendar gc2 = xmlGregorian.toGregorianCalendar();
+ gc2.setTimeZone(timeZone);
+ return gc2.getTimeInMillis();
+ }
+
+ /**
+ * Make a Gregorian calendar object from a returned XML string.
+ * @param gregorianString
+ * @return
+ */
+ public static XMLGregorianCalendar fromGregorianXML(String gregorianString) {
+ // typical string is 2018-10-20T00:00:00Z
+ if (gregorianString == null) {
+ return null;
+ }
+// GregorianCalendar gCal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+ gregorianString = gregorianString.replace("T", " ");
+ gregorianString = gregorianString.replace("Z", "");
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Date date = null;
+ try {
+ date = df.parse(gregorianString);
+ } catch (ParseException e) {
+ System.out.printf("Unparsable date string:\"%s\"", gregorianString);
+ e.printStackTrace();
+ return null;
+ }
+ return xmlGregCalFromMillis(date.getTime());
+// gCal.setTimeInMillis(date.getTime());
+//// gCal.se
+// return gCal;
+ }
+
+ public static String formatGregorianTime(XMLGregorianCalendar gregCal) {
+ if (gregCal == null) {
+ return null;
+ }
+ Long millis = millisFromGregorianXML(gregCal);
+ if (millis == null) {
+ return gregCal.toString();
+ }
+ return PamCalendar.formatDBDateTime(millis);
+ }
+}
diff --git a/src/tethys/calibration/CalibrationHandler.java b/src/tethys/calibration/CalibrationHandler.java
new file mode 100644
index 00000000..37dc186e
--- /dev/null
+++ b/src/tethys/calibration/CalibrationHandler.java
@@ -0,0 +1,573 @@
+package tethys.calibration;
+
+import java.lang.reflect.Field;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+
+import Acquisition.AcquisitionControl;
+import Acquisition.AcquisitionParameters;
+import Acquisition.AcquisitionProcess;
+import Array.ArrayManager;
+import Array.Hydrophone;
+import Array.PamArray;
+import Array.Preamplifier;
+import PamController.PamController;
+import PamController.soundMedium.GlobalMedium;
+import PamController.soundMedium.GlobalMedium.SoundMedium;
+import PamUtils.PamCalendar;
+import PamView.dialog.warn.WarnOnce;
+import dbxml.Queries;
+import PamController.soundMedium.GlobalMediumManager;
+import nilus.AlgorithmType.Parameters;
+import nilus.Calibration;
+import nilus.Calibration.FrequencyResponse;
+import nilus.Calibration.QualityAssurance;
+import nilus.Helper;
+import nilus.MetadataInfo;
+import nilus.QualityValueBasic;
+import nilus.ResponsibleParty;
+import tethys.Collection;
+import tethys.DocumentInfo;
+import tethys.DocumentNilusObject;
+import tethys.TethysControl;
+import tethys.TethysState;
+import tethys.TethysStateObserver;
+import tethys.TethysTimeFuncs;
+import tethys.calibration.swing.CalibrationsExportWizard;
+import tethys.dbxml.DBXMLConnect;
+import tethys.dbxml.TethysException;
+import tethys.niluswraps.NilusChecker;
+import tethys.niluswraps.NilusSettingsWrapper;
+import tethys.niluswraps.NilusUnpacker;
+import tethys.pamdata.AutoTethysProvider;
+import tethys.reporter.TethysReporter;
+
+public class CalibrationHandler implements TethysStateObserver {
+
+ private TethysControl tethysControl;
+
+ private ArrayList> calibrationsList;
+
+ public static final String[] updateOptions = {"as-needed", "unplanned", "yearly"};
+
+ public static final String[] calibrationMethods = {"Reference hydrophone", "Manufacturers specification", "Piston phone", "Other calibrated source", "Unknown"};
+
+ public static final String[] qaTypes = {"unverified", "valid", "invalid"};
+
+ private Helper nilusHelper;
+ /**
+ * @param tethysControl
+ */
+ public CalibrationHandler(TethysControl tethysControl) {
+ this.tethysControl = tethysControl;
+ calibrationsList = new ArrayList();
+ tethysControl.addStateObserver(this); try {
+ nilusHelper = new Helper();
+ } catch (JAXBException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void updateState(TethysState tethysState) {
+ switch (tethysState.stateType) {
+ case EXPORTING:
+ break;
+ case NEWPAMGUARDSELECTION:
+ case NEWPROJECTSELECTION:
+ case EXPORTRDATA:
+ case DELETEDATA:
+ case UPDATEMETADATA:
+ case UPDATESERVER:
+ if (isWantedState(tethysState)) {
+ updateDocumentsList();
+ }
+ default:
+ break;
+
+ }
+ }
+
+ /**
+ * Is it a state notification we want to respond to
+ * @param state
+ * @return true if worth it.
+ */
+ protected boolean isWantedState(TethysState state) {
+ if (state.collection == null) {
+ return true;
+ }
+ switch (state.collection) {
+ case OTHER:
+ case Calibrations:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Update the list of documents associated with the selected instrument.
+ */
+ private void updateDocumentsList() {
+
+ calibrationsList.clear();
+
+ ArrayList docsList = getArrayCalibrations();
+ // now immediately read the calibrations in again.
+ if (docsList == null) {
+ return;
+ }
+ NilusUnpacker unpacker = new NilusUnpacker();
+ for (DocumentInfo aDoc : docsList) {
+ Queries queries = tethysControl.getDbxmlConnect().getTethysQueries();
+ String result = null;
+ Calibration calObj = null;
+ try {
+ result = queries.getDocument(Collection.Calibrations.toString(), aDoc.getDocumentName());
+ if (result != null) {
+ // create a document and convert it into a Nilus calibrations document.
+ Document doc = tethysControl.getDbxmlQueries().convertStringToXMLDocument(result);
+ if (doc == null) {
+ System.out.println("Unable to convert Calibration result to Document\n " + result);
+ continue;
+ }
+ calObj = (Calibration) unpacker.unpackDocument(doc, Calibration.class);
+ if (calObj == null) {
+ System.out.println("Unable to convert Calibration document to nilus object\n " + result);
+ continue;
+ }
+ }
+ long t = System.currentTimeMillis();
+ try {
+ XMLGregorianCalendar gt = calObj.getMetadataInfo().getDate();
+ if (gt != null) {
+ t = TethysTimeFuncs.millisFromGregorianXML(gt);
+ }
+ }
+ catch (Exception e) {
+
+ }
+ DocumentNilusObject calDataUnit = new DocumentNilusObject(Collection.Calibrations, aDoc.getDocumentName(), calObj.getId(), calObj);
+ calibrationsList.add(calDataUnit);
+// System.out.println(result);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public int exportAllCalibrations() {
+
+ Calibration sampleCal = new Calibration();
+ try {
+ Helper.createRequiredElements(sampleCal);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e1) {
+ e1.printStackTrace();
+ }
+ sampleCal = CalibrationsExportWizard.showWizard(tethysControl.getGuiFrame(), sampleCal);
+ if (sampleCal == null) {
+ return 0;
+ }
+
+ NilusSettingsWrapper wrappedSample = new NilusSettingsWrapper();
+ wrappedSample.setNilusObject(sampleCal);
+
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ int nPhone = array.getHydrophoneCount();
+ DBXMLConnect dbxml = tethysControl.getDbxmlConnect();
+ int nExport = 0;
+ boolean overwrite = false;
+ boolean exists;
+ TethysReporter.getTethysReporter().clear();
+ for (int i = 0; i < nPhone; i++) {
+// String docName = getHydrophoneId(i);
+ NilusSettingsWrapper clonedWrap = wrappedSample.clone();
+ sampleCal = clonedWrap.getNilusObject(Calibration.class);
+ Calibration calDoc = createCalibrationDocument(i);
+ if (sampleCal != null) {
+ calDoc.setMetadataInfo(sampleCal.getMetadataInfo());
+ calDoc.setProcess(sampleCal.getProcess());
+ calDoc.setQualityAssurance(sampleCal.getQualityAssurance());
+ if (NilusChecker.isEmpty(sampleCal.getResponsibleParty()) == false) {
+ calDoc.setResponsibleParty(sampleCal.getResponsibleParty());
+ }
+ calDoc.setTimeStamp(sampleCal.getTimeStamp());
+ }
+ // check the contact info in the metadata.
+ // can't so because it's required.
+// MetadataInfo metaData = calDoc.getMetadataInfo();
+// if (metaData != null) {
+// if (NilusChecker.isEmpty(metaData.getContact())) {
+// metaData.setContact(null);
+// }
+// }
+
+ addParameterDetails(calDoc, i);
+ // run some checks of completeness of the data
+ NilusChecker.removeEmptyFields(calDoc);
+// ArrayList emptyFields = NilusChecker.checkEmptyFields(calDoc);
+
+ String calDocName = createDocumentName(calDoc, i);
+ exists = calDocumentExists(calDocName);
+ if (exists && overwrite == false) {
+ String msg = String.format("Calibration document %s already exists. Do you want to overwrite it and other documents from this date?", calDocName);
+ int ans = WarnOnce.showWarning("Calibration Export", msg, WarnOnce.OK_CANCEL_OPTION);
+ if (ans == WarnOnce.OK_OPTION) {
+ overwrite = true;
+ }
+ else {
+ return nExport;
+ }
+ }
+ boolean ok = false;
+ if (exists == true && overwrite == false) {
+ continue;
+ }
+ try {
+ if (exists) {
+ ok = dbxml.removeDocument(Collection.Calibrations, calDocName);
+ }
+ ok = dbxml.postAndLog(calDoc, calDocName);
+ } catch (TethysException e) {
+ e.printStackTrace();
+ tethysControl.showException(e);
+ ok = false;
+ break;
+ }
+ if (ok) {
+ nExport++;
+ }
+ }
+ tethysControl.sendStateUpdate(new TethysState(TethysState.StateType.EXPORTRDATA, Collection.Calibrations));
+ TethysReporter.getTethysReporter().showReport(true);
+ return nExport;
+ }
+
+ /**
+ * Add the separate pamguard parameters to the document which are used
+ * to make up the overall calibration.
+ * @param calDoc
+ * @param i hydrophone number
+ */
+ private void addParameterDetails(Calibration calDoc, int i) {
+ Parameters params = calDoc.getProcess().getParameters();
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.unitType);
+ AcquisitionParameters daqParams = daqControl.getAcquisitionParameters();
+ Hydrophone phone = array.getHydrophoneArray().get(i);
+ try {
+ nilusHelper.AddAnyElement(params.getAny(), "HydrophoneType", phone.getType());
+ nilusHelper.AddAnyElement(params.getAny(), "Sensitivity", String.format("%3.1f", phone.getSensitivity()));
+ nilusHelper.AddAnyElement(params.getAny(), "PreampGain", String.format("%3.1f", phone.getPreampGain()));
+ nilusHelper.AddAnyElement(params.getAny(), "ADCp-p", String.format("%3.2fV", daqParams.getVoltsPeak2Peak()));
+ Preamplifier preamp = daqParams.preamplifier;
+ if (preamp != null) {
+ nilusHelper.AddAnyElement(params.getAny(), "ADCAmplifier", String.format("%3.2fdB", preamp.getGain()));
+ }
+ } catch (JAXBException e) {
+ e.printStackTrace();
+ } catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Format the data in the dd MMMM yyyy format
+ * @param timeInMillis time in milliseconds
+ * @return formatted string.
+ */
+ public static String formatDate(long timeInMillis) {
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(timeInMillis);
+ c.setTimeZone(PamCalendar.defaultTimeZone);
+ DateFormat df = new SimpleDateFormat("yyMMdd");
+ df.setTimeZone(PamCalendar.defaultTimeZone);
+ Date d = c.getTime();
+ return df.format(d);
+ }
+
+
+ /**
+ * Get a name for the document, which is a bit like the id within
+ * the document, but also contain a yymmdd data string.
+ * @param calDoc
+ * @param i channel
+ * @return document name
+ */
+ private String createDocumentName(Calibration calDoc, int iChan) {
+ long docDate = System.currentTimeMillis();
+ XMLGregorianCalendar date = calDoc.getMetadataInfo().getDate();
+ if (date != null) {
+ docDate = TethysTimeFuncs.millisFromGregorianXML(date);
+ }
+ String dateStr = formatDate(docDate);
+ String name = String.format("%s_%s_ch%d", createCalibrationDocumentRoot(), dateStr, iChan);
+ return name;
+ }
+
+ /**
+ * Get a start of name for a calibration document. This will be used in the document name
+ * with a date and a channel, and the document Id just of the root and the channel.
+ * @return root string for document names and document id's.
+ */
+ public String createCalibrationDocumentRoot() {
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ if (array == null) {
+ return null;
+ }
+ String root = String.format("%s %s", array.getInstrumentType(), array.getInstrumentId());
+ root = root.replace(" ", "_");
+ return root;
+ }
+
+ /**
+ * Create a calibration document for a single hydrophone channel.
+ * @param pDeployment deployment, for cross referencing.
+ * @param channelIndex channel id. One document per channel for a multi hydrophone array.
+ * @return Calibration document.
+ */
+ public Calibration createCalibrationDocument(int channelIndex) {
+ AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.unitType);
+ return createCalibrationDocument(daqControl, channelIndex);
+ }
+
+ /**
+ * Create a calibration document for a single hydrophone channel.
+ * @param pDeployment deployment, for cross referencing.
+ * @param soundAcquisition Daq information - needed to get the ADC calibration information.
+ * @param channelIndex channel id. One document per channel for a multi hydrophone array.
+ * @return Calibration document.
+ */
+ public Calibration createCalibrationDocument(AcquisitionControl soundAcquisition, int channelIndex) {
+ /**
+ * Calibrations document id and cross referencing to Deploymnet documents:
+ * Identifier of instrument, preamplifier, or hydrophone.
+ * Corresponds to elements in Deployment:
+ * Deployment/Instrument/Id,
+ * Deployment/Sensors/Audio/HydrophoneId,
+ * Deployment/Sensors/Audio[i]/PreampId.
+ * As instruments may be calibrated multiple times, it is not an error for duplicate Id values to appear.
+ * It is recommended that the three different types of identifiers (instrument, hydrophone, preamp) be distinct,
+ * but the Type element may be used to distinguish them if they are not.
+ */
+
+ /*
+ * very remote possibility that DAQ doesn't exist. What to do in this case ? It's also possible that some configurations may
+ * have to have >1 DAQ's ?
+ */
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ if (array == null) {
+ return null;
+ }
+ if (channelIndex < 0 || channelIndex >= array.getHydrophoneCount()) {
+ return null;
+ }
+// ArrayManager.getArrayManager().get
+// hydrophones = array.
+ Hydrophone hydrophone = array.getHydrophoneArray().get(channelIndex);
+ double hSens = hydrophone.getSensitivity();
+ double preampGain = hydrophone.getPreampGain();
+
+ GlobalMediumManager mediumManager = PamController.getInstance().getGlobalMediumManager();
+ SoundMedium currentMedium = mediumManager.getCurrentMedium();
+ double dbRef = GlobalMedium.getdBreference(currentMedium); // probably in Pa, so multiply by 1e6. 20 (air) or 0 (water)
+
+ /**
+ * The calibration id can be a bit tricky, it will need to be cross referenced from the
+ * Deployment document, and it is likely that a deployment document will have to reference several
+ * calibration documents for different channels.
+ * Make the name from the Array name (new), the array Instrument Id (unique to the array)
+ * and the channel number. These will then all have to go into the Deployment document in
+ * the list of audio devices, cross referenced as the SensorId field.
+ *
+ */
+
+ Calibration calibration = new Calibration();
+
+ try {
+ Helper.createRequiredElements(calibration);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ e.printStackTrace();
+ }
+ String id = getHydrophoneId(channelIndex);
+// id = String.format("%d", channelIndex);
+ calibration.setId(id);
+ calibration.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis()));
+// calibration.setType(GlobalMedium.getRecieverString(currentMedium, false, false));
+ calibration.setType("end-to-end");
+ calibration.setIntensityReferenceUPa(AutoTethysProvider.roundSignificantFigures(dbRef*1e6,3));
+// String sensRef = GlobalMedium.getdBRefString(currentMedium);
+ // it doesn't like this since it has a unicode character. Leave it or change the micro to 'u'
+// calibration.setSensitivityReference(sensRef);
+ calibration.setSensitivityDBV(hSens+preampGain);
+ if (soundAcquisition != null) {
+ AcquisitionProcess daqProcess = soundAcquisition.getAcquisitionProcess();
+ double fullScale = daqProcess.rawAmplitude2dB(1, channelIndex, false);
+ calibration.setSensitivityDBFS(fullScale);
+ }
+ FrequencyResponse frs = calibration.getFrequencyResponse();
+ List hz = frs.getHz();
+ List db = frs.getDB();
+ hz.add(Double.valueOf(0));
+ db.add(Double.valueOf(hSens+preampGain));
+
+ if (NilusChecker.isEmpty(calibration.getResponsibleParty())) {
+ calibration.setResponsibleParty(null);
+ }
+
+ MetadataInfo metaInf = calibration.getMetadataInfo();
+ if (metaInf == null) {
+ metaInf = new MetadataInfo();
+ calibration.setMetadataInfo(metaInf);
+ }
+ metaInf.setDate(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis()));
+ metaInf.setUpdateFrequency("as-needed");
+ ResponsibleParty contact = metaInf.getContact();
+ if (contact == null) {
+ contact = new ResponsibleParty();
+ metaInf.setContact(contact);
+ }
+ if (NilusChecker.isEmpty(metaInf.getContact())) {
+ metaInf.setContact(null);
+ }
+ if (NilusChecker.isEmpty(metaInf)) {
+ calibration.setMetadataInfo(null);
+ }
+ contact.setIndividualName("Unknown");
+ contact.setOrganizationName("unknown");
+
+ QualityAssurance qa = calibration.getQualityAssurance();
+ if (qa == null) {
+ qa = new QualityAssurance();
+ calibration.setQualityAssurance(qa);
+ }
+ qa.setQuality(QualityValueBasic.VALID);
+ qa.setComment("Unknown calibration");
+
+
+ return calibration;
+ }
+
+ /**
+ * See if a document already exists. This should only occur if you
+ * try to export the same document twice with the same calibration date.
+ * @param documentName
+ * @return true if a document already exists.
+ */
+ public boolean calDocumentExists(String documentName) {
+ if (calibrationsList == null) {
+ return false;
+ }
+ for (int i = 0; i < calibrationsList.size(); i++) {
+ if (calibrationsList.get(i).getDocumentName().equalsIgnoreCase(documentName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return if we have at least one document for every channel.
+ * @return true if all cal documents exist.
+ */
+ public boolean haveAllChannelCalibrations() {
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ int nPhone = array.getHydrophoneCount();
+ for (int i = 0; i < nPhone; i++) {
+ if (haveChannelCalibration(i) == false) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Find whether we have a document for this instrument and channel.
+ * @param iChan
+ * @return true if we have an appropriate doc.
+ */
+ public boolean haveChannelCalibration(int iChan) {
+ if (calibrationsList == null) {
+ return false;
+ }
+ String seachPattern = makeChannelNamePart(iChan);
+ for (int i = 0; i < calibrationsList.size(); i++) {
+ String docName = calibrationsList.get(i).getDocumentName();
+ if (docName.endsWith(seachPattern)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get an id based on the instrument identifiers and channel number.
+ * This is the internal id of the document, not the document name which
+ * includes an additional date part in the name.
+ * @param channelIndex
+ * @return id string - instrument type + instrument id + channel
+ */
+ public String getHydrophoneId(int channelIndex) {
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ if (array == null) {
+ return null;
+ }
+ String id = String.format("%s_%s", createCalibrationDocumentRoot(), makeChannelNamePart(channelIndex));
+ id = id.replace(" ", "_");
+ return id;
+ }
+
+ /**
+ * Make the final part of the document name / id which is the channel number.
+ * @param channelIndex channel index
+ * @return string in the form ch%02d (e.g. ch03)
+ */
+ public String makeChannelNamePart(int channelIndex) {
+ return String.format("ch%02d", channelIndex);
+ }
+
+ /**
+ * @return the calibrationDataBlock
+ */
+ public ArrayList> getCalibrationDataList() {
+ return calibrationsList;
+ }
+
+ /**
+ * Make a list of document names associated with this instrument.
+ * @return list of calibration documents using this instrument, based on the start of the document name.
+ */
+ private ArrayList getArrayCalibrations() {
+ ArrayList allCals = null;
+ try {
+ allCals = tethysControl.getDbxmlQueries().getCollectionDocumentList(Collection.Calibrations);
+ }
+ catch (Exception e) {
+
+ }
+ if (allCals == null) {
+ return null;
+ }
+ String prefix = createCalibrationDocumentRoot(); // find doc names that have that root.
+ ArrayList theseCals = new ArrayList<>();
+ for (DocumentInfo aDoc : allCals) {
+ if (aDoc.getDocumentName().startsWith(prefix)) {
+ theseCals.add(aDoc);
+ }
+ }
+ return theseCals;
+ }
+}
diff --git a/src/tethys/calibration/swing/CalibrationProcessCard.java b/src/tethys/calibration/swing/CalibrationProcessCard.java
new file mode 100644
index 00000000..094d9d5d
--- /dev/null
+++ b/src/tethys/calibration/swing/CalibrationProcessCard.java
@@ -0,0 +1,205 @@
+package tethys.calibration.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.TitledBorder;
+
+import PamView.dialog.PamDialog;
+import PamView.dialog.PamGridBagContraints;
+import PamView.panel.WestAlignedPanel;
+import PamView.wizard.PamWizard;
+import nilus.AlgorithmType;
+import nilus.AlgorithmType.Parameters;
+import nilus.AlgorithmType.SupportSoftware;
+import nilus.Calibration;
+import nilus.Calibration.QualityAssurance;
+import nilus.Helper;
+import nilus.QualityValueBasic;
+import tethys.calibration.CalibrationHandler;
+import tethys.niluswraps.NilusChecker;
+
+/**
+ * Calibrations Process card attempts to fill in the
+ * calibration data for the Quality Assurance and Process fields.
+ * @author dg50
+ *
+ */
+public class CalibrationProcessCard extends CalibrationsCard {
+
+ private JPanel processPanel;
+
+ private JComboBox calMethod;
+
+ private JTextArea software;
+
+ private JTextField version;
+
+ private JComboBox qaQuality;
+
+ private JTextField qaComment;
+
+ public CalibrationProcessCard(PamWizard pamWizard) {
+ super(pamWizard, "Calibration Process");
+ this.setLayout(new BorderLayout());
+ processPanel = new JPanel(new GridBagLayout());
+ WestAlignedPanel wp;
+ this.add(BorderLayout.NORTH, wp = new WestAlignedPanel(processPanel));
+ wp.setBorder(new TitledBorder("Calibration Process"));
+
+ GridBagConstraints c = new PamGridBagContraints();
+
+ calMethod = new JComboBox();
+ String[] meths = CalibrationHandler.calibrationMethods;
+ for (int i = 0; i < meths.length; i++) {
+ calMethod.addItem(meths[i]);
+ }
+
+ qaQuality = new JComboBox<>();
+ String[] vals = CalibrationHandler.qaTypes;
+ for (int i = 0; i < vals.length; i++) {
+ qaQuality.addItem(vals[i]);
+ }
+
+ software = new JTextArea(5, 25);
+ software.setLineWrap(true);
+ software.setWrapStyleWord(true);
+ software.setToolTipText("Details of calibration method and software used");
+
+ version = new JTextField(20);
+ version.setToolTipText("Serial number of calibration device");
+
+ qaComment = new JTextField(20);
+ qaComment.setToolTipText("Comment on calibration quality");
+
+ processPanel.add(new JLabel("Method ", JLabel.RIGHT), c);
+ c.gridx++;
+ processPanel.add(calMethod, c);
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 1;
+ processPanel.add(new JLabel("Serial number ", JLabel.RIGHT), c);
+ c.gridx++;
+ c.gridwidth = 2;
+ processPanel.add(version, c);
+ c.gridx = 0;
+ c.gridy++;
+ c.gridwidth = 1;
+ processPanel.add(new JLabel("Quality ", JLabel.RIGHT), c);
+ c.gridx++;
+ processPanel.add(qaQuality, c);
+ c.gridx = 0;
+ c.gridy++;
+ processPanel.add(new JLabel("QA Comment ", JLabel.RIGHT), c);
+ c.gridx++;
+ c.gridwidth = 2;
+ processPanel.add(qaComment, c);
+
+ this.add(BorderLayout.CENTER, makeScrollablePanel(software, "Calibration method"));
+
+ }
+
+ private JScrollPane makeScrollablePanel(JTextArea textArea, String title) {
+ // TODO Auto-generated method stub
+// mainPanel.add(new Label(title, JLabel.LEFT));
+// textArea.setMinimumSize(new Dimension(200, 200));
+ JScrollPane scrollPane = new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+ scrollPane.setBorder(new TitledBorder(title));
+ scrollPane.setPreferredSize(new Dimension(scrollPane.getPreferredSize().height/2, 0));
+ return scrollPane;
+ }
+
+
+ @Override
+ public boolean getParams(Calibration calibration) {
+ if (calibration == null) {
+ return false;
+ }
+ AlgorithmType process = calibration.getProcess();
+ if (process == null) {
+ process = new AlgorithmType();
+ calibration.setProcess(process);
+ }
+ process.setMethod((String) calMethod.getSelectedItem());
+ process.setVersion(version.getText());
+ String soft = warnNotNull(getPamWizard(), software, "Calibration Method");
+ if (soft == null) {
+ return false;
+ }
+ process.setSoftware(soft);
+ if (software.getText() == null) {
+ getPamWizard().showWarning("You must specify the calibration method used");
+ }
+
+ QualityAssurance qa = calibration.getQualityAssurance();
+ if (qa == null) {
+ qa = new QualityAssurance();
+ calibration.setQualityAssurance(qa);
+ }
+ String t = warnNotNull(getPamWizard(), qaComment, "QA Comment");
+ if (t == null) {
+ return false;
+ }
+ qa.setComment(t);
+ qa.setQuality(QualityValueBasic.fromValue((String) qaQuality.getSelectedItem()));
+
+ // need to add a few fixed things for this to work...
+// List supportSoftware = process.getSupportSoftware();
+ Parameters params = process.getParameters();
+ if (params == null) {
+ params = new Parameters();
+ process.setParameters(params);
+// params.getAny().
+ }
+ try {
+ Helper.createRequiredElements(params);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+// if (checkEmptyFields(qa) == false) {
+// return false;
+// }
+// if (checkEmptyFields(process) == false) {
+//// return false;
+// }
+
+ return true;
+ }
+
+
+
+ @Override
+ public void setParams(Calibration calibration) {
+ if (calibration == null) {
+ return;
+ }
+ AlgorithmType process = calibration.getProcess();
+ if (process != null) {
+ calMethod.setSelectedItem(process.getMethod());
+ version.setText(process.getVersion());
+ software.setText(process.getSoftware());
+ }
+ QualityAssurance qa = calibration.getQualityAssurance();
+ if (qa != null) {
+ QualityValueBasic qb = qa.getQuality();
+ if (qb != null) {
+ qaQuality.setSelectedItem(qb.value());
+ }
+ qaComment.setText(qa.getComment());
+ }
+ }
+}
diff --git a/src/tethys/calibration/swing/CalibrationsCard.java b/src/tethys/calibration/swing/CalibrationsCard.java
new file mode 100644
index 00000000..a59482f4
--- /dev/null
+++ b/src/tethys/calibration/swing/CalibrationsCard.java
@@ -0,0 +1,14 @@
+package tethys.calibration.swing;
+
+import PamView.wizard.PamWizard;
+import PamView.wizard.PamWizardCard;
+import nilus.Calibration;
+import tethys.swing.TethysWizardCard;
+
+abstract public class CalibrationsCard extends TethysWizardCard {
+
+ public CalibrationsCard(PamWizard pamWizard, String title) {
+ super(pamWizard, title);
+ }
+
+}
diff --git a/src/tethys/calibration/swing/CalibrationsContactCard.java b/src/tethys/calibration/swing/CalibrationsContactCard.java
new file mode 100644
index 00000000..2dc6e581
--- /dev/null
+++ b/src/tethys/calibration/swing/CalibrationsContactCard.java
@@ -0,0 +1,208 @@
+package tethys.calibration.swing;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Date;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.TitledBorder;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.jdesktop.swingx.JXDatePicker;
+
+import PamView.dialog.PamDialog;
+import PamView.dialog.PamGridBagContraints;
+import PamView.panel.WestAlignedPanel;
+import PamView.wizard.PamWizard;
+import nilus.Calibration;
+import nilus.ContactInfo;
+import nilus.MetadataInfo;
+import nilus.ResponsibleParty;
+import tethys.TethysTimeFuncs;
+import tethys.calibration.CalibrationHandler;
+import tethys.niluswraps.NilusChecker;
+import tethys.swing.export.ResponsiblePartyPanel;
+
+public class CalibrationsContactCard extends CalibrationsCard {
+
+ private JXDatePicker datePicker;
+
+ private ResponsiblePartyPanel calibrator, dataManager;
+
+ private JComboBox updateInterval;
+
+ private MetadataInfo metaData;
+
+ private JButton copyDown, copyUp;
+
+ public CalibrationsContactCard(PamWizard pamWizard) {
+ super(pamWizard, "Contact Details");
+ // TODO Auto-generated constructor stub
+// setBorder(new TitledBorder("Contact"));
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+ updateInterval = new JComboBox<>();
+ String[] vals = CalibrationHandler.updateOptions;
+ for (int i = 0; i < vals.length; i++) {
+ updateInterval.addItem(vals[i]);
+ }
+
+ JPanel datePanel = new JPanel(new GridBagLayout());
+ JPanel lp = new WestAlignedPanel(datePanel);
+ lp.setBorder(new TitledBorder("Calibration date"));
+ GridBagConstraints c = new PamGridBagContraints();
+ datePanel.add(new JLabel("Calibration date: ", JLabel.RIGHT), c);
+ datePicker = new JXDatePicker();
+ c.gridx++;
+ datePanel.add(datePicker, c);
+ c.gridx = 0;
+ c.gridy++;
+ datePanel.add(new JLabel("Update Frequency", JLabel.RIGHT), c);
+ c.gridx++;
+ datePanel.add(updateInterval, c);
+
+ calibrator = new ResponsiblePartyPanel("Technical Person");
+ dataManager = new ResponsiblePartyPanel("Data Manager");
+
+ JPanel copyPanel = new JPanel(new GridBagLayout());
+ c = new PamGridBagContraints();
+ copyPanel.add(copyDown = new JButton("Copy down"),c);
+ c.gridx++;
+ copyPanel.add(copyUp = new JButton("Copy up"), c);
+
+ add(lp);
+ add(calibrator.getMainPanel());
+ add(copyPanel);
+ add(dataManager.getMainPanel());
+
+ copyDown.setToolTipText("Copy technical person to data manager");
+ copyUp.setToolTipText("Copy data manager to technical person");
+ copyDown.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ copyRPDown();
+ }
+ });
+ copyUp.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ copyRPUp();
+ }
+
+ });
+ }
+
+ protected void copyRPDown() {
+ copyRPData(calibrator, dataManager);
+ }
+ private void copyRPUp() {
+ copyRPData(dataManager, calibrator);
+ }
+
+ private void copyRPData(ResponsiblePartyPanel rFrom, ResponsiblePartyPanel rTo) {
+ ResponsibleParty rp = checkRPChildren(null);
+ rFrom.getParams(rp);
+ rTo.setParams(rp);
+ }
+
+ @Override
+ public boolean getParams(Calibration cardParams) {
+ ResponsibleParty rp = checkRPChildren(cardParams.getResponsibleParty());
+ cardParams.setResponsibleParty(rp);
+ calibrator.getParams(rp);
+
+ metaData = cardParams.getMetadataInfo();
+ if (metaData == null) {
+ metaData = new MetadataInfo();
+ cardParams.setMetadataInfo(metaData);
+ }
+ metaData.setContact(checkRPChildren(metaData.getContact()));
+ dataManager.getParams(metaData.getContact());
+ ResponsibleParty metaContact = metaData.getContact();
+ NilusChecker.removeEmptyFields(metaData);
+ if (metaData.getContact() == null) {
+ return PamDialog.showWarning(getPamWizard(), "Missing data", "The Data Manager fields must be completed");
+ }
+
+ metaData.setUpdateFrequency((String) updateInterval.getSelectedItem());
+ metaData.setDate(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis()));
+
+ Date date = datePicker.getDate();
+ if (date == null) {
+ return getPamWizard().showWarning("You must specify the data of the calibration");
+ }
+ long millis = date.getTime();
+ cardParams.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(millis));
+
+
+ checkEmptyFields(rp);
+ checkEmptyFields(metaData);
+
+ return true;
+ }
+
+ private ResponsibleParty checkRPChildren(ResponsibleParty rp) {
+ if (rp == null) {
+ rp = new ResponsibleParty();
+ }
+ if (rp.getContactInfo() == null) {
+ rp.setContactInfo(new ContactInfo());
+ }
+ if (rp.getContactInfo().getAddress() == null) {
+// rp.getContactInfo().setAddress(new Address());
+ }
+ return rp;
+ }
+
+ private ResponsibleParty findResponsibleParty(Calibration cal) {
+ if (cal == null) {
+ return null;
+ }
+ MetadataInfo metaInfo = cal.getMetadataInfo();
+ if (metaInfo != null) {
+ ResponsibleParty resp = metaInfo.getContact();
+ if (resp != null && resp.getIndividualName() != null) {
+ return resp;
+ }
+ }
+ return cal.getResponsibleParty();
+
+ }
+
+ @Override
+ public void setParams(Calibration cardParams) {
+ // fill in as much as possible from the existing Calibration
+ ResponsibleParty resp = cardParams.getResponsibleParty();
+ if (resp != null) {
+ calibrator.setParams(resp);
+ }
+
+ MetadataInfo metaInf = cardParams.getMetadataInfo();
+ if (metaInf != null) {
+ resp = metaInf.getContact();
+ if (resp != null) {
+ dataManager.getParams(resp);
+ }
+ String uf = metaInf.getUpdateFrequency();
+ if (uf != null) {
+ updateInterval.setSelectedItem(uf);
+ }
+ }
+
+ XMLGregorianCalendar ts = cardParams.getTimeStamp();
+ if (ts != null) {
+ datePicker.setDate(new Date(TethysTimeFuncs.millisFromGregorianXML(ts)));
+ }
+
+
+ }
+
+}
diff --git a/src/tethys/calibration/swing/CalibrationsExportWizard.java b/src/tethys/calibration/swing/CalibrationsExportWizard.java
new file mode 100644
index 00000000..74bb356a
--- /dev/null
+++ b/src/tethys/calibration/swing/CalibrationsExportWizard.java
@@ -0,0 +1,42 @@
+package tethys.calibration.swing;
+
+import java.awt.Window;
+
+import PamView.wizard.PamWizard;
+import PamView.wizard.PamWizardCard;
+import nilus.Calibration;
+
+public class CalibrationsExportWizard extends PamWizard {
+
+ private Calibration sampleDocument;
+
+ private CalibrationsExportWizard(Window parentFrame, Calibration sampleDocument) {
+ super(parentFrame, "Calibrations Export");
+ this.sampleDocument = sampleDocument;
+ addCard(new CalibrationProcessCard(this));
+ addCard(new CalibrationsContactCard(this));
+ }
+
+ public static Calibration showWizard(Window parentFrame, Calibration sampleDocument) {
+ CalibrationsExportWizard wiz = new CalibrationsExportWizard(parentFrame, sampleDocument);
+ wiz.setParams();
+ wiz.setVisible(true);
+ return wiz.sampleDocument;
+ }
+
+ @Override
+ public void setCardParams(PamWizardCard wizardCard) {
+ wizardCard.setParams(sampleDocument);
+ }
+
+ @Override
+ public boolean getCardParams(PamWizardCard wizardCard) {
+ return wizardCard.getParams(sampleDocument);
+ }
+
+ @Override
+ public void cancelButtonPressed() {
+ sampleDocument = null;
+ }
+
+}
diff --git a/src/tethys/calibration/swing/CalibrationsMainPanel.java b/src/tethys/calibration/swing/CalibrationsMainPanel.java
new file mode 100644
index 00000000..e13365ef
--- /dev/null
+++ b/src/tethys/calibration/swing/CalibrationsMainPanel.java
@@ -0,0 +1,77 @@
+package tethys.calibration.swing;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.TitledBorder;
+
+
+import PamView.panel.PamPanel;
+import tethys.TethysControl;
+import tethys.TethysState;
+import tethys.calibration.CalibrationHandler;
+import tethys.swing.TethysGUIPanel;
+
+public class CalibrationsMainPanel extends TethysGUIPanel {
+
+ private CalibrationHandler calibrationHandler;
+
+ private CalibrationsTable calibrationsTable;
+
+ private JPanel mainPanel;
+
+ private JPanel ctrlPanel;
+
+ private JButton exportButton;
+
+ private JLabel warning;
+
+ public CalibrationsMainPanel(TethysControl tethysControl, CalibrationHandler calibrationHandler) {
+ super(tethysControl);
+ this.calibrationHandler = calibrationHandler;
+ mainPanel = new PamPanel(new BorderLayout());
+ mainPanel.setBorder(new TitledBorder("Instrument calibration information"));
+
+ calibrationsTable = new CalibrationsTable(tethysControl, calibrationHandler);
+ mainPanel.add(BorderLayout.CENTER, calibrationsTable.getComponent());
+
+ ctrlPanel = new PamPanel(new BorderLayout());
+ exportButton = new JButton("Export ...");
+ ctrlPanel.add(BorderLayout.WEST, exportButton);
+ warning = new JLabel();
+ ctrlPanel.add(BorderLayout.CENTER, warning);
+ mainPanel.add(BorderLayout.NORTH, ctrlPanel);
+ exportButton.setToolTipText("Export calibration data to database");
+ exportButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ exportCalibrations();
+ }
+ });
+ }
+
+ protected void exportCalibrations() {
+ calibrationHandler.exportAllCalibrations();
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return mainPanel;
+ }
+
+ @Override
+ public void updateState(TethysState tethysState) {
+ super.updateState(tethysState);
+ enableControls();
+ }
+
+ private void enableControls() {
+ exportButton.setEnabled(getTethysControl().isServerOk());
+ }
+
+}
diff --git a/src/tethys/calibration/swing/CalibrationsTable.java b/src/tethys/calibration/swing/CalibrationsTable.java
new file mode 100644
index 00000000..45b91f18
--- /dev/null
+++ b/src/tethys/calibration/swing/CalibrationsTable.java
@@ -0,0 +1,285 @@
+package tethys.calibration.swing;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.JComponent;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.TitledBorder;
+import javax.swing.table.AbstractTableModel;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import PamController.PamController;
+import PamController.soundMedium.GlobalMedium;
+import PamController.soundMedium.GlobalMediumManager;
+import PamUtils.PamCalendar;
+import PamView.dialog.warn.WarnOnce;
+import PamView.panel.PamPanel;
+import PamView.tables.SwingTableColumnWidths;
+import nilus.Calibration;
+import tethys.Collection;
+import tethys.DocumentNilusObject;
+import tethys.TethysControl;
+import tethys.TethysState;
+import tethys.TethysState.StateType;
+import tethys.TethysTimeFuncs;
+import tethys.calibration.CalibrationHandler;
+import tethys.dbxml.TethysException;
+import tethys.swing.TethysGUIPanel;
+
+public class CalibrationsTable extends TethysGUIPanel {
+
+ private CalibrationHandler calibrationHandler;
+
+ private CalibrationsTableModel calTableModel;
+
+ private JPanel mainPanel;
+
+ private JTable calTable;
+
+ private TethysControl tethysControl;
+
+ /**
+ * @param calibrationHandler
+ */
+ public CalibrationsTable(TethysControl tethysControl, CalibrationHandler calibrationHandler) {
+ super(tethysControl);
+ this.tethysControl = tethysControl;
+ this.calibrationHandler = calibrationHandler;
+ calTableModel = new CalibrationsTableModel();
+ calTable = new JTable(calTableModel);
+ calTable.setRowSelectionAllowed(true);
+ calTable.addMouseListener(new TableMouse());
+
+ JScrollPane scrollPane = new JScrollPane(calTable);
+
+ mainPanel = new PamPanel(new BorderLayout());
+ mainPanel.add(BorderLayout.CENTER, scrollPane);
+
+ calTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ new SwingTableColumnWidths(tethysControl.getUnitName()+"CalibrationsTable", calTable);
+
+ }
+
+
+ @Override
+ public JComponent getComponent() {
+ return mainPanel;
+ }
+
+
+ @Override
+ public void updateState(TethysState tethysState) {
+ super.updateState(tethysState);
+ calTableModel.fireTableDataChanged();
+ }
+
+ private class TableMouse extends MouseAdapter {
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ showPopupMenu(e);
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger()) {
+ showPopupMenu(e);
+ }
+ }
+
+ }
+
+ public void showPopupMenu(MouseEvent e) {
+ int[] rows = calTable.getSelectedRows();
+ if (rows == null || rows.length == 0) {
+ return;
+ }
+ int n = rows.length;
+ DocumentNilusObject doc = calibrationHandler.getCalibrationDataList().get(rows[0]);
+
+ JPopupMenu popMenu = new JPopupMenu();
+ JMenuItem menuItem;
+ if (n == 1) {
+ menuItem = new JMenuItem("Show document " + doc.getDocumentName());
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ showCalibration(doc);
+ }
+ });
+ popMenu.add(menuItem);
+ }
+ if (n > 1) {
+ menuItem = new JMenuItem("Delete selected documents");
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ deleteCalibrations(rows);
+ }
+ });
+ popMenu.add(menuItem);
+ }
+ else {
+ menuItem = new JMenuItem("Delete document " + doc.getDocumentName());
+ menuItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ deleteCalibration(doc);
+ }
+ });
+ popMenu.add(menuItem);
+ }
+ popMenu.show(e.getComponent(), e.getX(), e.getY());
+ }
+
+ protected void deleteCalibration(DocumentNilusObject doc) {
+ String docName = doc.getDocumentName();
+ int ans = WarnOnce.showNamedWarning("delete doc " + Collection.Calibrations.collectionName(),
+ PamController.getMainFrame(), "Delete document",
+ "Are you sure you want to delete the document " + docName, WarnOnce.OK_CANCEL_OPTION);
+ if (ans == WarnOnce.OK_OPTION) {
+ try {
+ tethysControl.getDbxmlConnect().removeDocument(Collection.Calibrations.collectionName(), docName);
+ } catch (TethysException e) {
+ System.out.println("Failed to delete " + docName);
+ System.out.println(e.getMessage());
+ }
+ }
+ updateEverything();
+ calTableModel.fireTableDataChanged();
+ }
+
+
+ protected void showCalibration(DocumentNilusObject docInfo) {
+ tethysControl.displayDocument(docInfo);
+
+ }
+
+
+ protected void deleteCalibrations(int[] rows) {
+ String msg = String.format("Are you sure you want to delete %d calibrations documents ?", rows.length);
+ int ans = WarnOnce.showNamedWarning("Deletemanycalibrations", PamController.getMainFrame(), "Delete multiple documents", msg, WarnOnce.OK_CANCEL_OPTION);
+ if (ans != WarnOnce.OK_OPTION) {
+ return;
+ }
+ for (int i = 0; i < rows.length; i++) {
+ String docName = null;
+ try {
+ DocumentNilusObject doc = calibrationHandler.getCalibrationDataList().get(rows[i]);
+ docName = doc.getDocumentName();
+ tethysControl.getDbxmlConnect().removeDocument(Collection.Calibrations, docName);
+ } catch (TethysException e) {
+ System.out.println("Failed to delete " + docName);
+ System.out.println(e.getMessage());
+ }
+ }
+
+ updateEverything();
+
+ }
+
+ private void updateEverything() {
+ getTethysControl().sendStateUpdate(new TethysState(StateType.DELETEDATA, Collection.Calibrations));
+ }
+
+ class CalibrationsTableModel extends AbstractTableModel {
+
+ private static final long serialVersionUID = 1L;
+
+ private String[] columnNames = {"Document", "Id", "Date", "End to End", "Hydrophone"};
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ DocumentNilusObject dataUnit = null;
+ try {
+ dataUnit = calibrationHandler.getCalibrationDataList().get(rowIndex);
+ }
+ catch (Exception e) {
+ return null;
+ }
+ if (dataUnit == null) {
+ return null;
+ }
+ Calibration cal = dataUnit.getNilusObject();
+ switch (columnIndex) {
+ case 0:
+ return dataUnit.getDocumentName();
+ case 1:
+ return cal.getId();
+ case 2:
+ XMLGregorianCalendar ts = cal.getTimeStamp();
+ if (ts == null) {
+ return null;
+ }
+ long ms = TethysTimeFuncs.millisFromGregorianXML(ts);
+ return PamCalendar.formatDBDate(ms);
+ case 3:
+ return getFSString(cal);
+ case 4:
+ return getPhoneString(cal);
+// return String.format("%3.1fdB %s", cal.getSensitivityV(), cal.getType());
+ }
+ return null;
+ }
+
+ @Override
+ public int getRowCount() {
+ return calibrationHandler.getCalibrationDataList().size();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return columnNames.length;
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ if (column == 4) {
+ return PamController.getInstance().getGlobalMediumManager().getRecieverString();
+ }
+ else {
+ return columnNames[column];
+ }
+ }
+ }
+
+ public String getFSString(Calibration cal) {
+ Double fs = cal.getSensitivityDBFS();
+ if (fs == null) {
+ return null;
+ }
+ double ir = cal.getIntensityReferenceUPa();
+ String str = String.format("%3.1fdB", fs);
+ if (ir != 0) {
+ str += String.format(" re%.0f\u00B5Pa", ir);
+ }
+ return str;
+ }
+
+ public Object getPhoneString(Calibration cal) {
+ Double dbV = cal.getSensitivityV();
+ if (dbV == null) {
+ dbV = cal.getSensitivityDBV();
+ }
+ if (dbV == null) {
+ return null;
+ }
+ double ir = cal.getIntensityReferenceUPa();
+ String str = String.format("%3.1fdB", dbV);
+ if (ir != 0) {
+ str += String.format(" re%.0fV/\u00B5Pa", ir);
+ }
+ return str;
+ }
+}
diff --git a/src/tethys/database/TethysActions.java b/src/tethys/database/TethysActions.java
new file mode 100644
index 00000000..0c9ece36
--- /dev/null
+++ b/src/tethys/database/TethysActions.java
@@ -0,0 +1,27 @@
+package tethys.database;
+
+/**
+ * Possible document actions
+ * @author dg50
+ *
+ */
+public enum TethysActions {
+
+ ADDDOCUMENT, DELETEDOCUMENT, UPDATEDOCUMENT;
+
+// @Override
+// public String toString() {
+// switch (this) {
+// case ADDDOCUMENT:
+// return "Add document";
+// case DELETEDOCUMENT:
+// return "Delete document";
+// case UPDATEDOCUMENT:
+// return "Update document";
+// default:
+// return null;
+// }
+// }
+
+
+}
diff --git a/src/tethys/database/TethysLogDataBlock.java b/src/tethys/database/TethysLogDataBlock.java
new file mode 100644
index 00000000..7a3639d6
--- /dev/null
+++ b/src/tethys/database/TethysLogDataBlock.java
@@ -0,0 +1,16 @@
+package tethys.database;
+
+import PamguardMVC.PamDataBlock;
+import PamguardMVC.PamProcess;
+import tethys.TethysControl;
+
+public class TethysLogDataBlock extends PamDataBlock {
+
+ private TethysControl tethysControl;
+
+ public TethysLogDataBlock(TethysControl tethysControl) {
+ super(TethysLogDataUnit.class, "Tethys Log", null, 0);
+ this.tethysControl = tethysControl;
+ }
+
+}
diff --git a/src/tethys/database/TethysLogDataUnit.java b/src/tethys/database/TethysLogDataUnit.java
new file mode 100644
index 00000000..e1998c2b
--- /dev/null
+++ b/src/tethys/database/TethysLogDataUnit.java
@@ -0,0 +1,59 @@
+package tethys.database;
+
+import PamguardMVC.PamDataUnit;
+
+public class TethysLogDataUnit extends PamDataUnit {
+
+ private String collection;
+ private String documentId;
+ private TethysActions action;
+ private String comment;
+ private boolean success;
+
+ public TethysLogDataUnit(long timeMilliseconds, String collection, String documentId, TethysActions action, boolean success, String comment) {
+ super(timeMilliseconds);
+ this.collection = collection;
+ this.documentId = documentId;
+ this.action = action;
+ this.success = success;
+ this.comment = comment;
+
+ }
+
+ /**
+ * @return the collection
+ */
+ public String getCollection() {
+ return collection;
+ }
+
+ /**
+ * @return the documentId
+ */
+ public String getDocumentId() {
+ return documentId;
+ }
+
+ /**
+ * @return the action
+ */
+ public TethysActions getAction() {
+ return action;
+ }
+
+ /**
+ * @return the comment
+ */
+ public String getComment() {
+ return comment;
+ }
+
+ /**
+ * @return the success
+ */
+ public boolean isSuccess() {
+ return success;
+ }
+
+
+}
diff --git a/src/tethys/database/TethysLogger.java b/src/tethys/database/TethysLogger.java
new file mode 100644
index 00000000..9e7ae2ad
--- /dev/null
+++ b/src/tethys/database/TethysLogger.java
@@ -0,0 +1,128 @@
+package tethys.database;
+
+import java.sql.Types;
+
+import PamguardMVC.PamDataUnit;
+import generalDatabase.DBControlUnit;
+import generalDatabase.DBProcess;
+import generalDatabase.PamConnection;
+import generalDatabase.PamTableDefinition;
+import generalDatabase.PamTableItem;
+import generalDatabase.SQLLogging;
+import generalDatabase.SQLTypes;
+import tethys.TethysControl;
+
+/**
+ * Logging everything we put into Tethys in our own database.
+ * @author dg50
+ *
+ */
+public class TethysLogger extends SQLLogging {
+
+ private static TethysLogger tethysLogger;
+
+ private TethysControl tethysControl;
+
+ private TethysLogDataBlock logDataBlock;
+
+ private PamTableDefinition tableDefinition;
+
+ private PamTableItem collection, documentId, action, status, comment;
+
+ private boolean tableChecked = false;
+
+ private TethysLogger(TethysControl tethysControl, TethysLogDataBlock pamDataBlock) {
+ super(pamDataBlock);
+ this.tethysControl = tethysControl;
+ this.logDataBlock = pamDataBlock;
+ tableDefinition = new PamTableDefinition("TethysLog");
+ tableDefinition.addTableItem(collection = new PamTableItem("Collection", Types.VARCHAR));
+ tableDefinition.addTableItem(documentId = new PamTableItem("DocumentId", Types.VARCHAR));
+ tableDefinition.addTableItem(action = new PamTableItem("Action", Types.VARCHAR));
+ tableDefinition.addTableItem(status = new PamTableItem("Status", Types.VARCHAR));
+ tableDefinition.addTableItem(comment = new PamTableItem("Comment", Types.VARCHAR));
+ tableDefinition.setUpdatePolicy(UPDATE_POLICY_OVERWRITE);
+ setTableDefinition(tableDefinition);
+ }
+
+ public static TethysLogger getTethysLogger(TethysControl tethysControl) {
+ if (tethysLogger == null) {
+ tethysLogger = createTethysLogger(tethysControl);
+ }
+ return tethysLogger;
+ }
+
+ private boolean checkTable() {
+ if (tableChecked == true) {
+ return true;
+ }
+ if (findDBProcess() == null) {
+ return false;
+ }
+ else {
+ tableChecked = findDBProcess().checkTable(tableDefinition);
+ }
+ return tableChecked;
+ }
+
+ public boolean logAction(String collection, String documentId, TethysActions action, boolean success, String comment) {
+ PamConnection con = findDBConnection();
+ if (con == null) {
+ return false;
+ }
+ if (checkTable() == false) {
+ return false;
+ }
+
+ TethysLogDataUnit dataUnit = new TethysLogDataUnit(System.currentTimeMillis(), collection, documentId, action, success, comment);
+ return this.logData(con, dataUnit);
+ }
+
+ private PamConnection findDBConnection() {
+ return DBControlUnit.findConnection();
+ }
+
+ /**
+ * Find the database controlled unit. Must exist in viewer mode surely, but perhaps
+ * created after the Tethys module if the user is really crafty !
+ * @return the DB controlled unit.
+ */
+ private DBControlUnit findDBControl() {
+ return DBControlUnit.findDatabaseControl();
+ }
+
+ /**
+ * Fine the database process. Should exist.
+ * @return
+ */
+ private DBProcess findDBProcess() {
+ DBControlUnit dbControl = findDBControl();
+ if (dbControl == null) {
+ return null;
+ }
+ return dbControl.getDbProcess();
+ }
+
+ private static TethysLogger createTethysLogger(TethysControl tethysControl) {
+ TethysLogDataBlock datablock = new TethysLogDataBlock(tethysControl);
+ TethysLogger newLogger = new TethysLogger(tethysControl, datablock);
+ return newLogger;
+ }
+
+
+ @Override
+ public void setTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) {
+ TethysLogDataUnit tldu = (TethysLogDataUnit) pamDataUnit;
+ collection.setValue(tldu.getCollection());
+ documentId.setValue(tldu.getDocumentId());
+ action.setValue(tldu.getAction().toString());
+ status.setValue(tldu.isSuccess() ? "Success" : "Fail");
+ comment.setValue(tldu.getComment());
+ }
+
+// public TethysLogger(TethysControl tethysControl) {
+// this.tethysControl = tethysControl;
+// }
+
+
+}
diff --git a/src/tethys/dbxml/DBQueryResult.java b/src/tethys/dbxml/DBQueryResult.java
new file mode 100644
index 00000000..80a27246
--- /dev/null
+++ b/src/tethys/dbxml/DBQueryResult.java
@@ -0,0 +1,62 @@
+package tethys.dbxml;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class DBQueryResult {
+
+ public long queryTimeMillis;
+
+ public String queryResult;
+
+ public String schemaPlan;
+
+ public Exception queryException;
+
+ public DBQueryResult(long queryTimeMillis, String queryResult, String schemaPlan) {
+ super();
+ this.queryTimeMillis = queryTimeMillis;
+ this.queryResult = queryResult;
+ this.schemaPlan = schemaPlan;
+ }
+
+ public DBQueryResult(long queryTimeMillis, Exception queryException) {
+ super();
+ this.queryTimeMillis = queryTimeMillis;
+ this.queryException = queryException;
+ }
+
+ /**
+ * Get the result as an XML document.
+ * @return XML document
+ * @throws ParserConfigurationException
+ * @throws SAXException
+ * @throws IOException
+ */
+ public Document getDocument() throws ParserConfigurationException, SAXException, IOException {
+ if (queryResult == null) {
+ return null;
+ }
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+ //API to obtain DOM Document instance
+ DocumentBuilder builder = null;
+
+ //Create DocumentBuilder with default configuration
+ builder = factory.newDocumentBuilder();
+
+ //Parse the content to Document object
+ Document doc = builder.parse(new InputSource(new StringReader(queryResult)));
+ return doc;
+ }
+
+}
diff --git a/src/tethys/dbxml/DBXMLConnect.java b/src/tethys/dbxml/DBXMLConnect.java
new file mode 100644
index 00000000..9b12ecd5
--- /dev/null
+++ b/src/tethys/dbxml/DBXMLConnect.java
@@ -0,0 +1,554 @@
+package tethys.dbxml;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.util.ArrayList;
+
+import javax.xml.bind.JAXBException;
+
+import dbxml.JerseyClient;
+import dbxml.Queries;
+import dbxml.uploader.Importer;
+import nilus.MarshalXML;
+import tethys.Collection;
+import tethys.TethysControl;
+import tethys.database.TethysActions;
+import tethys.database.TethysLogger;
+import tethys.niluswraps.NilusChecker;
+import tethys.output.TethysExportParams;
+import tethys.reporter.TethysReport;
+import tethys.reporter.TethysReporter;
+
+/**
+ * Class containing functions for managing the database connection. Opening, closing,
+ * writing, keeping track of performance, etc.
+ * @author Doug Gillespie, Katie O'Laughlin
+ *
+ */
+public class DBXMLConnect {
+
+ private TethysControl tethysControl;
+ private File tempDirectory;
+
+ private JerseyClient jerseyClient;
+
+ private Queries queries;
+
+ private String currentSiteURL;
+
+// public static String[] collections = {"Deployments", "Detections", "Localizations", "Calibrations", "SpeciesAbbreviations"};
+
+ public DBXMLConnect(TethysControl tethysControl) {
+ this.tethysControl = tethysControl;
+
+ checkTempFolder();
+ }
+
+ /**
+ * Check the jersey client and the queries. Need to recreate
+ * if the url has changed.
+ * @return
+ */
+ private boolean checkClient() {
+ if (jerseyClient == null || queries == null || currentSiteURL == null) {
+ return false;
+ }
+ TethysExportParams params = tethysControl.getTethysExportParams();
+ if (!currentSiteURL.equalsIgnoreCase(params.getFullServerName())) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Get the client. The client will only be recreated if the url changes
+ * @return Jersy client
+ */
+ public synchronized JerseyClient getJerseyClient() {
+ if (!checkClient()) {
+ openConnections();
+ }
+ return jerseyClient;
+ }
+
+ /**
+ * Get the Queries object. This will only be recreated if the client changes.
+ * @return
+ */
+ public synchronized Queries getTethysQueries() {
+ if (!checkClient()) {
+ openConnections();
+ }
+ return queries;
+ }
+
+ /**
+ * Convert a nilus Object into a file
+ * @param nilusObject nilus object
+ * @param file file (should not exist)
+ * @return file (will be the same as input file)
+ * @throws TethysException
+ */
+ public File createXMLDocument(Object nilusObject, File file) throws TethysException {
+ Class objClass = nilusObject.getClass();
+ try {
+ MarshalXML marshal = new MarshalXML();
+ marshal.createInstance(objClass);
+ marshal.marshal(nilusObject, file.toString());
+ } catch(IllegalArgumentException e) {
+ throw new TethysException("IllegalArgumentException posting to Tethys: " + e.getMessage(), null);
+ } catch (IOException e) {
+ throw new TethysException("IOException posting to Tethys: " + e.getMessage(), null);
+ } catch (JAXBException e) {
+ throw new TethysException("JAXBException posting to Tethys: " + e.getMessage(), null);
+ }
+ return file;
+ }
+
+ /**
+ * Create a temporary nilus file.
+ * @param nilusObject
+ * @return
+ * @throws TethysException
+ */
+ public File createTempXMLDocument(Object nilusObject) throws TethysException {
+ String tempName = getTempFileName(nilusObject);
+ tempName = tempDirectory.getAbsolutePath() + File.separator + tempName + ".xml";
+ File tempFile = new File(tempName);
+ File retFile = createXMLDocument(nilusObject, tempFile);
+ retFile.deleteOnExit();
+ return retFile;
+ }
+
+
+ public boolean postAndLog(Object nilusObject) throws TethysException
+ {
+ return postAndLog(nilusObject, null);
+ }
+
+ /**
+ * I don't think this should ever be used since everything goes a bit pear
+ * shaped if the documentName isn't the same as the Id. However, for Calibration
+ * documents this is no longer the case, since a Calibration can have multiple
+ * entries on different dates, so allow it !
+ * @param nilusObject
+ * @param documentName
+ * @return
+ * @throws TethysException
+ */
+ public boolean postAndLog(Object nilusObject, String documentName) throws TethysException
+ {
+ boolean ok = NilusChecker.warnEmptyFields(tethysControl.getGuiFrame(), nilusObject);
+
+
+ TethysException e = null;
+ boolean success = false;
+ try {
+ success = postToTethys(nilusObject, documentName);
+ }
+ catch (TethysException ex) {
+ e = ex;
+ }
+ TethysLogger logger = TethysLogger.getTethysLogger(tethysControl);
+ Class objClass = nilusObject.getClass();
+ Collection collection = Collection.fromClass(objClass);
+ String documentId = getDocumentId(nilusObject);
+ logger.logAction(collection.collectionName(), documentId, TethysActions.ADDDOCUMENT, success, "");
+ if (e != null) {
+ throw (e);
+ }
+ return success;
+ }
+
+ /**
+ * take a nilus object loaded with PamGuard data and post it to the Tethys database
+ *
+ * @param pamGuardObjs a nilus object loaded with PamGuard data
+ * @return error string, null string means there are no errors
+ * @throws TethysException
+ */
+ private boolean postToTethys(Object nilusObject, String documentName) throws TethysException
+ {
+ Class objClass = nilusObject.getClass();
+ Collection collection = Collection.fromClass(nilusObject.getClass());
+ TethysExportParams params = new TethysExportParams();
+ String importReturn = null;
+ if (documentName == null) {
+ documentName = getTempFileName(nilusObject);
+ }
+ documentName = tempDirectory.getAbsolutePath() + File.separator + documentName + ".xml";
+ File tempFile = new File(documentName);
+ String bodgeName = documentName;//"C:\\Users\\dg50\\AppData\\Local\\Temp\\PAMGuardTethys\\Meygen2022_10a.xml";
+ try {
+ MarshalXML marshal = new MarshalXML();
+ marshal.createInstance(objClass);
+ marshal.marshal(nilusObject, tempFile.toString());
+ // tempFile = stripXMLHeader(tempFile);
+ importReturn = Importer.ImportFiles(params.getFullServerName(), collection.collectionName(),
+ new String[] { bodgeName }, "", "", false);
+
+
+ tempFile.deleteOnExit();
+ } catch(IllegalArgumentException e) {
+ throw new TethysException("IllegalArgumentException posting to Tethys: " + e.getMessage(), null);
+ } catch (IOException e) {
+ throw new TethysException("IOException posting to Tethys: " + e.getMessage(), null);
+ } catch (JAXBException e) {
+ throw new TethysException("JAXBException posting to Tethys: " + e.getMessage(), null);
+ }
+
+ /*
+ * The returned string consists of the file name, then an XML report.
+ * Quite hard to see much common structure in this, so just look for
+ * two words, and
+ */
+ boolean error = importReturn.contains("");
+ String name = tempFile.getName();
+ TethysReporter.getTethysReporter().addReport(new TethysReport(success, collection, name, name));
+// error = !success; might be a better options.
+ if (error) {
+ throw new TethysException("Error posting to Tethys", importReturn);
+ }
+ return success;
+ }
+
+ /**
+ * Update a document within Tethys. We're assuming that a
+ * document with the same name in the same collection already
+ * exists. If it doesn't / has a different name, then use
+ * the removedocument function
+ * @param nilusDocument
+ * @return
+ * @throws TethysException
+ */
+ public boolean updateDocument(Object nilusDocument) throws TethysException {
+ deleteDocument(nilusDocument);
+ return postToTethys(nilusDocument, null);
+ }
+
+ /**
+ * Delete a nilus document from the database. The only field which
+ * needs to be populated here is the Id. The code also uses the object
+ * class to identify the correct collection.
+ * @param nilusDocument
+ * @return
+ * @throws TethysException
+ */
+ public boolean deleteDocument(Object nilusDocument) throws TethysException {
+
+ Class objClass = nilusDocument.getClass();
+ Collection collection = Collection.fromClass(objClass);
+ String docId = getDocumentId(nilusDocument);
+ String result = null;
+ try {
+ result = jerseyClient.removeDocument(collection.collectionName(), docId );
+ /**
+ * Return from a sucessful delete is something like
+ *
+ deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId++, recordPeriod);
+
+ - ['ECoastNARW0']
+
+An error will throw an exception.
+ */
+ }
+ catch (Exception e) {
+// System.out.printf("Error deleting %s %s: %s\n", collection, docId, e.getMessage());
+ String msg = String.format("Error deleting %s:%s", collection, docId);
+ throw new TethysException(msg, e.getLocalizedMessage());
+ }
+ // forceFlush();
+ return true;
+ }
+
+ /**
+ * Delete a Deploymnet and any contained Detections document. Doesn't work !
+ * @param deploymentId
+ * @return
+ * @throws TethysException
+ */
+ public boolean deleteDeployment(String deploymentId) throws TethysException {
+ ArrayList detDocNames = tethysControl.getDbxmlQueries().getDetectionsDocuments(deploymentId);
+ JerseyClient jerseyClient = getJerseyClient();
+ Queries queries = null;
+ String result = null;
+ try {
+ result = jerseyClient.removeDocument("Deployments", deploymentId );
+ }
+ catch (Exception e) {
+ throw new TethysException("Error deleting deployment document " + deploymentId, e.getMessage());
+ }
+ return true;
+ }
+
+ /**
+ * Remove a document based on a collection name and a cdocument Id.
+ * @param collection collection name.
+ * @param documentName document name (not the internal Document Id)
+ * @return
+ * @throws TethysException
+ */
+ public boolean removeDocument(Collection collection, String documentName) throws TethysException {
+ return removeDocument(collection.collectionName(), documentName);
+ }
+
+ /**
+ * Remove a document based on a collection name and a document namw.
+ * @param collectionName collection name.
+ * @param documentName document name (not the internal Document Id)
+ * @return
+ * @throws TethysException
+ */
+ public boolean removeDocument(String collectionName, String documentName) throws TethysException {
+ try {
+ Object result = jerseyClient.removeDocument(collectionName, documentName );
+ /**
+ * Return from a sucessful delete is something like
+ *
+ deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId++, recordPeriod);
+
+ - ['ECoastNARW0']
+
+ An error will throw an exception.
+ */
+ }
+ catch (Exception e) {
+ String msg = String.format("Error deleting %s:%s", collectionName, documentName);
+ throw new TethysException(msg, e.getLocalizedMessage());
+ }
+ return true;
+ }
+
+ /**
+ * check the return string from importFiles and if it's an
+ * error, throw an exception. Otherwise do nothing.
+ * @param fileError
+ */
+ private void checkReturnString(String fileError) {
+ /**
+ * Example good string is
+ *
+C:\Users\dg50\AppData\Local\Temp\PAMGuardTethys\20080311_2DSimplex_0.xml: 7360 bytes
+
+
+ added
+
+
+ 20080311_2DSimplex_0
+
+
+
+
+Example error (file not existing)
+C:\Users\dg50\AppData\Local\Temp\PAMGuardTethys\20080311_2DSimplex_0.xmlnot: 0 bytes
+
+
+ C:\Users\dg50\AppData\Local\Temp\PAMGuardTethys\20080311_2DSimplex_0.xmlnot
+ does not exist
+
+
+
+
+
+ */
+
+
+ }
+
+ /**
+ * Seems we have to get rid of the line
+ * which is being put there by the marshaller ?
+ * @param tempFile
+ */
+ private File stripXMLHeader(File tempFile) {
+ // TODO Auto-generated method stub
+
+ File tempTemp = new File(tempFile.getAbsolutePath().replace(".temp.xml", ".xml"));
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(tempFile));
+ BufferedWriter writer = new BufferedWriter(new FileWriter(tempTemp));
+ String line = reader.readLine();
+ while (line != null) {
+ // see if the line has any unicode in it
+ int len = line.length();
+ byte[] bytes = line.getBytes();
+ if (len == bytes.length) {
+ System.out.println(line);
+ }
+
+ if (line.startsWith(" getCollectionDocumentList(Collection collection) {
+ if (collection == null) {
+ return null;
+ }
+
+ /**
+ * xQuery string based on examples in email from MR on 27/9/2023
+ */
+// String baseQuery = " {\r\n"
+ String baseQuery = " {\r\n"
+ + " for $doc in collection(\"COLLECTIONAME\")/DOCUMENTNAME\r\n"
+ + " return\r\n"
+ + " {\r\n"
+ + " base-uri($doc), \r\n"
+ + " $doc/Id\r\n"
+ + " }\r\n"
+ + " \r\n"
+ + "} \r\n"
+ + "";
+ String xQuery = baseQuery.replace("COLLECTIONAME", collection.collectionName());
+ xQuery = xQuery.replace("DOCUMENTNAME", collection.documentName());
+
+ Queries queries = dbXMLConnect.getTethysQueries();
+ String result = null;
+ try {
+ result = queries.QueryTethys(xQuery);
+ }
+ catch (Exception e) {
+// e.printStackTrace();
+ }
+ if (result == null) {
+ return null;
+ }
+// System.out.println(result);
+ ArrayList documentInfos = new ArrayList<>();
+
+ Document doc = convertStringToXMLDocument(result);
+ if (doc == null) {
+ return null;
+ }
+// PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter();
+// System.out.println(pamXMLWriter.getAsString(doc));
+ /**
+ * lots of elements along lines of
+ * dbxml:///Deployments/Meygen20229Meygen20229
+ */
+ NodeList returns = doc.getElementsByTagName("doc");
+ int n = returns.getLength();
+ String toStrip = "dbxml:///"+collection.collectionName()+"/";
+ for (int i = 0; i < n; i++) {
+ Node aNode = returns.item(i);
+ String nameStr = null;
+ String id = null;
+ NodeList kids = aNode.getChildNodes();
+ for (int k = 0; k < kids.getLength(); k++) {
+ Node kidNode = kids.item(k);
+ String name = kidNode.getNodeName();
+ String cont = kidNode.getTextContent();
+ switch(name) {
+ case "#text":
+ nameStr = cont;
+ nameStr = nameStr.replaceFirst(toStrip, "");
+ break;
+ case "Id":
+ id = kidNode.getTextContent();
+ break;
+ default:
+ System.out.printf("Uknonwn node in Collection list %s item %d, Node %d name %s content %s\n",
+ collection, i, k, name, cont);
+ }
+ }
+// if (i > 428) {
+// System.out.println("MARU cal doc");
+// }
+ // this is the doc name with a load of stuff in front,
+ // e.g. dbxml:///Deployments/1705_Array-2017-09-261705_Array-2017-09-26
+ if (nameStr == null) {
+ nameStr = aNode.getTextContent();
+ nameStr = nameStr.replaceFirst(toStrip, "");
+ }
+// if (aNode instanceof Element) {
+ // nameStr = getElementData((Element) aNode, "#text");
+ // }
+
+ if (id == null) {
+ if (aNode instanceof Element) {
+ id = getElementData((Element) aNode, "Id");
+ }
+ }
+
+ DocumentInfo docInfo = new DocumentInfo(collection, nameStr, id);
+ documentInfos.add(docInfo);
+// System.out.println(nameStr + " : " + id);
+ }
+ return documentInfos;
+
+
+
+ // if (collection.endsWith("s")) {
+ // collection = collection.substring(0, collection.length()-1);
+ // }
+// String baseQuery = "{\"return\":[\"COLLECTIONNAME/Id\"],\"select\":[],\"enclose\":1}";
+// baseQuery = baseQuery.replace("COLLECTIONNAME", collection);
+// String tagName = "Id";
+//
+// if (collection.equals("SpeciesAbbreviations")) {
+// baseQuery = "{\"return\":[\"Abbreviations/Name\"],\"select\":[],\"enclose\":1}";
+// tagName = "Name";
+// }
+//
+// DBQueryResult result;
+// try {
+// result = executeQuery(baseQuery);
+// } catch (TethysQueryException e) {
+// System.out.println("Error with query: " + baseQuery);
+// tethysControl.showException(e);
+// return null;
+// }
+//
+// if (result == null || result.queryResult == null) {
+// return null;
+// }
+// Document doc = convertStringToXMLDocument(result.queryResult);
+// if (doc == null) {
+// return null;
+// }
+// NodeList returns = doc.getElementsByTagName(tagName);
+// ArrayList docIds = new ArrayList<>();
+// int n = returns.getLength();
+// for (int i = 0; i < n; i++) {
+// Node aNode = returns.item(i);
+// String docId = aNode.getTextContent();
+// docIds.add(docId);
+// }
+//
+// return docIds;
+ }
+
+ /**
+ * Get a list of project names.
+ * @return
+ */
+ public ArrayList getProjectNames() {
+
+ String projectQuery = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}";
+
+ DBQueryResult result;
+ try {
+ result = executeQuery(projectQuery);
+ } catch (TethysQueryException e) {
+ tethysControl.showException(e);
+ return null;
+ }
+
+ if (result == null || result.queryResult == null) {
+ return null;
+ }
+
+ // System.out.println("Project query execution time millis = " + result.queryTimeMillis);
+
+ ArrayList projectNames = new ArrayList<>();
+ // iterate through the document and make a list of names, then make them unique.
+ /* looking for elements like this:
+ *
+ * check out the jaxb unmarshaller ...
+
+
+ LJ
+
+
+ */
+ Document doc = convertStringToXMLDocument(result.queryResult);
+ if (doc == null) {
+ return null;
+ }
+ NodeList returns = doc.getElementsByTagName("Project");
+ // System.out.println("N projects = " + returns.getLength());
+ int n = returns.getLength();
+ for (int i = 0; i < n; i++) {
+ Node aNode = returns.item(i);
+ String projName = aNode.getTextContent();
+ if (projName != null) {
+ if (!projectNames.contains(projName)) {
+ projectNames.add(projName);
+ }
+ }
+ // }
+ // if (aNode instanceof Element) {
+ // Node depEl = ((Element) aNode).getFirstChild();
+ // if (depEl == null) {
+ // continue;
+ // }
+ // if (depEl instanceof Element) {
+ // Element projEl = (Element) ((Element) depEl).getFirstChild();
+ // String projName = projEl.getTextContent();
+ // if (projName != null) {
+ // if (!projectNames.contains(projName)) {
+ // projectNames.add(projName);
+ // }
+ // }
+ // }
+ // }
+ }
+
+ Collections.sort(projectNames);
+
+ return projectNames;
+ }
+
+ /**
+ * Get project deployments that use a specific instrument id. More use than the call without this
+ * extra clause since it can handle overlapping deployments.
+ * @param projectName
+ * @param instrumentId
+ * @return
+ */
+ public ArrayList getProjectDeployments(String projectName, String instrumentId) {
+ if (projectName == null) {
+ return null;
+ }
+ String qBase = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"%s\"],\"optype\":\"binary\"},{\"op\":\"=\","
+ + "\"operands\":[\"Deployment/Instrument/InstrumentId\",\"%s\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String qStr = String.format(qBase, projectName, instrumentId);
+
+ return runProjectDeploymentsQuery(projectName, qStr);
+ }
+ /**
+ * Get some basic (not all) data for deployments associated with a project. Note that
+ * this may include deployments which are NOT part of the current dataset. That requires
+ * a search on Instrument as well.
+ * @param projectName
+ * @return
+ */
+ public ArrayList getProjectDeployments(String projectName) {
+ if (projectName == null) {
+ return null;
+ }
+ String qBase = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"%s\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String qStr = String.format(qBase, projectName);
+ return runProjectDeploymentsQuery(projectName, qStr);
+ }
+
+ /**
+ * Run the actual projects query from either of the two above functions.
+ * @param projectName
+ * @param qStr
+ * @return
+ */
+ private ArrayList runProjectDeploymentsQuery(String projectName, String qStr) {
+ DBQueryResult result = null;
+ try {
+ result = executeQuery(qStr);
+ } catch (TethysQueryException e1) {
+ tethysControl.showException(e1);
+ }
+ if (result == null) {
+ return null;
+ }
+ // System.out.println("Deployment query execution time millis = " + result.queryTimeMillis);
+
+ PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter();
+
+ Document doc = convertStringToXMLDocument(result.queryResult);
+ if (doc == null) {
+ return null;
+ }
+
+ // System.out.println(pamXMLWriter.getAsString(doc));
+
+ ArrayList deployments = new ArrayList<>();
+
+ NodeList returns = doc.getElementsByTagName("Deployment");
+ // if (returns.getLength() == 0) {
+ // // try REsult instead !
+ // returns = doc.getElementsByTagName("Result");
+ // }
+ // System.out.println("N projects = " + returns.getLength());
+ int n = returns.getLength();
+
+ // Queries queries = new Queries(null)
+ for (int i = 0; i < n; i++) {
+ Node aNode = returns.item(i);
+ if (aNode instanceof Element) {
+ Element returnedEl = (Element) aNode;
+
+ String Id = getElementData(returnedEl, "Id");
+ String project = getElementData(returnedEl, "Project");
+ String DeploymentId = getElementData(returnedEl, "DeploymentId");
+ String instrType = getElementData(returnedEl, "Instrument.Type");
+ String instrId = getElementData(returnedEl, "Instrument.InstrumentId");
+ String geometry = getElementData(returnedEl, "Instrument.GeometryType");
+ String audioStart = getElementData(returnedEl, "DeploymentDetails.AudioTimeStamp");
+ String audioEnd = getElementData(returnedEl, "RecoveryDetails.AudioTimeStamp");
+ String region = getElementData(returnedEl, "Region");
+ Deployment deployment = new Deployment();
+ try {
+ Helper.createRequiredElements(deployment);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ e.printStackTrace();
+ }
+ deployment.setId(Id);
+ deployment.setProject(projectName);
+ deployment.setDeploymentId(Integer.valueOf(DeploymentId));
+ XMLGregorianCalendar gcStart = TethysTimeFuncs.fromGregorianXML(audioStart);
+ XMLGregorianCalendar gcEnd = TethysTimeFuncs.fromGregorianXML(audioEnd);
+ // System.out.printf("Converted %s to %s\n", audioStart,
+ // PamCalendar.formatDBDateTime(TethysTimeFuncs.millisFromGregorianXML(gcStart), true));
+ deployment.getDeploymentDetails().setAudioTimeStamp(gcStart);
+ if (deployment.getRecoveryDetails() == null) {
+ deployment.setRecoveryDetails(new DeploymentRecoveryDetails());
+ }
+ deployment.getRecoveryDetails().setAudioTimeStamp(gcEnd);
+ if (instrType != null || instrId != null) {
+ Instrument instrument = new Instrument();
+ instrument.setType(instrType);
+ instrument.setInstrumentId(instrId);
+ instrument.setGeometryType(geometry);
+ deployment.setInstrument(instrument);
+ }
+ deployment.setRegion(region);
+ deployments.add(deployment);
+ }
+ }
+ return deployments;
+ }
+
+ /**
+ * Get a list of Detections documents which associate with a datablock and a deploymentId.
+ * @param dataBlock
+ * @param deploymentId can be null to get all docs for data block
+ * @return
+ */
+ public ArrayList getDetectionsDocuments(PamDataBlock dataBlock, String deploymentId) {
+ /**
+ * first query for Detections documents associated with this deployment and datablock.
+ * updated May 23
+ */
+ String queryNoDepl = "{\"species\":{\"query\":{\"op\":\"lib:completename2tsn\",\"optype\":\"function\",\"operands\":[\"%s\"]},\"return\":{\"op\":\"lib:tsn2completename\",\"optype\":\"function\",\"operands\":[\"%s\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String queryWithDepl = "{\"species\":{\"query\":{\"op\":\"lib:completename2tsn\",\"optype\":\"function\",\"operands\":[\"%s\"]},\"return\":{\"op\":\"lib:tsn2completename\",\"optype\":\"function\",\"operands\":[\"%s\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"TheDeploymentId\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String query;
+ if (deploymentId == null) {
+ query = queryNoDepl;
+ }
+ else {
+ query = queryWithDepl.replace("TheDeploymentId", deploymentId);
+ }
+ query = query.replace("LongDataName", dataBlock.getLongDataName());
+ DBQueryResult queryResult = null;
+ try {
+ queryResult = executeQuery(query);
+ } catch (TethysQueryException e1) {
+ tethysControl.showException(e1);
+ return null;
+ }
+ if (queryResult ==null) {
+ return null;
+ }
+ Document doc;
+ try {
+ doc = queryResult.getDocument();
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ if (doc == null) {
+ return null;
+ }
+ ArrayList detectionsNames = new ArrayList();
+ int count = 0;
+ NodeList returns = doc.getElementsByTagName("Detections");
+ // if (returns.getLength() == 0) {
+ // returns = doc.getElementsByTagName("Result");
+ // }
+ for (int i = 0; i < returns.getLength(); i++) {
+ Node aNode = returns.item(i);
+ String docName = aNode.getTextContent();
+ detectionsNames.add(docName);
+ }
+ return detectionsNames;
+ }
+
+
+ /**
+ * Get the names of all detection documents for a given deployment for all data streams.
+ * @param deploymentId
+ * @return
+ */
+ public ArrayList getDetectionsDocuments(String deploymentId) {
+ String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"SomeDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String queryStr = queryBase.replace("SomeDeploymentId", deploymentId);
+ DBQueryResult queryResult = null;
+ try {
+ queryResult = executeQuery(queryStr);
+ } catch (TethysQueryException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ if (queryResult == null || queryResult.queryException != null) {
+ return null;
+ }
+
+ // PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter();
+
+ Document doc = convertStringToXMLDocument(queryResult.queryResult);
+ if (doc == null) {
+ return null;
+ }
+
+ ArrayList detectionDocs = new ArrayList<>();
+
+ NodeList returns = doc.getElementsByTagName("Record");
+ if (returns.getLength() == 0) {
+ returns = doc.getElementsByTagName("Record");
+ }
+ for (int i = 0; i < returns.getLength(); i++) {
+ Node aNode = returns.item(i);
+ detectionDocs.add(aNode.getTextContent());
+ }
+ return detectionDocs;
+ }
+
+ public int countData(PamDataBlock dataBlock, String deploymentId) {
+ // /**
+ // * first query for Detections documents associated with this deployment and datablock.
+ // */
+ // String queryNoDepl = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ // String queryWithDepl = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"TheDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ // String query;
+ // if (deploymentId == null) {
+ // query = queryNoDepl;
+ // }
+ // else {
+ // query = queryWithDepl.replace("TheDeploymentId", deploymentId);
+ // }
+ // query = query.replace("LongDataName", dataBlock.getLongDataName());
+ // DBQueryResult queryResult = executeQuery(query);
+ // if (queryResult ==null) {
+ // return 0;
+ // }
+ // Document doc;
+ // try {
+ // doc = queryResult.getDocument();
+ // } catch (ParserConfigurationException | SAXException | IOException e) {
+ // e.printStackTrace();
+ // return 0;
+ // }
+ //
+ // int count = 0;
+ // NodeList returns = doc.getElementsByTagName("Return");
+ ArrayList documentNames = getDetectionsDocuments(dataBlock, deploymentId);
+ if (documentNames == null) {
+ return 0;
+ }
+ int count = 0;
+ for (String docName : documentNames) {
+ // System.out.println(aNode.getTextContent());
+ int count2 = countDetections2(docName);
+ count += count2; //countDetecionsData(docName);
+
+ }
+ return count;
+ }
+
+ public String getDocument(String collection, String documentId) {
+ // String queryBase = "return:(collection(\"replaceCollectionName\")/Detections[Id=\"ReplaceDocumentId\"])";
+ // queryBase = queryBase.replace("replaceCollectionName", collection);
+ // queryBase = queryBase.replace("ReplaceDocumentId", documentId);
+ //
+ // String result = null;
+ // try {
+ // Queries queries = dbXMLConnect.getTethysQueries();
+ // result = queries.QueryTethys(queryBase);
+ //// System.out.println(result);
+ // }
+ // catch (Exception e) {
+ // System.out.println("Error executing " + queryBase);
+ //// e.printStackTrace();
+ // return null;
+ // }
+ // return result;
+
+ Queries queries = dbXMLConnect.getTethysQueries();
+ String result = null;
+ try {
+ result = queries.getDocument(collection, documentId);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return result;
+
+ // String queryBase = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}";
+ }
+
+ /**
+ * Find out if a document exists ?
+ * @param collection
+ * @param documentId
+ * @return
+ */
+ public boolean documentExists(String collection, String documentId) {
+ Queries queries = dbXMLConnect.getTethysQueries();
+ String result = null;
+ try {
+ result = queries.getDocument(collection, documentId);
+ } catch (Exception e) {
+ return false;
+ }
+ if (result == null || result.length() == 0) {
+ return false;
+ }
+
+ return result.contains(documentId);
+ }
+
+ /**
+ * Count on effort detections in a Detections document
+ * @param docName
+ * @return
+ */
+ public int countDetections2(String docName) {
+ TethysExportParams params = tethysControl.getTethysExportParams();
+ String queryBase = "count(collection(\"Detections\")/Detections[Id=\"ReplaceDocumentId\"]/OnEffort/Detection)";
+ String query = queryBase.replace("ReplaceDocumentId", docName);
+
+ String result = null;
+ try {
+ Queries queries = dbXMLConnect.getTethysQueries();
+ result = queries.QueryTethys(query);
+ // System.out.println(result);
+ }
+ catch (Exception e) {
+ System.out.println("Error executing " + query);
+ // e.printStackTrace();
+ return -1;
+ }
+ int count = 0;
+ try {
+ count = Integer.valueOf(result);
+ }
+ catch (NumberFormatException e) {
+ System.out.println("Unable to interpret count data " + result);
+ return 0;
+ }
+ return count;
+ }
+
+ // /**
+ // * Get a count of the detections in a detections document.
+ // * Only looking in onEffort so far.
+ // * @param deploymentId
+ // * @param detectionDocId
+ // * @param dataBlock
+ // * @return
+ // */
+ // public int getDetectionsDetectionCount(String deploymentId, String detectionDocId, PamDataBlock dataBlock) {
+ // String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/OnEffort/Detection/Start\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Id\",\"SomeDetectionsId\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"SomeDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ // String queryStr = queryBase.replace("SomeDetectionsId", detectionDocId);
+ // queryStr = queryStr.replace("SomeDeploymentId", deploymentId);
+ // DBQueryResult queryResult = executeQuery(queryStr);
+ // if (queryResult == null || queryResult.queryException != null) {
+ // return 0;
+ // }
+ //// System.out.println("Detections query time ms = " + queryResult.queryTimeMillis);
+ //
+ // PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter();
+ //
+ // Document doc = convertStringToXMLDocument(queryResult.queryResult);
+ // if (doc == null) {
+ // return 0;
+ // }
+ //
+ //// System.out.println(pamXMLWriter.getAsString(doc));
+ //
+ //// ArrayList detectionDocs = new ArrayList<>();
+ //
+ // NodeList returns = doc.getElementsByTagName("Start");
+ // int n = returns.getLength();
+ // return n;
+ // }
+
+ // /**
+ // * This is the quickest way of counting data in a project, but it will load the start
+ // * times for every detection in a project at once, so might use a lot of memory. Also
+ // * it wll probably get data for all deployments in a project, which may not be what we want.
+ // * @param projectName
+ // * @param dataPrefixes
+ // * @return
+ // */
+ // public int[] countDataForProject(String projectName, String[] dataPrefixes) {
+ // int[] n = new int[dataPrefixes.length];
+ // ArrayList matchedDeployments = tethysControl.getDeploymentHandler().getMatchedDeployments();
+ //// ArrayList deployments = getProjectDeployments(projectName);
+ // if (matchedDeployments == null) {
+ // return null;
+ // }
+ // for (PDeployment aDeployment : matchedDeployments) {
+ //// ArrayList detectionsIds = getDetectionsDocsIds(aDeployment.getId());
+ //// for (String detId : detectionsIds) {
+ //// n += getDetectionsDetectionCount(aDeployment.getId(), detId, dataBlock);
+ //// }
+ // int[] newN = countDataForDeployment(projectName, aDeployment.deployment.getId(), dataPrefixes);
+ // for (int i = 0; i < n.length; i++) {
+ // n[i] += newN[i];
+ // }
+ // }
+ // return n;
+ // }
+
+ /**
+ * Count data within a deployment document which is associated with a set of datablocks
+ * Since the detections all come back in one query, it's easier to count all datablocks at once so
+ * that it can all happen off a single query.
+ * @param id
+ * @param dataBlockPrefixes
+ * @return
+ */
+ private int[] countDataForDeployment(String projectId, String deploymentId, String[] dataPrefixes) {
+ String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\",\"Detections/OnEffort/Detection/Start\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"ReplaceDeploymentIdString\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String queryString = queryBase.replace("ReplaceDeploymentIdString", deploymentId);
+ DBQueryResult result;
+ try {
+ result = executeQuery(queryString);
+ } catch (TethysQueryException e) {
+ tethysControl.showException(e);
+ return null;
+ }
+ if (result == null || result.queryResult == null) {
+ return null;
+ }
+ PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter();
+
+ Document doc = convertStringToXMLDocument(result.queryResult);
+ if (doc == null) {
+ return null;
+ }
+
+ // System.out.println(pamXMLWriter.getAsString(doc));
+
+ NodeList detsDocs = doc.getElementsByTagName("Detections");
+ int[] blockCounts = new int[dataPrefixes.length];
+
+ // String detDocPrefix = projectId + "_" + dataBlock.getDataName();
+
+ // int totalCalls = 0;
+ int detCount = 0;
+ int dataIndex;
+ for (int i = 0; i < detsDocs.getLength(); i++) {
+ Node detNode = detsDocs.item(i);
+
+ NodeList childNodes = detNode.getChildNodes();
+ detCount = childNodes.getLength()-1;
+ dataIndex = -1;
+ for (int n = 0; n < childNodes.getLength(); n++) {
+ Node aNode = childNodes.item(n);
+ if (aNode instanceof Element) {
+ Element el = (Element) aNode;
+ String nodeName = el.getNodeName();
+ if (nodeName.equals("Id")) {
+ String id = el.getTextContent();
+ for (int j = 0; j < dataPrefixes.length; j++) {
+ if (id != null && id.startsWith(dataPrefixes[j])) {
+ dataIndex = j;
+ }
+ }
+ // if (id != null && id.startsWith(detDocPrefix) == false) {
+ // detCount = 0;
+ // break;
+ // }
+ }
+ }
+ }
+ if (dataIndex >= 0) {
+ blockCounts[dataIndex] += detCount;
+ }
+ // System.out.printf("%d Added %d for new total %d\n",i, detCount, totalCalls);
+ }
+
+ return blockCounts;
+ }
+
+ public String getElementData(Element root, String elName) {
+ String[] tree = elName.split("\\.");
+ for (String element : tree) {
+ NodeList nodeList = root.getElementsByTagName(element);
+ // should only be one node for what we're unpacking.
+ if (nodeList == null || nodeList.getLength() == 0) {
+ return null;
+ }
+ int count = nodeList.getLength();
+ for (int i = 0; i < count; i++) {
+ Node firstNode = nodeList.item(i);
+ if (firstNode instanceof Element) {
+ root = (Element) firstNode;
+ break;
+ }
+ }
+ }
+ return root.getTextContent();
+ }
+
+
+ public String getElementAttribute(Element root, String elName, String attribute) {
+ String[] tree = elName.split("\\.");
+ for (String element : tree) {
+ NodeList nodeList = root.getElementsByTagName(element);
+ // should only be one node for what we're unpacking.
+ if (nodeList == null || nodeList.getLength() == 0) {
+ return null;
+ }
+ int count = nodeList.getLength();
+ for (int i = 0; i < count; i++) {
+ Node firstNode = nodeList.item(i);
+ if (firstNode instanceof Element) {
+ root = (Element) firstNode;
+ break;
+ }
+ }
+ }
+ return root.getAttribute(attribute);
+ }
+
+ public Document convertStringToXMLDocument(String xmlString) {
+ //Parser that produces DOM object trees from XML content
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+ //API to obtain DOM Document instance
+ DocumentBuilder builder = null;
+ try {
+ //Create DocumentBuilder with default configuration
+ builder = factory.newDocumentBuilder();
+
+ //Parse the content to Document object
+ Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
+ return doc;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Get the basic information about a Detections document. This is basically everything apart from
+ * the actual detections themselves.
+ * @param aDoc
+ * @return
+ */
+ public Detections getDetectionsDocInfo(String detectionsDocName) {
+// String oldqueryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\",\"Detections/Description\",\"Detections/DataSource\",\"Detections/Algorithm\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Id\",\"DetectionsDocName\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ // updated May 23
+ String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:completename2tsn\",\"optype\":\"function\",\"operands\":[\"%s\"]},\"return\":{\"op\":\"lib:tsn2completename\",\"optype\":\"function\",\"operands\":[\"%s\"]}},\"return\":[\"Detections/Id\",\"Detections/Description\",\"Detections/DataSource\",\"Detections/Algorithm\",\"Detections/QualityAssurance\",\"Detections/UserId\",\"Detections/MetadataInfo\",\"Detections/Effort\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Id\",\"DetectionsDocName\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String query = queryBase.replace("DetectionsDocName", detectionsDocName);
+ DBQueryResult queryResult;
+ try {
+ queryResult = executeQuery(query);
+ } catch (TethysQueryException e) {
+ tethysControl.showException(e);
+ return null;
+ }
+ Document doc;
+ try {
+ doc = queryResult.getDocument();
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return null;
+ }
+ // System.out.println(queryResult.queryResult);
+
+ Detections detections = new Detections();
+ try {
+ Helper.createRequiredElements(detections);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ e.printStackTrace();
+ }
+
+ NodeList returns = doc.getElementsByTagName("Result");
+ // System.out.println("N projects = " + returns.getLength());
+ int n = returns.getLength();
+ if (n == 0) {
+ return null;
+ }
+ Element result = (Element) returns.item(0);
+
+ DescriptionType description = detections.getDescription();
+ if (description == null) {
+ description = new DescriptionType();
+ detections.setDescription(description);
+ }
+ detections.setId(getElementData(result, "Id"));
+ description.setAbstract(getElementData(result, "Description.Abstract"));
+ description.setMethod(getElementData(result, "Description.Method"));
+ description.setObjectives(getElementData(result, "Description.Objectives"));
+
+ String deployment = getElementData(result, "DataSource.DeploymentId");
+ if (deployment != null) {
+ DataSourceType dataSource = detections.getDataSource();
+ if (dataSource == null) {
+ dataSource = new DataSourceType();
+ detections.setDataSource(dataSource);
+ }
+ dataSource.setDeploymentId(deployment);
+ }
+
+ // get the effort start an end
+ String effStart = getElementData(result, "Effort.Start");
+ String effEnd = getElementData(result, "Effort.End");
+ detections.getEffort().setStart(TethysTimeFuncs.fromGregorianXML(effStart));
+ detections.getEffort().setEnd(TethysTimeFuncs.fromGregorianXML(effEnd));
+ // try to find the granularity.
+ String granularityString = getElementData(result, "Effort.Kind.Granularity");
+ GranularityEnumType granularity = null;
+ if (granularityString != null) {
+ granularity = GranularityEnumType.fromValue(granularityString);
+ List kinds = detections.getEffort().getKind();
+ DetectionEffortKind kind = new DetectionEffortKind();
+ GranularityType granularityType = new GranularityType();
+ granularityType.setValue(granularity);
+ kind.setGranularity(granularityType);
+ // try to find the rest of the granularity information.
+ String binSize_m = getElementAttribute(result, "Effort.Kind.Granularity", "BinSize_m");
+ String encounterGap_m = getElementAttribute(result, "Effort.Kind.Granularity", "EncounterGap_m");
+ String firstBinStart = getElementAttribute(result, "Effort.Kind.Granularity", "FirstBinStart");
+ try {
+ granularityType.setBinSizeMin(Double.valueOf(binSize_m));
+ }
+ catch (NumberFormatException e) {
+ }
+ try {
+ granularityType.setEncounterGapMin(Double.valueOf(encounterGap_m));
+ }
+ catch (NumberFormatException e) {
+ }
+
+ kinds.add(kind);
+ }
+ // String
+
+
+
+ // TODO Auto-generated method stub
+ return detections;
+ }
+
+}
diff --git a/src/tethys/dbxml/DMXMLQueryTest.java b/src/tethys/dbxml/DMXMLQueryTest.java
new file mode 100644
index 00000000..e16e202a
--- /dev/null
+++ b/src/tethys/dbxml/DMXMLQueryTest.java
@@ -0,0 +1,79 @@
+package tethys.dbxml;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+
+import PamController.settings.output.xml.PamguardXMLWriter;
+import dbxml.JerseyClient;
+import tethys.output.TethysExportParams;
+
+public class DMXMLQueryTest {
+
+ public static void main(String[] args) {
+ new DMXMLQueryTest().runTest();
+ }
+
+ private void runTest() {
+ TethysExportParams params = new TethysExportParams();
+
+ JerseyClient jerseyClient = new JerseyClient(params.getFullServerName());
+
+// String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/DeploymentId\",\"Deployment/Site\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\"],\"select\":[],\"enclose\":1}";
+// String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/Region\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/DeploymentId\",\"2\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ //String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/Region\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/DeploymentId\",\"2\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}";
+// String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/Region\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\",\"Deployment/DeploymentId\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/DeploymentId\",\"2\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}";
+ String testJson = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}";
+ // web browse to http://localhost:9779/Client
+
+ String testResult = jerseyClient.queryJSON(testJson);
+
+ Document doc = convertStringToXMLDocument(testResult);
+
+ PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter();
+ String formettedXML = pamXMLWriter.getAsString(doc, true);
+
+ System.out.println(testResult);
+ System.out.println(formettedXML);
+// try {
+// Transformer serializer = SAXTransformerFactory.newInstance()
+// .newTransformer();
+// Source source = new StreamSource(testResult);
+// ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+// StreamResult res = new StreamResult(bytes);
+// serializer.transform(source, res);
+// System.out.println(bytes.toString());
+// } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
+// e.printStackTrace();
+// }
+// // System.err.println(testResult);
+// catch (TransformerException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+
+ }
+
+ private Document convertStringToXMLDocument(String xmlString) {
+ //Parser that produces DOM object trees from XML content
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+ //API to obtain DOM Document instance
+ DocumentBuilder builder = null;
+ try {
+ //Create DocumentBuilder with default configuration
+ builder = factory.newDocumentBuilder();
+
+ //Parse the content to Document object
+ Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
+ return doc;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/tethys/dbxml/ServerStatus.java b/src/tethys/dbxml/ServerStatus.java
new file mode 100644
index 00000000..25c9ebbf
--- /dev/null
+++ b/src/tethys/dbxml/ServerStatus.java
@@ -0,0 +1,35 @@
+package tethys.dbxml;
+
+public class ServerStatus {
+
+ public boolean ok;
+
+ public Exception error;
+
+ public ServerStatus(boolean ok, Exception error) {
+ super();
+ this.ok = ok;
+ this.error = error;
+ }
+
+ public String getFormatted() {
+ if (ok) {
+ return "Server OK";
+ }
+ if (error == null) {
+ return "Unknown error";
+ }
+ String msg = error.getLocalizedMessage();
+ if (msg.startsWith("Exception")) {
+ msg.substring(9);
+ }
+ return msg;
+ }
+
+ @Override
+ public String toString() {
+ return getFormatted();
+ }
+
+
+}
diff --git a/src/tethys/dbxml/TethysException.java b/src/tethys/dbxml/TethysException.java
new file mode 100644
index 00000000..034a1970
--- /dev/null
+++ b/src/tethys/dbxml/TethysException.java
@@ -0,0 +1,18 @@
+package tethys.dbxml;
+
+public class TethysException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ private String xmlError;
+
+ public TethysException(String message, String xmlError) {
+ super(message);
+ this.xmlError = xmlError;
+ }
+
+ public String getXmlError() {
+ return xmlError;
+ }
+
+}
diff --git a/src/tethys/dbxml/TethysQueryException.java b/src/tethys/dbxml/TethysQueryException.java
new file mode 100644
index 00000000..7f46d7bc
--- /dev/null
+++ b/src/tethys/dbxml/TethysQueryException.java
@@ -0,0 +1,19 @@
+package tethys.dbxml;
+
+public class TethysQueryException extends TethysException {
+
+
+ private static final long serialVersionUID = 1L;
+
+ private String queryString;
+
+ public TethysQueryException(String message, String queryString) {
+ super(message, null);
+ this.queryString = queryString;
+ }
+
+ public String getQueryString() {
+ return queryString;
+ }
+
+}
diff --git a/src/tethys/deployment/DeploymentExportOpts.java b/src/tethys/deployment/DeploymentExportOpts.java
new file mode 100644
index 00000000..18fa461f
--- /dev/null
+++ b/src/tethys/deployment/DeploymentExportOpts.java
@@ -0,0 +1,43 @@
+package tethys.deployment;
+
+import java.io.Serializable;
+
+/**
+ * options for Deployment export collected by the export Wizard.
+ * @author dg50
+ *
+ */
+public class DeploymentExportOpts implements Serializable, Cloneable {
+
+ public static final long serialVersionUID = 1L;
+
+ public boolean separateDeployments;
+
+ /**
+ * Minimum number of seconds between GPS points in a track.
+ */
+ public double trackPointInterval;
+
+ /**
+ * Max gap before recording periods are separated, potentially into
+ * separate Deployment documents
+ */
+ public int maxRecordingGapSeconds = 60;
+
+ /**
+ * A recording section after joining with max gap parameter is too short
+ * to be worth keeping.
+ */
+ public int minRecordingLengthSeconds = 10;
+
+ @Override
+ protected DeploymentExportOpts clone() {
+ try {
+ return (DeploymentExportOpts) super.clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+}
diff --git a/src/tethys/deployment/DeploymentHandler.java b/src/tethys/deployment/DeploymentHandler.java
new file mode 100644
index 00000000..0c435fc0
--- /dev/null
+++ b/src/tethys/deployment/DeploymentHandler.java
@@ -0,0 +1,1310 @@
+package tethys.deployment;
+
+import java.awt.Window;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.apache.commons.beanutils.converters.BigIntegerConverter;
+
+import Acquisition.AcquisitionControl;
+import Acquisition.AcquisitionParameters;
+import Acquisition.DaqStatusDataUnit;
+import Acquisition.DaqSystem;
+import Acquisition.FolderInputSystem;
+import Array.ArrayManager;
+import Array.Hydrophone;
+import Array.HydrophoneLocator;
+import Array.PamArray;
+import Array.Streamer;
+import Array.ThreadingHydrophoneLocator;
+import GPS.GPSControl;
+import GPS.GPSDataBlock;
+import GPS.GpsData;
+import GPS.GpsDataUnit;
+import PamController.PamSensor;
+import PamController.PamSettingManager;
+import PamController.PamSettings;
+import PamController.PamControlledUnit;
+import PamController.PamControlledUnitSettings;
+import PamController.PamController;
+import PamUtils.PamUtils;
+import PamguardMVC.PamDataBlock;
+import PamguardMVC.PamRawDataBlock;
+import binaryFileStorage.BinaryStore;
+import dataMap.OfflineDataMap;
+import dataMap.OfflineDataMapPoint;
+import generalDatabase.DBControlUnit;
+import metadata.MetaDataContol;
+import metadata.PamguardMetaData;
+import nilus.AcousticDataQAType;
+import nilus.AcousticDataQAType.Quality;
+import nilus.AcousticDataQAType.Quality.FrequencyRange;
+import nilus.Audio;
+import nilus.ChannelInfo;
+import nilus.ChannelInfo.DutyCycle;
+import nilus.ChannelInfo.DutyCycle.Regimen.RecordingDurationS;
+import nilus.ChannelInfo.DutyCycle.Regimen.RecordingIntervalS;
+import nilus.ChannelInfo.Sampling;
+import nilus.ChannelInfo.Sampling.Regimen;
+import nilus.Deployment;
+import nilus.Deployment.Data;
+import nilus.Deployment.Data.Tracks;
+import nilus.Deployment.Data.Tracks.Track;
+import nilus.Deployment.Data.Tracks.Track.Point;
+import nilus.Deployment.Data.Tracks.Track.Point.BearingDegN;
+import nilus.Deployment.Instrument;
+import nilus.Deployment.SamplingDetails;
+import nilus.Deployment.Sensors;
+import nilus.DeploymentRecoveryDetails;
+import nilus.DescriptionType;
+import nilus.GeometryTypeM;
+import nilus.Helper;
+import nilus.MetadataInfo;
+import nilus.UnknownSensor;
+import pamMaths.PamVector;
+import pamMaths.STD;
+import tethys.Collection;
+import tethys.TethysControl;
+import tethys.TethysLocationFuncs;
+import tethys.TethysState;
+import tethys.TethysStateObserver;
+import tethys.TethysTimeFuncs;
+import tethys.calibration.CalibrationHandler;
+import tethys.TethysState.StateType;
+import tethys.dbxml.DBXMLConnect;
+import tethys.dbxml.TethysException;
+import tethys.deployment.swing.DeploymentWizard;
+import tethys.deployment.swing.RecordingGapDialog;
+import tethys.niluswraps.PDeployment;
+import tethys.output.TethysExportParams;
+import tethys.pamdata.AutoTethysProvider;
+import tethys.reporter.TethysReporter;
+import tethys.swing.DeploymentTableObserver;
+
+/**
+ * Functions to gather data for the deployment document from all around PAMGuard.
+ * There should be just one of these, available from TethysControl and it will try
+ * to sensible handle when and how it updates it's list of PAMGuard and Tethys information
+ * Any part of PAMGuard wanting information on Deployments should come here.
+ * @author dg50
+ *
+ */
+public class DeploymentHandler implements TethysStateObserver, DeploymentTableObserver {
+
+ private TethysControl tethysControl;
+
+ /**
+ * @return the tethysControl
+ */
+ public TethysControl getTethysControl() {
+ return tethysControl;
+ }
+
+ private EffortFunctions effortFunctions;
+
+ private DeploymentOverview deploymentOverview;
+
+ private ArrayList projectDeployments;
+
+ private Helper nilusHelper;
+
+ private DeploymentExportOpts deploymentExportOptions = new DeploymentExportOpts();
+
+ public DeploymentHandler(TethysControl tethysControl) {
+ super();
+
+ this.tethysControl = tethysControl;
+
+ this.effortFunctions = new EffortFunctions(tethysControl);
+
+ tethysControl.addStateObserver(this);
+ try {
+ nilusHelper = new Helper();
+ } catch (JAXBException e) {
+ e.printStackTrace();
+ }
+
+ PamSettingManager.getInstance().registerSettings(new SettingsHandler());
+ }
+
+ /**
+ * Gather up all track information both from the GPS module (if it exists) and
+ * the type of hydrophone array (or many!)
+ * @return
+ */
+ public TrackInformation getTrackInformation() {
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ int nStreamers = array.getStreamerCount();
+ HydrophoneLocator locator = null;
+ for (int i = 0; i < nStreamers; i++) {
+ Streamer aStreamer = array.getStreamer(i);
+ locator = aStreamer.getHydrophoneLocator();
+// locator.getLocatorSettings().
+ }
+ // try to find a GPS datablock and see what's in it's datamap.
+ OfflineDataMap gpsDataMap = null;
+ GPSControl gpsControl = (GPSControl) PamController.getInstance().findControlledUnit(GPSControl.gpsUnitType);
+ if (gpsControl != null) {
+ GPSDataBlock gpsDataBlock = gpsControl.getGpsDataBlock();
+ gpsDataMap = gpsDataBlock.getPrimaryDataMap();
+ }
+ TrackInformation trackInformation = new TrackInformation(gpsDataMap, locator);
+ return trackInformation;
+ }
+
+ @Override
+ public void updateState(TethysState tethysState) {
+ switch (tethysState.stateType) {
+ case NEWPROJECTSELECTION:
+ updateProjectDeployments();
+ break;
+ case EXPORTRDATA:
+ case DELETEDATA:
+ updateProjectDeployments();
+ break;
+ case UPDATESERVER:
+ updateProjectDeployments();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Update the list of Tethys deployments
+ * @return true if OK
+ */
+ public boolean updateProjectDeployments() {
+ Deployment projData = tethysControl.getGlobalDeplopymentData();
+ ArrayList tethysDocs = tethysControl.getDbxmlQueries().getProjectDeployments(projData.getProject(), getInstrumentId());
+ if (tethysDocs == null) {
+ return false;
+ }
+ projectDeployments = new ArrayList<>();
+ for (Deployment deployment : tethysDocs) {
+ projectDeployments.add(new PDeployment(deployment));
+ }
+ matchPamguard2Tethys(deploymentOverview, projectDeployments);
+ tethysControl.sendStateUpdate(new TethysState(TethysState.StateType.NEWPAMGUARDSELECTION));
+ return true;
+ }
+
+ /**
+ * Get a list of Tethys deployment docs. Note that this
+ * doesn't update the list, but uses the one currently in memory
+ * so call updateTethysDeployments() first if necessary.
+ * @return list of (wrapped) nilus Deployment objects.
+ */
+ public ArrayList getProjectDeployments() {
+ if (projectDeployments == null) {
+ updateProjectDeployments();
+ }
+ return projectDeployments;
+ }
+
+// /**
+// * Get an overview of all the deployments.
+// * @return
+// */
+// public DeploymentOverview createPamguardOverview() {
+// // first find an acquisition module.
+// PamControlledUnit aModule = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
+// if (!(aModule instanceof AcquisitionControl)) {
+// // will return if it's null. Impossible for it to be the wrong type.
+// // but it's good practice to check anyway before casting.
+// return null;
+// }
+// // cast it to the right type.
+// AcquisitionControl daqControl = (AcquisitionControl) aModule;
+// AcquisitionParameters daqParams = daqControl.getAcquisitionParameters();
+// /**
+// * The daqParams class has most of what we need about the set up in terms of sample rate,
+// * number of channels, instrument type, ADC input range (part of calibration), etc.
+// * It also has a hydrophone list, which maps the input channel numbers to the hydrophon numbers.
+// * Realistically, this list is always 0,1,2,etc or it goes horribly wrong !
+// */
+// // so write functions here to get information from the daqParams.
+//// System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(),
+//// daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak);
+// /**
+// * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map
+// * but the datamap is a simple count of what's in the databasase which is not quite what we want.
+// * we're going to have to query the database to get more detailed informatoin I think.
+// * I'll do that here for now, but we may want to move this when we better organise the code.
+// * It also seems that there are 'bad' dates in the database when it starts new files, which are the date
+// * data were analysed at. So we really need to check the start and stop records only.
+// */
+// PamDataBlock daqInfoDataBlock = daqControl.getAcquisitionProcess().getDaqStatusDataBlock();
+// // just load everything. Probably OK for the acqusition, but will bring down
+// daqInfoDataBlock.loadViewerData(0, Long.MAX_VALUE, null);
+// ArrayList allStatusData = daqInfoDataBlock.getDataCopy();
+// /**
+// * Due to seird file overlaps we need to resort this by id if we can.
+// *
+// */
+// Collections.sort(allStatusData, new Comparator() {
+//
+// @Override
+// public int compare(DaqStatusDataUnit o1, DaqStatusDataUnit o2) {
+// if (o1.getDatabaseIndex() == 0) {
+// return (int) (o1.getTimeMilliseconds()-o2.getTimeMilliseconds());
+// }
+// return o1.getDatabaseIndex()-o2.getDatabaseIndex();
+// }
+// });
+//
+// ArrayList tempPeriods = null;
+//
+// if (allStatusData == null || allStatusData.size() == 0) {
+// System.out.println("Data appear to have no logged recording periods. Try to extract from raw audio ...");
+// tempPeriods = extractTimesFromFiles(daqControl);
+// }
+// else {
+// tempPeriods = extractTimesFromStatus(allStatusData);
+// }
+// if (tempPeriods == null || tempPeriods.size() == 0) {
+// System.out.println("Data appear to have no logged recording periods available either from the database or the raw recordings.");
+// tempPeriods = extractTimesFromOutputMaps();
+// }
+// if (tempPeriods == null || tempPeriods.size() == 0) {
+// System.out.println("Data appear to have no logged recording periods available either from the database or the raw recordings.");
+// return null;
+// }
+//
+// int nPeriods = tempPeriods.size();
+//// int i = 0;
+//// for (RecordingPeriod aP : tempPeriods) {
+//// System.out.printf("Pre merge %d : %s to %s\n", i++, PamCalendar.formatDBDateTime(aP.getRecordStart()),
+//// PamCalendar.formatDBDateTime(aP.getRecordStop()));
+//// }
+// // now go through those and merge into longer periods where there is no gap between files.
+// ListIterator iterator = tempPeriods.listIterator();
+// RecordingPeriod prevPeriod = null;
+// while (iterator.hasNext()) {
+// RecordingPeriod nextPeriod = iterator.next();
+// long nextDur = nextPeriod.getRecordStop()-nextPeriod.getRecordStart();
+// if (nextDur == 0) {
+// continue;
+// }
+// if (prevPeriod != null) {
+// long gap = nextPeriod.getRecordStart() - prevPeriod.getRecordStop();
+// long prevDur = prevPeriod.getRecordStop()-prevPeriod.getRecordStart();
+// if (gap < exportOptions.maxGapSeconds*1000) {
+// // ignoring up to 3s gap or a sample error < 2%.Dunno if this is sensible or not.
+// prevPeriod.setRecordStop(nextPeriod.getRecordStop());
+// iterator.remove();
+// nextPeriod = prevPeriod;
+// }
+// }
+// prevPeriod = nextPeriod;
+// }
+// // now remove ones which are too short even after merging.
+// iterator = tempPeriods.listIterator();
+// while (iterator.hasNext()) {
+// RecordingPeriod nextPeriod = iterator.next();
+// long duration = nextPeriod.getDuration();
+// if (duration < exportOptions.minLengthSeconds*1000L) {
+// iterator.remove();
+// }
+// }
+//// i = 0;
+//// for (RecordingPeriod aP : tempPeriods) {
+//// System.out.printf("Post merge %d : %s to %s\n", i++, PamCalendar.formatDBDateTime(aP.getRecordStart()),
+//// PamCalendar.formatDBDateTime(aP.getRecordStop()));
+//// }
+//// System.out.printf("Data have %d distinct files, but only %d distinct recording periods\n", nPeriods, tempPeriods.size());
+// DutyCycleInfo dutyCycleinfo = assessDutyCycle(tempPeriods);
+// // if it's duty cycles, then we only want a single entry.
+// ArrayList deploymentPeriods;
+// if (dutyCycleinfo.isDutyCycled == false) {
+// deploymentPeriods = tempPeriods;
+// }
+// else {
+// deploymentPeriods = new ArrayList<>();
+// deploymentPeriods.add(new RecordingPeriod(tempPeriods.get(0).getRecordStart(), tempPeriods.get(tempPeriods.size()-1).getRecordStop()));
+// }
+// /*
+// * do another sort of the deploymentPeriods. The start stops were in the order they went into the
+// * database in the hope that pairs were the right way round. Now check all data are/
+// */
+// Collections.sort(deploymentPeriods, new Comparator() {
+// @Override
+// public int compare(RecordingPeriod o1, RecordingPeriod o2) {
+// return (int) (o1.getRecordStart()-o2.getRecordStart());
+// }
+// });
+//
+// DeploymentOverview deploymentOverview = new DeploymentOverview(dutyCycleinfo, deploymentPeriods);
+// matchPamguard2Tethys(deploymentOverview, projectDeployments);
+// this.deploymentOverview = deploymentOverview;
+// return deploymentOverview;
+// // find the number of times it started and stopped ....
+//// System.out.printf("Input map of sound data indicates data from %s to %s with %d starts and %d stops over %d files\n",
+//// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), nStart, nStop, nFile+1);
+// // now work out where there are genuine gaps and make up a revised list of recording periods.
+//
+//
+// }
+
+ public void showOptions(Window parent) {
+ if (parent == null) {
+ parent = tethysControl.getGuiFrame();
+ }
+ DeploymentExportOpts newOpts = RecordingGapDialog.showDiloag(parent, deploymentExportOptions);
+ if (newOpts != null) {
+ deploymentExportOptions = newOpts;
+ createPamguardOverview();
+ }
+ }
+
+ public void createPamguardOverview() {
+ deploymentOverview = effortFunctions.makeRecordingOverview();
+ updateProjectDeployments();
+ matchPamguard2Tethys(deploymentOverview, projectDeployments);
+ }
+
+ /**
+ * Export button pressed on GUI. Run wizard....
+ */
+ public void exportDeployments() {
+ Deployment deployment = MetaDataContol.getMetaDataControl().getMetaData().getDeployment();
+ DeploymentExportOpts exportOptions = DeploymentWizard.showWizard(getTethysControl().getGuiFrame(), tethysControl, deployment, this.deploymentExportOptions);
+ if (exportOptions != null) {
+ this.deploymentExportOptions = exportOptions;
+ deploymentOverview = getDeploymentOverview();
+ ArrayList allPeriods = deploymentOverview.getRecordingPeriods();
+ exportDeployments(allPeriods);
+ }
+ }
+
+ /**
+ * Export deployments docs. Playing with a couple of different ways of doing this.
+ * @param selectedDeployments
+ */
+ public void exportDeployments(ArrayList selectedDeployments) {
+ TethysReporter.getTethysReporter().clear();
+ if (deploymentExportOptions.separateDeployments) {
+ exportSeparateDeployments(selectedDeployments);
+ }
+ else {
+ exportOneDeploymnet(selectedDeployments);
+ }
+ TethysReporter.getTethysReporter().showReport(tethysControl.getGuiFrame(), true);
+ }
+
+ /**
+ * Make one big deployment document with all the recording periods in it.
+ */
+ private void exportOneDeploymnet(ArrayList selectedDeployments) {
+ // do the lot, whatever ...
+ Float sampleRate = null;
+ AcquisitionControl daq = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
+ if (daq != null) {
+ DaqSystem system = daq.findDaqSystem(null);
+ AcquisitionParameters daqParams = daq.acquisitionParameters;
+ sampleRate = daqParams.sampleRate;
+ }
+
+ selectedDeployments = getDeploymentOverview().getRecordingPeriods();
+ int freeId = getTethysControl().getDeploymentHandler().getFirstFreeDeploymentId();
+ RecordingPeriod onePeriod = new RecordingPeriod(selectedDeployments.get(0).getRecordStart(),
+ selectedDeployments.get(selectedDeployments.size()-1).getRecordStop());
+ TethysExportParams exportParams = tethysControl.getTethysExportParams();
+ String id = String.format("%s_%s", exportParams.getDatasetName(), "all");
+ Deployment deployment = createDeploymentDocument(freeId, onePeriod, id);
+ // fill in a few things from here
+ Deployment globalMeta = getTethysControl().getGlobalDeplopymentData();
+ deployment.setCruise(globalMeta.getCruise());
+ deployment.setSite(globalMeta.getSite());
+ if (selectedDeployments.size() > 1) {
+// // now need to remove the sampling details - don't though, add invalid periods instead.
+// SamplingDetails samplingDetails = deployment.getSamplingDetails();
+// samplingDetails.getChannel().clear();
+// for (int i = 0; i < selectedDeployments.size(); i++) {
+// addSamplingDetails(deployment, selectedDeployments.get(i));
+// }
+ /*
+ * Instead, we're putting invalid periods into the QA section.
+ */
+ AcousticDataQAType qa = deployment.getQualityAssurance();
+ if (qa == null) {
+ deployment.setQualityAssurance(qa = new AcousticDataQAType());
+ }
+ List qualityList = qa.getQuality();
+ for (int i = 1; i < selectedDeployments.size(); i++) {
+ long end = selectedDeployments.get(i-1).getRecordStop();
+ long start = selectedDeployments.get(i).getRecordStart();
+ Quality q = new Quality();
+ q.setStart(TethysTimeFuncs.xmlGregCalFromMillis(end));
+ q.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(start));
+ q.setCategory("unusable");
+ if (sampleRate != null) {
+ FrequencyRange f = q.getFrequencyRange();
+ if (f == null) {
+ q.setFrequencyRange(f = new FrequencyRange());
+ }
+ f.setLowHz(0);
+ f.setHighHz(sampleRate/2);
+ }
+ q.setComment("No data (probably off or out of water)");
+ qualityList.add(q);
+ }
+ }
+ DBXMLConnect dbxmlConnect = getTethysControl().getDbxmlConnect();
+ PDeployment exDeploymnet = onePeriod.getMatchedTethysDeployment();
+ try {
+ if (exDeploymnet != null) {
+ deployment.setId(exDeploymnet.deployment.getId());
+ dbxmlConnect.updateDocument(deployment);
+ }
+ else {
+ dbxmlConnect.postAndLog(deployment);
+ }
+ }
+ catch (TethysException e) {
+ getTethysControl().showException(e);
+ }
+ getTethysControl().sendStateUpdate(new TethysState(StateType.UPDATESERVER, Collection.Deployments));
+ }
+
+ /**
+ * Make a separate deployment document for every recording period.
+ */
+ private void exportSeparateDeployments(ArrayList selectedDeployments) {
+
+ int freeId = getTethysControl().getDeploymentHandler().getFirstFreeDeploymentId();
+ // fill in a few things from here
+ Deployment globalMeta = getTethysControl().getGlobalDeplopymentData();
+ TethysExportParams exportParams = tethysControl.getTethysExportParams();
+ for (int i = 0; i < selectedDeployments.size(); i++) {
+ RecordingPeriod recordPeriod = selectedDeployments.get(i);
+ PDeployment exDeploymnet = recordPeriod.getMatchedTethysDeployment();
+ Deployment deployment = null;
+ String id = String.format("%s_%d", exportParams.getDatasetName(), i);
+ if (exDeploymnet != null) {
+ deployment = createDeploymentDocument(freeId, recordPeriod, id);
+ deployment.setId(exDeploymnet.deployment.getId());
+ }
+ if (deployment == null) {
+ deployment = createDeploymentDocument(freeId++, recordPeriod, id);
+ }
+ deployment.setCruise(globalMeta.getCruise());
+ deployment.setSite(globalMeta.getSite());
+ // also need to sort out track data here, etc.
+ DBXMLConnect dbxmlConnect = getTethysControl().getDbxmlConnect();
+ try {
+ if (exDeploymnet != null) {
+ dbxmlConnect.updateDocument(deployment);
+ }
+ else {
+ dbxmlConnect.postAndLog(deployment);
+ }
+ }
+ catch (TethysException e) {
+ getTethysControl().showException(e);
+ }
+ }
+ getTethysControl().sendStateUpdate(new TethysState(StateType.UPDATESERVER, Collection.Deployments));
+ }
+
+
+
+ public DeploymentOverview getDeploymentOverview() {
+ return deploymentOverview;
+ }
+
+ /**
+ * Match what we think the PAMGuard deployment times are with Tethys Deployments read back
+ * from the database.
+ * @param deploymentOverview
+ * @param deployments
+ */
+ private void matchPamguard2Tethys(DeploymentOverview deploymentOverview, ArrayList deployments) {
+ if (deployments == null || deploymentOverview == null) {
+ return;
+ }
+ ArrayList recordingPeriods = deploymentOverview.getRecordingPeriods();
+ for (RecordingPeriod aPeriod : recordingPeriods) {
+ PDeployment closestDeployment = findClosestDeployment(aPeriod, deployments);
+ aPeriod.setMatchedTethysDeployment(closestDeployment);
+ if (closestDeployment != null) {
+ closestDeployment.setMatchedPAMGaurdPeriod(aPeriod);
+ }
+ }
+ }
+
+ /**
+ * find the Tethys deployment that most closely matches the PAMGuard recording period.
+ * @param aPeriod
+ * @param deployments
+ * @return
+ */
+ private PDeployment findClosestDeployment(RecordingPeriod aPeriod, ArrayList deployments) {
+ double overlap = -1;
+ PDeployment bestDeployment = null;
+ for (PDeployment aDeployment : deployments) {
+ double newOverlap = getDeploymentOverlap(aDeployment, aPeriod);
+ if (newOverlap > overlap) {
+ bestDeployment = aDeployment;
+ overlap = newOverlap;
+ }
+ }
+ return bestDeployment;
+ }
+
+ /**
+ * Get the overlap in mills between a nilus Deployment and a PAMGuard recording period
+ * @param aDeployment nilus Deployment from Tethys
+ * @param aPeriod PAMGuard recording period
+ * @return overlap in milliseconds
+ */
+ public long getDeploymentOverlap(PDeployment aDeployment, RecordingPeriod aPeriod) {
+ long start = aPeriod.getRecordStart(); // recording period.
+ long stop = aPeriod.getRecordStop();
+ Long depStart = aDeployment.getAudioStart();
+ Long depStop = aDeployment.getAudioEnd();
+ if (depStart == null || depStop == null) {
+ return -1;
+ }
+ long overlap = (Math.min(stop, depStop)-Math.max(start, depStart));
+ return overlap;
+ }
+
+
+
+
+ /**
+ * Get a list of Tethys Deployment docs that match the current PAMGuard data. Watch for repeats
+ * if a single deployment doc covers many perdiods.
+ * @return
+ */
+ public ArrayList getMatchedDeployments() {
+ ArrayList matched = new ArrayList<>();
+ if (deploymentOverview == null) {
+ return matched;
+ }
+ for (RecordingPeriod period : deploymentOverview.getRecordingPeriods()) {
+ PDeployment deployment = period.getMatchedTethysDeployment();
+ if (deployment != null) {
+ if (matched.contains(deployment) == false) {
+ matched.add(period.getMatchedTethysDeployment());
+ }
+ }
+ }
+ return matched;
+ }
+
+ /**
+ * Get a list of instruments from the current project deployments.
+ * This may be a shorter list than the list of deployments.
+ * @return
+ */
+ public ArrayList getProjectInstruments() {
+ if (projectDeployments == null) {
+ return null;
+ }
+ ArrayList instruments = new ArrayList<>();
+ for (PDeployment aDepl : projectDeployments) {
+ Instrument intr = aDepl.deployment.getInstrument();
+ if (intr == null) {
+ continue;
+ }
+ PInstrument pInstr = new PInstrument(intr.getType(), intr.getInstrumentId());
+ if (instruments.contains(pInstr) == false) {
+ instruments.add(pInstr);
+ }
+ }
+ return instruments;
+ }
+ //in each channel
+// public ArrayList getDeployments() {
+//
+// DeploymentOverview recordingOverview = this.deploymentOverview;
+//
+// // first find an acquisition module.
+// PamControlledUnit aModule = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
+// if (!(aModule instanceof AcquisitionControl)) {
+// // will return if it's null. Impossible for it to be the wrong type.
+// // but it's good practice to check anyway before casting.
+// return null;
+// }
+// // cast it to the right type.
+// AcquisitionControl daqControl = (AcquisitionControl) aModule;
+// AcquisitionParameters daqParams = daqControl.getAcquisitionParameters();
+// /**
+// * The daqParams class has most of what we need about the set up in terms of sample rate,
+// * number of channels, instrument type, ADC input range (part of calibration), etc.
+// * It also has a hydrophone list, which maps the input channel numbers to the hydrophon numbers.
+// * Realistically, this list is always 0,1,2,etc or it goes horribly wrong !
+// */
+// // so write functions here to get information from the daqParams.
+//// System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(),
+//// daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak);
+// /**
+// * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map
+// * but the datamap is a simple count of what's in the databasase which is not quite what we want.
+// * we're going to have to query the database to get more detailed informatoin I think.
+// * I'll do that here for now, but we may want to move this when we better organise the code.
+// * It also seems that there are 'bad' dates in the database when it starts new files, which are the date
+// * data were analysed at. So we really need to check the start and stop records only.
+// */
+// PamDataBlock daqInfoDataBlock = daqControl.getAcquisitionProcess().getDaqStatusDataBlock();
+// // just load everything. Probably OK for the acqusition, but will bring down
+// daqInfoDataBlock.loadViewerData(0, Long.MAX_VALUE, null);
+// ArrayList allStatusData = daqInfoDataBlock.getDataCopy();
+// long dataStart = Long.MAX_VALUE;
+// long dataEnd = Long.MIN_VALUE;
+// if (allStatusData != null && allStatusData.size() > 0) {
+// // find the number of times it started and stopped ....
+// int nStart = 0, nStop = 0, nFile=0;
+// for (DaqStatusDataUnit daqStatus : allStatusData) {
+// switch (daqStatus.getStatus()) {
+// case "Start":
+// nStart++;
+// dataStart = Math.min(dataStart, daqStatus.getTimeMilliseconds());
+// break;
+// case "Stop":
+// nStop++;
+// dataEnd = Math.max(dataEnd, daqStatus.getEndTimeInMilliseconds());
+// break;
+// case "NextFile":
+// nFile++;
+// break;
+// }
+// }
+//
+//// System.out.printf("Input map of sound data indicates data from %s to %s with %d starts and %d stops over %d files\n",
+//// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), nStart, nStop, nFile+1);
+//
+// }
+//
+//// // and we find the datamap within that ...
+//// OfflineDataMap daqMap = daqInfoDataBlock.getOfflineDataMap(DBControlUnit.findDatabaseControl());
+//// if (daqMap != null) {
+//// // iterate through it.
+//// long dataStart = daqMap.getFirstDataTime();
+//// long dataEnd = daqMap.getLastDataTime();
+//// List mapPoints = daqMap.getMapPoints();
+//// System.out.printf("Input map of sound data indicates data from %s to %s with %d individual files\n",
+//// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), mapPoints.size());
+//// /*
+//// * clearly in the first database I've been looking at of Tinas data, this is NOT getting sensible start and
+//// * end times. Print them out to see what's going on.
+//// */
+////// for ()
+//// }
+// DeploymentRecoveryPair pair = new DeploymentRecoveryPair();
+// DeploymentRecoveryDetails deployment = new DeploymentRecoveryDetails();
+// DeploymentRecoveryDetails recovery = new DeploymentRecoveryDetails();
+// pair.deploymentDetails = deployment;
+// pair.recoveryDetails = recovery;
+//
+// deployment.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataStart));
+// deployment.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataStart));
+// recovery.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataEnd));
+// recovery.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataEnd));
+//
+// ArrayList drPairs = new ArrayList<>();
+// drPairs.add(pair);
+// return drPairs;
+//
+// }
+
+ /**
+ * Get the first free deploymendId. This will get appended to
+ * the ProjectName to make and id for each Deployment document
+ * @return
+ */
+ public int getFirstFreeDeploymentId() {
+ /**
+ * This is an integer used for the DeploymentId. Note that the String Id (currentl9) is just the Project name
+ * appended with this number.
+ */
+ int firstFree = 0;
+ if (projectDeployments != null) {
+ for (PDeployment dep : projectDeployments) {
+ firstFree = Math.max(firstFree, dep.deployment.getDeploymentId()+1);
+ }
+ }
+ return firstFree;
+ }
+
+ public Deployment createDeploymentDocument(int i, RecordingPeriod recordingPeriod, String deploymentId) {
+ Deployment deployment = new Deployment();
+ try {
+ nilus.Helper.createRequiredElements(deployment);
+ } catch (IllegalArgumentException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ PamguardMetaData pamguardMetaData = MetaDataContol.getMetaDataControl().getMetaData();
+ Deployment templateDeployment = pamguardMetaData.getDeployment();
+
+// Deployment globalDeplData = tethysControl.getGlobalDeplopymentData();
+ deployment.setId(deploymentId);
+ deployment.setDeploymentId(i);
+
+ DeploymentRecoveryDetails deploymentDetails = deployment.getDeploymentDetails();
+ if (deploymentDetails == null) {
+ deploymentDetails = new DeploymentRecoveryDetails();
+ }
+ DeploymentRecoveryDetails recoveryDetails = deployment.getRecoveryDetails();
+ if (recoveryDetails == null) {
+ recoveryDetails = new DeploymentRecoveryDetails();
+ }
+
+ deploymentDetails.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStart()));
+ recoveryDetails.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStop()));
+ // handle situation where deployment and recovery times are not the same as the audio times.
+ if (pamguardMetaData.useAudioForDeploymentTimes == false) {
+ if (templateDeployment.getDeploymentDetails().getAudioTimeStamp() != null) {
+ deploymentDetails.setTimeStamp(templateDeployment.getDeploymentDetails().getAudioTimeStamp());
+ }
+ if (templateDeployment.getRecoveryDetails().getAudioTimeStamp() != null) {
+ recoveryDetails.setTimeStamp(templateDeployment.getRecoveryDetails().getAudioTimeStamp());
+ }
+ }
+
+ deploymentDetails.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStart()));
+ recoveryDetails.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStop()));
+
+ deployment.setDeploymentDetails(deploymentDetails);
+ deployment.setRecoveryDetails(recoveryDetails);
+
+ getProjectData(deployment);
+
+ TethysLocationFuncs.getTrackAndPositionData(deployment);
+
+ getTrackDetails(deployment);
+
+ /**
+ * Get some of the meta data from the centralised source.
+ */
+ MetadataInfo metaData = templateDeployment.getMetadataInfo();
+ metaData.setDate(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis()));
+ metaData.setUpdateFrequency("as-needed");
+ deployment.setMetadataInfo(metaData);
+
+ deployment.setDescription(templateDeployment.getDescription());
+// DescriptionType description = deployment.getDescription();
+// if (description == null ) {
+// description = new DescriptionType();
+// deployment.setDescription(description);
+// description.setAbstract("No abstract");
+// description.setMethod("no methods");
+// description.setObjectives("No objectives");
+// }
+// description.set
+
+ addSamplingDetails(deployment, recordingPeriod);
+
+ getSensorDetails(deployment);
+
+ getSensors(deployment);
+
+ /**
+ * Stuff that may need to be put into the UI:
+ * Audio: can easily get current loc of raw and binary data, but may need to override these. I think
+ * this may be for the export UI ?
+ * Tracks: trackline information. General problem in PAMGUard.
+ */
+ getDataDetails(deployment);
+
+
+ return deployment;
+ }
+
+ /**
+ * Add the track to the deployment, if there is one (i.e. not for
+ * a fixed sensor).
+ * @param deployment
+ */
+ private void getTrackDetails(Deployment deployment) {
+ TrackInformation trackInfo = getTrackInformation();
+ if (trackInfo.haveGPSTrack() == false) {
+ return;
+ }
+ GPSDataBlock gpsDataBlock = (GPSDataBlock) trackInfo.getGpsDataMap().getParentDataBlock();
+ if (gpsDataBlock == null) {
+ return;
+ }
+ /*
+ * should have some track information. Do a load from the
+ * database for the whole deployment. this may be the entire GPS record, but
+ * we should be able to cope with that.
+ */
+ long trackStart = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getTimeStamp());
+ long trackEnd = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getTimeStamp());
+ long dataWin =(long) (Math.max(1./trackInfo.getGPSDataRate(), deploymentExportOptions.trackPointInterval));
+
+ // get the tracks object.
+ Tracks tracks = deployment.getData().getTracks();
+ if (tracks == null) {
+ tracks = new Tracks();
+ deployment.getData().setTracks(tracks);
+ }
+ List trackList = tracks.getTrack(); // lists are usually there.
+
+ Track aTrack = new Track();
+ trackList.add(aTrack);
+ List points = aTrack.getPoint();
+
+ gpsDataBlock.loadViewerData(trackStart-dataWin, trackEnd+dataWin, null);
+ long lastPointTime = 0;
+ ListIterator it = gpsDataBlock.getListIterator(0);
+ while (it.hasNext()) {
+ GpsDataUnit gpsDataUnit = it.next();
+ if (gpsDataUnit.getTimeMilliseconds()-lastPointTime < deploymentExportOptions.trackPointInterval*1000) {
+ continue;
+ }
+ GpsData gpsData = gpsDataUnit.getGpsData();
+ Point gpsPoint = new Point();
+ gpsPoint.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(gpsDataUnit.getTimeMilliseconds()));
+ gpsPoint.setLatitude(gpsData.getLatitude());
+ gpsPoint.setLongitude(PamUtils.constrainedAngle(gpsData.getLongitude()));
+ BearingDegN bdn = gpsPoint.getBearingDegN();
+ if (bdn == null) {
+ bdn = new BearingDegN();
+ gpsPoint.setBearingDegN(bdn);
+ }
+ bdn.setValue(AutoTethysProvider.roundDecimalPlaces(PamUtils.constrainedAngle(gpsData.getHeading()),1));
+ gpsPoint.setSpeedKn(AutoTethysProvider.roundDecimalPlaces(gpsData.getSpeed(),2));
+
+ points.add(gpsPoint);
+ lastPointTime = gpsDataUnit.getTimeMilliseconds();
+ }
+ }
+
+ public String getBinaryDataURI() {
+ BinaryStore binStore = BinaryStore.findBinaryStoreControl();
+ if (binStore != null) {
+ return binStore.getBinaryStoreSettings().getStoreLocation();
+ }
+ return null;
+ }
+
+ public String getDatabaseURI() {
+ DBControlUnit databaseControl = DBControlUnit.findDatabaseControl();
+ if (databaseControl != null) {
+ return databaseControl.getLongDatabaseName();
+ }
+ return null;
+ }
+
+ public String getRawDataURI() {
+ try {
+ PamControlledUnit daq = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
+ if (daq instanceof AcquisitionControl) {
+ AcquisitionControl daqCtrl = (AcquisitionControl) daq;
+ DaqSystem system = daqCtrl.findDaqSystem(null);// getAcquisitionProcess().getRunningSystem();
+ if (system instanceof FolderInputSystem) {
+ FolderInputSystem fip = (FolderInputSystem) system;
+ return fip.getFolderInputParameters().recentFiles.get(0);
+ }
+ }
+ }
+ catch (Exception e) {
+ }
+ return "unknown";
+ }
+
+ private void getDataDetails(Deployment deployment) {
+ Data data = deployment.getData();
+ if (data == null) {
+ data = new Data();
+ deployment.setData(data);
+ }
+ nilus.Deployment.Data.Audio audio = data.getAudio();
+ if (audio == null) {
+ audio = new nilus.Deployment.Data.Audio();
+ data.setAudio(audio);
+ }
+ audio.setURI(getRawDataURI());
+ String processed = "Database:"+getDatabaseURI();
+ String binary = getBinaryDataURI();
+ if (binary != null) {
+ binary += ";Binary:"+binary;
+ }
+ audio.setProcessed(processed);
+
+ }
+
+ /**
+ * Get sensor information. The Soundtrap CTD will count as a sensor.
+ * Modules that are sensors will have to implement a PAMSensor interface
+ * @param deployment
+ */
+ private void getSensors(Deployment deployment) {
+ ArrayList sensorModules = PamController.getInstance().findControlledUnits(PamSensor.class, true);
+ if (sensorModules == null || sensorModules.size() == 0) {
+ return;
+ }
+ Sensors sensors = deployment.getSensors();
+ if (sensors == null) {
+ sensors = new Sensors();
+ deployment.setSensors(sensors);
+ }
+ List sensorList = sensors.getSensor();
+ for (PamControlledUnit aUnit : sensorModules) {
+ PamSensor pamSensor = (PamSensor) aUnit;
+ UnknownSensor nilusSensor = new UnknownSensor();
+ try {
+ Helper.createRequiredElements(nilusSensor);
+ } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+// nilusSensor.setName(pamSensor.getUnitName());
+ nilusSensor.setType(pamSensor.getUnitType());
+ nilusSensor.setNumber(BigInteger.ZERO);
+ nilusSensor.setDescription(pamSensor.getSensorDescription());
+ nilusSensor.setSensorId(pamSensor.getUnitType());
+
+ sensorList.add(nilusSensor);
+ }
+ }
+
+ /**
+ * Add project Metadata to a Deploymnet document. This is currently being
+ * made available in the MetaDataControl module which should be added to PAMGuard
+ * as well as the Tethys output module.
+ * @param deployment
+ */
+ private boolean getProjectData(Deployment deployment) {
+// PamControlledUnit aUnit = PamController.getInstance().findControlledUnit(MetaDataContol.class, null);
+// if (aUnit instanceof MetaDataContol == false || true) {
+// deployment.setProject("thisIsAProject");
+// deployment.setPlatform("Yay a platform");
+// Instrument instrument = new Instrument();
+// instrument.setType("machiney");
+// instrument.setInstrumentId("12345555");
+// deployment.setInstrument(instrument);
+// return false;
+// }
+//
+// MetaDataContol metaControl = (MetaDataContol) aUnit;
+ PamguardMetaData metaData = MetaDataContol.getMetaDataControl().getMetaData();
+ Deployment deploymentData = tethysControl.getGlobalDeplopymentData();
+ deployment.setProject(deploymentData.getProject());
+ deployment.setDeploymentAlias(deploymentData.getDeploymentAlias());
+ deployment.setSite(deploymentData.getSite());
+ deployment.setCruise(deploymentData.getCruise());
+ deployment.setPlatform(getPlatform());
+ deployment.setRegion(deploymentData.getRegion());
+ Instrument instrument = new Instrument();
+ instrument.setType(getInstrumentType());
+ instrument.setInstrumentId(getInstrumentId());
+ // get the geometry type from the array manager.
+ String geomType = getGeometryType();
+ instrument.setGeometryType(geomType);
+ deployment.setInstrument(instrument);
+
+ // overwrite the default deployment and recovery times if there is non null data
+ XMLGregorianCalendar depTime = deploymentData.getDeploymentDetails().getTimeStamp();
+ if (depTime != null) {
+ deployment.getDeploymentDetails().setTimeStamp(depTime);
+ }
+ if (deploymentData.getRecoveryDetails() != null) {
+ XMLGregorianCalendar recMillis = deploymentData.getRecoveryDetails().getTimeStamp();
+ if (recMillis != null) {
+ deployment.getRecoveryDetails().setTimeStamp(recMillis);
+ }
+ double recLat = deploymentData.getRecoveryDetails().getLatitude();
+ double recLong = deploymentData.getRecoveryDetails().getLongitude();
+ if (recLat != 0 & recLong != 0.) {
+ deployment.getRecoveryDetails().setLatitude(recLat);
+ deployment.getRecoveryDetails().setLongitude(PamUtils.constrainedAngle(recLong));
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Instrument identifier, e.g. serial number
+ * @return
+ */
+ private String getInstrumentId() {
+ return ArrayManager.getArrayManager().getCurrentArray().getInstrumentId();
+ }
+
+ /**
+ * Test to see if it's possible to export Deployment documents. This is basically a test of
+ * various metadata fields that are required, such as instrument id's.
+ * @return null if OK, or a string describing the first encountered error
+ */
+ public String canExportDeployments() {
+
+ Deployment globalDeplData = tethysControl.getGlobalDeplopymentData();
+ if (globalDeplData.getProject() == null) {
+ return "You must set a project name";
+ }
+
+ PInstrument arrayInstrument = getCurrentArrayInstrument();
+ if (arrayInstrument == null) {
+ return "No 'Instrument' set. Goto array manager";
+ }
+ return null;
+ }
+
+ /**
+ * Get the Instrument info for the current array.
+ * @return
+ */
+ public PInstrument getCurrentArrayInstrument() {
+ PamArray currentArray = ArrayManager.getArrayManager().getCurrentArray();
+ String currType = currentArray.getInstrumentType();
+ String currId = currentArray.getInstrumentId();
+ PInstrument currentInstrument = null;
+ if (currType != null || currId != null) {
+ currentInstrument = new PInstrument(currType, currId);
+ }
+ return currentInstrument;
+ }
+
+ /**
+ * On what platform is the instrument deployed? (e.g. mooring, tag)
+ * @return
+ */
+ private String getPlatform() {
+ return getGeometryType();
+ }
+ /**
+ * Instrument type, e.g. HARP, EAR, Popup, DMON, Rock Hopper, etc.
+ * @return
+ */
+ private String getInstrumentType() {
+ return ArrayManager.getArrayManager().getCurrentArray().getInstrumentType();
+ }
+
+ /**
+ * Get a geometry type string for Tethys based on information in the array manager.
+ * @return
+ */
+ private String getGeometryType() {
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ int nStreamer = array.getStreamerCount();
+ for (int i = 0; i < nStreamer; i++) {
+ Streamer streamer = array.getStreamer(i);
+ HydrophoneLocator locator = streamer.getHydrophoneLocator();
+ if (locator == null) {
+ continue;
+ }
+ if (locator instanceof ThreadingHydrophoneLocator) {
+ return "cabled";
+ }
+ else {
+ return "rigid";
+ }
+ }
+ return "unknown";
+ }
+
+ private boolean getSensorDetails(Deployment deployment) {
+ PamArray array = ArrayManager.getArrayManager().getCurrentArray();
+ Sensors sensors = new Sensors();
+ List audioList = sensors.getAudio();
+ ArrayList phones = array.getHydrophoneArray();
+ int iPhone = 0;
+ long timeMillis = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp());
+ CalibrationHandler calibrationHandler = tethysControl.getCalibrationHandler();
+
+ for (Hydrophone aPhone : phones) {
+ PamVector hydLocs = array.getAbsHydrophoneVector(iPhone, timeMillis);
+ Audio audio = new Audio();
+ audio.setNumber(BigInteger.valueOf(iPhone));
+ String id = calibrationHandler.getHydrophoneId(iPhone);
+// audio.setSensorId(String.format("Hydrophone %d", iPhone)); // should replace with serial number if it exists.
+ audio.setSensorId(id);
+ GeometryTypeM geom = new GeometryTypeM();
+ geom.setXM(hydLocs.getCoordinate(0));
+ geom.setYM(hydLocs.getCoordinate(1));
+ geom.setZM(hydLocs.getCoordinate(2));
+// Geometry geom = new Geometry();
+// audio.setGeometry(geom);
+//// nilusHelper.
+// List geomCont = geom.getContent();
+// for (int iCoord = 0; iCoord < 3; iCoord++) {
+// geom.getContent().add(Double.valueOf(hydLocs.getCoordinate(iCoord)));
+// }
+// try {
+// MarshalXML mXML = new MarshalXML();
+// mXML.marshal(geom);
+// } catch (JAXBException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+ /**
+ * Need to be able to add the values from hydLocs to the geometry object, but can't.
+ */
+ audioList.add(audio);
+ iPhone++;
+ }
+// try {
+// MarshalXML mXML = new MarshalXML();
+// mXML.marshal(sensors);
+// } catch (JAXBException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+ deployment.setSensors(sensors);
+ return true;
+ }
+
+ /**
+ * Fill in the sampling details in a Deployment document.
+ * @param deployment
+ * @param recordingPeriod
+ */
+ private boolean addSamplingDetails(Deployment deployment, RecordingPeriod recordingPeriod) {
+
+ SamplingDetails samplingDetails = deployment.getSamplingDetails();
+ if (samplingDetails == null) {
+ samplingDetails = new SamplingDetails();
+ deployment.setSamplingDetails(samplingDetails);
+ }
+ // this is basically going to be a list of almost identical channel information
+ // currently just for the first acquisition. May extend to more.
+ // see if there is > 1 acquisition. May want to include many.
+ ArrayList daqUnits = PamController.getInstance().findControlledUnits(AcquisitionControl.class);
+
+ AcquisitionControl daq = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
+ if (daq == null) {
+ return false;
+ }
+ DaqSystem system = daq.findDaqSystem(null);
+ AcquisitionParameters daqParams = daq.acquisitionParameters;
+ int nChan = daqParams.nChannels;
+ float fs = daqParams.sampleRate;
+ int[] hydroMap = daqParams.getHydrophoneList();
+ int[] inputMap = daqParams.getHardwareChannelList();
+ double vp2p = daqParams.getVoltsPeak2Peak();
+
+ List channelInfos = samplingDetails.getChannel();
+ for (int i = 0; i < nChan; i++) {
+ ChannelInfo channelInfo = new ChannelInfo();
+ channelInfo.setStart(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStart()));
+ channelInfo.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStop()));
+
+ BigIntegerConverter biCon = new BigIntegerConverter();
+ BigInteger chanNum = BigInteger.valueOf(i);
+ channelInfo.setChannelNumber(chanNum);
+ if (hydroMap != null) {
+ channelInfo.setSensorNumber(hydroMap[i]);
+ }
+ else {
+ channelInfo.setSensorNumber(i);
+ }
+ /*
+ * Gain - may have to cycle through and see if this ever changes (or
+ * if was recorded that it changed which may not be the same!)
+ */
+ ChannelInfo.Gain gain = new ChannelInfo.Gain();
+ List gainList = gain.getRegimen();
+ nilus.ChannelInfo.Gain.Regimen aGain = new nilus.ChannelInfo.Gain.Regimen();
+ aGain.setGainDB(daqParams.getPreamplifier().getGain());
+ channelInfo.setGain(gain);
+
+ Sampling sampling = new Sampling();
+ List regimens = sampling.getRegimen();
+ Sampling.Regimen regimen = new Sampling.Regimen();
+ regimen.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStart()));
+ regimen.setSampleRateKHz(fs/1000.);
+ if (system != null) {
+ regimen.setSampleBits(system.getSampleBits());
+ }
+ regimens.add(regimen);
+
+ DutyCycleInfo dutyCycleInf = deploymentOverview.getDutyCycleInfo();
+ boolean isDS = dutyCycleInf != null && dutyCycleInf.isDutyCycled;
+ if (isDS) {
+ DutyCycle dutyCycle = new DutyCycle();
+ List reg = dutyCycle.getRegimen();
+ nilus.ChannelInfo.DutyCycle.Regimen dsr = new nilus.ChannelInfo.DutyCycle.Regimen();
+ reg.add(dsr);
+ RecordingDurationS ssss = new RecordingDurationS();
+ // round to a second ... or .1s if short duty cycle.
+ int dp = 1;
+ if (dutyCycleInf.meanOnTimeS > 59) {
+ dp = 0;
+ }
+ ssss.setValue(AutoTethysProvider.roundDecimalPlaces(dutyCycleInf.meanOnTimeS,dp));
+ dsr.setRecordingDurationS(ssss);
+ RecordingIntervalS ris = new RecordingIntervalS();
+ ris.setValue(AutoTethysProvider.roundDecimalPlaces(dutyCycleInf.meanOnTimeS + dutyCycleInf.meanGapS,dp));
+ dsr.setRecordingIntervalS(ris);
+ dsr.setTimeStamp(deployment.getDeploymentDetails().getAudioTimeStamp());
+ channelInfo.setDutyCycle(dutyCycle);
+ }
+
+ channelInfo.setSampling(sampling);
+
+ channelInfos.add(channelInfo);
+
+ /**
+ * Need something about duty cycling. this is probably something that will have to be added
+ * earlier to a wrapper around the Deployment class.
+ */
+ }
+ return true;
+ }
+
+ @Override
+ public void selectionChanged() {
+ // TODO Auto-generated method stub
+
+ }
+
+ private class SettingsHandler implements PamSettings {
+
+ @Override
+ public String getUnitName() {
+ return tethysControl.getUnitName();
+ }
+
+ @Override
+ public String getUnitType() {
+ return "Tethys Deployment Handler";
+ }
+
+ @Override
+ public Serializable getSettingsReference() {
+ return deploymentExportOptions;
+ }
+
+ @Override
+ public long getSettingsVersion() {
+ return DeploymentExportOpts.serialVersionUID;
+ }
+
+ @Override
+ public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
+ deploymentExportOptions = (DeploymentExportOpts) pamControlledUnitSettings.getSettings();
+ return true;
+ }
+
+ }
+
+ /**
+ * @return the deploymentExportOptions
+ */
+ public DeploymentExportOpts getDeploymentExportOptions() {
+ return deploymentExportOptions;
+ }
+
+}
diff --git a/src/tethys/deployment/DeploymentOverview.java b/src/tethys/deployment/DeploymentOverview.java
new file mode 100644
index 00000000..f296df8e
--- /dev/null
+++ b/src/tethys/deployment/DeploymentOverview.java
@@ -0,0 +1,80 @@
+package tethys.deployment;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.ListIterator;
+
+import Acquisition.AcquisitionControl;
+import Acquisition.AcquisitionParameters;
+import Acquisition.DaqStatusDataUnit;
+import PamController.PamControlledUnit;
+import PamController.PamController;
+import PamguardMVC.PamDataBlock;
+
+/**
+ * Class to give a general overview of all the effort in PAMGuard which will form the
+ * basis for Deployment Documents.
+ * This will tell us if data were on a regular duty cycle or more adhoc and also provide
+ * a list of all start and end times for these periods.
+ * @author dg50
+ *
+ */
+public class DeploymentOverview {
+
+ private ArrayList recordingPeriods = new ArrayList<>();
+
+ private DutyCycleInfo dutyCycleInfo;
+
+ public DeploymentOverview(DutyCycleInfo dutyCycleInfo) {
+ super();
+ this.dutyCycleInfo = dutyCycleInfo;
+ }
+
+ public DeploymentOverview(DutyCycleInfo dutyCycleInfo, ArrayList tempPeriods) {
+ this.dutyCycleInfo = dutyCycleInfo;
+ this.recordingPeriods = tempPeriods;
+ }
+
+
+ public void addRecordingPeriod(long start, long stop) {
+ addRecordingPeriod(new RecordingPeriod(start, stop));
+ }
+
+ private void addRecordingPeriod(RecordingPeriod recordingPeriod) {
+ recordingPeriods.add(recordingPeriod);
+ }
+
+ public ArrayList getRecordingPeriods() {
+ return recordingPeriods;
+ }
+
+ public DutyCycleInfo getDutyCycleInfo() {
+ return dutyCycleInfo;
+ }
+
+ /**
+ * Get the start time of the first recording
+ * @return
+ */
+ public Long getFirstStart() {
+ if (recordingPeriods.size() > 0) {
+ return recordingPeriods.get(0).getRecordStart();
+ }
+ return null;
+ }
+
+ /**
+ * Get the end time of the last recording
+ * @return
+ */
+ public Long getLastEnd() {
+ if (recordingPeriods.size() > 0) {
+ return recordingPeriods.get(recordingPeriods.size()-1).getRecordStop();
+ }
+ return null;
+ }
+
+
+
+}
diff --git a/src/tethys/deployment/DeploymentRecoveryPair.java b/src/tethys/deployment/DeploymentRecoveryPair.java
new file mode 100644
index 00000000..8e168a2a
--- /dev/null
+++ b/src/tethys/deployment/DeploymentRecoveryPair.java
@@ -0,0 +1,11 @@
+package tethys.deployment;
+
+import nilus.DeploymentRecoveryDetails;
+
+public class DeploymentRecoveryPair {
+
+// public DeploymentRecoveryDetails deploymentDetails;
+//
+// public DeploymentRecoveryDetails recoveryDetails;
+
+}
diff --git a/src/tethys/deployment/DeploymentWrapper.java b/src/tethys/deployment/DeploymentWrapper.java
new file mode 100644
index 00000000..01126c92
--- /dev/null
+++ b/src/tethys/deployment/DeploymentWrapper.java
@@ -0,0 +1,85 @@
+package tethys.deployment;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedType;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+import javax.xml.validation.Schema;
+
+//import nilus.Deployment.Data.Audio;
+//import nilus.Deployment;
+//import nilus.Deployment.Data;
+//import nilus.Deployment.Instrument;
+
+public class DeploymentWrapper {
+
+ public DeploymentWrapper(T tethysObject) {
+
+ }
+
+ public List getFieldNames() {
+ return null;
+ }
+
+ public List getComplexObjects() {
+
+ return null;
+ }
+
+ public static void main(String[] args) {
+ // quick play with some JAXB objects to see what they can do.
+// Deployment deployment = new Deployment();
+//
+// Class extends Deployment> deploymentClass = deployment.getClass();
+// Annotation[] annots = deploymentClass.getAnnotations();
+// AnnotatedType[] annotInterfaces = deploymentClass.getAnnotatedInterfaces();
+// Annotation[] declAnnots = deploymentClass.getDeclaredAnnotations();
+//
+// Instrument instrument = new Instrument();
+// instrument.setID("22");
+// instrument.setType("SoundTrap");
+// QName qName = new QName("Instrument");
+// JAXBElement jInst = new JAXBElement(qName, Instrument.class, instrument);
+// deployment.getContent().add(jInst);
+//
+// Deployment.Data data = new Data();
+// Audio audio = new Audio();
+// audio.setProcessed("??");
+// data.setAudio(audio);
+// JAXBElement jData = new JAXBElement(new QName("Data"), Data.class, data);
+// deployment.getContent().add(jData);
+//
+// String project = "Project Name";
+// JAXBElement jProj = new JAXBElement(new QName("Project"), String.class, project);
+// deployment.getContent().add(jProj);
+//
+// String aaa = "Project Something else";
+// JAXBElement jProj2 = new JAXBElement(new QName("Region"), String.class, aaa);
+// deployment.getContent().add(jProj2);
+//
+//
+// try {
+// JAXBContext jContext = JAXBContext.newInstance(Deployment.class);
+// Marshaller mar = (Marshaller) jContext.createMarshaller();
+// mar.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
+//
+// ByteArrayOutputStream bos = new ByteArrayOutputStream();
+// mar.marshal(deployment, bos);
+// String xml = new String(bos.toByteArray());
+// System.out.println(xml);
+//// Schema schema = mar.getSchema(); // is null. Can't generate it's own it seems.
+//
+// } catch (Exception e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+//
+ }
+
+}
diff --git a/src/tethys/deployment/DutyCycleInfo.java b/src/tethys/deployment/DutyCycleInfo.java
new file mode 100644
index 00000000..5bdbe89f
--- /dev/null
+++ b/src/tethys/deployment/DutyCycleInfo.java
@@ -0,0 +1,36 @@
+package tethys.deployment;
+
+import PamUtils.PamCalendar;
+
+public class DutyCycleInfo {
+
+ public boolean isDutyCycled;
+
+ public double meanOnTimeS;
+
+ public double meanGapS;
+
+ int nCycles;
+
+ public DutyCycleInfo(boolean isDutyCycled, double meanOnTimeS, double meanGapS, int nCycles) {
+ super();
+ this.isDutyCycled = isDutyCycled;
+ this.meanOnTimeS = meanOnTimeS;
+ this.meanGapS = meanGapS;
+ this.nCycles = nCycles;
+ }
+
+ @Override
+ public String toString() {
+ if (isDutyCycled == false) {
+ return "No duty cycle";
+ }
+ else {
+ return String.format("%s on, %s off, for %d cycles", PamCalendar.formatDuration((long) (meanOnTimeS*1000)),
+ PamCalendar.formatDuration((long) (meanGapS*1000)), nCycles);
+ }
+ }
+
+
+
+}
diff --git a/src/tethys/deployment/EffortFunctions.java b/src/tethys/deployment/EffortFunctions.java
new file mode 100644
index 00000000..2fd8f383
--- /dev/null
+++ b/src/tethys/deployment/EffortFunctions.java
@@ -0,0 +1,413 @@
+package tethys.deployment;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ListIterator;
+
+import Acquisition.AcquisitionControl;
+import Acquisition.AcquisitionParameters;
+import Acquisition.DaqStatusDataUnit;
+import PamController.PamControlledUnit;
+import PamController.PamController;
+import PamguardMVC.PamDataBlock;
+import PamguardMVC.PamRawDataBlock;
+import SoundRecorder.RecordingInfo;
+import binaryFileStorage.BinaryStore;
+import dataMap.OfflineDataMap;
+import dataMap.OfflineDataMapPoint;
+import pamMaths.STD;
+import tethys.TethysControl;
+import tethys.output.TethysExportParams;
+import tethys.pamdata.TethysDataProvider;
+
+/**
+ * functions for working out total effort and periods of recording from a variety of sources, which may be
+ * the recordings database, binary files, etc.
+ * @author dg50
+ *
+ */
+public class EffortFunctions {
+
+ private TethysControl tethysControl;
+
+
+ /**
+ * @param tethysControl
+ */
+ public EffortFunctions(TethysControl tethysControl) {
+ this.tethysControl = tethysControl;
+ }
+
+ private DeploymentOverview createOverview(RecordingList tempPeriods) {
+
+ DutyCycleInfo dutyCycleinfo = assessDutyCycle(tempPeriods);
+ if (dutyCycleinfo == null) {
+ return null;
+ }
+
+ // if it's duty cycles, then we only want a single entry.
+ RecordingList deploymentPeriods;
+ if (dutyCycleinfo.isDutyCycled == false) {
+ deploymentPeriods = tempPeriods;
+ }
+ else {
+ deploymentPeriods = new RecordingList();
+ deploymentPeriods.add(new RecordingPeriod(tempPeriods.get(0).getRecordStart(), tempPeriods.get(tempPeriods.size()-1).getRecordStop()));
+ }
+ /*
+ * do another sort of the deploymentPeriods. The start stops were in the order they went into the
+ * database in the hope that pairs were the right way round. Now check all data are/
+ */
+ Collections.sort(deploymentPeriods, new Comparator() {
+ @Override
+ public int compare(RecordingPeriod o1, RecordingPeriod o2) {
+ return (int) (o1.getRecordStart()-o2.getRecordStart());
+ }
+ });
+
+ DeploymentOverview deploymentOverview = new DeploymentOverview(dutyCycleinfo, deploymentPeriods);
+ return deploymentOverview;
+ }
+
+
+ public DeploymentOverview makeRecordingOverview() {
+
+ RecordingList recordingPeriods = listSoundAcquisitionDatabase();
+
+ RecordingList binaryPeriods = listBinaryFiles();
+
+ long l1 = listDuration(recordingPeriods);
+ long l2 = listDuration(binaryPeriods);
+ if (listDuration(binaryPeriods) > listDuration(recordingPeriods)) {
+ recordingPeriods = binaryPeriods;
+ }
+
+ DeploymentOverview deploymentOverview = createOverview(recordingPeriods);
+
+ return deploymentOverview;
+ }
+
+ private long listDuration(RecordingList recordingList) {
+ if (recordingList == null) {
+ return -1;
+ }
+ return recordingList.duration();
+ }
+
+ public RecordingList listBinaryFiles() {
+ BinaryStore binaryStore = BinaryStore.findBinaryStoreControl();
+ if (binaryStore == null) {
+ return null;
+ }
+ RecordingList bestList = null;
+ ArrayList allBlocks = PamController.getInstance().getDataBlocks();
+ for (PamDataBlock aBlock : allBlocks) {
+ OfflineDataMap dataMap = aBlock.getOfflineDataMap(binaryStore);
+ if (dataMap == null) {
+ continue;
+ }
+ TethysDataProvider tethysProvider = aBlock.getTethysDataProvider(tethysControl);
+ if (tethysProvider == null) {
+ continue; // do we really need this ?
+ }
+ RecordingList blockList = listMapPoints(dataMap);
+ if (blockList == null) {
+ continue;
+ }
+ if (bestList == null) {
+ bestList = blockList;
+ }
+ else {
+ long l1 = bestList.duration();
+ long l2 = blockList.duration();
+ if (l2>l1) {
+ bestList = blockList;
+ }
+ }
+ }
+ bestList = mergeRecordings(bestList);
+ return bestList;
+ }
+
+
+ public RecordingList listMapPoints(OfflineDataMap dataMap) {
+ List mapPoints = dataMap.getMapPoints();
+ if (mapPoints == null) {
+ return null;
+ }
+ RecordingList periods = new RecordingList();
+ for (OfflineDataMapPoint mapPoint : mapPoints) {
+ periods.add(new RecordingPeriod(mapPoint.getStartTime(), mapPoint.getEndTime()));
+ }
+ return periods;
+ }
+
+
+
+ public RecordingList listSoundAcquisitionDatabase() {
+ // first find an acquisition module.
+ PamControlledUnit aModule = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null);
+ if (!(aModule instanceof AcquisitionControl)) {
+ // will return if it's null. Impossible for it to be the wrong type.
+ // but it's good practice to check anyway before casting.
+ return null;
+ }
+ // cast it to the right type.
+ AcquisitionControl daqControl = (AcquisitionControl) aModule;
+ AcquisitionParameters daqParams = daqControl.getAcquisitionParameters();
+ /**
+ * The daqParams class has most of what we need about the set up in terms of sample rate,
+ * number of channels, instrument type, ADC input range (part of calibration), etc.
+ * It also has a hydrophone list, which maps the input channel numbers to the hydrophon numbers.
+ * Realistically, this list is always 0,1,2,etc or it goes horribly wrong !
+ */
+ // so write functions here to get information from the daqParams.
+ // System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(),
+ // daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak);
+ /**
+ * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map
+ * but the datamap is a simple count of what's in the databasase which is not quite what we want.
+ * we're going to have to query the database to get more detailed informatoin I think.
+ * I'll do that here for now, but we may want to move this when we better organise the code.
+ * It also seems that there are 'bad' dates in the database when it starts new files, which are the date
+ * data were analysed at. So we really need to check the start and stop records only.
+ */
+ PamDataBlock daqInfoDataBlock = daqControl.getAcquisitionProcess().getDaqStatusDataBlock();
+ // just load everything. Probably OK for the acqusition, but will bring down
+ daqInfoDataBlock.loadViewerData(0, Long.MAX_VALUE, null);
+ ArrayList allStatusData = daqInfoDataBlock.getDataCopy();
+ /**
+ * Due to weird file overlaps we need to resort this by id if we can.
+ *
+ */
+ Collections.sort(allStatusData, new Comparator() {
+
+ @Override
+ public int compare(DaqStatusDataUnit o1, DaqStatusDataUnit o2) {
+ if (o1.getDatabaseIndex() == 0) {
+ return (int) (o1.getTimeMilliseconds()-o2.getTimeMilliseconds());
+ }
+ return o1.getDatabaseIndex()-o2.getDatabaseIndex();
+ }
+ });
+
+ RecordingList tempPeriods = null;
+
+ if (allStatusData == null || allStatusData.size() == 0) {
+ System.out.println("Data appear to have no logged recording periods. Try to extract from raw audio ...");
+ tempPeriods = extractTimesFromFiles(daqControl);
+ }
+ else {
+ tempPeriods = extractTimesFromStatus(allStatusData);
+ }
+ if (tempPeriods == null || tempPeriods.size() == 0) {
+ System.out.println("Data appear to have no logged recording periods available either from the database or the raw recordings.");
+ tempPeriods = extractTimesFromOutputMaps();
+ }
+ if (tempPeriods == null || tempPeriods.size() == 0) {
+ System.out.println("Data appear to have no logged recording periods available either from the database or the raw recordings.");
+ return null;
+ }
+
+ int nPeriods = tempPeriods.size();
+ // int i = 0;
+ // for (RecordingPeriod aP : tempPeriods) {
+ // System.out.printf("Pre merge %d : %s to %s\n", i++, PamCalendar.formatDBDateTime(aP.getRecordStart()),
+ // PamCalendar.formatDBDateTime(aP.getRecordStop()));
+ // }
+
+ tempPeriods = mergeRecordings(tempPeriods);
+
+ return tempPeriods;
+ }
+
+ /**
+ * Merge close recordings and discard ones that are too short.
+ * @param tempPeriods all recording periods, may be from consecutive files.
+ * @return merged list.
+ */
+ private RecordingList mergeRecordings(RecordingList tempPeriods) {
+ // now go through those and merge into longer periods where there is no gap between files.
+ if (tempPeriods == null) {
+ return null;
+ }
+
+ DeploymentExportOpts exportOptions = tethysControl.getDeploymentHandler().getDeploymentExportOptions();
+
+ ListIterator iterator = tempPeriods.listIterator();
+ RecordingPeriod prevPeriod = null;
+ while (iterator.hasNext()) {
+ RecordingPeriod nextPeriod = iterator.next();
+ long nextDur = nextPeriod.getRecordStop()-nextPeriod.getRecordStart();
+ if (nextDur == 0) {
+ continue;
+ }
+ if (prevPeriod != null) {
+ long gap = nextPeriod.getRecordStart() - prevPeriod.getRecordStop();
+ long prevDur = prevPeriod.getRecordStop()-prevPeriod.getRecordStart();
+ if (gap < exportOptions.maxRecordingGapSeconds*1000) {
+ // ignoring up to 3s gap or a sample error < 2%.Dunno if this is sensible or not.
+ prevPeriod.setRecordStop(nextPeriod.getRecordStop());
+ iterator.remove();
+ nextPeriod = prevPeriod;
+ }
+ }
+ prevPeriod = nextPeriod;
+ }
+ // now remove ones which are too short even after merging.
+ iterator = tempPeriods.listIterator();
+ while (iterator.hasNext()) {
+ RecordingPeriod nextPeriod = iterator.next();
+ long duration = nextPeriod.getDuration();
+ if (duration < exportOptions.minRecordingLengthSeconds*1000L) {
+ iterator.remove();
+ }
+ }
+
+ return tempPeriods;
+ }
+
+ /**
+ * Work out whether or not the data are evenly duty cycled by testing the
+ * distributions of on and off times.
+ * @param tempPeriods
+ * @return
+ */
+ private DutyCycleInfo assessDutyCycle(RecordingList tempPeriods) {
+ if (tempPeriods == null) {
+ return null;
+ }
+ int n = tempPeriods.size();
+ if (n < 2) {
+ return new DutyCycleInfo(false, 0,0,n);
+ }
+ double[] ons = new double[n-1]; // ignore the last one since it may be artificially shortened which is OK
+ double[] gaps = new double[n-1];
+ for (int i = 0; i < n-1; i++) {
+ ons[i] = tempPeriods.get(i).getDuration()/1000.;
+ gaps[i] = (tempPeriods.get(i+1).getRecordStart()-tempPeriods.get(i).getRecordStop())/1000.;
+ }
+ /* now look at how consistent those values are
+ * But some data gets messed by small gaps, so want to
+ * remove outliers and concentrate on say 80% of the data.
+ */
+ ons = getDistributionCentre(ons, 80);
+ gaps = getDistributionCentre(gaps, 80);
+ Arrays.sort(gaps);
+
+
+ STD std = new STD();
+ double onsMean = std.getMean(ons);
+ double onsSTD = std.getSTD(ons);
+ double gapsMean = std.getMean(gaps);
+ double gapsSTD = std.getSTD(gaps);
+ boolean dutyCycle = onsSTD/onsMean < .05 && gapsSTD/gapsMean < 0.05;
+ DutyCycleInfo cycleInfo = new DutyCycleInfo(dutyCycle, onsMean, gapsMean, tempPeriods.size());
+ return cycleInfo;
+ }
+
+ /**
+ * Get the central part of a distribution without any outliers so
+ * that we can get a better assessment of duty cycle.
+ * @param data unsorted distribution data.
+ * @param percent percentage to include (half this removed from top and bottom)
+ * @return
+ */
+ private double[] getDistributionCentre(double[] data, double percent) {
+ if (data == null) {
+ return null;
+ }
+ Arrays.sort(data);
+ int nRem = (int) Math.round(data.length * (100-percent)/200);
+ int newLen = data.length-nRem*2;
+ double[] subdata = Arrays.copyOfRange(data, nRem, data.length-2*nRem);
+ if (subdata.length < 2) {
+ return data;
+ }
+ return subdata;
+ }
+
+
+ /**
+ * Get data times from any other datamap, since this will generally match the acquisition anyway
+ * @return
+ */
+ private RecordingList extractTimesFromOutputMaps() {
+ OfflineDataMap bestMap = null;
+ PamDataBlock bestBlock = null;
+ long firstStart = Long.MAX_VALUE;
+ long lastEnd = Long.MIN_VALUE;
+ ArrayList dataBlocks = PamController.getInstance().getDetectorDataBlocks();
+ for (PamDataBlock aBlock : dataBlocks) {
+ if (aBlock instanceof PamRawDataBlock) {
+ continue; // don't want acquisition !
+ }
+ OfflineDataMap dataMap = aBlock.getPrimaryDataMap();
+ if (dataMap == null) {
+ continue;
+ }
+ if (dataMap.getFirstDataTime() < firstStart && dataMap.getLastDataTime() > lastEnd) {
+ bestMap = dataMap;
+ bestBlock = aBlock;
+ firstStart = dataMap.getFirstDataTime();
+ lastEnd = dataMap.getLastDataTime();
+ }
+ }
+ if (bestMap == null) {
+ return null;
+ }
+ // get the times out of it.
+ RecordingList recPeriods = new RecordingList();
+ List mapPoints = bestMap.getMapPoints();
+ for (OfflineDataMapPoint mapPoint : mapPoints) {
+ recPeriods.add(new RecordingPeriod(mapPoint.getStartTime(), mapPoint.getEndTime()));
+ }
+ return recPeriods;
+ }
+
+ private RecordingList extractTimesFromStatus(ArrayList allStatusData) {
+ RecordingList tempPeriods = new RecordingList();
+ long dataStart = Long.MAX_VALUE;
+ long dataEnd = Long.MIN_VALUE;
+ Long lastStart = null;
+ int nStart = 0;
+ int nStop = 0;
+ int nFile = 0;
+ for (DaqStatusDataUnit daqStatus : allStatusData) {
+ switch (daqStatus.getStatus()) {
+ case "Start":
+ nStart++;
+ dataStart = Math.min(dataStart, daqStatus.getTimeMilliseconds());
+ lastStart = daqStatus.getTimeMilliseconds();
+ // System.out.println("Start at " + PamCalendar.formatDBDateTime(lastStart));
+ break;
+ case "Stop":
+ nStop++;
+ dataEnd = Math.max(dataEnd, daqStatus.getEndTimeInMilliseconds());
+ long lastEnd = daqStatus.getEndTimeInMilliseconds();
+ if (lastStart != null) {
+ // System.out.printf("Adding period %s to %s\n", PamCalendar.formatDBDateTime(lastStart),
+ // PamCalendar.formatDBDateTime(lastEnd));
+ tempPeriods.add(new RecordingPeriod(lastStart, lastEnd));
+ }
+ else {
+ // System.out.println("Skipping stop at " + PamCalendar.formatDBDateTime(lastEnd));
+ }
+ lastStart = null;
+ break;
+ case "NextFile":
+ nFile++;
+ break;
+ }
+ }
+ return tempPeriods;
+ }
+
+ private RecordingList extractTimesFromFiles(AcquisitionControl daqControl) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/src/tethys/deployment/PInstrument.java b/src/tethys/deployment/PInstrument.java
new file mode 100644
index 00000000..15fd3c31
--- /dev/null
+++ b/src/tethys/deployment/PInstrument.java
@@ -0,0 +1,49 @@
+package tethys.deployment;
+
+/**
+ * Class to handle instrument information
+ * @author dg50
+ *
+ */
+public class PInstrument {
+
+ public String instrumentType;
+
+ public String instrumentId;
+
+ public PInstrument(String instrumentType, String instrumentId) {
+ super();
+ this.instrumentType = instrumentType;
+ this.instrumentId = instrumentId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PInstrument == false) {
+ return false;
+ }
+ PInstrument other = (PInstrument) obj;
+ boolean eq = true;
+ if (this.instrumentType != null) {
+ eq &= this.instrumentType.equals(other.instrumentType);
+ }
+ if (this.instrumentId != null) {
+ eq &= this.instrumentId.equals(other.instrumentId);
+ }
+ if (other.instrumentType != null) {
+ eq &= other.instrumentType.equals(this.instrumentType);
+ }
+ if (other.instrumentId != null) {
+ eq &= other.instrumentId.equals(this.instrumentId);
+ }
+
+ return eq;
+
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s : %s", instrumentType == null ? "Undefined" : instrumentType, instrumentId);
+ }
+
+}
diff --git a/src/tethys/deployment/PamDeployment.java b/src/tethys/deployment/PamDeployment.java
new file mode 100644
index 00000000..24a17065
--- /dev/null
+++ b/src/tethys/deployment/PamDeployment.java
@@ -0,0 +1,64 @@
+package tethys.deployment;
+
+import java.io.Serializable;
+
+//import nilus.DeploymentRecoveryDetails;
+
+/**
+ * Wrapper and functions associated with the Tethys Deployment object which can
+ * exchange these with the PAMGuard database and display Everything is just held
+ * within a list, in no particular order, which getContent public
+ *
+ * This is from the Deployment JavaDoc. TBH it's pretty horrible, since it's possible to have
+ * more than one of each type of object in the list, so not sure what to do about that. Would be nicer
+ * as a HashTable. however we are where we're are for now. Start by focussing on getting the
+ * content saved for each type
+ *
+ * List getContent()
+ *
+ * Gets the value of the content property. This accessor method returns a
+ * reference to the live list,not a snapshot. Therefore any modification you
+ * make to the returned list will be present inside the JAXB object.This is why
+ * there is not a set method for the content property.
+ *
+ * For example, to add a new item, do as follows: getContent().add(newItem);
+ *
+ *
+ * Objects of the following type(s) are allowed in the list JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement
+ * JAXBElement String
+ * JAXBElement