From 5c969d888975a4f2f79c9011f25ef6bfd5352c01 Mon Sep 17 00:00:00 2001 From: Douglas Gillespie <50671166+douggillespie@users.noreply.github.com> Date: Wed, 19 Jul 2023 13:56:39 +0100 Subject: [PATCH] work on species mapping --- src/PamguardMVC/PamDataBlock.java | 7 +- .../ClickBlockSpeciesManager.java | 35 +++++++ src/clickDetector/ClickDataBlock.java | 12 +++ .../species/DataBlockSpeciesManager.java | 58 +++++++++++ src/tethys/species/DataBlockSpeciesMap.java | 37 ++++++++ src/tethys/species/DataBlockSpeciesTypes.java | 43 +++++++++ src/tethys/species/DatablockSpeciesMap.java | 12 --- src/tethys/species/SpeciesMapItem.java | 83 ++++++++++++++++ src/tethys/species/SpeciesTest.java | 2 +- src/tethys/species/SpeciesTypes.java | 20 ---- .../species/swing/DataBlockSpeciesDialog.java | 47 +++++++++ .../species/swing/DataBlockSpeciesPanel.java | 65 +++++++++++++ src/tethys/species/swing/SpeciesSubPanel.java | 95 +++++++++++++++++++ src/tethys/swing/DatablockSynchPanel.java | 53 ++++++++++- 14 files changed, 530 insertions(+), 39 deletions(-) create mode 100644 src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java create mode 100644 src/tethys/species/DataBlockSpeciesManager.java create mode 100644 src/tethys/species/DataBlockSpeciesMap.java create mode 100644 src/tethys/species/DataBlockSpeciesTypes.java delete mode 100644 src/tethys/species/DatablockSpeciesMap.java delete mode 100644 src/tethys/species/SpeciesTypes.java create mode 100644 src/tethys/species/swing/DataBlockSpeciesDialog.java create mode 100644 src/tethys/species/swing/DataBlockSpeciesPanel.java create mode 100644 src/tethys/species/swing/SpeciesSubPanel.java diff --git a/src/PamguardMVC/PamDataBlock.java b/src/PamguardMVC/PamDataBlock.java index d22a8543..c3a3ba7b 100644 --- a/src/PamguardMVC/PamDataBlock.java +++ b/src/PamguardMVC/PamDataBlock.java @@ -52,6 +52,7 @@ import Acquisition.AcquisitionProcess; import pamScrollSystem.ViewLoadObserver; import tethys.pamdata.AutoTethysProvider; import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; import dataGram.DatagramProvider; import dataMap.BespokeDataMapGraphic; import dataMap.OfflineDataMap; @@ -3103,13 +3104,13 @@ public class PamDataBlock extends PamObservable { this.tethysDataProvider = tethysDataProvider; } - /** * Get information about species types that may occur within this data - * block. + * block. Primarily for conversion into Tethys compatible data, but may + * prove to have other uses. * @return Types of species information available within this datablock. */ - public tethys.species.SpeciesTypes getSpeciesTypes() { + public DataBlockSpeciesManager getDatablockSpeciesManager() { return null; } diff --git a/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java new file mode 100644 index 00000000..971fe139 --- /dev/null +++ b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java @@ -0,0 +1,35 @@ +package clickDetector.ClickClassifiers; + +import clickDetector.ClickControl; +import clickDetector.ClickDataBlock; +import clickDetector.ClickDetection; +import tethys.species.DataBlockSpeciesManager; +import tethys.species.DataBlockSpeciesTypes; + +public class ClickBlockSpeciesManager extends DataBlockSpeciesManager { + + private ClickControl clickControl; + + public ClickBlockSpeciesManager(ClickControl clickControl, ClickDataBlock clickDataBlock) { + super(clickDataBlock); + this.clickControl = clickControl; + } + + @Override + public DataBlockSpeciesTypes getSpeciesTypes() { + ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager(); + if (masterManager == null) { + return null; + } + String[] speciesList = masterManager.getSpeciesList(); + + return new DataBlockSpeciesTypes(speciesList); + } + + @Override + public String getSpeciesString(ClickDetection dataUnit) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/clickDetector/ClickDataBlock.java b/src/clickDetector/ClickDataBlock.java index 3e650b85..e00c42ce 100644 --- a/src/clickDetector/ClickDataBlock.java +++ b/src/clickDetector/ClickDataBlock.java @@ -3,6 +3,7 @@ package clickDetector; import java.util.ListIterator; import pamScrollSystem.ViewLoadObserver; +import tethys.species.DataBlockSpeciesManager; //import staticLocaliser.StaticLocaliserControl; //import staticLocaliser.StaticLocaliserProvider; //import staticLocaliser.panels.AbstractLocaliserControl; @@ -10,6 +11,7 @@ import pamScrollSystem.ViewLoadObserver; import alarm.AlarmCounterProvider; import alarm.AlarmDataSource; import binaryFileStorage.BinaryStore; +import clickDetector.ClickClassifiers.ClickBlockSpeciesManager; import clickDetector.dataSelector.ClickDataSelectCreator; import clickDetector.offlineFuncs.OfflineClickLogging; import clickDetector.toad.ClickTOADCalculator; @@ -41,6 +43,8 @@ public class ClickDataBlock extends AcousticDataBlock implement private boolean isViewer; + private ClickBlockSpeciesManager clickBlockSpeciesManager; + public ClickDataBlock(ClickControl clickControl, PamProcess parentProcess, int channelMap) { @@ -304,5 +308,13 @@ public class ClickDataBlock extends AcousticDataBlock implement } } + @Override + public DataBlockSpeciesManager getDatablockSpeciesManager() { + if (clickBlockSpeciesManager == null) { + clickBlockSpeciesManager = new ClickBlockSpeciesManager(clickControl, this); + } + return clickBlockSpeciesManager; + } + } diff --git a/src/tethys/species/DataBlockSpeciesManager.java b/src/tethys/species/DataBlockSpeciesManager.java new file mode 100644 index 00000000..b44a23f1 --- /dev/null +++ b/src/tethys/species/DataBlockSpeciesManager.java @@ -0,0 +1,58 @@ +package tethys.species; + +import PamController.PamController; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import tethys.species.swing.DataBlockSpeciesDialog; + +/** + * Manage species conversion for a single datablock. + * @author dg50 + * + */ +abstract public class DataBlockSpeciesManager { + + private DataBlockSpeciesMap datablockSpeciesMap; + + private PamDataBlock dataBlock; + + public abstract DataBlockSpeciesTypes getSpeciesTypes(); + + public abstract String getSpeciesString(T dataUnit); + + public DataBlockSpeciesManager(PamDataBlock dataBlock) { + super(); + this.dataBlock = dataBlock; + } + + public SpeciesMapItem getSpeciesItem(T dataUnit) { + String speciesString = getSpeciesString(dataUnit); + if (speciesString == null) { + return null; + } + DataBlockSpeciesMap speciesMap = getDatablockSpeciesMap(); + if (speciesMap == null) { + return null; + } + return speciesMap.getItem(speciesString); + } + + public DataBlockSpeciesMap getDatablockSpeciesMap() { + return datablockSpeciesMap; + } + + public void setDatablockSpeciesMap(DataBlockSpeciesMap datablockSpeciesMap) { + this.datablockSpeciesMap = datablockSpeciesMap; + } + + public void showSpeciesDialog() { + DataBlockSpeciesDialog.showDialog(PamController.getMainFrame(), dataBlock); + } + + /** + * @return the dataBlock + */ + public PamDataBlock getDataBlock() { + return dataBlock; + } +} diff --git a/src/tethys/species/DataBlockSpeciesMap.java b/src/tethys/species/DataBlockSpeciesMap.java new file mode 100644 index 00000000..3827d20a --- /dev/null +++ b/src/tethys/species/DataBlockSpeciesMap.java @@ -0,0 +1,37 @@ +package tethys.species; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * Species map for a specified data block + * @author dg50 + * + */ +public class DataBlockSpeciesMap implements Serializable { + + public static final long serialVersionUID = 1L; + + private HashMap speciesTable = new HashMap<>(); + + protected HashMap getSpeciesTable() { + return speciesTable; + } + + protected void setSpeciesTable(HashMap speciesTable) { + this.speciesTable = speciesTable; + } + + public void putItem(String key, SpeciesMapItem speciesMapItem) { + speciesTable.put(key, speciesMapItem); + } + + public SpeciesMapItem getItem(String key) { + return speciesTable.get(key); + } + + public void removeItem(String key) { + speciesTable.remove(key); + } + +} diff --git a/src/tethys/species/DataBlockSpeciesTypes.java b/src/tethys/species/DataBlockSpeciesTypes.java new file mode 100644 index 00000000..6b9a4496 --- /dev/null +++ b/src/tethys/species/DataBlockSpeciesTypes.java @@ -0,0 +1,43 @@ +package tethys.species; + +import java.util.ArrayList; + +/** + * Class to return lists of species codes or names for a datablock. + * This information will then get incorporated into a more complicated translation table to + * provide PAMGuard data on it's way to Tethys with more rigid species code definitions. + * @author dg50 + * + */ +public class DataBlockSpeciesTypes { + + /** + * List of species names / codes associated with this data block. + */ + private ArrayList speciesNames; + + /** + * constructor to use with a array of String names. + * @param speciesList + */ + public DataBlockSpeciesTypes(String[] speciesList) { + if (speciesList == null) { + speciesNames = new ArrayList<>(); + } + else { + speciesNames = new ArrayList(speciesList.length); + for (int i = 0; i < speciesList.length; i++) { + speciesNames.add(speciesList[i]); + } + } + } + + /** + * @return the speciesNames + */ + public ArrayList getSpeciesNames() { + return speciesNames; + } + + +} diff --git a/src/tethys/species/DatablockSpeciesMap.java b/src/tethys/species/DatablockSpeciesMap.java deleted file mode 100644 index 07239ab5..00000000 --- a/src/tethys/species/DatablockSpeciesMap.java +++ /dev/null @@ -1,12 +0,0 @@ -package tethys.species; - -import java.io.Serializable; - -/** - * Species map for a specified data block - * @author dg50 - * - */ -public class DatablockSpeciesMap implements Serializable { - -} diff --git a/src/tethys/species/SpeciesMapItem.java b/src/tethys/species/SpeciesMapItem.java index d586ddd1..f1595a7a 100644 --- a/src/tethys/species/SpeciesMapItem.java +++ b/src/tethys/species/SpeciesMapItem.java @@ -2,18 +2,101 @@ package tethys.species; import java.io.Serializable; +/** + * Information linking a name within a PAMGuard datablock to a ITIS species code and call type. + * Also contains common and latin names for display purposes, though these are not essential. + * @author dg50 + * + */ public class SpeciesMapItem implements Serializable, Cloneable { public static final long serialVersionUID = 1L; + /** + * ITIS code. May be a real ITIS code or one of the -ve species that we're defining ourselves. + */ private int itisCode; + /** + * Species code that was used within PAMGuard. Redundant information, but useful + * for bookkeeping. + */ private String pamguardName; + /** + * Latin name extracted from ITIS database. Can be null if unknown. + * Probably not written to Tethys. + */ private String latinName; + /** + * Common species name from ITIS database. Can be null if unknown. + * Probably not written to Tethys. + */ private String commonName; + /** + * Type of call. Descriptive name for type of sound, e.g. 'click', 'whistle', 'D-call', + * etc. to complement the itis species code. Will be written to Tethys. + */ private String callType; + + public SpeciesMapItem(int itisCode, String callType, String pamguardName, String latinName, String commonName) { + super(); + this.itisCode = itisCode; + this.callType = callType; + this.pamguardName = pamguardName; + this.latinName = latinName; + this.commonName = commonName; + } + + public SpeciesMapItem(int itisCode, String callType, String pamguardName) { + super(); + this.itisCode = itisCode; + this.callType = callType; + this.pamguardName = pamguardName; + this.latinName = null; + this.commonName = null; + } + + /** + * ITIS code. May be a real ITIS code or one of the -ve species that we're defining ourselves. + * @return the itisCode + */ + public int getItisCode() { + return itisCode; + } + + /** + * Species code that was used within PAMGuard. Redundant information, but useful + * @return the pamguardName + */ + public String getPamguardName() { + return pamguardName; + } + + /** + * Latin name extracted from ITIS database. Can be null if unknown. + * @return the latinName + */ + public String getLatinName() { + return latinName; + } + + /** + * Common species name from ITIS database. Can be null if unknown. + * @return the commonName + */ + public String getCommonName() { + return commonName; + } + + /** + * Type of call. Descriptive name for type of sound, e.g. 'click', 'whistle', 'D-call', + * @return the callType + */ + public String getCallType() { + return callType; + } } diff --git a/src/tethys/species/SpeciesTest.java b/src/tethys/species/SpeciesTest.java index 804abb6c..affdff22 100644 --- a/src/tethys/species/SpeciesTest.java +++ b/src/tethys/species/SpeciesTest.java @@ -5,7 +5,7 @@ import dbxml.Queries; import tethys.dbxml.DBQueryResult; import tethys.dbxml.TethysQueryException; -public class SpeciesTest extends SpeciesTypes { +public class SpeciesTest { String uri = "http://localhost:9779"; public static void main(String[] args) { diff --git a/src/tethys/species/SpeciesTypes.java b/src/tethys/species/SpeciesTypes.java deleted file mode 100644 index 84ca0152..00000000 --- a/src/tethys/species/SpeciesTypes.java +++ /dev/null @@ -1,20 +0,0 @@ -package tethys.species; - -import java.util.ArrayList; - -/** - * Class to return lists of species codes or names for a datablock. - * This information will then get incorporated into a more complicated translation table to - * provide PAMGuard data on it's way to Tethys with more rigid species code definitions. - * @author dg50 - * - */ -public class SpeciesTypes { - - - /** - * List of species names / codes associated with this data block. - */ - private ArrayList speciesNames; - -} diff --git a/src/tethys/species/swing/DataBlockSpeciesDialog.java b/src/tethys/species/swing/DataBlockSpeciesDialog.java new file mode 100644 index 00000000..ff29cb16 --- /dev/null +++ b/src/tethys/species/swing/DataBlockSpeciesDialog.java @@ -0,0 +1,47 @@ +package tethys.species.swing; + +import java.awt.Window; + +import PamView.dialog.PamDialog; +import PamguardMVC.PamDataBlock; + +public class DataBlockSpeciesDialog extends PamDialog { + + private static final long serialVersionUID = 1L; + + DataBlockSpeciesPanel speciesPanel; + + private DataBlockSpeciesDialog(Window parentFrame, PamDataBlock dataBlock) { + super(parentFrame, dataBlock.getDataName() + " species", false); + speciesPanel = new DataBlockSpeciesPanel(dataBlock); + setDialogComponent(speciesPanel.getDialogComponent()); + } + + public static void showDialog(Window parentFrame, PamDataBlock dataBlock) { + DataBlockSpeciesDialog speciesDialog = new DataBlockSpeciesDialog(parentFrame, dataBlock); + speciesDialog.setParams(); + speciesDialog.setVisible(true); + } + + private void setParams() { + speciesPanel.setParams(); + } + + @Override + public boolean getParams() { + return speciesPanel.getParams(); + } + + @Override + public void cancelButtonPressed() { + // TODO Auto-generated method stub + + } + + @Override + public void restoreDefaultSettings() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/tethys/species/swing/DataBlockSpeciesPanel.java b/src/tethys/species/swing/DataBlockSpeciesPanel.java new file mode 100644 index 00000000..b90b12bc --- /dev/null +++ b/src/tethys/species/swing/DataBlockSpeciesPanel.java @@ -0,0 +1,65 @@ +package tethys.species.swing; + +import java.awt.BorderLayout; +import java.util.ArrayList; + +import javax.swing.BoxLayout; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; + +import PamView.dialog.PamDialogPanel; +import PamguardMVC.PamDataBlock; +import tethys.species.DataBlockSpeciesManager; +import tethys.species.DataBlockSpeciesMap; +import tethys.species.DataBlockSpeciesTypes; +import tethys.species.SpeciesMapItem; + +public class DataBlockSpeciesPanel implements PamDialogPanel { + + private JPanel mainPanel; + + private PamDataBlock dataBlock; + + private JPanel speciesPanel; + + public DataBlockSpeciesPanel(PamDataBlock dataBlock) { + super(); + this.dataBlock = dataBlock; + mainPanel = new JPanel(new BorderLayout()); + speciesPanel = new JPanel(); + mainPanel.add(speciesPanel, BorderLayout.CENTER); + mainPanel.setBorder(new TitledBorder(dataBlock.getDataName())); + } + + @Override + public JComponent getDialogComponent() { + return mainPanel; + } + + @Override + public void setParams() { + speciesPanel.removeAll(); + speciesPanel.setLayout(new BoxLayout(speciesPanel, BoxLayout.Y_AXIS)); + + DataBlockSpeciesManager speciesManager = dataBlock.getDatablockSpeciesManager(); + DataBlockSpeciesTypes speciesTypes = speciesManager.getSpeciesTypes(); + ArrayList speciesNames = speciesTypes.getSpeciesNames(); + DataBlockSpeciesMap speciesMap = speciesManager.getDatablockSpeciesMap(); + for (String aSpecies : speciesNames) { + SpeciesSubPanel subPanel = new SpeciesSubPanel(aSpecies); + speciesPanel.add(subPanel.getDialogComponent()); + if (speciesMap != null) { + SpeciesMapItem speciesInfo = speciesMap.getItem(aSpecies); + subPanel.setParams(speciesInfo); + } + } + } + + @Override + public boolean getParams() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/src/tethys/species/swing/SpeciesSubPanel.java b/src/tethys/species/swing/SpeciesSubPanel.java new file mode 100644 index 00000000..ab9ea2c3 --- /dev/null +++ b/src/tethys/species/swing/SpeciesSubPanel.java @@ -0,0 +1,95 @@ +package tethys.species.swing; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.BevelBorder; + +import PamView.dialog.PamGridBagContraints; +import tethys.species.SpeciesMapItem; + +public class SpeciesSubPanel { + + private JPanel mainPanel; + + private JLabel pamguardName; + private JTextField itisCode, callType, latinName, commonName; + private JButton searchButton; + + public SpeciesSubPanel(String aSpecies) { + mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(new BevelBorder(BevelBorder.RAISED)); + GridBagConstraints c = new PamGridBagContraints(); + mainPanel.add(new JLabel("Name ", JLabel.RIGHT), c); + c.gridx++; + mainPanel.add(pamguardName = new JLabel(aSpecies), c); + c.gridx++; + mainPanel.add(new JLabel(" ITIS code ", JLabel.RIGHT), c); + c.gridx++; + mainPanel.add(itisCode = new JTextField(3), c); + c.gridx ++; + mainPanel.add(searchButton = new JButton("Find")); + + int w1 = 2; + int w2 = 3; + c.gridx = 0; + c.gridy++; + c.gridwidth = w1; + mainPanel.add(new JLabel("Call / sound type ", JLabel.RIGHT), c); + c.gridx+= c.gridwidth; + c.gridwidth = w2; + mainPanel.add(callType = new JTextField(15), c); + c.gridx = 0; + c.gridy++; + c.gridwidth = w1; + mainPanel.add(new JLabel("Scientific name ", JLabel.RIGHT), c); + c.gridx+= c.gridwidth; + c.gridwidth = w2; + mainPanel.add(latinName = new JTextField(15), c); + c.gridx = 0; + c.gridy++; + c.gridwidth = w1; + mainPanel.add(new JLabel("Common name ", JLabel.RIGHT), c); + c.gridx+= c.gridwidth; + c.gridwidth = w2; + mainPanel.add(commonName = new JTextField(15), c); + + pamguardName.setToolTipText("Internal name within PAMGuard module"); + itisCode.setToolTipText("ITIS species code"); + searchButton.setToolTipText("Search for species code"); + callType.setToolTipText("Descriptive name for call type or measurement"); + latinName.setToolTipText("Scientific name"); + commonName.setToolTipText("Common name"); + + } + + public JComponent getDialogComponent() { + return mainPanel; + } + + public void setParams(SpeciesMapItem speciesMapItem) { + if (speciesMapItem == null) { + itisCode.setText(null); + callType.setText(null); + latinName.setText(null); + commonName.setText(null); + return; + } + pamguardName.setText(speciesMapItem.getPamguardName()); + itisCode.setText(String.format("%d", speciesMapItem.getItisCode())); + callType.setText(speciesMapItem.getCallType()); + latinName.setText(speciesMapItem.getLatinName()); + commonName.setText(speciesMapItem.getCommonName()); + } + + public SpeciesMapItem getParams() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/tethys/swing/DatablockSynchPanel.java b/src/tethys/swing/DatablockSynchPanel.java index 8da66a90..212eadf2 100644 --- a/src/tethys/swing/DatablockSynchPanel.java +++ b/src/tethys/swing/DatablockSynchPanel.java @@ -1,6 +1,8 @@ package tethys.swing; import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.KeyAdapter; @@ -10,7 +12,9 @@ import java.awt.event.MouseEvent; import java.util.ArrayList; import javax.swing.JComponent; +import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.border.TitledBorder; @@ -25,6 +29,7 @@ import dataMap.OfflineDataMap; import tethys.TethysControl; import tethys.TethysState; import tethys.output.DatablockSynchInfo; +import tethys.species.DataBlockSpeciesManager; public class DatablockSynchPanel extends TethysGUIPanel { @@ -68,21 +73,63 @@ public class DatablockSynchPanel extends TethysGUIPanel { private class MouseActions extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { - selectRow(); + int row = selectRow(); + if (e.isPopupTrigger() && row >= 0) { + showPopup(e, row); + } + } + + @Override + public void mousePressed(MouseEvent e) { + int row = selectRow(); + if (e.isPopupTrigger() && row >= 0) { + showPopup(e, row); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + int row = selectRow(); + if (e.isPopupTrigger() && row >= 0) { + showPopup(e, row); + } } } - private void selectRow() { + private int selectRow() { int row = synchTable.getSelectedRow(); if (row < 0) { - return; + return row; } DatablockSynchInfo synchInfo = dataBlockSynchInfo.get(row); // datablockDetectionsPanel.setDataBlock(synchInfo.getDataBlock()); notifyObservers(synchInfo.getDataBlock()); + return row; } + public void showPopup(MouseEvent e, int row) { + DatablockSynchInfo synchInfo = dataBlockSynchInfo.get(row); + if (synchInfo == null) { + return; + } + PamDataBlock dataBlock = synchInfo.getDataBlock(); + DataBlockSpeciesManager speciesManager = dataBlock.getDatablockSpeciesManager(); + if (speciesManager == null) { + return; + } + JPopupMenu popMenu = new JPopupMenu(); + JMenuItem menuItem = new JMenuItem("Species info ..."); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + speciesManager.showSpeciesDialog(); + } + }); + popMenu.add(menuItem); + popMenu.show(e.getComponent(), e.getX(), e.getY()); + } + @Override public void updateState(TethysState tethysState) { synchTableModel.fireTableDataChanged();