diff --git a/.classpath b/.classpath index a66e1b06..49faf461 100644 --- a/.classpath +++ b/.classpath @@ -6,9 +6,8 @@ - + - diff --git a/.gitignore b/.gitignore index 1cbbf601..76213268 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,9 @@ # eclipse project file .project -.hprof +# hprof memory analyser files. +*.hprof +java_pid*.* # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 9ba4622d..7b5e9ffa 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -11,9 +11,9 @@ org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=16 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=16 +org.eclipse.jdt.core.compiler.compliance=17 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -22,5 +22,5 @@ org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning -org.eclipse.jdt.core.compiler.release=disabled -org.eclipse.jdt.core.compiler.source=16 +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/repo/tethys/org/nilus/3.1 - July24/_remote.repositories b/repo/tethys/org/nilus/3.1 - July24/_remote.repositories new file mode 100644 index 00000000..e575e75f --- /dev/null +++ b/repo/tethys/org/nilus/3.1 - July24/_remote.repositories @@ -0,0 +1,4 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +#Tue Jul 16 19:29:56 BST 2024 +nilus-3.1.jar>= +nilus-3.1.pom>= diff --git a/repo/tethys/org/nilus/3.1 - July24/nilus-3.1-javadoc.jar b/repo/tethys/org/nilus/3.1 - July24/nilus-3.1-javadoc.jar new file mode 100644 index 00000000..3e6f7e64 Binary files /dev/null and b/repo/tethys/org/nilus/3.1 - July24/nilus-3.1-javadoc.jar differ diff --git a/repo/tethys/org/nilus/3.1 - July24/nilus-3.1.jar b/repo/tethys/org/nilus/3.1 - July24/nilus-3.1.jar new file mode 100644 index 00000000..1436b464 Binary files /dev/null and b/repo/tethys/org/nilus/3.1 - July24/nilus-3.1.jar differ diff --git a/repo/tethys/org/nilus/3.1 - July24/nilus-3.1.pom b/repo/tethys/org/nilus/3.1 - July24/nilus-3.1.pom new file mode 100644 index 00000000..cff3acf1 --- /dev/null +++ b/repo/tethys/org/nilus/3.1 - July24/nilus-3.1.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + tethys.org + nilus + 3.1 + POM was created from install:install-file + diff --git a/repo/tethys/org/nilus/3.1/_remote.repositories b/repo/tethys/org/nilus/3.1/_remote.repositories index e575e75f..6a1e6f59 100644 --- a/repo/tethys/org/nilus/3.1/_remote.repositories +++ b/repo/tethys/org/nilus/3.1/_remote.repositories @@ -1,4 +1,4 @@ #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. -#Tue Jul 16 19:29:56 BST 2024 +#Fri Aug 16 08:59:15 BST 2024 nilus-3.1.jar>= nilus-3.1.pom>= diff --git a/repo/tethys/org/nilus/3.1/m2e-lastUpdated.properties b/repo/tethys/org/nilus/3.1/m2e-lastUpdated.properties new file mode 100644 index 00000000..3ba9e3c0 --- /dev/null +++ b/repo/tethys/org/nilus/3.1/m2e-lastUpdated.properties @@ -0,0 +1,8 @@ +#Fri Aug 02 15:37:21 BST 2024 +repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|sources=1722609441199 +github|douggillespie|https\://maven.pkg.github.com/douggillespie/xbee-java|sources=1722609441199 +central|https\://repo1.maven.org/maven2|sources=1722609441199 +talan|https\://nexus.talanlabs.com/content/repositories/releases/|sources=1722609441199 +bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|sources=1722609441199 +unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|sources=1722609441199 +repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo|sources=1721155730840 diff --git a/repo/tethys/org/nilus/3.1/nilus-3.1-javadoc.jar b/repo/tethys/org/nilus/3.1/nilus-3.1-javadoc.jar index 3e6f7e64..b7a98646 100644 Binary files a/repo/tethys/org/nilus/3.1/nilus-3.1-javadoc.jar and b/repo/tethys/org/nilus/3.1/nilus-3.1-javadoc.jar differ diff --git a/repo/tethys/org/nilus/3.1/nilus-3.1-sources.jar.lastUpdated b/repo/tethys/org/nilus/3.1/nilus-3.1-sources.jar.lastUpdated new file mode 100644 index 00000000..b12d0313 --- /dev/null +++ b/repo/tethys/org/nilus/3.1/nilus-3.1-sources.jar.lastUpdated @@ -0,0 +1,16 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +#Fri Aug 02 15:37:21 BST 2024 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1721155730838 +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1722609441195 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1721155730561 +https\://repo1.maven.org/maven2/.lastUpdated=1721155729103 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:nilus\:jar\:sources\:3.1 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +https\://maven.pkg.github.com/douggillespie/xbee-java/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1721155729822 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1721155730818 +https\://maven.pkg.github.com/douggillespie/xbee-java/.lastUpdated=1721155729785 diff --git a/repo/tethys/org/nilus/3.1/nilus-3.1.jar b/repo/tethys/org/nilus/3.1/nilus-3.1.jar index 1436b464..5fb5fd80 100644 Binary files a/repo/tethys/org/nilus/3.1/nilus-3.1.jar and b/repo/tethys/org/nilus/3.1/nilus-3.1.jar differ diff --git a/src/Acquisition/AcquisitionProcess.java b/src/Acquisition/AcquisitionProcess.java index e26f7b34..338d484b 100644 --- a/src/Acquisition/AcquisitionProcess.java +++ b/src/Acquisition/AcquisitionProcess.java @@ -77,7 +77,7 @@ public class AcquisitionProcess extends PamProcess { protected PamRawDataBlock rawDataBlock; - private PamDataBlock daqStatusDataBlock; + private DaqStatusDataBlock daqStatusDataBlock; AcquisitionProcess acquisitionProcess; @@ -125,12 +125,11 @@ public class AcquisitionProcess extends PamProcess { // PamUtils.makeChannelMap(acquisitionControl.acquisitionParameters.nChannels), // acquisitionControl.acquisitionParameters.sampleRate)); - addOutputDataBlock(rawDataBlock = new PamRawDataBlock(name, this, //Xiao Yan Deng + addOutputDataBlock(rawDataBlock = new PamRawDataBlock(name, this, PamUtils.makeChannelMap(acquisitionControl.acquisitionParameters.nChannels,acquisitionControl.acquisitionParameters.getHardwareChannelList()), acquisitionControl.acquisitionParameters.sampleRate)); - - daqStatusDataBlock = new PamDataBlock(DaqStatusDataUnit.class, acquisitionControl.getUnitName(), + daqStatusDataBlock = new DaqStatusDataBlock(acquisitionControl.getUnitName(), this, 0); // daqStatusDataBlock. addOutputDataBlock(daqStatusDataBlock); @@ -1241,6 +1240,9 @@ public class AcquisitionProcess extends PamProcess { } public InputStoreInfo getStoreInfo(boolean detail) { + if (runningSystem == null) { + runningSystem = acquisitionControl.findDaqSystem(null); + } if (runningSystem instanceof DataInputStore) { return ((DataInputStore) runningSystem).getStoreInfo(detail); } diff --git a/src/Acquisition/DaqStatusDataBlock.java b/src/Acquisition/DaqStatusDataBlock.java new file mode 100644 index 00000000..21b8ded5 --- /dev/null +++ b/src/Acquisition/DaqStatusDataBlock.java @@ -0,0 +1,23 @@ +package Acquisition; + +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamProcess; +import dataMap.OfflineDataMap; +import effort.EffortProvider; +import effort.binary.DataMapEffortProvider; +import generalDatabase.DBControlUnit; + +public class DaqStatusDataBlock extends PamDataBlock { + + public DaqStatusDataBlock(String dataName, PamProcess parentProcess, int channelMap) { + super(DaqStatusDataUnit.class, dataName, parentProcess, channelMap); + } + + @Override + public EffortProvider autoEffortProvider() { + // make a provider which will pick up on the database data. + // db data are written every 60s, so put 62s as max gap. + return new DataMapEffortProvider(this, DBControlUnit.class, 62000L); + } + +} diff --git a/src/Acquisition/FolderInputSystem.java b/src/Acquisition/FolderInputSystem.java index 7f777aa1..912810b0 100644 --- a/src/Acquisition/FolderInputSystem.java +++ b/src/Acquisition/FolderInputSystem.java @@ -945,8 +945,12 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D InputStoreInfo storeInfo = new InputStoreInfo(acquisitionControl, allFiles.size(), firstFileStart, lastFileStart, lastFileEnd); if (detail) { long[] allFileStarts = new long[allFiles.size()]; + long[] allFileEnds = new long[allFiles.size()]; for (int i = 0; i < allFiles.size(); i++) { - allFileStarts[i] = getFileStartTime(allFiles.get(i).getAbsoluteFile()); + WavFileType aFile = allFiles.get(i); + allFileStarts[i] = getFileStartTime(aFile.getAbsoluteFile()); + aFile.getAudioInfo(); + allFileEnds[i] = (allFileStarts[i] + (long) (aFile.getDurationInSeconds()*1000.)); if (allFileStarts[i] < firstFileStart) { // System.out.printf("Swap first file from %s to %s\n", firstFile.getName(), allFiles.get(i).getName()); firstFile = allFiles.get(i); @@ -961,6 +965,7 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D storeInfo.setFirstFileStart(firstFileStart); // just incase changed. storeInfo.setLastFileEnd(lastFileEnd); // just incase changed storeInfo.setFileStartTimes(allFileStarts); + storeInfo.setFileEndTimes(allFileEnds); } return storeInfo; } diff --git a/src/GPS/GPSDataBlock.java b/src/GPS/GPSDataBlock.java index d9a4a521..fc0f8f84 100644 --- a/src/GPS/GPSDataBlock.java +++ b/src/GPS/GPSDataBlock.java @@ -2,6 +2,7 @@ package GPS; import java.util.ListIterator; +import GPS.effort.GpsEffortProvider; import nmeaEmulator.EmulatedData; import nmeaEmulator.NMEAEmulator; import pamScrollSystem.ViewLoadObserver; @@ -37,6 +38,7 @@ public class GPSDataBlock extends PamDataBlock implements NMEAEmula public GPSDataBlock(PamProcess process) { super(GpsDataUnit.class, process.getPamControlledUnit().getUnitName(), process, 1); setSynchLock(NavDataSynchronisation.getSynchobject()); + setEffortProvider(new GpsEffortProvider(this)); } @Override diff --git a/src/GPS/effort/GpsEffortProvider.java b/src/GPS/effort/GpsEffortProvider.java new file mode 100644 index 00000000..2661f332 --- /dev/null +++ b/src/GPS/effort/GpsEffortProvider.java @@ -0,0 +1,96 @@ +package GPS.effort; + +import java.util.ArrayList; +import java.util.List; + +import GPS.GPSDataBlock; +import PamView.symbol.PamSymbolManager; +import PamguardMVC.PamDataUnit; +import PamguardMVC.dataSelector.DataSelector; +import dataMap.OfflineDataMap; +import effort.EffortDataUnit; +import effort.EffortProvider; + +public class GpsEffortProvider extends EffortProvider { + + private GPSDataBlock gpsDataBlock; + + private GpsEffortSymbolManager effortSymbolManager; + + private EffortDataUnit realTimeData; + + public GpsEffortProvider(GPSDataBlock parentDataBlock) { + super(parentDataBlock); + this.gpsDataBlock = parentDataBlock; + effortSymbolManager = new GpsEffortSymbolManager(gpsDataBlock); + } + + @Override + public EffortDataUnit getEffort(long timeMilliseconds) { + return getSingleEffort(); + } + + @Override + public List getAllEffortThings() { + EffortDataUnit singleEff = getSingleEffort(); + ArrayList effList = new ArrayList<>(1); + if (singleEff != null) { + effList.add(singleEff); + } + return effList; + } + + @Override + public DataSelector getDataSelector(String selectorName) { + return null; + } + + @Override + public PamSymbolManager getSymbolManager() { + return effortSymbolManager; + } + + private EffortDataUnit getSingleEffort() { + if (!isViewer()) { + return realTimeData; + } + OfflineDataMap dataMap = gpsDataBlock.getPrimaryDataMap(); + if (dataMap == null) { + return null; + } + EffortDataUnit effData = new EffortDataUnit(this, null, dataMap.getFirstDataTime(), dataMap.getLastDataTime()); + return effData; + } + + @Override + public String getName() { + return gpsDataBlock.getDataName(); + } + + @Override + public void realTimeStart(long timeMilliseconds) { + // Do nothing + } + + @Override + public void realTimeStop(long timeMilliseconds) { + // Do nothing + } + + @Override + public void newData(PamDataUnit pamDataUnit) { + if (realTimeData == null) { + realTimeData = new EffortDataUnit(this,null,pamDataUnit.getTimeMilliseconds(), pamDataUnit.getTimeMilliseconds()); + } + else { + realTimeData.setEffortEnd(pamDataUnit.getTimeMilliseconds()); + } + } + + @Override + public void viewerLoadData() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/GPS/effort/GpsEffortSymbolManager.java b/src/GPS/effort/GpsEffortSymbolManager.java new file mode 100644 index 00000000..aff23bd0 --- /dev/null +++ b/src/GPS/effort/GpsEffortSymbolManager.java @@ -0,0 +1,22 @@ +package GPS.effort; + +import java.awt.Color; + +import PamView.PamColors; +import PamView.PamSymbolType; +import PamView.PamColors.PamColor; +import PamView.symbol.StandardSymbolManager; +import PamView.symbol.SymbolData; +import PamView.symbol.SymbolOnlyManager; +import PamguardMVC.PamDataBlock; + +public class GpsEffortSymbolManager extends SymbolOnlyManager { + + private static Color defColour = PamColors.getInstance().getColor(PamColor.GPSTRACK); + private static SymbolData defaultSymbol = new SymbolData(PamSymbolType.SYMBOL_LINESEGMENT, 10, 10, false, defColour, defColour); + + public GpsEffortSymbolManager(PamDataBlock pamDataBlock) { + super(pamDataBlock, defaultSymbol); + } + +} diff --git a/src/Localiser/LocalisationAlgorithm.java b/src/Localiser/LocalisationAlgorithm.java index 9c81557e..0da30c5f 100644 --- a/src/Localiser/LocalisationAlgorithm.java +++ b/src/Localiser/LocalisationAlgorithm.java @@ -1,9 +1,6 @@ package Localiser; -import java.io.Serializable; - -import PamDetection.LocContents; -import PamDetection.LocalisationInfo; +import tethys.localization.LocalizationCreator; /** * Interface to attach to localisation algorithms which can provide basic information @@ -19,4 +16,12 @@ public interface LocalisationAlgorithm { */ public LocalisationAlgorithmInfo getAlgorithmInfo(); + /** + * Get something that can make LocalisationType objects of a form + * a bit bespoke to the type of localiser. This may be better than having + * the standard functions in LocalizationBuilder guess what's best. + * @return can be null in which case standard functions will do the best they can. + */ + public LocalizationCreator getTethysCreator(); + } diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/CombinedBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/CombinedBearingLocaliser.java index 85549569..77f4cd33 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/CombinedBearingLocaliser.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/CombinedBearingLocaliser.java @@ -5,6 +5,7 @@ import java.io.Serializable; import Localiser.LocalisationAlgorithmInfo; import PamDetection.LocContents; import pamMaths.PamVector; +import tethys.localization.LocalizationCreator; @Deprecated public class CombinedBearingLocaliser implements BearingLocaliser { @@ -86,4 +87,10 @@ public class CombinedBearingLocaliser implements BearingLocaliser { return this; } + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/LSQBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/LSQBearingLocaliser.java index bc422c97..a1e74b63 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/LSQBearingLocaliser.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/LSQBearingLocaliser.java @@ -11,6 +11,7 @@ import Localiser.LocalisationAlgorithmInfo; import PamDetection.LocContents; import PamUtils.PamUtils; import pamMaths.PamVector; +import tethys.localization.LocalizationCreator; public class LSQBearingLocaliser implements BearingLocaliser { @@ -232,4 +233,10 @@ public class LSQBearingLocaliser implements BearingLocaliser { public LocalisationAlgorithmInfo getAlgorithmInfo() { return this; } + + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser.java index 643f0344..210989cc 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser.java @@ -13,6 +13,7 @@ import PamUtils.ArrayDump; import PamUtils.PamUtils; import PamUtils.SystemTiming; import pamMaths.PamVector; +import tethys.localization.LocalizationCreator; /** * Maximum likelihood bearing localiser to get bearings from a closely @@ -652,4 +653,10 @@ public class MLGridBearingLocaliser implements BearingLocaliser { public LocalisationAlgorithmInfo getAlgorithmInfo() { return this; } + + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser2.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser2.java index 3eb77f75..e7dd4f79 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser2.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/MLGridBearingLocaliser2.java @@ -15,6 +15,7 @@ import PamUtils.ArrayDump; import PamUtils.PamUtils; import PamUtils.SystemTiming; import pamMaths.PamVector; +import tethys.localization.LocalizationCreator; import tethys.pamdata.AutoTethysProvider; /** @@ -761,6 +762,12 @@ public class MLGridBearingLocaliser2 implements BearingLocaliser { public LocalisationAlgorithmInfo getAlgorithmInfo() { return this; } + + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } /** * For passing to Tethys output. diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java index 76a3dd68..3ac51b48 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java @@ -11,6 +11,7 @@ import Localiser.LocalisationAlgorithmInfo; import PamDetection.LocContents; import PamUtils.PamUtils; import pamMaths.PamVector; +import tethys.localization.LocalizationCreator; /** * Really simple BearingLocaliser which works with two element closely @@ -309,4 +310,9 @@ public class PairBearingLocaliser implements BearingLocaliser { public LocalisationAlgorithmInfo getAlgorithmInfo() { return this; } + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/SimplexBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/SimplexBearingLocaliser.java index 59b2ca0a..c701b058 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/SimplexBearingLocaliser.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/SimplexBearingLocaliser.java @@ -19,6 +19,7 @@ import Localiser.LocalisationAlgorithmInfo; import PamDetection.LocContents; import PamUtils.PamUtils; import pamMaths.PamVector; +import tethys.localization.LocalizationCreator; @Deprecated public class SimplexBearingLocaliser implements BearingLocaliser { @@ -250,6 +251,12 @@ public class SimplexBearingLocaliser implements BearingLocaliser { return this; } + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } + @Override public Serializable getParameters() { return null; diff --git a/src/Map/MapPanel.java b/src/Map/MapPanel.java index cc00acd2..e18e67af 100644 --- a/src/Map/MapPanel.java +++ b/src/Map/MapPanel.java @@ -38,6 +38,7 @@ import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Vector; @@ -83,6 +84,7 @@ import PamView.paneloverlay.overlaymark.MarkOverlayDraw; import PamView.symbol.PamSymbolChooser; import PamView.symbol.PamSymbolManager; import PamView.symbol.SymbolData; +import PamView.symbol.modifier.SymbolModifier; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import PamguardMVC.PamObservable; @@ -90,6 +92,8 @@ import PamguardMVC.PamObserver; import PamguardMVC.dataSelector.DataSelectDialog; import PamguardMVC.dataSelector.DataSelector; import PamguardMVC.debug.Debug; +import effort.EffortDataUnit; +import effort.EffortProvider; import pamMaths.PamVector; /** @@ -131,6 +135,8 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana private AffineTransform baseXform; private boolean repaintBase = false; + + private EffortDataUnit latestEffort; public MapPanel(MapController mapController, SimpleMap simpleMap) { this.mapController = mapController; @@ -786,6 +792,7 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana private GpsDataUnit lastDrawGpsDataUnit; private Coordinate3d lastGpsCoodinate; + private PamSymbol latestSymbol; long getMapStartTime() { switch (PamController.getInstance().getRunMode()) { @@ -797,22 +804,70 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana } return PamCalendar.getTimeInMillis(); } + + public EffortProvider findEffortProvider() { + if (simpleMapRef.mapParameters.colourByEffort == false) { + return null; + } + if (simpleMapRef.effortDataBlock == null) { + return null; + } + return simpleMapRef.effortDataBlock.getEffortProvider(); + } private void paintTrack(Graphics g, PamDataUnit lastDrawnUnit) { - long mapStartTime = getMapStartTime(); - g.setColor(PamColors.getInstance().getColor(PamColor.GPSTRACK)); + + GPSDataBlock gpsDataBlock = simpleMapRef.getGpsDataBlock(); + if (gpsDataBlock == null) { + return; + } + PamSymbolChooser symbolModifier = null; + List effortThings = null; + EffortDataUnit currentEffortThing = null; + EffortProvider effortProvider = findEffortProvider(); + PamSymbol effortSymbol = null; + Iterator effortIterator = null; + if (effortProvider != null) { + symbolModifier = effortProvider.getSymbolChooser(simpleMapRef.getSelectorName(), rectProj); + effortThings = effortProvider.getAllEffortThings(); + if (effortThings == null || effortThings.size() == 0) { + effortThings = null; + } + else { + effortIterator = effortThings.iterator(); + } + if (effortIterator != null && effortIterator.hasNext()) { + currentEffortThing = effortIterator.next(); + if (symbolModifier != null) { +// effortSymbol = symbolModifier.getPamSymbol(rectProj, currentEffortThing); + effortSymbol = effortProvider.getPamSymbol(symbolModifier, currentEffortThing); + latestEffort = currentEffortThing; + latestSymbol = effortSymbol; + } + } + } Graphics2D g2d = (Graphics2D) g; - g2d.setStroke(new BasicStroke(1)); + long mapStartTime = getMapStartTime(); + Color defaultColour = PamColors.getInstance().getColor(PamColor.GPSTRACK); + if (effortSymbol != null) { + g2d.setStroke(new BasicStroke(effortSymbol.getLineThickness())); + } + else { + g2d.setStroke(new BasicStroke(1)); + } + if (effortSymbol != null && mapStartTime > currentEffortThing.getEffortStart()) { + g.setColor(effortSymbol.getLineColor()); + } + else { + g.setColor(defaultColour); + } + // GPSControl gpsControl = GPSControl.getGpsControl(); // if (gpsControl == null) { // return; // } // PamDataBlock gpsDataBlock = gpsControl.getGpsDataBlock(); - GPSDataBlock gpsDataBlock = simpleMapRef.getGpsDataBlock(); - if (gpsDataBlock == null) { - return; - } long t1 = getMapStartTime(), t2 = Long.MAX_VALUE; if (PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW) { t1 = simpleMapRef.getViewerScroller().getMinimumMillis(); @@ -826,13 +881,48 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana GpsDataUnit dataUnit; synchronized (gpsDataBlock.getSynchLock()) { ListIterator gpsIterator = gpsDataBlock.getListIterator(0); + dataUnit = gpsIterator.next(); + if (gpsIterator.hasNext()) { - dataUnit = gpsIterator.next(); + gpsData = dataUnit.getGpsData(); lastFixTime = dataUnit.getTimeMilliseconds(); + + + c1 = rectProj.getCoord3d(gpsData.getLatitude(), gpsData.getLongitude(), 0.); while (gpsIterator.hasNext()) { dataUnit = gpsIterator.next(); + + // sort out effort colours. +// if (currentEffortThing != null) { + while (currentEffortThing != null && dataUnit.getTimeMilliseconds() > currentEffortThing.getEffortEnd()) { + // get the next one. then decide if we're in or not. + if (effortIterator.hasNext()) { + currentEffortThing = effortIterator.next(); + if (symbolModifier != null) { + effortSymbol = effortProvider.getPamSymbol(symbolModifier, currentEffortThing); + } + } + else { + break; + } +// else { +// currentEffortThing = null; +// effortSymbol = null; +// } + } +// } + if (effortSymbol != null && currentEffortThing.inEffort(dataUnit.getTimeMilliseconds())) { + g.setColor(effortSymbol.getLineColor()); + latestEffort = currentEffortThing; + latestSymbol = effortSymbol; + } + else { + g.setColor(defaultColour); +// latestSymbol = null; + } + gpsData = dataUnit.getGpsData(); if (gpsData.isDataOk() == false) { continue; @@ -909,7 +999,41 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana private void paintNewGPSData(Graphics g, GpsDataUnit newGpsDataUnit) { Coordinate3d c2; - g.setColor(PamColors.getInstance().getColor(PamColor.GPSTRACK)); +// g.setColor(PamColors.getInstance().getColor(PamColor.GPSTRACK)); +// if (latestSymbol != null) { +// float t = latestSymbol.getLineThickness(); +// if (t != 1) { +// Graphics2D g2d = (Graphics2D) g; +// g2d.setStroke(new BasicStroke(t)); +// } +// if (latestEffort != null && latestEffort.inEffort(newGpsDataUnit.getTimeMilliseconds())) { +// g.setColor(latestSymbol.getLineColor()); +// } +// } +// else { + EffortProvider effortProvider = findEffortProvider(); + boolean effSet = false; + if (effortProvider != null) { + latestEffort = effortProvider.getLastEffort(); + if (latestEffort != null) { + PamSymbolChooser symbolModifier = effortProvider.getSymbolChooser(simpleMapRef.getSelectorName(), rectProj); + if (symbolModifier != null) { + PamSymbol symbol = effortProvider.getPamSymbol(symbolModifier, latestEffort); +// PamSymbol symbol = symbolModifier.getPamSymbol(rectProj, latestEffort); + if (symbol != null && latestEffort.inEffort(newGpsDataUnit.getTimeMilliseconds())) { + symbol.getSymbolData().setGraphicsProperties(g); + effSet = true; + } + } + } + } + if (!effSet) { + g.setColor(PamColors.getInstance().getColor(PamColor.GPSTRACK)); + } + /** + * This can get quite long, so need to do the same iterating through the effort data as for normal plotting. + */ + GpsData gpsData = newGpsDataUnit.getGpsData(); c2 = rectProj.getCoord3d(gpsData.getLatitude(), gpsData.getLongitude(), 0.); if (lastGpsCoodinate != null) { @@ -1055,7 +1179,7 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana mapDrawingOptions = null; rectProj.setProjectorDrawingOptions(null); } - DataSelector ds = dataBlock.getDataSelector(simpleMapRef.getUnitName(), false, DATASELECTNAME); + DataSelector ds = dataBlock.getDataSelector(simpleMapRef.getSelectorName(), false, DATASELECTNAME); rectProj.setDataSelector(ds); // see if the datablock has a symbol manager. PamSymbolManager symbolManager = dataBlock.getPamSymbolManager(); @@ -1252,13 +1376,21 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana @Override public void addData(PamObservable o, PamDataUnit arg) { - +// if (arg instanceof EffortDataUnit) { + // won't work since only the data send notifications. +// System.out.println("Effort add, so repaint base"); +// repaintBaseDrawing(); +// } // PamDataBlock block = (PamDataBlock) o; repaint(250); } @Override public void updateData(PamObservable observable, PamDataUnit pamDataUnit) { +// if (pamDataUnit instanceof EffortDataUnit) { +// System.out.println("Effort update, so repaint base"); +// repaintBaseDrawing(); +// } repaint(250); } @@ -1340,6 +1472,10 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana aBlock.addObserver(this); } } + EffortProvider effBlock = findEffortProvider(); + if (effBlock != null) { + effBlock.getParentDataBlock().addObserver(this); + } } protected void createKey() { @@ -1852,6 +1988,27 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana this.mapController = mapController; } + @Override + public String getToolTipText(MouseEvent event) { + String tip = super.getToolTipText(event); + if (tip == null) { + return tip; + } + if (tip.startsWith("GPS") == false) { + return tip; + } + + return tip; + } + + public EffortDataUnit findEffortThing(long timeMilliseconds) { + EffortProvider effortProvider = findEffortProvider(); + if (effortProvider == null) { + return null; + } + return effortProvider.getEffort(timeMilliseconds); + } + } diff --git a/src/Map/MapParameters.java b/src/Map/MapParameters.java index 11baeb07..77bf309e 100644 --- a/src/Map/MapParameters.java +++ b/src/Map/MapParameters.java @@ -95,6 +95,12 @@ public class MapParameters implements Serializable, Cloneable, ManagedParameters public int symbolSize = Hydrophone.DefaultSymbolSize; + public boolean colourByEffort = false; + /** + * Name of data block providing effort data. + */ + public String effortDataSource; + private static final int defaultMapRange = 10000; /** * Value to store persistently between runs. diff --git a/src/Map/MapParametersDialog.java b/src/Map/MapParametersDialog.java index 03d77300..20a9c0c0 100644 --- a/src/Map/MapParametersDialog.java +++ b/src/Map/MapParametersDialog.java @@ -31,7 +31,12 @@ import Array.Hydrophone; import Map.gridbaselayer.GridDialogPanel; import PamView.dialog.PamDialog; import PamView.dialog.PamGridBagContraints; +import PamView.dialog.SettingsButton; +import PamView.dialog.SourcePanel; import PamView.panel.PamNorthPanel; +import PamguardMVC.PamDataBlock; +import effort.EffortProvider; +import effort.swing.EffortSourcePanel; @@ -64,6 +69,8 @@ public class MapParametersDialog extends PamDialog { private JCheckBox headingUp = new JCheckBox("Ship heading always up"); private JCheckBox showSurface = new JCheckBox("Show sea surface"); + + private JCheckBox colourByEffort = new JCheckBox("Colour track-line by efort"); private MapFileManager mapFileManager; @@ -78,6 +85,10 @@ public class MapParametersDialog extends PamDialog { public JCheckBox showGrid; private SimpleMap simpleMap; + + private EffortSourcePanel effortSourcePanel; + + private SettingsButton effortSettings; private MapParametersDialog(java.awt.Window parentFrame, SimpleMap simpleMap) { @@ -110,15 +121,21 @@ public class MapParametersDialog extends PamDialog { setDialogComponent(tabbedPane); setHelpPoint("mapping.mapHelp.docs.overview"); // this.enableHelpButton(true); + colourByEffort.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + enableControls(); + } + }); //hydroCheckBox.get } // MapParameters oldParameters, MapFileManager mapFile public static MapParameters showDialog(java.awt.Window parentFrame, SimpleMap simpleMap) { - if (singleInstance == null || singleInstance.simpleMap != simpleMap) { +// if (singleInstance == null || singleInstance.simpleMap != simpleMap) { singleInstance = new MapParametersDialog(parentFrame, simpleMap); - } +// } singleInstance.mapParameters = simpleMap.mapParameters.clone(); singleInstance.mapFileManager = simpleMap.mapFileManager; singleInstance.setParams(); @@ -141,6 +158,8 @@ public class MapParametersDialog extends PamDialog { keepShipCentred.setSelected(mapParameters.keepShipCentred); headingUp.setSelected(mapParameters.headingUp); showSurface.setSelected(mapParameters.hideSurface == false); + colourByEffort.setSelected(mapParameters.colourByEffort); + effortSourcePanel.setSource(mapParameters.effortDataSource); filePanel.setMapFile(mapParameters.mapFile); @@ -177,6 +196,8 @@ public class MapParametersDialog extends PamDialog { return showWarning("Range rings sepration must be > 0"); } } + mapParameters.colourByEffort = colourByEffort.isSelected(); + mapParameters.effortDataSource = effortSourcePanel.getSourceName(); } catch (Exception Ex) { return false; @@ -216,6 +237,14 @@ public class MapParametersDialog extends PamDialog { GridBagLayout layout; setLayout(layout = new GridBagLayout()); GridBagConstraints constraints = new PamGridBagContraints(); + effortSourcePanel = new EffortSourcePanel(singleInstance); + effortSettings = new SettingsButton(); + effortSettings.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showEffortSettings(); + } + }); // t.setLayout(new GridLayout(4,3)); constraints.anchor = GridBagConstraints.WEST; constraints.gridx = 0; @@ -224,37 +253,62 @@ public class MapParametersDialog extends PamDialog { constraints.gridx ++; addComponent(this,trackShowtime = new JTextField(7), constraints); constraints.gridx ++; - addComponent(this,new JLabel(" s"), constraints); + addComponent(this,new JLabel(" s "), constraints); + constraints.gridx++; + addComponent(this, colourByEffort, constraints); + constraints.gridx += 2; + constraints.gridwidth = 1; + constraints.fill = constraints.NONE; + constraints.anchor = constraints.LINE_END; + addComponent(this, effortSettings, constraints); constraints.gridx = 0; constraints.gridy ++; + constraints.anchor = constraints.LINE_START; addComponent(this,new JLabel("Data storage time "), constraints); constraints.gridx ++; addComponent(this,dataKeepTime = new JTextField(7), constraints); constraints.gridx ++; - addComponent(this,new JLabel(" s"), constraints); + addComponent(this,new JLabel(" s "), constraints); + constraints.gridx++; + constraints.gridwidth = 3; + constraints.fill = constraints.HORIZONTAL; + addComponent(this, effortSourcePanel.getPanel(), constraints); constraints.gridx = 0; constraints.gridy ++; + constraints.gridwidth = 1; addComponent(this,new JLabel("Data display time "), constraints); constraints.gridx ++; addComponent(this,dataShowTime = new JTextField(7), constraints); constraints.gridx ++; - addComponent(this,new JLabel(" s"), constraints); + addComponent(this,new JLabel(" s "), constraints); constraints.gridx = 0; constraints.gridy ++; - constraints.gridwidth = 3; + constraints.gridwidth = 2; addComponent(this,shipCheckBox, constraints); - constraints.gridy ++; + constraints.gridx += constraints.gridwidth; addComponent(this,keepShipOnMap, constraints); + constraints.gridy ++; constraints.gridx = 0; - constraints.gridy ++; - constraints.gridwidth = 3; addComponent(this,keepShipCentred, constraints); - constraints.gridy ++; + constraints.gridx += constraints.gridwidth; addComponent(this,headingUp, constraints); constraints.gridy ++; + constraints.gridx = 0; addComponent(this, showSurface, constraints); } + + protected void showEffortSettings() { + PamDataBlock effortBlock = effortSourcePanel.getSource(); + if (effortBlock == null) { + return; + } + EffortProvider effortProvider = effortBlock.getEffortProvider(); + if (effortProvider == null) { + return; + } + effortProvider.showOptionsDialog(singleInstance, simpleMap.getSelectorName()); + } } class HydrophonePanel extends JPanel { @@ -491,6 +545,9 @@ public class MapParametersDialog extends PamDialog { colourByChannel.setEnabled(hydroCheckBox.isSelected()); symbolSizeSpinner.setEnabled(hydroCheckBox.isSelected()); ringsRange.setEnabled(ringsType.getSelectedIndex() > 0); + boolean ec = colourByEffort.isSelected(); + effortSettings.setSelected(ec); + effortSourcePanel.setEnabled(ec); } diff --git a/src/Map/MapRectProjector.java b/src/Map/MapRectProjector.java index 2c45a517..41550890 100644 --- a/src/Map/MapRectProjector.java +++ b/src/Map/MapRectProjector.java @@ -34,6 +34,7 @@ import PamUtils.LatLong; import PamUtils.PamCoordinate; import PamUtils.PamUtils; import PamguardMVC.debug.Debug; +import effort.EffortDataUnit; /** * The Map Rectangle Projector. @@ -427,7 +428,15 @@ public class MapRectProjector extends MapProjector { if (rPix > 20) { return null; } - return closest.getSummaryString(); + EffortDataUnit effortData = mapPanelRef.findEffortThing(closest.getTimeMilliseconds()); + if (effortData == null) { + return closest.getSummaryString(); + } + else { + String effSummary = effortData.toString(); + String str = closest.getSummaryString() + "Effort: " + effSummary; + return str; + } } diff --git a/src/Map/SimpleMap.java b/src/Map/SimpleMap.java index 96410ad4..651594b7 100644 --- a/src/Map/SimpleMap.java +++ b/src/Map/SimpleMap.java @@ -101,6 +101,7 @@ import PamguardMVC.PamObservable; import PamguardMVC.PamObserver; import PamguardMVC.dataSelector.DataSelector; import PamguardMVC.debug.Debug; +import effort.EffortProvider; /** * Mainly a container for map objects, holding the main MapPanel and the right @@ -201,6 +202,8 @@ public class SimpleMap extends JPanel implements PamObserver, PamScrollObserver, private GridbaseControl gridBaseControl; + protected PamDataBlock effortDataBlock; + // JToolTip mouseToolTip; public SimpleMap(MapController mapController, boolean isMainTab, MapPanel mapPanel) { @@ -263,6 +266,14 @@ public class SimpleMap extends JPanel implements PamObserver, PamScrollObserver, public SimpleMap(MapController mapController, boolean isMainTab) { this(mapController, isMainTab, new MapPanel(mapController, null)); } + + /** + * Name for data selectors and data filters. + * @return + */ + public String getSelectorName() { + return getUnitName(); + } public String getUnitName() { if (thisMapIndex != 0) { @@ -570,6 +581,8 @@ public class SimpleMap extends JPanel implements PamObserver, PamScrollObserver, } initViewerControls(); + + effortDataBlock = PamController.getInstance().getDataBlockByLongName(mapParameters.effortDataSource); if (mapFileManager != null) { mapFileManager.readFileData(mapParameters.mapFile); @@ -1146,9 +1159,23 @@ public class SimpleMap extends JPanel implements PamObserver, PamScrollObserver, } } } + subscribeEffortProvider(); return changes; } + + /** + * Subscribe the effort provider to the scroller. + */ + private void subscribeEffortProvider() { + if (viewerScroller == null) { + return; + } + EffortProvider effProv = mapPanel.findEffortProvider(); + if (effProv != null) { + viewerScroller.addDataBlock(effProv.getParentDataBlock()); + } + } public PamScrollSlider getViewerScroller() { return viewerScroller; @@ -1206,6 +1233,7 @@ public class SimpleMap extends JPanel implements PamObserver, PamScrollObserver, getViewerScroller().reLoad(); } } + effortDataBlock = PamController.getInstance().getDataBlockByLongName(mapParameters.effortDataSource); } @Override diff --git a/src/PamController/InputStoreInfo.java b/src/PamController/InputStoreInfo.java index cde04c8c..e2d83f3c 100644 --- a/src/PamController/InputStoreInfo.java +++ b/src/PamController/InputStoreInfo.java @@ -8,6 +8,7 @@ public class InputStoreInfo { private int nFiles; private long firstFileStart, lastFileStart, lastFileEnd; private long[] fileStartTimes; + private long[] allFileEnds; public InputStoreInfo(DataInputStore dataInputStore, int nFiles, long firstFileStart, long lastFileStart, long lastFileEnd) { super(); @@ -96,6 +97,21 @@ public class InputStoreInfo { public void setLastFileEnd(long lastFileEnd) { this.lastFileEnd = lastFileEnd; } + + /** + * Set all file end times. + * @param allFileEnds + */ + public void setFileEndTimes(long[] allFileEnds) { + this.allFileEnds = allFileEnds; + } + + /** + * @return the allFileEnds + */ + public long[] getAllFileEnds() { + return allFileEnds; + } diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java index b106a575..161e673b 100644 --- a/src/PamController/PamController.java +++ b/src/PamController/PamController.java @@ -1334,7 +1334,13 @@ public class PamController implements PamControllerInterface, PamSettings { } for (int iU = 0; iU < pamControlledUnits.size(); iU++) { for (int iP = 0; iP < pamControlledUnits.get(iU).getNumPamProcesses(); iP++) { - pamControlledUnits.get(iU).getPamProcess(iP).pamStart(); + PamProcess pamProcess = pamControlledUnits.get(iU).getPamProcess(iP); + pamProcess.pamStart(); + int nOut = pamProcess.getNumOutputDataBlocks(); + for (int iB = 0; iB < nOut; iB++) { + PamDataBlock outBlock = pamProcess.getOutputDataBlock(iB); + outBlock.pamStart(startTime); + } } // long t2 = System.currentTimeMillis(); // System.out.printf("==================================Time taken to call @@ -1378,11 +1384,19 @@ public class PamController implements PamControllerInterface, PamSettings { // statusCheckThread = new Thread(new StatusTimer()); // statusCheckThread.start(); ArrayList pamControlledUnits = pamConfiguration.getPamControlledUnits(); + + long stopTime = PamCalendar.getTimeInMillis(); // tell all controlled units to stop for (int iU = 0; iU < pamControlledUnits.size(); iU++) { for (int iP = 0; iP < pamControlledUnits.get(iU).getNumPamProcesses(); iP++) { - pamControlledUnits.get(iU).getPamProcess(iP).pamStop(); + PamProcess pamProcess = pamControlledUnits.get(iU).getPamProcess(iP); + pamProcess.pamStop(); + int nOut = pamProcess.getNumOutputDataBlocks(); + for (int iB = 0; iB < nOut; iB++) { + PamDataBlock outBlock = pamProcess.getOutputDataBlock(iB); + outBlock.pamStop(stopTime); + } } } diff --git a/src/PamModel/PamModel.java b/src/PamModel/PamModel.java index e97b315e..61242ea8 100644 --- a/src/PamModel/PamModel.java +++ b/src/PamModel/PamModel.java @@ -47,6 +47,7 @@ import fftManager.PamFFTControl; import group3dlocaliser.Group3DLocaliserControl; import meygenturbine.MeygenTurbine; import printscreen.PrintScreenControl; +import ravendata.RavenControl; import rockBlock.RockBlockControl; import tethys.TethysControl; import turbineops.TurbineOperationControl; @@ -473,6 +474,12 @@ final public class PamModel implements PamSettings { mi.setMaxNumber(1); //mi.addGUICompatabilityFlag(PamGUIManager.FX); //has FX enabled GUI. mi.setHidden(SMRUEnable.isEnable() == false); + + mi = PamModuleInfo.registerControlledUnit(RavenControl.class.getName(), RavenControl.defaultName); + mi.setToolTipText("Import data from Raven selection tables"); + mi.setModulesMenuGroup(utilitiesGroup); + mi.setHidden(SMRUEnable.isEnable() == false); + } /* diff --git a/src/PamView/PamDetectionOverlayGraphics.java b/src/PamView/PamDetectionOverlayGraphics.java index e4667b8b..86418683 100644 --- a/src/PamView/PamDetectionOverlayGraphics.java +++ b/src/PamView/PamDetectionOverlayGraphics.java @@ -703,7 +703,7 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw { Coordinate3d topLeft = generalProjector.getCoord3d(pamDetection.getTimeMilliseconds(), frequency[1], 0); Coordinate3d botRight = generalProjector.getCoord3d(pamDetection.getTimeMilliseconds() + - pamDetection.getSampleDuration() * 1000./parentDataBlock.getSampleRate(), + pamDetection.getDurationInMilliseconds(), frequency[0], 0); if (botRight.x < topLeft.x){ diff --git a/src/PamView/dialog/warn/WarnOnce.java b/src/PamView/dialog/warn/WarnOnce.java index cd7ad08d..ef16b100 100644 --- a/src/PamView/dialog/warn/WarnOnce.java +++ b/src/PamView/dialog/warn/WarnOnce.java @@ -372,6 +372,10 @@ public class WarnOnce implements PamSettings { return -1; } + if (parent == null) { + parent = PamController.getMainFrame(); + } + // show the warning if (canShowDialog()) { WarnOnceDialog wo = new WarnOnceDialog(parent, title, message, messageType, helpPoint, error, okButtonText, cancelButtonText); diff --git a/src/PamView/symbol/SymbolData.java b/src/PamView/symbol/SymbolData.java index b5ed71c8..2db797a1 100644 --- a/src/PamView/symbol/SymbolData.java +++ b/src/PamView/symbol/SymbolData.java @@ -1,6 +1,9 @@ package PamView.symbol; +import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; import java.io.Serializable; import PamView.PamSymbolType; @@ -165,4 +168,17 @@ public class SymbolData implements Serializable, Cloneable { this.symbol = symbol; } + /** + * Set the line properties for the given graphics handle. + * @param g + */ + public void setGraphicsProperties(Graphics g) { + if (lineColor != null) { + g.setColor(lineColor); + } + if (lineThickness != 1) { + ((Graphics2D) g).setStroke(new BasicStroke(lineThickness)); + } + } + } diff --git a/src/PamView/symbol/SymbolOnlyManager.java b/src/PamView/symbol/SymbolOnlyManager.java new file mode 100644 index 00000000..fde90058 --- /dev/null +++ b/src/PamView/symbol/SymbolOnlyManager.java @@ -0,0 +1,21 @@ +package PamView.symbol; + +import PamguardMVC.PamDataBlock; + +/** + * Version of the standard symbol manager that only has the optoin on the main + * symbol type and no modifiers whatsoever. + * @author dg50 + * + */ +public class SymbolOnlyManager extends StandardSymbolManager { + + public SymbolOnlyManager(PamDataBlock pamDataBlock, SymbolData defaultSymbol) { + super(pamDataBlock, defaultSymbol); + // TODO Auto-generated constructor stub + } + + @Override + public void addSymbolModifiers(PamSymbolChooser psc) { + } +} diff --git a/src/PamguardMVC/PamDataBlock.java b/src/PamguardMVC/PamDataBlock.java index fefb181c..9a19073f 100644 --- a/src/PamguardMVC/PamDataBlock.java +++ b/src/PamguardMVC/PamDataBlock.java @@ -58,10 +58,13 @@ import tethys.species.DataBlockSpeciesManager; import dataGram.DatagramProvider; import dataMap.BespokeDataMapGraphic; import dataMap.OfflineDataMap; +import effort.EffortProvider; +import effort.binary.DataMapEffortProvider; import annotation.DataAnnotationType; import annotation.handler.AnnotationHandler; import binaryFileStorage.BinaryDataSource; import binaryFileStorage.BinaryOfflineDataMap; +import binaryFileStorage.BinaryStore; import binaryFileStorage.SecondaryBinaryStore; import PamController.OfflineDataStore; import PamController.PamControlledUnit; @@ -1081,6 +1084,11 @@ public class PamDataBlock extends PamObservable { System.err.printf("Not loading %s since initialisation not yet complete\n", getDataName()); return false; } +// long tenDays = 3600L*24L*1000L*10L; +// if (offlineDataLoadInfo.getEndMillis() - offlineDataLoadInfo.getStartMillis() > tenDays) { +// System.out.printf("Big many day data load %s to %s in %s", PamCalendar.formatDateTime(offlineDataLoadInfo.getStartMillis()), +// PamCalendar.formatDateTime(offlineDataLoadInfo.getEndMillis()) ,getLongDataName()); +// } saveViewerData(); @@ -1124,6 +1132,11 @@ public class PamDataBlock extends PamObservable { firstViewerUID = Math.min(firstViewerUID, uid); lastViewerUID = Math.max(lastViewerUID, uid); } + + EffortProvider effProv = getEffortProvider(); + if (effProv != null) { + effProv.viewerLoadData(); + } return loadOk; } @@ -1269,6 +1282,10 @@ public class PamDataBlock extends PamObservable { */ if (shouldNotify()) { notifyInstantObservers(pamDataUnit); + EffortProvider effProvider = getEffortProvider(); + if (effProvider != null) { + effProvider.newData(pamDataUnit); + } } if (offlineDataLoading.isCurrentOfflineLoadKeep()) { @@ -3054,7 +3071,16 @@ public class PamDataBlock extends PamObservable { case PamControllerInterface.HYDROPHONE_ARRAY_CHANGED: clearDataOrigins(); break; + case PamController.INITIALIZATION_COMPLETE: + effortProvider = autoEffortProvider(); + break; + case PamController.ADD_CONTROLLEDUNIT: + if (PamController.getInstance().isInitializationComplete()) { + effortProvider = autoEffortProvider(); + } + break; } + } /** @@ -3658,6 +3684,8 @@ public class PamDataBlock extends PamObservable { private DataSelectorCreator dataSelectorCreator; + private EffortProvider effortProvider; + public void setRecordingTrigger(RecorderTrigger recorderTrigger) { this.recorderTrigger = recorderTrigger; RecorderControl.registerRecorderTrigger(recorderTrigger); @@ -4345,4 +4373,60 @@ public class PamDataBlock extends PamObservable { } } } + + + /** + * @return the effort provider. + */ + public EffortProvider getEffortProvider() { + return effortProvider; + } + + /** + * Auto generate an effort provider. This may get called many times + * for blocks without effort, but that doesn't really matter since its + * only going to happen when opening dialogs, etc. + * @return + */ + public EffortProvider autoEffortProvider() { + if (effortProvider != null) { + // don't change if there already is one. + return effortProvider; + } + // see if we can do an auto binary one. + BinaryStore binaryStore = BinaryStore.findBinaryStoreControl(); + if (binaryStore != null && getBinaryDataSource() != null) { + return new DataMapEffortProvider(this, BinaryStore.class); + } + // other options may follow ... + return null; + } + + /** + * @param effortProvider the effortProvider to set + */ + protected void setEffortProvider(EffortProvider effortProvider) { + this.effortProvider = effortProvider; + } + + /** + * Need this notification at startup time to perform a few standard actions. + * @param startTime + */ + public void pamStart(long startTime) { + EffortProvider effP = getEffortProvider(); + if (effP != null) { + effP.realTimeStart(startTime); + } + } + /** + * Need this notification at stop time to perform a few standard actions. + * @param startTime + */ + public void pamStop(long stopTime) { + EffortProvider effP = getEffortProvider(); + if (effP != null) { + effP.realTimeStop(stopTime); + } + } } diff --git a/src/PamguardMVC/PamDataUnit.java b/src/PamguardMVC/PamDataUnit.java index 12a9f085..966fd857 100644 --- a/src/PamguardMVC/PamDataUnit.java +++ b/src/PamguardMVC/PamDataUnit.java @@ -977,7 +977,15 @@ abstract public class PamDataUnit // add frequency and amplitude information double[] frequency = this.getFrequency(); if (frequency != null) { - str += "Frequency: " + FrequencyFormat.formatFrequencyRange(this.getFrequency(), true) + "
"; + boolean allzeros = true; + for (int i = 0; i < frequency.length; i++) { + if (frequency[i] > 0) { + allzeros = false; + } + } + if (!allzeros) { + str += "Frequency: " + FrequencyFormat.formatFrequencyRange(this.getFrequency(), true) + "
"; + } } if (getAmplitudeDB() != 0) { str += String.format("Amplitude: %3.1fdB
", getAmplitudeDB()); diff --git a/src/PamguardMVC/PamRawDataBlock.java b/src/PamguardMVC/PamRawDataBlock.java index 6b06ead5..cab14b71 100644 --- a/src/PamguardMVC/PamRawDataBlock.java +++ b/src/PamguardMVC/PamRawDataBlock.java @@ -34,6 +34,8 @@ import Acquisition.RawDataBinaryDataSource; import PamController.PamController; import PamDetection.RawDataUnit; import PamUtils.PamUtils; +import dataMap.OfflineDataMap; +import effort.EffortProvider; /** * Extension of RecyclingDataBlock that is used for Raw audio data. @@ -602,6 +604,13 @@ public class PamRawDataBlock extends AcousticDataBlock { } } + @Override + public EffortProvider autoEffortProvider() { + return null; + } + + + // @Override // protected void findParentSource() { // super.findParentSource(); diff --git a/src/bearinglocaliser/BearingLocaliserControl.java b/src/bearinglocaliser/BearingLocaliserControl.java index 3bfe7b7e..c3c1744b 100644 --- a/src/bearinglocaliser/BearingLocaliserControl.java +++ b/src/bearinglocaliser/BearingLocaliserControl.java @@ -32,6 +32,7 @@ import bearinglocaliser.toad.TOADBearingProvider; import offlineProcessing.OLProcessDialog; import offlineProcessing.OfflineTaskGroup; import pamViewFX.fxNodes.pamDialogFX.PamDialogFX2AWT; +import tethys.localization.LocalizationCreator; import userDisplay.UserDisplayControl; public class BearingLocaliserControl extends PamControlledUnit implements PamSettings, LocalisationAlgorithm, LocalisationAlgorithmInfo { @@ -238,6 +239,12 @@ public class BearingLocaliserControl extends PamControlledUnit implements PamSet return this; } + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } + private BearingAlgorithm findAlgorithm() { BearingAlgorithmGroup[] groups = bearingProcess.getBearingAlgorithmGroups(); diff --git a/src/clickDetector/ClickControl.java b/src/clickDetector/ClickControl.java index 68f1aef9..ddb8fdc1 100644 --- a/src/clickDetector/ClickControl.java +++ b/src/clickDetector/ClickControl.java @@ -39,8 +39,7 @@ import org.w3c.dom.Element; import rocca.RoccaControl; import soundPlayback.PlaybackControl; import targetMotionOld.TargetMotionLocaliser; - - +import tethys.localization.LocalizationCreator; import binaryFileStorage.BinaryStore; import Filters.FilterDialog; import Filters.FilterParams; @@ -1300,5 +1299,11 @@ public class ClickControl extends PamControlledUnit implements PamSettings, Loca return clickDetector.getLocaliserInfo(); } + @Override + public LocalizationCreator getTethysCreator() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/src/clickDetector/ClickDataBlock.java b/src/clickDetector/ClickDataBlock.java index 5536aa79..6f878835 100644 --- a/src/clickDetector/ClickDataBlock.java +++ b/src/clickDetector/ClickDataBlock.java @@ -2,6 +2,7 @@ package clickDetector; import java.util.ListIterator; +import Localiser.LocalisationAlgorithm; import pamScrollSystem.ViewLoadObserver; import tethys.TethysControl; import tethys.pamdata.TethysDataProvider; @@ -336,5 +337,15 @@ public class ClickDataBlock extends AcousticDataBlock implement return new DataAutomationInfo(DataAutomation.AUTOMATIC); } + @Override + public LocalisationAlgorithm getLocalisationAlgorithm() { + /* + * This is usually the bearing algorithm from click control. + * Howeveer, someone may have added an additional bearing localiser + * in which case, the default function should find that. + */ + return super.getLocalisationAlgorithm(); + } + } diff --git a/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java b/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java index afc60ec7..1023eb86 100644 --- a/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java +++ b/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Vector; +import Localiser.LocalisationAlgorithm; import Localiser.detectionGroupLocaliser.GroupDetection; import PamController.PamController; import PamController.PamControllerInterface; @@ -16,9 +17,11 @@ import PamController.PamViewParameters; import PamUtils.PamCalendar; import PamView.symbol.StandardSymbolManager; import pamScrollSystem.ViewLoadObserver; +import targetMotionOld.TargetMotionLocaliser; import tethys.TethysControl; import tethys.pamdata.TethysDataProvider; import tethys.species.DataBlockSpeciesManager; +import clickDetector.ClickControl; import clickDetector.ClickDetection; //import staticLocaliser.StaticLocaliserControl; //import staticLocaliser.StaticLocaliserProvider; @@ -317,6 +320,20 @@ public class OfflineEventDataBlock extends SuperDetDataBlock tml = clickControl.getTargetMotionLocaliser(); + return tml; +// return super.getLocalisationAlgorithm(); + } + } diff --git a/src/effort/EffortDataUnit.java b/src/effort/EffortDataUnit.java new file mode 100644 index 00000000..d8eca35a --- /dev/null +++ b/src/effort/EffortDataUnit.java @@ -0,0 +1,104 @@ +package effort; + +import PamUtils.PamCalendar; +import PamguardMVC.PamDataUnit; + +public class EffortDataUnit extends PamDataUnit { + + /** + * Value for effort end to say that effort is ongoing. + */ + public static final long ONGOINGEFFORT = Long.MAX_VALUE/2; + + private PamDataUnit referenceDataUnit; + private EffortProvider effortProvider; + + + public EffortDataUnit(EffortProvider effortProvider, PamDataUnit referenceDataUnit, long effortStart, long effortEnd) { + super(effortStart); + getBasicData().setEndTime(effortEnd); + this.effortProvider = effortProvider; + this.setReferenceDataUnit(referenceDataUnit); + } + + /** + * + * @return Start of effort period. + */ + public long getEffortStart() { + return getTimeMilliseconds(); + } + + + /** + * + * @return End of effort period. + */ + public long getEffortEnd() { + return getEndTimeInMilliseconds(); + } + + /** + * Set the effort end time + * @param endTime + */ + public void setEffortEnd(long endTime) { + getBasicData().setEndTime(endTime); + } + + /** + * + * @param timeMilliseconds + * @return time is in effort period + */ + public boolean inEffort(long timeMilliseconds) { + return (timeMilliseconds >= getEffortStart() && timeMilliseconds <= getEffortEnd()); + } + + /** + * Description of the effort, for tool tips, etc. + * @return + */ + public String getEffortDescription() { + return this.getSummaryString(); + } + + /** + * @return the referenceDataUnit + */ + public PamDataUnit getReferenceDataUnit() { + return referenceDataUnit; + } + + /** + * @param referenceDataUnit the referenceDataUnit to set + */ + public void setReferenceDataUnit(PamDataUnit referenceDataUnit) { + this.referenceDataUnit = referenceDataUnit; + } + + @Override + public String toString() { + String str; + if (getEffortEnd() >= ONGOINGEFFORT/2) { + str = String.format("%s ongoing from %s",effortProvider.getName(), PamCalendar.formatDBDateTime(getEffortStart())); + } + else { + str = String.format("%s %s to %s",effortProvider.getName(), PamCalendar.formatDBDateTime(getEffortStart()), PamCalendar.formatDBDateTime(getEffortEnd())); + } + if (referenceDataUnit != null) { + str += "
" + referenceDataUnit.getSummaryString(); + } + return str; + } + + @Override + public int compareTo(PamDataUnit o) { + if (o instanceof EffortDataUnit) { + EffortDataUnit oth = (EffortDataUnit) o; + return (int) (oth.getEffortStart()-getEffortStart()); + } + return 0; + } + +} diff --git a/src/effort/EffortManager.java b/src/effort/EffortManager.java new file mode 100644 index 00000000..a341a11d --- /dev/null +++ b/src/effort/EffortManager.java @@ -0,0 +1,50 @@ +package effort; + +import java.util.ArrayList; + +import PamController.PamController; +import PamguardMVC.PamDataBlock; + +/** + * Singleton class to provide management for all types of Effort in PAMGuard. + * @author dg50 + * + */ +public class EffortManager { + + private static EffortManager singleInstance; + + private EffortManager() { + + } + + /** + * Get singleton instance of EffortManager + * @return + */ + public static EffortManager getEffortManager() { + if (singleInstance == null) { + singleInstance = new EffortManager(); + } + return singleInstance; + } + + /** + * Get a list of all data blocks that might provide effort data. + * @return + */ + public ArrayList getEffortDataBlocks() { + ArrayList allBlocks = getPamController().getDataBlocks(); + ArrayList effortBlocks = new ArrayList(); + for (PamDataBlock aBlock : allBlocks) { + if (aBlock.getEffortProvider() != null) { + effortBlocks.add(aBlock); + } + } + return effortBlocks; + } + + private PamController getPamController() { + return PamController.getInstance(); + } +} diff --git a/src/effort/EffortProvider.java b/src/effort/EffortProvider.java new file mode 100644 index 00000000..6da999c2 --- /dev/null +++ b/src/effort/EffortProvider.java @@ -0,0 +1,192 @@ +package effort; + +import java.awt.Frame; +import java.awt.Window; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import Map.MapParametersDialog; +import PamController.PamController; +import PamView.GeneralProjector; +import PamView.PamSymbol; +import PamView.symbol.PamSymbolChooser; +import PamView.symbol.PamSymbolManager; +import PamView.symbol.SwingSymbolOptionsPanel; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import PamguardMVC.dataSelector.DataSelectDialog; +import PamguardMVC.dataSelector.DataSelector; + +/** + * Set of functions that can be returned from any datablock which can + * give information about effort. For detectors with binary storage, they + * will return a standard binary store effort provider. Others, e.g. + * logger forms, acquisition, etc. can so something much more bespoke.

