diff --git a/src/RightWhaleEdgeDetector/species/RWSpeciesManager.java b/src/RightWhaleEdgeDetector/species/RWSpeciesManager.java index 86f0bf49..65c2afd7 100644 --- a/src/RightWhaleEdgeDetector/species/RWSpeciesManager.java +++ b/src/RightWhaleEdgeDetector/species/RWSpeciesManager.java @@ -3,7 +3,8 @@ package RightWhaleEdgeDetector.species; import PamguardMVC.PamDataBlock; import RightWhaleEdgeDetector.RWEDataUnit; import tethys.species.DataBlockSpeciesManager; -import tethys.species.DataBlockSpeciesTypes; +import tethys.species.DataBlockSpeciesCodes; +import tethys.species.SpeciesMapItem; public class RWSpeciesManager extends DataBlockSpeciesManager { @@ -11,15 +12,16 @@ public class RWSpeciesManager extends DataBlockSpeciesManager { public RWSpeciesManager(PamDataBlock dataBlock) { super(dataBlock); + setDefaultDefaultSpecies(new SpeciesMapItem(RWSpeciesTypes.eubalaena, RWSpeciesTypes.onlyType, RWSpeciesTypes.defaultName)); } @Override - public DataBlockSpeciesTypes getSpeciesTypes() { - return rwSpeciesTypes; + public DataBlockSpeciesCodes getSpeciesCodes() { + return null; } @Override - public String getSpeciesString(RWEDataUnit dataUnit) { + public String getSpeciesCode(RWEDataUnit dataUnit) { return RWSpeciesTypes.onlyType; } diff --git a/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java b/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java index 7a249a68..654fe24c 100644 --- a/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java +++ b/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java @@ -1,15 +1,17 @@ package RightWhaleEdgeDetector.species; -import tethys.species.DataBlockSpeciesTypes; +import tethys.species.DataBlockSpeciesCodes; -public class RWSpeciesTypes extends DataBlockSpeciesTypes { +public class RWSpeciesTypes extends DataBlockSpeciesCodes { public static final String onlyType = "Up call"; - private static final int glacialis = 180536; + public static final int eubalaena = 180536; + + public static final String defaultName = "Right Whale"; public RWSpeciesTypes() { - super(glacialis, onlyType); + super(eubalaena, defaultName, onlyType); } } diff --git a/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java index 930ec8f0..89812008 100644 --- a/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java +++ b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java @@ -4,7 +4,7 @@ import clickDetector.ClickControl; import clickDetector.ClickDataBlock; import clickDetector.ClickDetection; import tethys.species.DataBlockSpeciesManager; -import tethys.species.DataBlockSpeciesTypes; +import tethys.species.DataBlockSpeciesCodes; import tethys.species.ITISTypes; import tethys.species.SpeciesMapItem; @@ -16,11 +16,11 @@ public class ClickBlockSpeciesManager extends DataBlockSpeciesManager speciesNames; @@ -31,7 +32,7 @@ public class DataBlockSpeciesTypes { /** * @param defaultType */ - public DataBlockSpeciesTypes(String defaultType) { + public DataBlockSpeciesCodes(String defaultType) { this.defaultType = defaultType; } @@ -39,8 +40,10 @@ public class DataBlockSpeciesTypes { * @param itisDefault * @param defaultType */ - public DataBlockSpeciesTypes(int itisDefault, String defaultType) { + public DataBlockSpeciesCodes(int itisDefault, String defaultName, String defaultType) { this.itisDefault = itisDefault; + speciesNames = new ArrayList<>(); + speciesNames.add(defaultName); this.defaultType = defaultType; } @@ -48,7 +51,7 @@ public class DataBlockSpeciesTypes { * constructor to use with a array of String names. * @param speciesList */ - public DataBlockSpeciesTypes(String defaultType, String[] speciesList) { + public DataBlockSpeciesCodes(String defaultType, String[] speciesList) { this.defaultType = defaultType; if (speciesList == null) { speciesNames = new ArrayList<>(); diff --git a/src/tethys/species/DataBlockSpeciesManager.java b/src/tethys/species/DataBlockSpeciesManager.java index 83582c61..bf94ffa9 100644 --- a/src/tethys/species/DataBlockSpeciesManager.java +++ b/src/tethys/species/DataBlockSpeciesManager.java @@ -1,5 +1,7 @@ package tethys.species; +import java.util.ArrayList; + import PamController.PamController; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; @@ -7,31 +9,86 @@ import tethys.species.swing.DataBlockSpeciesDialog; /** * Manage species conversion for a single datablock. + * + * there seem to be three types of manager:
+ * 1. Datablocks which have a totally free list of species codes, such as the click detector, or whistle classifier
+ * 1a. A slight variation on this is blocks which have a list and also a default for data units which aren't classified.
+ * 2. Datablocks which have a single type which may be unknown or partially known, but we want the possibility of overriding it. + * e.g. the whistle detector may default to odontocete, but may be overridden to a mystecete species.
+ * 3. Datablocks with no information, or where the list from (1.) is empty.

+ * In all cases, we need to handle this reasonably sensibly. The code list is always the start of this and must + * always return something, even if it's 'unknown'. + * * @author dg50 * */ abstract public class DataBlockSpeciesManager { + /** + * The serialised bit. Always exists (or should be created) even if there + * are no real species, via a defaultdefaultSpecies. + */ private DataBlockSpeciesMap datablockSpeciesMap; private PamDataBlock dataBlock; - private String defaultName = null; + /* + * Below are three ways of getting species codes. At least ONE of these + * must return something. + */ + + /** + * Object that contains a list of species codes. This may be fluid + * between configurations and may change during a session, e.g. through + * the addition of a new click type or changes to the whistle classifier settings. + * @return object containing a list of species types. + */ + public abstract DataBlockSpeciesCodes getSpeciesCodes(); + /** + * A default species code. Can be null, in which case it won't be used or + * can be set to something like 'Unknown' + */ + private String defaultSpeciesCode = null; + + /** + * For use in detectors that have a strong default species, but no + * real list of different species codes. Can be left null. + */ private SpeciesMapItem defaultDefaultSpecies = null; - public abstract DataBlockSpeciesTypes getSpeciesTypes(); - public abstract String getSpeciesString(T dataUnit); + /** + * Gets a species string for a specific data unit, This is abstracted + * since different detectors store this in non standard ways. The result of + * this should be within the set provided by getSpeciesCodes() which can then + * be used in the DataBlockSpeciesMap to look up an itis code. + * @param dataUnit + * @return A species code for a specific data unit. May be null (e.g. for an unclassified click) + */ + public abstract String getSpeciesCode(T dataUnit); public DataBlockSpeciesManager(PamDataBlock dataBlock) { super(); this.dataBlock = dataBlock; datablockSpeciesMap = SpeciesMapManager.getInstance().getSpeciesMap(dataBlock); +// datablockSpeciesMap.clearMap(); + clearMapNulls(); + checkMapDefault(); } + /** + * Clear up some old maps which have got a null null default. + */ + private void clearMapNulls() { + SpeciesMapItem nullVal = datablockSpeciesMap.getItem(null); + if (nullVal == null) { + datablockSpeciesMap.removeItem(null); + } + } + public SpeciesMapItem getSpeciesItem(T dataUnit) { - String speciesString = getSpeciesString(dataUnit); + String speciesString = getSpeciesCode(dataUnit); if (speciesString == null) { return getDefaultDefaultSpecies(); } @@ -42,6 +99,30 @@ abstract public class DataBlockSpeciesManager { return speciesMap.getItem(speciesString); } + /** + * Get all PAMGuard species codes, which may come from the DataBlockSpeciesCodes + * object, or the defaultSpeciesCode, or the defaultDefaultSpecies name. Ideally, + * at least one of these should have something, or we'll stick in an "Unknown" + * @return + */ + public ArrayList getAllSpeciesCodes() { + ArrayList allCodes = new ArrayList(); + if (defaultSpeciesCode != null) { + allCodes.add(defaultSpeciesCode); + } + if (defaultDefaultSpecies != null) { + allCodes.add(defaultDefaultSpecies.getPamguardName()); + } + DataBlockSpeciesCodes codeList = getSpeciesCodes(); + if (codeList != null) { + allCodes.addAll(codeList.getSpeciesNames()); + } + if (allCodes.size() == 0) { + allCodes.add("Unknown"); + } + return allCodes; + } + public DataBlockSpeciesMap getDatablockSpeciesMap() { if (datablockSpeciesMap == null) { datablockSpeciesMap = new DataBlockSpeciesMap(); @@ -51,9 +132,16 @@ abstract public class DataBlockSpeciesManager { } private void checkMapDefault() { - SpeciesMapItem defaultItem = datablockSpeciesMap.getItem(getDefaultName()); +// SpeciesMapItem defaultItem = datablockSpeciesMap.getItem(getDefaultSpeciesCode()); +// if (defaultItem == null) { +// datablockSpeciesMap.putItem(getDefaultSpeciesCode(), getDefaultDefaultSpecies()); +// } + if (defaultDefaultSpecies == null) { + return; + } + SpeciesMapItem defaultItem = datablockSpeciesMap.getItem(defaultDefaultSpecies.getPamguardName()); if (defaultItem == null) { - datablockSpeciesMap.putItem(getDefaultName(), getDefaultDefaultSpecies()); + datablockSpeciesMap.putItem(defaultDefaultSpecies.getPamguardName(), defaultDefaultSpecies); } } @@ -84,19 +172,20 @@ abstract public class DataBlockSpeciesManager { */ public void setDefaultDefaultSpecies(SpeciesMapItem defaultDefaultSpecies) { this.defaultDefaultSpecies = defaultDefaultSpecies; + checkMapDefault(); } /** * @return the defaultName */ - public String getDefaultName() { - return defaultName; + public String getDefaultSpeciesCode() { + return defaultSpeciesCode; } /** * @param defaultName the defaultName to set */ - public void setDefaultName(String defaultName) { - this.defaultName = defaultName; + public void setDefaultSpeciesCode(String defaultName) { + this.defaultSpeciesCode = defaultName; } } diff --git a/src/tethys/species/DataBlockSpeciesMap.java b/src/tethys/species/DataBlockSpeciesMap.java index 6d6b6857..a704d9ac 100644 --- a/src/tethys/species/DataBlockSpeciesMap.java +++ b/src/tethys/species/DataBlockSpeciesMap.java @@ -4,7 +4,10 @@ import java.io.Serializable; import java.util.HashMap; /** - * Species map for a specified data block + * Species map for a specified data block

+ * This is the bit that can be serialised, and is primarily (only) a hash table of + * SpeciesMapItems which relate String species codes for a detector to more + * details itis and scientific name information. * @author dg50 * */ @@ -33,5 +36,9 @@ public class DataBlockSpeciesMap implements Serializable { public void removeItem(String key) { speciesTable.remove(key); } + + public void clearMap() { + speciesTable.clear(); + } } diff --git a/src/tethys/species/SpeciesTest.java b/src/tethys/species/SpeciesTest.java index b476b3ba..13403f8d 100644 --- a/src/tethys/species/SpeciesTest.java +++ b/src/tethys/species/SpeciesTest.java @@ -129,9 +129,9 @@ public class SpeciesTest { private void runJson() { // String jQ = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}"; // String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}"; - String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}"; +// String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/tsn\",\"180488\"],\"optype\":\"binary\"}],\"enclose\":1}"; // String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"=\",\"operands\":[\"ranks/rank/completename\",\"Physeter macrocephalus\"],\"optype\":\"binary\"}],\"enclose\":1}"; -// String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"dbxml:contains\",\"operands\":[\"ranks/rank/completename\",\"Sperm\"],\"optype\":\"function\"}],\"enclose\":1}"; + String jQ = "{\"return\":[\"ranks/rank\"],\"select\":[{\"op\":\"dbxml:contains\",\"operands\":[\"ranks/rank/completename\",\"Sperm\"],\"optype\":\"function\"}],\"enclose\":1}"; System.out.println(jQ); diff --git a/src/tethys/species/swing/DataBlockSpeciesPanel.java b/src/tethys/species/swing/DataBlockSpeciesPanel.java index b7b69370..e2649f74 100644 --- a/src/tethys/species/swing/DataBlockSpeciesPanel.java +++ b/src/tethys/species/swing/DataBlockSpeciesPanel.java @@ -12,7 +12,7 @@ import PamView.dialog.PamDialogPanel; import PamguardMVC.PamDataBlock; import tethys.species.DataBlockSpeciesManager; import tethys.species.DataBlockSpeciesMap; -import tethys.species.DataBlockSpeciesTypes; +import tethys.species.DataBlockSpeciesCodes; import tethys.species.SpeciesMapItem; public class DataBlockSpeciesPanel implements PamDialogPanel { @@ -46,8 +46,8 @@ public class DataBlockSpeciesPanel implements PamDialogPanel { subPanels.clear(); DataBlockSpeciesManager speciesManager = dataBlock.getDatablockSpeciesManager(); - DataBlockSpeciesTypes speciesTypes = speciesManager.getSpeciesTypes(); - ArrayList speciesNames = speciesTypes.getSpeciesNames(); +// DataBlockSpeciesCodes speciesTypes = speciesManager.getSpeciesCodes(); + ArrayList speciesNames = speciesManager.getAllSpeciesCodes(); DataBlockSpeciesMap speciesMap = speciesManager.getDatablockSpeciesMap(); for (String aSpecies : speciesNames) { SpeciesSubPanel subPanel = new SpeciesSubPanel(aSpecies); diff --git a/src/tethys/species/swing/SpeciesSubPanel.java b/src/tethys/species/swing/SpeciesSubPanel.java index 0233cbc9..548b23a1 100644 --- a/src/tethys/species/swing/SpeciesSubPanel.java +++ b/src/tethys/species/swing/SpeciesSubPanel.java @@ -139,7 +139,7 @@ public class SpeciesSubPanel { tsn = Integer.valueOf(itisCode.getText()); } catch (NumberFormatException e) { - PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specified an ITIS taxanomic code"); + PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specify an ITIS taxanomic code"); return null; } latin = latinName.getText(); @@ -149,7 +149,8 @@ public class SpeciesSubPanel { PamDialog.showWarning(PamController.getMainFrame(), pamguardName.getText(), "You must specified a call type"); return null; } - return new SpeciesMapItem(tsn, callType, pamguardName.getText(), latin, vernacular); + String pamName = pamguardName.getText().replace("\"", ""); + return new SpeciesMapItem(tsn, callType, pamName, latin, vernacular); } } diff --git a/src/whistlesAndMoans/species/WhistleSpeciesManager.java b/src/whistlesAndMoans/species/WhistleSpeciesManager.java index 8c4085b4..78827730 100644 --- a/src/whistlesAndMoans/species/WhistleSpeciesManager.java +++ b/src/whistlesAndMoans/species/WhistleSpeciesManager.java @@ -3,7 +3,7 @@ package whistlesAndMoans.species; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import tethys.species.DataBlockSpeciesManager; -import tethys.species.DataBlockSpeciesTypes; +import tethys.species.DataBlockSpeciesCodes; import tethys.species.ITISTypes; import tethys.species.SpeciesMapItem; import whistlesAndMoans.ConnectedRegionDataUnit; @@ -15,19 +15,20 @@ public class WhistleSpeciesManager extends DataBlockSpeciesManager dataBlock) { super(dataBlock); - setDefaultDefaultSpecies(new SpeciesMapItem(180404, "Tonal", "Odontocete")); + setDefaultDefaultSpecies(new SpeciesMapItem(180404, "Tonal", "Tonal")); } @Override - public DataBlockSpeciesTypes getSpeciesTypes() { - String spList[] = {"Unknown"}; - - DataBlockSpeciesTypes whistleSpeciesTypes = new DataBlockSpeciesTypes("Tonal", spList); - return whistleSpeciesTypes; + public DataBlockSpeciesCodes getSpeciesCodes() { +// String spList[] = {"Unknown"}; +// +// DataBlockSpeciesCodes whistleSpeciesTypes = new DataBlockSpeciesCodes("Tonal", spList); +// return whistleSpeciesTypes; + return null; } @Override - public String getSpeciesString(ConnectedRegionDataUnit dataUnit) { + public String getSpeciesCode(ConnectedRegionDataUnit dataUnit) { return defaultName; }