+ * For real time, will need quite different behaviour to offline. Datablocks + * with a effortProvider are going to notify this and a local list will be + * kept of starts and ends for the entire operation period. This will be + * overridden for differeing offline scenarios and bespoke cases such as + * logger forms (so need to get a notification in here for every data unit too !) + * @author dg50 + * + */ +public abstract class EffortProvider { + + private PamDataBlock parentDataBlock; + private boolean isViewer; + + public EffortProvider(PamDataBlock parentDataBlock) { + super(); + this.parentDataBlock = parentDataBlock; + this.isViewer = PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW; + } + + /** + * Notified at real time start. + * @param timeMilliseconds + */ + public abstract void realTimeStart(long timeMilliseconds); + + /** + * notified at real time end + * @param timeMilliseconds + */ + public abstract void realTimeStop(long timeMilliseconds); ; + + /** + * Notified for real time data. + * @param pamDataUnit + */ + public abstract void newData(PamDataUnit pamDataUnit); ; + + /** + * Get the effort for a specific time. + * @param timeMilliseconds + * @return Effort thing. Can be null if off effort. + */ + public EffortDataUnit getEffort(long timeMilliseconds) { + List allEfforts = getAllEffortThings(); + if (allEfforts == null) { + return null; + } + Iterator it = allEfforts.iterator(); + while (it.hasNext()) { + EffortDataUnit next = it.next(); + if (timeMilliseconds >= next.getEffortStart() && timeMilliseconds <= next.getEffortEnd()) { + return next; + } + } + return null; + } + + /** + * Called when viewer data have been loaded for the parent datablock. + */ + public abstract void viewerLoadData(); + + /** + * Get all effort things. e.g. for binary data this is more or less a copy of + * the datamap (perhaps new units without the gaps). + * @return + */ + public abstract List getAllEffortThings(); + + /** + * @return the parentDataBlock + */ + public PamDataBlock getParentDataBlock() { + return parentDataBlock; + } + + /** + * Get a data selector. For specialist effort modules, this will probably call + * through to the datablocks data selection system. Others, such as binaryEffortProvider + * can return null since they are either on or off. + * @param selectorName + * @return + */ + public abstract DataSelector getDataSelector(String selectorName); + + /** + * Get the name of this effort provider. + */ + public abstract String getName(); + + /** + * Get a symbol manager. For specialist effort modules, this will probably call + * through to the datablocks existing symbol management system. Others, such as binaryEffortProvider + * will need a chooser for the simple on/off data types. . + * @return + */ + public abstract PamSymbolManager getSymbolManager(); + + public PamSymbolChooser getSymbolChooser(String chooserName, GeneralProjector projector) { + PamSymbolManager symbolManager = getSymbolManager(); + if (symbolManager == null) { + return null; + } + return symbolManager.getSymbolChooser(chooserName, projector); + } + + public PamSymbol getPamSymbol(String symbolChooserName, PamDataUnit dataUnit, GeneralProjector projector) { + PamSymbolChooser chooser = getSymbolChooser(symbolChooserName, projector); + return getPamSymbol(chooser, dataUnit); + } + + /** + * Need to use this to get symbols for effort instead of direct calls into + * the symbol chooser, since the symbol chooser will almost definitely want + * it's own type of data unit, NOT the EffortDataUnit which will probably crash + * due to a cast exception. + * @param chooser + * @param dataUnit + * @return + */ + public PamSymbol getPamSymbol(PamSymbolChooser chooser, PamDataUnit dataUnit) { + if (chooser == null) { + return null; + } + // possible that the data is an Effort unit that wraps a real data unit. Need to + // probably pass the original. + if (dataUnit instanceof EffortDataUnit) { + PamDataUnit refData = ((EffortDataUnit) dataUnit).getReferenceDataUnit(); + if (refData != null) { + dataUnit = refData; + } + } + + return chooser.getPamSymbol(chooser.getProjector(), dataUnit); + } + + public boolean showOptionsDialog(Window parent, String observerName) { + PamSymbolChooser symbolChooser = getSymbolChooser(observerName, null); + if (symbolChooser == null) { + return false; + } + SwingSymbolOptionsPanel panel = symbolChooser.getSwingOptionsPanel(null); + if (panel == null) { + return false; + } + DataSelectDialog dataSelectDialog = new DataSelectDialog(parent, parentDataBlock, null, symbolChooser); + boolean ans = dataSelectDialog.showDialog(); + + return ans; + } + + /** + * @return the isViewer + */ + public boolean isViewer() { + return isViewer; + } + + public EffortDataUnit getLastEffort() { + List all = getAllEffortThings(); + if (all == null || all.size() == 0) { + return null; + } + return all.get(all.size()-1); + } + +} diff --git a/src/effort/binary/DataMapEffortProvider.java b/src/effort/binary/DataMapEffortProvider.java new file mode 100644 index 00000000..11d27047 --- /dev/null +++ b/src/effort/binary/DataMapEffortProvider.java @@ -0,0 +1,158 @@ +package effort.binary; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import PamController.OfflineDataStore; +import PamController.PamController; +import PamView.symbol.PamSymbolManager; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import PamguardMVC.dataSelector.DataSelector; +import binaryFileStorage.BinaryStore; +import dataMap.OfflineDataMap; +import dataMap.OfflineDataMapPoint; +import effort.EffortDataUnit; +import effort.EffortProvider; + +/** + * Effort provider for most types of datablock that bases itself off one of the + * datamaps, binary (preferred) or database. Binary better since database doesn't really + * have proper effort data for most blocks. + * However, we want this to work online too, so will need to have quite different functionality + * for real time and viewer operations. + * @author dg50 + * + */ +public class DataMapEffortProvider extends EffortProvider { + + private DataMapSymbolManager binarySymbolManager; + + private Class dataStoreClass; + + private long maxGap = 0; + + private ArrayList allEfforts; + + /** + * + * @param parentDataBlock + * @param dataStoreClass + * @param maxGapMillis + */ + public DataMapEffortProvider(PamDataBlock parentDataBlock, Class dataStoreClass, long maxGapMillis) { + super(parentDataBlock); + this.dataStoreClass = dataStoreClass; + this.maxGap = maxGapMillis; + binarySymbolManager = new DataMapSymbolManager(parentDataBlock); + } + + /** + * + * @param parentDataBlock + * @param dataStoreClass + */ + public DataMapEffortProvider(PamDataBlock parentDataBlock, Class dataStoreClass) { + this(parentDataBlock, dataStoreClass, 0); + } + + @Override + public String getName() { + return getParentDataBlock().getDataName(); + } + +// @Override +// public EffortDataUnit getEffort(long timeMilliseconds) { +// OfflineDataMap dataMap = findDataMap(); +// if (dataMap == null) { +// return null; +// } +// OfflineDataMapPoint foundPt = dataMap.findMapPoint(timeMilliseconds); +// if (foundPt != null) { +// return new DataMapEffortThing(this, getParentDataBlock(), foundPt.getStartTime(), foundPt.getEndTime()); +// } +// return null; +// } + + @Override + public List getAllEffortThings() { + return allEfforts; + } + + private OfflineDataMap findDataMap() { + if (dataStoreClass == null) { + return getParentDataBlock().getPrimaryDataMap(); + } + try { + OfflineDataStore dataStore = (OfflineDataStore) PamController.getInstance().findControlledUnit(dataStoreClass, null); + if (dataStore != null) { + return getParentDataBlock().getOfflineDataMap(dataStore); + } + } + catch (Exception e) { + } + return null; + } + + @Override + public DataSelector getDataSelector(String selectorName) { + // TODO Auto-generated method stub + return null; + } + + @Override + public PamSymbolManager getSymbolManager() { + return binarySymbolManager; + } + + @Override + public void realTimeStart(long timeMilliseconds) { + if (allEfforts == null) { + allEfforts = new ArrayList<>(); + } + EffortDataUnit newEffort = new EffortDataUnit(this, null, timeMilliseconds, EffortDataUnit.ONGOINGEFFORT); + allEfforts.add(newEffort); + } + + @Override + public void realTimeStop(long timeMilliseconds) { + if (allEfforts == null || allEfforts.size() == 0) { + return; + } + EffortDataUnit lastEff = allEfforts.get(allEfforts.size()-1); + lastEff.setEffortEnd(timeMilliseconds); + + } + + @Override + public void newData(PamDataUnit pamDataUnit) { + // do nothing for individual data units. + } + + @Override + public void viewerLoadData() { + // should merge continuous binary data into one big lump or several big lumps if duty cycled. + OfflineDataMap dataMap = findDataMap(); + if (dataMap == null) { + return; + } + ArrayList allPoints = new ArrayList<>(); + Iterator it = dataMap.getListIterator(); + DataMapEffortThing currentThing = null; + while (it.hasNext()) { + OfflineDataMapPoint pt = it.next(); + if (currentThing == null || pt.getStartTime() - currentThing.getEffortEnd() > maxGap) { + currentThing = new DataMapEffortThing(this, getParentDataBlock(), pt.getStartTime(), pt.getEndTime()); + allPoints.add(currentThing); + } + else { + currentThing.setEffortEnd(pt.getEndTime()); + } + } + + allEfforts = allPoints; + + } + +} diff --git a/src/effort/binary/DataMapEffortThing.java b/src/effort/binary/DataMapEffortThing.java new file mode 100644 index 00000000..8c270bf1 --- /dev/null +++ b/src/effort/binary/DataMapEffortThing.java @@ -0,0 +1,22 @@ +package effort.binary; + +import PamguardMVC.PamDataBlock; +import effort.EffortDataUnit; +import effort.EffortProvider; + +public class DataMapEffortThing extends EffortDataUnit { + + + private PamDataBlock parentDatablock; + + public DataMapEffortThing(EffortProvider effortProvider, PamDataBlock parentDatablock, long effortStart, long effortEnd) { + super(effortProvider, null, effortStart, effortEnd); + this.parentDatablock = parentDatablock; + } + + @Override + public String getEffortDescription() { + String str = String.format("%s", parentDatablock.getDataName()); + return str; + } +} diff --git a/src/effort/binary/DataMapSymbolManager.java b/src/effort/binary/DataMapSymbolManager.java new file mode 100644 index 00000000..4243d0dc --- /dev/null +++ b/src/effort/binary/DataMapSymbolManager.java @@ -0,0 +1,18 @@ +package effort.binary; + +import PamView.symbol.PamSymbolChooser; +import PamView.symbol.StandardSymbolManager; +import PamView.symbol.SymbolData; +import PamView.symbol.SymbolOnlyManager; +import PamguardMVC.PamDataBlock; + +public class DataMapSymbolManager extends SymbolOnlyManager { + + public static SymbolData defaultSymbol = new SymbolData(); + + public DataMapSymbolManager(PamDataBlock pamDataBlock) { + super(pamDataBlock, defaultSymbol); + } + + +} diff --git a/src/effort/swing/EffortSourcePanel.java b/src/effort/swing/EffortSourcePanel.java new file mode 100644 index 00000000..b47e7c3c --- /dev/null +++ b/src/effort/swing/EffortSourcePanel.java @@ -0,0 +1,28 @@ +package effort.swing; + +import java.awt.Window; +import java.util.ArrayList; + +import PamView.dialog.SourcePanel; +import PamguardMVC.PamDataBlock; +import effort.EffortManager; + +public class EffortSourcePanel extends SourcePanel { + + public EffortSourcePanel(Window ownerWindow) { + super(ownerWindow, PamDataBlock.class, false, false); + } + + public EffortSourcePanel(Window ownerWindow, String borderTitle) { + super(ownerWindow, borderTitle, PamDataBlock.class, false, false); + } + + @Override + public ArrayList getCompatibleDataBlocks() { + return EffortManager.getEffortManager().getEffortDataBlocks(); + } + + + + +} diff --git a/src/effortmonitor/EffortControl.java b/src/effortmonitor/EffortControl.java index a15b1cf2..b8e9e760 100644 --- a/src/effortmonitor/EffortControl.java +++ b/src/effortmonitor/EffortControl.java @@ -33,6 +33,11 @@ import pamScrollSystem.PamScroller; import pamScrollSystem.PamScrollerData; import userDisplay.UserDisplayControl; +/** + * Record scroll effort. + * @author dg50 + * + */ public class EffortControl extends PamControlledUnit implements PamSettings{ public static String unitType = "Scroll Effort"; diff --git a/src/generalDatabase/DBMapMakingDialog.java b/src/generalDatabase/DBMapMakingDialog.java index 52c44092..7cc791fb 100644 --- a/src/generalDatabase/DBMapMakingDialog.java +++ b/src/generalDatabase/DBMapMakingDialog.java @@ -32,8 +32,8 @@ public class DBMapMakingDialog extends PamDialog { JPanel p = new JPanel(); p.setBorder(new TitledBorder("Creating data map")); p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS)); - p.add(databaseName = new JLabel("")); - p.add(streamName = new JLabel("")); + p.add(databaseName = new JLabel(" ")); + p.add(streamName = new JLabel(" ")); p.add(streamProgress = new JProgressBar()); // p.setPreferredSize(new Dimension(400, 200)); streamName.setPreferredSize(new Dimension(250, 5)); diff --git a/src/generalDatabase/lookupTables/LookUpTables.java b/src/generalDatabase/lookupTables/LookUpTables.java index abea6653..75ba15af 100644 --- a/src/generalDatabase/lookupTables/LookUpTables.java +++ b/src/generalDatabase/lookupTables/LookUpTables.java @@ -144,11 +144,14 @@ public class LookUpTables { String topic1 = list.get(i).getTopic().trim(); for (int j = i+1; j < n; j++) { String code2 = list.get(j).getCode().trim(); - String topic2 = list.get(j).getTopic().trim(); + String topic2 = list.get(j).getTopic(); + if (topic2 != null) { + topic2 = topic2.trim(); if (code.equals(code2) && topic1.equals(topic2)) { isRepeat[j] = true; nRepeat++; } + } } } if (nRepeat == 0) { @@ -183,7 +186,7 @@ public class LookUpTables { return null; } ArrayList topics = new ArrayList<>(); - String qStr = "SELECT DISTINCT Topic FROM " + lutTableDef.getTableName(); + String qStr = "SELECT DISTINCT Topic FROM " + lutTableDef.getTableName() + " WHERE TOPIC IS NOT NULL"; try { Statement stmt = con.getConnection().createStatement(); boolean ok = stmt.execute(qStr); diff --git a/src/group3dlocaliser/Group3DParams.java b/src/group3dlocaliser/Group3DParams.java index 6467a9ad..b455494a 100644 --- a/src/group3dlocaliser/Group3DParams.java +++ b/src/group3dlocaliser/Group3DParams.java @@ -17,8 +17,8 @@ public class Group3DParams implements Serializable, Cloneable, ManagedParameters public static final long serialVersionUID = 1L; - @Deprecated - private GroupedSourceParameters groupedSourceParams; +// @Deprecated +// private GroupedSourceParameters groupedSourceParams; private String sourceName; @@ -146,9 +146,9 @@ public class Group3DParams implements Serializable, Cloneable, ManagedParameters * @return the sourceName */ public String getSourceName() { - if (sourceName == null && groupedSourceParams != null) { - sourceName = groupedSourceParams.getDataSource(); - } +// if (sourceName == null && groupedSourceParams != null) { +// sourceName = groupedSourceParams.getDataSource(); +// } return sourceName; } diff --git a/src/loggerForms/FormDescription.java b/src/loggerForms/FormDescription.java index a212b94d..b6d862e7 100644 --- a/src/loggerForms/FormDescription.java +++ b/src/loggerForms/FormDescription.java @@ -56,7 +56,6 @@ import pamScrollSystem.AbstractPamScrollerAWT; import pamScrollSystem.ScrollPaneAddon; import PamView.PamTabPanel; import PamView.panel.PamPanel; -import PamView.symbol.StandardSymbolManager; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import PamController.PamControlledUnitSettings; @@ -67,7 +66,6 @@ import PamUtils.PamCalendar; import PamUtils.XMLUtils; import loggerForms.controlDescriptions.ControlTypes; import loggerForms.controlDescriptions.InputControlDescription; -import loggerForms.PropertyTypes; import loggerForms.controlDescriptions.ControlDescription; import loggerForms.formdesign.FormEditDialog; import loggerForms.formdesign.FormEditor; @@ -75,6 +73,7 @@ import loggerForms.formdesign.FormList; import loggerForms.propertyInfos.BEARINGinfo; import loggerForms.propertyInfos.HEADINGinfo; import loggerForms.propertyInfos.RANGEinfo; +import loggerForms.symbol.LoggerSymbolManager; /** * * @author Graham Weatherup - SMRU @@ -242,7 +241,7 @@ public class FormDescription implements Cloneable, Comparable { formsDataBlock = new FormsDataBlock(this, getFormName(), formsControl.getFormsProcess(), 0); formsDataBlock.SetLogging(new FormsLogging(this,formsDataBlock)); formsDataBlock.setOverlayDraw(new LoggerFormGraphics(formsControl, this)); - formsDataBlock.setPamSymbolManager(new StandardSymbolManager(formsDataBlock, LoggerFormGraphics.defaultSymbol, false)); + formsDataBlock.setPamSymbolManager(new LoggerSymbolManager(formsDataBlock)); setTimeOfNextSave(); @@ -1068,7 +1067,7 @@ public class FormDescription implements Cloneable, Comparable { normalForm = createForm(); formComponent = normalForm.getComponent(); } - formsDataDisplayTable = new FormsDataDisplayTable(this); + formsDataDisplayTable = new FormsDataDisplayTable(formsControl, this); splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, formComponent, formsDataDisplayTable.getMainPanel()); if (formSettingsControl.getFormSettings().splitPanelPosition != null) { @@ -1122,7 +1121,8 @@ public class FormDescription implements Cloneable, Comparable { } public LoggerForm createForm() { - return new LoggerForm(this,LoggerForm.NewDataForm); + boolean viewer = PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW; + return new LoggerForm(this, viewer ? LoggerForm.NewDataForm : LoggerForm.NewDataForm); } @@ -1230,6 +1230,22 @@ public class FormDescription implements Cloneable, Comparable { removeForm(parentFrame); } } + + /** + * Delete a data unit from memory and from database. + * @param dataUnit + * @return + */ + public boolean deleteDataUnit(FormsDataUnit dataUnit) { + if (dataUnit == null) { + return false; + } + boolean ans = getFormsDataBlock().remove(dataUnit, true); + if (formsDataDisplayTable != null) { + formsDataDisplayTable.dataChanged(); + } + return ans; + } /** * Create a new subtab form on the appropriate sub tab panel. */ @@ -1646,6 +1662,15 @@ public class FormDescription implements Cloneable, Comparable { normalForm.restoreData(formsDataUnit); } } + + public void optionsChange() { + if (normalForm != null) { + normalForm.optionsChange(); + } + if (formsDataDisplayTable != null) { + formsDataDisplayTable.optionsChange(); + } + } /** * Get a count of open sub tab forms. diff --git a/src/loggerForms/FormsControl.java b/src/loggerForms/FormsControl.java index 94cf9112..ba34a520 100644 --- a/src/loggerForms/FormsControl.java +++ b/src/loggerForms/FormsControl.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.logging.LogManager; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -34,6 +35,7 @@ import loggerForms.FormDescription.FormPlotOptionsStore; import loggerForms.monitor.FormsMonitorMaster; import PamController.PamControlledUnit; import PamController.PamControlledUnitSettings; +import PamController.PamController; import PamController.PamControllerInterface; import PamController.PamSettingManager; import PamController.PamSettings; @@ -48,16 +50,14 @@ import PamView.PamTabPanel; import PamView.PamView; import PamguardMVC.PamDataBlock; - /** * - * @author Graham Weatherup - * controls the logger forms module + * @author Graham Weatherup controls the logger forms module */ -public class FormsControl extends PamControlledUnit { +public class FormsControl extends PamControlledUnit implements PamSettings { public static ArrayList restrictedTitles = new ArrayList(); - + private ArrayList formDescriptions = new ArrayList(); private ArrayList UDFErrors = new ArrayList(); @@ -66,11 +66,13 @@ public class FormsControl extends PamControlledUnit { private FormsAlertSidePanel formsAlertSidePanel; private FormsProcess formsProcess; - + public static final String unitType = "Logger Forms"; - + private FormsMonitorMaster formsMonitor; - + + private FormsParameters formsParameters = new FormsParameters(); + // /** A set of dummy parameters, used solely to pull together different settings for XML export */ // private FormsTempParams dummyParams; @@ -83,8 +85,7 @@ public class FormsControl extends PamControlledUnit { formsTabPanel = new FormsTabPanel(this); formsAlertSidePanel = new FormsAlertSidePanel(this); formsMonitor = new FormsMonitorMaster(this, formsProcess); -// dummyParams = new FormsTempParams(); -// PamSettingManager.getInstance().registerSettings(this); + PamSettingManager.getInstance().registerSettings(this); } @@ -100,7 +101,7 @@ public class FormsControl extends PamControlledUnit { * */ private boolean buildRestrictedTitles() { - + DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); if (dbControl == null) { return false; @@ -108,30 +109,29 @@ public class FormsControl extends PamControlledUnit { String keywordString = null; try { keywordString = DBControlUnit.findDatabaseControl().getDatabaseSystem().getKeywords(); - } - catch (NullPointerException e) { + } catch (NullPointerException e) { return false; } - + String[] keywords; if (keywordString != null) { keywords = keywordString.split(","); - for (String k:keywords){ + for (String k : keywords) { restrictedTitles.add(k); } } - + try { PamConnection con = DBControlUnit.findConnection(); if (con == null) { return false; } keywordString = con.getConnection().getMetaData().getSQLKeywords(); - + keywords = keywordString.split(","); - - for (String k:keywords){ + + for (String k : keywords) { restrictedTitles.add(k); } // System.out.println(keywordString); @@ -141,20 +141,21 @@ public class FormsControl extends PamControlledUnit { } catch (SQLException e) { e.printStackTrace(); return false; - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); return false; } - + } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see PamController.PamControlledUnit#notifyModelChanged(int) */ @Override public void notifyModelChanged(int changeType) { - switch(changeType) { + switch (changeType) { case PamControllerInterface.INITIALIZATION_COMPLETE: generateForms(); break; @@ -173,29 +174,32 @@ public class FormsControl extends PamControlledUnit { /** * Get the form description for a specific index. + * * @param iForm form index * @return for description */ public FormDescription getFormDescription(int iForm) { return formDescriptions.get(iForm); } - + /** * Get a form index from a form description + * * @param formDescription Form Descriptions * @return form index or -1 if not found */ public int getFormIndex(FormDescription formDescription) { return formDescriptions.indexOf(formDescription); } - + /** - * Find a form which has a particular order value. + * Find a form which has a particular order value. + * * @param order order (starts from 1 generally) - * @return a form, or null if none have that order. + * @return a form, or null if none have that order. */ public FormDescription findFormByOrder(int order) { - for (FormDescription aForm:formDescriptions) { + for (FormDescription aForm : formDescriptions) { PropertyDescription formProperty = aForm.findProperty(PropertyTypes.ORDER); if (formProperty == null) { continue; @@ -210,6 +214,7 @@ public class FormsControl extends PamControlledUnit { /** * Find a form description with a given name. + * * @param formName * @return form description or null. */ @@ -217,7 +222,7 @@ public class FormsControl extends PamControlledUnit { if (formName == null) { return null; } - for (FormDescription ad:formDescriptions) { + for (FormDescription ad : formDescriptions) { if (ad.getFormName().equals(formName)) { return ad; } @@ -227,41 +232,40 @@ public class FormsControl extends PamControlledUnit { } return null; } - - public Character getOutputTableNameCounterSuffix(FormDescription thisFormDescription){ - + + public Character getOutputTableNameCounterSuffix(FormDescription thisFormDescription) { + String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String thisTableName = thisFormDescription.getDBTABLENAME(); - int count=0; + int count = 0; int position = 0; - - for (FormDescription formDescription : formDescriptions){ - if ((formDescription.getDBTABLENAME()==thisFormDescription.getDBTABLENAME())){ - position=count; + + for (FormDescription formDescription : formDescriptions) { + if ((formDescription.getDBTABLENAME() == thisFormDescription.getDBTABLENAME())) { + position = count; break; } - + count++; - + } - // if (count==0){ - // return ""; - // }else{ - // return Character.; - // Integer.toString(arg0, arg1) - // System.out.println("*********"); - // System.out.println(position); - - // } - // System.out.println(letters.charAt(position)); - // System.out.println("*********"); + // if (count==0){ + // return ""; + // }else{ + // return Character.; + // Integer.toString(arg0, arg1) + // System.out.println("*********"); + // System.out.println(position); + + // } + // System.out.println(letters.charAt(position)); + // System.out.println("*********"); return letters.charAt(position); } - /** - * Generates a list of tables beginning with UDF_ and reads - * their contents into a FormDescription + * Generates a list of tables beginning with UDF_ and reads their contents into + * a FormDescription */ public void readUDFTables() { /* @@ -281,7 +285,7 @@ public class FormsControl extends PamControlledUnit { ArrayList udfTableNameList = new ArrayList(); PamConnection dbCon = dbControl.getConnection(); - + if (dbCon == null) { System.out.println("Database not opened: Logger forms cannot be read"); return; @@ -289,42 +293,38 @@ public class FormsControl extends PamControlledUnit { try { DatabaseMetaData dbmd = dbCon.getConnection().getMetaData(); - String[] types = {"TABLE"}; - ResultSet resultSet = dbmd.getTables(null, null, "%", types);//not getting all tables from db in ODB + String[] types = { "TABLE" }; + ResultSet resultSet = dbmd.getTables(null, null, "%", types);// not getting all tables from db in ODB - - - //Loop through database tables - while (resultSet.next()){ + // Loop through database tables + while (resultSet.next()) { String tableName = resultSet.getString(3); // System.out.println("LogFor: "+tableName); - //If starts with 'UDF_' create form description from it. - if( tableName.toUpperCase().startsWith("UDF_")){ + // If starts with 'UDF_' create form description from it. + if (tableName.toUpperCase().startsWith("UDF_")) { udfTableNameList.add(tableName); } } - } catch (SQLException e) { e.printStackTrace(); } - - if (UDFErrors.size()>0){ + if (UDFErrors.size() > 0) { } - for (String tableName:udfTableNameList){ + for (String tableName : udfTableNameList) { FormDescription formDescription = new FormDescription(this, tableName); formDescriptions.add(formDescription); } - - // at this point, before datablocks are created, sort the forms into order. + + // at this point, before datablocks are created, sort the forms into order. Collections.sort(formDescriptions); // hotKeyControl.removeAllListeners(); - // finally create the datablocks. - // at the same time, can reset the order properties to a simple sequence. + // finally create the datablocks. + // at the same time, can reset the order properties to a simple sequence. int iForm = 0; - for (FormDescription aFD:formDescriptions) { + for (FormDescription aFD : formDescriptions) { formsProcess.addOutputDataBlock(aFD.getFormsDataBlock()); aFD.setFormOrderProperty(++iForm); /* @@ -338,21 +338,24 @@ public class FormsControl extends PamControlledUnit { } } - - public void addFormDescription(String newFormName){ + + public void addFormDescription(String newFormName) { FormDescription formDescription = new FormDescription(this, newFormName); formsProcess.addOutputDataBlock(formDescription.getFormsDataBlock()); } /** - * Get the correct type of reference to the forms tab panel. - * @return reference to the forms tab panel. + * Get the correct type of reference to the forms tab panel. + * + * @return reference to the forms tab panel. */ public FormsTabPanel getFormsTabPanel() { return formsTabPanel; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see PamController.PamControlledUnit#getTabPanel() */ @Override @@ -372,8 +375,6 @@ public class FormsControl extends PamControlledUnit { } - - /** * @return the formsProcess */ @@ -381,7 +382,9 @@ public class FormsControl extends PamControlledUnit { return formsProcess; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see PamController.PamControlledUnit#createDetectionMenu(java.awt.Frame) */ @Override @@ -391,27 +394,38 @@ public class FormsControl extends PamControlledUnit { detMenu.add(menuItem); menuItem.addActionListener(new NewLoggerForm(parentFrame)); // if (SMRUEnable.isEnable()) { - JMenu editMenu = new JMenu("Edit form"); - for (int i = 0; i < getNumFormDescriptions(); i++) { - FormDescription fd = getFormDescription(i); - JMenuItem fm = new JMenuItem(fd.getFormName() + "..."); - fm.addActionListener(new EditForm(parentFrame, fd)); - editMenu.add(fm); - } - detMenu.add(editMenu); + JMenu editMenu = new JMenu("Edit form"); + for (int i = 0; i < getNumFormDescriptions(); i++) { + FormDescription fd = getFormDescription(i); + JMenuItem fm = new JMenuItem(fd.getFormName() + "..."); + fm.addActionListener(new EditForm(parentFrame, fd)); + editMenu.add(fm); + } + detMenu.add(editMenu); // } detMenu.add(menuItem = new JMenuItem("Regenerate all forms")); menuItem.addActionListener(new ReGenerateForms(parentFrame)); - - - + if (PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW) { + JCheckBoxMenuItem changebox = new JCheckBoxMenuItem("Allow Viewer changes"); + changebox.setToolTipText("Allow the editing, adding, and deleting of data in Viewer mode"); + changebox.setSelected(formsParameters.allowViewerChanges); + changebox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + formsParameters.allowViewerChanges = changebox.isSelected(); + notifyOptionsChange(); + } + }); + detMenu.add(changebox); + } + return detMenu; } class NewLoggerForm implements ActionListener { - + private Frame parentFrame; - + public NewLoggerForm(Frame parentFrame) { this.parentFrame = parentFrame; } @@ -419,15 +433,22 @@ public class FormsControl extends PamControlledUnit { @Override public void actionPerformed(ActionEvent arg0) { newLoggerform(parentFrame); - } - + } + + private void notifyOptionsChange() { + if (formDescriptions == null) { + return; + } + for (FormDescription formDesc: formDescriptions) { + formDesc.optionsChange(); + } } class ReGenerateForms implements ActionListener { - + private Frame parentFrame; - + public ReGenerateForms(Frame parentFrame) { this.parentFrame = parentFrame; } @@ -435,37 +456,41 @@ public class FormsControl extends PamControlledUnit { @Override public void actionPerformed(ActionEvent arg0) { regenerateForms(parentFrame); - + } - + } - + class EditForm implements ActionListener { private FormDescription formDescription; private Frame parentFrame; + public EditForm(Frame parentFrame, FormDescription formDescription) { super(); this.parentFrame = parentFrame; this.formDescription = formDescription; } + @Override public void actionPerformed(ActionEvent arg0) { this.formDescription.editForm(parentFrame); } } - + /** * Create a new logger form + * * @param parentFrame parent frame - * @return selected name for new form, or null if nothing created. + * @return selected name for new form, or null if nothing created. */ public String newLoggerform(Frame parentFrame) { - String newName = JOptionPane.showInputDialog(parentFrame, "Enter the name for the new user form", "New Logger Form", JOptionPane.OK_CANCEL_OPTION); + String newName = JOptionPane.showInputDialog(parentFrame, "Enter the name for the new user form", + "New Logger Form", JOptionPane.OK_CANCEL_OPTION); if (newName == null) { return null; } // will make a form table definition with a standard structure and name UDF_ ... - // check the current name starts with UDF and add if necessary. + // check the current name starts with UDF and add if necessary. if (newName.toUpperCase().startsWith("UDF_") == false) { newName = "UDF_" + newName; } @@ -473,11 +498,11 @@ public class FormsControl extends PamControlledUnit { message += "\nNote that youwill have to exit PAMGUARD and enter form control data by hand into this table."; message += "\nFuture releases will (hopefully) contain a more friendly programmable interface"; int ans = JOptionPane.showConfirmDialog(parentFrame, message, "Create Form", JOptionPane.OK_CANCEL_OPTION); - if(ans == JOptionPane.CANCEL_OPTION) { + if (ans == JOptionPane.CANCEL_OPTION) { return null; } UDFTableDefinition tableDef = new UDFTableDefinition(newName); - message = String.format("The table %s could not be created in the databse %s", newName, + message = String.format("The table %s could not be created in the databse %s", newName, DBControlUnit.findDatabaseControl().getDatabaseName()); if (DBControlUnit.findDatabaseControl().getDbProcess().checkTable(tableDef) == false) { JOptionPane.showMessageDialog(parentFrame, "Error Creating form", message, JOptionPane.ERROR_MESSAGE); @@ -485,33 +510,32 @@ public class FormsControl extends PamControlledUnit { return newName; } - /** * Generate all forms and associated processes, notifying databases, maps, etc - * so that any required actions can be taken. + * so that any required actions can be taken. */ private void generateForms() { buildRestrictedTitles(); - + readUDFTables(); createProcesses(); - + formsTabPanel.createForms(); - // initialise + // initialise DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); if (dbControl == null) { return; } - + DBControlUnit.findDatabaseControl().getDbProcess().updateProcessList(); if (isViewer) { updateFormDataMaps(); } - - formsAlertSidePanel.getFormsAlertPanel().updateFormsShowing(); + + formsAlertSidePanel.getFormsAlertPanel().updateFormsShowing(); // will also at this point need to tell the main gui frame to update // it's menu since it needs to incorporate a list of forms for editing PamView pamView = getPamView(); @@ -522,22 +546,23 @@ public class FormsControl extends PamControlledUnit { formsMonitor.rebuiltForms(); } - + /** - * Delete and recreate all forms / form data, etc. + * Delete and recreate all forms / form data, etc. + * * @param parentFrame */ public void regenerateForms(Window parentFrame) { formsTabPanel.removeAllForms(); - - for (FormDescription formDescription:formDescriptions) { + + for (FormDescription formDescription : formDescriptions) { formDescription.destroyForms(); } formDescriptions.clear(); formsProcess.removeAllDataBlocks(); generateForms(); FormsPlotOptionsDialog.deleteDialog(); - + } @Override @@ -565,14 +590,16 @@ public class FormsControl extends PamControlledUnit { boolean ans = FormsPlotOptionsDialog.showDialog(parentFrame, this); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see PamController.PamControlledUnit#canClose() */ @Override public boolean canClose() { // return false if any forms have open sub forms. int subFormCount = 0; - for (FormDescription fd:formDescriptions) { + for (FormDescription fd : formDescriptions) { subFormCount += fd.getSubformCount(); } if (subFormCount == 0) { @@ -584,10 +611,10 @@ public class FormsControl extends PamControlledUnit { } /** - * Rewrite all UDF tables in forms which have been altered. + * Rewrite all UDF tables in forms which have been altered. */ public void rewriteChangedUDFTables() { - for (FormDescription aForm:formDescriptions) { + for (FormDescription aForm : formDescriptions) { if (aForm.isNeedsUDFSave()) { aForm.writeUDFTable(null); aForm.setNeedsUDFSave(false); @@ -614,10 +641,10 @@ 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. + * 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 */ @@ -637,48 +664,31 @@ public class FormsControl extends PamControlledUnit { int val = (Integer) value; return val != 0; } - + return null; } -// @Override -// public Serializable getSettingsReference() { -// return (Serializable) dummyParams; -// } -// -// @Override -// public long getSettingsVersion() { -// return 0; -// } -// -// @Override -// public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { -// return false; -// } -// -// /** -// * Private class to pass along various parameter classes that Logger forms use -// * -// * @author mo55 -// * -// */ -// private class FormsTempParams implements ManagedParameters { -// -// @Override -// public PamParameterSet getParameterSet() { -// PamParameterSet ps = new PamParameterSet(this); -// try { -// Field field = FormsControl.this.getClass().getDeclaredField("formDescriptions"); -// ps.put(new PrivatePamParameterData(this, field) { -// @Override -// public Object getData() throws IllegalArgumentException, IllegalAccessException { -// return formDescriptions; -// } -// }); -// } catch (NoSuchFieldException | SecurityException e) { -// e.printStackTrace(); -// } -// return ps; -// } -// } + + @Override + public Serializable getSettingsReference() { + return formsParameters; + } + + @Override + public long getSettingsVersion() { + return FormsParameters.serialVersionUID; + } + + @Override + public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { + this.formsParameters = (FormsParameters) pamControlledUnitSettings.getSettings(); + return true; + } + + /** + * @return the formsParameters + */ + public FormsParameters getFormsParameters() { + return formsParameters; + } } diff --git a/src/loggerForms/FormsDataBlock.java b/src/loggerForms/FormsDataBlock.java index ff6aa1a1..220ae3ba 100644 --- a/src/loggerForms/FormsDataBlock.java +++ b/src/loggerForms/FormsDataBlock.java @@ -7,6 +7,8 @@ import PamguardMVC.PamProcess; import PamguardMVC.dataSelector.DataSelector; import PamguardMVC.dataSelector.DataSelectorCreator; import loggerForms.dataselect.FormDataSelCreator; +import loggerForms.effort.FormsEffortUnit; +import loggerForms.effort.LoggerEffortProvider; import loggerForms.monitor.FormsDataSelectorCreator; /** * @@ -16,6 +18,8 @@ import loggerForms.monitor.FormsDataSelectorCreator; public class FormsDataBlock extends PamDataBlock { private FormDescription formDescription; + + private LoggerEffortProvider loggerEffortProvider; public FormsDataBlock(FormDescription formDescription, String dataName, PamProcess parentProcess, int channelMap) { @@ -25,6 +29,7 @@ public class FormsDataBlock extends PamDataBlock { setDataSelectCreator(new FormDataSelCreator(this, formDescription)); // setBinaryDataSource(new FormsBinaryIO(formDescription.getFormsControl(), this)); // setNaturalLifetimeMillis(60000); + setEffortProvider(loggerEffortProvider = new LoggerEffortProvider(this)); } public FormDescription getFormDescription() { diff --git a/src/loggerForms/FormsDataDisplayTable.java b/src/loggerForms/FormsDataDisplayTable.java index 1300fc79..011739f2 100644 --- a/src/loggerForms/FormsDataDisplayTable.java +++ b/src/loggerForms/FormsDataDisplayTable.java @@ -4,10 +4,15 @@ package loggerForms; import java.awt.GridLayout; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.ListSelectionEvent; @@ -20,6 +25,7 @@ import PamController.PamController; import PamUtils.PamCalendar; import PamView.PamTable; import PamView.dialog.PamDialog; +import PamView.dialog.warn.WarnOnce; import PamguardMVC.PamDataBlock; /** @@ -37,11 +43,13 @@ public class FormsDataDisplayTable { private JScrollPane scrollPane; + private FormsControl formsControl; + /** * @param formDescription */ - public FormsDataDisplayTable(FormDescription formDescription) { - // TODO Auto-generated constructor stub + public FormsDataDisplayTable(FormsControl formsControl, FormDescription formDescription) { + this.formsControl = formsControl; this.formDescription=formDescription; // GridLayout(rows,columns) @@ -63,36 +71,16 @@ public class FormsDataDisplayTable { formsTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); // for now, don't allow edits in viewer mode. - if (PamController.getInstance().getRunMode() != PamController.RUN_PAMVIEW) { +// if (PamController.getInstance().getRunMode() != PamController.RUN_PAMVIEW) { formsTable.addMouseListener(new EditDataListener()); - } +// } scrollPane = new JScrollPane(formsTable); mainPanel.add(scrollPane); - -// mainPanel.setPreferredSize(new Dimension(800, 200)); - - - } -// class TimerListener implements ActionListener { -// boolean doneLayout; -// public void actionPerformed(ActionEvent ev) { -// // table. -//// nmeaTableData.fireTableRowsUpdated(0, 10); -// formsTableDataModel.fireTableDataChanged(); -// -// if (doneLayout == false && formsTableDataModel.getRowCount() > 0) { -// doneLayout = true; -// } -// } -// } - - - class TableListListener implements ListSelectionListener { @Override @@ -108,9 +96,15 @@ public class FormsDataDisplayTable { formDescription.viewDataUnit(formsDataUnit); } } - } + private boolean canEdit() { + if (PamController.getInstance().getRunMode() != PamController.RUN_PAMVIEW) { + return true; + } + if (formsControl == null) return false; + return formsControl.getFormsParameters().allowViewerChanges; + } /** * Find the data unit for a particular row in the table. * @param iRow @@ -125,9 +119,11 @@ public class FormsDataDisplayTable { class EditDataListener extends MouseAdapter{ @Override public void mouseClicked(MouseEvent e) { + if (canEdit() == false) { + return; + } if (e.getClickCount() == 2) { -// FormsDataBlock formsDataBlock = formDescription.getFormsDataBlock(); int row = formsTable.getSelectedRow(); FormsDataUnit formsDataUnit = findDataUnitForRow(row); @@ -135,14 +131,32 @@ public class FormsDataDisplayTable { PamDialog.showWarning(null, "WARNING", "could not find formsDataUnit"); return; } - - - - FormsDataUnitEditor due = new FormsDataUnitEditor(formDescription,formsDataUnit); - + editDataUnit(formsDataUnit); } } + + @Override + public void mousePressed(MouseEvent e) { + maybePopup(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + maybePopup(e); + } + + private void maybePopup(MouseEvent e) { + if (e.isPopupTrigger() == false) { + return; + } + if (canEdit() == false) { + return; + } + int row = formsTable.getSelectedRow(); + + showPopupMenu(e.getPoint()); + } } @@ -259,9 +273,69 @@ public class FormsDataDisplayTable { return mainPanel; } + public void showPopupMenu(Point pt) { + + FormsDataUnit dataUnit = findDataUnitForRow(formsTable.getSelectedRow()); + JPopupMenu menu = new JPopupMenu(); + JMenuItem menuItem; + if (dataUnit != null) { + menuItem = new JMenuItem("Edit row ..."); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + editDataUnit(dataUnit); + } + }); + menu.add(menuItem); + } + menuItem = new JMenuItem("Create row ..."); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + addDataUnit(); + } + }); + menu.add(menuItem); + + if (dataUnit != null) { + menu.addSeparator(); + menuItem = new JMenuItem("Delete row ..."); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + deleteDataUnit(dataUnit); + } + }); + menu.add(menuItem); + } + menu.show(formsTable, pt.x, pt.y); + } + + private boolean editDataUnit(FormsDataUnit dataUnit) { + FormsDataUnitEditor due = new FormsDataUnitEditor(formDescription, dataUnit); + return true; + } + + private boolean deleteDataUnit(FormsDataUnit dataUnit) { + if (dataUnit == null) { + return false; + } + int ans = WarnOnce.showWarning("Delete logger form data", "Are you sure you want to delete data Id " + dataUnit.getDatabaseIndex(), WarnOnce.OK_CANCEL_OPTION); + if (ans != WarnOnce.OK_OPTION) { + return false; + } + formDescription.deleteDataUnit(dataUnit); + return true; + } + + private boolean addDataUnit() { + formDescription.viewDataUnit(null); + return false; + } + /** * Called when data have changed in the datablock. */ @@ -276,4 +350,12 @@ public class FormsDataDisplayTable { public JScrollPane getScrollPane() { return scrollPane; } + + /** + * Some optins have changed. + */ + public void optionsChange() { + // TODO Auto-generated method stub + + } } diff --git a/src/loggerForms/FormsDataUnit.java b/src/loggerForms/FormsDataUnit.java index 32ab905d..30cb4f0a 100644 --- a/src/loggerForms/FormsDataUnit.java +++ b/src/loggerForms/FormsDataUnit.java @@ -2,7 +2,10 @@ package loggerForms; import GPS.GpsData; import PamUtils.PamCalendar; +import PamView.GeneralProjector; import PamguardMVC.PamDataUnit; +import generalDatabase.SQLTypes; +import loggerForms.controlDescriptions.ControlDescription; /** * * @author Graham Weatherup @@ -12,9 +15,6 @@ import PamguardMVC.PamDataUnit; * UTCmillisecond * PCLocalTime * - * - * - * */ public class FormsDataUnit extends PamDataUnit { @@ -94,6 +94,82 @@ public class FormsDataUnit extends PamDataUnit { return formOriginLatLong; } + @Override + public long getTimeMilliseconds() { + Long time = findTimeValue(PropertyTypes.STARTTIME); + if (time != null) { + return time; + } + return super.getTimeMilliseconds(); + } + + /** + * Find one of the time property controls and get its value. + * @param timeProperty + * @return + */ + public Long findTimeValue(PropertyTypes timeProperty) { + if (formData == null) { + return null; + } + PropertyDescription prop = formDescription.findProperty(timeProperty); + if (prop == null) { + return null; + } + String ctrlTitle = prop.getItemInformation().getStringProperty("Title"); + if (ctrlTitle == null) { + return null; + } + int timeControlIndex = formDescription.findInputControlByName(ctrlTitle); + if (timeControlIndex < 0 || timeControlIndex >= formData.length) { + return null; + } + Object timeObj = formData[timeControlIndex]; + /* + * this should have found the time contol in the form of a string from the database. + * try to unpack it. + */ + Long timeMillis = SQLTypes.millisFromTimeStamp(timeObj); + + return timeMillis; + } + + /** + * find a correctly set property value for the end time (if set). + * @return + */ + public Long getSetEndTime() { + return findTimeValue(PropertyTypes.ENDTIME); + } + + @Override + public long getEndTimeInMilliseconds() { + Long time = findTimeValue(PropertyTypes.ENDTIME); + if (time != null) { + return time; + } + return super.getEndTimeInMilliseconds(); + } + + @Override + public String getSummaryString() { + String str = String.format("%s", formDescription.getFormNiceName()); + Object[] data = getFormData(); + int iDat = 0; + for (ControlDescription cd:formDescription.getInputControlDescriptions()) { + if (data[iDat] == null) { + str += String.format("

%s: -", cd.getTitle()); + } + else { + str += String.format("

%s: %s", cd.getTitle(), data[iDat].toString()); + } + iDat++; + } + + str += ""; + return str; + } + } diff --git a/src/loggerForms/FormsDataUnitEditor.java b/src/loggerForms/FormsDataUnitEditor.java index 9cbb8fbc..deea3dff 100644 --- a/src/loggerForms/FormsDataUnitEditor.java +++ b/src/loggerForms/FormsDataUnitEditor.java @@ -16,8 +16,6 @@ import PamUtils.PamCalendar; public class FormsDataUnitEditor{ - - /** * @param formDescription * @param formsDataUnit @@ -29,8 +27,6 @@ public class FormsDataUnitEditor{ JFrame frame=PamController.getInstance().getGuiFrameManager().getFrame(frameNo); - - FormsDataUnit updatedData = FormsDataUnitEditDialog.showDialog(frame, formDescription, formsDataUnit); if (updatedData != null) { diff --git a/src/loggerForms/FormsLogging.java b/src/loggerForms/FormsLogging.java index 64e0d8e6..e2c9c843 100644 --- a/src/loggerForms/FormsLogging.java +++ b/src/loggerForms/FormsLogging.java @@ -2,16 +2,20 @@ package loggerForms; import java.util.ArrayList; +import PamController.PamViewParameters; import loggerForms.controlDescriptions.ControlDescription; import loggerForms.controlDescriptions.InputControlDescription; +import pamScrollSystem.ViewLoadObserver; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; +import generalDatabase.PamConnection; +import generalDatabase.PamTableDefinition; import generalDatabase.SQLLogging; import generalDatabase.SQLTypes; public class FormsLogging extends SQLLogging { - FormDescription formDescription; + private FormDescription formDescription; protected FormsLogging(FormDescription formDescription, PamDataBlock pamDataBlock) { super(pamDataBlock); @@ -20,53 +24,34 @@ public class FormsLogging extends SQLLogging { setTableDefinition(formDescription.getOutputTableDef()); } -// @Override -// public void setTableData(PamDataUnit pamDataUnit) { -// -// FormsDataUnit formDataUnit = (FormsDataUnit) pamDataUnit; -// int dataLen = formDataUnit.getFormData().length; -// int tableLen= getTableDefinition().getTableItemCount(); -// -//// for (int j=0;j inputCtrls = formDescription.getInputControlDescriptions(); InputControlDescription cd; @@ -76,9 +61,6 @@ public class FormsLogging extends SQLLogging { } -// for (ControlDescription controlDescription:formDescription.getInputControlDescriptions()){ -// controlDescription.moveDataTo -// } } /* (non-Javadoc) @@ -98,21 +80,6 @@ public class FormsLogging extends SQLLogging { } } -// -// int dataLen = formDescription.getInputControlDescriptions().size(); -// int tableLen= getTableDefinition().getTableItemCount(); -// int diff = tableLen-dataLen; -// Object[] formData = new Object[dataLen]; -// int tableIndex; -// for (int j=0;j for now this is basically just disabling buttons if * we're in viewer mode. A More sophisticated function - * might consider enabling / diabling depending on whether + * might consider enabling / disabling depending on whether * or not a form can be saved. */ public void enableControls() { boolean isViewer = PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW; - if (saveButton != null) saveButton.setEnabled(!isViewer); - if (clearButton != null) clearButton.setEnabled(!isViewer); - if (cancelButton != null) cancelButton.setEnabled(!isViewer); + boolean viewerEds = false; + if (formDescription != null) { + FormsControl formsControl = formDescription.getFormsControl(); + viewerEds = formsControl.getFormsParameters().allowViewerChanges; + } + if (saveButton != null) { + saveButton.setEnabled(!isViewer || viewerEds); + if (isViewer) { + saveButton.setText(restoredDataUnit == null ? "Save" : "Update..."); + } + } + if (clearButton != null) { + clearButton.setEnabled(!isViewer); + } + if (cancelButton != null) { + cancelButton.setEnabled(!isViewer); + } } class SaveButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Save")) { +// if (e.getActionCommand().equals("Save")) { String er = getFormErrors(); getFormWarnings(); @@ -628,7 +645,7 @@ public class LoggerForm{ if (er==null){ save(); } - } +// } } } @@ -636,17 +653,16 @@ public class LoggerForm{ @Override public void actionPerformed(ActionEvent e) { - if (e.getActionCommand().equals("Save")) { +// if (e.getActionCommand().equals("Save")) { String er = getFormErrors(); getFormWarnings(); - - + if (er==null){ save(); formDescription.removeSubtabform(loggerForm); } - } +// } } } @@ -737,9 +753,16 @@ public class LoggerForm{ * @param formsDataUnit */ void restoreData(FormsDataUnit formsDataUnit){ - // this.formsDataUnit = formsDataUnit; - Object[] formData = formsDataUnit.getFormData(); - transferDataArrayToForm(formData); + restoredDataUnit = formsDataUnit; + if (formsDataUnit != null) { + // this.formsDataUnit = formsDataUnit; + Object[] formData = formsDataUnit.getFormData(); + transferDataArrayToForm(formData); + } + else { + clear(); + } + enableControls(); } /** @@ -840,14 +863,40 @@ public class LoggerForm{ * Extract and save teh data inot a new PAmDAtaUnit. */ private void save() { - //create form data object v + //create form data object Object[] formData = extractFormData(); + + boolean isViewer = PamController.getInstance().getRunMode() == PamController.RUN_PAMVIEW; + boolean isNew = true; + if (isViewer && restoredDataUnit != null) { + isNew = false; + } - if (NewOrEdit==NewDataForm){ + if (isNew){ FormsDataUnit formDataUnit = new FormsDataUnit(loggerForm,PamCalendar.getTimeInMillis(), formDescription, formData); - // dU.setParentDataBlock(formDescription.getFormsDataBlock()); -// System.out.println(formDescription.getXMLData(formDataUnit)); formDescription.getFormsDataBlock().addPamData(formDataUnit); + // in viewer mode, will need to do something to get this to save. + if (isViewer) { + formDescription.getFormsDataBlock().getLogging().logData(DBControlUnit.findConnection(), formDataUnit); + formDescription.getFormsDataBlock().sortData(); + } + } + else { + // update the data form. Ask first. + Frame win = formDescription.getFormsControl().getGuiFrame(); + String msg = "Do you want to update this form with new data ?"; + int ans = WarnOnce.showWarning(win, "Logger forms: " + formDescription.getFormName(), msg, WarnOnce.OK_CANCEL_OPTION); + if (ans == WarnOnce.OK_OPTION) { + if (restoredDataUnit == null) { + WarnOnce.showWarning(win, "Logger forms: " + formDescription.getFormName(), "No data to update", WarnOnce.WARNING_MESSAGE); + } + else { + restoredDataUnit.setFormsData(loggerForm, formData); + // should update database on next SaveData, but not before. + formDescription.getFormsDataBlock().updatePamData(restoredDataUnit, PamCalendar.getTimeInMillis()); + formDescription.getFormsDataBlock().sortData(); + } + } } // else if(NewOrEdit==EditDataForm && formsDataUnit != null){ // formsDataUnit.setFormsData(formData); @@ -914,6 +963,9 @@ public class LoggerForm{ public JButton getSaveButton() { return saveButton; } + public void optionsChange() { + enableControls(); + } // public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) { // GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit); diff --git a/src/loggerForms/LoggerFormGraphics.java b/src/loggerForms/LoggerFormGraphics.java index 57612663..7ad5759f 100644 --- a/src/loggerForms/LoggerFormGraphics.java +++ b/src/loggerForms/LoggerFormGraphics.java @@ -32,6 +32,7 @@ import PamView.PamSymbolType; import PamView.PanelOverlayDraw; import PamView.GeneralProjector.ParameterType; import PamView.GeneralProjector.ParameterUnits; +import PamView.symbol.PamSymbolChooser; import PamView.symbol.SymbolData; import PamguardMVC.PamDataUnit; @@ -189,7 +190,7 @@ public class LoggerFormGraphics extends PanelOverlayDraw { double shipCourse = plotOrigin.getCourseOverGround(); double shipHead = plotOrigin.getHeading(); - PamSymbol plotSymbol = getPlotSymbol(formDataUnit); + PamSymbol plotSymbol = getPlotSymbol(generalProjector, formDataUnit); Coordinate3d detOrigin = generalProjector.getCoord3d(plotOrigin.getLatitude(), plotOrigin.getLongitude(), plotOrigin.getHeight()); // see if there is range heading and bearing data. @@ -248,7 +249,7 @@ public class LoggerFormGraphics extends PanelOverlayDraw { int nControls = data.length; ControlDescription controlDescription; ArrayList controlDescriptions = formDescription.getInputControlDescriptions(); - PamSymbol plotSymbol = getPlotSymbol(dataUnit); + PamSymbol plotSymbol = getPlotSymbol(generalProjector, dataUnit); if (plotSymbol == null) { return null; } @@ -354,7 +355,22 @@ public class LoggerFormGraphics extends PanelOverlayDraw { * @param pamDataUnit data unit to plot * @return symbol. */ - private PamSymbol getPlotSymbol(FormsDataUnit dataUnit) { + private PamSymbol getPlotSymbol(GeneralProjector projector, FormsDataUnit dataUnit) { + /** + * Try to use the new selector system. If it's not there, then revert to + * the older system. + */ + PamSymbolChooser chooser = null; + if (projector != null) { + chooser = projector.getPamSymbolChooser(); + } + if (chooser != null) { + PamSymbol chosenSymbol = chooser.getPamSymbol(projector, dataUnit); + if (chosenSymbol != null) { + return chosenSymbol; + } + } + /** * first go through all the controls and see which is * the first one that's initiated plotting. If it's @@ -409,22 +425,7 @@ public class LoggerFormGraphics extends PanelOverlayDraw { @Override public String getHoverText(GeneralProjector generalProjector, PamDataUnit dataUnit, int iSide) { - FormsDataUnit formsDU = (FormsDataUnit) dataUnit; - String str = String.format("%s", formDescription.getFormNiceName()); - Object[] data = formsDU.getFormData(); - int iDat = 0; - for (ControlDescription cd:formDescription.getInputControlDescriptions()) { - if (data[iDat] == null) { - str += String.format("

%s: -", cd.getTitle()); - } - else { - str += String.format("

%s: %s", cd.getTitle(), data[iDat].toString()); - } - iDat++; - } - - str += ""; - return str; + return dataUnit.getSummaryString(); } private void createSymbols() { diff --git a/src/loggerForms/PropertyTypes.java b/src/loggerForms/PropertyTypes.java index b0a034f9..b473ee7a 100644 --- a/src/loggerForms/PropertyTypes.java +++ b/src/loggerForms/PropertyTypes.java @@ -1,7 +1,7 @@ package loggerForms; public enum PropertyTypes { - ORDER, AUTOALERT,SUBTABS,POPUP,HIDDEN,AUTORECORD,BEARING, + STARTTIME, ENDTIME, ORDER, AUTOALERT,SUBTABS,POPUP,HIDDEN,AUTORECORD,BEARING, RANGE,HEADING,FONT,DBTABLENAME, FORMCOLOUR,FORMCOLOR, HOTKEY,NOCLEAR,NOCANCEL,NOTOFFLINE,NOTONLINE, @@ -16,6 +16,10 @@ public enum PropertyTypes { public String getDescription() { switch (this) { + case STARTTIME: + return "Form start time. Will be used as main data UTC. If undefined, form time is save time"; + case ENDTIME: + return "Form end time. Will be used data end time in period data"; case AUTOALERT: return "A warning will be issued if the form has not been completed for a set time"; case AUTORECORD: diff --git a/src/loggerForms/controlDescriptions/ControlDescription.java b/src/loggerForms/controlDescriptions/ControlDescription.java index 85b780b9..80b34940 100644 --- a/src/loggerForms/controlDescriptions/ControlDescription.java +++ b/src/loggerForms/controlDescriptions/ControlDescription.java @@ -3,8 +3,6 @@ */ package loggerForms.controlDescriptions; -import generalDatabase.EmptyTableDefinition; - import java.sql.Types; import javax.swing.JPanel; @@ -12,7 +10,6 @@ import javax.swing.JPanel; import org.w3c.dom.Document; import org.w3c.dom.Element; -import PamUtils.XMLUtils; import loggerForms.FormDescription; import loggerForms.FormsDataUnit; import loggerForms.FormsTableItem; @@ -37,7 +34,6 @@ public abstract class ControlDescription extends ItemDescription { protected ControlDescription(FormDescription formDescription, ItemInformation itemInformation) { super(formDescription, itemInformation); eType = ControlTypes.valueOf(getType()); -// System.out.println(getType()+";"+eType.toString()); } @@ -88,11 +84,6 @@ public abstract class ControlDescription extends ItemDescription { return formsTableItems; } - - - - - private ControlTypes eType; /** diff --git a/src/loggerForms/effort/FormsEffortUnit.java b/src/loggerForms/effort/FormsEffortUnit.java new file mode 100644 index 00000000..294218cb --- /dev/null +++ b/src/loggerForms/effort/FormsEffortUnit.java @@ -0,0 +1,15 @@ +package loggerForms.effort; + +import effort.EffortDataUnit; +import loggerForms.FormsDataUnit; + +public class FormsEffortUnit extends EffortDataUnit { + + private FormsDataUnit parentFormUnit; + + public FormsEffortUnit(LoggerEffortProvider loggerEffortProvider, FormsDataUnit parentFormUnit, long formEndTime) { + super(loggerEffortProvider, parentFormUnit, parentFormUnit.getTimeMilliseconds(), formEndTime); + this.parentFormUnit = parentFormUnit; + } + +} diff --git a/src/loggerForms/effort/LoggerEffortProvider.java b/src/loggerForms/effort/LoggerEffortProvider.java new file mode 100644 index 00000000..0cf79889 --- /dev/null +++ b/src/loggerForms/effort/LoggerEffortProvider.java @@ -0,0 +1,165 @@ +package loggerForms.effort; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import PamController.PamController; +import PamView.symbol.PamSymbolManager; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import PamguardMVC.dataSelector.DataSelector; +import dataMap.OfflineDataMap; +import effort.EffortDataUnit; +import effort.EffortProvider; +import loggerForms.FormDescription; +import loggerForms.FormsDataBlock; +import loggerForms.FormsDataUnit; + +public class LoggerEffortProvider extends EffortProvider { + + private FormsDataBlock formsDataBlock; + + private ArrayList onlineEffort; + + public LoggerEffortProvider(FormsDataBlock parentDataBlock) { + super(parentDataBlock); + this.formsDataBlock = parentDataBlock; + FormDescription formsDescription = parentDataBlock.getFormDescription(); + } + +// @Override +// public EffortDataUnit getEffort(long timeMilliseconds) { +// ListIterator iterator = formsDataBlock.getListIterator(timeMilliseconds, 0, PamDataBlock.MATCH_BEFORE, PamDataBlock.POSITION_BEFORE); +// FormsDataUnit currentUnit = null; +// FormsDataUnit nextUnit = null; +// if (iterator == null) { +// return null; +// } +// +// if (iterator.hasNext()) { +// currentUnit = iterator.next(); +// } +// if (iterator.hasNext()) { +// nextUnit = iterator.next(); +// } +// if (currentUnit == null) { +// return null; +// } +// long endTime = getEndTime(currentUnit, nextUnit); +// +// return new FormsEffortUnit(this, currentUnit, endTime); +// } + + private long getEndTime(FormsDataUnit currentUnit, FormsDataUnit nextUnit) { + Long end = currentUnit.getSetEndTime(); + if (end != null) { + return end; + } + if (nextUnit == null) { + return getLastDatasetTime(); + } + else { + return nextUnit.getTimeMilliseconds(); + } + } + + @Override + public List getAllEffortThings() { + return onlineEffort; + } + + @Override + public void viewerLoadData() { + ArrayList allList = new ArrayList(); + ListIterator iterator = formsDataBlock.getListIterator(0); + FormsDataUnit currentUnit = null; + FormsDataUnit nextUnit = null; + if (iterator.hasNext()) { + currentUnit = iterator.next(); + } + while (iterator.hasNext()) { + nextUnit = iterator.next(); + long end = getEndTime(currentUnit, nextUnit); + allList.add(new FormsEffortUnit(this, currentUnit, end)); + currentUnit = nextUnit; + } + if (currentUnit != null) { + long end = getEndTime(currentUnit, null); + allList.add(new FormsEffortUnit(this, currentUnit, end)); + } + onlineEffort = allList; + } + + @Override + public DataSelector getDataSelector(String selectorName) { + // TODO Auto-generated method stub + return null; + } + + @Override + public PamSymbolManager getSymbolManager() { + return formsDataBlock.getPamSymbolManager(); + } + + /** + * Get the last time of any data in this dataset from any data map. + * @return + */ + private long getLastDatasetTime() { + long lastTime = Long.MIN_VALUE; + ArrayList allData = PamController.getInstance().getDataBlocks(); + for (PamDataBlock aBlock : allData) { + OfflineDataMap dataMap = aBlock.getPrimaryDataMap(); + if (dataMap != null) { + lastTime = Math.max(lastTime, dataMap.getLastDataTime()); + } + } + + return lastTime; + } + + @Override + public String getName() { + return formsDataBlock.getDataName(); + } + + @Override + public void realTimeStart(long timeMilliseconds) { + // Don't do anything with start and end of processing + } + + @Override + public void realTimeStop(long timeMilliseconds) { + // Don't do anything with start and end of processing + } + + @Override + public void newData(PamDataUnit pamDataUnit) { + // generate effort things from incoming form data. + if (onlineEffort == null) { + onlineEffort = new ArrayList<>(); + } + FormsEffortUnit lastEffort = null; + if (onlineEffort.size() > 0) { + lastEffort = (FormsEffortUnit) onlineEffort.get(onlineEffort.size()-1); + } + FormsDataUnit formDataUnit = (FormsDataUnit) pamDataUnit; + long thisStart = formDataUnit.getTimeMilliseconds(); + Long thisEnd = formDataUnit.getSetEndTime(); + if (lastEffort != null) { + /* + * If the previous effort didn't have a end time, then use this start as that's end. + */ + if (lastEffort.getEffortEnd() >= EffortDataUnit.ONGOINGEFFORT/2) { + lastEffort.setEffortEnd(thisStart); + } + } + if (thisEnd == null) { + thisEnd = EffortDataUnit.ONGOINGEFFORT; + } + FormsEffortUnit newEffort = new FormsEffortUnit(this, formDataUnit, thisEnd); + onlineEffort.add(newEffort); + } + +} diff --git a/src/loggerForms/formdesign/FormEditor.java b/src/loggerForms/formdesign/FormEditor.java index 35df6d9b..4bc49adf 100644 --- a/src/loggerForms/formdesign/FormEditor.java +++ b/src/loggerForms/formdesign/FormEditor.java @@ -11,6 +11,7 @@ import loggerForms.ItemInformation; import loggerForms.PropertyDescription; import loggerForms.PropertyTypes; import loggerForms.UDColName; +import loggerForms.controlDescriptions.ControlTypes; import loggerForms.formdesign.propertypanels.AutoAlertPanel; import loggerForms.formdesign.propertypanels.BearingPanel; import loggerForms.formdesign.propertypanels.BooleanPanel; @@ -26,6 +27,7 @@ import loggerForms.formdesign.propertypanels.PropertyPanel; import loggerForms.formdesign.propertypanels.RangePanel; import loggerForms.formdesign.propertypanels.SymbolPanel; import loggerForms.formdesign.propertypanels.TextPanel; +import loggerForms.formdesign.propertypanels.XReferencePanel; /** * Layer that sits between the form description and the actual edit @@ -154,6 +156,10 @@ public class FormEditor { public PropertyPanel makePropertyPanel(PropertyTypes propertyType) { switch (propertyType) { + case STARTTIME: + return new XReferencePanel(this, propertyType, ControlTypes.TIMESTAMP); + case ENDTIME: + return new XReferencePanel(this, propertyType, ControlTypes.TIMESTAMP); case AUTOALERT: return new IntegerPanel(this, propertyType, UDColName.AutoUpdate, "Alert operator every", "minutes"); case AUTORECORD: diff --git a/src/loggerForms/formdesign/propertypanels/XReferencePanel.java b/src/loggerForms/formdesign/propertypanels/XReferencePanel.java new file mode 100644 index 00000000..84ec28f4 --- /dev/null +++ b/src/loggerForms/formdesign/propertypanels/XReferencePanel.java @@ -0,0 +1,95 @@ +package loggerForms.formdesign.propertypanels; + +import java.util.ArrayList; + +import javax.swing.JComboBox; +import javax.swing.JLabel; + +import loggerForms.ItemInformation; +import loggerForms.PropertyTypes; +import loggerForms.UDColName; +import loggerForms.controlDescriptions.ControlTypes; +import loggerForms.formdesign.ControlTitle; +import loggerForms.formdesign.FormEditor; +import loggerForms.formdesign.FormEditor.EditNotify; + +/** + * Property form for a cross reference sontrol. + * @author dg50 + * + */ +public class XReferencePanel extends PropertyPanel { + + private ControlTypes controlType; + + private JComboBox fieldNames; + + public XReferencePanel(FormEditor formEditor, PropertyTypes propertyType, ControlTypes controlType) { + super(formEditor, propertyType); + this.controlType = controlType; + addItem(new JLabel(" Use ")); + addItem(fieldNames = new JComboBox()); + } + /* (non-Javadoc) + * @see loggerForms.formdesign.propertypanels.PropertyPanel#notifyChanges(loggerForms.formdesign.FormEditor.EditNotify) + */ + @Override + public void notifyChanges(EditNotify notifyType) { + fillComboBox(); + } + + /** + * Fill the combo box with a list of all control names that have + * numeric data which might be used for bearing information. + */ + private void fillComboBox() { + String currentValue = (String) fieldNames.getSelectedItem(); + fieldNames.removeAllItems(); + ArrayList ctrlTitles = formEditor.getControlTitles(); + for (ControlTitle title:ctrlTitles) { + if (title.getType() == null) { + continue; + } + if (title.getType() == controlType) { + fieldNames.addItem(title.getItemInformation().getStringProperty(UDColName.Title.toString())); + } + } + if (currentValue != null) { + fieldNames.setSelectedItem(currentValue); + } + else { +// pushProperty(); + } + } + + @Override + public void propertyEnable(boolean enabled) { + fieldNames.setEnabled(enabled); + } + + @Override + public void pushProperty(ItemInformation itemInformation) { + super.pushProperty(itemInformation); + if (itemInformation == null) { + return; + } + try { + fieldNames.setSelectedItem(itemInformation.getStringProperty(UDColName.Title.toString())); + } + catch (Exception e) {}; + } + + @Override + public ItemInformation fetchProperty(ItemInformation itemInformation) { + itemInformation = super.fetchProperty(itemInformation); + if (itemInformation == null) { + return null; + } + + itemInformation.setProperty(UDColName.Title.toString(), fieldNames.getSelectedItem()); + + return itemInformation; + } + + +} diff --git a/src/loggerForms/symbol/IntegerSymbolModifier.java b/src/loggerForms/symbol/IntegerSymbolModifier.java new file mode 100644 index 00000000..03cbec8d --- /dev/null +++ b/src/loggerForms/symbol/IntegerSymbolModifier.java @@ -0,0 +1,53 @@ +package loggerForms.symbol; + +import java.awt.Color; + +import PamView.GeneralProjector; +import PamView.PamColors; +import PamView.PamSymbolType; +import PamView.symbol.PamSymbolChooser; +import PamView.symbol.SymbolData; +import PamguardMVC.PamDataUnit; +import loggerForms.FormDescription; +import loggerForms.controlDescriptions.ControlDescription; + +/** + * Integer symbol modifier. Basically returns the whale colour rotation. + * @author dg50 + * + */ +public class IntegerSymbolModifier extends LoggerSymbolModifier { + + public IntegerSymbolModifier(FormDescription formDescription, ControlDescription controlDescription, + PamSymbolChooser symbolChooser, int modifyableBits) { + super(formDescription, controlDescription, symbolChooser, modifyableBits); + } + + @Override + public SymbolData getSymbolData(GeneralProjector projector, PamDataUnit dataUnit) { + Object data = getControlData(dataUnit); + if (data == null) { + return null; + } + int number = 0; + if (data instanceof String) { + try { + number = Integer.valueOf(data.toString()); + } + catch (NumberFormatException e) { + return null; + } + } + if (data instanceof Number) { + try { + number = Integer.valueOf(data.toString()); + } + catch (Exception e) { + return null; + } + } + Color col = PamColors.getInstance().getChannelColor(number); + return new SymbolData(PamSymbolType.SYMBOL_CIRCLE, 1, 1, true, col, col); + } + +} diff --git a/src/loggerForms/symbol/LoggerSymbolChooser.java b/src/loggerForms/symbol/LoggerSymbolChooser.java new file mode 100644 index 00000000..d25e05bc --- /dev/null +++ b/src/loggerForms/symbol/LoggerSymbolChooser.java @@ -0,0 +1,23 @@ +package loggerForms.symbol; + +import PamView.GeneralProjector; +import PamView.symbol.StandardSymbolChooser; +import PamView.symbol.StandardSymbolManager; +import PamView.symbol.SymbolData; +import PamguardMVC.PamDataBlock; +import dataPlots.data.SimpleSymbolChooser; +import loggerForms.FormsDataBlock; + +public class LoggerSymbolChooser extends StandardSymbolChooser { + + private FormsDataBlock formsDataBlock; + + public LoggerSymbolChooser(StandardSymbolManager standardSymbolManager, FormsDataBlock pamDataBlock, + String displayName, SymbolData defaultSymbol, GeneralProjector projector) { + super(standardSymbolManager, pamDataBlock, displayName, defaultSymbol, projector); + this.formsDataBlock = pamDataBlock; + + } + + +} diff --git a/src/loggerForms/symbol/LoggerSymbolManager.java b/src/loggerForms/symbol/LoggerSymbolManager.java new file mode 100644 index 00000000..b39ee650 --- /dev/null +++ b/src/loggerForms/symbol/LoggerSymbolManager.java @@ -0,0 +1,130 @@ +package loggerForms.symbol; + +import PamView.GeneralProjector; +import PamView.PamSymbol; +import PamView.symbol.PamSymbolChooser; +import PamView.symbol.PamSymbolManager; +import PamView.symbol.StandardSymbolChooser; +import PamView.symbol.StandardSymbolManager; +import PamView.symbol.SymbolData; +import PamView.symbol.modifier.SymbolModType; +import PamguardMVC.PamDataBlock; +import loggerForms.FormDescription; +import loggerForms.FormsDataBlock; +import loggerForms.LoggerFormGraphics; +import loggerForms.PropertyDescription; +import loggerForms.PropertyTypes; +import loggerForms.controlDescriptions.ControlDescription; +import loggerForms.formdesign.FormList; +import loggerForms.formdesign.propertypanels.SymbolPanel; + +public class LoggerSymbolManager extends StandardSymbolManager { + + private FormsDataBlock formsDataBlock; + private SymbolData standardFormSymbol; + + public LoggerSymbolManager(FormsDataBlock pamDataBlock) { + super(pamDataBlock, LoggerFormGraphics.defaultSymbol); + this.formsDataBlock = pamDataBlock; + } + + @Override + protected LoggerSymbolChooser createSymbolChooser(String displayName, GeneralProjector projector) { + return new LoggerSymbolChooser(this, formsDataBlock, displayName, getDefaultSymbol(), projector); + } + + @Override + public SymbolData getDefaultSymbol() { + /** + * the default default is a generic one for logger data. See if it is overridden by a symbol + * specified for the form. + */ + SymbolData formSymbol = getFormSymbol(); + if (formSymbol != null) { + return formSymbol; + } + else { + return super.getDefaultSymbol(); + } + } + + /** + * Get the default symbol for the form. Might be null, + * though might have been set in the form properties. + * @return + */ + public SymbolData getFormSymbol() { + if (standardFormSymbol == null) { + FormDescription formDescription = formsDataBlock.getFormDescription(); + PropertyDescription formProperty = formDescription.findProperty(PropertyTypes.SYMBOLTYPE); + if (formProperty == null) { + return null; + } + PamSymbol symbol = SymbolPanel.createSymbol(formProperty.getItemInformation()); + if (symbol != null) { + standardFormSymbol = symbol.getSymbolData(); + } + } + return standardFormSymbol; + } + + @Override + public void addSymbolModifiers(PamSymbolChooser psc) { + // probably don't want the standard ones. +// super.addSymbolModifiers(psc); + /* + * now add symbol modifiers for each control in the form. + * This will primarily be lookups which should have defined colours. + * May be able to do other controls based on their type / null / >0 values. + * Focus on lut's for now. + */ + FormDescription formDescription = formsDataBlock.getFormDescription(); + FormList ctrls = formDescription.getControlDescriptions(); + for (ControlDescription ctrlDescription : ctrls) { + LoggerSymbolModifier modifier = createSymbolModifier(formDescription, ctrlDescription, psc); + if (modifier != null) { + psc.addSymbolModifier(modifier); + } + } + } + + private LoggerSymbolModifier createSymbolModifier(FormDescription formDescription, + ControlDescription ctrlDescription, PamSymbolChooser psc) { + switch (ctrlDescription.getEType()) { + case CHAR: + break; + case CHECKBOX: + break; + case COUNTER: + return new IntegerSymbolModifier(formDescription, ctrlDescription, psc, SymbolModType.FILLCOLOUR | SymbolModType.LINECOLOUR); + case DOUBLE: + break; + case INTEGER: + return new IntegerSymbolModifier(formDescription, ctrlDescription, psc, SymbolModType.FILLCOLOUR | SymbolModType.LINECOLOUR); + case LATLONG: + break; + case LOOKUP: + return new LookupSymbolModifier(formDescription, ctrlDescription, psc, SymbolModType.EVERYTHING); + case NMEACHAR: + break; + case NMEAFLOAT: + break; + case NMEAINT: + break; + case SHORT: + return new IntegerSymbolModifier(formDescription, ctrlDescription, psc, SymbolModType.FILLCOLOUR | SymbolModType.LINECOLOUR); + case SINGLE: + break; + case STATIC: + break; + case TIME: + break; + case TIMESTAMP: + break; + default: + break; + + } + return null; + } +} diff --git a/src/loggerForms/symbol/LoggerSymbolModifier.java b/src/loggerForms/symbol/LoggerSymbolModifier.java new file mode 100644 index 00000000..5a31e3a4 --- /dev/null +++ b/src/loggerForms/symbol/LoggerSymbolModifier.java @@ -0,0 +1,66 @@ +package loggerForms.symbol; + +import PamView.GeneralProjector; +import PamView.symbol.PamSymbolChooser; +import PamView.symbol.SymbolData; +import PamView.symbol.modifier.SymbolModifier; +import PamguardMVC.PamDataUnit; +import loggerForms.FormDescription; +import loggerForms.FormsDataUnit; +import loggerForms.controlDescriptions.ControlDescription; + +abstract public class LoggerSymbolModifier extends SymbolModifier { + + protected FormDescription formDescription; + protected ControlDescription controlDescription; + protected int controlIndex; + + public LoggerSymbolModifier(FormDescription formDescription, ControlDescription controlDescription, + PamSymbolChooser symbolChooser, int modifyableBits) { + super(controlDescription.getTitle(), symbolChooser, modifyableBits); + this.formDescription = formDescription; + this.controlDescription = controlDescription; + controlIndex = formDescription.getControlIndex(controlDescription); + } + + /** + * Get the data object for this control from the data unit. + * @param dataUnit + * @return + */ + public Object getControlData(PamDataUnit dataUnit) { + if (dataUnit instanceof FormsDataUnit == false) { + return null; + } + FormsDataUnit formDataUnit = (FormsDataUnit) dataUnit; + Object[] data = formDataUnit.getFormData(); + if (data == null || data.length <= controlIndex || controlIndex < 0) { + return null; + } + return data[controlIndex]; + } + + + /** + * @return the formDescription + */ + protected FormDescription getFormDescription() { + return formDescription; + } + + /** + * @return the controlDescription + */ + protected ControlDescription getControlDescription() { + return controlDescription; + } + + /** + * @return the controlIndex + */ + protected int getControlIndex() { + return controlIndex; + } + + +} diff --git a/src/loggerForms/symbol/LookupSymbolModifier.java b/src/loggerForms/symbol/LookupSymbolModifier.java new file mode 100644 index 00000000..64d12a46 --- /dev/null +++ b/src/loggerForms/symbol/LookupSymbolModifier.java @@ -0,0 +1,42 @@ +package loggerForms.symbol; + +import PamView.GeneralProjector; +import PamView.PamSymbol; +import PamView.symbol.PamSymbolChooser; +import PamView.symbol.SymbolData; +import PamguardMVC.PamDataUnit; +import generalDatabase.lookupTables.LookupItem; +import generalDatabase.lookupTables.LookupList; +import loggerForms.FormDescription; +import loggerForms.FormsDataUnit; +import loggerForms.controlDescriptions.CdLookup; +import loggerForms.controlDescriptions.ControlDescription; + +public class LookupSymbolModifier extends LoggerSymbolModifier { + + public LookupSymbolModifier(FormDescription formDescription, ControlDescription controlDescription, + PamSymbolChooser symbolChooser, int modifyableBits) { + super(formDescription, controlDescription, symbolChooser, modifyableBits); + } + + @Override + public SymbolData getSymbolData(GeneralProjector projector, PamDataUnit dataUnit) { + Object data = getControlData(dataUnit); + if (data == null) { + return null; + } + + LookupList lutList = ((CdLookup)controlDescription).getLookupList(); + int lutIndex = lutList.indexOfCode(data.toString()); + LookupItem lutItem = lutList.getLookupItem(lutIndex); + if (lutItem == null) { + return null; + } + PamSymbol symbol = lutItem.getSymbol(); + if (symbol == null) { + return null; + } + return symbol.getSymbolData(); + } + +} diff --git a/src/ravendata/RavenControl.java b/src/ravendata/RavenControl.java new file mode 100644 index 00000000..7769770d --- /dev/null +++ b/src/ravendata/RavenControl.java @@ -0,0 +1,103 @@ +package ravendata; + +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; + +import javax.swing.JMenuItem; + +import Acquisition.AcquisitionControl; +import PamController.InputStoreInfo; +import PamController.PamConfiguration; +import PamController.PamControlledUnit; +import PamController.PamControlledUnitSettings; +import PamController.PamController; +import PamController.PamSettingManager; +import PamController.PamSettings; +import PamView.dialog.warn.WarnOnce; +import pamViewFX.PamSettingsMenuPane; +import ravendata.swing.RavenImportDialog; + +/** + * System for importing and displaying data from Raven selection tables. + * @author dg50 + * + */ +public class RavenControl extends PamControlledUnit implements PamSettings { + + private RavenProcess ravenProcess; + + private static final String unitType = "Raven Import"; + public static final String defaultName = unitType; + + private RavenParameters ravenParameters = new RavenParameters(); + + public RavenControl(String unitName) { + super(unitType, unitName); + this.ravenProcess = new RavenProcess(this); + addPamProcess(ravenProcess); + PamSettingManager.getInstance().registerSettings(this); + } + + public RavenControl(PamConfiguration pamConfiguration, String unitType, String unitName) { + super(pamConfiguration, unitType, unitName); + } + + @Override + public JMenuItem createDetectionMenu(Frame parentFrame) { + JMenuItem menuItem = new JMenuItem("Import Raven data ..."); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + importData(parentFrame); + } + }); + return menuItem; + } + + protected void importData(Frame parentFrame) { + RavenParameters newParams = RavenImportDialog.showDialog(parentFrame, ravenParameters); + if (newParams == null) { + return; + } + ravenParameters = newParams; + // import the data. 1. Check for existing and delete, 2. Import, 3. rebuild datamap, 4. load data + RavenFileReader fileReader = null; + ArrayList ravenData = null; + try { + fileReader = new RavenFileReader(this, ravenParameters.importFile); + ravenData = fileReader.readTable(); + + fileReader.closeFile(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + if (ravenData != null) { + ravenProcess.createPAMGuardData(fileReader, ravenData); + } + } + + + + @Override + public Serializable getSettingsReference() { + return ravenParameters; + } + + @Override + public long getSettingsVersion() { + return RavenParameters.serialVersionUID; + } + + @Override + public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { + ravenParameters = (RavenParameters) pamControlledUnitSettings.getSettings(); + return true; + } + +} diff --git a/src/ravendata/RavenDataBlock.java b/src/ravendata/RavenDataBlock.java new file mode 100644 index 00000000..8fe3f9c5 --- /dev/null +++ b/src/ravendata/RavenDataBlock.java @@ -0,0 +1,16 @@ +package ravendata; + +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamProcess; + +public class RavenDataBlock extends PamDataBlock { + + private RavenProcess ravenProcess; + + public RavenDataBlock(RavenProcess parentProcess, int channelMap) { + super(RavenDataUnit.class, "Selection", parentProcess, channelMap); + this.ravenProcess = parentProcess; + } + + +} diff --git a/src/ravendata/RavenDataRow.java b/src/ravendata/RavenDataRow.java new file mode 100644 index 00000000..0e77da18 --- /dev/null +++ b/src/ravendata/RavenDataRow.java @@ -0,0 +1,159 @@ +package ravendata; + +public class RavenDataRow { + + private int iRow; + private String[] data; + private Integer selection; + private String view; + private Integer channel; + private double beginT; + private double endT; + private double f1; + private double f2; + private int[] dataIndexes; + private boolean unpackOK; + + // data on a row of raven data from a table. + public RavenDataRow(int iRow, String[] data, int[] dataIndexes) { + this.iRow = iRow; + this.data = data; + this.dataIndexes = dataIndexes; + unpackOK = unpackRow(dataIndexes); + } + + /** + * @return the iRow + */ + protected int getiRow() { + return iRow; + } + + /** + * @return the data + */ + protected String[] getData() { + return data; + } + + /** + * Get a String value from the given column. + * @param iCol + * @return + */ + public String getString(int iCol) { + return data[iCol]; + } + + /** + * Read an Integer value from the given column. + * @param iCol + * @return + */ + public Integer getInteger(int iCol) { + try { + return Integer.valueOf(data[iCol]); + } + catch (NumberFormatException e) { + return null; + } + } + /** + * Read a double value from the given column. + * @param iCol + * @return + */ + public Double getDouble(int iCol) { + try { + return Double.valueOf(data[iCol]); + } + catch (NumberFormatException e) { + return null; + } + } + + /** + * Unpack the row into more useful columns using the column indexes. + * @param mainIndexes + * @return + */ + private boolean unpackRow(int[] mainIndexes) { + try { + selection = getInteger(mainIndexes[0]); + view = getString(mainIndexes[1]); + channel = getInteger(mainIndexes[2]); + beginT = getDouble(mainIndexes[3]); + endT = getDouble(mainIndexes[4]); + f1 = getDouble(mainIndexes[5]); + f2 = getDouble(mainIndexes[6]); + } + catch (Exception e) { + return false; + } + return true; + } + + /** + * @return the selection + */ + protected Integer getSelection() { + return selection; + } + + /** + * @return the view + */ + protected String getView() { + return view; + } + + /** + * @return the channel + */ + protected Integer getChannel() { + return channel; + } + + /** + * @return the beginT + */ + protected double getBeginT() { + return beginT; + } + + /** + * @return the endT + */ + protected double getEndT() { + return endT; + } + + /** + * @return the f1 + */ + protected double getF1() { + return f1; + } + + /** + * @return the f2 + */ + protected double getF2() { + return f2; + } + + /** + * @return the dataIndexes + */ + protected int[] getDataIndexes() { + return dataIndexes; + } + + /** + * @return the unpackOK + */ + protected boolean isUnpackOK() { + return unpackOK; + } + +} diff --git a/src/ravendata/RavenDataUnit.java b/src/ravendata/RavenDataUnit.java new file mode 100644 index 00000000..49929ccf --- /dev/null +++ b/src/ravendata/RavenDataUnit.java @@ -0,0 +1,20 @@ +package ravendata; + +import PamDetection.PamDetection; +import PamguardMVC.AcousticDataUnit; +import PamguardMVC.DataUnitBaseData; +import PamguardMVC.PamDataUnit; + +public class RavenDataUnit extends PamDataUnit implements AcousticDataUnit, PamDetection { + + public RavenDataUnit(long timeMilliseconds, int channelMap, long durationMillis, double f1, double f2) { + super(timeMilliseconds); + setChannelBitmap(channelMap); + setDurationInMilliseconds(durationMillis); + double[] freq = {f1, f2}; + setFrequency(freq); + } + + + +} diff --git a/src/ravendata/RavenFileReader.java b/src/ravendata/RavenFileReader.java new file mode 100644 index 00000000..f18e8eb0 --- /dev/null +++ b/src/ravendata/RavenFileReader.java @@ -0,0 +1,101 @@ +package ravendata; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; + +public class RavenFileReader { + + private RavenControl ravenControl; + private File ravenFile; + private ArrayList columnNames; + private BufferedReader fileReader; + + private static String[] standardColumns = {"Selection", "View", "Channel", "Begin Time (s)", "End Time (s)", "Low Freq (Hz)", "High Freq (Hz)"}; +// private static String[] otherColumns = {"Selection", "View", "Channel", "Begin Time (s)", "End Time (s)", "end", "Low Freq (Hz)", "High Freq (Hz)", +// "Begin File", "Delta Time (s)", "File Offset (s)", "Occupancy", "Manual Review", "Notes", "SongNumber"}; + /* + * Sometimes some names appear in different places. Bugger. + * so need to find the index of each of the main columns we want. + */ + private int[] mainIndexes; +private int columnErrors; + + + public RavenFileReader(RavenControl ravenControl, String ravenFile) throws IOException { + this.ravenControl = ravenControl; + this.ravenFile = new File(ravenFile); + openFile(); + } + + public void closeFile() throws IOException { + if (fileReader != null) { + fileReader.close(); + } + } + + /** + * open the file, read the file header and get a list of column names. + * @throws IOException + */ + private void openFile() throws IOException { + fileReader = new BufferedReader(new FileReader(ravenFile)); + String firstLine = fileReader.readLine(); + if (firstLine == null) { + throw new IOException("Empty file"); + } + String[] cols = firstLine.split("\t"); + columnNames = new ArrayList<>(); + for (int i = 0; i < cols.length; i++) { + columnNames.add(cols[i]); + } + checkColumnNames(); + } + + public ArrayList readTable() throws IOException { + ArrayList allData = new ArrayList(); + int iRow = 0; + while(true) { + String aLine = fileReader.readLine(); + if (aLine == null) { + break; + } + String[] split = aLine.split("\t"); + RavenDataRow aRow = new RavenDataRow(iRow++, split, mainIndexes); + allData.add(aRow); + } + return allData; + } + + /** + * Check we have the correct standard columns. + */ + private int checkColumnNames() { + mainIndexes = new int[standardColumns.length]; + columnErrors = 0; + for (int i = 0; i < standardColumns.length; i++) { + mainIndexes[i] = columnNames.indexOf(standardColumns[i]); + if (mainIndexes[i] < 0) { + System.out.printf("Raven error: Unable to find column \"%s\" in data table\n", standardColumns[i]); + columnErrors++; + } + } + return columnErrors; + } + + public boolean exists() { + return ravenFile.exists(); + } + + /** + * get a count of column errors. + * @return the columnErrors + */ + protected int getColumnErrors() { + return columnErrors; + } + +} diff --git a/src/ravendata/RavenLogging.java b/src/ravendata/RavenLogging.java new file mode 100644 index 00000000..fab6c7de --- /dev/null +++ b/src/ravendata/RavenLogging.java @@ -0,0 +1,30 @@ +package ravendata; + +import PamDetection.AcousticSQLLogging; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import generalDatabase.PamTableItem; +import generalDatabase.SQLLogging; +import generalDatabase.SQLTypes; + +public class RavenLogging extends AcousticSQLLogging { + + private RavenDataBlock ravenDataBlock; + private RavenControl ravenControl; + + private PamTableItem f1; + + public RavenLogging(RavenControl ravenControl, RavenDataBlock pamDataBlock) { + super(pamDataBlock, ravenControl.getUnitName()); + this.ravenControl = ravenControl; + this.ravenDataBlock = pamDataBlock; + } + + @Override + protected PamDataUnit createDataUnit(SQLTypes sqlTypes, long timeMilliseconds, int chanMap, long duration, + double[] f) { + return new RavenDataUnit(timeMilliseconds, chanMap, duration, f[0], f[1]); + } + + +} diff --git a/src/ravendata/RavenParameters.java b/src/ravendata/RavenParameters.java new file mode 100644 index 00000000..d5d4718f --- /dev/null +++ b/src/ravendata/RavenParameters.java @@ -0,0 +1,10 @@ +package ravendata; + +import java.io.Serializable; + +public class RavenParameters implements Serializable, Cloneable { + + public static final long serialVersionUID = 1L; + + public String importFile; +} diff --git a/src/ravendata/RavenProcess.java b/src/ravendata/RavenProcess.java new file mode 100644 index 00000000..25993477 --- /dev/null +++ b/src/ravendata/RavenProcess.java @@ -0,0 +1,130 @@ +package ravendata; + +import java.awt.Color; +import java.util.ArrayList; + +import Acquisition.AcquisitionControl; +import PamController.InputStoreInfo; +import PamController.PamController; +import PamView.PamSymbolType; +import PamView.dialog.warn.WarnOnce; +import PamView.symbol.StandardSymbolManager; +import PamView.symbol.SymbolData; +import PamguardMVC.PamProcess; +import dataMap.OfflineDataMap; +import generalDatabase.DBControlUnit; +import ravendata.swing.RavenGraphics; + +public class RavenProcess extends PamProcess { + + private RavenControl ravenControl; + + private RavenDataBlock ravenDataBlock; + + private RavenLogging ravenLogging; + + private static SymbolData standardSymbol = new SymbolData(PamSymbolType.SYMBOL_SQUARE, 20, 20, false, Color.white, Color.red); + + public RavenProcess(RavenControl pamControlledUnit) { + super(pamControlledUnit, null); + this.ravenControl = pamControlledUnit; + ravenDataBlock = new RavenDataBlock(this, 0); + addOutputDataBlock(ravenDataBlock); + ravenLogging = new RavenLogging(pamControlledUnit, ravenDataBlock); + ravenDataBlock.SetLogging(ravenLogging); + ravenDataBlock.setOverlayDraw(new RavenGraphics(ravenDataBlock)); + ravenDataBlock.setPamSymbolManager(new StandardSymbolManager(ravenDataBlock, standardSymbol)); + } + + @Override + public void pamStart() { + // TODO Auto-generated method stub + + } + + @Override + public void pamStop() { + // TODO Auto-generated method stub + + } + protected void createPAMGuardData(RavenFileReader fileReader, ArrayList ravenData) { + /** + * Need to find the acquisition module and then get detailed times of every file, not just + * the datamap, which is currently just a normal databsae map of the db entries, so it not + * necessarily precise on the starts / ends of files for the viewer. + */ + AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.class, null); + if (daqControl == null) { + WarnOnce.showWarning("No acquisition module", "Can only import ROCCA data if there is a Sound Acquisition Module", + WarnOnce.WARNING_MESSAGE); + return; + } + // need to get the detailed data map. + InputStoreInfo daqInfo = daqControl.getStoreInfo(true); + if (daqInfo == null || daqInfo.getAllFileEnds() == null || daqInfo.getAllFileEnds().length == 0) { + WarnOnce.showWarning("No sound file info module", "Can only import ROCCA data if sound files arre present to extract absolute times", + WarnOnce.WARNING_MESSAGE); + return; + } + // need these to look for gaps to convert ROCCA time to abs time. + long[] fileStarts = daqInfo.getFileStartTimes(); + long[] fileEnds = daqInfo.getAllFileEnds(); + // make an array of absolute times to match to ROCCA data. + // these are the end times of each file (start of first file is known to be 0). + long[] absTime = new long[fileStarts.length+1]; // one longer to capture end of last file. + for (int i = 0; i < fileStarts.length; i++) { + absTime[i+1] = absTime[i] + fileEnds[i]-fileStarts[i]; + } + + // delete all existing data from database. + ravenDataBlock.clearAll(); + ravenLogging.deleteData(0, System.currentTimeMillis()*2); + + for (RavenDataRow ravenRow : ravenData) { + int fileInd = getTimeIndex(ravenRow.getBeginT()*1000, absTime); + if (fileInd == absTime.length) { + String msg = String.format("Data at time %6.4f is beyond the end of available sound file data", ravenRow.getBeginT()); + WarnOnce.showWarning("Error importing RAVEN data", msg, WarnOnce.WARNING_MESSAGE); + break; + } + long fileStart = fileStarts[fileInd]; + long absStart = fileStart + (long) (ravenRow.getBeginT()*1000.)-absTime[fileInd]; + long duration = (long) ((ravenRow.getEndT()-ravenRow.getBeginT())*1000.); + int chanMap = 1<<(ravenRow.getChannel()-1); + RavenDataUnit rdu = new RavenDataUnit(absStart, chanMap, duration, ravenRow.getF1(), ravenRow.getF2()); + getRavenDataBlock().addPamData(rdu); + ravenLogging.logData(DBControlUnit.findConnection(), rdu); + } + + OfflineDataMap dataMap = ravenDataBlock.getPrimaryDataMap(); +// dataMap.c + DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); + if (dbControl != null) { + dbControl.createOfflineDataMap(ravenControl.getGuiFrame(), ravenControl); + } + + dataMap = ravenDataBlock.getPrimaryDataMap(); + } + + /** + * Find which file time bin the raven data are in + * @param ravenTime + * @param absTimes + * @return + */ + private int getTimeIndex(double ravenTime, long[] absTimes) { + int i = 0; + while (i < absTimes.length-1 && ravenTime > absTimes[i+1]) { + i++; + } + return i; + } + + /** + * @return the ravenDataBlock + */ + public RavenDataBlock getRavenDataBlock() { + return ravenDataBlock; + } + +} diff --git a/src/ravendata/swing/RavenGraphics.java b/src/ravendata/swing/RavenGraphics.java new file mode 100644 index 00000000..db69ce36 --- /dev/null +++ b/src/ravendata/swing/RavenGraphics.java @@ -0,0 +1,18 @@ +package ravendata.swing; + +import java.awt.Color; + +import PamView.PamDetectionOverlayGraphics; +import PamView.PamSymbol; +import PamView.PamSymbolType; +import PamguardMVC.PamDataBlock; + +public class RavenGraphics extends PamDetectionOverlayGraphics { + + public static final PamSymbol defaultSymbol = new PamSymbol(PamSymbolType.SYMBOL_SQUARE,12, 12, false, Color.white, Color.red); + + public RavenGraphics(PamDataBlock parentDataBlock) { + super(parentDataBlock, defaultSymbol); + } + +} diff --git a/src/ravendata/swing/RavenImportDialog.java b/src/ravendata/swing/RavenImportDialog.java new file mode 100644 index 00000000..af82e452 --- /dev/null +++ b/src/ravendata/swing/RavenImportDialog.java @@ -0,0 +1,111 @@ +package ravendata.swing; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; + +import PamUtils.PamFileChooser; +import PamUtils.PamFileFilter; +import PamView.dialog.PamDialog; +import PamView.dialog.PamGridBagContraints; +import PamView.panel.PamAlignmentPanel; +import ravendata.RavenParameters; + +public class RavenImportDialog extends PamDialog { + + private static RavenImportDialog singleInstance; + private RavenParameters ravenParameters; + + private JTextField ravenFile; + + private JButton chooseButton; + + + + private RavenImportDialog(Window parentFrame) { + super(parentFrame, "Import Raven Data", false); + JPanel mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(new TitledBorder("Choose Raven selection table")); + GridBagConstraints c = new PamGridBagContraints(); + ravenFile = new JTextField(80); + ravenFile.setEditable(false); + chooseButton = new JButton("Select ..."); + c.gridwidth = 2; + mainPanel.add(ravenFile, c); + c.gridy++; + mainPanel.add(new PamAlignmentPanel(chooseButton, BorderLayout.EAST), c); + + chooseButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + chooseFile(e); + } + }); + setDialogComponent(mainPanel); + } + + protected void chooseFile(ActionEvent e) { + PamFileFilter fileFilter = new PamFileFilter("Raven files", ".txt"); +// fileFilter. + PamFileChooser chooser = new PamFileChooser(ravenParameters.importFile); + chooser.setFileFilter(fileFilter); + int ans = chooser.showDialog(this, "Select ..."); + if (ans == JFileChooser.APPROVE_OPTION) { + File f = chooser.getSelectedFile(); + if (f != null) { + ravenFile.setText(f.getAbsolutePath()); + } + } + } + + public static RavenParameters showDialog(Window parentFrame, RavenParameters ravenParameters) { +// if (singleInstance == null) { + singleInstance = new RavenImportDialog(parentFrame); +// } + singleInstance.setParams(ravenParameters); + singleInstance.setVisible(true); + return singleInstance.ravenParameters; + } + + private void setParams(RavenParameters ravenParameters) { + this.ravenParameters = ravenParameters; + ravenFile.setText(ravenParameters.importFile); + } + + @Override + public boolean getParams() { + String fn = ravenFile.getText(); + if (fn == null) { + return showWarning("Error - No file selected"); + } + File f = new File(fn); + if (f.exists() == false) { + String str = String.format("The file %s does not exist", fn); + return showWarning(str); + } + ravenParameters.importFile = fn; + return true; + } + + @Override + public void cancelButtonPressed() { + this.ravenParameters = null; + } + + @Override + public void restoreDefaultSettings() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/targetMotionOld/TargetMotionLocaliser.java b/src/targetMotionOld/TargetMotionLocaliser.java index dc0c6321..d1922ed7 100644 --- a/src/targetMotionOld/TargetMotionLocaliser.java +++ b/src/targetMotionOld/TargetMotionLocaliser.java @@ -3,6 +3,7 @@ package targetMotionOld; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; @@ -17,12 +18,17 @@ import javax.swing.SwingWorker; import pamScrollSystem.AbstractScrollManager; import pamScrollSystem.ViewerScrollerManager; +import targetMotionModule.TargetMotionLocaliserProvider; import targetMotionOld.algorithms.LeastSquaresNew; import targetMotionOld.algorithms.Simplex2DNew; import targetMotionOld.algorithms.Simplex3DNew; import targetMotionOld.dialog.TargetMotionDialog; +import targetMotionOld.tethys.TMALocalizationCreator; +import tethys.localization.LocalizationCreator; import GPS.GPSDataBlock; import GPS.GpsDataUnit; +import Localiser.LocalisationAlgorithm; +import Localiser.LocalisationAlgorithmInfo; import Localiser.algorithms.timeDelayLocalisers.bearingLoc.AbstractLocaliser; import Localiser.detectionGroupLocaliser.DetectionGroupOptions; import Localiser.detectionGroupLocaliser.GroupDetection; @@ -32,12 +38,14 @@ import PamController.PamControlledUnit; import PamController.PamController; import PamController.PamControllerInterface; import PamDetection.AbstractLocalisation; +import PamDetection.LocContents; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import PamguardMVC.PamObservable; import PamguardMVC.PamObserver; import PamguardMVC.PamObserverAdapter; import PamguardMVC.debug.Debug; +import bearinglocaliser.BearingLocaliserParams; /** * Reinstated Target motion add-in as used by the click detector. Hope one day still to replace this @@ -46,7 +54,7 @@ import PamguardMVC.debug.Debug; * * @param */ -public class TargetMotionLocaliser extends AbstractLocaliser { +public class TargetMotionLocaliser extends AbstractLocaliser implements LocalisationAlgorithm, LocalisationAlgorithmInfo { public enum Interractive {START, SAVE, BACK, CANCEL, SETNULL, KEEPOLD}; // public enum WorkStatus {IDLE, LOADING, WAITING}; @@ -77,6 +85,7 @@ public class TargetMotionLocaliser extends AbstractLoc public int currentEventIndex; // private T currentEvent; //private WorkStatus workStatus; + private TMALocalizationCreator tmaLocalizationCreator; public TargetMotionLocaliser(PamControlledUnit pamControlledUnit, PamDataBlock dataBlock, PamDataBlock subDetectionBlock) { super(dataBlock); @@ -97,6 +106,11 @@ public class TargetMotionLocaliser extends AbstractLoc return "Target Motion Localiser"; } + @Override + public LocalisationAlgorithmInfo getAlgorithmInfo() { + return this; + } + @Override public boolean localiseDataUnit(T dataUnit) { // TODO Auto-generated method stub @@ -719,4 +733,30 @@ public class TargetMotionLocaliser extends AbstractLoc return null; } } + + @Override + public int getLocalisationContents() { + return LocContents.HAS_LATLONG | LocContents.HAS_AMBIGUITY | LocContents.HAS_DEPTH; + } + + @Override + public String getAlgorithmName() { + return "Target Motion Localiser"; + } + + @Override + public LocalizationCreator getTethysCreator() { + if (tmaLocalizationCreator == null) { + tmaLocalizationCreator = new TMALocalizationCreator(this); + } + return tmaLocalizationCreator; + } + + + @Override + public Serializable getParameters() { + // TODO Auto-generated method stub +// return new BearingLocaliserParams(); + return null; + } } diff --git a/src/targetMotionOld/algorithms/LeastSquaresNew.java b/src/targetMotionOld/algorithms/LeastSquaresNew.java index 8cf4a869..deeba931 100644 --- a/src/targetMotionOld/algorithms/LeastSquaresNew.java +++ b/src/targetMotionOld/algorithms/LeastSquaresNew.java @@ -73,8 +73,7 @@ public class LeastSquaresNew extends AbstractTargetMot @Override public LocContents getLocContents() { - // TODO Auto-generated method stub - return null; + return new LocContents(LocContents.HAS_LATLONG | LocContents.HAS_PERPENDICULARERRORS); } @Override diff --git a/src/targetMotionOld/algorithms/Simplex2DNew.java b/src/targetMotionOld/algorithms/Simplex2DNew.java index 8b7e5298..fc63ba6c 100644 --- a/src/targetMotionOld/algorithms/Simplex2DNew.java +++ b/src/targetMotionOld/algorithms/Simplex2DNew.java @@ -61,8 +61,7 @@ public class Simplex2DNew extends AbstractTargetMotion @Override public LocContents getLocContents() { - // TODO Auto-generated method stub - return null; + return new LocContents(LocContents.HAS_LATLONG | LocContents.HAS_PERPENDICULARERRORS); } @Override diff --git a/src/targetMotionOld/algorithms/Simplex3DNew.java b/src/targetMotionOld/algorithms/Simplex3DNew.java index f73dfee3..dafe4de8 100644 --- a/src/targetMotionOld/algorithms/Simplex3DNew.java +++ b/src/targetMotionOld/algorithms/Simplex3DNew.java @@ -35,8 +35,7 @@ public class Simplex3DNew extends Simplex2DNew{ @Override public LocContents getLocContents() { - // TODO Auto-generated method stub - return null; + return new LocContents(LocContents.HAS_LATLONG | LocContents.HAS_DEPTH | LocContents.HAS_DEPTHERROR | LocContents.HAS_PERPENDICULARERRORS); } } diff --git a/src/targetMotionOld/tethys/TMALocalizationCreator.java b/src/targetMotionOld/tethys/TMALocalizationCreator.java new file mode 100644 index 00000000..6c8d1d63 --- /dev/null +++ b/src/targetMotionOld/tethys/TMALocalizationCreator.java @@ -0,0 +1,181 @@ +package targetMotionOld.tethys; + +import java.util.List; + +import Localiser.LocaliserModel; +import Localiser.algorithms.locErrors.EllipticalError; +import Localiser.algorithms.locErrors.LocaliserError; +import Localiser.detectionGroupLocaliser.GroupLocResult; +import Localiser.detectionGroupLocaliser.GroupLocalisation; +import PamDetection.AbstractLocalisation; +import PamDetection.LocContents; +import PamUtils.LatLong; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import nilus.AngularCoordinateType; +import nilus.LocalizationType; +import nilus.Localize; +import nilus.WGS84CoordinateType; +import nilus.LocalizationType.Angular; +import nilus.LocalizationType.Parameters; +import nilus.LocalizationType.WGS84; +import nilus.LocalizationType.Parameters.TargetMotionAnalysis; +import nilus.Localize.Effort; +import nilus.Localize.Effort.CoordinateReferenceSystem; +import pamMaths.PamVector; +import targetMotionOld.TargetMotionLocaliser; +import tethys.TethysTimeFuncs; +import tethys.localization.CoordinateName; +import tethys.localization.LocalizationBuilder; +import tethys.localization.LocalizationCreator; +import tethys.localization.LocalizationSubTypes; +import tethys.localization.LocalizationTypes; +import tethys.localization.ReferenceFrame; +import tethys.localization.TimeReference; +import tethys.pamdata.AutoTethysProvider; + +public class TMALocalizationCreator implements LocalizationCreator { + + + int maxDimension = 2; + + public TMALocalizationCreator(TargetMotionLocaliser targetMotionLocaliser) { + // TODO Auto-generated constructor stub + } + + @Override + public boolean sortLocalisationCoordinates(LocalizationBuilder localizationBuilder, PamDataBlock dataBlock) { + Localize doc = localizationBuilder.getCurrentDocument(); + Effort locEffort = doc.getEffort(); + locEffort.setTimeReference(TimeReference.beam.toString()); + + List locTypes = locEffort.getLocalizationType(); + locTypes.add(LocalizationTypes.Point.toString()); + locTypes.add(LocalizationTypes.PerpendicularRange.toString()); + + CoordinateReferenceSystem coordRefs = locEffort.getCoordinateReferenceSystem(); + coordRefs.setName(CoordinateName.WGS84.toString()); + coordRefs.setSubtype(LocalizationSubTypes.Geographic.toString()); + + locEffort.setDimension(2); + + return true; + } + + @Override + public LocalizationType createLocalization(LocalizationBuilder localizationBuilder, PamDataUnit dataUnit) { + /* + * Add two types of localisation. A WGS84 and a perpendicular range. + */ + AbstractLocalisation pamLoc = dataUnit.getLocalisation(); + LatLong latLong = pamLoc.getLatLong(0); + if (pamLoc instanceof GroupLocalisation == false || latLong == null) { + return localizationBuilder.createStandardLocalization(dataUnit); + } + LocalizationType loc = localizationBuilder.makeBaseLoc(dataUnit); + GroupLocalisation groupLoc = (GroupLocalisation) pamLoc; + GroupLocResult groupLocResult = groupLoc.getGroupLocaResult(0); + LocaliserModel tmaModel = groupLocResult.getModel(); + boolean hasDepth = false; + LocContents locCont = new LocContents(LocContents.HAS_LATLONG); + if (tmaModel != null) { + locCont = tmaModel.getLocContents(); + if (locCont.hasLocContent(LocContents.HAS_DEPTH)) { + hasDepth = true; + } + } + int nDim = hasDepth ? 3 : 2; + maxDimension = Math.max(maxDimension, nDim); + /** + * Export the latlong data. + */ + WGS84 wgs84 = new WGS84(); + WGS84CoordinateType coord = new WGS84CoordinateType(); + wgs84.setCoordinate(coord); + coord.setLongitude(latLong.getLongitude()); + coord.setLatitude(latLong.getLatitude()); + if (hasDepth) { + coord.setElevationM(AutoTethysProvider.roundDecimalPlaces(latLong.getHeight(),3)); + } + PamVector errors = groupLocResult.getErrorVector(); + LocaliserError genError = groupLocResult.getLocError(); + WGS84CoordinateType wgsErr = null; + double[] errorVec = null; + if (errors != null) { + errorVec = errors.getVector(); + } + else if (genError instanceof EllipticalError) { + EllipticalError elliptical = (EllipticalError) genError; + PamVector dir = genError.getErrorDirection(); + // these are errors perpendicular and parallel to the track + // so aren't really lat long errors. + errorVec = elliptical.getEllipseDim(); + } + /* + * Needs a bit of work to get errors in correct direction (needs import + * of track data for this value ?) and conversion to latlong units. + */ +// if (errorVec != null && errorVec.length >= 2) { +// wgsErr = new WGS84CoordinateType(); +// wgsErr.setLongitude(errorVec[0]); +// wgsErr.setLatitude(errorVec[1]); +// if (hasDepth && errorVec.length >= 3) { +// wgsErr.setElevationM(errorVec[2]); +// } +// wgs84.setCoordinateError(wgsErr); +// } + + + loc.setWGS84(wgs84); + + // set the TMA information + Parameters params = loc.getParameters(); + if (params == null) { + params = new Parameters(); + loc.setParameters(params); + } + TargetMotionAnalysis tma = new TargetMotionAnalysis(); + tma.setStart(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getTimeMilliseconds())); + tma.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getEndTimeInMilliseconds())); + params.setTargetMotionAnalysis(tma); + Long timeAbeam = groupLocResult.getBeamTime(); + if (timeAbeam != null) { + loc.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(timeAbeam)); + } + +// now also output a perpendicular distance. + Double perp = groupLocResult.getPerpendicularDistance(); + if (perp != null) { + loc.setPerpendicularRangeM(perp); + } + + + // con only output one type. +// if (perp != null) { +// AngularCoordinateType acType = new AngularCoordinateType(); +// acType.setAngle1(90); +// acType.setDistanceM(AutoTethysProvider.roundDecimalPlaces(perp,1)); +// Angular angular = new Angular(); +// angular.setCoordinate(acType); +// if (errors != null) { +// AngularCoordinateType angErr = new AngularCoordinateType(); +// angErr.setDistanceM(errors.norm()); +// angular.setCoordinateError(angErr); +// } +// loc.setAngular(angular); +// } + + + + return loc; + } + + @Override + public boolean checkDocument(LocalizationBuilder localizationBuilder) { + boolean ok = localizationBuilder.checkDocument(); + Effort locEffort = localizationBuilder.getCurrentDocument().getEffort(); + locEffort.setDimension(maxDimension); + return ok; + } + +} diff --git a/src/tethys/CollectionHandler.java b/src/tethys/CollectionHandler.java index 66208fa0..c3eb0bc0 100644 --- a/src/tethys/CollectionHandler.java +++ b/src/tethys/CollectionHandler.java @@ -1,5 +1,19 @@ package tethys; +import java.util.List; + +import PamController.PamControlledUnit; +import PamController.PamguardVersionInfo; +import PamModel.PamPluginInterface; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamProcess; +import nilus.Deployment; +import nilus.DetectionEffort; +import nilus.DetectionEffortKind; +import tethys.niluswraps.PDeployment; +import tethys.output.StreamExportParams; +import tethys.pamdata.TethysDataProvider; + abstract public class CollectionHandler { private Collection collection; @@ -35,4 +49,93 @@ abstract public class CollectionHandler { public abstract String getHelpPoint(); + /** + * Get the Detection Effort part of a Detections document + * @param pDeployment + * @param dataBlock + * @param exportParams + * @return + */ + public DetectionEffort getDetectorEffort(PDeployment pDeployment, PamDataBlock dataBlock, StreamExportParams exportParams) { + DetectionEffort effort = new DetectionEffort(); + Deployment deployment = pDeployment.nilusObject; + Long effortStart = pDeployment.getAudioStart(); + Long effortEnd = pDeployment.getAudioEnd(); + effort.setStart(TethysTimeFuncs.xmlGregCalFromMillis(effortStart)); + effort.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(effortEnd)); + // effort.set // no setter for DetectionEffortKind + List effortKinds = effort.getKind(); + + TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl); + dataProvider.getEffortKinds(pDeployment, effortKinds, exportParams); + + + return effort; + } + + /** + * Method string for Detections Algorithm documents. + * @param dataBlock + * @return + */ + public String getMethodString(PamDataBlock dataBlock) { + if (dataBlock == null) { + return null; + } + PamProcess process = dataBlock.getParentProcess(); + return "PAMGuard " + process.getProcessName(); + + } + + /** + * Software string for Detections Algorithm documents. + * @param dataBlock + * @return + */ + public String getSoftwareString(PamDataBlock dataBlock) { + if (dataBlock == null) { + return null; + } + return dataBlock.getLongDataName(); + } + + /** + * Software string for Detections Algorithm documents. + * @param dataBlock + * @return + */ + public String getVersionString(PamDataBlock dataBlock) { + if (dataBlock == null) { + return null; + } + PamProcess process = dataBlock.getParentProcess(); + PamControlledUnit pcu = process.getPamControlledUnit(); + PamPluginInterface plugin = pcu.getPlugin(); + if (plugin == null) { + return PamguardVersionInfo.version; + } + else { + return plugin.getVersion(); + } + } + + /** + * + * @param dataBlock + * @return default value is PAMGuard + */ + public String getSupportSoftware(PamDataBlock dataBlock) { + return "PAMGuard"; + } + + /** + * + * @param dataBlock + * @return PAMGuard version + */ + public String getSupportSoftwareVersion(PamDataBlock dataBlock) { + // should try to dig into the binary store and get the version from there. + return PamguardVersionInfo.version; + } + } diff --git a/src/tethys/dbxml/DBXMLQueries.java b/src/tethys/dbxml/DBXMLQueries.java index b3392568..ee49664b 100644 --- a/src/tethys/dbxml/DBXMLQueries.java +++ b/src/tethys/dbxml/DBXMLQueries.java @@ -622,13 +622,15 @@ public class DBXMLQueries { /** - * Get the names of all detection documents for a given deployment for all data streams. - * @param deploymentId + * Get the names of all the detection or localisation documents for a given deployment id. + * @param collection Localizations or Detetections + * @param deploymentId Deployment document id. * @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}"; + public ArrayList getDeploymentDocuments(Collection collection, 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\":[\"collectionname/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"collectionname/DataSource/DeploymentId\",\"SomeDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}"; String queryStr = queryBase.replace("SomeDeploymentId", deploymentId); + queryStr = queryStr.replace("collectionname", collection.documentName()); DBQueryResult queryResult = null; try { queryResult = executeQuery(queryStr); @@ -660,6 +662,86 @@ public class DBXMLQueries { return detectionDocs; } + /** + * Get the names of all detection documents for a given deployment for all data streams. + * @param deploymentId + * @return + */ + public ArrayList getDetectionsDocuments(String deploymentId) { + return getDeploymentDocuments(Collection.Detections, 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; + } + + /** + * Get the names of all localisation documents for a given deployment for all data streams. + * @param deploymentId + * @return + */ + public ArrayList getLocalizationsDocuments(String deploymentId) { + return getDeploymentDocuments(Collection.Localizations, 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\":[\"Localize/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Localize/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. diff --git a/src/tethys/deployment/DeploymentHandler.java b/src/tethys/deployment/DeploymentHandler.java index 51768b8f..29345107 100644 --- a/src/tethys/deployment/DeploymentHandler.java +++ b/src/tethys/deployment/DeploymentHandler.java @@ -60,7 +60,8 @@ 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.Data.Tracks.Track.Point.CourseOverGroundDegN; +import nilus.Deployment.Data.Tracks.Track.Point.HeadingDegN; import nilus.Deployment.Instrument; import nilus.Deployment.SamplingDetails; import nilus.Deployment.Sensors; @@ -890,6 +891,7 @@ public class DeploymentHandler extends CollectionHandler implements TethysStateO tracks = new Tracks(); deployment.getData().setTracks(tracks); } + tracks.setSpeedUnit("kn"); List trackList = tracks.getTrack(); // lists are usually there. Track aTrack = new Track(); @@ -909,13 +911,32 @@ public class DeploymentHandler extends CollectionHandler implements TethysStateO 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); + CourseOverGroundDegN cog = gpsPoint.getCourseOverGroundDegN(); + if (cog == null) { + cog = new CourseOverGroundDegN(); + gpsPoint.setCourseOverGroundDegN(cog); } - bdn.setValue(AutoTethysProvider.roundDecimalPlaces(PamUtils.constrainedAngle(gpsData.getHeading()),1)); - gpsPoint.setSpeedKn(AutoTethysProvider.roundDecimalPlaces(gpsData.getSpeed(),2)); + cog.setValue(PamUtils.constrainedAngle(gpsData.getCourseOverGround())); + cog.setNorth(HeadingTypes.TRUE.toString()); + Double trueHead = gpsData.getTrueHeading(); + if (trueHead != null && trueHead.isInfinite()) { + HeadingDegN th = new HeadingDegN(); + th.setValue(PamUtils.constrainedAngle(trueHead)); + th.setNorth(HeadingTypes.TRUE.toString()); + gpsPoint.setHeadingDegN(th); + } + else { + // else try magnetic + Double magHead = gpsData.getMagneticHeading(); + if (magHead != null && magHead.isInfinite()) { + HeadingDegN mh = new HeadingDegN(); + mh.setValue(PamUtils.constrainedAngle(magHead)); + mh.setNorth(HeadingTypes.MAGNETIC.toString()); + gpsPoint.setHeadingDegN(mh); + } + } + + gpsPoint.setSpeedOverGround(AutoTethysProvider.roundDecimalPlaces(gpsData.getSpeed(),2)); points.add(gpsPoint); lastPointTime = gpsDataUnit.getTimeMilliseconds(); diff --git a/src/tethys/deployment/HeadingTypes.java b/src/tethys/deployment/HeadingTypes.java new file mode 100644 index 00000000..3e5dc26f --- /dev/null +++ b/src/tethys/deployment/HeadingTypes.java @@ -0,0 +1,24 @@ +package tethys.deployment; + +/** + * Enum of heading types (mostly for track output in Deployment documents) + * @author dg50 + * + */ +public enum HeadingTypes { + + TRUE, MAGNETIC; + + @Override + public String toString() { + switch (this) { + case MAGNETIC: + return "magnetic"; + case TRUE: + return "true"; + default: + break; + } + return null; + } +} diff --git a/src/tethys/detection/DetectionsHandler.java b/src/tethys/detection/DetectionsHandler.java index af899d0c..bc1d7df1 100644 --- a/src/tethys/detection/DetectionsHandler.java +++ b/src/tethys/detection/DetectionsHandler.java @@ -1,6 +1,5 @@ package tethys.detection; -import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -14,16 +13,11 @@ import Localiser.LocalisationAlgorithm; import Localiser.LocalisationAlgorithmInfo; import PamController.PamControlledUnit; import PamController.PamController; -import PamController.PamguardVersionInfo; -import PamDetection.LocContents; -import PamDetection.LocalisationInfo; -import PamModel.PamPluginInterface; import PamUtils.PamCalendar; import PamView.dialog.PamDialog; import PamView.dialog.warn.WarnOnce; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; -import PamguardMVC.PamProcess; import PamguardMVC.dataSelector.DataSelector; import PamguardMVC.superdet.SuperDetDataBlock; import PamguardMVC.superdet.SuperDetDataBlock.ViewerLoadPolicy; @@ -32,20 +26,12 @@ import dataMap.OfflineDataMapPoint; import nilus.AlgorithmType; import nilus.AlgorithmType.SupportSoftware; import nilus.Localize.Effort; -import nilus.Localize.Effort.CoordinateReferenceSystem; -import nilus.Localize.Effort.ReferencedDocuments; -import nilus.Localize.Effort.ReferencedDocuments.Document; -import nilus.Localize.Localizations; import nilus.DataSourceType; -import nilus.Deployment; import nilus.Detection; -import nilus.DetectionEffort; -import nilus.DetectionEffortKind; import nilus.DetectionGroup; import nilus.Detections; import nilus.GranularityEnumType; import nilus.Helper; -import nilus.Localize; import tethys.Collection; import tethys.CollectionHandler; import tethys.TethysControl; @@ -53,11 +39,8 @@ import tethys.TethysTimeFuncs; import tethys.dbxml.DBXMLConnect; import tethys.dbxml.TethysException; import tethys.deployment.DeploymentHandler; -import tethys.localization.CoordinateName; +import tethys.localization.LocalizationBuilder; import tethys.localization.LocalizationHandler; -import tethys.localization.LocalizationSubType; -import tethys.localization.LocalizationType; -import tethys.localization.PLocalization; import tethys.niluswraps.NilusDataWrapper; import tethys.niluswraps.PDeployment; import tethys.niluswraps.PDetections; @@ -78,7 +61,6 @@ import tethys.swing.export.DetectionsExportWizard; public class DetectionsHandler extends CollectionHandler { public int uniqueDetectionsId=1; - public int uniqueDetectionId; private volatile boolean activeExport; @@ -134,94 +116,94 @@ public class DetectionsHandler extends CollectionHandler { } - /** - * Get the Detection Effort part of a Detections document - * @param pDeployment - * @param dataBlock - * @param exportParams - * @return - */ - private DetectionEffort getDetectorEffort(PDeployment pDeployment, PamDataBlock dataBlock, StreamExportParams exportParams) { - DetectionEffort effort = new DetectionEffort(); - Deployment deployment = pDeployment.nilusObject; - Long effortStart = pDeployment.getAudioStart(); - Long effortEnd = pDeployment.getAudioEnd(); - effort.setStart(TethysTimeFuncs.xmlGregCalFromMillis(effortStart)); - effort.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(effortEnd)); - // effort.set // no setter for DetectionEffortKind - List effortKinds = effort.getKind(); - - TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl); - dataProvider.getEffortKinds(pDeployment, effortKinds, exportParams); - - - return effort; - } - - /** - * Method string for Detections Algorithm documents. - * @param dataBlock - * @return - */ - public String getMethodString(PamDataBlock dataBlock) { - if (dataBlock == null) { - return null; - } - PamProcess process = dataBlock.getParentProcess(); - return "PAMGuard " + process.getProcessName(); - - } - - /** - * Software string for Detections Algorithm documents. - * @param dataBlock - * @return - */ - public String getSoftwareString(PamDataBlock dataBlock) { - if (dataBlock == null) { - return null; - } - return dataBlock.getLongDataName(); - } - - /** - * Software string for Detections Algorithm documents. - * @param dataBlock - * @return - */ - public String getVersionString(PamDataBlock dataBlock) { - if (dataBlock == null) { - return null; - } - PamProcess process = dataBlock.getParentProcess(); - PamControlledUnit pcu = process.getPamControlledUnit(); - PamPluginInterface plugin = pcu.getPlugin(); - if (plugin == null) { - return PamguardVersionInfo.version; - } - else { - return plugin.getVersion(); - } - } - - /** - * - * @param dataBlock - * @return default value is PAMGuard - */ - public String getSupportSoftware(PamDataBlock dataBlock) { - return "PAMGuard"; - } - - /** - * - * @param dataBlock - * @return PAMGuard version - */ - public String getSupportSoftwareVersion(PamDataBlock dataBlock) { - // should try to dig into the binary store and get the version from there. - return PamguardVersionInfo.version; - } +// /** +// * Get the Detection Effort part of a Detections document +// * @param pDeployment +// * @param dataBlock +// * @param exportParams +// * @return +// */ +// private DetectionEffort getDetectorEffort(PDeployment pDeployment, PamDataBlock dataBlock, StreamExportParams exportParams) { +// DetectionEffort effort = new DetectionEffort(); +// Deployment deployment = pDeployment.nilusObject; +// Long effortStart = pDeployment.getAudioStart(); +// Long effortEnd = pDeployment.getAudioEnd(); +// effort.setStart(TethysTimeFuncs.xmlGregCalFromMillis(effortStart)); +// effort.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(effortEnd)); +// // effort.set // no setter for DetectionEffortKind +// List effortKinds = effort.getKind(); +// +// TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl); +// dataProvider.getEffortKinds(pDeployment, effortKinds, exportParams); +// +// +// return effort; +// } +// +// /** +// * Method string for Detections Algorithm documents. +// * @param dataBlock +// * @return +// */ +// public String getMethodString(PamDataBlock dataBlock) { +// if (dataBlock == null) { +// return null; +// } +// PamProcess process = dataBlock.getParentProcess(); +// return "PAMGuard " + process.getProcessName(); +// +// } +// +// /** +// * Software string for Detections Algorithm documents. +// * @param dataBlock +// * @return +// */ +// public String getSoftwareString(PamDataBlock dataBlock) { +// if (dataBlock == null) { +// return null; +// } +// return dataBlock.getLongDataName(); +// } +// +// /** +// * Software string for Detections Algorithm documents. +// * @param dataBlock +// * @return +// */ +// public String getVersionString(PamDataBlock dataBlock) { +// if (dataBlock == null) { +// return null; +// } +// PamProcess process = dataBlock.getParentProcess(); +// PamControlledUnit pcu = process.getPamControlledUnit(); +// PamPluginInterface plugin = pcu.getPlugin(); +// if (plugin == null) { +// return PamguardVersionInfo.version; +// } +// else { +// return plugin.getVersion(); +// } +// } +// +// /** +// * +// * @param dataBlock +// * @return default value is PAMGuard +// */ +// public String getSupportSoftware(PamDataBlock dataBlock) { +// return "PAMGuard"; +// } +// +// /** +// * +// * @param dataBlock +// * @return PAMGuard version +// */ +// public String getSupportSoftwareVersion(PamDataBlock dataBlock) { +// // should try to dig into the binary store and get the version from there. +// return PamguardVersionInfo.version; +// } /** * Detections will be exported in a separate worker thread since export may take some time and @@ -418,14 +400,13 @@ public class DetectionsHandler extends CollectionHandler { ArrayList deployments = depHandler.getMatchedDeployments(); LocalizationHandler localizationHandler = tethysControl.getLocalizationHandler(); + LocalizationBuilder localizationBuilder = null; /* * The main documents for both dets and locs. */ Detections detectionsDocument = null; - Localize localiseDocument = null; DetectionGroup onEffortDetections = null; - Localizations localisations = null; OfflineDataMap dataMap = dataBlock.getPrimaryDataMap(); DataSelector dataSelector = dataBlock.getDataSelector(tethysControl.getDataSelectName(), false); @@ -479,11 +460,10 @@ public class DetectionsHandler extends CollectionHandler { // onEffortDetections = null; // detectionList = null; // } - if (localiseDocument == null && streamExportParams.exportLocalisations) { - localiseDocument = startLocalisationDocument(deployment, detectionsDocument, dataBlock, streamExportParams); - Effort eff = localiseDocument.getEffort(); - localiseDocument.getEffort().setStart(TethysTimeFuncs.xmlGregCalFromMillis(deployment.getAudioStart())); - localisations = localiseDocument.getLocalizations(); + if (localizationBuilder == null && streamExportParams.exportLocalisations) { + localizationBuilder = new LocalizationBuilder(tethysControl, deployment, detectionsDocument, dataBlock, streamExportParams); + Effort eff = localizationBuilder.getCurrentDocument().getEffort(); + eff.setStart(TethysTimeFuncs.xmlGregCalFromMillis(deployment.getAudioStart())); } // else { // localisations = null; @@ -517,11 +497,7 @@ public class DetectionsHandler extends CollectionHandler { * Localisations don't do granularity, so do all. */ if (streamExportParams.exportLocalisations) { - // convert the dets into localisations and add them. - nilus.LocalizationType localization = localizationHandler.createLocalization(localiseDocument, dataBlock, dataUnit, streamExportParams); - if (localization != null) { - localisations.getLocalization().add(localization); - } + localizationBuilder.addLocalization(dataUnit); } if (exportCount % 100 == 0) { @@ -552,16 +528,16 @@ public class DetectionsHandler extends CollectionHandler { } detectionsDocument = null; } - if (localiseDocument != null) { - closeLocaliseDocument(localiseDocument, mapPoint.getEndTime()); + if (localizationBuilder != null) { + localizationBuilder.closeDocument(mapPoint.getEndTime()); try { - if (checkLocaliseDocument(localiseDocument, granularityHandler)) { - dbxmlConnect.postAndLog(localiseDocument); + if (localizationBuilder.checkDocument()) { + dbxmlConnect.postAndLog(localizationBuilder.getCurrentDocument()); } } catch (TethysException e) { tethysControl.showException(e); } - localiseDocument = null; + localizationBuilder = null; } } @@ -598,27 +574,19 @@ public class DetectionsHandler extends CollectionHandler { } detectionsDocument = null; } - if (localiseDocument != null) { - Detection dets[] = granularityHandler.cleanup(deployment.getAudioEnd()); - if (dets != null) { - for (int dd = 0; dd < dets.length; dd++) { - exportCount++; - documentCount++; - // localiseDocument.getOnEffort().getDetection().add(dets[dd]); - } - } - prog = new DetectionExportProgress(deployment, detectionsDocument,totalMapPoints, doneMapPoints, - lastUnitTime, totalCount, exportCount, skipCount, DetectionExportProgress.STATE_WRITING); - closeLocaliseDocument(localiseDocument, deployment.getAudioEnd()); + prog = new DetectionExportProgress(deployment, detectionsDocument,totalMapPoints, doneMapPoints, + lastUnitTime, totalCount, exportCount, skipCount, DetectionExportProgress.STATE_WRITING); + if (localizationBuilder != null) { + localizationBuilder.closeDocument(deployment.getAudioEnd()); try { - if (checkLocaliseDocument(localiseDocument, granularityHandler)) { - dbxmlConnect.postAndLog(localiseDocument); + if (localizationBuilder.checkDocument()) { + dbxmlConnect.postAndLog(localizationBuilder.getCurrentDocument()); } } catch (TethysException e) { - tethysControl.showException(e); + tethysControl.showException(e); + } + localizationBuilder = null; } - localiseDocument = null; - } } // prog = new DetectionExportProgress(null, null,totalMapPoints, totalMapPoints, @@ -686,175 +654,6 @@ public class DetectionsHandler extends CollectionHandler { return detections; } - private Localize startLocalisationDocument(PDeployment deployment, Detections detectionsDocument, PamDataBlock dataBlock, - StreamExportParams exportParams) { - Localize localisations = new Localize(); - try { - Helper.createRequiredElements(localisations); - } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { - e.printStackTrace(); - return null; - } - Effort eff = localisations.getEffort(); - if (eff == null) { - eff = new Effort(); - try { - Helper.createRequiredElements(eff); - } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { - e.printStackTrace(); - return null; - } - localisations.setEffort(eff); - } - if (detectionsDocument != null) { - /* - * add the reference document information. - * Within PAMGuard, this will always be 1:1 with a Detections doc. - */ - - ReferencedDocuments refDocs = eff.getReferencedDocuments(); - if (refDocs == null) { - refDocs = new ReferencedDocuments(); - try { - Helper.createRequiredElements(refDocs); - } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { - e.printStackTrace(); - } - eff.setReferencedDocuments(refDocs); - } - Document detectsDoc = new Document(); - detectsDoc.setId(detectionsDocument.getId()); - detectsDoc.setType(Collection.Detections.collectionName()); - detectsDoc.setIndex(BigInteger.ZERO); - eff.getReferencedDocuments().getDocument().add(detectsDoc); - } - - TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(tethysControl); - - String prefix = deployment.nilusObject.getId() + "_" + dataProvider.getDetectionsName(); - String fullId = ""; - /* - * Check the document name isn't already used and increment id as necessary. - */ - while (true) { - fullId = String.format("%s_%d", prefix, uniqueDetectionsId++); - if (!tethysControl.getDbxmlQueries().documentExists(Collection.Localizations.toString(), fullId)) { - break; - } - } - localisations.setId(fullId); - // detections.setDescription(dataProvider.getDescription(deployment, tethysExportParams)); - localisations.setDescription(exportParams.getNilusDetectionDescription()); - DataSourceType dataSource = new DataSourceType(); - dataSource.setDeploymentId(deployment.nilusObject.getId()); - // dataSource.setEnsembleId(""); ToDo - localisations.setDataSource(dataSource); - AlgorithmType algorithm = localisations.getAlgorithm(); - - if (dataProvider != null) { - algorithm = dataProvider.getAlgorithm(Collection.Localizations); - // detections.setAlgorithm(algorithm); - } - LocalisationAlgorithm locAlgorithm = dataBlock.getLocalisationAlgorithm(); - LocalisationAlgorithmInfo locAlgoinfo = null; - if (locAlgorithm != null) { - locAlgoinfo = locAlgorithm.getAlgorithmInfo(); - } - if (locAlgoinfo != null) { - algorithm.setMethod(locAlgoinfo.getAlgorithmName()); - } - else { - algorithm.setMethod(getMethodString(dataBlock)); - } - algorithm.setSoftware(getSoftwareString(dataBlock)); - algorithm.setVersion(getVersionString(dataBlock)); - - List supSoft = algorithm.getSupportSoftware(); - SupportSoftware supportSoft = new SupportSoftware(); - supportSoft.setSoftware(getSupportSoftware(dataBlock)); - supportSoft.setVersion(getSupportSoftwareVersion(dataBlock)); - supSoft.add(supportSoft); - localisations.setAlgorithm(algorithm); - - localisations.setUserId("PAMGuard user"); - // localisations.setEffort(getLocaliserEffort(deployment, dataBlock, exportParams)); - sortLocaliseCoordinates(dataBlock, localisations); - - // sort out coordinate system. - - return localisations; - } - - private boolean sortLocaliseCoordinates(PamDataBlock dataBlock, Localize localisations) { - LocalisationInfo locInfo = dataBlock.getLocalisationContents(); - Effort locEffort = localisations.getEffort(); - if (locEffort == null) { - locEffort = new Effort(); - localisations.setEffort(locEffort); - } - try { - Helper.createRequiredElements(locEffort); - } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { - e.printStackTrace(); - return false; - } - locEffort.setTimeReference("relative"); -// List locTypes = locEffort.getLocalizationType(); - boolean ambiguity = locInfo.hasLocContent(LocContents.HAS_AMBIGUITY); - CoordinateReferenceSystem coordRefs = locEffort.getCoordinateReferenceSystem(); - if (locInfo.getLocContent() == 0) { - return false; - } - else if (locInfo.hasLocContent(LocContents.HAS_LATLONG)) { - coordRefs.setName(CoordinateName.WGS84.toString()); - coordRefs.setSubtype(LocalizationSubType.Geographic.toString()); - locEffort.setLocalizationType(LocalizationType.Point.toString()); -// locEffort.set - if (locInfo.hasLocContent(LocContents.HAS_DEPTH)) { - locEffort.setDimension(3); - } - else { - locEffort.setDimension(2); - } -// locEffort.set - } - else if (locInfo.hasLocContent(LocContents.HAS_XYZ)) { - coordRefs.setName(CoordinateName.Cartesian.toString()); - coordRefs.setSubtype(LocalizationSubType.Engineering.toString()); - locEffort.setLocalizationType(LocalizationType.Point.toString()); - locEffort.setDimension(3); - } - else if (locInfo.hasLocContent(LocContents.HAS_XY)) { - coordRefs.setName(CoordinateName.Cartesian.toString()); - coordRefs.setSubtype(LocalizationSubType.Engineering.toString()); - locEffort.setLocalizationType(LocalizationType.Point.toString()); - locEffort.setDimension(2); - } - else if (locInfo.hasLocContent(LocContents.HAS_BEARING)) { - coordRefs.setName(CoordinateName.Polar.toString()); - coordRefs.setSubtype(LocalizationSubType.Engineering.toString()); - locEffort.setLocalizationType(LocalizationType.Bearing.toString()); - if (ambiguity) { - locEffort.setDimension(1); - } - else { - locEffort.setDimension(2); - } - } - else { - return false; - } - - return true; - } - - - private nilus.Localize.Effort getLocaliserEffort(PDeployment deployment, PamDataBlock dataBlock, StreamExportParams exportParams) { - // TODO Auto-generated method stub - return null; - } - - /** * Close a detections document. This basically just means rewriting the end time and it's only * important in the event that a document got too big and has to be restarted. @@ -865,9 +664,6 @@ public class DetectionsHandler extends CollectionHandler { detections.getEffort().setEnd(TethysTimeFuncs.xmlGregCalFromMillis(audioEnd)); } - private void closeLocaliseDocument(Localize localiseDocument, long endTime) { - localiseDocument.getEffort().setEnd(TethysTimeFuncs.xmlGregCalFromMillis(endTime)); - } /** @@ -914,10 +710,6 @@ public class DetectionsHandler extends CollectionHandler { return true; } - private boolean checkLocaliseDocument(Localize localiseDocument, GranularityHandler granularityHandler) { - // TODO Auto-generated method stub - return true; - } /** * Worker thread for exporting detections. diff --git a/src/tethys/localization/CoordinateName.java b/src/tethys/localization/CoordinateName.java index 5b948d52..d8b68624 100644 --- a/src/tethys/localization/CoordinateName.java +++ b/src/tethys/localization/CoordinateName.java @@ -7,5 +7,38 @@ package tethys.localization; * */ public enum CoordinateName { - WGS84, UTM, Cartesian, Polar, Spherical, Cylindrical, Range, PerpindicularRange; + WGS84, UTM, Cartesian, Polar, Spherical, Cylindrical, Range, PerpendicularRange; + /* + * I beleive there is only one LocalizationSubType for each of these. + * Cartesian onwards is always engineering subtype + * WGS84 must be geographic + * UTM must be derived. + */ + + /* + * Localizationtype is more confusing + * e.g. for WGS84, LocalizationType might be point or track. + * UTM can be point or track. + * The most of the others + * + */ + + public LocalizationSubTypes getSubType() { + switch (this) { + case Cartesian: + case Cylindrical: + case PerpendicularRange: + case Polar: + case Range: + case Spherical: + return LocalizationSubTypes.Engineering; + case UTM: + return LocalizationSubTypes.Derived; + case WGS84: + return LocalizationSubTypes.Geographic; + default: + break; + } + return null; + } } diff --git a/src/tethys/localization/LocalizationBuilder.java b/src/tethys/localization/LocalizationBuilder.java new file mode 100644 index 00000000..6405a497 --- /dev/null +++ b/src/tethys/localization/LocalizationBuilder.java @@ -0,0 +1,619 @@ +package tethys.localization; + +import java.math.BigInteger; +import java.util.List; + +import Localiser.LocalisationAlgorithm; +import Localiser.LocalisationAlgorithmInfo; +import Localiser.detectionGroupLocaliser.GroupLocResult; +import Localiser.detectionGroupLocaliser.GroupLocalisation; +import PamDetection.AbstractLocalisation; +import PamDetection.LocContents; +import PamDetection.LocalisationInfo; +import PamUtils.LatLong; +import PamUtils.PamUtils; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import nilus.AlgorithmType; +import nilus.AngularCoordinateType; +import nilus.BearingType; +import nilus.DataSourceType; +import nilus.Detections; +import nilus.Helper; +import nilus.LocalizationType; +import nilus.Localize; +import nilus.SpeciesIDType; +import nilus.WGS84CoordinateType; +import nilus.AlgorithmType.SupportSoftware; +import nilus.LocalizationType.Angular; +import nilus.LocalizationType.Bearing; +import nilus.LocalizationType.Parameters; +import nilus.LocalizationType.References; +import nilus.LocalizationType.WGS84; +import nilus.LocalizationType.Parameters.TargetMotionAnalysis; +import nilus.LocalizationType.References.Reference; +import nilus.Localize.Effort; +import nilus.Localize.Effort.CoordinateReferenceSystem; +import nilus.Localize.Effort.ReferencedDocuments; +import nilus.Localize.Effort.ReferencedDocuments.Document; +import pamMaths.PamVector; +import tethys.Collection; +import tethys.TethysControl; +import tethys.TethysTimeFuncs; +import tethys.niluswraps.PDeployment; +import tethys.output.StreamExportParams; +import tethys.pamdata.AutoTethysProvider; +import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; +import tethys.species.SpeciesMapItem; + +/** + * Class to build a single localisation document during export. + * Works hand in had with the global LocalisationHandler and also + * with other functions it's going to find in the datablock and whatever localisation + * algorithm was used. + * @author dg50 + * + */ +public class LocalizationBuilder { + + private PDeployment deployment; + private Detections detectionsDocument; + private PamDataBlock dataBlock; + private StreamExportParams streamExportParams; + private TethysControl tethysControl; + private LocalizationHandler localisationHandler; + private LocalisationAlgorithm localisationAlgorithm; + + private Localize currentDocument; + private LocalizationCreator localisationCreator; + private TethysDataProvider dataProvider; + + public LocalizationBuilder(TethysControl tethysControl, PDeployment deployment, Detections detectionsDocument, PamDataBlock dataBlock, + StreamExportParams exportParams) { + this.deployment = deployment; + this.detectionsDocument = detectionsDocument; + this.dataBlock = dataBlock; + this.streamExportParams = exportParams; + this.tethysControl = tethysControl; + dataProvider = dataBlock.getTethysDataProvider(tethysControl); + localisationHandler = tethysControl.getLocalizationHandler(); + localisationAlgorithm = dataBlock.getLocalisationAlgorithm(); + if (localisationAlgorithm != null) { + localisationCreator = localisationAlgorithm.getTethysCreator(); + } + currentDocument = startLocalisationDocument(deployment, detectionsDocument, dataBlock, exportParams); + } + + public Localize startLocalisationDocument(PDeployment deployment, Detections detectionsDocument, PamDataBlock dataBlock, + StreamExportParams exportParams) { + currentDocument = new Localize(); + try { + Helper.createRequiredElements(currentDocument); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + return null; + } + Effort eff = currentDocument.getEffort(); + if (eff == null) { + eff = new Effort(); + try { + Helper.createRequiredElements(eff); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + return null; + } + currentDocument.setEffort(eff); + } + if (detectionsDocument != null) { + /* + * add the reference document information. + * Within PAMGuard, this will always be 1:1 with a Detections doc. + */ + + ReferencedDocuments refDocs = eff.getReferencedDocuments(); + if (refDocs == null) { + refDocs = new ReferencedDocuments(); + try { + Helper.createRequiredElements(refDocs); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + eff.setReferencedDocuments(refDocs); + } + Document detectsDoc = new Document(); + detectsDoc.setId(detectionsDocument.getId()); + detectsDoc.setType(Collection.Localizations.collectionName()); + detectsDoc.setIndex(BigInteger.ZERO); + eff.getReferencedDocuments().getDocument().add(detectsDoc); + } + + + String prefix = deployment.nilusObject.getId() + "_" + dataProvider.getDetectionsName(); + String fullId = localisationHandler.getLocalisationdocId(prefix); + currentDocument.setId(fullId); + // detections.setDescription(dataProvider.getDescription(deployment, tethysExportParams)); + currentDocument.setDescription(exportParams.getNilusDetectionDescription()); + DataSourceType dataSource = new DataSourceType(); + dataSource.setDeploymentId(deployment.nilusObject.getId()); + // dataSource.setEnsembleId(""); ToDo + currentDocument.setDataSource(dataSource); + AlgorithmType algorithm = currentDocument.getAlgorithm(); + + if (dataProvider != null) { + algorithm = dataProvider.getAlgorithm(Collection.Localizations); + // detections.setAlgorithm(algorithm); + } + LocalisationAlgorithm locAlgorithm = dataBlock.getLocalisationAlgorithm(); + LocalisationAlgorithmInfo locAlgoinfo = null; + if (locAlgorithm != null) { + locAlgoinfo = locAlgorithm.getAlgorithmInfo(); + } + if (locAlgoinfo != null) { + algorithm.setMethod(locAlgoinfo.getAlgorithmName()); + } + else { + algorithm.setMethod(localisationHandler.getMethodString(dataBlock)); + } + algorithm.setSoftware(localisationHandler.getSoftwareString(dataBlock)); + algorithm.setVersion(localisationHandler.getVersionString(dataBlock)); + + List supSoft = algorithm.getSupportSoftware(); + SupportSoftware supportSoft = new SupportSoftware(); + supportSoft.setSoftware(localisationHandler.getSupportSoftware(dataBlock)); + supportSoft.setVersion(localisationHandler.getSupportSoftwareVersion(dataBlock)); + supSoft.add(supportSoft); + currentDocument.setAlgorithm(algorithm); + + currentDocument.setUserId("PAMGuard user"); + // localisations.setEffort(getLocaliserEffort(deployment, dataBlock, exportParams)); + sortLocaliseCoordinates(dataBlock); + + // sort out coordinate system. + + return currentDocument; + } + + private boolean sortLocaliseCoordinates(PamDataBlock dataBlock) { + boolean done = false; + if (localisationCreator != null) { + done = localisationCreator.sortLocalisationCoordinates(this, dataBlock); + } + if (!done) { + sortStandardCoordinates(dataBlock); + } + return done; + } + + public boolean sortStandardCoordinates(PamDataBlock dataBlock) { + LocalisationInfo locInfo = dataBlock.getLocalisationContents(); + Effort locEffort = currentDocument.getEffort(); + if (locEffort == null) { + locEffort = new Effort(); + currentDocument.setEffort(locEffort); + } + try { + Helper.createRequiredElements(locEffort); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + return false; + } + locEffort.setTimeReference("relative"); +// List locTypes = locEffort.getLocalizationType(); + boolean ambiguity = locInfo.hasLocContent(LocContents.HAS_AMBIGUITY); + CoordinateReferenceSystem coordRefs = locEffort.getCoordinateReferenceSystem(); + List locTypes = locEffort.getLocalizationType(); + if (locInfo.getLocContent() == 0) { + return false; + } + else if (locInfo.hasLocContent(LocContents.HAS_LATLONG)) { + coordRefs.setName(CoordinateName.WGS84.toString()); + coordRefs.setSubtype(LocalizationSubTypes.Geographic.toString()); + locTypes.add(LocalizationTypes.Point.toString()); +// locEffort.set + if (locInfo.hasLocContent(LocContents.HAS_DEPTH)) { + locEffort.setDimension(3); + } + else { + locEffort.setDimension(2); + } +// locEffort.set + } + else if (locInfo.hasLocContent(LocContents.HAS_XYZ)) { + coordRefs.setName(CoordinateName.Cartesian.toString()); + coordRefs.setSubtype(LocalizationSubTypes.Engineering.toString()); + locTypes.add(LocalizationTypes.Point.toString()); + locEffort.setDimension(3); + } + else if (locInfo.hasLocContent(LocContents.HAS_XY)) { + coordRefs.setName(CoordinateName.Cartesian.toString()); + coordRefs.setSubtype(LocalizationSubTypes.Engineering.toString()); + locTypes.add(LocalizationTypes.Point.toString()); + locEffort.setDimension(2); + } + else if (locInfo.hasLocContent(LocContents.HAS_BEARING)) { + coordRefs.setName(CoordinateName.Polar.toString()); + coordRefs.setSubtype(LocalizationSubTypes.Engineering.toString()); + locTypes.add(LocalizationTypes.Bearing.toString()); + if (ambiguity) { + locEffort.setDimension(1); + } + else { + locEffort.setDimension(2); + } + } + else { + return false; + } + + return true; + } + + public LocalizationType addLocalization(PamDataUnit dataUnit) { + LocalizationType newLoc = createLocalization(dataUnit); + if (newLoc != null) { + currentDocument.getLocalizations().getLocalization().add(newLoc); + } + return newLoc; + } + + private LocalizationType createLocalization(PamDataUnit dataUnit) { + if (localisationCreator != null) { + return localisationCreator.createLocalization(this, dataUnit); + } + else { + return createStandardLocalization(dataUnit); + } + } + + public LocalizationType createStandardLocalization(PamDataUnit dataUnit) { + /* + * Get the current type from the document. This should always exist, so + * just go for it, then switch on the value to make the localisation. + */ + CoordinateReferenceSystem coordSystem = currentDocument.getEffort().getCoordinateReferenceSystem(); + String name = coordSystem.getName(); + CoordinateName coordName = CoordinateName.valueOf(name); + if (coordName == null) { + return null; + } + LocalizationType locEl = null; + switch (coordName) { + case Cartesian: + locEl = createCartesianLoc(dataUnit); + break; + case Cylindrical: + locEl = createCylindricalLoc(dataUnit); + break; + case PerpendicularRange: + locEl = createPerpRange(dataUnit); + break; + case Polar: + locEl = createPolarLoc(dataUnit); + break; + case Range: + locEl = createRangeLoc(dataUnit); + break; + case Spherical: + locEl = createSphericalLoc(dataUnit); + break; + case UTM: + break; + case WGS84: + locEl = createWGS84Loc(dataUnit); + break; + default: + break; + + } + return locEl; + } + + public LocalizationType makeBaseLoc(PamDataUnit dataUnit) { + LocalizationType locType = new LocalizationType(); + try { + Helper.createRequiredElements(locType); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + locType.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getTimeMilliseconds())); + + locType.setEvent(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getTimeMilliseconds()).toString()); + + DataBlockSpeciesManager spManager = dataBlock.getDatablockSpeciesManager(); + if (spManager != null) { + SpeciesMapItem speciesStuff = spManager.getSpeciesItem(dataUnit); + SpeciesIDType species = new SpeciesIDType(); + if (speciesStuff != null) { + species.setValue(BigInteger.valueOf(speciesStuff.getItisCode())); + locType.setSpeciesId(species); + } + } + + References references = locType.getReferences(); + if (references == null) { + references = new References(); + try { + Helper.createRequiredElements(references); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + locType.setReferences(references); + } + Reference reference = new Reference(); + reference.setIndex(BigInteger.valueOf(dataUnit.getUID())); + reference.setEventRef("UID"); + locType.getReferences().getReference().add(reference); + + return locType; + } + + /** + * Get angle in degrees constrained to 0-360 + * @param radians + * @return + */ + public double constrainRadianAngle(double radians) { + double deg = Math.toDegrees(radians); + if (Math.abs(deg) > 3600) { + return 359.9; + } + deg = PamUtils.constrainedAngle(deg); + deg = AutoTethysProvider.roundDecimalPlaces(deg, 2); + return deg; + } + + /** + * Convert a vertical angle from radians to degrees and round. + * @param radians + * @return + */ + public double toSlantAngle(double radians) { + /* + * these really need to be constrained to -90 to 90, but I don't see what to do if + * they are outside that range. + */ + double deg = Math.toDegrees(radians); + deg= PamUtils.constrainedAngle(deg, 180); + deg = AutoTethysProvider.roundDecimalPlaces(deg, 2); + return deg; + } + + public LocalizationType createWGS84Loc(PamDataUnit dataUnit) { + AbstractLocalisation loc = dataUnit.getLocalisation(); + if (loc == null) { + return null; + } + LatLong latlong = loc.getLatLong(0); + if (latlong == null) { + return null; + } + LocalizationType locType = makeBaseLoc(dataUnit); + + + /** + * Export the latlong data. + */ + WGS84 wgs84 = new WGS84(); + WGS84CoordinateType coord = new WGS84CoordinateType(); + wgs84.setCoordinate(coord); + coord.setLongitude(latlong.getLongitude()); + coord.setLatitude(latlong.getLatitude()); + coord.setElevationM(AutoTethysProvider.roundDecimalPlaces(latlong.getHeight(),3)); + + PamVector planarVec = loc.getPlanarVector(); + locType.setWGS84(wgs84); + +// locType.setParameters(null); + Parameters params = locType.getParameters(); + if (params == null) { + params = new Parameters(); + locType.setParameters(params); + } + TargetMotionAnalysis tma = new TargetMotionAnalysis(); + tma.setStart(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getTimeMilliseconds())); + tma.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getEndTimeInMilliseconds())); + params.setTargetMotionAnalysis(tma); + + + // see if it's possible to get a beam measurement. + if (loc instanceof GroupLocalisation) { + GroupLocalisation groupLoc = (GroupLocalisation) loc; + GroupLocResult groupLocResult = groupLoc.getGroupLocaResult(0); + Double perpDist = groupLocResult.getPerpendicularDistance(); + Long beamTime = groupLocResult.getBeamTime(); + if (perpDist != null && beamTime != null) { + AngularCoordinateType acType = new AngularCoordinateType(); + acType.setAngle1(90); + acType.setDistanceM(AutoTethysProvider.roundDecimalPlaces(perpDist,1)); + Angular angular = new Angular(); + angular.setCoordinate(acType); + locType.setAngular(angular); + locType.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(beamTime)); + currentDocument.getEffort().setTimeReference(TimeReference.beam.toString()); + } + // groupLoc.getp + } + + /* + * Try to also add a range loc. + */ + // loc. + + return locType; + } + + public LocalizationType createSphericalLoc(PamDataUnit dataUnit) { + // TODO Auto-generated method stub + return null; + } + + public LocalizationType createRangeLoc(PamDataUnit dataUnit) { + // TODO Auto-generated method stub + return null; + } + + public LocalizationType createBearingLoc(PamDataUnit dataUnit) { + AbstractLocalisation loc = dataUnit.getLocalisation(); + if (loc == null) { + return null; + } + LocalizationType locType = makeBaseLoc(dataUnit); + double[] angles = loc.getAngles(); + if (angles == null || angles.length == 0) { + return null; + } + BearingType angType = new BearingType(); + angType.setAngle1(constrainRadianAngle(angles[0])); + if (angles.length >= 2) { + angType.setAngle2(toSlantAngle(angles[1])); + // if (angType.getAngle2() > 360) { + // angType.setAngle2(Math.toDegrees(angles[1])); + // } + } + Bearing bearing = new Bearing(); + bearing.setCoordinate(angType); + locType.setBearing(bearing); + + double[] angErr = loc.getAngleErrors(); + if (angErr != null && angErr.length >= 1) { + BearingType angErrType = new BearingType(); + angErrType.setAngle1(constrainRadianAngle(angErr[0])); + if (angErr.length >= 2) { + angErrType.setAngle2(constrainRadianAngle(angErr[1])); + } + bearing.setCoordinateError(angErrType); + } + + return locType; + } + public LocalizationType createPolarLoc(PamDataUnit dataUnit) { + AbstractLocalisation loc = dataUnit.getLocalisation(); + if (loc == null) { + return null; + } + if (loc.hasLocContent(LocContents.HAS_RANGE) == false) { + + // do the more basic bearing type instead. + return createBearingLoc(dataUnit); + } + LocalizationType locType = makeBaseLoc(dataUnit); + double[] angles = loc.getAngles(); + if (angles == null || angles.length == 0) { + return null; + } + AngularCoordinateType angType = new AngularCoordinateType(); + angType.setAngle1(constrainRadianAngle(angles[0])); + if (angles.length >= 2) { + angType.setAngle2(constrainRadianAngle(angles[1])); + if (angType.getAngle2() > 360) { + angType.setAngle2(toSlantAngle(angles[1])); + } + } + if (loc.hasLocContent(LocContents.HAS_RANGE)) { + angType.setDistanceM(loc.getRange(0)); + } + Angular angular = new Angular(); + angular.setCoordinate(angType); + locType.setAngular(angular); + + double[] angErr = loc.getAngleErrors(); + if (angErr != null && angErr.length >= 1) { + AngularCoordinateType angErrType = new AngularCoordinateType(); + angErrType.setAngle1(constrainRadianAngle(angErr[0])); + if (angErr.length >= 2) { + angErrType.setAngle2(constrainRadianAngle(angErr[1])); + } + if (loc.hasLocContent(LocContents.HAS_RANGEERROR)) { + angErrType.setDistanceM(loc.getRangeError(0)); + } + angular.setCoordinateError(angErrType); + } + + return locType; + } + + public LocalizationType createPerpRange(PamDataUnit dataUnit) { + // TODO Auto-generated method stub + return null; + } + + public LocalizationType createCylindricalLoc(PamDataUnit dataUnit) { + // TODO Auto-generated method stub + return null; + } + + public LocalizationType createCartesianLoc(PamDataUnit dataUnit) { + // TODO Auto-generated method stub + return null; + } + + + /** + * @return the deployment + */ + public PDeployment getDeployment() { + return deployment; + } + + /** + * @return the detectionsDocument + */ + public Detections getDetectionsDocument() { + return detectionsDocument; + } + + /** + * @return the dataBlock + */ + public PamDataBlock getDataBlock() { + return dataBlock; + } + + /** + * @return the exportParams + */ + public StreamExportParams getExportParams() { + return streamExportParams; + } + + /** + * @return the tethysControl + */ + public TethysControl getTethysControl() { + return tethysControl; + } + + /** + * @return the localisationHandler + */ + public LocalizationHandler getLocalisationHandler() { + return localisationHandler; + } + + /** + * @return the localisationAlgorithm + */ + public LocalisationAlgorithm getLocalisationAlgorithm() { + return localisationAlgorithm; + } + + /** + * @return the currentDocument + */ + public Localize getCurrentDocument() { + return currentDocument; + } + + public void closeDocument(long endTime) { + currentDocument.getEffort().setEnd(TethysTimeFuncs.xmlGregCalFromMillis(endTime)); + } + + public boolean checkDocument() { + // TODO Auto-generated method stub + return true; + } + + + +} diff --git a/src/tethys/localization/LocalizationCreator.java b/src/tethys/localization/LocalizationCreator.java new file mode 100644 index 00000000..4a164455 --- /dev/null +++ b/src/tethys/localization/LocalizationCreator.java @@ -0,0 +1,21 @@ +package tethys.localization; + +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import nilus.LocalizationType; + +/** + * Creator thingy that Localisation algorithms can use to overwrite any standard + * behaviour in LocalizatinBuilder. + * @author dg50 + * + */ +public interface LocalizationCreator { + + public boolean sortLocalisationCoordinates(LocalizationBuilder localizationBuilder, PamDataBlock dataBlock) ; + + public LocalizationType createLocalization(LocalizationBuilder localizationBuilder, PamDataUnit dataUnit); + + public boolean checkDocument(LocalizationBuilder localizationBuilder); + +} diff --git a/src/tethys/localization/LocalizationHandler.java b/src/tethys/localization/LocalizationHandler.java index 3ce8f10f..0d4fdffe 100644 --- a/src/tethys/localization/LocalizationHandler.java +++ b/src/tethys/localization/LocalizationHandler.java @@ -1,6 +1,5 @@ package tethys.localization; -import java.math.BigInteger; import java.util.ArrayList; import Localiser.detectionGroupLocaliser.GroupLocResult; @@ -10,14 +9,6 @@ import PamDetection.LocContents; import PamUtils.LatLong; import PamUtils.PamUtils; import PamguardMVC.PamDataBlock; -import PamguardMVC.PamDataUnit; -import nilus.AngularCoordinateType; -import nilus.BearingType; -import nilus.CoordinateType; -import nilus.Helper; -import nilus.LocalizationType; -import nilus.LocalizationType.References; -import nilus.LocalizationType.References.Reference; import nilus.Localize; import nilus.SpeciesIDType; import pamMaths.PamVector; @@ -25,17 +16,14 @@ import nilus.Localize.Effort.CoordinateReferenceSystem; import tethys.Collection; import tethys.CollectionHandler; import tethys.TethysControl; -import tethys.TethysTimeFuncs; import tethys.detection.StreamDetectionsSummary; import tethys.niluswraps.NilusDataWrapper; import tethys.niluswraps.PDeployment; -import tethys.output.StreamExportParams; -import tethys.pamdata.AutoTethysProvider; -import tethys.species.DataBlockSpeciesManager; -import tethys.species.SpeciesMapItem; public class LocalizationHandler extends CollectionHandler { + private int uniqueLocalisationsId = 1; + public LocalizationHandler(TethysControl tethysControl) { super(tethysControl, Collection.Localizations); } @@ -63,7 +51,7 @@ public class LocalizationHandler extends CollectionHandler { * Get a list of Localization documents associated with a particular data block for the list of deployments * documents. Group them by abstract or something * @param dataBlock - * @param deployments can be null for all deployments. + * @param deployments can be null for all deployments. * @return */ public StreamDetectionsSummary> getStreamLocalizations(PamDataBlock dataBlock, ArrayList deployments) { @@ -93,276 +81,18 @@ public class LocalizationHandler extends CollectionHandler { return null; } - /** - * Create a Localization element object to add to a Localizations document. - * @param localiseDocument - * @param dataBlock - * @param dataUnit - * @param streamExportParams - * @return - */ - public LocalizationType createLocalization(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { + public String getLocalisationdocId(String prefix) { /* - * Get the current type from the document. This should always exist, so - * just go for it, then switch on the value to make the localisation. + * Check the document name isn't already used and increment id as necessary. */ - CoordinateReferenceSystem coordSystem = localiseDocument.getEffort().getCoordinateReferenceSystem(); - String name = coordSystem.getName(); - CoordinateName coordName = CoordinateName.valueOf(name); - if (coordName == null) { - return null; - } - LocalizationType locEl = null; - switch (coordName) { - case Cartesian: - locEl = createCartesianLoc(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - case Cylindrical: - locEl = createCylindricalLoc(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - case PerpindicularRange: - locEl = createPerpRange(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - case Polar: - locEl = createPolarLoc(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - case Range: - locEl = createRangeLoc(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - case Spherical: - locEl = createSphericalLoc(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - case UTM: - break; - case WGS84: - locEl = createWGS84Loc(localiseDocument, dataBlock, dataUnit, streamExportParams); - break; - default: - break; - - } - return locEl; - } - - private LocalizationType makeBaseLoc(PamDataBlock dataBlock, PamDataUnit dataUnit) { - LocalizationType locType = new LocalizationType(); - try { - Helper.createRequiredElements(locType); - } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { - e.printStackTrace(); - } - locType.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getTimeMilliseconds())); - - DataBlockSpeciesManager spManager = dataBlock.getDatablockSpeciesManager(); - if (spManager != null) { - SpeciesMapItem speciesStuff = spManager.getSpeciesItem(dataUnit); - SpeciesIDType species = new SpeciesIDType(); - if (speciesStuff != null) { - species.setValue(BigInteger.valueOf(speciesStuff.getItisCode())); - locType.setSpeciesId(species); + String fullId; + while (true) { + fullId = String.format("%s_%d", prefix, uniqueLocalisationsId++); + if (!tethysControl.getDbxmlQueries().documentExists(Collection.Localizations.toString(), fullId)) { + break; } } - - References references = locType.getReferences(); - if (references == null) { - references = new References(); - try { - Helper.createRequiredElements(references); - } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { - e.printStackTrace(); - } - locType.setReferences(references); - } - Reference reference = new Reference(); - reference.setIndex(BigInteger.valueOf(dataUnit.getUID())); - reference.setEventRef("UID"); - locType.getReferences().getReference().add(reference); - - return locType; - } - - /** - * Get angle in degrees constrained to 0-360 - * @param radians - * @return - */ - private double constrainRadianAngle(double radians) { - double deg = Math.toDegrees(radians); - if (Math.abs(deg) > 3600) { - return 359.9; - } - deg = PamUtils.constrainedAngle(deg); - deg = AutoTethysProvider.roundDecimalPlaces(deg, 2); - return deg; - } - - /** - * Convert a vertical angle from radians to degrees and round. - * @param radians - * @return - */ - private double toSlantAngle(double radians) { - /* - * these really need to be constrained to -90 to 90, but I don't see what to do if - * they are outside that range. - */ - double deg = Math.toDegrees(radians); - deg= PamUtils.constrainedAngle(deg, 180); - deg = AutoTethysProvider.roundDecimalPlaces(deg, 2); - return deg; - } - - private LocalizationType createWGS84Loc(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - AbstractLocalisation loc = dataUnit.getLocalisation(); - if (loc == null) { - return null; - } - LatLong latlong = loc.getLatLong(0); - if (latlong == null) { - return null; - } - LocalizationType locType = makeBaseLoc(dataBlock, dataUnit); - CoordinateType coord = new CoordinateType(); - coord.setX(latlong.getLongitude()); - coord.setY(latlong.getLatitude()); - coord.setZ(latlong.getHeight()); - - PamVector planarVec = loc.getPlanarVector(); - locType.setCoordinate(coord); - - // see if it's possible to get a beam measurement. - if (loc instanceof GroupLocalisation) { - GroupLocalisation groupLoc = (GroupLocalisation) loc; - GroupLocResult groupLocResult = groupLoc.getGroupLocaResult(0); - Double perpDist = groupLocResult.getPerpendicularDistance(); - Long beamTime = groupLocResult.getBeamTime(); - if (perpDist != null && beamTime != null) { - AngularCoordinateType acType = new AngularCoordinateType(); - acType.setAngle1(90); - acType.setDistanceM(AutoTethysProvider.roundDecimalPlaces(perpDist,1)); - locType.setAngularCoordinate(acType); - locType.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(beamTime)); - locType.setCoordinate(null); - } - // groupLoc.getp - } - - /* - * Try to also add a range loc. - */ - // loc. - - return locType; - } - - private LocalizationType createSphericalLoc(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - // TODO Auto-generated method stub - return null; - } - - private LocalizationType createRangeLoc(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - // TODO Auto-generated method stub - return null; - } - - private LocalizationType createBearingLoc(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - AbstractLocalisation loc = dataUnit.getLocalisation(); - if (loc == null) { - return null; - } - LocalizationType locType = makeBaseLoc(dataBlock, dataUnit); - double[] angles = loc.getAngles(); - if (angles == null || angles.length == 0) { - return null; - } - BearingType angType = new BearingType(); - angType.setAngle1(constrainRadianAngle(angles[0])); - if (angles.length >= 2) { - angType.setAngle2(toSlantAngle(angles[1])); - // if (angType.getAngle2() > 360) { - // angType.setAngle2(Math.toDegrees(angles[1])); - // } - } - locType.setBearing(angType); - - double[] angErr = loc.getAngleErrors(); - if (angErr != null && angErr.length >= 1) { - BearingType angErrType = new BearingType(); - angErrType.setAngle1(constrainRadianAngle(angErr[0])); - if (angErr.length >= 2) { - angErrType.setAngle2(constrainRadianAngle(angErr[1])); - } - locType.setBearingError(angErrType); - } - - return locType; - } - private LocalizationType createPolarLoc(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - AbstractLocalisation loc = dataUnit.getLocalisation(); - if (loc == null) { - return null; - } - if (loc.hasLocContent(LocContents.HAS_RANGE) == false) { - - // do the more basic bearing type instead. - return createBearingLoc(localiseDocument, dataBlock, dataUnit, streamExportParams); - } - LocalizationType locType = makeBaseLoc(dataBlock, dataUnit); - double[] angles = loc.getAngles(); - if (angles == null || angles.length == 0) { - return null; - } - AngularCoordinateType angType = new AngularCoordinateType(); - angType.setAngle1(constrainRadianAngle(angles[0])); - if (angles.length >= 2) { - angType.setAngle2(constrainRadianAngle(angles[1])); - if (angType.getAngle2() > 360) { - angType.setAngle2(toSlantAngle(angles[1])); - } - } - if (loc.hasLocContent(LocContents.HAS_RANGE)) { - angType.setDistanceM(loc.getRange(0)); - } - locType.setAngularCoordinate(angType); - - double[] angErr = loc.getAngleErrors(); - if (angErr != null && angErr.length >= 1) { - AngularCoordinateType angErrType = new AngularCoordinateType(); - angErrType.setAngle1(constrainRadianAngle(angErr[0])); - if (angErr.length >= 2) { - angErrType.setAngle2(constrainRadianAngle(angErr[1])); - } - if (loc.hasLocContent(LocContents.HAS_RANGEERROR)) { - angErrType.setDistanceM(loc.getRangeError(0)); - } - locType.setAngularCoordinateError(angErrType); - } - - return locType; - } - - private LocalizationType createPerpRange(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - // TODO Auto-generated method stub - return null; - } - - private LocalizationType createCylindricalLoc(Localize localiseDocument, PamDataBlock dataBlock, - PamDataUnit dataUnit, StreamExportParams streamExportParams) { - // TODO Auto-generated method stub - return null; - } - - private LocalizationType createCartesianLoc(Localize localiseDocument, PamDataBlock dataBlock, PamDataUnit dataUnit, - StreamExportParams streamExportParams) { - // TODO Auto-generated method stub - return null; + return fullId; } } diff --git a/src/tethys/localization/LocalizationSubType.java b/src/tethys/localization/LocalizationSubTypes.java similarity index 58% rename from src/tethys/localization/LocalizationSubType.java rename to src/tethys/localization/LocalizationSubTypes.java index ce558751..b86517ad 100644 --- a/src/tethys/localization/LocalizationSubType.java +++ b/src/tethys/localization/LocalizationSubTypes.java @@ -5,6 +5,11 @@ package tethys.localization; * @author dg50 * */ -public enum LocalizationSubType { +public enum LocalizationSubTypes { Geographic, Derived, Engineering; + /* + * Geographic is WGS84 + * Derived is something like UTM, but is basically geographic + * Engineering is relative to platform or fixed point. + */ } diff --git a/src/tethys/localization/LocalizationType.java b/src/tethys/localization/LocalizationTypes.java similarity index 73% rename from src/tethys/localization/LocalizationType.java rename to src/tethys/localization/LocalizationTypes.java index 568fc70e..8beea160 100644 --- a/src/tethys/localization/LocalizationType.java +++ b/src/tethys/localization/LocalizationTypes.java @@ -6,6 +6,6 @@ package tethys.localization; * @author dg50 * */ -public enum LocalizationType { - Bearing, PerpindicularRange, Point, Range, Track; +public enum LocalizationTypes { + Bearing, PerpendicularRange, Point, Range, Track; } diff --git a/src/tethys/localization/TimeReference.java b/src/tethys/localization/TimeReference.java index 96bbca70..4f98e8b9 100644 --- a/src/tethys/localization/TimeReference.java +++ b/src/tethys/localization/TimeReference.java @@ -6,5 +6,5 @@ package tethys.localization; * */ public enum TimeReference { - absolute, channel, relative; + absolute, channel, relative, beam; } diff --git a/src/tethys/output/TethysExportParams.java b/src/tethys/output/TethysExportParams.java index a0ff683b..307993b5 100644 --- a/src/tethys/output/TethysExportParams.java +++ b/src/tethys/output/TethysExportParams.java @@ -47,6 +47,7 @@ public class TethysExportParams implements Serializable, Cloneable{ public boolean listDocsInPamguard; private String effortSourceName; + /** diff --git a/src/tethys/pamdata/AutoTethysProvider.java b/src/tethys/pamdata/AutoTethysProvider.java index 2226da0a..177a1f85 100644 --- a/src/tethys/pamdata/AutoTethysProvider.java +++ b/src/tethys/pamdata/AutoTethysProvider.java @@ -123,6 +123,12 @@ abstract public class AutoTethysProvider implements TethysDataProvider { } if (collection == Collection.Localizations) { nilus.AlgorithmType.Parameters locParameters = this.getLocalisationParameters(); + if (locParameters == null) { + /* + * It seems Tethys MUST have parameters, so make an empty one if needed. + */ + locParameters = new nilus.AlgorithmType.Parameters(); + } if (algoParameters == null) { algorithm.setParameters(locParameters); } @@ -143,6 +149,11 @@ abstract public class AutoTethysProvider implements TethysDataProvider { return algorithm; } + /** + * Localisation parameters. Some localisers don't actually have any parameters, + * but Tethys requires a parameters element, so if there aren't any, set a dummy + * @return + */ public nilus.AlgorithmType.Parameters getLocalisationParameters() { LocalisationAlgorithm algo = pamDataBlock.getLocalisationAlgorithm(); if (algo == null) { diff --git a/src/tethys/swing/DatablockDetectionsPanel.java b/src/tethys/swing/DatablockDetectionsPanel.java index 2935c3c4..886187f7 100644 --- a/src/tethys/swing/DatablockDetectionsPanel.java +++ b/src/tethys/swing/DatablockDetectionsPanel.java @@ -283,7 +283,7 @@ public class DatablockDetectionsPanel extends TethysGUIPanel implements StreamTa menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { -// deleteDocument(pDets); + deleteDocument(pDets); } }); popMenu.add(menuItem); diff --git a/src/tethys/swing/PAMGuardDeploymentsTable.java b/src/tethys/swing/PAMGuardDeploymentsTable.java index cef4d468..78d3df3f 100644 --- a/src/tethys/swing/PAMGuardDeploymentsTable.java +++ b/src/tethys/swing/PAMGuardDeploymentsTable.java @@ -250,31 +250,47 @@ private RecordingList masterList; * @return true if there are no Detections or if they are sucessfully removed as well. */ private boolean checkDetections(Deployment deployment) { - // get any deployment documents that associate with this deployment. - ArrayList detectionDocs = getTethysControl().getDbxmlQueries().getDetectionsDocuments(deployment.getId()); - if (detectionDocs == null || detectionDocs.size() == 0) { + // get any deployment documents that associate with this deployment. + ArrayList detectionDocs = getTethysControl().getDbxmlQueries().getDeploymentDocuments(Collection.Detections, deployment.getId()); + ArrayList localizationDocs = getTethysControl().getDbxmlQueries().getDeploymentDocuments(Collection.Localizations, deployment.getId()); + int nDocs = 0; + if (detectionDocs != null) nDocs += detectionDocs.size(); + if (localizationDocs != null) nDocs += localizationDocs.size(); + if (nDocs == 0) { return true; } - String msg = String.format("One or more Detections documents are associated with Deployment %s
", deployment.getId()); + String msg = String.format("%d other documents are associated with Deployment %s
", nDocs, deployment.getId()); for (String str : detectionDocs) { msg += String.format("
%s", str); } msg += String.format("

You must delete these prior to deleting the Deploymen. Go ahead and delete ?"); - int ans = WarnOnce.showWarning(getTethysControl().getGuiFrame(), "Existing Detections documents !" , msg, WarnOnce.OK_CANCEL_OPTION); + int ans = WarnOnce.showWarning(getTethysControl().getGuiFrame(), "Existing Detection / Localization documents !" , msg, WarnOnce.OK_CANCEL_OPTION); if (ans == WarnOnce.CANCEL_OPTION) { return false; } // OK, so delete all the Detections too !!! boolean errors = false; - for (String str : detectionDocs) { - try { - boolean gone = getTethysControl().getDbxmlConnect().removeDocument(Collection.Detections, str); - } catch (TethysException e) { - getTethysControl().showException(e); - errors = true; + if (detectionDocs != null) { + for (String str : detectionDocs) { + try { + boolean gone = getTethysControl().getDbxmlConnect().removeDocument(Collection.Detections, str); + } catch (TethysException e) { + getTethysControl().showException(e); + errors = true; + } } } - + if (localizationDocs != null) { + for (String str : localizationDocs) { + try { + boolean gone = getTethysControl().getDbxmlConnect().removeDocument(Collection.Localizations, str); + } catch (TethysException e) { + getTethysControl().showException(e); + errors = true; + } + } + } + return !errors; } diff --git a/src/tethys/swing/documents/TethysDocumentTable.java b/src/tethys/swing/documents/TethysDocumentTable.java index 40700d70..b58f906b 100644 --- a/src/tethys/swing/documents/TethysDocumentTable.java +++ b/src/tethys/swing/documents/TethysDocumentTable.java @@ -1,6 +1,9 @@ package tethys.swing.documents; import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; @@ -8,18 +11,24 @@ import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; import javax.swing.JComponent; +import javax.swing.JLabel; 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 PamController.PamController; import PamView.dialog.PamDialogPanel; +import PamView.dialog.PamGridBagContraints; import PamView.dialog.warn.WarnOnce; +import PamView.panel.WestAlignedPanel; import PamView.tables.SwingTableColumnWidths; import tethys.Collection; import tethys.DocumentInfo; @@ -47,6 +56,10 @@ public class TethysDocumentTable implements PamDialogPanel { private JScrollPane scrollPane; + private JComboBox collectionSelector; + + // won't work since only Deployment documents have project info. +// private JCheckBox projectOnly; /** * @param tethysControl * @param collectionName @@ -55,6 +68,37 @@ public class TethysDocumentTable implements PamDialogPanel { this.tethysControl = tethysControl; this.collection = collection; mainPanel = new JPanel(new BorderLayout()); + JPanel topPanel = new JPanel(new GridBagLayout()); + JPanel northPanel = new WestAlignedPanel(topPanel); + GridBagConstraints c = new PamGridBagContraints(); + northPanel.setBorder(new TitledBorder("Options")); + collectionSelector = new JComboBox(); + Collection[] items = Collection.mainList(); + for (int i = 0; i < items.length; i++) { + collectionSelector.addItem(items[i]); + } +// projectOnly = new JCheckBox("Current project only"); + topPanel.add(new JLabel("Collection "),c); + c.gridx++; + topPanel.add(collectionSelector,c); +// topPanel.add(projectOnly); + mainPanel.add(BorderLayout.NORTH, northPanel); + collectionSelector.setSelectedItem(collection); +// projectOnly.setSelected(tethysControl.getTethysExportParams().projectOnlyDocs); + collectionSelector.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + collectionChanged(); + } + }); +// projectOnly.addActionListener(new ActionListener() { +// +// @Override +// public void actionPerformed(ActionEvent e) { +// collectionChanged(); +// } +// }); + tableModel = new TableModel(); mainTable = new JTable(tableModel); scrollPane = new JScrollPane(mainTable); @@ -65,6 +109,19 @@ public class TethysDocumentTable implements PamDialogPanel { mainTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); } + /** + * Called on any options change. + */ + protected void collectionChanged() { + Collection newItem = (Collection) collectionSelector.getSelectedItem(); + if (newItem == null) { + return; + } + this.collection = newItem; + + updateTableData(); + } + public void updateTableData() { documentInfos = tethysControl.getDbxmlQueries().getCollectionDocumentList(collection); if (documentInfos != null) { @@ -88,6 +145,18 @@ public class TethysDocumentTable implements PamDialogPanel { showPopupMenu(e); } } + + @Override + public void mouseClicked(MouseEvent e) { + int row = mainTable.getSelectedRow(); + if (row < 0|| row >= documentInfos.size()) { + return; + } + DocumentInfo docInfo = documentInfos.get(row); + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { + showDocument(docInfo); + } + } } @@ -101,8 +170,9 @@ public class TethysDocumentTable implements PamDialogPanel { } DocumentInfo docInfo = documentInfos.get(row); + String docName = docInfo.getDocumentName(); JPopupMenu popMenu = new JPopupMenu(); - JMenuItem menuItem = new JMenuItem("Show document " + docInfo); + JMenuItem menuItem = new JMenuItem("Show document " + docName); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -114,8 +184,9 @@ public class TethysDocumentTable implements PamDialogPanel { int[] rows = mainTable.getSelectedRows(); if (rows != null && rows.length == 1) { + popMenu.addSeparator(); // docName = documentNames.get(rows[0]); - menuItem = new JMenuItem("Delete document " + docInfo); + menuItem = new JMenuItem("Delete document " + docName); menuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -252,6 +323,7 @@ public class TethysDocumentTable implements PamDialogPanel { public void setCollection(Collection collection) { this.collection = collection; + this.collectionSelector.setSelectedItem(collection); updateTableData(); } diff --git a/src/tethys/swing/documents/TethysDocumentsFrame.java b/src/tethys/swing/documents/TethysDocumentsFrame.java index a376d6f1..9b0c5eb0 100644 --- a/src/tethys/swing/documents/TethysDocumentsFrame.java +++ b/src/tethys/swing/documents/TethysDocumentsFrame.java @@ -15,7 +15,7 @@ public class TethysDocumentsFrame extends PamDialog { private TethysDocumentTable documentsTable; private TethysDocumentsFrame(Window parentFrame,TethysControl tethysControl) { - super(parentFrame, "Documents", false); + super(parentFrame, "Tethys Documents", false); documentsTable = new TethysDocumentTable(tethysControl, null); setDialogComponent(documentsTable.getDialogComponent()); setModalityType(ModalityType.MODELESS); @@ -25,11 +25,11 @@ public class TethysDocumentsFrame extends PamDialog { } public static void showTable(Window parentFrame, TethysControl tethysControl, Collection collection) { - if (singleInstance == null) { +// if (singleInstance == null) { singleInstance = new TethysDocumentsFrame(parentFrame, tethysControl); - } +// } singleInstance.documentsTable.setCollection(collection); - singleInstance.setTitle(collection.collectionName() + " Documents"); +// singleInstance.setTitle(collection.collectionName() + " Documents"); singleInstance.setVisible(true); } diff --git a/src/whistlesAndMoans/WhistleMoanControl.java b/src/whistlesAndMoans/WhistleMoanControl.java index f6f4409c..aa36c48a 100644 --- a/src/whistlesAndMoans/WhistleMoanControl.java +++ b/src/whistlesAndMoans/WhistleMoanControl.java @@ -19,6 +19,7 @@ import detectionPlotFX.data.DDPlotRegister; import detectionPlotFX.rawDDPlot.ClickDDPlotProvider; import detectionPlotFX.whistleDDPlot.WhistleDDPlotProvider; import spectrogramNoiseReduction.SpectrogramNoiseProcess; +import tethys.localization.LocalizationCreator; import whistlesAndMoans.layoutFX.WhistleMoanGUIFX; import whistlesAndMoans.plots.WhistlePlotProvider; import PamController.PamConfiguration; @@ -236,4 +237,9 @@ public class WhistleMoanControl extends PamControlledUnit implements PamSettings public LocalisationAlgorithmInfo getAlgorithmInfo() { return whistleToneProcess.getLocAlgorithmInfo(); } + + @Override + public LocalizationCreator getTethysCreator() { + return null; + } }