diff --git a/.project b/.project index 9ee4af40..48129c11 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - PamGuard Main DG + PamGuard Main Tethys diff --git a/README.html b/README.html index f39f4964..d4faac7a 100644 --- a/README.html +++ b/README.html @@ -324,9 +324,8 @@ href="http://www.gnu.org/licenses/gpl-3.0-standalone.html">http://www.gnu.org/li

INSTALLATION

The latest version of PAMGuard has been tested on 64 bit -Windows 10. We expect it to work without problems on 64 bit versions of Windows -8 and probably 7. Some testing has been undertaken on Windows 11 and nothing -unexpected has been noted.

+Windows 10 and Windows 11. We expect it to work without problems on 64 bit +versions of Windows 8 and probably 7.

On Windows, download and run the Windows installer.

@@ -372,23 +371,27 @@ size for the JVM being used to run Pamguard i.e. how much memory it gets to use. The default max size usually being too low.

The -Djava.library.path=lib64 tells the JVM that it should -look in the folder called "lib64" for the required shared libraries (change -to lib for the -32 bit version).

+look in the folder called "lib64" for the required shared libraries +(change to lib +for the 32 bit version).

For "Mixed" and "Viewer" modes just add a "-m" or "-v" to the list of java arguments. On Windows just run the appropriately named executable (e.g. PamguardBeta_MixedMode.exe or PamguardBeta_ViewerMode.exe):

-

java -Xms384m --Xmx4096m -Djava.library.path=lib64 -jar PamguardBeta_xxxxxx.jar -v

+

java +-Xms384m -Xmx4096m -Djava.library.path=lib64 -jar PamguardBeta_xxxxxx.jar -v

 

-

Latest Version 2.02.09 June 2023

+

Latest Version 2.02.10 January 2024

+ +

Version 2.02.09 June 2023

Version 2.02.08 May 2023

@@ -457,8 +460,86 @@ Version 2.00.10 June 2017

Version 2.02.09 June 2023

+name="_Latest_Version_2.02.08">Version 2.02.10 January 2024 + +

New Features

+ +

Importing modules from other configurations: New options from file menu allowing +import of specific modules, or module settings from other configurations. E.g. +if you had three similar configurations and had set one of them up with a new +detector, or got the click classifier settings set up just right in one of +those configurations, you can import the additional modules or the click +detector settings easily into the other configurations.

+ +

Improved SUD (soundtrap compressed +files) file performance when scrolling through +audio data in Viewer mode.

+ +

Viewer Launch by right clicking on sqlite database and selecting “open with / +Pamguard ViewerMode” launcher menu option.

+ +

Bug Fixes

+ +

Logger Forms

+ +

Boolean (logical true/false, yes/no) data +were not showing correctly in Viewer mode. Now fixed

+ +

Data selectors for plotting on map were not +working, also fixed

+ +

Bearing localizer running offline was not +correctly saving updated bearings to the database. Now fixed.

+ +

ROCCA Classifier fixes

+ +

Allow Rocca to run without classifiers: +Fixed bug that threw an error if no classifier files were  specified in +Rocca Params dialog

+ +

Fix memory issue with +RoccaContourDataBlocks not being released for garbage collection

+ +

Set RoccaContourDataBlock objects to null +and stop PamObserver Timer to

+ +

force release

+ +

Fix problem tracing whistles in Rocca +spectrogram pop-up: Whistle and raw data were being cleared before the user had +time to trace out the whistle, causing PAMGuard to throw an exception.  +Both were already being cleared when the pop-up window is closed, so no need to +do it here.

+ +

DIFAR Module: +Bug crashing the module with null pointer errors fixed.

+ +

Whistle Detector: Fixed bug which caused the detector to slow to almost zero speed +when large complex sounds with many branches were detected.

+ +

Click Detector Offline Event Marking: Fixed problem of events not being correctly deleted and also of +clicks not being correctly reassigned to different events.

+ +

Screen Position: When using multiple monitors, if you move a configuration to a +computer with a different monitor layout, the GUI should work out if it’s +opening on a screen area which no longer exists and move itself onto the +primary monitor.

+ +

File Folder Processing: Previous version had a bug which caused files to not always be +sorted into the correct order for processing. This caused some instability in +some detectors, causing memory leaks when new data arrived with time stamps +earlier than already processed data in memory. This is now fixed – files are ow +correctly sorted alphabetically by file name, i.e. not including the +name of the folder containing the files.

+ +

Version 2.02.09 June 2023

Bug Fixes

@@ -484,8 +565,8 @@ bearings, the localizer was not correctly loading required raw or FFT data to input to the cross correlation algorithm. This is now fixed so that you can reprocess bearings in viewer mode.

-

Map files: Added additional exception handlers -to handle corrupt map files.

+

Map files: Added additional exception +handlers to handle corrupt map files.

New Features

@@ -508,16 +589,16 @@ the first two characters of the string name may be.

Bug Fixes

-

Use of localization sensor and orientation data -for static hydrophones had a bug whereby it would continually ‘forget’ angle -offsets applied to static hydrophones in viewer mode. This is now fixed.

+

Use of localization sensor and orientation +data for static hydrophones had a bug whereby it would continually ‘forget’ +angle offsets applied to static hydrophones in viewer mode. This is now fixed.

Click tool bar: Correctly shows event selection options even if no species classification options are in place.

-

Fixed Landmarks: Earlier versions were -‘losing’ these every time PAMGuard started or new data were loaded in viewer -mode. Now fixed.

+

Fixed Landmarks: Earlier versions were ‘losing’ +these every time PAMGuard started or new data were loaded in viewer mode. Now +fixed.

ROCCA: Fixed (another) memory leak which caused PAMGuard to crash when processing large data sets with the ROCCA @@ -563,10 +644,10 @@ whistle classification module.

SoundTrap SUD file reading. If you’re using SoundTrap autonomous recorders from Ocean Instruments, you no longer need to decompress the SoundTrap files prior to processing. This will save time and a -lot of disk space. Extraction of clicks from the inbuilt SoundTrap Click detector -can also happen while processing SUD file data with other detectors, thereby -streamlining the whole processing chain. Read the online Help for details. -  

+lot of disk space. Extraction of clicks from the inbuilt SoundTrap Click +detector can also happen while processing SUD file data with other detectors, +thereby streamlining the whole processing chain. Read the online Help for +details.   

Version 2.02.05 October 2022

@@ -624,7 +705,7 @@ audio files.

Bug Fixes

Soundtrap DWV import. Will now generate -binary files even if DWV file doesnÂ’t exist (which is correct behavior in +binary files even if DWV file doesn‚’t exist (which is correct behavior in quiet conditions when no clicks were detected).

Spectrogram. Changes to stop occasional @@ -659,8 +740,8 @@ running in real time. Added template names based on file names.

#13 Merging files when offline processing file folders: Had an error introduced in last release which caused it to fail to recognise gaps between files, meaning that some output data (i.e. after a gap) would have an -incorrect time stamp. This did not affect data if the ‘merge contiguous -files’ option was not selected.

+incorrect time stamp. This did not affect data if the ‘merge contiguous files’ +option was not selected.

#14 Logger forms data were not plotting correctly. This was due to the required data selection functions not being fully implemented. This @@ -669,9 +750,9 @@ selections from drop down lists within any form.

 

-

Note that updates have also been made to the Matlab interface -to PAMGuard binary files, which has now also been migrated to GitHub at https://github.com/PAMGuard/PAMGuardMatlab. +

Note that updates have also been made to the Matlab +interface to PAMGuard binary files, which has now also been migrated to GitHub +at https://github.com/PAMGuard/PAMGuardMatlab.

 

@@ -686,9 +767,8 @@ the TF FX display to crash if no data were displayed.

See major release notes for V 2.02.01 below.

-

Bug 495: TD FX display throws -NullPointerException if user has removed all data units and then moves mouse -over display area.

+

Bug 495: TD FX display throws NullPointerException +if user has removed all data units and then moves mouse over display area.

Version 2.02.01 October 2021

@@ -711,11 +791,11 @@ font-family:"Times New Roman",serif'> 

File Format Change

-

Changes have been made to the binary file format to support -the output of additional noise outputs for certain detectors (See below). -Binary files created with this version will not be compatible with earlier -versions 2.01.### and below. This version will read and may convert earlier -format binary files.

+

Changes have been made to the binary file format to support the +output of additional noise outputs for certain detectors (See below). Binary +files created with this version will not be compatible with earlier versions +2.01.### and below. This version will read and may convert earlier format +binary files.

 

@@ -733,10 +813,10 @@ href="http://www.pamguard.org/downloads.php?cat_id=3">here.

Detection Group Localiser

-

This module has been renamed “Detection Grouper”, so -as to avoid confusion with the Group 3D localizer. This is because the -Detection Grouper is more for organizing data into groups to be localized than -it is for doing localization.

+

This module has been renamed “Detection Grouper”, so as to +avoid confusion with the Group 3D localizer. This is because the Detection +Grouper is more for organizing data into groups to be localized than it is for +doing localization.

Minor Bug Fixes

@@ -791,9 +871,9 @@ lang=EN-US> Allow Clip Generator to create both a binary record and a wav file

5.        -Implemented a Backup Manager for backing up multiple types of data to multiple -locations]

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Implemented a Backup Manager for backing up multiple types +of data to multiple locations]

6.        Extend the Hyperbolic Localiser to handle 2D planar arrays (previously limited to 3D volumetric arrays)

14.        -new CPOD features

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       new CPOD features

15.        Better interpolation of data by the Decimator when decimating/upsampling by a non-integer amount

16.        -Noise Level Outputs - as an aid to performance diagnosis, some detectors -(currently the GPL, Click Detector and Whistle and Moan Detector) are -outputting additional noise metrics to their binary output files. These can be -read with the PAMGuard -Matlab library and used to diagnose system performance in varying noise conditions. -Improved displays within PAMGuard for these noise metrics will be included in a -future release.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Noise Level Outputs - as an aid to performance diagnosis, +some detectors (currently the GPL, Click Detector and Whistle and Moan +Detector) are outputting additional noise metrics to their binary output files. +These can be read with the PAMGuard Matlab +library and used to diagnose system performance in varying noise +conditions. Improved displays within PAMGuard for these noise metrics will be +included in a future release.

17.        An implementation of the Generalized Power Law Detector, -developed by Tyler Helble ([Helble et al., ‘A generalized power-law detection -algorithm for humpback whale vocalizationsĂ‚Â’, The Journal of the Acoustical -Society of America, vol. 131, no. 4, pp. 2682–2699, 2012) is now available. -For details, see the online help

+developed by Tyler Helble ([Helble et al., ‘A generalized power-law detection +algorithm for humpback whale vocalizations’, The Journal of the Acoustical +Society of America, vol. 131, no. 4, pp. 2682–2699, 2012) is now available. For +details, see the online help

18.        -A Deep Learning module for sound classification is now available. This allows -users to deploy a large variety of deep learning models natively in PAMGuard. -For details, see the        A Deep Learning module for sound classification is now +available. This allows users to deploy a large variety of deep learning models +natively in PAMGuard. For details, see the online help.

@@ -1123,8 +1204,8 @@ lang=EN-US> Add option to alarm module to attach screenshots of all frames to email alerts.

7.        -Add Beamformer and Bearing Localiser modules

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Add Beamformer and Bearing Localiser modules

8.        &nb lang=EN-US> Bug 437. Right whale detector crashing if no input was set.

6.        -Bug 438. Text not showing in tabs in Night colour mode.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Bug 438. Text not showing in tabs in Night colour mode.

7.        &nb Bug 440. Measurement Computing Cards not enumerating properly.

9.        -Bug 441. Plot coordinate calculations incorrect in PamAxis.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Bug 441. Plot coordinate calculations incorrect in PamAxis.

10.        Bug 443. NI playback crashing immediately if a device is not present.

12.        -Bug 444. Bug in data selector which caused it to mess up history of recent psf -files.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Bug 444. Bug in data selector which caused it to mess up +history of recent psf files.

13.       

15.        -Bug 447. Viewer mode throws exception when trying to load beamformer -localisations

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Bug 447. Viewer mode throws exception when trying to load +beamformer localisations

16.        Bug 431. Error when trying to mark section of spectrogram to send to Bearing Calculator module

6.        -Bug 432. MySQL database interface - connection problems

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Bug 432. MySQL database interface - connection problems

Upgrades

@@ -1479,8 +1560,8 @@ Upgrades to the Group Localiser, including better error estimation.

2.        Click Train Detector upgrades, including ability to import time -chunks from csv file for batch processing.

+lang=EN-US> Click Train Detector upgrades, including ability to import +time chunks from csv file for batch processing.

3.        &nb New Analog Array Sensors module, to read data from 3-axis accelerometers.

6.        -Send Email option added to Alarm module.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Send Email option added to Alarm module.

7.       

1.        -Bug 338. Problem displaying coastlines and bathymetric contours around -the dateline (+/- 180 longitude) in the map.

+Bug 338. Problem displaying coastlines and bathymetric contours around the +dateline (+/- 180 longitude) in the map.

2.        @@ -1864,17 +1945,17 @@ interface when importing Soundtrap data. Also changed the default date/time format to ISO8601 standard.

2.        -A number of upgrades and fixes to the Localiser algorithms, including expanding -to work with whistles.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       A number of upgrades and fixes to the Localiser algorithms, +including expanding to work with whistles.

3.        -Added option to export all settings and parameters as an XML-formatted file. Note -that this required changes to the structure of the Array Manager, and as such -any settings (psf) files created with this version of Pamguard cannot be used -in older versions. Older psf files can be loaded with this version, but will be -converted.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       Added option to export all settings and parameters as an +XML-formatted file. Note that this required changes to the structure of the +Array Manager, and as such any settings (psf) files created with this version +of Pamguard cannot be used in older versions. Older psf files can be loaded +with this version, but will be converted.

4.       

Upgrades

1.        -During conversion from Core to Beta versions, if there are any problems -matching database units to binary store units the UID values will now be set to -negative numbers instead of leaving them null. The user is warned about this -and encouraged to manually fix the database.

+lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>       During conversion from Core to Beta versions, if there are +any problems matching database units to binary store units the UID values will +now be set to negative numbers instead of leaving them null. The user is warned +about this and encouraged to manually fix the database.

@@ -2126,26 +2207,26 @@ the PAMGuard Viewer the older data will be converted to the new format (see below for details).

The most significant change in the binary -file format is the addition of a Unique Data Identifier (UID) to each unit of data. -This is intended to aid in offline analysis by making it easier for the user to -link what they are seeing on different PAMGuard displays and also to link with -any data post processed in Matlab or other custom analysis software. UIDĂ‚Â’s -are also added to PAMGuard database tables.

+file format is the addition of a Unique Data Identifier (UID) to each unit of +data. This is intended to aid in offline analysis by making it easier for the +user to link what they are seeing on different PAMGuard displays and also to +link with any data post processed in Matlab or other custom analysis software. +UID’s are also added to PAMGuard database tables.

Converting Old Data

If old data are opened with the PAMGuard viewer they will automatically be converted. For safety, the original binary files will not be overwritten and the new data will be placed in a new folder -on your computer with the same path as the old data, but suffixed with -‘_WithUIDĂ‚Â’, e.g. if your binary data were previously stored in the folder +on your computer with the same path as the old data, but suffixed with ‘_WithUID’, +e.g. if your binary data were previously stored in the folder C:\MySurvey\binarydata the new data will be written to C:\MySurvey\binarydata_WithUID.

The additional UID column will be added to all database tables and populated with unique values. For data which are stored -in both the binary files and in database tables, the same UIDĂ‚Â’s will be used -in both data stores.

+in both the binary files and in database tables, the same UID’s will be used in +both data stores.

New Displays

@@ -2214,8 +2295,8 @@ Hawaii/Temperate Pacific/North Atlantic datasets. This has been corrected.

2.       -Bug 320. Pamguard stopped reading Click Detector Event data from -database when target motion analysis information was encountered. Corrected.

+Bug 320. Pamguard stopped reading Click Detector Event data from database +when target motion analysis information was encountered. Corrected.

3.       @@ -2236,8 +2317,8 @@ lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'> &nb

3.       -Rocca Module: added StartHr, ProportionWhists and ProportionClicks parameters -to Event classifier

+Rocca Module: added StartHr, ProportionWhists and ProportionClicks +parameters to Event classifier

4.       @@ -2379,19 +2460,19 @@ November 2016

1.       Bug 303. Some ASIO sound cards not working with either ASIO system in PAMGuard. For the PAMGuard ASIO system, this was due to a data format used by some sound -cards never being properly implemented. For the “New ASIO system” which -is based on jAsioHost, the unpacking of that format contained a bug which -returned incorrect numbers, so data were swamped with noise. Both systems are -now fixed. By preference, users should use the PAMGuard ASIO system since the -JAsioHost based system seems to drop samples when many channels are running at -high sample rate.

+cards never being properly implemented. For the “New ASIO system” which is +based on jAsioHost, the unpacking of that format contained a bug which returned +incorrect numbers, so data were swamped with noise. Both systems are now fixed. +By preference, users should use the PAMGuard ASIO system since the JAsioHost +based system seems to drop samples when many channels are running at high +sample rate.

2.       -Bug 305. Date and Time not being correctly extracted -from wav files created using SoundTrap recorders. Fixed by correctly finding -and unpacking information in the accompanying xml log files that come with -SoundTrap files.

+Bug 305. Date and Time not being correctly +extracted from wav files created using SoundTrap recorders. Fixed by correctly +finding and unpacking information in the accompanying xml log files that come +with SoundTrap files.

Version 1.15.06 November 2016

@@ -2671,8 +2752,8 @@ being imported into the new database. Problem 2 was that indexing of imported click events in the new database was incorrect. Both these issues have now been fixed.

-

Version 1.15.02 -March 2016

+

Version 1.15.02 March +2016

A number of small bug fixes following release of 1.15.00.

@@ -2749,8 +2830,8 @@ same click multiple times

1.       -Bug 253. Database import fails when Access database contains -queries. Fixed.

+Bug 253. Database import fails when Access database +contains queries. Fixed.

2.       @@ -2824,13 +2905,13 @@ for details.

3.       -GPS Loading into PAMGuard Viewer. This has been -modified so that the rules governing GPS data collection and storage also apply -when loading data from the database. For instance, if you've stored all GPS -data, you've probably got a record every second in the database which can -create memory overflows if you try to load a lot of data in the viewer. You can -now tell PAMGuard to only load a data point every n seconds which will reduce -the number of points loaded. Useful when making large scale overview maps of a +GPS Loading into PAMGuard Viewer. This has been modified +so that the rules governing GPS data collection and storage also apply when +loading data from the database. For instance, if you've stored all GPS data, +you've probably got a record every second in the database which can create +memory overflows if you try to load a lot of data in the viewer. You can now +tell PAMGuard to only load a data point every n seconds which will reduce the +number of points loaded. Useful when making large scale overview maps of a survey.

4.

Menu Layout

-

The PAMGuard menus have been rearranged into a more -intuitive grouping which we believe will help users find functionality more -easily.

+

The PAMGuard menus have been rearranged into a more intuitive +grouping which we believe will help users find functionality more easily.

'Detection' menu has been renamed to 'Settings' since many menu items within this menu were not directly to do with 'Detection'.

@@ -3197,8 +3277,8 @@ whistles as well.

This module, funded by NOAA for the South West Fisheries Science Centre (SWFSC), measures pitch and roll from analogue accelerometer sensors in a hydrophone. Data are fed real time into the updated hydrophone -array manager in order that bearings from a tetrahedral tracking array are correctly -calculated in real world coordinates.

+array manager in order that bearings from a tetrahedral tracking array are +correctly calculated in real world coordinates.

Wild ArcGIS Interface (Maps and Mapping group)

@@ -3208,12 +3288,12 @@ marine mammal survey package. See online help for details.

Alarms (Utilities Group)

-

This is a general system of visual and audio alarms developed -by Doug Gillespie for use on a variety of projects. The alarms can be coupled -to any module or detector in PAMGuard. Where appropriate, modules can control -which of their data will cause an alarm action (e.g. in the Click detector you -can set which types of classified click will fire the alarm). See online help -for details.  

+

This is a general system of visual and audio alarms +developed by Doug Gillespie for use on a variety of projects. The alarms can be +coupled to any module or detector in PAMGuard. Where appropriate, modules can +control which of their data will cause an alarm action (e.g. in the Click +detector you can set which types of classified click will fire the alarm). See +online help for details.  

Noise Band Monitor (Sound Processing Group)

@@ -3222,9 +3302,9 @@ of third octave noise bands. See online help for details.

Filtered Noise Measurement (Sound Processing Group)

-

This module, developed by Douglas Gillespie, measures noise -levels in a single frequency band using a variety of filter functions. See -online help for details.

+

This module, developed by Douglas Gillespie, measures noise levels +in a single frequency band using a variety of filter functions. See online help +for details.

Envelope Tracing (Beta Only, Sound Processing Group)

@@ -3260,11 +3340,10 @@ different. Details are available in the online help.

FLAC File Support

Can now read raw audio data direct from FLAC files. FLAC is a lossless compression -algorithm for audio data. Files, or folders of files are accessed in the same way -as WAV and AIFF files in the Sound Acquisition module. In a future release we -also hope to provide support for writing FLAC files from the sound recorder -module.

+href="http://en.wikipedia.org/wiki/FLAC">FLAC is a lossless compression algorithm +for audio data. Files, or folders of files are accessed in the same way as WAV +and AIFF files in the Sound Acquisition module. In a future release we also +hope to provide support for writing FLAC files from the sound recorder module.

Sound Recorder Module

@@ -3307,8 +3386,9 @@ shaped Finite Impulse Response filters (see online help for details).

Radar Display

-

Can now show bearings relative to true North OR the vessel heading. -Also has the option of only showing certain types of click and whistle.

+

Can now show bearings relative to true North OR the vessel +heading. Also has the option of only showing certain types of click and +whistle.

Bug Fixes

@@ -3387,8 +3467,8 @@ survey software package.

Core Functionality

-

New storage options have been implemented -which give the user greater control of where data are stored.

+

New storage options have been +implemented which give the user greater control of where data are stored.

Modules have been arranged into different groups in the configuration menus and tool tip texts have been added @@ -3475,8 +3555,8 @@ inter-detection interval.

margin-left:36.0pt'> 

Target Motion Analysis: Updated target motion analysis module -so that it works in three (as opposed to two) dimensions.

+margin-left:36.0pt'>Target Motion Analysis: Updated target motion analysis +module so that it works in three (as opposed to two) dimensions.

 

@@ -3619,8 +3699,8 @@ Symbol'>''         -Bearings can be calculated using the envelope of the waveform rather than -the full waveform. The waveform or envelope can also be filtered prior to +Bearings can be calculated using the envelope of the waveform rather +than the full waveform. The waveform or envelope can also be filtered prior to bearing calculation.

'         Whistle classifier has some new features in the classifier training -panel. It is also now possible to export training data files directly from binary -data files.

+panel. It is also now possible to export training data files directly from +binary data files.

'         @@ -3841,14 +3921,14 @@ modules which resulted in a number of bugs which could cause confusion as to which hydrophones were being used during localisation or during calibrated measurement. The situation tended to only arise with a small number of ASIO sound cards such as the RME Fireface 400 on which the most useful inputs, the -balanced line inputs, are hardware channels 4,5,6 and 7 on the back of the -instrument. (On the Fireface 800, the balanced line inputs are channels 0 to -7). When using the National Instruments system, data were always sent into the -rest of PAMGUARD with sequential channel numbering starting at 0. This was -required in order to support multiple NI Daq boards where it is possible to -read for example channel 0 and 1 on two different devices, so to uniquely -identify channels in the rest of PAMGUARD, the only rational thing to do was to -re-label those channels 0,1,2,3.

+balanced line inputs, are hardware channels 4,5,6 and 7 on the back of the instrument. +(On the Fireface 800, the balanced line inputs are channels 0 to 7). When using +the National Instruments system, data were always sent into the rest of +PAMGUARD with sequential channel numbering starting at 0. This was required in +order to support multiple NI Daq boards where it is possible to read for +example channel 0 and 1 on two different devices, so to uniquely identify +channels in the rest of PAMGUARD, the only rational thing to do was to re-label +those channels 0,1,2,3.

There have been other annoyances with the ASIO channel numbering scheme. For instance, if you had a configuration which worked in real @@ -3965,12 +4045,12 @@ port is closed. Might prevent a few problems when using a GPS.

Bug Fixes

Crashes caused in real time or Mixed Mode if the number of -software channels exceeds the number of hydrophones configured in the array manager. -It is of course illogical to have software channels which are not assigned to a -hydrophone, so rather than entirely prevent PAMGUARD from crashing I have -inserted additional checks into the hydrophone array dialog which will prevent -the user from closing that dialog unless all software channels are assigned to -a hydrophone.

+software channels exceeds the number of hydrophones configured in the array +manager. It is of course illogical to have software channels which are not +assigned to a hydrophone, so rather than entirely prevent PAMGUARD from +crashing I have inserted additional checks into the hydrophone array dialog +which will prevent the user from closing that dialog unless all software +channels are assigned to a hydrophone.

Version 1.8.01 Beta February 2010

@@ -4020,9 +4100,9 @@ Symbol'>''         -False buffer overflows at low sample rates stopped (size of data in individual -data blocks had been increased at low sample rates, but when this exceeded 3s a -false buffer overflow would occur).

+
False buffer overflows at low sample rates stopped (size of data in +individual data blocks had been increased at low sample rates, but when this +exceeded 3s a false buffer overflow would occur).

 

@@ -4036,8 +4116,8 @@ Symbol'>''         -This results in a major speed up of data exchange between modules and -can lead to a x4 improvement in overall performance.

+
This results in a major speed up of data exchange between modules and can +lead to a x4 improvement in overall performance.

'         @@ -4072,8 +4152,8 @@ arrays to give two polar angle coordinates. this can be used to resolve left right ambiguity and is implemented for both the click and the whistle/moan detectors. As a result, the click detector bearing time display can now be set to go from -180 to 180 degrees rather than 0 - 180 degrees. In this case, -clicks in the upper half of the bearing display will be to port and clicks in the -right half will be to starboard. As you pass a whale which is to port, the +clicks in the upper half of the bearing display will be to port and clicks in +the right half will be to starboard. As you pass a whale which is to port, the clicks will move UP the display. In the long term, I hope to turn this display around so that time is up the screen rather than across. 

@@ -4150,9 +4230,9 @@ Symbol'>''         -Channel lists in output data streams of Decimator and other modules -fixed, so that when channel numbers change, downstream modules configurations -get the correct list of available channels.

+
Channel lists in output data streams of Decimator and other modules fixed, +so that when channel numbers change, downstream modules configurations get the +correct list of available channels.

'         @@ -4364,8 +4444,8 @@ acquisition. 

Bug fixes

-

Speed up of graphics, particularly regarding large quantities -of gps track  data

+

Speed up of graphics, particularly regarding large +quantities of gps track  data

National Instruments cards with names > 20 characters long are now correctly  recognised.

@@ -4775,8 +4855,8 @@ Symbol'>'1.0Beta 22 Jan 2008 - -Pamguard starts two releases, core and beta release,

+class=Heading2Char>1.0Beta 22 Jan 2008 - Pamguard +starts two releases, core and beta release,

this is the beta release

@@ -4848,12 +4928,12 @@ and Ishmael-type detectors and localisers.

Information from above modules can be displayed on configurable user displays which support real time scrolling spectrograms and radar displays. Detection and localisation information can be optionally -displayed on the map display.Map enhancements include improved scrolling whereby -the user can click and drag to pan the area. PamGuard can now interface with -MySQL database servers and users can easily select which information is logged. -(This replaces the previous 'flat-file' logging feature). A simulation module -allows virtual vocalising animals to be placed on the map to assist in training -and development. Extensive online user help has been added to PamGuard +displayed on the map display.Map enhancements include improved scrolling +whereby the user can click and drag to pan the area. PamGuard can now interface +with MySQL database servers and users can easily select which information is +logged. (This replaces the previous 'flat-file' logging feature). A simulation +module allows virtual vocalising animals to be placed on the map to assist in +training and development. Extensive online user help has been added to PamGuard Application

0.03b - first version used in a real 'at sea' environment.18/08/06

diff --git a/repo/org/pamguard/x3/2.2.5/_remote.repositories b/repo/org/pamguard/x3/2.2.5/_remote.repositories index 86e3f288..0c907465 100644 --- a/repo/org/pamguard/x3/2.2.5/_remote.repositories +++ b/repo/org/pamguard/x3/2.2.5/_remote.repositories @@ -1,6 +1,12 @@ #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/org/pamguard/x3/2.2.5/_remote.repositories #Wed Aug 02 09:25:44 BST 2023 X3-2.2.5-sources.jar>= X3-2.2.5-javadoc.jar>= X3-2.2.5.jar>= X3-2.2.5.pom>= +======== +#Thu Dec 21 11:14:13 GMT 2023 +nilus-3.0.pom>= +nilus-3.0.jar>= +>>>>>>>> upstream/main:repo/tethys/org/nilus/3.0/_remote.repositories diff --git a/repo/pamguard/org/x3/2.2.3/_remote.repositories b/repo/pamguard/org/x3/2.2.3/_remote.repositories index 8724e7f4..25e5c11e 100644 --- a/repo/pamguard/org/x3/2.2.3/_remote.repositories +++ b/repo/pamguard/org/x3/2.2.3/_remote.repositories @@ -1,4 +1,10 @@ #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/_remote.repositories #Thu Oct 26 14:35:14 BST 2023 x3-2.2.3.jar>= x3-2.2.3.pom>= +======== +#Fri Jan 12 10:06:13 GMT 2024 +x3-2.2.7.jar>= +x3-2.2.7.pom>= +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/_remote.repositories diff --git a/repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated b/repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated index e9aa1150..b7d7754e 100644 --- a/repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated +++ b/repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated @@ -1,12 +1,25 @@ #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated #Thu Oct 26 14:39:06 BST 2023 @default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1698327545863 file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1698327544361 +======== +#Fri Jan 12 10:09:16 GMT 2024 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1705054156080 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705054154613 +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated https\://repo1.maven.org/maven2/.error= file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= https\://nexus.bedatadriven.com/content/groups/public/.error= +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1698327545797 https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1698327545616 https\://repo1.maven.org/maven2/.lastUpdated=1698327546068 https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:javadoc\:2.2.3 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +======== +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1705054156060 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1705054155868 +https\://repo1.maven.org/maven2/.lastUpdated=1705054156344 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:javadoc\:2.2.7 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated diff --git a/repo/pamguard/org/x3/2.2.3/x3-2.2.3-sources.jar.lastUpdated b/repo/pamguard/org/x3/2.2.3/x3-2.2.3-sources.jar.lastUpdated index c4ae07f1..452f92c8 100644 --- a/repo/pamguard/org/x3/2.2.3/x3-2.2.3-sources.jar.lastUpdated +++ b/repo/pamguard/org/x3/2.2.3/x3-2.2.3-sources.jar.lastUpdated @@ -1,4 +1,5 @@ #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3-sources.jar.lastUpdated #Thu Oct 26 15:50:39 BST 2023 @default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1698327461349 file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1698327459306 @@ -12,3 +13,16 @@ https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not tran file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1698331839687 file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1698327461288 +======== +#Fri Jan 12 10:06:49 GMT 2024 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1705054009062 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705054007956 +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1705054008945 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1705054008751 +https\://repo1.maven.org/maven2/.lastUpdated=1705054009308 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:sources\:2.2.7 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7-sources.jar.lastUpdated diff --git a/repo/pamguard/org/x3/2.2.3/x3-2.2.3.pom b/repo/pamguard/org/x3/2.2.3/x3-2.2.3.pom index e739da2f..3319e94f 100644 --- a/repo/pamguard/org/x3/2.2.3/x3-2.2.3.pom +++ b/repo/pamguard/org/x3/2.2.3/x3-2.2.3.pom @@ -4,6 +4,10 @@ 4.0.0 pamguard.org x3 +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3.pom 2.2.3 +======== + 2.2.7 +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom POM was created from install:install-file diff --git a/repo/pamguard/org/x3/2.2.7/_remote.repositories b/repo/pamguard/org/x3/2.2.7/_remote.repositories new file mode 100644 index 00000000..25e5c11e --- /dev/null +++ b/repo/pamguard/org/x3/2.2.7/_remote.repositories @@ -0,0 +1,10 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/_remote.repositories +#Thu Oct 26 14:35:14 BST 2023 +x3-2.2.3.jar>= +x3-2.2.3.pom>= +======== +#Fri Jan 12 10:06:13 GMT 2024 +x3-2.2.7.jar>= +x3-2.2.7.pom>= +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/_remote.repositories diff --git a/repo/pamguard/org/x3/2.2.7/m2e-lastUpdated.properties b/repo/pamguard/org/x3/2.2.7/m2e-lastUpdated.properties new file mode 100644 index 00000000..df337f63 --- /dev/null +++ b/repo/pamguard/org/x3/2.2.7/m2e-lastUpdated.properties @@ -0,0 +1,11 @@ +#Fri Jan 12 10:09:16 GMT 2024 +bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|javadoc=1705054156349 +repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|sources=1705054009341 +repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|javadoc=1705054156349 +talan|https\://nexus.talanlabs.com/content/repositories/releases/|javadoc=1705054156349 +central|https\://repo1.maven.org/maven2|sources=1705054009341 +unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|javadoc=1705054156349 +talan|https\://nexus.talanlabs.com/content/repositories/releases/|sources=1705054009341 +bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|sources=1705054009341 +unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|sources=1705054009341 +central|https\://repo1.maven.org/maven2|javadoc=1705054156349 diff --git a/repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated b/repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated new file mode 100644 index 00000000..b7d7754e --- /dev/null +++ b/repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated @@ -0,0 +1,25 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated +#Thu Oct 26 14:39:06 BST 2023 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1698327545863 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1698327544361 +======== +#Fri Jan 12 10:09:16 GMT 2024 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1705054156080 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705054154613 +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3-javadoc.jar.lastUpdated +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1698327545797 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1698327545616 +https\://repo1.maven.org/maven2/.lastUpdated=1698327546068 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:javadoc\:2.2.3 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +======== +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1705054156060 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1705054155868 +https\://repo1.maven.org/maven2/.lastUpdated=1705054156344 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:javadoc\:2.2.7 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7-javadoc.jar.lastUpdated diff --git a/repo/pamguard/org/x3/2.2.7/x3-2.2.7-sources.jar.lastUpdated b/repo/pamguard/org/x3/2.2.7/x3-2.2.7-sources.jar.lastUpdated new file mode 100644 index 00000000..452f92c8 --- /dev/null +++ b/repo/pamguard/org/x3/2.2.7/x3-2.2.7-sources.jar.lastUpdated @@ -0,0 +1,28 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3-sources.jar.lastUpdated +#Thu Oct 26 15:50:39 BST 2023 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1698327461349 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1698327459306 +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1698327460817 +https\://repo1.maven.org/maven2/.lastUpdated=1698327461652 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:sources\:2.2.3 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1698331839687 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1698327461288 +======== +#Fri Jan 12 10:06:49 GMT 2024 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1705054009062 +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705054007956 +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error= +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1705054008945 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1705054008751 +https\://repo1.maven.org/maven2/.lastUpdated=1705054009308 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact pamguard.org\:x3\:jar\:sources\:2.2.7 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7-sources.jar.lastUpdated diff --git a/repo/pamguard/org/x3/2.2.7/x3-2.2.7.jar b/repo/pamguard/org/x3/2.2.7/x3-2.2.7.jar new file mode 100644 index 00000000..6f9a7ad4 Binary files /dev/null and b/repo/pamguard/org/x3/2.2.7/x3-2.2.7.jar differ diff --git a/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom b/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom new file mode 100644 index 00000000..3319e94f --- /dev/null +++ b/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom @@ -0,0 +1,13 @@ + + + 4.0.0 + pamguard.org + x3 +<<<<<<<< HEAD:repo/pamguard/org/x3/2.2.3/x3-2.2.3.pom + 2.2.3 +======== + 2.2.7 +>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom + POM was created from install:install-file + diff --git a/repo/tethys/org/javaclient/3.0/_remote.repositories b/repo/tethys/org/javaclient/3.0/_remote.repositories new file mode 100644 index 00000000..432cee9e --- /dev/null +++ b/repo/tethys/org/javaclient/3.0/_remote.repositories @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Thu Dec 21 11:13:37 GMT 2023 +javaclient-3.0.jar>= +javaclient-3.0.pom>= diff --git a/repo/tethys/org/javaclient/3.0/javaclient-3.0.jar b/repo/tethys/org/javaclient/3.0/javaclient-3.0.jar new file mode 100644 index 00000000..d1654195 Binary files /dev/null and b/repo/tethys/org/javaclient/3.0/javaclient-3.0.jar differ diff --git a/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom b/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom new file mode 100644 index 00000000..80fee21c --- /dev/null +++ b/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + tethys.org + javaclient + 3.0 + POM was created from install:install-file + diff --git a/repo/tethys/org/javaclient/maven-metadata-local.xml b/repo/tethys/org/javaclient/maven-metadata-local.xml new file mode 100644 index 00000000..629dfa04 --- /dev/null +++ b/repo/tethys/org/javaclient/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + tethys.org + javaclient + + 3.0 + + 3.0 + + 20231221111337 + + diff --git a/repo/tethys/org/nilus/3.0/_remote.repositories b/repo/tethys/org/nilus/3.0/_remote.repositories new file mode 100644 index 00000000..0c907465 --- /dev/null +++ b/repo/tethys/org/nilus/3.0/_remote.repositories @@ -0,0 +1,12 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +<<<<<<<< HEAD:repo/org/pamguard/x3/2.2.5/_remote.repositories +#Wed Aug 02 09:25:44 BST 2023 +X3-2.2.5-sources.jar>= +X3-2.2.5-javadoc.jar>= +X3-2.2.5.jar>= +X3-2.2.5.pom>= +======== +#Thu Dec 21 11:14:13 GMT 2023 +nilus-3.0.pom>= +nilus-3.0.jar>= +>>>>>>>> upstream/main:repo/tethys/org/nilus/3.0/_remote.repositories diff --git a/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties b/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties new file mode 100644 index 00000000..8382f138 --- /dev/null +++ b/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties @@ -0,0 +1,11 @@ +#Thu Dec 21 16:45:12 GMT 2023 +bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|javadoc=1703177112968 +talan|https\://nexus.talanlabs.com/content/repositories/releases/|javadoc=1703177112968 +repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo|javadoc=1703177112968 +central|https\://repo1.maven.org/maven2|sources=1703157324238 +unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|javadoc=1703177112968 +repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo|sources=1703157324238 +talan|https\://nexus.talanlabs.com/content/repositories/releases/|sources=1703157324238 +bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|sources=1703157324238 +unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|sources=1703157324238 +central|https\://repo1.maven.org/maven2|javadoc=1703177112968 diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated b/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated new file mode 100644 index 00000000..34e39dc5 --- /dev/null +++ b/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated @@ -0,0 +1,12 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +#Thu Dec 21 16:45:12 GMT 2023 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1703177112601 +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1703177110940 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703177112519 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1703177112101 +https\://repo1.maven.org/maven2/.lastUpdated=1703177112965 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:nilus\:jar\:javadoc\:3.0 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated b/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated new file mode 100644 index 00000000..8ceb547f --- /dev/null +++ b/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated @@ -0,0 +1,12 @@ +#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. +#Thu Dec 21 11:15:24 GMT 2023 +@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1703157323819 +https\://repo1.maven.org/maven2/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error= +file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1703157322932 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error= +https\://nexus.bedatadriven.com/content/groups/public/.error= +https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703157323770 +https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1703157323508 +https\://repo1.maven.org/maven2/.lastUpdated=1703157324237 +https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:nilus\:jar\:sources\:3.0 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0.jar b/repo/tethys/org/nilus/3.0/nilus-3.0.jar new file mode 100644 index 00000000..195d268e Binary files /dev/null and b/repo/tethys/org/nilus/3.0/nilus-3.0.jar differ diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0.pom b/repo/tethys/org/nilus/3.0/nilus-3.0.pom new file mode 100644 index 00000000..ba47dee9 --- /dev/null +++ b/repo/tethys/org/nilus/3.0/nilus-3.0.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + tethys.org + nilus + 3.0 + POM was created from install:install-file + diff --git a/repo/tethys/org/nilus/maven-metadata-local.xml b/repo/tethys/org/nilus/maven-metadata-local.xml new file mode 100644 index 00000000..d053c39d --- /dev/null +++ b/repo/tethys/org/nilus/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + tethys.org + nilus + + 3.0 + + 3.0 + + 20231221111413 + + diff --git a/src/AIS/AISParameters.java b/src/AIS/AISParameters.java index 982b5763..2f902b44 100644 --- a/src/AIS/AISParameters.java +++ b/src/AIS/AISParameters.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class AISParameters implements Serializable, Cloneable, ManagedParameters { @@ -51,7 +52,7 @@ public class AISParameters implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("nmeaSource"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/AIS/AISPositionReport.java b/src/AIS/AISPositionReport.java index fda5b10f..ca23ad50 100644 --- a/src/AIS/AISPositionReport.java +++ b/src/AIS/AISPositionReport.java @@ -5,6 +5,7 @@ import java.io.Serializable; import NMEA.NMEABitArray; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.LatLong; /** @@ -160,7 +161,7 @@ sensor. @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/AIS/AISStaticData.java b/src/AIS/AISStaticData.java index 7ca318c5..cbf891dc 100644 --- a/src/AIS/AISStaticData.java +++ b/src/AIS/AISStaticData.java @@ -6,6 +6,7 @@ import java.util.Calendar; import NMEA.NMEABitArray; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamCalendar; public class AISStaticData extends AISReport implements Serializable, ManagedParameters{ @@ -393,7 +394,7 @@ public class AISStaticData extends AISReport implements Serializable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/Acquisition/AcquisitionControl.java b/src/Acquisition/AcquisitionControl.java index 6ef615fb..b9410172 100644 --- a/src/Acquisition/AcquisitionControl.java +++ b/src/Acquisition/AcquisitionControl.java @@ -283,6 +283,16 @@ public class AcquisitionControl extends RawInputControlledUnit implements PamSet return daqControllers; } + @Override + public String getDataLocation() { + if (offlineFileServer == null) { + return null; + } + else { + return offlineFileServer.getDataLocation(); + } + } + public AcquisitionProcess getDaqProcess() { return acquisitionProcess; } diff --git a/src/Acquisition/AcquisitionDialog.java b/src/Acquisition/AcquisitionDialog.java index 50e0d977..cb739bb2 100644 --- a/src/Acquisition/AcquisitionDialog.java +++ b/src/Acquisition/AcquisitionDialog.java @@ -151,6 +151,7 @@ public class AcquisitionDialog extends PamDialog { acquisitionParameters = oldParams.clone(); acquisitionControl = daqControl; +// singleInstance = null; if (singleInstance == null || singleInstance.getOwner() != parentFrame) { singleInstance = new AcquisitionDialog(parentFrame); diff --git a/src/Acquisition/AcquisitionParameters.java b/src/Acquisition/AcquisitionParameters.java index fd79799e..a9c02698 100644 --- a/src/Acquisition/AcquisitionParameters.java +++ b/src/Acquisition/AcquisitionParameters.java @@ -10,6 +10,7 @@ import Array.Preamplifier; import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamguardMVC.PamConstants; @@ -320,7 +321,7 @@ public class AcquisitionParameters implements Serializable, Cloneable, ManagedPa @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("channelList"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/Acquisition/AcquisitionProcess.java b/src/Acquisition/AcquisitionProcess.java index c5e331fc..b8c33ac5 100644 --- a/src/Acquisition/AcquisitionProcess.java +++ b/src/Acquisition/AcquisitionProcess.java @@ -211,10 +211,10 @@ public class AcquisitionProcess extends PamProcess implements DataInputStore { if (systemPrepared == false) return; + newDataQueue.clearList(); // clear this first to make sure nothing new comes in. + // before starting, clear all old data rawDataBlock.clearAll(); - - newDataQueue.clearList(); sampleRateErrorFilter.prepareFilter(); totalExtraSamples = 0; @@ -302,6 +302,7 @@ public class AcquisitionProcess extends PamProcess implements DataInputStore { // called by PamController. // stop the running system - not the selected system since // this may have changed + restartTimer.stop(); // stallCheckTimer.stop(); pamStop(""); @@ -471,6 +472,9 @@ public class AcquisitionProcess extends PamProcess implements DataInputStore { * have been emptied and processing has stopped */ protected void pamHasStopped() { + + newDataQueue.clearList(); // clear this first to make sure nothing new comes in. + if (runningSystem == null){ runningSystem = acquisitionControl.findDaqSystem(null); } @@ -650,9 +654,10 @@ public class AcquisitionProcess extends PamProcess implements DataInputStore { restartTimer.stop(); - PamController.getInstance().pamStop(); - - PamController.getInstance().pamStart(false); + PamController.getInstance().restartPamguard(); +// PamController.getInstance().pamStop(); +// +// PamController.getInstance().pamStart(false); } diff --git a/src/Acquisition/DaqStatusModuleHeader.java b/src/Acquisition/DaqStatusModuleHeader.java index 5af44a54..5a548a6a 100644 --- a/src/Acquisition/DaqStatusModuleHeader.java +++ b/src/Acquisition/DaqStatusModuleHeader.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import binaryFileStorage.BinaryHeader; import binaryFileStorage.BinaryObjectData; @@ -30,7 +31,7 @@ class DaqStatusModuleHeader extends ModuleHeader implements Serializable, Manage @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("daqName"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/Acquisition/FileInputParameters.java b/src/Acquisition/FileInputParameters.java index 6453b2f1..9a3f114d 100644 --- a/src/Acquisition/FileInputParameters.java +++ b/src/Acquisition/FileInputParameters.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Used by FileInputSystem @@ -78,7 +79,7 @@ public class FileInputParameters implements Serializable, Cloneable, ManagedPara return null; } - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/Acquisition/FolderInputSystem.java b/src/Acquisition/FolderInputSystem.java index 98264e73..7b20311e 100644 --- a/src/Acquisition/FolderInputSystem.java +++ b/src/Acquisition/FolderInputSystem.java @@ -318,13 +318,12 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D } selection = folderInputParameters.getSelectedFiles(); } - - if (selection!=null && selection.length > 0) { + if (selection == null) { + return 0; + } + if (selection.length > 0) { System.out.println("FolderInputSystem.makeSelFileList(): Searching for sound files in " + selection[0]); } - - if (selection==null) return 0; //sometimes happens - return makeSelFileList(selection); } @@ -519,8 +518,8 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D */ public void newFileList(FileListData fileListData) { - System.out.printf("Wav list recieved with %d files after %d millis\n", - fileListData.getFileCount(), System.currentTimeMillis() - wavListStart); +// System.out.printf("Wav list recieved with %d files after %d millis\n", +// fileListData.getFileCount(), System.currentTimeMillis() - wavListStart); allFiles = fileListData.getListCopy(); List asList = allFiles; @@ -539,8 +538,6 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D if (file.isFile() && !file.isHidden() && acquisitionDialog != null) { //Hidden files should not be used in analysis... try { - - System.out.println("FolderInputSystem - newFileList"); audioStream = PamAudioFileManager.getInstance().getAudioInputStream(file); AudioFormat audioFormat = audioStream.getFormat(); fileSamples = audioStream.getFrameLength(); @@ -703,7 +700,7 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D if (currentFile > 0 && currentFile >= allFiles.size()) { fileListComplete(); } -// System.out.println("FolderinputSytem: daqHasEnded"); + System.out.println("FolderinputSytem: daqHasEnded"); } private void setFolderProgress() { @@ -923,7 +920,6 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D return true; } for (int i = 0; i < allFiles.size(); i++) { - System.out.println("Get file start time"); long fileStart = getFileStartTime(allFiles.get(i).getAbsoluteFile()); if (fileStart >= startTime) { currentFile = i; diff --git a/src/Acquisition/SoundCardParameters.java b/src/Acquisition/SoundCardParameters.java index e962db72..a54b62b4 100644 --- a/src/Acquisition/SoundCardParameters.java +++ b/src/Acquisition/SoundCardParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import simulatedAcquisition.SimProcess; /** @@ -47,7 +48,7 @@ public class SoundCardParameters implements Serializable, Cloneable, ManagedPara return null; } - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/Acquisition/filedate/StandardFileDateSettings.java b/src/Acquisition/filedate/StandardFileDateSettings.java index 074540f1..b699ca9a 100644 --- a/src/Acquisition/filedate/StandardFileDateSettings.java +++ b/src/Acquisition/filedate/StandardFileDateSettings.java @@ -6,6 +6,7 @@ import java.util.TimeZone; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import soundtrap.STXMLFile; public class StandardFileDateSettings implements Serializable, Cloneable, ManagedParameters { @@ -150,7 +151,7 @@ public class StandardFileDateSettings implements Serializable, Cloneable, Manage @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } } diff --git a/src/Acquisition/gpstiming/PPSParameters.java b/src/Acquisition/gpstiming/PPSParameters.java index 76bdd012..478d7728 100644 --- a/src/Acquisition/gpstiming/PPSParameters.java +++ b/src/Acquisition/gpstiming/PPSParameters.java @@ -6,6 +6,7 @@ import Acquisition.AcquisitionControl; import Acquisition.AcquisitionDialog; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class PPSParameters implements Cloneable, Serializable, ManagedParameters { @@ -36,7 +37,7 @@ public class PPSParameters implements Cloneable, Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Acquisition/pamAudio/WavAudioFile.java b/src/Acquisition/pamAudio/WavAudioFile.java index b20a4b1b..77d07b54 100644 --- a/src/Acquisition/pamAudio/WavAudioFile.java +++ b/src/Acquisition/pamAudio/WavAudioFile.java @@ -14,6 +14,7 @@ import javax.sound.sampled.UnsupportedAudioFileException; import org.codehaus.plexus.util.FileUtils; import Acquisition.offlineFuncs.AquisitionLoadPoint; import PamDetection.RawDataUnit; +import PamguardMVC.PamConstants; //import PamUtils.CPUMonitor; import PamguardMVC.PamDataBlock; import PamguardMVC.dataOffline.OfflineDataLoadInfo; @@ -47,6 +48,8 @@ public class WavAudioFile implements PamAudioFileLoader { * Get the file extensions associated with loading these data. */ protected ArrayList fileExtensions; + + private double[] channelBackground = new double[PamConstants.MAX_CHANNELS]; public WavAudioFile() { fileExtensions = new ArrayList(Arrays.asList(new String[]{".wav", ".aif", ".aiff"})); @@ -190,6 +193,9 @@ public class WavAudioFile implements PamAudioFileLoader { newDataUnit = new RawDataUnit(ms, 1 << ichan, totalSamples, newSamples); newDataUnit.setFileSamples(totalSamples + skipped / frameSize); //set the number samples into the wav file. + + removeDCComponent(doubleData[ichan], ichan, audioFormat); + newDataUnit.setRawData(doubleData[ichan], true); //System.out.println("New wav data: " + PamCalendar.formatDateTime(newDataUnit.getTimeMilliseconds())); @@ -211,6 +217,26 @@ public class WavAudioFile implements PamAudioFileLoader { } + private void removeDCComponent(double[] ds, int channel, AudioFormat audioFormat) { + /* + * do a simple background subtraction with about a 1s time constant. + * If the background is currently zero initialise it to the mean data value. + */ + double alpha = 1./audioFormat.getSampleRate(); + double alpha_1 = 1.-alpha; + double bg = channelBackground[channel]; + if (bg == 0.) { + for (int i = 0; i < ds.length; i++) { + bg += ds[i]; + } + bg /= ds.length; + } + for (int i = 0; i < ds.length; i++) { + ds[i] -= bg; + bg = bg*alpha_1 + ds[i]*alpha; + } + } + /** * Open a sound file. * @param soundFile diff --git a/src/AirgunDisplay/AirgunParameters.java b/src/AirgunDisplay/AirgunParameters.java index fe779657..5fae8317 100644 --- a/src/AirgunDisplay/AirgunParameters.java +++ b/src/AirgunDisplay/AirgunParameters.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamUtils.LatLong; @@ -95,7 +96,7 @@ public class AirgunParameters implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("dimE"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/Array/ArrayDialog.java b/src/Array/ArrayDialog.java index 3469b1a2..4475d7bb 100644 --- a/src/Array/ArrayDialog.java +++ b/src/Array/ArrayDialog.java @@ -44,6 +44,8 @@ public class ArrayDialog extends PamDialog implements ActionListener { private EnvironmentPanel environmentPanel; private HydrophoneDiagram hydrophoneDiagram; + + private InstrumentIdentityPanel instrumentIdentityPanel; private JButton okButton, cancelButton; @@ -69,11 +71,14 @@ public class ArrayDialog extends PamDialog implements ActionListener { eastPanel.add(channelPanel.getChannelPanel()); environmentPanel = new EnvironmentPanel(this); + instrumentIdentityPanel = new InstrumentIdentityPanel(); + // eastPanel.add(environmentPanel.getEnvironmentPanel()); hydrophoneDiagram = new HydrophoneDiagram(this); JPanel westPanel = new JPanel(new BorderLayout()); westPanel.add(BorderLayout.CENTER, hydrophoneDiagram.getPlotPanel()); westPanel.add(BorderLayout.SOUTH, environmentPanel.getEnvironmentPanel()); + westPanel.add(BorderLayout.NORTH, instrumentIdentityPanel.getComponent()); splitPanel.add(westPanel); @@ -144,6 +149,7 @@ public class ArrayDialog extends PamDialog implements ActionListener { hydrophoneDialogPanel.setParams(selArray); channelPanel.setParams(); hydrophoneDiagram.rePaint(); + instrumentIdentityPanel.setParams(selArray); if (selArray != null) { environmentPanel.setNewSpeed(selArray.getSpeedOfSound()); } @@ -171,6 +177,7 @@ public class ArrayDialog extends PamDialog implements ActionListener { array.setSpeedOfSound(environmentPanel.getNewSpeed()); array.setSpeedOfSoundError(environmentPanel.getNewError()); hydrophoneDialogPanel.getParams(); + instrumentIdentityPanel.getParams(array); if (checkDaqChannels(array) == false) { return false; @@ -250,6 +257,7 @@ public class ArrayDialog extends PamDialog implements ActionListener { environmentPanel.setNewSpeed(currentArray.getSpeedOfSound()); environmentPanel.setNewError(currentArray.getSpeedOfSoundError()); } + instrumentIdentityPanel.setParams(currentArray); } void newChannelSelection() { diff --git a/src/Array/Hydrophone.java b/src/Array/Hydrophone.java index 4cd073d4..be3b11f8 100644 --- a/src/Array/Hydrophone.java +++ b/src/Array/Hydrophone.java @@ -28,6 +28,7 @@ import java.util.Arrays; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import pamMaths.PamVector; import PamView.PamSymbol; @@ -333,7 +334,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters { /** * @return Returns the coordinate. */ - protected double[] getCoordinates() { + public double[] getCoordinates() { return Arrays.copyOf(coordinate,3); } @@ -478,7 +479,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet pps = PamParameterSet.autoGenerate(this); + PamParameterSet pps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); Field f; try { f = this.getClass().getDeclaredField("coordinate"); diff --git a/src/Array/HydrophoneDataBlock.java b/src/Array/HydrophoneDataBlock.java index 8f8b2d9b..aaa16f6d 100644 --- a/src/Array/HydrophoneDataBlock.java +++ b/src/Array/HydrophoneDataBlock.java @@ -54,7 +54,7 @@ public class HydrophoneDataBlock extends PamDataBlock { */ @Override public int getNumRequiredBeforeLoadTime() { - return ArrayManager.getArrayManager().getCurrentArray().getHydrophoneCount(); + return ArrayManager.getArrayManager().getCurrentArray().getHydrophoneCount()*2; } diff --git a/src/Array/HydrophoneLocator.java b/src/Array/HydrophoneLocator.java index d51fafbb..5d6c9d7c 100644 --- a/src/Array/HydrophoneLocator.java +++ b/src/Array/HydrophoneLocator.java @@ -7,6 +7,7 @@ import Array.streamerOrigin.StreamerDataIterator; import GPS.GpsData; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamUtils.LatLong; import PamguardMVC.PamDataBlock; @@ -225,7 +226,7 @@ abstract public class HydrophoneLocator implements Serializable, Cloneable, Mana */ @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("pamArray"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/Array/HydrophoneProcess.java b/src/Array/HydrophoneProcess.java index ee712abf..6c5c9f68 100644 --- a/src/Array/HydrophoneProcess.java +++ b/src/Array/HydrophoneProcess.java @@ -3,152 +3,151 @@ package Array; import pamScrollSystem.AbstractScrollManager; import PamUtils.PamCalendar; import PamView.symbol.StandardSymbolManager; +import PamguardMVC.PamConstants; import PamguardMVC.PamDataBlock; import PamguardMVC.PamProcess; public class HydrophoneProcess extends PamProcess{ + + private StreamerDataBlock streamerDataBlock; + private boolean arrayDataSaved; + private ArrayManager arrayManager; + private HydrophoneDataBlock hydrophoneDataBlock; + private HydrophoneSQLLogging hydrophoneSQLlogging; + + public HydrophoneProcess(ArrayManager arrayManager) { + super(arrayManager, null); + this.arrayManager = arrayManager; + + addOutputDataBlock(streamerDataBlock = new StreamerDataBlock(this)); + streamerDataBlock.setOverlayDraw(new StreamerOverlayGraphics()); + streamerDataBlock.setPamSymbolManager(new StandardSymbolManager(streamerDataBlock, StreamerOverlayGraphics.streamerSymbol, true)); + streamerDataBlock.SetLogging(new StreamerLogging(this, streamerDataBlock)); - private StreamerDataBlock streamerDataBlock; - private boolean arrayDataSaved; - private ArrayManager arrayManager; - private HydrophoneDataBlock hydrophoneDataBlock; - private HydrophoneSQLLogging hydrophoneSQLlogging; - - public HydrophoneProcess(ArrayManager arrayManager) { - super(arrayManager, null); - this.arrayManager = arrayManager; - - addOutputDataBlock(streamerDataBlock = new StreamerDataBlock(this)); - streamerDataBlock.setOverlayDraw(new StreamerOverlayGraphics()); - streamerDataBlock.setPamSymbolManager(new StandardSymbolManager(streamerDataBlock, StreamerOverlayGraphics.streamerSymbol, true)); - streamerDataBlock.SetLogging(new StreamerLogging(this, streamerDataBlock)); - - hydrophoneDataBlock= new HydrophoneDataBlock("Hydrophone Data", this, 0xFFFFFFFF); - hydrophoneSQLlogging=new HydrophoneSQLLogging(hydrophoneDataBlock); - hydrophoneDataBlock.SetLogging(hydrophoneSQLlogging); - addOutputDataBlock(hydrophoneDataBlock); - - streamerDataBlock.setMixedDirection(PamDataBlock.MIX_OUTOFDATABASE); - hydrophoneDataBlock.setMixedDirection(PamDataBlock.MIX_OUTOFDATABASE); - } - - @Override - public void destroyProcess(){ - for (int i=0; i + * This may cause trouble in offline analysis if you want to make changes to the phone layout + * (for example changing a hydrophone separation). + */ + public void createArrayData() { +// DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); +// DBProcess dbProcess = null; +// if (dbControl != null) { +// dbProcess = dbControl.getDbProcess(); +// } + + long timeNow = PamCalendar.getTimeInMillis(); + + createDefaultStreamerUnits(timeNow); + createDefaultHydrophoneUnits(timeNow); - } - - /** - * @return the streamerDataBlock - */ - protected StreamerDataBlock getStreamerDataBlock() { - return streamerDataBlock; - } - - /** - * Save all the array data to the database. This get's called when - * the array manager dialog has been called or when PAMGuard starts to ensure - * that there is a database record of how the hydrophones were arranged.

- * This may cause trouble in offline analysis if you want to make changes to the phone layout - * (for example changing a hydrophone separation). - */ - public void createArrayData() { - // DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); - // DBProcess dbProcess = null; - // if (dbControl != null) { - // dbProcess = dbControl.getDbProcess(); - // } - - long timeNow = PamCalendar.getTimeInMillis(); - - createDefaultStreamerUnits(timeNow); - createDefaultHydrophoneUnits(timeNow); - - arrayDataSaved = true; - } - public int createDefaultStreamerUnits(long timeNow) { - - PamArray currentArray = arrayManager.getCurrentArray(); - if (currentArray == null) { - return 0; + arrayDataSaved = true; } - int n = currentArray.getNumStreamers(); - Streamer s; - StreamerDataUnit sdu; - StreamerDataBlock sdb = arrayManager.getStreamerDatabBlock(); - for (int i = 0; i < n; i++) { - if (sdb.getPreceedingUnit(timeNow,1<%s
UID:%d, Database: %d
%s
", + "GPS Data", getUID(), getDatabaseIndex(), PamCalendar.formatDBDateTime(getTimeMilliseconds(), true)); if (gpsData != null) { str += gpsData.summaryString(); } return str; } + @Override + public double[] getFrequency() { + return null; + } + } diff --git a/src/GPS/GpsLogger.java b/src/GPS/GpsLogger.java index b02c32e6..f0f990c8 100644 --- a/src/GPS/GpsLogger.java +++ b/src/GPS/GpsLogger.java @@ -295,7 +295,8 @@ public class GpsLogger extends SQLLogging { * time from the UTC column which is NOT the GpsData time which was the real GPS time. */ int gpsIntTimeVal = gpsTime.getIntegerValue(); - Object ts = getTableDefinition().getTimeStampItem().getValue(); + PamTableDefinition pamTableDef = (PamTableDefinition) getTableDefinition(); + Object ts = pamTableDef.getTimeStampItem().getValue(); long gpsDate = sqlTypes.millisFromTimeStamp(ts); if (gpsDate%1000 == 0) { // some databases may have stored the milliseconds, in which diff --git a/src/IshmaelDetector/IshDetParams.java b/src/IshmaelDetector/IshDetParams.java index d79b8d60..f8d4c2a9 100644 --- a/src/IshmaelDetector/IshDetParams.java +++ b/src/IshmaelDetector/IshDetParams.java @@ -17,6 +17,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.GroupedSourceParameters; public class IshDetParams implements Serializable, Cloneable, ManagedParameters { @@ -96,7 +97,7 @@ public class IshDetParams implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("inputDataSource"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/IshmaelDetector/IshDisplayParams.java b/src/IshmaelDetector/IshDisplayParams.java index 609f9c2b..a0dea6aa 100644 --- a/src/IshmaelDetector/IshDisplayParams.java +++ b/src/IshmaelDetector/IshDisplayParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Ishamel display parameters for the Spectrogram plug in. @@ -42,7 +43,7 @@ public class IshDisplayParams implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/IshmaelDetector/IshLogger.java b/src/IshmaelDetector/IshLogger.java index c9abdcfe..6bd47109 100644 --- a/src/IshmaelDetector/IshLogger.java +++ b/src/IshmaelDetector/IshLogger.java @@ -8,14 +8,13 @@ import java.sql.Types; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; - +import generalDatabase.EmptyTableDefinition; //import pamDatabase.SQLLogging; //import PamguardMVC.RecyclingDataBlock; import generalDatabase.PamDetectionLogging; public class IshLogger extends PamDetectionLogging { IshDetControl ishDetControl; - PamTableDefinition tableDefinition; PamTableItem systemDate, durationSecs, secSinceStart, peakHeight; // Peak is more important than start time for matched filter & spectrogram correlation PamTableItem peakSample, peakDelaySecs; @@ -25,7 +24,7 @@ public class IshLogger extends PamDetectionLogging { super(pamDataBlock, UPDATE_POLICY_WRITENEW); this.ishDetControl = ishDetControl; - tableDefinition = getTableDefinition(); + EmptyTableDefinition tableDefinition = getTableDefinition(); // PamTableItem tableItem; // setUpdatePolicy(UPDATE_POLICY_WRITENEW); diff --git a/src/IshmaelLocator/IshLocSqlLogging.java b/src/IshmaelLocator/IshLocSqlLogging.java index 0b95afe3..c43539d0 100644 --- a/src/IshmaelLocator/IshLocSqlLogging.java +++ b/src/IshmaelLocator/IshLocSqlLogging.java @@ -14,14 +14,13 @@ import IshmaelDetector.IshDetection; import PamUtils.LatLong; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; - +import generalDatabase.EmptyTableDefinition; //import pamDatabase.SQLLogging; //import PamguardMVC.RecyclingDataBlock; import generalDatabase.PamDetectionLogging; public class IshLocSqlLogging extends PamDetectionLogging { IshLocControl ishLocControl; - PamTableDefinition tableDefinition; PamTableItem systemDate, durationSecs, secSinceStart, peakHeight; private PamTableItem latitude, longitude, refLatitude, refLongitude, x, y, z; @@ -30,7 +29,7 @@ public class IshLocSqlLogging extends PamDetectionLogging { super(pamDataBlock, UPDATE_POLICY_WRITENEW); this.ishLocControl = ishDetControl; - tableDefinition = getTableDefinition(); + EmptyTableDefinition tableDefinition = getTableDefinition(); tableDefinition.addTableItem(latitude = new PamTableItem("Latitude", Types.DOUBLE)); tableDefinition.addTableItem(longitude = new PamTableItem("Longitude", Types.DOUBLE)); tableDefinition.addTableItem(refLatitude = new PamTableItem("ReferenceLatitude", Types.DOUBLE)); diff --git a/src/KernelSmoothing/KernelSmoothingParameters.java b/src/KernelSmoothing/KernelSmoothingParameters.java index 8b5f010c..6ddd593b 100644 --- a/src/KernelSmoothing/KernelSmoothingParameters.java +++ b/src/KernelSmoothing/KernelSmoothingParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class KernelSmoothingParameters implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class KernelSmoothingParameters implements Serializable, Cloneable, Manag @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Localiser/DelayMeasurementParams.java b/src/Localiser/DelayMeasurementParams.java index dc92235d..4a232970 100644 --- a/src/Localiser/DelayMeasurementParams.java +++ b/src/Localiser/DelayMeasurementParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import fftFilter.FFTFilterParams; /** @@ -157,7 +158,7 @@ public class DelayMeasurementParams implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java index 19aae965..0eb58fcb 100644 --- a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java +++ b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMCParams2.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Paramters for running a Marklov chain Monte Carlo algorithm. @@ -141,7 +142,7 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java b/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java index bc3983b6..214f337c 100644 --- a/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java +++ b/src/Localiser/algorithms/genericLocaliser/MCMC/old/MCMCParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class MCMCParams implements Serializable, Cloneable, ManagedParameters { @@ -64,7 +65,7 @@ public class MCMCParams implements Serializable, Cloneable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java index d7cdc11f..d012bfdb 100644 --- a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java +++ b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/HyperbolicParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** @@ -69,7 +70,7 @@ public class HyperbolicParams implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Localiser/controls/RawOrFFTParams.java b/src/Localiser/controls/RawOrFFTParams.java index 0545ea90..9df83a54 100644 --- a/src/Localiser/controls/RawOrFFTParams.java +++ b/src/Localiser/controls/RawOrFFTParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import Spectrogram.WindowFunction; /** @@ -104,7 +105,7 @@ public class RawOrFFTParams implements Serializable, Cloneable, RawOrFFTParamsIn @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/Map/GebcoMapFile.java b/src/Map/GebcoMapFile.java index befe7d3a..acb2112c 100644 --- a/src/Map/GebcoMapFile.java +++ b/src/Map/GebcoMapFile.java @@ -85,7 +85,15 @@ public class GebcoMapFile implements MapFileManager { * @see Map.MapFile#readFileData(java.io.File) */ public boolean readFileData(File file) { - return readMapFile(file, true); + try { + return readMapFile(file, true); + } + catch (Exception e) { + // trap error someone reported at end November 22. Suspect it was their corrupt map file causing problems. + String err = String.format("Map file %s is missing or corrupt and cannot be loaded", file.getName()); + WarnOnce.showWarning("Map File Error", err, WarnOnce.OK_OPTION); + return false; + } } private boolean readMapFile(File gebcoFile, boolean readContours) { diff --git a/src/Map/MapDetectionsParameters.java b/src/Map/MapDetectionsParameters.java index a52aff72..bfc72e9b 100644 --- a/src/Map/MapDetectionsParameters.java +++ b/src/Map/MapDetectionsParameters.java @@ -7,6 +7,7 @@ import java.util.ListIterator; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * PArameters for MapDetectionsManager which @@ -65,7 +66,7 @@ public class MapDetectionsParameters implements Serializable, Cloneable, Managed @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/Map/MapPanel.java b/src/Map/MapPanel.java index e3122141..225f01ef 100644 --- a/src/Map/MapPanel.java +++ b/src/Map/MapPanel.java @@ -1096,6 +1096,7 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana return; } ds = dataBlock.getDataSelector(simpleMapRef.getUnitName(), false, DATASELECTNAME); +// ds = null; ArrayList dataCopy = dataBlock.getDataCopy(earliestToPlot, now, true, ds); duIterator = dataCopy.listIterator(); while (duIterator.hasNext()) { diff --git a/src/Map/MapParameters.java b/src/Map/MapParameters.java index b0eee649..11baeb07 100644 --- a/src/Map/MapParameters.java +++ b/src/Map/MapParameters.java @@ -27,6 +27,7 @@ import java.lang.reflect.Field; import Array.Hydrophone; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class MapParameters implements Serializable, Cloneable, ManagedParameters { @@ -301,7 +302,7 @@ public class MapParameters implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/Map/MapRectProjector.java b/src/Map/MapRectProjector.java index dd402886..2c45a517 100644 --- a/src/Map/MapRectProjector.java +++ b/src/Map/MapRectProjector.java @@ -20,9 +20,15 @@ */ package Map; +import java.awt.Point; import java.awt.event.MouseMotionAdapter; import java.awt.geom.AffineTransform; +import java.util.ListIterator; +import GPS.GPSControl; +import GPS.GPSDataBlock; +import GPS.GpsDataUnit; +import PamController.PamController; import PamUtils.Coordinate3d; import PamUtils.LatLong; import PamUtils.PamCoordinate; @@ -385,6 +391,45 @@ public class MapRectProjector extends MapProjector { return xTrans; } + @Override + public String getHoverText(Point mousePoint, int ploNumberMatch) { + String text = super.getHoverText(mousePoint, ploNumberMatch); + if (text == null) { + return findGpsTrackText(mousePoint, ploNumberMatch); + } + else { + return text; + } + } + + private String findGpsTrackText(Point mousePoint, int ploNumberMatch) { + GPSControl gpsControl = GPSControl.getGpsControl(); + if (gpsControl == null || mousePoint == null) { + return null; + } + LatLong currentPos = getDataPosition(new Coordinate3d(mousePoint.x, mousePoint.y)); + GPSDataBlock gpsDataBlock = gpsControl.getGpsDataBlock(); + double dist = Double.MAX_VALUE; + GpsDataUnit closest = null; + ListIterator it = gpsDataBlock.getListIterator(0); + while (it.hasNext()) { + GpsDataUnit gpsUnit = it.next(); + double r = gpsUnit.getGpsData().distanceToMetres(currentPos); + if (r < dist) { + dist = r; + closest = gpsUnit; + } + } + if (closest == null) { + return null; + } + double rPix = dist*this.pixelsPerMetre; + if (rPix > 20) { + return null; + } + return closest.getSummaryString(); + } + } diff --git a/src/Map/gridbaselayer/GridbaseParameters.java b/src/Map/gridbaselayer/GridbaseParameters.java index 2af62e75..fe608b8d 100644 --- a/src/Map/gridbaselayer/GridbaseParameters.java +++ b/src/Map/gridbaselayer/GridbaseParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class GridbaseParameters implements Cloneable, Serializable, ManagedParameters { @@ -25,7 +26,7 @@ public class GridbaseParameters implements Cloneable, Serializable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/NMEA/NMEAParameters.java b/src/NMEA/NMEAParameters.java index 42393be3..9da8c22c 100644 --- a/src/NMEA/NMEAParameters.java +++ b/src/NMEA/NMEAParameters.java @@ -24,6 +24,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import serialComms.jserialcomm.PJSerialComm; public class NMEAParameters implements Serializable, Cloneable, ManagedParameters { @@ -149,7 +150,7 @@ public class NMEAParameters implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/PamController/OfflineDataStore.java b/src/PamController/OfflineDataStore.java index 52e64150..20a34041 100644 --- a/src/PamController/OfflineDataStore.java +++ b/src/PamController/OfflineDataStore.java @@ -33,6 +33,13 @@ public interface OfflineDataStore { */ public String getDataSourceName(); + /** + * Get the data location. This may be a specific file, or might be a folder + * if data are in many files, a URI, etc. + * @return store locations + */ + public String getDataLocation(); + /** * Load data for a given datablock between two time limits. * @param dataBlock datablock owner of the data diff --git a/src/PamController/PamControlledUnit.java b/src/PamController/PamControlledUnit.java index f1962ca8..654bd715 100644 --- a/src/PamController/PamControlledUnit.java +++ b/src/PamController/PamControlledUnit.java @@ -23,6 +23,7 @@ package PamController; import java.awt.Component; import java.awt.Frame; import java.util.ArrayList; +import java.util.List; import javax.swing.JFrame; import javax.swing.JMenu; @@ -30,16 +31,14 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; -import offlineProcessing.OfflineTask; import offlineProcessing.OfflineTaskGroup; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - import PamController.status.ModuleStatus; import PamController.status.ModuleStatusManager; import PamController.status.ProcessCheck; +import PamModel.PamModel; import PamModel.PamModuleInfo; +import PamModel.PamPluginInterface; import PamView.ClipboardCopier; import PamView.PamGui; import PamView.PamSidePanel; @@ -845,6 +844,16 @@ public abstract class PamControlledUnit implements SettingsNameProvider { } return worstStatus; } + + /** + * Get the offline state of this module. This can generally + * be idle, but can be a higher state when map making at startup + * and when running an offline task. + * @return + */ + public int getOfflineState() { + return PamController.PAM_IDLE; + } // /** // * Get a list of available offline tasks for this module. This is mostly used for tasks that @@ -880,6 +889,53 @@ public abstract class PamControlledUnit implements SettingsNameProvider { public int getInstanceIndex() { return instanceIndex; } + + /** + * Get detail if this is a plugin. + * @return plugin detail, or null if it's not a plugin. + */ + public PamPluginInterface getPlugin() { + List pluginList = ((PamModel) PamController.getInstance().getModelInterface()).getPluginList(); + if (pluginList == null) { + return null; + } + for (PamPluginInterface plugin : pluginList) { + if (plugin.getClassName().equals(this.getClass().getName())) { + return plugin; + } + } + return null; + } + + /** + * The PamConfiguration holds the master list of modules which form part of a + * configuration. It should be accessed to find list of datablocks, etc. rather than + * doing everything through PAMController whenever possible. + * @return the pamConfiguration + */ + public PamConfiguration getPamConfiguration() { + if (pamConfiguration == null) { + pamConfiguration = PamController.getInstance().getPamConfiguration(); + } + return pamConfiguration; + } + + /** + * Is this module in the main configuration. If it isn't then it's probably a dummy config + * used in the batch processor or for importing / exporting configs, so it should be stopped from + * doing too much ! + * @return + */ + public boolean isInMainConfiguration() { + return pamConfiguration == PamController.getInstance().getPamConfiguration(); + } + + /** + * @param pamConfiguration the pamConfiguration to set + */ + public void setPamConfiguration(PamConfiguration pamConfiguration) { + this.pamConfiguration = pamConfiguration; + } /** * The PamConfiguration holds the master list of modules which form part of a diff --git a/src/PamController/PamControlledUnitSettings.java b/src/PamController/PamControlledUnitSettings.java index ccdc18bf..4d8c1ecc 100644 --- a/src/PamController/PamControlledUnitSettings.java +++ b/src/PamController/PamControlledUnitSettings.java @@ -36,6 +36,7 @@ import org.apache.commons.io.input.ClassLoaderObjectInputStream; import PamModel.PamModel; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.dialog.warn.WarnOnce; @@ -398,8 +399,13 @@ public class PamControlledUnitSettings implements Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } + @Override + public String toString() { + return String.format("Type %s; Name %s, Data ", getUnitType(), getUnitName()) + getSettings(); + } + } diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java index 389015ae..dfa37f56 100644 --- a/src/PamController/PamController.java +++ b/src/PamController/PamController.java @@ -37,6 +37,7 @@ import javax.swing.ToolTipManager; import com.jcraft.jsch.ConfigRepository.Config; import com.sun.xml.bind.v2.TODO; +import Acquisition.AcquisitionControl; import Acquisition.AcquisitionProcess; //import com.sun.org.apache.xerces.internal.dom.DocumentImpl; @@ -57,6 +58,7 @@ import fftManager.FFTDataUnit; import generalDatabase.DBControlUnit; import javafx.application.Platform; import javafx.stage.Stage; +import metadata.MetaDataContol; import Array.ArrayManager; import PamController.command.MulticastController; import PamController.command.NetworkController; @@ -64,6 +66,7 @@ import PamController.command.TerminalController; import PamController.command.WatchdogComms; import PamController.fileprocessing.ReprocessManager; import PamController.masterReference.MasterReferencePoint; +import PamController.settings.BatchViewSettingsImport; import PamController.settings.output.xml.PamguardXMLWriter; import PamController.settings.output.xml.XMLWriterDialog; import PamController.soundMedium.GlobalMediumManager; @@ -123,6 +126,12 @@ public class PamController implements PamControllerInterface, PamSettings { public static final int PAM_INITIALISING = 4; public static final int PAM_STOPPING = 5; public static final int PAM_COMPLETE = 6; + public static final int PAM_MAPMAKING = 7; + public static final int PAM_OFFLINETASK = 8; + + public static final int BUTTON_START = 1; + public static final int BUTTON_STOP = 2; + private volatile int lastStartStopButton = 0; // status' for RunMode = RUN_PAMVIEW public static final int PAM_LOADINGDATA = 2; @@ -156,7 +165,7 @@ public class PamController implements PamControllerInterface, PamSettings { /** * The current PAM status */ - private transient int pamStatus = PAM_IDLE; + private volatile int pamStatus = PAM_IDLE; /** * PamGuard view params. @@ -186,6 +195,8 @@ public class PamController implements PamControllerInterface, PamSettings { private static PamController uniqueController; private Timer diagnosticTimer; + + private boolean debugDumpBufferAtRestart = false; private NetworkController networkController; private int nNetPrepared; @@ -234,6 +245,10 @@ public class PamController implements PamControllerInterface, PamSettings { */ private Thread statusCheckThread; private WaitDetectorThread detectorEndThread; + private boolean firstDataLoadComplete; + // keep a track of the total number of times PAMGuard is started for debug purposes. + private int nStarts; + private RestartRunnable restartRunnable; private PamController(int runMode, Object object) { @@ -436,7 +451,7 @@ public class PamController implements PamControllerInterface, PamSettings { // addModule(mi, "Temporary Database"); // } - // Add a note to the putput console for the user to ignore the SLF4J warning (see http://www.slf4j.org/codes.html#StaticLoggerBinder + // Add a note to the output console for the user to ignore the SLF4J warning (see http://www.slf4j.org/codes.html#StaticLoggerBinder // for details). I spent a few hours trying to get rid of this warning, but without any luck. If you do a google search // there are a lot of forum suggestions on how to fix, but none seemed to work for me. Added both slf4j-nop and // slf4j-simple to dependency list, neither made a difference. Changed order of dependencies, ran purges and updates, @@ -452,6 +467,7 @@ public class PamController implements PamControllerInterface, PamSettings { System.out.println(""); System.out.println("Note - ignore the following SLF4J warn/error messages, they are not applicable to this application"); ArrayManager.getArrayManager(); // create the array manager so that it get's it's settings + MetaDataContol.getMetaDataControl(); /** * Check for archived files and unpack automatically. @@ -490,17 +506,31 @@ public class PamController implements PamControllerInterface, PamSettings { addView(guiFrameManager.initPrimaryView(this, pamModelInterface)); } + /** + * Calling this will cause a callback to this.restoreSettings which + * includes a list of modules which will then get created, and in turn + * load all of their own settings from the settings manager. + */ PamSettingManager.getInstance().registerSettings(this); + + /** + * For offline batch processing a few funnies happen here. We'll be open + * in viewer mode, but it's likely a psf will have been passed as an input argument. + * We will therefore have to extract all the modules from that psfx as well and either + * add them as new modules, or get their settings and use those to update existing settings + * That should probably be done here before the final calls to setup processes, etc. + */ + if (getRunMode() == RUN_PAMVIEW && PamSettingManager.remote_psf != null) { + loadOtherSettings(PamSettingManager.remote_psf); + } + /* + * Get any other required modules for this run mode. + */ pamModelInterface.startModel(); setupProcesses(); - // if (getRunMode() == RUN_PAMVIEW) { - // createViewerStatusBar(); - // pamControlledUnits.add(new OfflineProcessingControlledUnit("OfflineProcessing")); - // } - /* * We are running as a remote application, start process straight away! */ @@ -571,6 +601,7 @@ public class PamController implements PamControllerInterface, PamSettings { // }); } + /** * Clear all data selectors and symbol managers. Required since some of these will have loaded as various modules were created, * but may also require additional data selectors and symbol managers from super detections which were not availble. @@ -583,6 +614,11 @@ public class PamController implements PamControllerInterface, PamSettings { } + /** + * This gets called after other data initialisation tasks (such as data mapping). + * @author dg50 + * + */ class DataInitialised implements Runnable { @Override public void run() { @@ -1018,8 +1054,45 @@ public class PamController implements PamControllerInterface, PamSettings { */ public void restartPamguard() { pamStop(); - startLater(); + + /* + * launch a restart thread, that won't do ANYTHING until + * PAMGuard is really idle and buffers are cleared. Can only + * have one of these at a time ! + */ + if (restartRunnable != null) { + System.out.println("Warning !!!! PAMGuard is already trying to restart!"); + return; + } + restartRunnable = new RestartRunnable(); + Thread restartThread = new Thread(restartRunnable, "RestartPAMGuard Thread"); + restartThread.run(); } + + private class RestartRunnable implements Runnable { + + @Override + public void run() { + long t1 = System.currentTimeMillis(); + while (getPamStatus() != PAM_IDLE) { + try { + Thread.sleep(200); + } catch (InterruptedException e) { + + } + } + long t2 = System.currentTimeMillis(); + restartRunnable = null; + System.out.printf("PAMGuard safe to restart after %d milliseconds\n", t2-t1); + startLater(false); + + } + + } + + + + /** * calls pamStart using the SwingUtilities * invokeLater command to start PAMGAURD @@ -1051,7 +1124,13 @@ public class PamController implements PamControllerInterface, PamSettings { @Override public void run() { - pamStart(saveSettings); + /* + * do a final check that the stop button hasn't been pressed - can arrive a bit + * late if the system was continually restarting. + */ + if (lastStartStopButton != BUTTON_STOP) { + pamStart(saveSettings); + } } } @@ -1076,6 +1155,26 @@ public class PamController implements PamControllerInterface, PamSettings { } } + /** + * Called from the start button. A little book keeping + * to distinguish this from automatic starts / restarts + * @return true if started. + */ + @Override + public boolean manualStart() { + lastStartStopButton = BUTTON_START; + return pamStart(); + } + + /** + * Called from the stop button. A little book keeping + * to distinguish this from automatic starts / restarts + */ + @Override + public void manualStop() { + lastStartStopButton = BUTTON_STOP; + pamStop(); + } /** * Start PAMGUARD. This function also gets called from the @@ -1161,9 +1260,17 @@ public class PamController implements PamControllerInterface, PamSettings { } if (saveSettings) { + startTime = PamCalendar.getSessionStartTime(); +// System.out.printf("Saving settings for start time %s\n", PamCalendar.formatDBDateTime(startTime)); saveSettings(PamCalendar.getSessionStartTime()); } + if (++nStarts > 1 && debugDumpBufferAtRestart) { + // do this here - all processses should have reset buffers to start again by now. + String msg = String.format("Starting PAMGuard go %d", nStarts); + dumpBufferStatus(msg, false); + } + StorageOptions.getInstance().setBlockOptions(); t1 = System.currentTimeMillis(); @@ -1225,6 +1332,7 @@ public class PamController implements PamControllerInterface, PamSettings { } } + dumpBufferStatus("In stopping", false); /* * now launch another thread to wait for everything to have stopped, but * leave this function so that AWT is released and graphics can update, the @@ -1252,9 +1360,11 @@ public class PamController implements PamControllerInterface, PamSettings { long t2 = System.currentTimeMillis(); if (t2 - t1 > 5000) { System.out.printf("Stopping, but stuck in loop for CheckRunStatus for %3.1fs\n", (double) (t2-t1)/1000.); + dumpBufferStatus("Stopping stuck in loop", false); + break; // crap out anyway. } try { - Thread.sleep(10); + Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } @@ -1265,19 +1375,43 @@ public class PamController implements PamControllerInterface, PamSettings { } + /** + * Look in every data block, particularly threaded ones, and dump + * the buffer status. This will have to go via PamProcess so that + * additional information can be added from any processes that + * hold additional data in other internal buffers. + * @param message Message to print prior to dumping buffers for debug. + * @param sayEmpties dump info even if a buffer is empty (otherwise, only ones that have stuff still) + */ + public void dumpBufferStatus(String message, boolean sayEmpties) { + if (debugDumpBufferAtRestart == false) return; + + System.out.println("**** Dumping process buffer status: " + message); + ArrayList pamControlledUnits = pamConfiguration.getPamControlledUnits(); + for (PamControlledUnit aUnit : pamControlledUnits) { + int numProcesses = aUnit.getNumPamProcesses(); + for (int i=0; i pamControlledUnits = pamConfiguration.getPamControlledUnits(); if (PamModel.getPamModel().isMultiThread()) { @@ -1298,7 +1434,7 @@ public class PamController implements PamControllerInterface, PamSettings { pamControlledUnits.get(iU).flushDataBlockBuffers(2000); } } - setPamStatus(PAM_IDLE); + dumpBufferStatus("In pamStopped, now idle", true); // wait here until the status has changed to Pam_Idle, so that we know // that we've really finished processing all data @@ -1319,6 +1455,11 @@ public class PamController implements PamControllerInterface, PamSettings { } guiFrameManager.pamEnded(); + long stopTime = PamCalendar.getTimeInMillis(); + saveEndSettings(stopTime); + + setPamStatus(PAM_IDLE); + // no good having this here since it get's called at the end of every file. // if (GlobalArguments.getParam(PamController.AUTOEXIT) != null) { //// can exit here, since we've auto started, can auto exit. @@ -1437,6 +1578,26 @@ public class PamController implements PamControllerInterface, PamSettings { pamConfiguration.saveSettings(timeNow); } + /** + * Gets called in pamStart and may / will attempt to store all + * PAMGUARD settings via the database and binary storage modules. + */ + private void saveEndSettings(long timeNow) { +// System.out.printf("Updating settings with end time %s\n", PamCalendar.formatDBDateTime(timeNow)); + ArrayList pamControlledUnits = pamConfiguration.getPamControlledUnits(); + PamControlledUnit pcu; + PamSettingsSource settingsSource; + for (int iU = 0; iU < pamControlledUnits.size(); iU++) { + pcu = pamControlledUnits.get(iU); + if (PamSettingsSource.class.isAssignableFrom(pcu.getClass())) { + settingsSource = (PamSettingsSource) pcu; + settingsSource.saveEndSettings(timeNow); + } + } + } + + + /** * Export configuration into an XML file * @param parentFrame @@ -1676,16 +1837,23 @@ public class PamController implements PamControllerInterface, PamSettings { * Updates the entire datamap. */ public void updateDataMap(){ + System.out.println("updateDataMap:"); if (DBControlUnit.findDatabaseControl()==null) return; + + System.out.println("updateDataMap: 1"); ArrayList datablocks=getDataBlocks() ; + System.out.println("updateDataMap: 2"); + DBControlUnit.findDatabaseControl().updateDataMap(datablocks); - if (BinaryStore.findBinaryStoreControl()!=null) { - BinaryStore.findBinaryStoreControl().getDatagramManager().updateDatagrams(); - } + System.out.println("updateDataMap: 3"); + + BinaryStore.findBinaryStoreControl().getDatagramManager().updateDatagrams(); + + System.out.println("updateDataMap: 4"); notifyModelChanged(PamControllerInterface.EXTERNAL_DATA_IMPORTED); } @@ -1758,6 +1926,10 @@ public class PamController implements PamControllerInterface, PamSettings { if (moduleChange(changeType)) { clearSelectorsAndSymbols(); } + + if (changeType == DATA_LOAD_COMPLETE) { + firstDataLoadComplete = true; + } } @@ -1894,12 +2066,78 @@ public class PamController implements PamControllerInterface, PamSettings { public void setPamStatus(int pamStatus) { this.pamStatus = pamStatus; + /* + * This only get's called once when set idle at viewer mode startup. + */ + if (debugDumpBufferAtRestart) { + System.out.printf("******* PamController.setPamStatus to %d, real status is %d set in thread %s\n", + pamStatus, getRealStatus(), Thread.currentThread().toString()); + } if (getRunMode() != RUN_PAMVIEW) { TopToolBar.enableStartButton(pamStatus == PAM_IDLE); TopToolBar.enableStopButton(pamStatus == PAM_RUNNING); } showStatusWarning(pamStatus); } + + /** + * This was within the StatusCommand class, but useful to have it here since it's needed + * in more than one place. In viewer mode at startup there are a number of things going on + * in different threads, such as the creation of datamaps, and this can (hopefully) handle those bespoke + * goings on. + * @return program status for multithreaded statup tasks. + */ + public int getRealStatus() { + PamController pamController = PamController.getInstance(); + if (pamController.isInitializationComplete() == false) { + return PamController.PAM_INITIALISING; + } + int runMode = PamController.getInstance().getRunMode(); + if (runMode == PamController.RUN_NETWORKRECEIVER) { + return PamController.PAM_RUNNING; + } + int status = pamController.getPamStatus(); + if (status == PamController.PAM_IDLE) { + status = PamController.PAM_IDLE; + } + else { + ArrayList daqs = PamController.getInstance().findControlledUnits(AcquisitionControl.unitType); + if (daqs != null) for (int i = 0; i < daqs.size(); i++) { + try { + AcquisitionControl daq = (AcquisitionControl) daqs.get(i); + if (daq.isStalled()) { + status = PamController.PAM_STALLED; + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + } + WatchdogComms watchdogComms = PamController.getInstance().getWatchdogComms(); + status = watchdogComms.getModifiedWatchdogState(status); + /* + * This function is now being used in batch processing of offline data, where it may be necessary + * to get status information from many different modules, for example when executing offline tasks + * or just at startup while generating datamaps and datagrams. + * So go through all modules and get the highest state of any of them. + */ + if (getRunMode() == RUN_PAMVIEW) { + if (firstDataLoadComplete == false) { + status = PAM_INITIALISING; + } + try { + for (PamControlledUnit aUnit : pamConfiguration.getPamControlledUnits()) { + status = Math.max(status, aUnit.getOfflineState()); + } + } + catch (Exception e) { + //just incase there is a concurrent modification at startup. + } + } + + return status; + } /** * show a warning when we're waiting for detectors to stop @@ -1928,6 +2166,7 @@ public class PamController implements PamControllerInterface, PamSettings { statusWarning.setWarningMessage(warningMessage); statusWarning.setWarnignLevel(1); warningSystem.addWarning(statusWarning); +// System.out.println(warningMessage); } } @@ -2184,6 +2423,31 @@ public class PamController implements PamControllerInterface, PamSettings { private boolean manualStop; + /** + * Used when in viewer mode and planning batch processing with a modified + * configuration, i.e. the command line has been supplied a normal viewer mode + * database and also a psfx file. The settings from the database will already have + * been loaded, this will load any modules that weren't there and will override all the + * settings in other modules with these ones (except some specials such as data storage locations) + * @param psfxFile Name of additional psfx file. + */ + private boolean loadOtherSettings(String psfxName) { + + File psfxFile = new File(psfxName); + if (psfxFile.exists() == false) { + return false; + } + + PamSettingsGroup settingsGroup = PSFXReadWriter.getInstance().loadFileSettings(psfxFile); + if (settingsGroup == null) { + return false; + } + + BatchViewSettingsImport importer = new BatchViewSettingsImport(this, settingsGroup); + importer.importSettings(); + return true; + } + /** * Called to load a specific set of PAMGUARD settings in * viewer mode, which were previously loaded in from a @@ -2400,7 +2664,7 @@ public class PamController implements PamControllerInterface, PamSettings { if (dbc == null) { return null; } - return dbc.getDatabaseName(); + return dbc.getLongDatabaseName(); } return null; } diff --git a/src/PamController/PamControllerInterface.java b/src/PamController/PamControllerInterface.java index d363f958..9cc416d8 100644 --- a/src/PamController/PamControllerInterface.java +++ b/src/PamController/PamControllerInterface.java @@ -458,6 +458,17 @@ public interface PamControllerInterface { * Close all modules and free up resources. */ public void pamClose(); + + /** + * Start function called from button to do a bit of extra book keeping + * @return + */ + public boolean manualStart(); + + /** + * Stop function called from button to do a bit of extra book keeping + */ + public void manualStop(); //public void controllerAddFileMenuItem(); diff --git a/src/PamController/PamSensor.java b/src/PamController/PamSensor.java new file mode 100644 index 00000000..03e51efe --- /dev/null +++ b/src/PamController/PamSensor.java @@ -0,0 +1,20 @@ +package PamController; + +/** + * Interface to define modules which can be considered as sensors of some sort. + * e.g. depth and orientation modules and the SoundTrap clickdetecotr + * @author dg50 + * + */ +public interface PamSensor { + + public String getUnitName(); + + public String getUnitType(); + + public String getSensorDescription(); + + public String getSensorId(); + + +} diff --git a/src/PamController/PamSettingManager.java b/src/PamController/PamSettingManager.java index ddd15740..43d92d09 100644 --- a/src/PamController/PamSettingManager.java +++ b/src/PamController/PamSettingManager.java @@ -44,6 +44,7 @@ import javax.swing.plaf.FontUIResource; import pamViewFX.fxNodes.utilsFX.PamUtilsFX; import pamViewFX.fxSettingsPanes.SettingsFileDialogFX; +import pamguard.GlobalArguments; //XMLSettings //import org.jdom.Document; @@ -383,6 +384,8 @@ public class PamSettingManager { boolean[] usedSettings, PamSettings user) { if (settingsList == null) return null; // go through the list and see if any match this module. Avoid repeats. +// String unitName = user.getUnitName(); +// String unitType = user.getUnitType(); for (int i = 0; i < settingsList.size(); i++) { if (usedSettings != null && usedSettings[i]) continue; if (isSettingsUnit(user, settingsList.get(i))) { @@ -392,6 +395,7 @@ public class PamSettingManager { return settingsList.get(i); } } + /* * To improve complex module loading where settings may be saved by multiple sub-modules, in * July 2015 many modules which had fixed settings had their settings names and types changed ! @@ -476,7 +480,7 @@ public class PamSettingManager { */ public PamSettings findSettingsOwner(String unitType, String unitName, String unitClassName) { for (PamSettings owner:owners) { - if (owner.getClass() != null) { + if (owner.getClass() != null && unitClassName != null) { if (owner.getClass().getName().equals(unitClassName) == false) { continue; } @@ -492,7 +496,7 @@ public class PamSettingManager { /** * Call just before PAMGUARD exits to save the settings * either to psf and / or database tables. - * @return true if settings saved sucessfully. + * @return true if settings saved successfully. */ public boolean saveFinalSettings() { int runMode = PamController.getInstance().getRunMode(); @@ -1029,8 +1033,9 @@ public class PamSettingManager { loadingLocalSettings = true; loadSettingsFileData(); + - if (PamSettingManager.RUN_REMOTE == false) { + if (PamSettingManager.RUN_REMOTE == false && GlobalArguments.isBatch() == false) { if (settingsFileData != null) { TipOfTheDayManager.getInstance().setShowAtStart(settingsFileData.showTipAtStartup); if (settingsFileData.showTipAtStartup) { @@ -1480,11 +1485,20 @@ public class PamSettingManager { if (settings.getUnitName() == null || settingsUser.getUnitName() == null) return false; if (settings.getUnitType() == null || settingsUser.getUnitType() == null) return false; - - if (settings.getUnitName().equals(settingsUser.getUnitName()) - && settings.getUnitType().equals(settingsUser.getUnitType()) - && settings.versionNo == settingsUser.getSettingsVersion()){ - return true; + /* + * some of the settings names used in Viewer mode have become too long, notably + * in some data selectors which are using a datablocks long data name. This + * screws things up, so moving to a begins with rather than equals for the name. + */ + String name = settingsUser.getUnitName(); + String type = settingsUser.getUnitType(); + long version = settingsUser.getSettingsVersion(); + + if (settings.getUnitType().equals(type) + && settings.versionNo == version){ + if (name.startsWith(settings.getUnitName())) { + return true; + } } return false; diff --git a/src/PamController/PamSettingsSource.java b/src/PamController/PamSettingsSource.java index ed67807a..ba4079cc 100644 --- a/src/PamController/PamSettingsSource.java +++ b/src/PamController/PamSettingsSource.java @@ -20,6 +20,14 @@ public interface PamSettingsSource { */ public boolean saveStartSettings(long timeNow); + /** + * Save settings when processing ends. + * This may just be an update of the settings saves with saveStartSettings, e.g. an end time. + * @param timeNow + * @return true if saved correctly. + */ + public boolean saveEndSettings(long timeNow); + /** * Get the number of different settings * within the settings source. diff --git a/src/PamController/PamguardVersionInfo.java b/src/PamController/PamguardVersionInfo.java index d46e0d2a..ddb47056 100644 --- a/src/PamController/PamguardVersionInfo.java +++ b/src/PamController/PamguardVersionInfo.java @@ -16,7 +16,7 @@ public class PamguardVersionInfo { * @return release type */ static public ReleaseType getReleaseType() { - return ReleaseType.CORE; + return ReleaseType.OTHER; } /** @@ -31,12 +31,12 @@ public class PamguardVersionInfo { * Version number, major version.minorversion.sub-release. * Note: can't go higher than sub-release 'f' */ - static public final String version = "2.02.11b"; + static public final String version = "2.02.10b"; /** * Release date */ - static public final String date = "10 November 2023"; + static public final String date = "2 March 2024"; // /** // * Release type - Beta or Core diff --git a/src/PamController/UsedModuleInfo.java b/src/PamController/UsedModuleInfo.java index 88756866..1170027a 100644 --- a/src/PamController/UsedModuleInfo.java +++ b/src/PamController/UsedModuleInfo.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Very simple class used in an ArrayList of used modules that @@ -54,8 +55,16 @@ public class UsedModuleInfo implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } + /** + * Get the unit name of the module being imported. + * @return + */ + public String getUnitName() { + return unitName; + } + } diff --git a/src/PamController/command/BatchStatusCommand.java b/src/PamController/command/BatchStatusCommand.java index a58012b2..046dff3e 100644 --- a/src/PamController/command/BatchStatusCommand.java +++ b/src/PamController/command/BatchStatusCommand.java @@ -2,6 +2,7 @@ package PamController.command; import Acquisition.AcquisitionControl; import PamController.PamController; +import offlineProcessing.OfflineTaskManager; import pamViewFX.PamControlledGUIFX; /** @@ -21,6 +22,19 @@ public class BatchStatusCommand extends ExtCommand { @Override public String execute(String command) { + if (PamController.getInstance().getRunMode() == PamController.RUN_NORMAL) { + return getNormalModeStatus(command); + } + else { + return getViewerModeStatus(command); + } + } + + private String getViewerModeStatus(String command) { + return OfflineTaskManager.getManager().getBatchStatus(); + } + + private String getNormalModeStatus(String command) { AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.class, null); if (daqControl == null) { return null; diff --git a/src/PamController/command/StatusCommand.java b/src/PamController/command/StatusCommand.java index 7d500e95..74acf77f 100644 --- a/src/PamController/command/StatusCommand.java +++ b/src/PamController/command/StatusCommand.java @@ -31,33 +31,7 @@ public class StatusCommand extends ExtCommand { private int getRealStatus() { PamController pamController = PamController.getInstance(); - if (pamController.isInitializationComplete() == false) { - return PamController.PAM_INITIALISING; - } - int runMode = PamController.getInstance().getRunMode(); - if (runMode == PamController.RUN_NETWORKRECEIVER) { - return PamController.PAM_RUNNING; - } - int status = pamController.getPamStatus(); - if (status == PamController.PAM_IDLE) { - status = PamController.PAM_IDLE; - } - else { - ArrayList daqs = PamController.getInstance().findControlledUnits(AcquisitionControl.unitType); - if (daqs != null) for (int i = 0; i < daqs.size(); i++) { - try { - AcquisitionControl daq = (AcquisitionControl) daqs.get(i); - if (daq.isStalled()) { - status = PamController.PAM_STALLED; - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - } - WatchdogComms watchdogComms = PamController.getInstance().getWatchdogComms(); - return watchdogComms.getModifiedWatchdogState(status); + return pamController.getRealStatus(); } diff --git a/src/PamController/settings/BatchViewSettingsImport.java b/src/PamController/settings/BatchViewSettingsImport.java new file mode 100644 index 00000000..d9cb5b2a --- /dev/null +++ b/src/PamController/settings/BatchViewSettingsImport.java @@ -0,0 +1,155 @@ +package PamController.settings; + +import java.util.ArrayList; + +import PamController.DataInputStore; +import PamController.OfflineDataStore; +import PamController.OfflineFileDataStore; +import PamController.PamControlledUnit; +import PamController.PamControlledUnitSettings; +import PamController.PamController; +import PamController.PamSettingManager; +import PamController.PamSettings; +import PamController.PamSettingsGroup; +import PamController.UsedModuleInfo; +import PamModel.PamModuleInfo; + +/** + * A set of functions to handle importing and overriding settings imported from a psfx during + * batch mode processing in viewer mode. Some of this is quite similar to code in SettingsImport + * but different enough that it's easier to have in a separate set of functions. + * @author dg50 + * + */ +public class BatchViewSettingsImport { + + private PamController pamController; + private PamSettingsGroup settingsGroup; + private SettingsImport settingsImport; + + public BatchViewSettingsImport(PamController pamController, PamSettingsGroup settingsGroup) { + this.pamController = pamController; + this.settingsGroup = settingsGroup; + settingsImport = new SettingsImport(pamController); + } + + public boolean importSettings() { + + // first organise by controlled unit + ArrayList moduleGroups = settingsImport.organiseSettingsGroups(settingsGroup.getUnitSettings()); + // can now go through those modules and see which exist and which need to be added. Not asking questions, just doing it! + for (SettingsImportGroup moduleGroup : moduleGroups) { + UsedModuleInfo moduleInfo = moduleGroup.getUsedModuleInfo(); + PamControlledUnit exModule = pamController.findControlledUnit(moduleInfo.getUnitType(), moduleInfo.getUnitName()); + boolean existingStore = false; + if (exModule != null) { + existingStore = isDataStore(exModule); + System.out.printf("Module %s:%s already exists in model (data store: %s)\n", moduleInfo.getUnitType(), moduleInfo.getUnitName(), Boolean.valueOf(existingStore)); + } + else { + System.out.printf("Module %s:%s will be added to model\n", moduleInfo.getUnitType(), moduleInfo.getUnitName()); + // add the module. No questions asked. + PamModuleInfo pamModuleInfo = moduleGroup.getPamModuleInfo(); + if (pamModuleInfo == null) { + System.out.printf("Module %s:%s is not available to this PAMGuard installation\n", moduleInfo.getUnitType(), moduleInfo.getUnitName()); + continue; + } + exModule = pamController.addModule(pamModuleInfo, moduleInfo.getUnitName()); + } + // set the settings for that module, but only if it's NOT a data storage module. + if (exModule == null) { + continue; + } +// if (exModule.getUnitName().contains("Noise")) { +// System.out.printf("restoring settings for %s, %s\n", exModule.getUnitType(), exModule.getUnitName()); +// +// } + if (isDataStore(exModule)) { + System.out.printf("Skip restoring settings for %s, %s\n", exModule.getUnitType(), exModule.getUnitName()); + continue; + } + restoreSettings(moduleGroup.getMainSettings()); + ArrayList subSets = moduleGroup.getSubSettings(); + if (subSets != null) { + for (PamControlledUnitSettings aSet : subSets) { + restoreSettings(aSet); + } + } +// exModule.notifyModelChanged(PamController.INITIALIZATION_COMPLETE); +// if (exModule.getTabPanel() != null) { +//// exModule.getTabPanel() +// } + } + /* + * Don't need to call this here since it get's called shortly + * from PAMController once all modules are in place. + */ +// pamController.notifyModelChanged(PamController.INITIALIZATION_COMPLETE); + + // send out an initialisation complete to help restore settings +// ArrayList allSettings = settingsGroup.getUnitSettings(); +// for (PamControlledUnitSettings aSet : allSettings) { +// PamSettings owner = PamSettingManager.getInstance().findSettingsOwner(aSet.getUnitType(), aSet.getUnitName(), null); +// if (owner == null) { +// System.out.printf("Cannot find owner for %s, %s, %s\n", aSet.getUnitType(), aSet.getUnitName(), aSet.getOwnerClassName()); +// } +// else { +// owner.restoreSettings(aSet); +// } +// } + + return true; + } + + /** + * Find the owner of these settings and send it it's new settings. + * @param aSet + * @return true if found and set sucessfully. + */ + private boolean restoreSettings(PamControlledUnitSettings aSet) { + PamSettings owner = PamSettingManager.getInstance().findSettingsOwner(aSet.getUnitType(), aSet.getUnitName(), null); + if (owner == null) { + System.out.printf("Cannot find owner for %s, %s, %s\n", aSet.getUnitType(), aSet.getUnitName(), aSet.getOwnerClassName()); + return false; + } + else { + try { + owner.restoreSettings(aSet); + } + catch (Exception e) { + System.out.printf("Exception restoring settings %s, %s, %s\n", aSet.getUnitType(), aSet.getUnitName(), aSet.getOwnerClassName()); + e.printStackTrace(); + return false; + } + } + return true; + } + + + + /** + * Is the module a data store. If it is, we probably won't want to copy over it's settings. + * @param controlledUnit PAMGuard module + * @return true if it's data output or input. + */ + private boolean isDataStore(PamControlledUnit controlledUnit) { + return isDataStore(controlledUnit.getClass()); + } + + /** + * Is the class a data store. If it is, we probably won't want to copy over it's settings. + * @param moduleClass module class + * @return true if it's data output or input. + */ + private boolean isDataStore(Class moduleClass) { + //OfflineFileDataStore, DataInputStore + if (OfflineDataStore.class.isAssignableFrom(moduleClass)) { + return true; + } + if (DataInputStore.class.isAssignableFrom(moduleClass)) { + return true; + } + return false; + } + +} diff --git a/src/PamController/settings/SettingsImport.java b/src/PamController/settings/SettingsImport.java index 0c52fb31..e5ed64d6 100644 --- a/src/PamController/settings/SettingsImport.java +++ b/src/PamController/settings/SettingsImport.java @@ -29,7 +29,10 @@ import PamView.dialog.warn.WarnOnce; */ public class SettingsImport { + private PamController pamController; + public SettingsImport(PamController pamController) { + this.pamController = pamController; } /** @@ -116,14 +119,16 @@ public class SettingsImport { */ private PamControlledUnit importReplace(SettingsImportGroup importGroup, String replaceModule) { PamControlledUnitSettings mainSet = importGroup.getMainSettings(); - PamControlledUnit unit = PamController.getInstance().findControlledUnit(mainSet.getUnitType(), replaceModule); + UsedModuleInfo importInfo = importGroup.getUsedModuleInfo(); + PamControlledUnit unit = PamController.getInstance().findControlledUnit(importInfo.getUnitType(), replaceModule); if (unit == null) { - System.out.println("Unable to find " + mainSet.getUnitType() + " " + mainSet.getUnitName() + " for settings replacement"); + System.out.println("Unable to find " + importInfo.getUnitType() + " " + importInfo.getUnitName() + " for settings replacement"); return null; } // check we can cast it to PamSettings - if (PamSettings.class.isAssignableFrom(unit.getClass())) { + if (PamSettings.class.isAssignableFrom(unit.getClass()) && mainSet != null) { try { + mainSet.setUnitName(replaceModule); ((PamSettings) unit).restoreSettings(mainSet); } catch (Exception e) { @@ -132,7 +137,7 @@ public class SettingsImport { System.err.println(e.getMessage()); } } - loadSubUnitSettings(importGroup, mainSet.getUnitName()); + loadSubUnitSettings(importGroup, replaceModule); return unit; } @@ -149,7 +154,15 @@ public class SettingsImport { } PamSettingManager setManager = PamSettingManager.getInstance(); for (PamControlledUnitSettings pamSettings:subSets) { - PamSettings owner = setManager.findSettingsOwner(pamSettings.getUnitType(), unitName, pamSettings.getOwnerClassName()); + /* + * class name in pamSettings is no longer correct, so cannot use pamSettings.getOwnerClassName(). + * but the classnames of all the sub modules are unknown (and will be different form the unit class name + * which can be got from importGroup.getPamModuleInfo().getClassName + * so will have to do this only on the unit type and name and hope for no conflicts (catch exception). + */ +// PamModuleInfo moduleInfo = importGroup.getPamModuleInfo(); +// String className = moduleInfo.getClassName(); + PamSettings owner = setManager.findSettingsOwner(pamSettings.getUnitType(), unitName, null); if (owner == null) { System.out.println(String.format("Cannot find settings owner for %s %s in current model", pamSettings.getUnitType(), unitName)); continue; @@ -168,7 +181,8 @@ public class SettingsImport { private PamControlledUnit importNew(SettingsImportGroup importGroup) { PamControlledUnitSettings mainSet = importGroup.getMainSettings(); - String moduleName = mainSet.getUnitName(); + UsedModuleInfo importInfo = importGroup.getUsedModuleInfo(); + String moduleName = importInfo.unitName; // check we've got a name that doesnt' exist and replace it if if does. // int startChar = 0; @@ -199,11 +213,11 @@ public class SettingsImport { PamControlledUnit unit = PamController.getInstance().addModule(PamController.getMainFrame(), moduleInfo); if (unit == null) { - System.out.println("Unable to find " + mainSet.getUnitType() + " " + mainSet.getUnitName() + " for settings replacement"); + System.out.println("Unable to find " + importInfo.getUnitType() + " " + importInfo.getUnitName() + " for settings replacement"); return null; } // check we can cast it to PamSettings - if (PamSettings.class.isAssignableFrom(unit.getClass())) { + if (PamSettings.class.isAssignableFrom(unit.getClass()) && mainSet != null) { try { mainSet.setUnitName(unit.getUnitName()); // need to force the unit name for some modules. ((PamSettings) unit).restoreSettings(mainSet); @@ -224,7 +238,7 @@ public class SettingsImport { * @param settings * @return */ - ArrayList organiseSettingsGroups(ArrayList settings) { + public ArrayList organiseSettingsGroups(ArrayList settings) { /** * this needs rewriting for psfx files which are organised differently. first we need to find * a list of PAMGuard modules by finding the settings group of the PAMController. diff --git a/src/PamController/settings/SettingsImportDialog.java b/src/PamController/settings/SettingsImportDialog.java index 6f6621e6..4241a0cf 100644 --- a/src/PamController/settings/SettingsImportDialog.java +++ b/src/PamController/settings/SettingsImportDialog.java @@ -195,12 +195,14 @@ public class SettingsImportDialog extends PamDialog { @Override public Object getValueAt(int rowIndex, int columnIndex) { SettingsImportGroup set = groupedSettings.get(rowIndex); - PamControlledUnitSettings mainSet = set.getMainSettings(); +// PamControlledUnitSettings mainSet = set.getMainSettings(); switch (columnIndex) { case 0: - return mainSet.getUnitType(); + return set.getUsedModuleInfo().getUnitType(); +// return mainSet.getUnitType(); case 1: - return mainSet.getUnitName(); + return set.getUsedModuleInfo().unitName; +// return mainSet.getUnitName(); case 2: // return choiceBoxes[rowIndex].getSelectedItem().toString(); return set.getImportChoice().toString(); diff --git a/src/PamController/settings/SettingsImportGroup.java b/src/PamController/settings/SettingsImportGroup.java index a74a6885..98bf1e4f 100644 --- a/src/PamController/settings/SettingsImportGroup.java +++ b/src/PamController/settings/SettingsImportGroup.java @@ -82,8 +82,10 @@ public class SettingsImportGroup { try { ownerClass = Class.forName(usedModuleInfo.className); } catch (ClassNotFoundException e) { + + System.out.println("Unknown class in loaded settings: " + usedModuleInfo.className); // TODO Auto-generated catch block - e.printStackTrace(); +// e.printStackTrace(); } ArrayList existingModules = PamController.getInstance().findControlledUnits(ownerClass); diff --git a/src/PamController/settings/output/xml/PamguardXMLWriter.java b/src/PamController/settings/output/xml/PamguardXMLWriter.java index 6b42c4e7..f74edce0 100644 --- a/src/PamController/settings/output/xml/PamguardXMLWriter.java +++ b/src/PamController/settings/output/xml/PamguardXMLWriter.java @@ -29,6 +29,7 @@ import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import com.sun.javafx.runtime.VersionInfo; @@ -42,12 +43,14 @@ import PamController.PamguardVersionInfo; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterData; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamCalendar; import PamUtils.XMLUtils; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import PamguardMVC.PamProcess; import binaryFileStorage.BinaryStore; +import tethys.TethysControl; /** * Class for writing XML configuration output to a file. @@ -62,6 +65,8 @@ public class PamguardXMLWriter implements PamSettings { private static final Set> WRAPPER_TYPES = getWrapperTypes(); private XMLWriterSettings writerSettings = new XMLWriterSettings(); + private boolean excludeDisplaySettings; +// private String xmlNameSpace; private static PamguardXMLWriter singleInstance; @@ -83,6 +88,19 @@ public class PamguardXMLWriter implements PamSettings { } return singleInstance; } + + /** + * Recursively walk the tree and add a namespace to every + * single element. + * @param doc + * @param nameSpace + * @return + */ + public boolean addNameSpaceToElements(Document doc, Element el, String nameSpace) { +// el.setAttributeNS(nameSpace, nameSpace, nameSpace); + NamedNodeMap attributes = el.getAttributes(); + return true; + } /** * Make a document with the options specified in writerSettings. @@ -371,6 +389,32 @@ public class PamguardXMLWriter implements PamSettings { * @return xml content as a a string. */ public String getAsString(Document doc) { + return getAsString(doc, true); +// try { +// DOMSource domSource = new DOMSource(doc); +// StringWriter writer = new StringWriter(); +// StreamResult result = new StreamResult(writer); +// TransformerFactory tf = TransformerFactory.newInstance(); +// Transformer transformer = tf.newTransformer(); +// transformer.setOutputProperty(OutputKeys.METHOD, "xml"); +// transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); +//// transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); +// transformer.setOutputProperty(OutputKeys.INDENT, "yes"); +// transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); +// transformer.transform(domSource, result); +// return writer.toString(); +// } catch (TransformerException e) { +// e.printStackTrace(); +// return null; +// } + } + /** + * Get the xml document as a String. + * @param doc xml document + * @param indent Indent / format the document. + * @return xml content as a a string. + */ + public String getAsString(Document doc, boolean indent) { try { DOMSource domSource = new DOMSource(doc); StringWriter writer = new StringWriter(); @@ -380,7 +424,7 @@ public class PamguardXMLWriter implements PamSettings { transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); transformer.transform(domSource, result); return writer.toString(); @@ -411,8 +455,7 @@ public class PamguardXMLWriter implements PamSettings { * @param pamSettingsUnit * @return xml element */ - private Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit) { - + public Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit) { int[] settingInds = findSettings(null, pamSettingsUnit.getUnitName()); PamSettings[] settingsObjects = null; if (settingInds != null) { @@ -436,7 +479,7 @@ public class PamguardXMLWriter implements PamSettings { * can be temporary settings objects when writing temporary settings from dialogs. * @return new XML element. */ - private Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit, PamSettings[] toWrite) { + public Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit, PamSettings[] toWrite) { Element moduleData = doc.createElement("MODULE"); moduleData.setAttribute("Java.class", pamSettingsUnit.getClass().getName()); moduleData.setAttribute("UnitType", pamSettingsUnit.getUnitType()); @@ -457,6 +500,9 @@ public class PamguardXMLWriter implements PamSettings { Element settingEl = doc.createElement("CONFIGURATION"); moduleData.appendChild(settingEl); for (int i = 0; i < toWrite.length; i++) { + if (wantObject(toWrite[i]) == false) { + continue; + } Element setEl = writeSettings(doc, toWrite[i], new ArrayList()); if (setEl != null) { settingEl.appendChild(setEl); @@ -467,6 +513,32 @@ public class PamguardXMLWriter implements PamSettings { return moduleData; } + /** + * USed by the Tethys writer to avoid writing display settings. + * @param pamSettings + * @return + */ + private boolean wantObject(PamSettings pamSettings) { + if (excludeDisplaySettings == false) { + return true; + } + Object obj = pamSettings.getSettingsReference(); + if (obj == null) { + return false; + } + if (obj instanceof ManagedParameters) { + ManagedParameters managedParams = (ManagedParameters) obj; + PamParameterSet paramSet = managedParams.getParameterSet(); + if (paramSet == null) { + return false; + } + if (paramSet.getParameterSetType() == ParameterSetType.DISPLAY && excludeDisplaySettings) { + return false; + } + } + return true; + } + /** * Write settings for a settings object, using the standard retreived object * from the settings. @@ -478,6 +550,14 @@ public class PamguardXMLWriter implements PamSettings { private Element writeSettings(Document doc, PamSettings pamSettings, ArrayList objectHierarchy) { return writeSettings(doc, pamSettings, pamSettings.getSettingsReference(), objectHierarchy); } + + public Document writeOneObject(Object data) { + Document doc = XMLUtils.createBlankDoc(); + Element el = doc.createElement("Settings"); + Element newel = writeObjectData(doc, el, data, new ArrayList()); + doc.appendChild(newel); + return doc; + } /** * Write settings using an object of choice instead of the standard one from PamSettings. @@ -489,6 +569,7 @@ public class PamguardXMLWriter implements PamSettings { * @return */ private Element writeSettings(Document doc, PamSettings pamSettings, Object data, ArrayList objectHierarchy) { + Element el = doc.createElement("SETTINGS"); el.setAttribute("Type", pamSettings.getUnitType()); el.setAttribute("Name", pamSettings.getUnitName()); @@ -500,10 +581,13 @@ public class PamguardXMLWriter implements PamSettings { return el; } - private Element writeObjectData(Document doc, Element el, Object data, ArrayList objectHierarchy) { + public Element writeObjectData(Document doc, Element el, Object data, ArrayList objectHierarchy) { if (data == null) { return null; } + if (objectHierarchy == null) { + objectHierarchy = new ArrayList<>(); + } if (objectHierarchy.contains(data)) { // just write the reference, but nothing else or we'll end up in an infinite loop of objects. Element e = doc.createElement("Object"); @@ -525,8 +609,10 @@ public class PamguardXMLWriter implements PamSettings { if (parameterSet == null) { return null; } - - objectHierarchy.add(data); + + if (objectHierarchy != null) { + objectHierarchy.add(data); + } for (PamParameterData pamParam:parameterSet.getParameterCollection()) { try { Object paramData = pamParam.getData(); @@ -765,9 +851,10 @@ public class PamguardXMLWriter implements PamSettings { processData.setAttribute("Name", process.getProcessName()); PamDataBlock source = process.getParentDataBlock(); if (source != null) { - Element inputEl = doc.createElement("Input"); - inputEl.setAttribute("Name", source.getLongDataName()); - inputEl.setAttribute("Channels", String.format("0x%X", source.getChannelMap())); + Element inputEl = source.getDataBlockXML(doc); +// Element inputEl = doc.createElement("Input"); +// inputEl.setAttribute("Name", source.getLongDataName()); +// inputEl.setAttribute("Channels", String.format("0x%X", source.getChannelMap())); processData.appendChild(inputEl); } int nOut = process.getNumOutputDataBlocks(); @@ -798,7 +885,16 @@ public class PamguardXMLWriter implements PamSettings { */ private int[] findSettings(String type, String name) { if (settingsSets == null) { - return null; + makeSettingsList(); + if (settingsSets == null) { + return null; + } + } + if (usedSettingsSets == null) { + usedSettingsSets = new boolean[settingsSets.size()]; + } + else if (usedSettingsSets.length < settingsSets.size()) { + usedSettingsSets = Arrays.copyOf(usedSettingsSets, settingsSets.size()); } int[] found = new int[settingsSets.size()]; int nFound = 0; @@ -818,7 +914,7 @@ public class PamguardXMLWriter implements PamSettings { return Arrays.copyOf(found, nFound); } - private ArrayList makeSettingsList() { + public ArrayList makeSettingsList() { PamSettingManager settingsManager = PamSettingManager.getInstance(); settingsSets = settingsManager.getOwners(); if (settingsSets == null) { @@ -850,6 +946,14 @@ public class PamguardXMLWriter implements PamSettings { return doc; } + /** + * Is this element a writable type ? Basically, this means + * that it's a primitive of some sort. Otherwise it's + * probably an object and may even be a list in which case + * it will need treating differently. + * @param clazz + * @return + */ public static boolean isWritableType(Class clazz) { if (clazz.isEnum()) return true; @@ -940,5 +1044,23 @@ public class PamguardXMLWriter implements PamSettings { return true; } + /** + * @return the excludeDisplaySettings + */ + public boolean isExcludeDisplaySettings() { + return excludeDisplaySettings; + } + + /** + * @param excludeDisplaySettings the excludeDisplaySettings to set + */ + public void setExcludeDisplaySettings(boolean excludeDisplaySettings) { + this.excludeDisplaySettings = excludeDisplaySettings; + } + +// public void setStaticNameSpace(String xmlNameSpace) { +// this.xmlNameSpace = xmlNameSpace; +// } + } diff --git a/src/PamController/settings/output/xml/XMLWriterSettings.java b/src/PamController/settings/output/xml/XMLWriterSettings.java index 8e5d0969..dcd60b83 100644 --- a/src/PamController/settings/output/xml/XMLWriterSettings.java +++ b/src/PamController/settings/output/xml/XMLWriterSettings.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class XMLWriterSettings implements Serializable, Cloneable, ManagedParameters { @@ -34,7 +35,7 @@ public class XMLWriterSettings implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/PamController/soundMedium/GlobalMediumParams.java b/src/PamController/soundMedium/GlobalMediumParams.java index 0a52ac83..8bf10f27 100644 --- a/src/PamController/soundMedium/GlobalMediumParams.java +++ b/src/PamController/soundMedium/GlobalMediumParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamController.soundMedium.GlobalMedium.SoundMedium; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Stores parameters for the current medium. @@ -41,7 +42,7 @@ public class GlobalMediumParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/PamModel/PamModel.java b/src/PamModel/PamModel.java index bc475091..4c0e0c1a 100644 --- a/src/PamModel/PamModel.java +++ b/src/PamModel/PamModel.java @@ -23,6 +23,7 @@ package PamModel; import java.io.File; import java.io.FileNotFoundException; import java.io.Serializable; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; @@ -44,11 +45,15 @@ import whistlesAndMoans.AbstractWhistleDataUnit; import fftManager.FFTDataUnit; import fftManager.PamFFTControl; import group3dlocaliser.Group3DLocaliserControl; +import metadata.MetaDataContol; import meygenturbine.MeygenTurbine; import printscreen.PrintScreenControl; import rockBlock.RockBlockControl; +import tethys.TethysControl; import turbineops.TurbineOperationControl; import GPS.GpsDataUnit; +import Map.MapController; +import Map.gridbaselayer.GridbaseControl; import NMEA.NMEADataUnit; import PamController.PamControlledUnitSettings; import PamController.PamController; @@ -62,6 +67,7 @@ import PamguardMVC.PamDataBlock; import analogarraysensor.ArraySensorControl; import backupmanager.BackupManager; import beamformer.continuous.BeamFormerControl; +import beamformer.localiser.BeamFormLocaliserControl; import bearinglocaliser.BearingLocaliserControl; import binaryFileStorage.SecondaryBinaryStore; import cepstrum.CepstrumControl; @@ -454,6 +460,20 @@ final public class PamModel implements PamSettings { mi.setToolTipText("Manage automated data backups"); mi.setModulesMenuGroup(utilitiesGroup); mi.setMaxNumber(1); + + +// mi = PamModuleInfo.registerControlledUnit(MetaDataContol.class.getName(), MetaDataContol.unitType); +// mi.setToolTipText("Project Meta Data"); +// mi.setModulesMenuGroup(utilitiesGroup); +// mi.setMaxNumber(1); + + if (isViewer) { + mi = PamModuleInfo.registerControlledUnit(TethysControl.class.getName(), TethysControl.defaultName); + mi.setToolTipText("Interface to Tethys Database"); + mi.setModulesMenuGroup(utilitiesGroup); + mi.setMaxNumber(1); + mi.setHidden(SMRUEnable.isEnable() == false); + } /* * ************* End Utilities Group ******************* @@ -928,14 +948,17 @@ final public class PamModel implements PamSettings { } - /* (non-Javadoc) - * @see PamModel.PamModelInterface#startModel() + + + /** + * Add any remaining REQUIRED modules.
+ * this get's called after the PamController has loaded it's main settings. + * So at this point, go through all the PamModuleInfo's and check that + * all have at least the minimum number required + * @return true */ public synchronized boolean startModel() { /* - * this get's called after the PamController has loaded it's main settings. - * So at this point, go through all the PamModuleInfo's and check that - * all have at least the minimum number required */ PamSettingManager.getInstance().registerSettings(this); @@ -952,11 +975,11 @@ final public class PamModel implements PamSettings { // writeModuleList(); - return false; + return true; } /** - * Really just debu goutput to make a list of all modules ... + * Really just debug output to make a list of all modules ... */ private void writeModuleList() { ArrayList moduleInfoList = PamModuleInfo.getModuleList(); @@ -1063,7 +1086,7 @@ final public class PamModel implements PamSettings { // clear the current list pluginList.clear(); daqList.clear(); - + /* * If developing a new PAMPlugin in eclipse, the easiest way to do it is to make a new * Eclipse project for your plugin code. Within that project, copy this PamModel class @@ -1078,6 +1101,8 @@ final public class PamModel implements PamSettings { * When you export the code for your plugin to a jar file, remember to NOT inlcude the copy of * PamModel ! */ + +// pluginList.add(new MorlaisWP1aPlugin()); // Load up whatever default classloader was used to create this class. Must use the same classloader // for all plugins, or else we will not be able to create proper dependencies between them or be able @@ -1145,11 +1170,30 @@ final public class PamModel implements PamSettings { // to add that URL to the default classloader path. URL newURL = jarList.get(i).toURI().toURL(); + // original method +// Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); +// method.setAccessible(true); +// method.invoke(cl, newURL); + + // first fix attempt - create a brand new URLClassLoader. As expected, we get a ClassCastException when trying + // to load the parameters so we can't save params using this method +// URL[] newURLArray = new URL[1]; +// newURLArray[0] = newURL; +// cl = new URLClassLoader(newURLArray); // second attempt - custom class loader with the system app loader specified as the parent. Loads controlled unit, but // as before it doesn't load the parameters classLoader.addURL(newURL); + // third attempt +// Class genericClass = cl.getClass(); +// Method method = genericClass.getSuperclass().getDeclaredMethod("addURL", new Class[] {URL.class}); +// method.setAccessible(true); +// method.invoke(cl, new Object[] {newURL}); + + + + // Save the name of the class to the global pluginBeingLoaded variable, and load the class. this.setPluginBeingLoaded(className); // Class c = cl.loadClass(className); @@ -1171,13 +1215,15 @@ final public class PamModel implements PamSettings { if (intf[j].getName().equals("PamModel.PamPluginInterface")) { // create an instance of the interface class. - PamPluginInterface pf = (PamPluginInterface) c.newInstance(); + Constructor constructor = c.getDeclaredConstructor(null); + PamPluginInterface pf = (PamPluginInterface) constructor.newInstance(null); if (getPluginBeingLoaded()==null) { continue; } // Let the user know which valid plugins have been found - System.out.println(" Creating instance of " + pf.getDefaultName() + ": " + pf.getClassName()); + System.out.printf(" Loading plugin interface for %s : %s version %s\n", + pf.getDefaultName(), pf.getClassName(), pf.getVersion()); if (getPluginBeingLoaded()==null) { continue; } @@ -1193,7 +1239,7 @@ final public class PamModel implements PamSettings { pluginList.add(pf); // add it to the list } else { - System.out.println(" Error: "+pf.getDefaultName()+" cannot run in this mode. Skipping module."); + System.out.println(" Error: " + pf.getDefaultName()+" cannot run in this mode. Skipping module."); } if (getPluginBeingLoaded()==null) { continue; @@ -1202,12 +1248,16 @@ final public class PamModel implements PamSettings { // now check for interfaces that implement DaqSystemInterface if (intf[j].getName().equals("Acquisition.DaqSystemInterface")) { - DaqSystemInterface pf = (DaqSystemInterface) c.newInstance(); // create an instance of the interface class + Constructor constructor = c.getDeclaredConstructor(null); + DaqSystemInterface pf = (DaqSystemInterface) constructor.newInstance(null); +// DaqSystemInterface pf = (DaqSystemInterface) c.newInstance(); // create an instance of the interface class if (getPluginBeingLoaded()==null) { continue; } - - System.out.println(" Creating instance of " + pf.getDefaultName() + ": " + className); + + System.out.printf(" Loading daq plugin interface for %s version %s\n", + pf.getDefaultName(), pf.getVersion()); +// System.out.println(" Creating instance of " + pf.getDefaultName() + ": " + className); if (getPluginBeingLoaded()==null) { continue; } @@ -1230,8 +1280,9 @@ final public class PamModel implements PamSettings { "for help.

" + "This plug-in will not be available for loading"; String help = null; - int ans = WarnOnce.showWarning(PamController.getInstance().getGuiFrameManager().getFrame(0), title, msg, WarnOnce.WARNING_MESSAGE, help, e1); + int ans = WarnOnce.showWarning(PamController.getMainFrame(), title, msg, WarnOnce.WARNING_MESSAGE, help, e1); System.err.println("Exception while loading " + className); + System.err.println(e1.getMessage()); continue; } } @@ -1244,7 +1295,7 @@ final public class PamModel implements PamSettings { "for help.

" + "This plug-in will not be available for loading"; String help = null; - int ans = WarnOnce.showWarning(PamController.getInstance().getGuiFrameManager().getFrame(0), title, msg, WarnOnce.WARNING_MESSAGE, help, ex); + int ans = WarnOnce.showWarning(PamController.getMainFrame(), title, msg, WarnOnce.WARNING_MESSAGE, help, ex); System.err.println("Exception while loading " + jarList.get(i).getName()); continue; } @@ -1269,7 +1320,7 @@ final public class PamModel implements PamSettings { // instantiate the plugin control class using the custom class loader try { -// File classFile = new File(pf.getJarFile()); + File classFile = new File(pf.getJarFile()); //URLClassLoader cl = new URLClassLoader(new URL[]{classFile.toURI().toURL()}); // mi = PamModuleInfo.registerControlledUnit(pf.getClassName(), pf.getDescription(),cl); mi = PamModuleInfo.registerControlledUnit(pf.getClassName(), pf.getDescription(),classLoader); @@ -1335,7 +1386,7 @@ final public class PamModel implements PamSettings { "for help.

" + "This plug-in will not be available for loading"; String help = null; - int ans = WarnOnce.showWarning(PamController.getInstance().getGuiFrameManager().getFrame(0), title, msg, WarnOnce.WARNING_MESSAGE, help, e1); + int ans = WarnOnce.showWarning(PamController.getMainFrame(), title, msg, WarnOnce.WARNING_MESSAGE, help, e1); System.err.println("Exception while loading " + pf.getDefaultName()); pluginList.remove(pf); continue; diff --git a/src/PamModel/PamModelSettings.java b/src/PamModel/PamModelSettings.java index 9e4b0632..667747b8 100644 --- a/src/PamModel/PamModelSettings.java +++ b/src/PamModel/PamModelSettings.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class PamModelSettings implements Cloneable, Serializable, ManagedParameters { @@ -74,7 +75,7 @@ public class PamModelSettings implements Cloneable, Serializable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/PamModel/parametermanager/PamParameterData.java b/src/PamModel/parametermanager/PamParameterData.java index a15a3c15..79944a90 100644 --- a/src/PamModel/parametermanager/PamParameterData.java +++ b/src/PamModel/parametermanager/PamParameterData.java @@ -34,6 +34,11 @@ abstract public class PamParameterData { */ private String postTitle; + /** + * field length for automatic dialogs. + */ + private int fieldLength; + /** * @param parentObject @@ -45,6 +50,21 @@ abstract public class PamParameterData { this.field = field; } + /** + * @param parentObject + * @param field + * @param shortName + * @param toolTip + * @param fieldLength length of text in automatic dialogs. + */ + public PamParameterData(Object parentObject, Field field, String shortName, String toolTip, int fieldLength) { + super(); + this.field = field; + this.shortName = shortName; + this.toolTip = toolTip; + this.fieldLength = fieldLength; + } + /** * @param parentObject * @param field @@ -58,7 +78,6 @@ abstract public class PamParameterData { this.toolTip = toolTip; } - /** * @param shortName the shortName to set */ @@ -66,6 +85,20 @@ abstract public class PamParameterData { this.shortName = shortName; } + /** + * Set info about a parameter + * @param shortName short name, e.g. to use in a dialog + * @param postTitle post title, e.g. text coming after a data entry field in a dialog + * @param toolTip tool tip to display over the component in a dialog. + * @param fieldLength length of text in automatic dialogs. + */ + public void setInfo(String shortName, String postTitle, String toolTip, int fieldLength) { + this.shortName = shortName; + this.postTitle = postTitle; + this.toolTip = toolTip; + this.fieldLength = fieldLength; + } + /** * Set info about a parameter * @param shortName short name, e.g. to use in a dialog @@ -136,6 +169,9 @@ abstract public class PamParameterData { * @return a short name for the field, suitable for use in dialogs. */ public String getShortName() { + if (shortName == null) { + return getFieldName(); + } return shortName; } @@ -166,5 +202,19 @@ abstract public class PamParameterData { return String.format("Param %s class %s", getFieldName(), getDataClass()); } + /** + * @return the fieldLength + */ + public int getFieldLength() { + return fieldLength; + } + + /** + * @param fieldLength the fieldLength to set + */ + public void setFieldLength(int fieldLength) { + this.fieldLength = fieldLength; + } + } diff --git a/src/PamModel/parametermanager/PamParameterDataGetter.java b/src/PamModel/parametermanager/PamParameterDataGetter.java index 3947f2dc..9a3e99b0 100644 --- a/src/PamModel/parametermanager/PamParameterDataGetter.java +++ b/src/PamModel/parametermanager/PamParameterDataGetter.java @@ -59,9 +59,12 @@ public class PamParameterDataGetter extends PrivatePamParameterData { if (setter == null) { return false; } + // need to convert the type + Object convObj = convertStringType(data); try { - setter.invoke(getParentObject(), data); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + Object parentObj = getParentObject(); + setter.invoke(parentObj, convObj); + } catch (InvocationTargetException e) { e.printStackTrace(); return false; } diff --git a/src/PamModel/parametermanager/PamParameterSet.java b/src/PamModel/parametermanager/PamParameterSet.java index 751f3d27..2425b2e7 100644 --- a/src/PamModel/parametermanager/PamParameterSet.java +++ b/src/PamModel/parametermanager/PamParameterSet.java @@ -10,7 +10,6 @@ import java.util.Collection; import java.util.Hashtable; import java.util.List; -import binaryFileStorage.BinaryStoreSettings; /** * Description of the parameters within a class. Primarily holds a list @@ -29,6 +28,9 @@ public class PamParameterSet { private static boolean printDebug = false; + public enum ParameterSetType {DETECTOR, DISPLAY}; + + private ParameterSetType parameterSetType; /** * Standard modifiers to exclude. This is important for many classes which will tend to * do crazy things such as incorporate ALL of their final fields, e.g. when a Color @@ -55,8 +57,21 @@ public class PamParameterSet { * in the STANDARD_MODIFIER_EXCLUSIONS list (FINAL or STATIC). * @return Created parameter set. */ + @Deprecated public static PamParameterSet autoGenerate(Object parentObject) { - return autoGenerate(parentObject, STANDARD_MODIFIER_EXCLUSIONS); + return autoGenerate(parentObject, ParameterSetType.DETECTOR); + } + /** + * Automatically generate a parameter set for a class. Will include all public fields and + * any private or protected fields for which a getter can be found that has a similar enough name + * @param parentObject class to generate description for. Exception is anything that's listed + * in the STANDARD_MODIFIER_EXCLUSIONS list (FINAL or STATIC). + * @return Created parameter set. + */ + public static PamParameterSet autoGenerate(Object parentObject, ParameterSetType parameterSetType) { + PamParameterSet paramSet = autoGenerate(parentObject, STANDARD_MODIFIER_EXCLUSIONS); + paramSet.setParameterSetType(parameterSetType); + return paramSet; } /** @@ -286,4 +301,19 @@ public class PamParameterSet { public PamParameterData removeParameterData(String paramName) { return parameterDatas.remove(paramName); } + + /** + * @return the parameterSetType + */ + public ParameterSetType getParameterSetType() { + return parameterSetType; + } + + /** + * @param parameterSetType the parameterSetType to set + */ + public void setParameterSetType(ParameterSetType parameterSetType) { + this.parameterSetType = parameterSetType; + } + } diff --git a/src/PamModel/parametermanager/ParameterSetManager.java b/src/PamModel/parametermanager/ParameterSetManager.java new file mode 100644 index 00000000..3420a7c4 --- /dev/null +++ b/src/PamModel/parametermanager/ParameterSetManager.java @@ -0,0 +1,73 @@ +package PamModel.parametermanager; + +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JMenuItem; + +import PamModel.parametermanager.swing.ManagedParameterDialog; +import generalDatabase.parameterstore.ParameterDatabaseStore; + +/** + * Just about everything giving overall control of some managed parameters. + * May be a bit too specific on first cut and need to be abstracted. + * Testing on 'Deployment' data. + * @author dg50 + * + * @param + */ +public class ParameterSetManager { + + private T managedParams; + private String name; + + public ParameterSetManager(T defaultParams, String name) { + setManagedParams(defaultParams); + this.name = name; +// if (managedParams == null) { +// managedParams = new T(); +// } + } + + /** + * @return the managedParams + */ + public T getManagedParams() { + return managedParams; + } + + /** + * @param managedParams the managedParams to set + */ + public void setManagedParams(T managedParams) { + this.managedParams = managedParams; + } + + public JMenuItem getMenuItem(Window parent) { + if (managedParams == null) { + return null; + } + JMenuItem menuItem = new JMenuItem(name + " ..."); + menuItem.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + showDialog(parent); + } + }); + + return menuItem; + } + + protected void showDialog(Window parent) { + ManagedParameterDialog dialog = new ManagedParameterDialog(parent, name, managedParams); + T newParams = dialog.showDialog(parent, name, managedParams); + + if (newParams != null) { + ParameterDatabaseStore paramDatabase = new ParameterDatabaseStore("MetaData"); + paramDatabase.saveParameterSet(newParams); + } + } + +} diff --git a/src/PamModel/parametermanager/PrivatePamParameterData.java b/src/PamModel/parametermanager/PrivatePamParameterData.java index e3fed547..6b29d9cd 100644 --- a/src/PamModel/parametermanager/PrivatePamParameterData.java +++ b/src/PamModel/parametermanager/PrivatePamParameterData.java @@ -1,6 +1,7 @@ package PamModel.parametermanager; import java.lang.reflect.Field; +import java.lang.reflect.Type; /** * Abstract instance of PamParameterDataInterface which implements everything @@ -36,9 +37,48 @@ public abstract class PrivatePamParameterData extends PamParameterData { * This should really be implemented in every concrete class, but no time to do that now. Aim to delete * this function here, then go through and implement everywhere ... */ - return false; +// return false; + Object convData = convertStringType(data); + getField().set(this, convData); + + return true; } + /** + * convert a string type to a different type appropriate for the field in + * question. + * @param value + * @return + */ + public Object convertStringType(Object value) { + if (value == null) { + return null; + } + if (value instanceof String == false) { + return value; + } + String str = (String) value; + Type type = getField().getGenericType(); + Class cls = getField().getType(); + String clsName = cls.getName(); + switch (clsName) { + case "int": + case "Integer": + return Integer.valueOf(str); + case "double": + case "Double": + return Double.valueOf(str); + case "float": + case "Float": + return Float.valueOf(str); + case "short": + case "Short": + return Short.valueOf(str); + + } + + return value; + } } diff --git a/src/PamModel/parametermanager/swing/ManagedParameterDialog.java b/src/PamModel/parametermanager/swing/ManagedParameterDialog.java new file mode 100644 index 00000000..9a3aa995 --- /dev/null +++ b/src/PamModel/parametermanager/swing/ManagedParameterDialog.java @@ -0,0 +1,49 @@ +package PamModel.parametermanager.swing; + +import java.awt.Window; + +import PamModel.parametermanager.ManagedParameters; +import PamView.dialog.PamDialog; + +public class ManagedParameterDialog extends PamDialog { + + private T params; + + private ManagedParameterPanel parameterPanel; + + public ManagedParameterDialog(Window parentFrame, String title, T params) { + super(parentFrame, title, false); + parameterPanel = new ManagedParameterPanel(params); + setDialogComponent(parameterPanel.getPanel()); + } + + public T showDialog(Window parentFrame, String title, T parameters) { +// ManagedParameterDialog dialog = new ManagedParameterDialog<>(parentFrame, title, parameters); + setParams(parameters); + setVisible(true); + + return params; + } + + private void setParams(T params) { + this.params = params; + this.parameterPanel.setParams(params); + } + + @Override + public boolean getParams() { + return parameterPanel.getParams(params); + } + + @Override + public void cancelButtonPressed() { + params = null; + } + + @Override + public void restoreDefaultSettings() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/PamModel/parametermanager/swing/ManagedParameterPanel.java b/src/PamModel/parametermanager/swing/ManagedParameterPanel.java new file mode 100644 index 00000000..416bef77 --- /dev/null +++ b/src/PamModel/parametermanager/swing/ManagedParameterPanel.java @@ -0,0 +1,149 @@ +package PamModel.parametermanager.swing; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.Collection; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.text.JTextComponent; + +import PamModel.parametermanager.FieldNotFoundException; +import PamModel.parametermanager.ManagedParameters; +import PamModel.parametermanager.PamParameterData; +import PamModel.parametermanager.PamParameterSet; +import PamView.dialog.PamDialog; +import PamView.dialog.PamGridBagContraints; + +public class ManagedParameterPanel { + + private JPanel mainPanel; + private Collection parameterSet; + + private static final int DEFAULT_TEXT_LENGTH = 6; + private static final int MAX_SINGLE_LINE_LENGTH = 40; + + private JTextComponent[] textComponents; + + public ManagedParameterPanel(T parameterExample) { + + mainPanel = new JPanel(new GridBagLayout()); + GridBagConstraints c = new PamGridBagContraints(); + PamParameterSet exampleSet = parameterExample.getParameterSet(); + parameterSet = exampleSet.getParameterCollection(); + int n = parameterSet.size(); + textComponents = new JTextComponent[n]; + int i = 0; + for (PamParameterData paramData : parameterSet) { + textComponents[i] = createComponent(paramData); + c.gridx = 0; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.NORTHEAST; + mainPanel.add(new JLabel(paramData.getShortName(), JLabel.RIGHT), c); + c.gridx++; + if (textComponents[i] instanceof JTextArea) { + c.fill = GridBagConstraints.HORIZONTAL; + } + else { + c.fill = GridBagConstraints.NONE; + } + c.anchor = GridBagConstraints.WEST; + mainPanel.add(textComponents[i], c); + + textComponents[i].setToolTipText(getTipText(paramData)); + + c.gridy++; + i++; + } + } + + private String getTipText(PamParameterData paramData) { + String tip = paramData.getToolTip(); + if (tip != null) { + return tip; + } + else { + return paramData.getFieldName(); + } + } + + private JTextComponent createComponent(PamParameterData paramData) { + int textLen = paramData.getFieldLength(); + if (textLen == 0) { + textLen = DEFAULT_TEXT_LENGTH; + } + if (textLen <= MAX_SINGLE_LINE_LENGTH) { + return new JTextField(textLen); + } + else { + JTextField dummyField = new JTextField(2); +// dummyField.getBorder(). + JTextArea textArea = new JTextArea(textLen/MAX_SINGLE_LINE_LENGTH+1, MAX_SINGLE_LINE_LENGTH); + textArea.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); + return textArea; + } + } + + public JComponent getPanel() { + return mainPanel; + } + + public void setParams(T params) { + int i = 0; + PamParameterData newParamData = null; + Object data = null; + for (PamParameterData paramData : this.parameterSet) { + // find the parameter in the new parameters (parameterSet is just a formatting placeholder) + try { + newParamData = params.getParameterSet().findParameterData(paramData.getFieldName()); + } catch (FieldNotFoundException e) { + e.printStackTrace(); + } + try { + data = newParamData.getData(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + if (data != null) { + textComponents[i].setText(data.toString()); + } + else { + textComponents[i].setText(null); + } + i++; + } + } + + public boolean getParams(T params) { + int i = 0; + PamParameterData newParamData = null; + Object data = null; + for (PamParameterData paramData : this.parameterSet) { + // find the parameter in the new parameters (parameterSet is just a formatting placeholder) + try { + newParamData = params.getParameterSet().findParameterData(paramData.getFieldName()); + } catch (FieldNotFoundException e) { + e.printStackTrace(); + } + String txt = textComponents[i].getText(); + try { + newParamData.setData(txt); + } catch (IllegalArgumentException | IllegalAccessException e) { + String msg = "Invalid parameter. Data type should be " + paramData.getField().getType().getName(); + return PamDialog.showWarning(null, newParamData.getShortName(), msg); + } + + i++; + } + + return true; + } + +} diff --git a/src/PamUtils/Coordinate3d.java b/src/PamUtils/Coordinate3d.java index 57a859f4..a8b6d156 100644 --- a/src/PamUtils/Coordinate3d.java +++ b/src/PamUtils/Coordinate3d.java @@ -26,6 +26,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Class definition for a x,y coordinate number type. @@ -168,7 +169,7 @@ public class Coordinate3d implements Serializable , Cloneable, PamCoordinate, Ma @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/PamUtils/LatLong.java b/src/PamUtils/LatLong.java index 6b8f9df9..6d465ee6 100644 --- a/src/PamUtils/LatLong.java +++ b/src/PamUtils/LatLong.java @@ -15,6 +15,7 @@ import java.text.NumberFormat; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.PamConstants; import net.sf.geographiclib.Geodesic; import net.sf.geographiclib.PolygonArea; @@ -833,7 +834,7 @@ public class LatLong implements Serializable, Cloneable, Transferable, PamCoordi */ @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("height"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/PamUtils/PamCalendar.java b/src/PamUtils/PamCalendar.java index 79e2fd8e..2e1388f9 100644 --- a/src/PamUtils/PamCalendar.java +++ b/src/PamUtils/PamCalendar.java @@ -47,10 +47,7 @@ public class PamCalendar { public static TimeZone defaultTimeZone = TimeZone.getTimeZone("UTC"); - /* - * Not used: all now handled in PamCalendar. - */ -// private static TimeZone localTimeZone = defaultTimeZone;// TimeZone.getDefault(); + private static TimeZone localTimeZone = defaultTimeZone;// TimeZone.getDefault(); public static final long millisPerDay = 1000L*24L*3600L; @@ -63,7 +60,7 @@ public class PamCalendar { private static boolean soundFile; /** - * time from the start of the file to the current moment. + * time from the start of the file to the currentmoment. * This is updated every time data re read from the file, so is * accurate to about 1/10 second. * For accurate timing within detectors, always try to use sample number @@ -180,44 +177,8 @@ public class PamCalendar { public static TimeZone getDisplayTimeZone(boolean useLocal) { // return TimeZone.getTimeZone("UTC"); - return useLocal ? CalendarControl.getInstance().getChosenTimeZone() : defaultTimeZone; -// return useLocal ? localTimeZone : defaultTimeZone; - } - - /** - * Get the display time zone offset in milliseconds. - * @param useLocal - * @return - */ - public static long getDisplayTimeZoneOffest(boolean useLocal) { - TimeZone tz = getDisplayTimeZone(useLocal); - return tz.getOffset(getTimeInMillis()); - } - - /** - * Get a short string describing the time zone. This should be less than - * 10 characters. So if the full name of the TZ is long, then write it - * in the format "UTC+..." - * @param useLocal - * @return - */ - public static String getShortDisplayTimeZoneString(boolean useLocal) { - TimeZone tz = getDisplayTimeZone(useLocal); - String str = tz.getDisplayName(); - str = CalendarControl.getInstance().getTZCode(true); - if (str.length() <= 10) { - return str; - } - // otherwise make up a string. - long offset = getDisplayTimeZoneOffest(useLocal) / 1000; - boolean isInt = offset % 3600 == 0; - if (isInt) { - str = String.format("UTC%+d", offset/3600); - } - else { - str = String.format("UTC%+3.1f", (double) offset/3600.); - } - return str; +// return useLocal ? CalendarControl.getInstance().getChosenTimeZone() : defaultTimeZone; + return useLocal ? localTimeZone : defaultTimeZone; } public static String formatDateTime(Date date) { @@ -430,13 +391,8 @@ public class PamCalendar { public static String formatDBStyleTime(long timeInMillis, boolean showMillis, boolean useLocal) { Calendar c = Calendar.getInstance(); - TimeZone tz = getDisplayTimeZone(useLocal); -// if (tz != null) { -// long offs = tz.getOffset(timeInMillis); -// timeInMillis += tz.getOffset(timeInMillis); -// } c.setTimeInMillis(timeInMillis); - c.setTimeZone(tz); + c.setTimeZone(getDisplayTimeZone(useLocal)); DateFormat df; if (showMillis) { df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); @@ -444,7 +400,7 @@ public class PamCalendar { else { df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } - df.setTimeZone(tz); + df.setTimeZone(getDisplayTimeZone(useLocal)); Date d = c.getTime(); // return String.format("%tY-% implements PamWorkWrapper result) { oldFileList = result; + sortFiles(result); fileListUser.newFileList(result); } diff --git a/src/PamView/ColourArray.java b/src/PamView/ColourArray.java index edbdb61d..51f6c531 100644 --- a/src/PamView/ColourArray.java +++ b/src/PamView/ColourArray.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * A series of functions for creating arrays of colours @@ -410,7 +411,7 @@ public class ColourArray implements Cloneable, Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/PamView/GeneralProjector.java b/src/PamView/GeneralProjector.java index b9aa21e4..5329d10c 100644 --- a/src/PamView/GeneralProjector.java +++ b/src/PamView/GeneralProjector.java @@ -265,6 +265,11 @@ public abstract class GeneralProjector { JComponent toolTipComponent; + /** + * Gets an adapter that can provide tooltips automatically based on plotted data units. + * @param component + * @return + */ public MouseHoverAdapter getMouseHoverAdapter(JComponent component) { ToolTipManager tt = ToolTipManager.sharedInstance(); tt.registerComponent(component); @@ -384,7 +389,9 @@ public abstract class GeneralProjector { } String hintText = dataBlock.getHoverText(this, hoveredDataUnit, hoverData.get(unitIndex).getAmbiguity()); - if (hintText == null) return null; + if (hintText == null) { + return null; + } // System.out.println(hintText); return hintText; } diff --git a/src/PamView/GroupedSourceParameters.java b/src/PamView/GroupedSourceParameters.java index f26cdafd..fb0b7509 100644 --- a/src/PamView/GroupedSourceParameters.java +++ b/src/PamView/GroupedSourceParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamUtils; import PamView.dialog.GroupedSourcePanel; @@ -210,7 +211,7 @@ public class GroupedSourceParameters implements Serializable, Cloneable, Managed */ @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/PamView/GuiFrameSettings.java b/src/PamView/GuiFrameSettings.java index d367c1e3..3445c790 100644 --- a/src/PamView/GuiFrameSettings.java +++ b/src/PamView/GuiFrameSettings.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import PamController.PamControlledUnit; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; /** @@ -55,7 +56,7 @@ public class GuiFrameSettings implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("unitFrameInfo"); ps.put(new PrivatePamParameterData(this, field) { @@ -89,7 +90,7 @@ public class GuiFrameSettings implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("guiFrame"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/PamView/PamGui.java b/src/PamView/PamGui.java index 0ebec8a3..ac51f1bc 100644 --- a/src/PamView/PamGui.java +++ b/src/PamView/PamGui.java @@ -61,6 +61,7 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JRootPane; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; @@ -73,6 +74,7 @@ import javax.swing.event.MenuListener; import Acquisition.DaqSystemInterface; import annotation.tasks.AnnotationManager; +import metadata.MetaDataContol; import performanceTests.PerformanceDialog; import tipOfTheDay.TipOfTheDayManager; import Array.ArrayManager; @@ -601,17 +603,17 @@ public class PamGui extends PamView implements WindowListener, PamSettings { fileMenu.add(menuItem); } - if (SMRUEnable.isEnable()) { - menuItem = new JMenuItem("Import PAMGuard Modules"); - menuItem.setToolTipText("Import module settings from a different PAMGuard configuration (psfx files only"); - menuItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - importSettings(); - } - }); - fileMenu.add(menuItem); - } + // if (SMRUEnable.isEnable()) { + menuItem = new JMenuItem("Import PAMGuard Modules"); + menuItem.setToolTipText("Import module settings from a different PAMGuard configuration (psfx files only"); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + importSettings(); + } + }); + fileMenu.add(menuItem); +// } fileMenu.addSeparator(); @@ -761,6 +763,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings { //for changing "hydrophones" to "microphone" and vice versa if medium changes. menu.addMenuListener(new SettingsMenuListener()); + menu.add(MetaDataContol.getMetaDataControl().createMenu(frame)); menu.addSeparator(); @@ -1265,7 +1268,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings { class menuPamStart implements ActionListener { public void actionPerformed(ActionEvent ev){ - pamControllerInterface.pamStart(); + pamControllerInterface.manualStart(); } } @@ -1282,7 +1285,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings { class menuPamStop implements ActionListener { public void actionPerformed(ActionEvent ev){ - pamControllerInterface.pamStop(); + pamControllerInterface.manualStop(); // enableLoggingMenu(); } } @@ -1666,10 +1669,10 @@ public class PamGui extends PamView implements WindowListener, PamSettings { protected void getGuiParameters() { guiParameters.extendedState = frame.getExtendedState(); guiParameters.state = frame.getState(); - if (guiParameters.state != Frame.MAXIMIZED_BOTH) { +// if (guiParameters.state != Frame.MAXIMIZED_BOTH) { guiParameters.size = frame.getSize(); guiParameters.bounds = frame.getBounds(); - } +// } } /** @@ -1984,6 +1987,30 @@ public class PamGui extends PamView implements WindowListener, PamSettings { public PamTabbedPane getTabbedPane() { return this.mainTab; } + + /** + * find a parent window for a JComponent. This can be useful in + * finding windows to open child dialogs when the object holding + * the component may not have a direct reference back to it's dialog. + * @param component any Swing component + * @return parent Window (or frame) if it can be found + */ + public static Window findComponentWindow(JComponent component) { + if (component == null) { + return null; + } + JRootPane root = component.getRootPane(); + if (root == null) { + return null; + } + Container rootP = root.getParent(); + if (rootP instanceof Window) { + return (Window) rootP; + } + else { + return null; + } + } } \ No newline at end of file diff --git a/src/PamView/PamSymbol.java b/src/PamView/PamSymbol.java index 00c471f6..2a4f4061 100644 --- a/src/PamView/PamSymbol.java +++ b/src/PamView/PamSymbol.java @@ -38,6 +38,7 @@ import javax.swing.JPanel; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.PamColors.PamColor; import PamView.symbol.SymbolData; @@ -808,7 +809,7 @@ public class PamSymbol extends PamSymbolBase implements Serializable, Icon, Clon @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/PamView/dialog/warn/WarnOnce.java b/src/PamView/dialog/warn/WarnOnce.java index 93ed4618..cd7ad08d 100644 --- a/src/PamView/dialog/warn/WarnOnce.java +++ b/src/PamView/dialog/warn/WarnOnce.java @@ -48,6 +48,7 @@ public class WarnOnce implements PamSettings { int ans = showWarning(parent, "Warning Messages", "Show all PAMGuard warning messages", WarnOnce.OK_CANCEL_OPTION); if (ans == WarnOnce.CANCEL_OPTION) return; singleInstance.warnOnceList.clearList(); + singleInstance.showThisSess.clear(); } @Override diff --git a/src/PamView/panel/SplitPanePositionData.java b/src/PamView/panel/SplitPanePositionData.java new file mode 100644 index 00000000..b7207e6e --- /dev/null +++ b/src/PamView/panel/SplitPanePositionData.java @@ -0,0 +1,62 @@ +package PamView.panel; + +import java.io.Serializable; + +public class SplitPanePositionData implements Serializable { + + + public static final long serialVersionUID = 1L; + private int position; + private double propPosition; + private int height; + + + public SplitPanePositionData(int position, double propPosition, int height) { + super(); + this.position = position; + this.setHeight(height); + this.setPropPosition(propPosition); + } + + /** + * @return the position + */ + public int getPosition() { + return position; + } + + /** + * @param position the position to set + */ + public void setPosition(int position) { + this.position = position; + } + + /** + * @return the propPosition + */ + public double getPropPosition() { + return propPosition; + } + + /** + * @param propPosition the propPosition to set + */ + public void setPropPosition(double propPosition) { + this.propPosition = propPosition; + } + + /** + * @return the height + */ + public int getHeight() { + return height; + } + + /** + * @param height the height to set + */ + public void setHeight(int height) { + this.height = height; + } +} diff --git a/src/PamView/panel/SplitPanePositioner.java b/src/PamView/panel/SplitPanePositioner.java new file mode 100644 index 00000000..f6bc4190 --- /dev/null +++ b/src/PamView/panel/SplitPanePositioner.java @@ -0,0 +1,95 @@ +package PamView.panel; + +import java.io.Serializable; + +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; + +import PamController.PamControlledUnitSettings; +import PamController.PamSettingManager; +import PamController.PamSettings; + +/** + * Class that will remember and reset the position of a split pane. Any split pane. + * Just call this constructor with a unique name and the splitPane and a default + * between 0 and 1 and it will register itself automatically with PamSettings. + * @author dg50 + * + */ +public class SplitPanePositioner implements PamSettings { + + private static final String unitType = "Split Pane Position"; + + private String unitName; + + private JSplitPane splitPane; + + /** + * Constructor for split pane positioner. Just call this constructor for each + * split pane, then forget about it. This will have been registered with + * PamSettings and will handle everything, restoring the split pane position + * when PAMGuard is restarted. + * @param unitName A unique name for the split pane. + * @param splitPane reference to an existing split pane. + * @param proportionalDefault default position (0 < position < 1). + */ + public SplitPanePositioner(String unitName, JSplitPane splitPane, double proportionalDefault) { + super(); + this.splitPane = splitPane; + this.unitName = unitName; + boolean exists = PamSettingManager.getInstance().registerSettings(this); + if (exists == false) { + // use the default + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + splitPane.setDividerLocation(proportionalDefault); + } + }); + } + } + + @Override + public String getUnitName() { + return unitName; + } + + @Override + public String getUnitType() { + return unitType; + } + + @Override + public Serializable getSettingsReference() { +// System.out.printf("Save split position %s as %d out of %d\n", unitName, splitPane.getDividerLocation(), splitPane.getHeight()); + double propPosition = (double) splitPane.getDividerLocation() / (double) splitPane.getHeight(); + SplitPanePositionData posData = new SplitPanePositionData(splitPane.getDividerLocation(), propPosition, splitPane.getHeight()); + return posData; + } + + @Override + public long getSettingsVersion() { + return SplitPanePositionData.serialVersionUID; + } + + @Override + public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { + + SplitPanePositionData posData = (SplitPanePositionData) pamControlledUnitSettings.getSettings(); + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + int newPos = posData.getPosition() + splitPane.getHeight() - posData.getHeight(); +// System.out.printf("Set split %s position to %d or %3.3f of %d\n", unitName, +// posData.getPosition(), posData.getPropPosition(), splitPane.getHeight()); + splitPane.setDividerLocation(posData.getPosition()); + } + }); + return true; + } + + + +} diff --git a/src/PamView/paneloverlay/OverlayDataInfo.java b/src/PamView/paneloverlay/OverlayDataInfo.java index 3c3ed86b..fd590d82 100644 --- a/src/PamView/paneloverlay/OverlayDataInfo.java +++ b/src/PamView/paneloverlay/OverlayDataInfo.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class OverlayDataInfo implements Serializable, Cloneable, ManagedParameters { @@ -31,7 +32,7 @@ public class OverlayDataInfo implements Serializable, Cloneable, ManagedParamete */ @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java b/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java index f6c8d446..ae081fc1 100644 --- a/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java +++ b/src/PamView/paneloverlay/overlaymark/MarkDataSelectorParams.java @@ -6,6 +6,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamguardMVC.PamDataBlock; @@ -73,7 +74,7 @@ public class MarkDataSelectorParams implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("overlayChoices"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/PamView/symbol/ManagedSymbolData.java b/src/PamView/symbol/ManagedSymbolData.java index 23bb555d..19789f61 100644 --- a/src/PamView/symbol/ManagedSymbolData.java +++ b/src/PamView/symbol/ManagedSymbolData.java @@ -3,7 +3,11 @@ package PamView.symbol; import java.io.Serializable; import java.util.Hashtable; -public class ManagedSymbolData implements Cloneable, Serializable { +import PamModel.parametermanager.ManagedParameters; +import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; + +public class ManagedSymbolData implements Cloneable, Serializable, ManagedParameters { public static final long serialVersionUID = 1L; @@ -34,5 +38,10 @@ public class ManagedSymbolData implements Cloneable, Serializable { return symbolOptions; } + @Override + public PamParameterSet getParameterSet() { + return PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); + } + } diff --git a/src/PamView/wizard/PamWizard.java b/src/PamView/wizard/PamWizard.java new file mode 100644 index 00000000..9ba67e01 --- /dev/null +++ b/src/PamView/wizard/PamWizard.java @@ -0,0 +1,160 @@ +package PamView.wizard; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.JButton; +import javax.swing.JPanel; + +import PamView.dialog.PamDialog; +import tethys.swing.export.ExportStreamInfoPanel; +import tethys.swing.export.ExportWizardCard; + +abstract public class PamWizard extends PamDialog { + + private static final long serialVersionUID = 1L; + + private JPanel cardPanel; + + private CardLayout cardLayout; + + private JPanel mainPanel; + + private JButton prevButton; + + private ArrayList wizardCards = new ArrayList(); + + public PamWizard(Window parentFrame, String title) { + super(parentFrame, title, false); + + cardLayout = new CardLayout(); + mainPanel = new JPanel(new BorderLayout()); + cardPanel = new JPanel(cardLayout); + mainPanel.add(BorderLayout.CENTER, cardPanel); + + setDialogComponent(mainPanel); + + getOkButton().setText("Finish"); + prevButton = new JButton("Previous"); + getButtonPanel().add(prevButton, 0); + prevButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + previousButton(); + } + }); + + setResizable(true); + } + + public void addCard(PamWizardCard wizPanel) { + cardPanel.add(wizPanel, wizPanel.getTitle()); + wizardCards.add(wizPanel); + } + + /** + * Get the main panel. This is the main dialog panel and uses a borderlayout + * with the cards in the CENTER of the panel. Additional information panels + * (generally fixed and not changing with the dialog) can be added NORTH, SOUTH, WEST and EAST. + * @return main Panel. + */ + public JPanel getMainPanel() { + return mainPanel; + } + + /** + * Called when 'previous' button is clicked. + */ + protected void previousButton() { + cardLayout.previous(cardPanel); + enableControls(); + } + + public void enableControls() { + int iCard = getCardIndex(); + prevButton.setEnabled(iCard > 0); + boolean isLast = iCard == wizardCards.size()-1; +// getOkButton().setEnabled(!isLast); + getOkButton().setText(isLast ? "Finish" : "Next"); + } + + private boolean checkCurrentCard() { + int iCard = getCardIndex(); + if (iCard < 0) { + return true; + } + return getCardParams(wizardCards.get(iCard)); + } + + abstract public void setCardParams(PamWizardCard wizardCard); + + abstract public boolean getCardParams(PamWizardCard wizardCard); + + public int getCardIndex() { + for (int i = 0; i < cardPanel.getComponentCount(); i++) { + Component component = cardPanel.getComponent(i); + if (component.isVisible()) { + return i; + } + } + return -1; + } + + public JButton getPreviousButton() { + return prevButton; + } + + public void setParams() { + for (PamWizardCard wizCard : wizardCards) { + setCardParams(wizCard); + } + enableControls(); + } + + @Override + public boolean getParams() { + /** + * This is the OK button, so we need to NOT return OK, which would close the + * dialog until we're on the last card. + */ + if (checkCurrentCard() == false) { + return false; + } + int iCard = getCardIndex(); + if (iCard < wizardCards.size()-1) { + cardLayout.next(cardPanel); + enableControls(); + return false; + } + + return true; + } + + + + @Override + public void restoreDefaultSettings() { + // TODO Auto-generated method stub + + } + + /** + * Move to the first card in the stack + */ + public void moveFirst() { + cardLayout.first(cardPanel); + } + + /** + * Move to the last card in the stack + */ + public void moveLast() { + cardLayout.last(cardPanel); + } + +} diff --git a/src/PamView/wizard/PamWizardCard.java b/src/PamView/wizard/PamWizardCard.java new file mode 100644 index 00000000..7d4fa88c --- /dev/null +++ b/src/PamView/wizard/PamWizardCard.java @@ -0,0 +1,43 @@ +package PamView.wizard; + +import javax.swing.JPanel; + + +/** + * Base class for PAMGuard wizard cards. + * @author dg50 + * + * @param class type for parameters to set and get. + */ +abstract public class PamWizardCard extends JPanel { + + private static final long serialVersionUID = 1L; + + private String title; + + private PamWizard pamWizard; + + /** + * @param title + */ + public PamWizardCard(PamWizard pamWizard, String title) { + this.pamWizard = pamWizard; + this.title = title; + } + + public abstract boolean getParams(T cardParams); + + public abstract void setParams(T cardParams); + + public String getTitle() { + return title; + } + + /** + * @return the pamWizard + */ + public PamWizard getPamWizard() { + return pamWizard; + } + +} diff --git a/src/PamguardMVC/AcousticDataBlock.java b/src/PamguardMVC/AcousticDataBlock.java index ec7477c1..f7fb5c8e 100644 --- a/src/PamguardMVC/AcousticDataBlock.java +++ b/src/PamguardMVC/AcousticDataBlock.java @@ -1,5 +1,8 @@ package PamguardMVC; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import PamController.PamControllerInterface; import PamguardMVC.nanotime.NanosFromSamples; @@ -90,5 +93,12 @@ abstract public class AcousticDataBlock extends PamD return parentSourceData; } + @Override + public Element getDataBlockXML(Document doc) { + Element el = super.getDataBlockXML(doc); + el.setAttribute("SampleRate", String.format("%3.1f", getSampleRate())); + return el; + } + } diff --git a/src/PamguardMVC/DataAutomation.java b/src/PamguardMVC/DataAutomation.java new file mode 100644 index 00000000..cd424c60 --- /dev/null +++ b/src/PamguardMVC/DataAutomation.java @@ -0,0 +1,29 @@ +package PamguardMVC; + +/** + * @author dg50 + * Levels of automation for the various datas in PAMGuard. + * Should be used within DataAutomationInfo to perhaps combine with other info in the future. + * + */ +public enum DataAutomation { + + AUTOMATIC, MANUAL, MANUALANDAUTOMATIC; + + @Override + public String toString() { + switch (this) { + case AUTOMATIC: + return "Automatic"; + case MANUAL: + return "Manual"; + case MANUALANDAUTOMATIC: + return "Manual and automatic"; + default: + break; + + } + return null; + } + +} diff --git a/src/PamguardMVC/DataAutomationInfo.java b/src/PamguardMVC/DataAutomationInfo.java new file mode 100644 index 00000000..42c7e42d --- /dev/null +++ b/src/PamguardMVC/DataAutomationInfo.java @@ -0,0 +1,44 @@ +package PamguardMVC; + +/** + * Returned by datablocks, though default is null, to give information on how + * automatic the process was. + * @author dg50 + * + */ +public class DataAutomationInfo { + + + private DataAutomation automation; + + /** + * @param automation + */ + public DataAutomationInfo(DataAutomation automation) { + this.setAutomation(automation); + } + + /** + * @return the automation + */ + public DataAutomation getAutomation() { + return automation; + } + + /** + * @param automation the automation to set + */ + public void setAutomation(DataAutomation automation) { + this.automation = automation; + } + + @Override + public String toString() { + if (automation == null) { + return "Unknown data automation"; + } + return automation.toString(); + } + + +} diff --git a/src/PamguardMVC/DataBlock2D.java b/src/PamguardMVC/DataBlock2D.java index beae1e15..89eb0ec9 100644 --- a/src/PamguardMVC/DataBlock2D.java +++ b/src/PamguardMVC/DataBlock2D.java @@ -1,5 +1,8 @@ package PamguardMVC; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import dataPlotsFX.data.DataTypeInfo; abstract public class DataBlock2D extends AcousticDataBlock { @@ -39,4 +42,18 @@ abstract public class DataBlock2D extends AcousticDat * @return data type information. */ abstract public DataTypeInfo getScaleInfo(); + + public Element getDataBlockXML(Document doc) { + Element el = super.getDataBlockXML(doc); + DataTypeInfo dti = getScaleInfo(); + if (dti != null) { + if (dti.dataType != null) { + el.setAttribute("DataType", dti.dataType.toString()); + } + if (dti.dataUnits != null) { + el.setAttribute("DataUnits", dti.dataUnits.toString()); + } + } + return el; + } } diff --git a/src/PamguardMVC/PamDataBlock.java b/src/PamguardMVC/PamDataBlock.java index 97bd709c..3bcce61a 100644 --- a/src/PamguardMVC/PamDataBlock.java +++ b/src/PamguardMVC/PamDataBlock.java @@ -44,10 +44,16 @@ import javax.swing.Timer; import javax.swing.border.EmptyBorder; import org.springframework.core.GenericTypeResolver; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import Acquisition.AcquisitionControl; import Acquisition.AcquisitionProcess; import pamScrollSystem.ViewLoadObserver; +import tethys.TethysControl; +import tethys.pamdata.AutoTethysProvider; +import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; import dataGram.DatagramProvider; import dataMap.BespokeDataMapGraphic; import dataMap.OfflineDataMap; @@ -62,6 +68,7 @@ import PamController.PamController; import PamController.PamControllerInterface; import PamDetection.LocContents; import PamDetection.LocalisationInfo; +import PamDetection.PamDetection; import PamUtils.PamCalendar; import PamUtils.PamUtils; import PamView.symbol.PamSymbolManager; @@ -69,8 +76,10 @@ import PamguardMVC.background.BackgroundDataBlock; import PamguardMVC.background.BackgroundManager; import PamguardMVC.dataOffline.OfflineDataLoadInfo; import PamguardMVC.dataOffline.OfflineDataLoading; +import PamguardMVC.dataSelector.DataSelectParams; import PamguardMVC.dataSelector.DataSelector; import PamguardMVC.dataSelector.DataSelectorCreator; +import PamguardMVC.dataSelector.DataSelectorSettings; import PamguardMVC.dataSelector.NullDataSelectorCreator; import PamguardMVC.datamenus.DataMenuParent; import PamguardMVC.nanotime.NanoTimeCalculator; @@ -2155,7 +2164,7 @@ public class PamDataBlock extends PamObservable { */ @Override public String toString() { - return getDataName(); + return getLongDataName(); } /** @@ -2833,7 +2842,7 @@ public class PamDataBlock extends PamObservable { * @return temporary copy of the data */ public ArrayList getDataCopy(long t1, long t2, boolean assumeOrder, DataSelector dataSelector) { - if (dataSelector == null) { + if (dataSelector == null || dataSelector.getParams().getCombinationFlag() == DataSelectParams.DATA_SELECT_DISABLE) { return getDataCopy(t1, t2, assumeOrder); } else { @@ -2865,6 +2874,7 @@ public class PamDataBlock extends PamObservable { private SQLLogging logging; private JSONObjectDataSource jsonDataSource; + public Vector getProcessAnnotations() { return processAannotations; @@ -3074,6 +3084,34 @@ public class PamDataBlock extends PamObservable { public SQLLogging getLogging() { return logging; } + + /** + * Gets a data provider for Tethys. These will probably need + * to be bespoke, but for now will autogenerate based on the SQLLogging information. + * @return the tethysDataProvider + */ + public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) { + return null; + } + + /** + * Get the level of automation employed by the generation of these data. + * Should ideally be completed for everything providing data to Tethys. + * @return level of automation for this data block. + */ + public DataAutomationInfo getDataAutomationInfo() { + return null; + } + + /** + * Get information about species types that may occur within this data + * block. Primarily for conversion into Tethys compatible data, but may + * prove to have other uses. + * @return Types of species information available within this datablock. + */ + public DataBlockSpeciesManager getDatablockSpeciesManager() { + return null; + } final public boolean getCanLog() { return (logging != null); @@ -4229,4 +4267,42 @@ public class PamDataBlock extends PamObservable { public void setBackgroundManager(BackgroundManager backgroundManager) { this.backgroundManager = backgroundManager; } + + /** + * Get a brief summary of datablock to include in XML descriptions. + * Basic output is very simple. Expect other datablock to extend this by + * adding additional attributes. + * @param doc + * @return XML element with description of data. + */ + public Element getDataBlockXML(Document doc) { + Element inputEl = doc.createElement("Input"); + if (getParentProcess() != null && getParentProcess().getPamControlledUnit() != null) { + PamControlledUnit pcu = getParentProcess().getPamControlledUnit(); + inputEl.setAttribute("ModuleType", pcu.getUnitType()); + inputEl.setAttribute("ModuleName", pcu.getUnitName()); + } + inputEl.setAttribute("Name", getLongDataName()); + inputEl.setAttribute("Channels", String.format("0x%X", getChannelMap())); + return inputEl; + } + + /** + * Look in every data block, particularly threaded ones, and dump + * the buffer status. This will have to go via PamProcess so that + * additional information can be added from any processes that + * hold additional data in other internal buffers. + * @param message Message to print prior to dumping buffers for debug. + * @param sayEmpties dump info even if a buffer is empty (otherwise, only ones that have stuff still) + */ + public void dumpBufferStatus(String message, boolean sayEmpties) { + int nObs = countObservers(); + for (int i = 0; i < nObs; i++) { + PamObserver obs = getPamObserver(i); + if (obs instanceof ThreadedObserver) { + ThreadedObserver tObs = (ThreadedObserver) obs; + tObs.dumpBufferStatus(message, sayEmpties); + } + } + } } diff --git a/src/PamguardMVC/PamDataUnit.java b/src/PamguardMVC/PamDataUnit.java index 3295381f..8630a7d1 100644 --- a/src/PamguardMVC/PamDataUnit.java +++ b/src/PamguardMVC/PamDataUnit.java @@ -974,8 +974,13 @@ abstract public class PamDataUnit // add frequency and amplitude information - str += "Frequency: " + FrequencyFormat.formatFrequencyRange(this.getFrequency(), true) + "
"; - str += String.format("Amplitude: %3.1fdB
", getAmplitudeDB()); + double[] frequency = this.getFrequency(); + if (frequency != null) { + str += "Frequency: " + FrequencyFormat.formatFrequencyRange(this.getFrequency(), true) + "
"; + } + if (getAmplitudeDB() != 0) { + str += String.format("Amplitude: %3.1fdB
", getAmplitudeDB()); + } if (getSignalSPL() != null) { str += String.format("SPL: %3.1fdBre1uPa
",linAmplitudeToDB(getSignalSPL())); } diff --git a/src/PamguardMVC/PamObservable.java b/src/PamguardMVC/PamObservable.java index 0d693c99..46d149d9 100644 --- a/src/PamguardMVC/PamObservable.java +++ b/src/PamguardMVC/PamObservable.java @@ -208,6 +208,14 @@ public class PamObservable {//extends PanelOverlayDraw { if (System.currentTimeMillis() - startTime > timeOutms) { // have taken too long, so return that we've failed. System.out.println("Wait timeout in threaded observer"); + // and clear everything that's left. + for (int i = 0; i < pamObservers.size(); i++) { + pamObserver = pamObservers.get(i); + if (pamObserver.getClass() == ThreadedObserver.class) { + threadedObserver = (ThreadedObserver) pamObserver; + threadedObserver.clearEverything(); + } + } return false; } try { diff --git a/src/PamguardMVC/PamProcess.java b/src/PamguardMVC/PamProcess.java index 3d43f05b..e6321207 100644 --- a/src/PamguardMVC/PamProcess.java +++ b/src/PamguardMVC/PamProcess.java @@ -767,7 +767,7 @@ abstract public class PamProcess implements PamObserver, ProcessAnnotator { } }); - private int lastSourceNotificationType; + private volatile int lastSourceNotificationType; private Object lastSourceNotificationObject; @@ -1065,4 +1065,24 @@ abstract public class PamProcess implements PamObserver, ProcessAnnotator { return lastSourceNotificationObject; } + /** + * Say the status of any buffers, particularly in output buffers of + * data blocks, but can add bespoke info for other internal buffers + * for some processes. + * @param message + * @param sayEmpties include info even if a buffer is empty. + */ + public void dumpBufferStatus(String message, boolean sayEmpties) { + ArrayList outputs = getOutputDataBlocks(); + try { + for (PamDataBlock output : outputs) { + output.dumpBufferStatus(message, sayEmpties); + } + } + catch (Exception e) { + System.err.println("Error dumping buffer data from process " + getProcessName()); + e.printStackTrace(); + } + } + } diff --git a/src/PamguardMVC/PamRawDataBlock.java b/src/PamguardMVC/PamRawDataBlock.java index eda2bb30..f1246242 100644 --- a/src/PamguardMVC/PamRawDataBlock.java +++ b/src/PamguardMVC/PamRawDataBlock.java @@ -145,6 +145,17 @@ public class PamRawDataBlock extends AcousticDataBlock { } } + /** + * Reset data integrity checking counters. + */ + public void reset() { + prevChannelSample = new long[PamConstants.MAX_CHANNELS]; + summaryTotals = new double[PamConstants.MAX_CHANNELS]; + summaryTotals2 = new double[PamConstants.MAX_CHANNELS]; + summaryMaxVal = new double[PamConstants.MAX_CHANNELS]; + summaryCount = new int[PamConstants.MAX_CHANNELS]; + } + @Override public void addPamData(RawDataUnit pamDataUnit) { /* diff --git a/src/PamguardMVC/RawDataDisplayOptions.java b/src/PamguardMVC/RawDataDisplayOptions.java index 9ed8355c..6ff49562 100644 --- a/src/PamguardMVC/RawDataDisplayOptions.java +++ b/src/PamguardMVC/RawDataDisplayOptions.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class RawDataDisplayOptions implements Serializable, Cloneable, ManagedParameters { @@ -13,7 +14,7 @@ public class RawDataDisplayOptions implements Serializable, Cloneable, ManagedPa @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/PamguardMVC/RawDataUnavailableException.java b/src/PamguardMVC/RawDataUnavailableException.java index 581f981d..37e4275a 100644 --- a/src/PamguardMVC/RawDataUnavailableException.java +++ b/src/PamguardMVC/RawDataUnavailableException.java @@ -61,7 +61,7 @@ public class RawDataUnavailableException extends Exception { return String.format("Samples %d length %d requested from %s have not yet arrived", startSample, duration, rawDataBlock.getDataName()); case INVALID_CHANNEL_LIST: - return String.format("Samples %d length %d requested from %s do not contain the reqeusted channels %s", + return String.format("Samples %d length %d requested from %s do not contain the reqeusted channels", startSample, duration, rawDataBlock.getDataName()); case NEGATIVE_DURATION: return String.format("Negative data duration request for %d samples" , duration); diff --git a/src/PamguardMVC/ThreadedObserver.java b/src/PamguardMVC/ThreadedObserver.java index 806cf607..83713af0 100644 --- a/src/PamguardMVC/ThreadedObserver.java +++ b/src/PamguardMVC/ThreadedObserver.java @@ -444,6 +444,7 @@ public class ThreadedObserver implements PamObserver { else { emptyRead = false; int lc=0; + ObservedObject observedObject; while (!toDoList.isEmpty()) { // if (stopFlag) { @@ -458,11 +459,21 @@ public class ThreadedObserver implements PamObserver { // get the first object, send it for processing and then remove from the list - ObservedObject observedObject = toDoList.get(0); - performAction(observedObject); synchronized(synchLock) { - toDoList.remove(0); + if (toDoList.size() > 0) { + observedObject = toDoList.remove(0); + } + else { + break; + } } + // need to do this bit outside of the synch block. + performAction(observedObject); +// synchronized(synchLock) { +// if (toDoList.size() > 0) { // list may have been cleared during a shut down. +// toDoList.remove(0); +// } +// } } } } @@ -525,4 +536,21 @@ public class ThreadedObserver implements PamObserver { } } + + public void clearEverything() { + synchronized (synchLock) { + System.out.printf("Clearing %d objects from todo list in %s\n", toDoList.size(), singleThreadObserver.getObserverName()); + toDoList.clear(); + } + } + + public void dumpBufferStatus(String message, boolean sayEmpties) { + int n = toDoList.size(); + if (sayEmpties == false && n == 0) { + return; + } + String name = singleThreadObserver.getObserverName(); + System.out.printf("Threaded observer %s has %d objects in queue\n", name, n); + } + } diff --git a/src/PamguardMVC/blockprocess/PamBlockParams.java b/src/PamguardMVC/blockprocess/PamBlockParams.java index 249d98e1..aaaed713 100644 --- a/src/PamguardMVC/blockprocess/PamBlockParams.java +++ b/src/PamguardMVC/blockprocess/PamBlockParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import gpl.GPLParameters; /** @@ -44,7 +45,7 @@ public class PamBlockParams implements Cloneable, Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/PamguardMVC/dataSelector/CompoundParams.java b/src/PamguardMVC/dataSelector/CompoundParams.java index d63f1957..6f80972e 100644 --- a/src/PamguardMVC/dataSelector/CompoundParams.java +++ b/src/PamguardMVC/dataSelector/CompoundParams.java @@ -19,4 +19,10 @@ public class CompoundParams extends DataSelectParams { public DataSelectParams getSelectorParams(DataSelector dataSelector) { return selectorParams.get(dataSelector.getLongSelectorName()); } + + @Override + public int getCombinationFlag() { + return DATA_SELECT_AND; + } + } diff --git a/src/PamguardMVC/dataSelector/DataSelectParams.java b/src/PamguardMVC/dataSelector/DataSelectParams.java index da0f5e74..0d4af3fb 100644 --- a/src/PamguardMVC/dataSelector/DataSelectParams.java +++ b/src/PamguardMVC/dataSelector/DataSelectParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Data select parameters. @@ -53,7 +54,7 @@ abstract public class DataSelectParams implements Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/PamguardMVC/dataSelector/DataSelector.java b/src/PamguardMVC/dataSelector/DataSelector.java index 0503479f..b033976c 100644 --- a/src/PamguardMVC/dataSelector/DataSelector.java +++ b/src/PamguardMVC/dataSelector/DataSelector.java @@ -9,7 +9,10 @@ import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JMenuItem; +import org.w3c.dom.Document; + import PamController.PamController; +import PamController.settings.output.xml.PamguardXMLWriter; import PamView.dialog.PamDialogPanel; import PamView.dialog.SettingsButton; import PamguardMVC.PamDataBlock; @@ -39,7 +42,7 @@ public abstract class DataSelector { private String selectorTitle; private boolean allowScores; - + /** * Create a data selector for a DataBlock. If allowScores is * true, then the selector MAY (but may not) offer a more complicated @@ -104,18 +107,8 @@ public abstract class DataSelector { if (parentFrame == null) { parentFrame = PamController.getMainFrame(); } - Window localWin = parentFrame; - DataSelectorChangeListener localChangeListener = changeListener; JMenuItem menuItem = new JMenuItem("Data selection ..."); - menuItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - boolean ok = showSelectDialog(localWin); - if (ok && changeListener != null) { - changeListener.selectorChange(DataSelector.this); - } - } - }); + menuItem.addActionListener(new ShowSettingsButton(parentFrame, changeListener)); return menuItem; } @@ -129,6 +122,24 @@ public abstract class DataSelector { return ok; } + /** + * Get descriptive text about the data selector which can be + * added to dialogs and other information panels. + * @return descriptive text. Default is a xml dump of params. + */ + public String getDescription() { + if (getParams() == null) { + return null; + } + PamguardXMLWriter xmlWriter = PamguardXMLWriter.getXMLWriter(); + Document doc = xmlWriter.writeOneObject(getParams()); + if (doc != null) { + String str = xmlWriter.getAsString(doc, true); + return str; + } + return null; + } + /** * Score a PAMDataUnit. this is used in preference * to a boolean select function so that the user can add different @@ -228,25 +239,40 @@ public abstract class DataSelector { * @param parentWindow */ public JButton getDialogButton(Window parentWindow) { + return getDialogButton(parentWindow, null); + } + /** + * Create a settings type button that can be inserted into a + * larger dialog. + * @param parentWindow + */ + + public JButton getDialogButton(Window parentWindow, DataSelectorChangeListener changeListener) { JButton button = new SettingsButton(); - button.addActionListener(new ShowSettingsButton(parentWindow)); + button.addActionListener(new ShowSettingsButton(parentWindow, changeListener)); button.setToolTipText("Data selection options for " + getSelectorTitle()); return button; } private class ShowSettingsButton implements ActionListener { private Window parentWindow; + private DataSelectorChangeListener changeListener; /** * @param parentWindow + * @param changeListener */ - public ShowSettingsButton(Window parentWindow) { + public ShowSettingsButton(Window parentWindow, DataSelectorChangeListener changeListener) { super(); this.parentWindow = parentWindow; + this.changeListener = changeListener; } @Override public void actionPerformed(ActionEvent e) { - showSelectDialog(parentWindow); + boolean ok = showSelectDialog(parentWindow); + if (ok && changeListener != null) { + changeListener.selectorChange(DataSelector.this); + } } } diff --git a/src/PamguardMVC/dataSelector/DataSelectorCreator.java b/src/PamguardMVC/dataSelector/DataSelectorCreator.java index 77e199b5..25dde7c1 100644 --- a/src/PamguardMVC/dataSelector/DataSelectorCreator.java +++ b/src/PamguardMVC/dataSelector/DataSelectorCreator.java @@ -200,7 +200,14 @@ public abstract class DataSelectorCreator implements PamSettings { return allSelectors.get(0); } else { - return new CompoundDataSelector(pamDataBlock, allSelectors, selectorName, allowScores, selectorType); + CompoundDataSelector selector = new CompoundDataSelector(pamDataBlock, allSelectors, selectorName, allowScores, selectorType); + // not needed since it get's done after this call anyway. +// DataSelectParams params = dataSelectorSettings.getParams(selectorName); +// if (params instanceof CompoundParams) { +// selector.setParams(params); +// } + + return selector; } } diff --git a/src/PamguardMVC/dataSelector/DataSelectorSettings.java b/src/PamguardMVC/dataSelector/DataSelectorSettings.java index f29c8103..df66d20e 100644 --- a/src/PamguardMVC/dataSelector/DataSelectorSettings.java +++ b/src/PamguardMVC/dataSelector/DataSelectorSettings.java @@ -7,6 +7,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DataSelectorSettings implements Serializable, ManagedParameters { @@ -42,7 +43,7 @@ public class DataSelectorSettings implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("selectorParams"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/PamguardMVC/datakeeper/DataKeeperSettings.java b/src/PamguardMVC/datakeeper/DataKeeperSettings.java index 446669c6..3765ef72 100644 --- a/src/PamguardMVC/datakeeper/DataKeeperSettings.java +++ b/src/PamguardMVC/datakeeper/DataKeeperSettings.java @@ -7,6 +7,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DataKeeperSettings implements Serializable, Cloneable, ManagedParameters { @@ -51,7 +52,7 @@ public class DataKeeperSettings implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("keepTimeData"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/PamguardMVC/toad/GenericTOADSourceParams.java b/src/PamguardMVC/toad/GenericTOADSourceParams.java index e0c2237c..cd12140a 100644 --- a/src/PamguardMVC/toad/GenericTOADSourceParams.java +++ b/src/PamguardMVC/toad/GenericTOADSourceParams.java @@ -6,6 +6,7 @@ import Localiser.DelayMeasurementParams; import Localiser.controls.RawOrFFTParams; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * General parameters for detection TOAD measurement. Is split @@ -67,7 +68,7 @@ public class GenericTOADSourceParams implements Cloneable, Serializable, Managed @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java b/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java index c08a3f68..3b7546c2 100644 --- a/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java +++ b/src/RightWhaleEdgeDetector/RWEBinaryDataSource.java @@ -218,7 +218,7 @@ public class RWEBinaryDataSource extends BinaryDataSource { binaryObjectData.getDataUnitBaseData().setSampleDuration(duration); // rweDataUnit = new RWEDataUnit(aSound.timeMilliseconds, channelMap, // startSample, duration, aSound); - rweDataUnit = new RWEDataUnit(binaryObjectData.getDataUnitBaseData(), aSound); + rweDataUnit = new RWEDataUnit(rweProcess, binaryObjectData.getDataUnitBaseData(), aSound); rweDataUnit.setSequenceBitmap(sequenceMap); double f[] = new double[2]; f[0] = aSound.minFreq * rweDataBlock.getSampleRate()/rweDataBlock.getFftLength(); diff --git a/src/RightWhaleEdgeDetector/RWEDataBlock.java b/src/RightWhaleEdgeDetector/RWEDataBlock.java index 1969bca0..90c9a616 100644 --- a/src/RightWhaleEdgeDetector/RWEDataBlock.java +++ b/src/RightWhaleEdgeDetector/RWEDataBlock.java @@ -2,19 +2,29 @@ package RightWhaleEdgeDetector; import PamView.GroupedDataSource; import PamView.GroupedSourceParameters; +import PamguardMVC.DataAutomation; +import PamguardMVC.DataAutomationInfo; import PamguardMVC.PamProcess; import PamguardMVC.dataOffline.OfflineDataLoadInfo; import PamguardMVC.dataSelector.DataSelectorCreator; import RightWhaleEdgeDetector.datasel.RWDataSelCreator; +import RightWhaleEdgeDetector.species.RWSpeciesManager; +import RightWhaleEdgeDetector.species.RWTethysDataProvider; import pamScrollSystem.ViewLoadObserver; +import tethys.TethysControl; +import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; import whistlesAndMoans.AbstractWhistleDataBlock; -public class RWEDataBlock extends AbstractWhistleDataBlock implements GroupedDataSource { +public class RWEDataBlock extends AbstractWhistleDataBlock implements GroupedDataSource { private double[] rwFreqRange = {50., 250.}; private RWEControl rweControl; private RWEProcess rweProcess; private RWDataSelCreator dataSelCreator; + + private RWSpeciesManager rwSpeciesManager; + private RWTethysDataProvider rwTethysDataProvider; public RWEDataBlock(RWEControl rweControl, String dataName, RWEProcess rweProcess, int channelMap) { @@ -53,4 +63,25 @@ public class RWEDataBlock extends AbstractWhistleDataBlock implements GroupedDat return dataSelCreator; } + @Override + public DataBlockSpeciesManager getDatablockSpeciesManager() { + if (rwSpeciesManager == null) { + rwSpeciesManager = new RWSpeciesManager(this); + } + return rwSpeciesManager; + } + + @Override + public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) { + if (rwTethysDataProvider == null) { + rwTethysDataProvider = new RWTethysDataProvider(tethysControl, rweProcess.getRweDataBlock()); + } + return rwTethysDataProvider; + } + + @Override + public DataAutomationInfo getDataAutomationInfo() { + return new DataAutomationInfo(DataAutomation.AUTOMATIC); + } + } diff --git a/src/RightWhaleEdgeDetector/RWEDataUnit.java b/src/RightWhaleEdgeDetector/RWEDataUnit.java index 226e0f64..c3144ebf 100644 --- a/src/RightWhaleEdgeDetector/RWEDataUnit.java +++ b/src/RightWhaleEdgeDetector/RWEDataUnit.java @@ -6,26 +6,31 @@ import whistlesAndMoans.AbstractWhistleDataUnit; public class RWEDataUnit extends AbstractWhistleDataUnit { public RWESound rweSound; + private RWEProcess rweProcess; - public RWEDataUnit(long timeMilliseconds, int channelBitmap, + public RWEDataUnit(RWEProcess rweProcess, long timeMilliseconds, int channelBitmap, long startSample, long duration, RWESound rweSound) { super(timeMilliseconds, channelBitmap, startSample, duration); this.rweSound = rweSound; + this.rweProcess = rweProcess; // TODO Auto-generated constructor stub } - public RWEDataUnit(DataUnitBaseData basicData, RWESound rweSound) { + public RWEDataUnit(RWEProcess rweProcess, DataUnitBaseData basicData, RWESound rweSound) { super(basicData); this.rweSound = rweSound; + this.rweProcess = rweProcess; } - double[] freqsHz; @Override public double[] getFreqsHz() { - if (freqsHz == null) { - freqsHz = new double[rweSound.sliceCount]; + double[] f = new double[rweSound.sliceCount]; + RWEDataBlock rweDataBlock = rweProcess.getRweDataBlock(); + double binToHz = rweDataBlock.getSampleRate() / rweDataBlock.getFftLength(); + for (int i = 0; i < f.length; i++) { + f[i] = (double) rweSound.peakFreq[i] * binToHz; } - return null; + return f; } @Override @@ -35,8 +40,16 @@ public class RWEDataUnit extends AbstractWhistleDataUnit { @Override public double[] getTimesInSeconds() { - // TODO Auto-generated method stub - return null; + if (rweSound == null) { + return null; + } + double[] t = new double[rweSound.sliceCount]; + RWEDataBlock rweDataBlock = rweProcess.getRweDataBlock(); + double binToT = rweDataBlock.getFftHop() / rweDataBlock.getSampleRate(); + for (int i = 0; i < t.length; i++) { + t[i] = (double) rweSound.sliceList[i] * binToT; + } + return t; } @Override diff --git a/src/RightWhaleEdgeDetector/RWEParameters.java b/src/RightWhaleEdgeDetector/RWEParameters.java index 8bb661a4..4b179378 100644 --- a/src/RightWhaleEdgeDetector/RWEParameters.java +++ b/src/RightWhaleEdgeDetector/RWEParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class RWEParameters implements Serializable, Cloneable, ManagedParameters { @@ -41,7 +42,7 @@ public class RWEParameters implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/RightWhaleEdgeDetector/RWEProcess.java b/src/RightWhaleEdgeDetector/RWEProcess.java index ccc766bb..081489c9 100644 --- a/src/RightWhaleEdgeDetector/RWEProcess.java +++ b/src/RightWhaleEdgeDetector/RWEProcess.java @@ -42,6 +42,10 @@ public class RWEProcess extends PamProcess { private FFTDataBlock sourceDataBlock; private RWEDataBlock rweDataBlock; + public RWEDataBlock getRweDataBlock() { + return rweDataBlock; + } + private Hashtable bearingLocalisers; private StandardSymbolManager symbolManager; /** @@ -212,7 +216,7 @@ public class RWEProcess extends PamProcess { // System.out.println(String.format("Detected sound type %d on channel %d", // soundType, this.iChannel)); duration = sourceDataBlock.getFftHop() * aSound.duration; - rweDataUnit = new RWEDataUnit(aSound.timeMilliseconds, + rweDataUnit = new RWEDataUnit(RWEProcess.this, aSound.timeMilliseconds, 1< { + + private RWSpeciesTypes rwSpeciesTypes = new RWSpeciesTypes(); + + public RWSpeciesManager(PamDataBlock dataBlock) { + super(dataBlock); + setDefaultDefaultSpecies(new SpeciesMapItem(RWSpeciesTypes.eubalaena, RWSpeciesTypes.onlyType, RWSpeciesTypes.defaultName)); + } + + @Override + public DataBlockSpeciesCodes getSpeciesCodes() { + return null; + } + + @Override + public String getSpeciesCode(RWEDataUnit dataUnit) { + return RWSpeciesTypes.defaultName; + } + +} diff --git a/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java b/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java new file mode 100644 index 00000000..654fe24c --- /dev/null +++ b/src/RightWhaleEdgeDetector/species/RWSpeciesTypes.java @@ -0,0 +1,17 @@ +package RightWhaleEdgeDetector.species; + +import tethys.species.DataBlockSpeciesCodes; + +public class RWSpeciesTypes extends DataBlockSpeciesCodes { + + public static final String onlyType = "Up call"; + + public static final int eubalaena = 180536; + + public static final String defaultName = "Right Whale"; + + public RWSpeciesTypes() { + super(eubalaena, defaultName, onlyType); + } + +} diff --git a/src/RightWhaleEdgeDetector/species/RWTethysDataProvider.java b/src/RightWhaleEdgeDetector/species/RWTethysDataProvider.java new file mode 100644 index 00000000..3577bd12 --- /dev/null +++ b/src/RightWhaleEdgeDetector/species/RWTethysDataProvider.java @@ -0,0 +1,37 @@ +package RightWhaleEdgeDetector.species; + +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import RightWhaleEdgeDetector.RWEDataUnit; +import nilus.Detection; +import nilus.Detection.Parameters; +import tethys.TethysControl; +import tethys.output.StreamExportParams; +import tethys.output.TethysExportParams; +import tethys.pamdata.AutoTethysProvider; + +public class RWTethysDataProvider extends AutoTethysProvider { + + public RWTethysDataProvider(TethysControl tethysControl, PamDataBlock pamDataBlock) { + super(tethysControl, pamDataBlock); + } + + @Override + public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams, + StreamExportParams streamExportParams) { + Detection detection = super.createDetection(dataUnit, tethysExportParams, streamExportParams); + if (detection == null) { + return null; + } + + RWEDataUnit rweDataUnit = (RWEDataUnit) dataUnit; + + Parameters parameters = detection.getParameters(); + parameters.setScore((double) rweDataUnit.rweSound.soundType); + double snr = 20.*Math.log10(rweDataUnit.rweSound.signal/rweDataUnit.rweSound.noise); + parameters.setSNRDB(snr); + + return detection; + } + +} diff --git a/src/SoundRecorder/RecorderSettings.java b/src/SoundRecorder/RecorderSettings.java index 72c9576d..4fcd6eec 100644 --- a/src/SoundRecorder/RecorderSettings.java +++ b/src/SoundRecorder/RecorderSettings.java @@ -16,6 +16,7 @@ import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterData; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamUtils; import PamguardMVC.PamRawDataBlock; import SoundRecorder.trigger.RecorderTrigger; @@ -443,7 +444,7 @@ public class RecorderSettings implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("channelBitmap"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/SoundRecorder/trigger/RecorderTriggerData.java b/src/SoundRecorder/trigger/RecorderTriggerData.java index 2192afc9..9b0cb32c 100644 --- a/src/SoundRecorder/trigger/RecorderTriggerData.java +++ b/src/SoundRecorder/trigger/RecorderTriggerData.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Information for triggered recordings to tell each recorder how long @@ -271,7 +272,7 @@ public class RecorderTriggerData implements Serializable, Cloneable, ManagedPara */ @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("lastTriggerStart"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/Spectrogram/SpectrogramDisplay.java b/src/Spectrogram/SpectrogramDisplay.java index dd2536d6..08a7bf2d 100644 --- a/src/Spectrogram/SpectrogramDisplay.java +++ b/src/Spectrogram/SpectrogramDisplay.java @@ -77,6 +77,7 @@ import pamScrollSystem.PamScrollerData; import pamScrollSystem.RangeSpinner; import pamScrollSystem.RangeSpinnerListener; import pamScrollSystem.jumping.ScrollJumper; +import pamguard.GlobalArguments; import soundPlayback.PlaybackControl; import soundPlayback.PlaybackProgressMonitor; import userDisplay.UserDisplayControl; @@ -274,7 +275,8 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett // this should result in settings being loaded if they exist. PamSettingManager.getInstance().registerSettings(this); // always need to register, even if we're using old parameters // } - if (spectrogramParameters == null) { + boolean isBatch = GlobalArguments.getParam("-batch") != null; + if (spectrogramParameters == null && isBatch == false) { this.spectrogramParameters = new SpectrogramParameters(); PamView view = userDisplayControl.getPamView(); if (view != null) { @@ -285,6 +287,14 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett } } } + if (spectrogramParameters == null) { + /* + * this can happen in batch mode if a display was added. + * Hopefully not a problem, but may need to set some parameters to + * set display up correctly. + */ + spectrogramParameters = new SpectrogramParameters(); + } spectrogramDisplay = this; @@ -1642,6 +1652,9 @@ InternalFrameListener, DisplayPanelContainer, SpectrogramParametersUser, PamSett return; } long t1 = dataUnit.getTimeMilliseconds()-viewerScroller.getValueMillis(); + if (timeAxis == null) { + return; + } int x1 = (int) Math.floor(timeAxis.getPosition(t1/1000)); int x2 = x1; if (dataUnit.getDurationInMilliseconds() != null) { diff --git a/src/alarm/AlarmParameters.java b/src/alarm/AlarmParameters.java index df89b940..0694adfc 100644 --- a/src/alarm/AlarmParameters.java +++ b/src/alarm/AlarmParameters.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class AlarmParameters implements Serializable, Cloneable, ManagedParameters { @@ -103,7 +104,7 @@ public class AlarmParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("hadHold"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/alarm/actions/email/SendEmailSettings.java b/src/alarm/actions/email/SendEmailSettings.java index dcd4dc0b..da558c85 100644 --- a/src/alarm/actions/email/SendEmailSettings.java +++ b/src/alarm/actions/email/SendEmailSettings.java @@ -28,6 +28,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import alarm.actions.serial.AlarmSerialSettings; /** @@ -158,7 +159,7 @@ public class SendEmailSettings implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/alarm/actions/serial/AlarmSerialSettings.java b/src/alarm/actions/serial/AlarmSerialSettings.java index b14e785c..801cc765 100644 --- a/src/alarm/actions/serial/AlarmSerialSettings.java +++ b/src/alarm/actions/serial/AlarmSerialSettings.java @@ -8,6 +8,7 @@ import com.fazecast.jSerialComm.SerialPort; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import serialComms.SerialPortConstants; import serialComms.jserialcomm.PJSerialComm; @@ -68,7 +69,7 @@ public class AlarmSerialSettings implements Serializable, Cloneable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/alarm/actions/sound/PlaySoundParams.java b/src/alarm/actions/sound/PlaySoundParams.java index c9f97970..6481e41d 100644 --- a/src/alarm/actions/sound/PlaySoundParams.java +++ b/src/alarm/actions/sound/PlaySoundParams.java @@ -6,6 +6,7 @@ import java.util.Arrays; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import alarm.AlarmParameters; public class PlaySoundParams implements Cloneable, Serializable, ManagedParameters { @@ -33,7 +34,7 @@ public class PlaySoundParams implements Cloneable, Serializable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/alarm/actions/udp/AlarmUDPParams.java b/src/alarm/actions/udp/AlarmUDPParams.java index 10728bb2..7a7bfa61 100644 --- a/src/alarm/actions/udp/AlarmUDPParams.java +++ b/src/alarm/actions/udp/AlarmUDPParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class AlarmUDPParams implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class AlarmUDPParams implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/amplifier/AmpParameters.java b/src/amplifier/AmpParameters.java index 98e52a63..89aac38c 100644 --- a/src/amplifier/AmpParameters.java +++ b/src/amplifier/AmpParameters.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamguardMVC.PamConstants; @@ -41,7 +42,7 @@ public class AmpParameters implements Cloneable, Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("rawDataSource"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/analogarraysensor/ArraySensorLogging.java b/src/analogarraysensor/ArraySensorLogging.java index e4eba2e9..ca13752a 100644 --- a/src/analogarraysensor/ArraySensorLogging.java +++ b/src/analogarraysensor/ArraySensorLogging.java @@ -56,7 +56,8 @@ public class ArraySensorLogging extends SQLLogging { AnalogSensorData aData = new AnalogSensorData(rawValue, calValue); sensorData[i] = aData; } - int chanMap = getTableDefinition().getChannelBitmap().getIntegerValue(); + PamTableDefinition pamTableDef = (PamTableDefinition) getTableDefinition(); + int chanMap = pamTableDef.getChannelBitmap().getIntegerValue(); int streamer = PamUtils.getSingleChannel(chanMap); if (streamer < 0) streamer = 0; AnalogArraySensorDataUnit asdu = new AnalogArraySensorDataUnit(timeMilliseconds, streamer, sensorData); diff --git a/src/analogarraysensor/ArraySensorParams.java b/src/analogarraysensor/ArraySensorParams.java index c59d31eb..b84081a6 100644 --- a/src/analogarraysensor/ArraySensorParams.java +++ b/src/analogarraysensor/ArraySensorParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import Array.sensors.ArrayDisplayParameters; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class ArraySensorParams implements Serializable, Cloneable, ManagedParameters { @@ -47,7 +48,7 @@ public class ArraySensorParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/analoginput/AnalogDeviceParams.java b/src/analoginput/AnalogDeviceParams.java index 1b43c7b9..cae97232 100644 --- a/src/analoginput/AnalogDeviceParams.java +++ b/src/analoginput/AnalogDeviceParams.java @@ -6,6 +6,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import analoginput.calibration.CalibrationData; @@ -63,7 +64,7 @@ public class AnalogDeviceParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("calibrationTable"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/analoginput/AnalogInputParams.java b/src/analoginput/AnalogInputParams.java index acd041e4..a64d51ba 100644 --- a/src/analoginput/AnalogInputParams.java +++ b/src/analoginput/AnalogInputParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class AnalogInputParams implements Serializable, Cloneable, ManagedParameters { @@ -13,7 +14,7 @@ public class AnalogInputParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/analoginput/AnalogRangeData.java b/src/analoginput/AnalogRangeData.java index 00043994..7a7d7109 100644 --- a/src/analoginput/AnalogRangeData.java +++ b/src/analoginput/AnalogRangeData.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class AnalogRangeData implements Serializable, Cloneable, Comparable, ManagedParameters { @@ -119,7 +120,7 @@ public class AnalogRangeData implements Serializable, Cloneable, Comparable 0) { diff --git a/src/annotation/timestamp/TimestampSQLLogging.java b/src/annotation/timestamp/TimestampSQLLogging.java index fd1d7be6..2f6b0728 100644 --- a/src/annotation/timestamp/TimestampSQLLogging.java +++ b/src/annotation/timestamp/TimestampSQLLogging.java @@ -3,6 +3,7 @@ package annotation.timestamp; import java.sql.Types; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -22,12 +23,12 @@ public class TimestampSQLLogging implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(timestamp); } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { TimestampAnnotation timestampAnnotation = (TimestampAnnotation) pamDataUnit.findDataAnnotation(TimestampAnnotation.class, timestampAnnotationType.getAnnotationName()); if (timestampAnnotation == null) { @@ -40,7 +41,7 @@ public class TimestampSQLLogging implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { try { TimestampAnnotation timestampAnnotation = new TimestampAnnotation(timestampAnnotationType); Long note = sqlTypes.millisFromTimeStamp(timestamp.getValue()); diff --git a/src/annotation/userforms/UserFormSQLAddon.java b/src/annotation/userforms/UserFormSQLAddon.java index fb5a20f0..8156bfda 100644 --- a/src/annotation/userforms/UserFormSQLAddon.java +++ b/src/annotation/userforms/UserFormSQLAddon.java @@ -3,6 +3,7 @@ package annotation.userforms; import java.util.ArrayList; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -32,7 +33,7 @@ public class UserFormSQLAddon implements SQLLoggingAddon { @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { loggerTableItems.clear(); FormDescription formDescription = userFormAnnotationType.findFormDescription(); if (formDescription == null) { @@ -58,7 +59,7 @@ public class UserFormSQLAddon implements SQLLoggingAddon { } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { if (pamDataUnit == null) { clearTableItems(); return false; @@ -103,7 +104,7 @@ public class UserFormSQLAddon implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { FormDescription formDescription = userFormAnnotationType.findFormDescription(); if (formDescription == null) { return false; diff --git a/src/annotationMark/spectrogram/SpectrogramMarkParams.java b/src/annotationMark/spectrogram/SpectrogramMarkParams.java index 0d65e6e4..89540c01 100644 --- a/src/annotationMark/spectrogram/SpectrogramMarkParams.java +++ b/src/annotationMark/spectrogram/SpectrogramMarkParams.java @@ -5,6 +5,7 @@ import java.util.List; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import annotation.DataAnnotationType; import annotation.handler.AnnotationChoices; @@ -31,7 +32,7 @@ public class SpectrogramMarkParams implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/backupmanager/FileLocation.java b/src/backupmanager/FileLocation.java index 1508125a..6557821d 100644 --- a/src/backupmanager/FileLocation.java +++ b/src/backupmanager/FileLocation.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Information on a file path or folder path that can be used with the @@ -42,7 +43,7 @@ public class FileLocation implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/backupmanager/settings/BackupSettings.java b/src/backupmanager/settings/BackupSettings.java index 71b90fda..bc9ac14c 100644 --- a/src/backupmanager/settings/BackupSettings.java +++ b/src/backupmanager/settings/BackupSettings.java @@ -6,6 +6,7 @@ import java.util.List; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public abstract class BackupSettings implements Serializable, Cloneable, ManagedParameters { @@ -40,7 +41,7 @@ public abstract class BackupSettings implements Serializable, Cloneable, Managed @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/beamformer/BeamAlgorithmParams.java b/src/beamformer/BeamAlgorithmParams.java index 7cde91b4..eabdb943 100644 --- a/src/beamformer/BeamAlgorithmParams.java +++ b/src/beamformer/BeamAlgorithmParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import beamformer.algorithms.basicFreqDomain.BasicFreqDomParams; /* @@ -336,7 +337,7 @@ public abstract class BeamAlgorithmParams implements Serializable, Cloneable, Ma @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/beamformer/BeamFormerParams.java b/src/beamformer/BeamFormerParams.java index f5cc3f5d..d6082a1d 100644 --- a/src/beamformer/BeamFormerParams.java +++ b/src/beamformer/BeamFormerParams.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.HashMap; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamUtils.DeepCloner; import PamView.GroupedSourceParameters; @@ -325,7 +326,7 @@ public class BeamFormerParams implements Cloneable, Serializable, ManagedParamet */ @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("algorithmParamsTable"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/beamformer/annotation/BFAnnotationLogging.java b/src/beamformer/annotation/BFAnnotationLogging.java index 83d7641a..ba9bed54 100644 --- a/src/beamformer/annotation/BFAnnotationLogging.java +++ b/src/beamformer/annotation/BFAnnotationLogging.java @@ -6,6 +6,7 @@ import PamDetection.LocContents; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import beamformer.loc.BeamFormerLocalisation; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -29,7 +30,7 @@ public class BFAnnotationLogging implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(bfPhones); pamTableDefinition.addTableItem(bfArrayType); pamTableDefinition.addTableItem(bfContents); @@ -38,7 +39,7 @@ public class BFAnnotationLogging implements SQLLoggingAddon { } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { bfPhones.setValue(null); bfArrayType.setValue(null); bfContents.setValue(null); @@ -64,7 +65,7 @@ public class BFAnnotationLogging implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { Float[] Angles = new Float[2]; for (int i = 0; i < 2; i++) { Angles[i] = (Float) angle[i].getFloatValue(); diff --git a/src/bearinglocaliser/BearingLocaliserParams.java b/src/bearinglocaliser/BearingLocaliserParams.java index 277c8e5d..d697781c 100644 --- a/src/bearinglocaliser/BearingLocaliserParams.java +++ b/src/bearinglocaliser/BearingLocaliserParams.java @@ -8,6 +8,7 @@ import java.util.HashMap; import Localiser.controls.RawOrFFTParamsInterface; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamView.GroupedSourceParameters; import bearinglocaliser.algorithms.BearingAlgorithmParams; @@ -188,7 +189,7 @@ public class BearingLocaliserParams implements Serializable, Cloneable, RawOrFFT @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("algorithmParamsTable"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java b/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java index 3b6c0bed..cea3e25f 100644 --- a/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java +++ b/src/bearinglocaliser/algorithms/BearingAlgorithmParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class BearingAlgorithmParams implements Serializable, Cloneable, ManagedParameters { @@ -60,7 +61,7 @@ public class BearingAlgorithmParams implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/bearinglocaliser/annotation/BearingAnnotationSQL.java b/src/bearinglocaliser/annotation/BearingAnnotationSQL.java index bc4b88bb..d56e8be7 100644 --- a/src/bearinglocaliser/annotation/BearingAnnotationSQL.java +++ b/src/bearinglocaliser/annotation/BearingAnnotationSQL.java @@ -4,6 +4,7 @@ import java.sql.Types; import PamguardMVC.PamDataUnit; import bearinglocaliser.BearingLocalisation; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -34,7 +35,7 @@ public class BearingAnnotationSQL implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(algoName); pamTableDefinition.addTableItem(bfPhones); pamTableDefinition.addTableItem(bfArrayType); @@ -48,7 +49,7 @@ public class BearingAnnotationSQL implements SQLLoggingAddon { } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { algoName.setValue(null); bfPhones.setValue(null); bfArrayType.setValue(null); @@ -96,7 +97,7 @@ public class BearingAnnotationSQL implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { Float[] Angles = new Float[2]; int nNans = 0; for (int i = 0; i < 2; i++) { diff --git a/src/binaryFileStorage/BinaryFooter.java b/src/binaryFileStorage/BinaryFooter.java index 98142a16..f410998b 100644 --- a/src/binaryFileStorage/BinaryFooter.java +++ b/src/binaryFileStorage/BinaryFooter.java @@ -7,6 +7,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamCalendar; public class BinaryFooter implements Serializable, ManagedParameters { @@ -230,7 +231,7 @@ public class BinaryFooter implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/binaryFileStorage/BinaryHeader.java b/src/binaryFileStorage/BinaryHeader.java index b27652ec..b1d7a986 100644 --- a/src/binaryFileStorage/BinaryHeader.java +++ b/src/binaryFileStorage/BinaryHeader.java @@ -9,6 +9,7 @@ import java.lang.reflect.Field; import PamController.PamguardVersionInfo; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamUtils.PamCalendar; @@ -289,7 +290,7 @@ public class BinaryHeader implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("pamguard"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/binaryFileStorage/BinaryOutputStream.java b/src/binaryFileStorage/BinaryOutputStream.java index 1e474686..67307c12 100644 --- a/src/binaryFileStorage/BinaryOutputStream.java +++ b/src/binaryFileStorage/BinaryOutputStream.java @@ -49,7 +49,7 @@ public class BinaryOutputStream { private DataOutputStream noiseOutputStream; - private int storedObjects; + private int storedObjects, storedNoiseCount; private String mainFileName, indexFileName; @@ -219,6 +219,7 @@ public class BinaryOutputStream { else { noiseOutputStream = null; } + storedNoiseCount = 0; return true; } @@ -450,6 +451,7 @@ public class BinaryOutputStream { footer.setHighestUID(parentDataBlock.getUidHandler().getCurrentUID()); boolean ok = footer.writeFooter(dataOutputStream, BinaryStore.getCurrentFileFormat()); if (noiseOutputStream != null) { +// footer.setnObjects(storedNoiseCount); ok &= footer.writeFooter(noiseOutputStream, BinaryStore.getCurrentFileFormat()); } lastObjectType = BinaryTypes.FILE_FOOTER; @@ -487,12 +489,20 @@ public class BinaryOutputStream { // } public synchronized boolean storeData(int objectId, DataUnitBaseData baseData, BinaryObjectData binaryObjectData) { + boolean ok; if (objectId == BinaryTypes.BACKGROUND_DATA & noiseOutputStream != null) { - return storeData(noiseOutputStream, objectId, baseData, binaryObjectData); + ok = storeData(noiseOutputStream, objectId, baseData, binaryObjectData); + if (ok) { + storedNoiseCount++; + } } else { - return storeData(dataOutputStream, objectId, baseData, binaryObjectData); + ok = storeData(dataOutputStream, objectId, baseData, binaryObjectData); + if (ok) { + storedObjects++; + } } + return ok; } /** * Writes data to a file. Note that the length of data may be greater than @@ -505,7 +515,9 @@ public class BinaryOutputStream { */ public synchronized boolean storeData(DataOutputStream outputStream, int objectId, DataUnitBaseData baseData, BinaryObjectData binaryObjectData) { if (lastObjectType == BinaryTypes.MODULE_FOOTER) { - System.out.printf("Storing binary object type %d in file %s with no module header\n", objectId, outputStream == null ? null : outputStream.toString()); + System.out.printf("Storing binary object at %s from %s in file %s with no module header\n", + PamCalendar.formatDBDateTime(baseData.getTimeMilliseconds()), + parentDataBlock.getDataName(), outputStream == null ? null : outputStream.toString()); } byte[] data = binaryObjectData.getData(); int objectLength = binaryObjectData.getDataLength(); @@ -562,7 +574,6 @@ public class BinaryOutputStream { return false; } - storedObjects++; return true; diff --git a/src/binaryFileStorage/BinarySettingsStorage.java b/src/binaryFileStorage/BinarySettingsStorage.java index 48278c1d..c59992d8 100644 --- a/src/binaryFileStorage/BinarySettingsStorage.java +++ b/src/binaryFileStorage/BinarySettingsStorage.java @@ -110,6 +110,12 @@ public class BinarySettingsStorage implements PamSettingsSource { return false;*/ } + @Override + public boolean saveEndSettings(long timeNow) { + // do nothing at the end of a run with binary store. + return true; + } + // private boolean writeData(DataOutputStream dos, int objectId, byte[] data) { // int totalLen = data.length + 16; // int dataLen = data.length; diff --git a/src/binaryFileStorage/BinaryStore.java b/src/binaryFileStorage/BinaryStore.java index 98b6dc84..67453533 100644 --- a/src/binaryFileStorage/BinaryStore.java +++ b/src/binaryFileStorage/BinaryStore.java @@ -155,6 +155,8 @@ PamSettingsSource, DataOutputStore { private PamControlledGUISwing binaryStoreGUISwing; private BackupInformation backupInformation; + + private BinaryDataMapMaker dataMapMaker; public static int getCurrentFileFormat() { return CURRENT_FORMAT; @@ -424,6 +426,25 @@ PamSettingsSource, DataOutputStore { } return true; } + + public boolean checkCommandLine() { + /* + * check to see if there is a command line override of the currently stored folder name. + */ + String globFolder = GlobalArguments.getParam(GlobalFolderArg); + if (globFolder == null) { + return false; + } + boolean ok = checkGlobFolder(globFolder); + if (ok) { + binaryStoreSettings.setStoreLocation(globFolder); // remember it. + return true; + } + else { + System.err.println("Unable to set binary storage folder " + globFolder); + return false; + } + } /** * Set and create if necessary the global folder. @@ -540,6 +561,12 @@ PamSettingsSource, DataOutputStore { return binarySettingsStorage.saveStartSettings(timeNow); } + @Override + public boolean saveEndSettings(long timeNow) { + // TODO Auto-generated method stub + return false; + } + @Override public int getNumSettings() { if (binarySettingsStorage == null) { @@ -595,7 +622,8 @@ PamSettingsSource, DataOutputStore { // this first operation should be fast enough that it doesn't // need rethreading. - if (isViewer()) { + boolean hasCommandLine = checkCommandLine(); + if (isViewer() && !hasCommandLine) { BinaryStoreSettings newSettings = null; if (PamGUIManager.isSwing()) { //open the swing dialog. @@ -784,8 +812,8 @@ PamSettingsSource, DataOutputStore { * updates to the dialog to display progress, then close the * dialog. */ - BinaryDataMapMaker bdmm = new BinaryDataMapMaker(this); - AWTScheduler.getInstance().scheduleTask(bdmm); + dataMapMaker = new BinaryDataMapMaker(this); + AWTScheduler.getInstance().scheduleTask(dataMapMaker); } @@ -917,6 +945,7 @@ PamSettingsSource, DataOutputStore { } PamController.getInstance().notifyModelChanged(PamControllerInterface.CHANGED_OFFLINE_DATASTORE); // System.out.println("BinaryDataMapMaker really done " + this); + dataMapMaker = null; } @Override @@ -2547,5 +2576,22 @@ PamSettingsSource, DataOutputStore { BinaryStoreDeleter storeDeleter = new BinaryStoreDeleter(this); return storeDeleter.deleteDataFrom(timeMillis); } + @Override + public int getOfflineState() { + int state = super.getOfflineState(); + if (dataMapMaker != null) { + System.out.println("Binary store is map making"); + state = Math.max(state, PamController.PAM_MAPMAKING); + } + if (datagramManager != null & datagramManager.getStatus()) { + state = Math.max(state, PamController.PAM_MAPMAKING); + System.out.println("Binary store is creating datagram"); + } + return state; + } + + public String getDataLocation() { + return binaryStoreSettings.getStoreLocation(); + } } diff --git a/src/binaryFileStorage/BinaryStoreSettings.java b/src/binaryFileStorage/BinaryStoreSettings.java index 441baddd..78c42e99 100644 --- a/src/binaryFileStorage/BinaryStoreSettings.java +++ b/src/binaryFileStorage/BinaryStoreSettings.java @@ -6,6 +6,7 @@ import java.io.Serializable; import PamController.PamFolders; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class BinaryStoreSettings implements Serializable, Cloneable, ManagedParameters { @@ -90,7 +91,7 @@ public class BinaryStoreSettings implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/cepstrum/CepstrumParams.java b/src/cepstrum/CepstrumParams.java index a24fab3a..59f6fbb9 100644 --- a/src/cepstrum/CepstrumParams.java +++ b/src/cepstrum/CepstrumParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class CepstrumParams implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class CepstrumParams implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/clickDetector/BTDisplayParameters.java b/src/clickDetector/BTDisplayParameters.java index 143b3eab..bf9604f7 100644 --- a/src/clickDetector/BTDisplayParameters.java +++ b/src/clickDetector/BTDisplayParameters.java @@ -6,6 +6,7 @@ import java.util.Arrays; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import clickDetector.tdPlots.ClickSymbolOptions; @@ -137,7 +138,7 @@ public class BTDisplayParameters implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("showSpeciesList"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/BasicClickIdParameters.java b/src/clickDetector/BasicClickIdParameters.java index feeefb67..6cc5925c 100644 --- a/src/clickDetector/BasicClickIdParameters.java +++ b/src/clickDetector/BasicClickIdParameters.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; @@ -83,7 +84,7 @@ public class BasicClickIdParameters implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickDetector/ClickAlarm.java b/src/clickDetector/ClickAlarm.java index f9459296..515945ab 100644 --- a/src/clickDetector/ClickAlarm.java +++ b/src/clickDetector/ClickAlarm.java @@ -33,6 +33,7 @@ import javax.sound.sampled.Clip; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; /** @@ -209,7 +210,7 @@ public class ClickAlarm implements Comparable, Serializable, Cloneab @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("fileIsLoaded"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/ClickBinaryModuleFooter.java b/src/clickDetector/ClickBinaryModuleFooter.java index 35718e17..f24ed53c 100644 --- a/src/clickDetector/ClickBinaryModuleFooter.java +++ b/src/clickDetector/ClickBinaryModuleFooter.java @@ -12,6 +12,7 @@ import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import binaryFileStorage.BinaryHeader; import binaryFileStorage.BinaryObjectData; import binaryFileStorage.ModuleFooter; @@ -128,7 +129,7 @@ public class ClickBinaryModuleFooter extends ModuleFooter implements ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("clickDetectorName"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/ClickBinaryModuleHeader.java b/src/clickDetector/ClickBinaryModuleHeader.java index 1cb7f8d8..f36f7854 100644 --- a/src/clickDetector/ClickBinaryModuleHeader.java +++ b/src/clickDetector/ClickBinaryModuleHeader.java @@ -2,6 +2,7 @@ package clickDetector; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import binaryFileStorage.BinaryHeader; import binaryFileStorage.BinaryObjectData; import binaryFileStorage.ModuleHeader; @@ -28,7 +29,7 @@ public class ClickBinaryModuleHeader extends ModuleHeader implements ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java new file mode 100644 index 00000000..bb7528bf --- /dev/null +++ b/src/clickDetector/ClickClassifiers/ClickBlockSpeciesManager.java @@ -0,0 +1,52 @@ +package clickDetector.ClickClassifiers; + +import clickDetector.ClickControl; +import clickDetector.ClickDataBlock; +import clickDetector.ClickDetection; +import tethys.species.DataBlockSpeciesManager; +import tethys.species.DataBlockSpeciesCodes; +import tethys.species.ITISTypes; +import tethys.species.SpeciesMapItem; + +public class ClickBlockSpeciesManager extends DataBlockSpeciesManager { + + private ClickControl clickControl; + + public ClickBlockSpeciesManager(ClickControl clickControl, ClickDataBlock clickDataBlock) { + super(clickDataBlock); + this.clickControl = clickControl; + setDefaultDefaultSpecies(new SpeciesMapItem(ITISTypes.OTHER, "Unknown", "Unknown")); + setDefaultSpeciesCode("Unknown"); + } + + @Override + public DataBlockSpeciesCodes getSpeciesCodes() { + ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager(); + if (masterManager == null) { + return null; + } + String[] speciesList = masterManager.getSpeciesList(); + // add the default + String[] fullList = new String[speciesList.length+1]; + fullList[0] = getDefaultSpeciesCode(); + for (int i = 0; i < speciesList.length; i++) { + fullList[i+1] = speciesList[i]; + } + + return new DataBlockSpeciesCodes("Click", fullList); + } + + @Override + public String getSpeciesCode(ClickDetection dataUnit) { + ClickTypeMasterManager masterManager = clickControl.getClickTypeMasterManager(); + if (masterManager == null) { + return null; + } + int listIndex = masterManager.codeToListIndex(dataUnit.getClickType()); + if (listIndex < 0) { + return null; + } + return masterManager.getSpeciesList()[listIndex]; + } + +} diff --git a/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java b/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java index d937b164..78b56316 100644 --- a/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java +++ b/src/clickDetector/ClickClassifiers/ClickTypeCommonParams.java @@ -28,6 +28,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Superclass for click parameters, including the ClickTypeParms and @@ -191,7 +192,7 @@ abstract public class ClickTypeCommonParams implements Cloneable, Serializable, @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java b/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java index baa057ac..840d2086 100644 --- a/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java +++ b/src/clickDetector/ClickClassifiers/annotation/ClickAnnotationSQL.java @@ -3,6 +3,7 @@ package clickDetector.ClickClassifiers.annotation; import java.sql.Types; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -33,12 +34,12 @@ public class ClickAnnotationSQL implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(classifierSetTable); } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { ClickClassifierAnnotation clickAnnotation = (ClickClassifierAnnotation) pamDataUnit.findDataAnnotation(ClickClassificationType.class); //create a comma delimited string @@ -53,7 +54,7 @@ public class ClickAnnotationSQL implements SQLLoggingAddon { @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { String array = classifierSetTable.getDeblankedStringValue(); //read in the classification set. This a list of all the classifiers the clicks passed. diff --git a/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java b/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java index 9c925607..6cc4f1b5 100644 --- a/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java +++ b/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierParameters.java @@ -7,6 +7,7 @@ import java.util.Vector; import PamModel.SMRUEnable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class SweepClassifierParameters implements Serializable, Cloneable, ManagedParameters { @@ -72,7 +73,7 @@ public class SweepClassifierParameters implements Serializable, Cloneable, Manag @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("classifierSets"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/ClickControl.java b/src/clickDetector/ClickControl.java index e03b73a7..9787c59f 100644 --- a/src/clickDetector/ClickControl.java +++ b/src/clickDetector/ClickControl.java @@ -26,6 +26,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.Serializable; import java.util.ArrayList; +import java.util.List; import java.util.ListIterator; import javax.swing.JMenu; @@ -1071,7 +1072,7 @@ public class ClickControl extends PamControlledUnit implements PamSettings { subDet.removeSuperDetection(event); } } - clickDetector.getOfflineEventDataBlock().remove(event); + clickDetector.getOfflineEventDataBlock().remove(event, true); } @Override @@ -1168,6 +1169,31 @@ public class ClickControl extends PamControlledUnit implements PamSettings { return targetMotionLocaliser; } + /** + * Remove clicks from existing events, if they have any. They may not. + * This is called whenever clicks are assigned to a new event to make + * sure that they don't end up in two events. + * @param markedClicks + */ + public void removeFromEvents(List markedClicks) { + if (markedClicks == null) { + return; + } + for (PamDataUnit dataUnit : markedClicks) { + OfflineEventDataUnit anEvent = (OfflineEventDataUnit) dataUnit.getSuperDetection(OfflineEventDataUnit.class); + if (anEvent == null) { + continue; + } + anEvent.removeSubDetection(dataUnit); + if (anEvent.getSubDetectionsCount() == 0) { + deleteEvent(anEvent); + } + else { + anEvent.updateDataUnit(System.currentTimeMillis()); + } + } + + } /** * Reassign all the clicks on one event to a different event @@ -1199,7 +1225,7 @@ public class ClickControl extends PamControlledUnit implements PamSettings { } clickEvent.setComment(clickEvent.getComment() + " Clicks reassigned to event " + reassignEvent.getEventId()); offlineEventDataBlock.updatePamData(clickEvent, PamCalendar.getTimeInMillis()); - offlineEventDataBlock.remove(clickEvent); + offlineEventDataBlock.remove(clickEvent, true); reassignEvent.sortSubDetections(); offlineEventDataBlock.updatePamData(reassignEvent, now); if (ClickTrainDetection.class.isAssignableFrom(reassignEvent.getClass())) { diff --git a/src/clickDetector/ClickDataBlock.java b/src/clickDetector/ClickDataBlock.java index 3e650b85..5536aa79 100644 --- a/src/clickDetector/ClickDataBlock.java +++ b/src/clickDetector/ClickDataBlock.java @@ -3,6 +3,9 @@ package clickDetector; import java.util.ListIterator; import pamScrollSystem.ViewLoadObserver; +import tethys.TethysControl; +import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; //import staticLocaliser.StaticLocaliserControl; //import staticLocaliser.StaticLocaliserProvider; //import staticLocaliser.panels.AbstractLocaliserControl; @@ -10,8 +13,10 @@ import pamScrollSystem.ViewLoadObserver; import alarm.AlarmCounterProvider; import alarm.AlarmDataSource; import binaryFileStorage.BinaryStore; +import clickDetector.ClickClassifiers.ClickBlockSpeciesManager; import clickDetector.dataSelector.ClickDataSelectCreator; import clickDetector.offlineFuncs.OfflineClickLogging; +import clickDetector.tethys.ClickTethysDataProvider; import clickDetector.toad.ClickTOADCalculator; import dataMap.OfflineDataMap; import fftManager.fftorganiser.FFTDataOrganiser; @@ -24,6 +29,8 @@ import PamUtils.PamUtils; import PamView.GroupedDataSource; import PamView.GroupedSourceParameters; import PamguardMVC.AcousticDataBlock; +import PamguardMVC.DataAutomation; +import PamguardMVC.DataAutomationInfo; import PamguardMVC.FFTDataHolderBlock; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; @@ -41,6 +48,8 @@ public class ClickDataBlock extends AcousticDataBlock implement private boolean isViewer; + private ClickBlockSpeciesManager clickBlockSpeciesManager; + public ClickDataBlock(ClickControl clickControl, PamProcess parentProcess, int channelMap) { @@ -65,6 +74,8 @@ public class ClickDataBlock extends AcousticDataBlock implement private ClickTOADCalculator clickTOADCalculator; + private ClickTethysDataProvider clickTethysDataProvider; + /** * Click detector loading has to be a bit different to normal - first * data are loaded from the binary store, then a subset of these data @@ -304,5 +315,26 @@ public class ClickDataBlock extends AcousticDataBlock implement } } + @Override + public DataBlockSpeciesManager getDatablockSpeciesManager() { + if (clickBlockSpeciesManager == null) { + clickBlockSpeciesManager = new ClickBlockSpeciesManager(clickControl, this); + } + return clickBlockSpeciesManager; + } + + @Override + public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) { + if (clickTethysDataProvider == null) { + clickTethysDataProvider = new ClickTethysDataProvider(tethysControl, this); + } + return clickTethysDataProvider; + } + + @Override + public DataAutomationInfo getDataAutomationInfo() { + return new DataAutomationInfo(DataAutomation.AUTOMATIC); + } + } diff --git a/src/clickDetector/ClickDisplayManager.java b/src/clickDetector/ClickDisplayManager.java index f46aeca8..2329bb4a 100644 --- a/src/clickDetector/ClickDisplayManager.java +++ b/src/clickDetector/ClickDisplayManager.java @@ -28,6 +28,7 @@ import PamController.PamSettingManager; import PamController.PamSettings; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamView.MenuItemEnabler; @@ -302,7 +303,7 @@ public class ClickDisplayManager implements PamSettings { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("className"); ps.put(new PrivatePamParameterData(this, field) { @@ -406,8 +407,13 @@ public class ClickDisplayManager implements PamSettings { public Serializable getSettingsReference() { cdmp.countEverything(this); + cdmp.saveDisplayLocations(getWindowList()); return cdmp; } + + public void restoreWindowSizes() { + cdmp.restoreWindowSizes(getWindowList()); + } public int countDisplays(Class displayType) { int count = 0; diff --git a/src/clickDetector/ClickDisplayManagerParameters2.java b/src/clickDetector/ClickDisplayManagerParameters2.java index 86ccbca6..6bcc110a 100644 --- a/src/clickDetector/ClickDisplayManagerParameters2.java +++ b/src/clickDetector/ClickDisplayManagerParameters2.java @@ -1,14 +1,20 @@ package clickDetector; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; import java.io.Serializable; import java.lang.reflect.Field; +import java.util.ArrayList; +import Layout.PamInternalFrame; import clickDetector.IDI_Display.IDIHistogramImage; import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class ClickDisplayManagerParameters2 implements Cloneable, Serializable, ManagedParameters { @@ -34,6 +40,10 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable, private boolean initialised = false; + private boolean manualWindowSizes = false; + + private ArrayList windowSizes = new ArrayList(); + public ClickDisplayManagerParameters2() { setDefaults(); } @@ -158,6 +168,11 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable, return null; } + /** + * This populates the serialised settings with lists of how many displays of + * each type there are. + * @param clickDisplayManager + */ public void countEverything(ClickDisplayManager clickDisplayManager) { lastMode = PamController.getInstance().getRunMode(); if (lastMode >= NMODES) lastMode = 0; @@ -181,7 +196,7 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable, @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("initialised"); ps.put(new PrivatePamParameterData(this, field) { @@ -207,4 +222,101 @@ public class ClickDisplayManagerParameters2 implements Cloneable, Serializable, return ps; } + /** + * Save windows sizes in an array list. + * @param windowList + */ + public void saveDisplayLocations(ArrayList windowList) { + if (windowList == null) { + return; + } + getWindowSizes(); // make sure the array is created + windowSizes.clear(); + for (ClickDisplay disp : windowList) { + Point loc = disp.getFrame().getLocation(); + Dimension sz = disp.getFrame().getSize(); + String cls = disp.getClass().toString(); + windowSizes.add(new WindowSizeData(cls, loc, sz)); + } + } + + /** + * Try to restore window locations and sizes from a stored list. + * @param windowList + * @return + */ + public boolean restoreWindowSizes(ArrayList windowList){ + if (windowSizes == null || windowList == null) { + return false; + } + int resized = 0; + for (ClickDisplay disp : windowList) { + PamInternalFrame frame = disp.getFrame(); + String cls = disp.getClass().toString(); + // find an element in the list with that class. + WindowSizeData sizeData = null; + for (int i = 0; i < windowSizes.size(); i++) { + if (windowSizes.get(i).windowClass.equals(cls)) { + sizeData = windowSizes.remove(i); + break; + } + } + if (sizeData != null) { + frame.setLocation(sizeData.location); + frame.setSize(sizeData.size); + resized ++; + } + } + return resized > 0; + } + + + + /** + * @return the windowSizes + */ + public ArrayList getWindowSizes() { + if (windowSizes == null) { + windowSizes = new ArrayList<>(); + } + return windowSizes; + } + + + + /** + * @return the manualWindowSizes + */ + public boolean isManualWindowSizes() { + return manualWindowSizes; + } + + /** + * @param manualWindowSizes the manualWindowSizes to set + */ + public void setManualWindowSizes(boolean manualWindowSizes) { + this.manualWindowSizes = manualWindowSizes; + } + + + + private class WindowSizeData implements Serializable { + + static public final long serialVersionUID = 1; + + protected String windowClass; + + public WindowSizeData(String windowClass, Point location, Dimension size) { + super(); + this.windowClass = windowClass; + this.location = location; + this.size = size; + } + + protected Point location; + + protected Dimension size; + + } + } diff --git a/src/clickDetector/ClickParameters.java b/src/clickDetector/ClickParameters.java index 3146b0e4..118eaf21 100644 --- a/src/clickDetector/ClickParameters.java +++ b/src/clickDetector/ClickParameters.java @@ -38,6 +38,7 @@ import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterData; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.GroupedSourceParameters; import PamView.dialog.GroupedSourcePanel; import PamView.paneloverlay.overlaymark.MarkDataSelectorParams; @@ -441,7 +442,7 @@ public class ClickParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { PamParameterData param = ps.findParameterData("dbThreshold"); param.setShortName("Detection Threshold"); diff --git a/src/clickDetector/ClickSpectrumParams.java b/src/clickDetector/ClickSpectrumParams.java index 6784c9fa..d18927e3 100644 --- a/src/clickDetector/ClickSpectrumParams.java +++ b/src/clickDetector/ClickSpectrumParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class ClickSpectrumParams implements Serializable, Cloneable, ManagedParameters { @@ -38,7 +39,7 @@ public class ClickSpectrumParams implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/clickDetector/ClickSpectrumTemplateParams.java b/src/clickDetector/ClickSpectrumTemplateParams.java index ff156b0e..caad2b6e 100644 --- a/src/clickDetector/ClickSpectrumTemplateParams.java +++ b/src/clickDetector/ClickSpectrumTemplateParams.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; @@ -39,7 +40,7 @@ public class ClickSpectrumTemplateParams implements Serializable, Cloneable, Man @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("clickTemplateArray"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/ClickTabPanel.java b/src/clickDetector/ClickTabPanel.java index cf32c245..d969b5ca 100644 --- a/src/clickDetector/ClickTabPanel.java +++ b/src/clickDetector/ClickTabPanel.java @@ -72,9 +72,19 @@ public class ClickTabPanel extends JDesktopPane implements ComponentListener { public void componentMoved(ComponentEvent e) { } + /** + * This get's called during startup when the window is created and will + * automatically resize everything. IT may get called 2 or 3 times at startup + * as components such as the side bar sort themselves out. + */ public void componentResized(ComponentEvent e) { // if (++resizeCount < 5) { - arrangeWindows(); + if (clickTabPanelControl.clickDisplayManager.cdmp.isManualWindowSizes() == false) { + arrangeWindows(); + } + else { + clickTabPanelControl.clickDisplayManager.restoreWindowSizes(); + } // } } diff --git a/src/clickDetector/ClickTabPanelControl.java b/src/clickDetector/ClickTabPanelControl.java index 4880521e..5e8f6491 100644 --- a/src/clickDetector/ClickTabPanelControl.java +++ b/src/clickDetector/ClickTabPanelControl.java @@ -26,6 +26,7 @@ import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -117,11 +118,29 @@ public class ClickTabPanelControl implements PamTabPanel { menu.add(clickDisplayManager.getModulesMenu()); - menuItem = new JMenuItem("Arrange Windows ..."); + menu.add(clickControl.angleVetoes.getDisplayMenuItem(parentFrame)); + + menu.addSeparator(); + + JCheckBoxMenuItem autoArrange = new JCheckBoxMenuItem("Auto arrange windows"); + autoArrange.setSelected(clickDisplayManager.cdmp.isManualWindowSizes() == false); + autoArrange.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + clickDisplayManager.cdmp.setManualWindowSizes(autoArrange.isSelected() == false); + if (autoArrange.isSelected()) { + clickPanel.arrangeWindows(); + } + } + }); + autoArrange.setToolTipText("Automatically arrange windows in a standard layout whenever the display dimensions change"); + menu.add(autoArrange); + + menuItem = new JMenuItem("Arrange Windows Now"); menuItem.addActionListener(new ArrangeWindows(parentFrame)); + menuItem.setToolTipText("Automatically arrange windows in a standard layout"); menu.add(menuItem); - menu.add(clickControl.angleVetoes.getDisplayMenuItem(parentFrame)); return menu; } diff --git a/src/clickDetector/ConcatenatedSpectParams.java b/src/clickDetector/ConcatenatedSpectParams.java index 6bf67108..db3f6a0b 100644 --- a/src/clickDetector/ConcatenatedSpectParams.java +++ b/src/clickDetector/ConcatenatedSpectParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.ColourArray.ColourArrayType; public class ConcatenatedSpectParams implements Serializable, Cloneable, ManagedParameters { @@ -44,7 +45,7 @@ public class ConcatenatedSpectParams implements Serializable, Cloneable, Manage @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/clickDetector/IDI_DisplayParams.java b/src/clickDetector/IDI_DisplayParams.java index 0198fe92..e7641768 100644 --- a/src/clickDetector/IDI_DisplayParams.java +++ b/src/clickDetector/IDI_DisplayParams.java @@ -29,6 +29,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; /** @@ -270,7 +271,7 @@ public class IDI_DisplayParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("saveOutput"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/TrackedClickGroupLogging.java b/src/clickDetector/TrackedClickGroupLogging.java index 6016f704..90e7af9a 100644 --- a/src/clickDetector/TrackedClickGroupLogging.java +++ b/src/clickDetector/TrackedClickGroupLogging.java @@ -1,5 +1,6 @@ package clickDetector; +import generalDatabase.PamTableDefinition; import generalDatabase.SQLTypes; import PamguardMVC.PamDataUnit; import clickDetector.offlineFuncs.OfflineEventDataUnit; @@ -30,7 +31,8 @@ public class TrackedClickGroupLogging extends ClickGroupLogging { boolean isUpdate = true; // Timestamp ts = (Timestamp) getTableDefinition().getTimeStampItem().getValue(); // long t = PamCalendar.millisFromTimeStamp(ts); - int updateIndex = (Integer) getTableDefinition().getUpdateReference().getValue(); + PamTableDefinition tableDef = (PamTableDefinition) getTableDefinition(); + int updateIndex = (Integer) tableDef.getUpdateReference().getValue(); if (updateIndex > 0) { tcg = this.clickGroupDataBlock.findByDatabaseIndex(updateIndex); } diff --git a/src/clickDetector/WignerPlotOptions.java b/src/clickDetector/WignerPlotOptions.java index 0ef46f2e..e05640a6 100644 --- a/src/clickDetector/WignerPlotOptions.java +++ b/src/clickDetector/WignerPlotOptions.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class WignerPlotOptions implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class WignerPlotOptions implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/clickDetector/alarm/ClickAlarmParameters.java b/src/clickDetector/alarm/ClickAlarmParameters.java index 3cc714b2..8bed53c6 100644 --- a/src/clickDetector/alarm/ClickAlarmParameters.java +++ b/src/clickDetector/alarm/ClickAlarmParameters.java @@ -7,6 +7,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamguardMVC.dataSelector.DataSelectParams; @@ -127,7 +128,7 @@ public class ClickAlarmParameters extends DataSelectParams implements Cloneable, @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("eventTypes"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/clicktrains/ClickTrainIdParams.java b/src/clickDetector/clicktrains/ClickTrainIdParams.java index 9f9b03c2..c6d4746f 100644 --- a/src/clickDetector/clicktrains/ClickTrainIdParams.java +++ b/src/clickDetector/clicktrains/ClickTrainIdParams.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; /** @@ -59,7 +60,7 @@ public class ClickTrainIdParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("dataVersion"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java b/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java index 668fec3e..a8cc198c 100644 --- a/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java +++ b/src/clickDetector/dataSelector/ClickTrainDataSelect2Params.java @@ -8,6 +8,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamguardMVC.dataSelector.DataSelectParams; @@ -91,7 +92,7 @@ public class ClickTrainDataSelect2Params extends DataSelectParams implements Clo @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("wantType"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/dataSelector/ClickTrainDataSelector2.java b/src/clickDetector/dataSelector/ClickTrainDataSelector2.java index 0520b4fb..9bde5123 100644 --- a/src/clickDetector/dataSelector/ClickTrainDataSelector2.java +++ b/src/clickDetector/dataSelector/ClickTrainDataSelector2.java @@ -82,7 +82,7 @@ public class ClickTrainDataSelector2 extends DataSelector { } SQLLogging logging = getPamDataBlock().getLogging(); if (logging == null) return null; //cannot happen! - PamTableDefinition tableDef = logging.getTableDefinition(); + EmptyTableDefinition tableDef = logging.getTableDefinition(); if (params.isIncludeUnclassified()) { return null; } diff --git a/src/clickDetector/dataSelector/ClickTrainSelectParameters.java b/src/clickDetector/dataSelector/ClickTrainSelectParameters.java index 3cfc5189..75462778 100644 --- a/src/clickDetector/dataSelector/ClickTrainSelectParameters.java +++ b/src/clickDetector/dataSelector/ClickTrainSelectParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.dataSelector.DataSelectParams; import clickDetector.ClickParameters; @@ -32,7 +33,7 @@ public class ClickTrainSelectParameters extends DataSelectParams implements Seri @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickDetector/echoDetection/JamieEchoParams.java b/src/clickDetector/echoDetection/JamieEchoParams.java index ec00df42..e3cbadb5 100644 --- a/src/clickDetector/echoDetection/JamieEchoParams.java +++ b/src/clickDetector/echoDetection/JamieEchoParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class JamieEchoParams implements Serializable, Cloneable, ManagedParameters { @@ -31,7 +32,7 @@ public static final long serialVersionUID = 3L; @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickDetector/echoDetection/SimpleEchoParams.java b/src/clickDetector/echoDetection/SimpleEchoParams.java index fe5eae8e..eb6095a1 100644 --- a/src/clickDetector/echoDetection/SimpleEchoParams.java +++ b/src/clickDetector/echoDetection/SimpleEchoParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class SimpleEchoParams implements Serializable, Cloneable, ManagedParameters { @@ -26,7 +27,7 @@ public class SimpleEchoParams implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickDetector/localisation/ClickLocParams.java b/src/clickDetector/localisation/ClickLocParams.java index fcfaaff6..6a597258 100644 --- a/src/clickDetector/localisation/ClickLocParams.java +++ b/src/clickDetector/localisation/ClickLocParams.java @@ -7,6 +7,7 @@ import java.util.Arrays; import Localiser.detectionGroupLocaliser.DetectionGroupOptions; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class ClickLocParams implements Serializable, Cloneable, DetectionGroupOptions, ManagedParameters { @@ -110,7 +111,7 @@ public class ClickLocParams implements Serializable, Cloneable, DetectionGroupOp @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("internalVersion"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/clickDetector/offlineFuncs/ClicksOffline.java b/src/clickDetector/offlineFuncs/ClicksOffline.java index 6628595e..4eff23ae 100644 --- a/src/clickDetector/offlineFuncs/ClicksOffline.java +++ b/src/clickDetector/offlineFuncs/ClicksOffline.java @@ -632,6 +632,7 @@ public class ClicksOffline { OfflineEventDataUnit newUnit = new OfflineEventDataUnit(null, getNextEventColourIndex(), null); newUnit = OfflineEventDialog.showDialog(win, clickControl, newUnit); if (newUnit != null) { + clickControl.removeFromEvents(markedClicks); newUnit.addSubDetections(markedClicks); offlineEventDataBlock.addPamData(newUnit); clickControl.setLatestOfflineEvent(newUnit); diff --git a/src/clickDetector/offlineFuncs/DatabaseChecks.java b/src/clickDetector/offlineFuncs/DatabaseChecks.java index 38bfe6a5..585bbf50 100644 --- a/src/clickDetector/offlineFuncs/DatabaseChecks.java +++ b/src/clickDetector/offlineFuncs/DatabaseChecks.java @@ -102,16 +102,17 @@ public class DatabaseChecks { long resultTime; long firstTime = Long.MAX_VALUE; long lastTime = Long.MIN_VALUE; + PamTableDefinition pamTableDef = (PamTableDefinition) clickLogging.getTableDefinition(); try { Statement stmt = con.getConnection().createStatement(); ResultSet result = stmt.executeQuery(sqlStr); while (result.next()) { nClicks++; clickLogging.transferDataFromResult(sqlTypes, result); - ts = clickLogging.getTableDefinition().getTimeStampItem().getValue(); + ts = pamTableDef.getTimeStampItem().getValue(); resultTime = sqlTypes.millisFromTimeStamp(ts); if (resultTime%1000 == 0) { - resultTime += clickLogging.getTableDefinition().getTimeStampMillis().getIntegerValue(); + resultTime += pamTableDef.getTimeStampMillis().getIntegerValue(); } firstTime = Math.min(firstTime, resultTime); lastTime = Math.max(lastTime, resultTime); @@ -188,7 +189,7 @@ public class DatabaseChecks { eventDataBlock.addPamData(event); PamConnection con = DBControlUnit.findConnection(); // now find a cursor and save it. - PamTableDefinition eventTableDef = eventDataBlock.getLogging().getTableDefinition(); + PamTableDefinition eventTableDef = (PamTableDefinition) eventDataBlock.getLogging().getTableDefinition(); PamCursor cursor = eventDataBlock.getLogging().getViewerCursorFinder().getCursor(con, eventTableDef); cursor.immediateInsert(con); int newId = event.getDatabaseIndex(); diff --git a/src/clickDetector/offlineFuncs/LabelClicksDialog.java b/src/clickDetector/offlineFuncs/LabelClicksDialog.java index 0e25b495..113f7864 100644 --- a/src/clickDetector/offlineFuncs/LabelClicksDialog.java +++ b/src/clickDetector/offlineFuncs/LabelClicksDialog.java @@ -146,6 +146,7 @@ public class LabelClicksDialog extends PamDialog { * @param thenClose option to close dialog */ private void addClicksToEvent(OfflineEventDataUnit event, boolean thenClose) { + removeFromOldEvent(markedClicks); event.addSubDetections(markedClicks); offlineEventListPanel.tableDataChanged(); clickControl.setLatestOfflineEvent(event); @@ -154,6 +155,15 @@ public class LabelClicksDialog extends PamDialog { } } + /** + * clicks may have already been part of an event, so need to remove them from that + * event first, and if there is nothing left in that event, delete the event. + * @param markedClicks2 + */ + private void removeFromOldEvent(List markedClicks) { + clickControl.removeFromEvents(markedClicks); + } + @Override public void restoreDefaultSettings() { // TODO Auto-generated method stub diff --git a/src/clickDetector/offlineFuncs/OfflineClickLogging.java b/src/clickDetector/offlineFuncs/OfflineClickLogging.java index a75897f7..43a73fea 100644 --- a/src/clickDetector/offlineFuncs/OfflineClickLogging.java +++ b/src/clickDetector/offlineFuncs/OfflineClickLogging.java @@ -51,7 +51,7 @@ public class OfflineClickLogging extends SQLLogging { tableDef.addTableItem(clickNumber = new PamTableItem("ClickNo", Types.INTEGER)); tableDef.addTableItem(amplitude = new PamTableItem("Amplitude", Types.DOUBLE)); tableDef.addTableItem(channelNumbers = new PamTableItem("Channels", Types.INTEGER)); - tableDef.setUseCheatIndexing(true); + tableDef.setUseCheatIndexing(false); setTableDefinition(tableDef); } @@ -277,13 +277,14 @@ public class OfflineClickLogging extends SQLLogging { Integer millis; Object ts; SQLTypes sqlTypes = dbControl.getConnection().getSqlTypes(); + PamTableDefinition tableDef = (PamTableDefinition) getTableDefinition(); try { while (resultSet.next()) { transferDataFromResult(sqlTypes, resultSet); - ts = getTableDefinition().getTimeStampItem().getValue(); + ts = tableDef.getTimeStampItem().getValue(); long m = SQLTypes.millisFromTimeStamp(ts); if (m%1000 == 0) { - millis = (Integer) getTableDefinition().getTimeStampMillis().getValue(); + millis = (Integer) tableDef.getTimeStampMillis().getValue(); if (millis != null) { m += millis; } diff --git a/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java b/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java index 4af5872b..afc60ec7 100644 --- a/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java +++ b/src/clickDetector/offlineFuncs/OfflineEventDataBlock.java @@ -16,6 +16,10 @@ import PamController.PamViewParameters; import PamUtils.PamCalendar; import PamView.symbol.StandardSymbolManager; import pamScrollSystem.ViewLoadObserver; +import tethys.TethysControl; +import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; +import clickDetector.ClickDetection; //import staticLocaliser.StaticLocaliserControl; //import staticLocaliser.StaticLocaliserProvider; //import staticLocaliser.panels.AbstractLocaliserControl; @@ -23,7 +27,12 @@ import pamScrollSystem.ViewLoadObserver; import clickDetector.ClickDetector; import clickDetector.ClickTrainDetection; import clickDetector.dataSelector.ClickTrainDataSelectorCreator; +import clickDetector.tethys.ClickEventSpeciesManager; +import clickDetector.tethys.ClickEventTethysDataProvider; +import clickDetector.tethys.ClickTethysDataProvider; import dataMap.OfflineDataMap; +import PamguardMVC.DataAutomation; +import PamguardMVC.DataAutomationInfo; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import PamguardMVC.dataOffline.OfflineDataLoadInfo; @@ -49,6 +58,8 @@ public class OfflineEventDataBlock extends SuperDetDataBlock getDatablockSpeciesManager() { + if (eventSpeciesManager == null) { + eventSpeciesManager = new ClickEventSpeciesManager(clickDetector, this); + } + return eventSpeciesManager; + } + + @Override + public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) { + if (eventTethysDataProvider == null) { + eventTethysDataProvider = new ClickEventTethysDataProvider(tethysControl, this); + } + return eventTethysDataProvider; + } + + @Override + public DataAutomationInfo getDataAutomationInfo() { + return new DataAutomationInfo(DataAutomation.MANUALANDAUTOMATIC); + } + } diff --git a/src/clickDetector/offlineFuncs/OfflineParameters.java b/src/clickDetector/offlineFuncs/OfflineParameters.java index 2ab82962..0c4b2c71 100644 --- a/src/clickDetector/offlineFuncs/OfflineParameters.java +++ b/src/clickDetector/offlineFuncs/OfflineParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class OfflineParameters implements Serializable, Cloneable, ManagedParameters { @@ -28,7 +29,7 @@ public class OfflineParameters implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java b/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java index d4fb6fb2..0b9b0996 100644 --- a/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java +++ b/src/clickDetector/offlineFuncs/rcImport/RainbowDatabseConverter.java @@ -148,7 +148,7 @@ public class RainbowDatabseConverter { ClickDataBlock clickDataBlock = clickControl.getClickDataBlock(); clickLogging = new ClickImportLogging(clickControl); - PamTableDefinition tableDef = clickLogging.getTableDefinition(); + PamTableDefinition tableDef = (PamTableDefinition) clickLogging.getTableDefinition(); boolean ok = checkTable(pamConnection, tableDef); if (!ok) { System.out.println("Error in Pamguard clicks table"); @@ -156,7 +156,7 @@ public class RainbowDatabseConverter { } eventLogging = new OfflineEventLogging(clickControl, clickControl.getClickDetector().getOfflineEventDataBlock()); - tableDef = eventLogging.getTableDefinition(); + tableDef = (PamTableDefinition) eventLogging.getTableDefinition(); ok = checkTable(pamConnection, tableDef); if (!ok) { System.out.println("Error in Pamguard events table"); diff --git a/src/clickDetector/tethys/ClickEventSpeciesManager.java b/src/clickDetector/tethys/ClickEventSpeciesManager.java new file mode 100644 index 00000000..c0ee92fd --- /dev/null +++ b/src/clickDetector/tethys/ClickEventSpeciesManager.java @@ -0,0 +1,57 @@ +package clickDetector.tethys; + +import java.util.Vector; + +import PamguardMVC.PamDataUnit; +import clickDetector.ClickControl; +import clickDetector.ClickDetector; +import clickDetector.offlineFuncs.ClicksOffline; +import clickDetector.offlineFuncs.OfflineEventDataBlock; +import clickDetector.offlineFuncs.OfflineEventDataUnit; +import generalDatabase.lookupTables.LookUpTables; +import generalDatabase.lookupTables.LookupItem; +import generalDatabase.lookupTables.LookupList; +import tethys.species.DataBlockSpeciesCodes; +import tethys.species.DataBlockSpeciesManager; + +public class ClickEventSpeciesManager extends DataBlockSpeciesManager { + + private OfflineEventDataBlock eventDataBlock; + private ClickDetector clickDetector; + private ClickControl clickControl; + private ClicksOffline clicksOffline; + + public ClickEventSpeciesManager(ClickDetector clickDetector, OfflineEventDataBlock eventDataBlock) { + super(eventDataBlock); + this.clickDetector = clickDetector; + this.eventDataBlock = eventDataBlock; + clickControl = clickDetector.getClickControl(); + clicksOffline = clickControl.getClicksOffline(); + } + + @Override + public DataBlockSpeciesCodes getSpeciesCodes() { + LookupList lutList = LookUpTables.getLookUpTables().getLookupList(ClicksOffline.ClickTypeLookupName); + if (lutList == null || lutList.getLutList().size() == 0) { + return new DataBlockSpeciesCodes("Unknown"); + } + Vector spList = lutList.getLutList(); + String[] spNames = new String[spList.size()]; + int i = 0; + for (LookupItem lItem : spList) { + spNames[i++] = lItem.getCode(); + } + return new DataBlockSpeciesCodes("Unknown", spNames); + } + + @Override + public String getSpeciesCode(PamDataUnit dataUnit) { + OfflineEventDataUnit eventDataUnit = (OfflineEventDataUnit) dataUnit; + String eventType = eventDataUnit.getEventType(); + if (eventType == null) { + eventType = "Unknown"; + } + return eventType; + } + +} diff --git a/src/clickDetector/tethys/ClickEventTethysDataProvider.java b/src/clickDetector/tethys/ClickEventTethysDataProvider.java new file mode 100644 index 00000000..bbc5d1fd --- /dev/null +++ b/src/clickDetector/tethys/ClickEventTethysDataProvider.java @@ -0,0 +1,72 @@ +package clickDetector.tethys; + +import java.math.BigInteger; + +import PamguardMVC.PamDataUnit; +import clickDetector.offlineFuncs.OfflineEventDataBlock; +import clickDetector.offlineFuncs.OfflineEventDataUnit; +import nilus.Detection; +import nilus.GranularityEnumType; +import nilus.Detection.Parameters; +import nilus.Detection.Parameters.UserDefined; +import tethys.TethysControl; +import tethys.output.StreamExportParams; +import tethys.output.TethysExportParams; +import tethys.pamdata.AutoTethysProvider; +import tethys.swing.export.ExportWizardCard; +import tethys.swing.export.GranularityCard; + +public class ClickEventTethysDataProvider extends AutoTethysProvider { + + private OfflineEventDataBlock eventDataBlock; + + public ClickEventTethysDataProvider(TethysControl tethysControl, OfflineEventDataBlock eventDataBlock) { + super(tethysControl, eventDataBlock); + this.eventDataBlock = eventDataBlock; + } + + @Override + public GranularityEnumType[] getAllowedGranularities() { + GranularityEnumType[] allowed = {GranularityEnumType.GROUPED}; + return allowed; + } + @Override + public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams, + StreamExportParams streamExportParams) { + Detection detection = super.createDetection(dataUnit, tethysExportParams, streamExportParams); + if (detection == null) { + return null; + } + OfflineEventDataUnit eventDataUnit = (OfflineEventDataUnit) dataUnit; + detection.setCount(BigInteger.valueOf(eventDataUnit.getSubDetectionsCount())); + String comment = eventDataUnit.getComment(); + if (comment != null && comment.length() > 0) { + detection.setComment(comment); + } + Parameters params = detection.getParameters(); + addUserNumber(params, "MinNumber", eventDataUnit.getMinNumber()); + addUserNumber(params, "BestNumber", eventDataUnit.getBestNumber()); + addUserNumber(params, "MaxNumber", eventDataUnit.getMaxNumber()); + + + return detection; + } + + private void addUserNumber(Parameters params, String numName, Short number) { + if (number == null) { + return; + } + addUserDefined(params, numName, number.toString()); + } + + @Override + public boolean wantExportDialogCard(ExportWizardCard wizPanel) { + if (wizPanel.getClass() == GranularityCard.class) { + return false; + } + else { + return true; + } + } + +} diff --git a/src/clickDetector/tethys/ClickTethysDataProvider.java b/src/clickDetector/tethys/ClickTethysDataProvider.java new file mode 100644 index 00000000..44e1c8c8 --- /dev/null +++ b/src/clickDetector/tethys/ClickTethysDataProvider.java @@ -0,0 +1,22 @@ +package clickDetector.tethys; + +import clickDetector.ClickDataBlock; +import nilus.GranularityEnumType; +import tethys.TethysControl; +import tethys.pamdata.AutoTethysProvider; + +public class ClickTethysDataProvider extends AutoTethysProvider { + + private ClickDataBlock clickDataBlock; + + public ClickTethysDataProvider(TethysControl tethysControl, ClickDataBlock clickDataBlock) { + super(tethysControl, clickDataBlock); + this.clickDataBlock = clickDataBlock; + } + + @Override + public GranularityEnumType[] getAllowedGranularities() { + return GranularityEnumType.values(); // everything ! + } + +} diff --git a/src/clickTrainDetector/ClickTrainParams.java b/src/clickTrainDetector/ClickTrainParams.java index 1200883d..0a3663b9 100644 --- a/src/clickTrainDetector/ClickTrainParams.java +++ b/src/clickTrainDetector/ClickTrainParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamUtils; import clickTrainDetector.classification.CTClassifierParams; import clickTrainDetector.classification.simplechi2classifier.Chi2ThresholdParams; @@ -127,7 +128,7 @@ public class ClickTrainParams implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickTrainDetector/classification/CTClassifierParams.java b/src/clickTrainDetector/classification/CTClassifierParams.java index 91d4e8a7..64fa96e9 100644 --- a/src/clickTrainDetector/classification/CTClassifierParams.java +++ b/src/clickTrainDetector/classification/CTClassifierParams.java @@ -5,6 +5,7 @@ import java.util.UUID; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; @@ -68,7 +69,7 @@ public class CTClassifierParams implements Cloneable, Serializable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java b/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java index 83a326c8..b3e26d12 100644 --- a/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java +++ b/src/clickTrainDetector/classification/templateClassifier/SpectrumTemplateParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * @@ -53,7 +54,7 @@ public class SpectrumTemplateParams implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java index 499fee9f..046c6478 100644 --- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java +++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTChi2Params.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Parameters class must extend this. @@ -38,7 +39,7 @@ public class MHTChi2Params implements Cloneable, Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java index 43b58860..bf312d7e 100644 --- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java +++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTClickTrainAlgorithm.java @@ -45,6 +45,7 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings public static final String MHT_NAME = "MHT detector"; + /** * Reference to the click train control. */ @@ -354,6 +355,7 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings TrackBitSet trackBitSet; TrackDataUnits trackUnits; if (nTracks>0) Debug.out.println("-------------------Grab Done Trains---------------"); + try { for (int i =0; i0) Debug.out.println("-------------------------------------------------"); @@ -415,12 +421,19 @@ public class MHTClickTrainAlgorithm implements ClickTrainAlgorithm, PamSettings return mhtGUI; } + Thread previousThread = null; /** * Update the algorithm * @param flag- flag indicating the update type. */ - public void update(int flag, Object info) { + public synchronized void update(int flag, Object info) { + if (Thread.currentThread() != previousThread) { + // see flag id constants in ClickTrianControl + System.out.printf("Thread change to %s in MHTClicktrainAlgorithm.update flag %d, object %s\n", + Thread.currentThread().toString(), flag, info); + previousThread = Thread.currentThread(); + } switch (flag) { case ClickTrainControl.PROCESSING_START: //make sure the kernel is cleared before processing diff --git a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java index 9666a3c2..585d5d39 100644 --- a/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java +++ b/src/clickTrainDetector/clickTrainAlgorithms/mht/MHTKernel.java @@ -3,6 +3,7 @@ package clickTrainDetector.clickTrainAlgorithms.mht; import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; +import java.util.Comparator; import PamUtils.PamArrayUtils; import PamguardMVC.debug.Debug; @@ -285,28 +286,39 @@ public class MHTKernel { BitSet currentBitSet; MHTChi2 mhtChi2; int index; - for (int i=0; i { //first sort the tracks by increasing chi2 values. //sort the possible tracks by chi2 values //now sort the chi2 values so they correspond to the track list. - Collections.sort(newPossibleTracks, (left, right)->{ - //Note- this is definitely in the correct order - return Double.compare(left.chi2Track.getChi2(), right.chi2Track.getChi2()); - }); +// Collections.sort(newPossibleTracks, (left, right)->{ +// //Note- this is definitely in the correct order +// return Double.compare(left.chi2Track.getChi2(), right.chi2Track.getChi2()); +// }); + try { + Collections.sort(newPossibleTracks, new Comparator() { + @Override + public int compare(TrackBitSet left, TrackBitSet right) { + return Double.compare(left.chi2Track.getChi2(), right.chi2Track.getChi2()); + } + }); + } + catch (Exception e) { + System.out.printf("Handled MHTKernel Exception %s in pruneProbMatrix: %s\n", e.getClass().getSimpleName(), e.getMessage()); + } // for (int i=0; i checkAllDatagrams() { ArrayList grammedDataBlocks = getDataBlocks(); ArrayList updateBlocks = new ArrayList(); + boolean isBatch = GlobalArguments.getParam("-batch") != null; /** * Check to see if any of the blocks have an existing datagram */ - if (datagramSettings.validDatagramSettings == false) { + if (datagramSettings.validDatagramSettings == false && isBatch == false) { /* * this is the first time this has been run, so ask * the user what datagram size they want. @@ -169,6 +171,8 @@ public class DatagramManager { private volatile DatagramProgressDialog datagramProgressDialog; + private volatile DatagramCreator datagramCreator; + /** * update a list of datagrams. This should be done in a @@ -176,9 +180,17 @@ public class DatagramManager { * @param updateList */ public void updateDatagrams(ArrayList updateList) { - DatagramCreator datagramCreator = new DatagramCreator(updateList); + datagramCreator = new DatagramCreator(updateList); AWTScheduler.getInstance().scheduleTask(datagramCreator); } + + /** + * Get true if the datagram worker is running. + * @return + */ + public boolean getStatus() { + return datagramCreator != null; + } class DatagramCreatorTask extends Task { @@ -542,6 +554,7 @@ public class DatagramManager { publish(new DatagramProgress(PamTaskUpdate.STATUS_DONE, 1, 1)); } + datagramCreator = null; } @Override diff --git a/src/dataGram/DatagramSettings.java b/src/dataGram/DatagramSettings.java index e466d55d..a3b5a4df 100644 --- a/src/dataGram/DatagramSettings.java +++ b/src/dataGram/DatagramSettings.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DatagramSettings implements Serializable, Cloneable, ManagedParameters { @@ -33,7 +34,7 @@ public class DatagramSettings implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataMap/DataMapParameters.java b/src/dataMap/DataMapParameters.java index 22eed747..cd714199 100644 --- a/src/dataMap/DataMapParameters.java +++ b/src/dataMap/DataMapParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DataMapParameters implements Cloneable, Serializable, ManagedParameters { @@ -36,7 +37,7 @@ public class DataMapParameters implements Cloneable, Serializable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataMap/DataStreamPanel.java b/src/dataMap/DataStreamPanel.java index 957eadfd..275be1f5 100644 --- a/src/dataMap/DataStreamPanel.java +++ b/src/dataMap/DataStreamPanel.java @@ -747,11 +747,20 @@ public class DataStreamPanel extends JPanel implements DataMapObserver { String tipText; if (startTimeArrow != null && startTimeArrow.contains(me.getPoint())) { - tipText = "Data Start: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataStart(), true); + tipText = "Data Start: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataStart(), false); } else if (endTimeArrow != null && endTimeArrow.contains(me.getPoint())) { - tipText = "Data End: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataEnd(), true); + tipText = "Data End: " + PamCalendar.formatDateTime(dataBlock.getCurrentViewDataEnd(), false); } else { - tipText = "Cursor: " + PamCalendar.formatDateTime(tm, true); + OfflineDataMap dMap = dataBlock.getPrimaryDataMap(); + if (dMap != null) { + tipText = String.format("%s Data from

%s to %s

Cursor: %s", dataBlock.getDataName(), + PamCalendar.formatDateTime(dMap.getFirstDataTime(), false), + PamCalendar.formatDateTime(dMap.getLastDataTime(), false), + PamCalendar.formatDateTime(tm, true)); + } + else { + tipText = "Cursor: " + PamCalendar.formatDateTime(tm, true); + } } // tipText += "
Panel height = " + getHeight(); diff --git a/src/dataMap/OfflineDataMap.java b/src/dataMap/OfflineDataMap.java index 2295af01..d51ee120 100644 --- a/src/dataMap/OfflineDataMap.java +++ b/src/dataMap/OfflineDataMap.java @@ -84,6 +84,8 @@ abstract public class OfflineDataMap { public static final int POINT_END = 0x8; // 8 public static final int IN_DATA = 0x10; // 16 public static final int NO_DATA = 0x20; // 32 + + private static final long oneDayInMillis = 3600L*24L*1000L; public OfflineDataMap(OfflineDataStore offlineDataStore, PamDataBlock parentDataBlock) { super(); @@ -145,10 +147,10 @@ abstract public class OfflineDataMap { */ synchronized public void addDataPoint(TmapPoint mapPoint) { boolean first = (mapPoints.size() == 0); - if (mapPoint.getStartTime() > 0) { + if (mapPoint.getStartTime() > oneDayInMillis) { firstDataTime = Math.min(firstDataTime, mapPoint.getStartTime()); } - if (mapPoint.getEndTime() > 0) { + if (mapPoint.getEndTime() > oneDayInMillis) { lastDataTime = Math.max(lastDataTime, mapPoint.getEndTime()); // if (mapPoint.getEndTime() > System.currentTimeMillis()) { // System.out.println("Stupid large data time in " + mapPoint.getName()); @@ -273,10 +275,10 @@ abstract public class OfflineDataMap { while (it.hasNext()) { aPoint = it.next(); - if (aPoint.getStartTime() > 0) { + if (aPoint.getStartTime() > oneDayInMillis) { firstDataTime = Math.min(firstDataTime, aPoint.getStartTime()); } - if (aPoint.getEndTime() > 0) { + if (aPoint.getEndTime() > oneDayInMillis) { lastDataTime = Math.max(lastDataTime, aPoint.getEndTime()); } n = aPoint.getNDatas(); @@ -361,6 +363,28 @@ abstract public class OfflineDataMap { } } + /** + * Get the start time of the first datamap point or Long.minval + * @return + */ + public long getMapStartTime() { + if (mapPoints == null || mapPoints.size() == 0) { + return Long.MIN_VALUE; + } + return mapPoints.get(0).getStartTime(); + } + + /** + * Get the start time of the first datamap point or Long.minval + * @return + */ + public long getMapEndTime() { + if (mapPoints == null || mapPoints.size() == 0) { + return Long.MIN_VALUE; + } + return mapPoints.get(mapPoints.size()-1).getEndTime(); + } + /** * @return the lowestPoint */ diff --git a/src/dataMap/OfflineDataMapPoint.java b/src/dataMap/OfflineDataMapPoint.java index af9e1910..d1e8917c 100644 --- a/src/dataMap/OfflineDataMapPoint.java +++ b/src/dataMap/OfflineDataMapPoint.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamCalendar; /** @@ -251,7 +252,7 @@ abstract public class OfflineDataMapPoint implements Comparable impl // TODO Auto-generated method stub return "Sound Files"; } + + @Override + public String getDataLocation() { + getOfflineFileParameters(); + return offlineFileParameters.folderName; + } public TmapPoint findFirstMapPoint(Iterator mapIterator, long startMillis, long endMillis) { TmapPoint mapPoint, prevMapPoint = null; diff --git a/src/dataPlots/TDParameters.java b/src/dataPlots/TDParameters.java index 80d67871..bb7f14db 100644 --- a/src/dataPlots/TDParameters.java +++ b/src/dataPlots/TDParameters.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import dataPlots.layout.GraphParameters; import pamScrollSystem.PamScroller; @@ -45,7 +46,7 @@ public class TDParameters implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataPlots/layout/DataListInfo.java b/src/dataPlots/layout/DataListInfo.java index 05edd3f8..d506fe64 100644 --- a/src/dataPlots/layout/DataListInfo.java +++ b/src/dataPlots/layout/DataListInfo.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * TDDataInfo objects can't be serialised since they contain @@ -44,7 +45,7 @@ public class DataListInfo implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataPlots/layout/GraphParameters.java b/src/dataPlots/layout/GraphParameters.java index f505422e..5fc3fe2a 100644 --- a/src/dataPlots/layout/GraphParameters.java +++ b/src/dataPlots/layout/GraphParameters.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import dataPlots.data.TDDataInfo; @@ -41,7 +42,7 @@ public class GraphParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("dataListInfos"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/dataPlotsFX/TDGraphParametersFX.java b/src/dataPlotsFX/TDGraphParametersFX.java index c4d6de46..f3f6c691 100644 --- a/src/dataPlotsFX/TDGraphParametersFX.java +++ b/src/dataPlotsFX/TDGraphParametersFX.java @@ -8,6 +8,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.GeneralProjector.ParameterType; import PamView.GeneralProjector.ParameterUnits; import javafx.scene.paint.Color; @@ -137,7 +138,7 @@ public class TDGraphParametersFX implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("channels"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/dataPlotsFX/TDParametersFX.java b/src/dataPlotsFX/TDParametersFX.java index c87320bc..8b614dcc 100644 --- a/src/dataPlotsFX/TDParametersFX.java +++ b/src/dataPlotsFX/TDParametersFX.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import javafx.geometry.Orientation; import userDisplayFX.UserDisplayNodeParams; @@ -122,7 +123,7 @@ public class TDParametersFX implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataPlotsFX/data/TDScaleInfoData.java b/src/dataPlotsFX/data/TDScaleInfoData.java index a0d54dba..9cd2ea3c 100644 --- a/src/dataPlotsFX/data/TDScaleInfoData.java +++ b/src/dataPlotsFX/data/TDScaleInfoData.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamguardMVC.PamConstants; @@ -105,7 +106,7 @@ public class TDScaleInfoData implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("autoDivisor"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java b/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java index 388ea462..ec6a1030 100644 --- a/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java +++ b/src/dataPlotsFX/rawClipDataPlot/FFTPlotSettings.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType; @@ -48,7 +49,7 @@ public class FFTPlotSettings implements ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java b/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java index c39aeb96..de80f049 100644 --- a/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java +++ b/src/dataPlotsFX/scroller/TDAcousticScrollerParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import dataPlotsFX.scrollingPlot2D.StandardPlot2DColours; import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType; @@ -55,7 +56,7 @@ public class TDAcousticScrollerParams implements Cloneable, Serializable, Manage @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java b/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java index 159fa2ad..40aed7c7 100644 --- a/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java +++ b/src/dataPlotsFX/scrollingPlot2D/PlotParams2D.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.scene.paint.Color; @@ -156,7 +157,7 @@ public class PlotParams2D implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java b/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java index 7aafc8ad..a8f2faa2 100644 --- a/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java +++ b/src/dataPlotsFX/spectrogramPlotFX/SpectrogramParamsFX.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import dataPlotsFX.scrollingPlot2D.PlotParams2D; import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType; import javafx.beans.property.DoubleProperty; @@ -125,7 +126,7 @@ public class SpectrogramParamsFX extends PlotParams2D implements Serializable, @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dbht/DbHtDisplayParams.java b/src/dbht/DbHtDisplayParams.java index 61e8386c..fb7cab16 100644 --- a/src/dbht/DbHtDisplayParams.java +++ b/src/dbht/DbHtDisplayParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DbHtDisplayParams implements Serializable, Cloneable, ManagedParameters { @@ -40,7 +41,7 @@ public class DbHtDisplayParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/dbht/DbHtParameters.java b/src/dbht/DbHtParameters.java index 7ef321f7..2e32bb3e 100644 --- a/src/dbht/DbHtParameters.java +++ b/src/dbht/DbHtParameters.java @@ -9,6 +9,7 @@ import PamModel.parametermanager.FieldNotFoundException; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterData; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class DbHtParameters implements Serializable, Cloneable, ManagedParameters { @@ -186,7 +187,7 @@ public class DbHtParameters implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("frequencyPoints"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/dbht/alarm/DbHtAlarmParameters.java b/src/dbht/alarm/DbHtAlarmParameters.java index beb98589..5023e1ae 100644 --- a/src/dbht/alarm/DbHtAlarmParameters.java +++ b/src/dbht/alarm/DbHtAlarmParameters.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class DbHtAlarmParameters implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class DbHtAlarmParameters implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("returnedMeasure"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/dbht/offline/DbHtSummaryParams.java b/src/dbht/offline/DbHtSummaryParams.java index b77adf17..34c4951a 100644 --- a/src/dbht/offline/DbHtSummaryParams.java +++ b/src/dbht/offline/DbHtSummaryParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DbHtSummaryParams implements Serializable, Cloneable, ManagedParameters { @@ -23,7 +24,7 @@ public class DbHtSummaryParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/decimator/DecimatorControl.java b/src/decimator/DecimatorControl.java index 9be3d77b..4b09dc29 100644 --- a/src/decimator/DecimatorControl.java +++ b/src/decimator/DecimatorControl.java @@ -202,6 +202,15 @@ public class DecimatorControl extends PamControlledUnit implements PamSettings, } return offlineFileServer.getDataSourceName(); } + + @Override + public String getDataLocation() { + if (offlineFileServer == null) { + return getUnitName(); + } + return offlineFileServer.getDataLocation(); + } + @Override public boolean loadData(PamDataBlock dataBlock, OfflineDataLoadInfo offlineDataLoadInfo, ViewLoadObserver loadObserver) { if (offlineFileServer == null) { diff --git a/src/decimator/DecimatorParams.java b/src/decimator/DecimatorParams.java index 6f37fbf8..21e29ce4 100644 --- a/src/decimator/DecimatorParams.java +++ b/src/decimator/DecimatorParams.java @@ -26,6 +26,7 @@ import Filters.FilterBand; import Filters.FilterParams; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DecimatorParams implements Serializable, Cloneable, ManagedParameters { @@ -102,7 +103,7 @@ public class DecimatorParams implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/decimator/DecimatorProcessW.java b/src/decimator/DecimatorProcessW.java index 3ade7634..e99260bb 100644 --- a/src/decimator/DecimatorProcessW.java +++ b/src/decimator/DecimatorProcessW.java @@ -41,8 +41,10 @@ public class DecimatorProcessW extends PamProcess { @Override public void pamStart() { - // TODO Auto-generated method stub - + outputDataBlock.reset(); + if (decimatorWorker != null) { + decimatorWorker.reset(); + } } @Override diff --git a/src/decimator/DecimatorWorker.java b/src/decimator/DecimatorWorker.java index db3b4104..21908a12 100644 --- a/src/decimator/DecimatorWorker.java +++ b/src/decimator/DecimatorWorker.java @@ -77,6 +77,13 @@ public class DecimatorWorker { createFilters(); } + /** + * Reset all counters and output buffers. + */ + public void reset() { + createFilters(); + } + /** * Make the decimator filters. If reducing frequency, then the filter * is applied before decimation (obviously!) so is set up based on the diff --git a/src/depthReadout/DepthParameters.java b/src/depthReadout/DepthParameters.java index 1e40df4e..99dcdd25 100644 --- a/src/depthReadout/DepthParameters.java +++ b/src/depthReadout/DepthParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DepthParameters implements Serializable, Cloneable, ManagedParameters { @@ -37,7 +38,7 @@ public class DepthParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/depthReadout/MccDepthParameters.java b/src/depthReadout/MccDepthParameters.java index 7859a1a7..d027670a 100644 --- a/src/depthReadout/MccDepthParameters.java +++ b/src/depthReadout/MccDepthParameters.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import mcc.MccJniInterface; import mcc.mccjna.MCCConstants; @@ -44,7 +45,7 @@ public class MccDepthParameters implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } @@ -62,7 +63,7 @@ public class MccDepthParameters implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("mccSensorParameters"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/detectionPlotFX/plots/FFTPlotParams.java b/src/detectionPlotFX/plots/FFTPlotParams.java index 483f9051..3b8a428d 100644 --- a/src/detectionPlotFX/plots/FFTPlotParams.java +++ b/src/detectionPlotFX/plots/FFTPlotParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType; public class FFTPlotParams implements Serializable, Cloneable, ManagedParameters { @@ -98,7 +99,7 @@ public class FFTPlotParams implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/detectionPlotFX/plots/SpectrumPlotParams.java b/src/detectionPlotFX/plots/SpectrumPlotParams.java index 36d1807e..c0790a9a 100644 --- a/src/detectionPlotFX/plots/SpectrumPlotParams.java +++ b/src/detectionPlotFX/plots/SpectrumPlotParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class SpectrumPlotParams implements Serializable, Cloneable, ManagedParameters { @@ -38,7 +39,7 @@ public class SpectrumPlotParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/detectionPlotFX/plots/WaveformPlotParams.java b/src/detectionPlotFX/plots/WaveformPlotParams.java index 0c631272..fefc68b5 100644 --- a/src/detectionPlotFX/plots/WaveformPlotParams.java +++ b/src/detectionPlotFX/plots/WaveformPlotParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import depthReadout.DepthParameters; import fftFilter.FFTFilterParams; @@ -63,7 +64,7 @@ public class WaveformPlotParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/detectionPlotFX/plots/WignerPlotParams.java b/src/detectionPlotFX/plots/WignerPlotParams.java index 0dece899..15f38498 100644 --- a/src/detectionPlotFX/plots/WignerPlotParams.java +++ b/src/detectionPlotFX/plots/WignerPlotParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import pamViewFX.fxNodes.utilsFX.ColourArray.ColourArrayType; @@ -51,7 +52,7 @@ public class WignerPlotParams implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/detectiongrouplocaliser/DetectionGroupProcess.java b/src/detectiongrouplocaliser/DetectionGroupProcess.java index 3c5158fb..587b3719 100644 --- a/src/detectiongrouplocaliser/DetectionGroupProcess.java +++ b/src/detectiongrouplocaliser/DetectionGroupProcess.java @@ -458,6 +458,7 @@ public class DetectionGroupProcess extends PamProcess { detectionGroupDataBlock.saveViewerData(); int nUpdates = 0; int nOK = 0; + int consecutiveOK = 0; System.out.printf("Checking %d data units in %s ", detectionGroupDataBlock.getUnitsCount(), detectionGroupDataBlock.getDataName()); synchronized (detectionGroupDataBlock.getSynchLock()) { ListIterator it = detectionGroupDataBlock.getListIterator(0); @@ -466,11 +467,16 @@ public class DetectionGroupProcess extends PamProcess { boolean ok = checkDataIntegrity(du, false); if (ok) { nUpdates++; + consecutiveOK = 0; } else { nOK++; + consecutiveOK++; } System.out.printf("."); + if (consecutiveOK % 80 == 0) { + System.out.printf("\n"); + } } } System.out.printf("\n%s: %d out of %d data units required corrections\n", detectionGroupDataBlock.getDataName(), nUpdates, nUpdates+nOK); @@ -486,7 +492,7 @@ public class DetectionGroupProcess extends PamProcess { subTabLogging = detectionGroupLogging.getSubLogging(); PamConnection con = DBControlUnit.findConnection(); String desc = String.format("Detection group UID %d at %s", du.getUID(), PamCalendar.formatDBDateTime(du.getTimeMilliseconds())); - String idList = "( " + du.getUID() + " )"; + String idList = "( " + du.getDatabaseIndex() + " )"; ArrayList stData = subTabLogging.loadSubtableData(con, detectionGroupLogging, idList, null); if (stData == null) { System.out.println("Error loading sub table data for event uid " + du.getUID()); diff --git a/src/detectiongrouplocaliser/DetectionGroupSettings.java b/src/detectiongrouplocaliser/DetectionGroupSettings.java index 318d2b8c..3bc28816 100644 --- a/src/detectiongrouplocaliser/DetectionGroupSettings.java +++ b/src/detectiongrouplocaliser/DetectionGroupSettings.java @@ -6,6 +6,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamView.paneloverlay.overlaymark.OverlayMarkDataInfo; import annotation.handler.AnnotationChoices; @@ -109,7 +110,7 @@ public class DetectionGroupSettings implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("overlayMarkInfo"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/difar/DifarParameters.java b/src/difar/DifarParameters.java index c54774e9..b8b8dc8c 100644 --- a/src/difar/DifarParameters.java +++ b/src/difar/DifarParameters.java @@ -15,6 +15,7 @@ import Filters.FilterType; import PamController.PamController; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamUtils.PamCalendar; import PamView.PamGui; @@ -588,7 +589,7 @@ public class DifarParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } @@ -659,7 +660,7 @@ public class DifarParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } @@ -773,7 +774,7 @@ public class DifarParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("groupList"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/difar/beamforming/BeamformControl.java b/src/difar/beamforming/BeamformControl.java index edf3507b..bf04ea05 100644 --- a/src/difar/beamforming/BeamformControl.java +++ b/src/difar/beamforming/BeamformControl.java @@ -88,6 +88,16 @@ public class BeamformControl extends PamControlledUnit implements PamSettings, O return DifarParameters.serialVersionUID; } + @Override + public String getDataLocation() { + if (offlineFileServer != null) { + return offlineFileServer.getDataLocation(); + } + else { + return null; + } + } + @Override public boolean restoreSettings( PamControlledUnitSettings pamControlledUnitSettings) { diff --git a/src/difar/beamforming/BeamformParameters.java b/src/difar/beamforming/BeamformParameters.java index 6688d309..2d65e576 100644 --- a/src/difar/beamforming/BeamformParameters.java +++ b/src/difar/beamforming/BeamformParameters.java @@ -5,6 +5,8 @@ import Filters.FilterParams; import Filters.FilterType; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; +import PamUtils.DeepCloner; import PamUtils.PamUtils; public class BeamformParameters implements Serializable, Cloneable, ManagedParameters { @@ -110,7 +112,7 @@ public class BeamformParameters implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/difar/dataSelector/DifarSelectParameters.java b/src/difar/dataSelector/DifarSelectParameters.java index bc9814ad..af1c703e 100644 --- a/src/difar/dataSelector/DifarSelectParameters.java +++ b/src/difar/dataSelector/DifarSelectParameters.java @@ -6,6 +6,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamUtils; import PamguardMVC.dataSelector.DataSelectParams; @@ -61,7 +62,7 @@ public class DifarSelectParameters extends DataSelectParams implements Cloneable @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/difar/demux/GreenridgeParams.java b/src/difar/demux/GreenridgeParams.java index d86fa2da..470357df 100644 --- a/src/difar/demux/GreenridgeParams.java +++ b/src/difar/demux/GreenridgeParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class GreenridgeParams implements Serializable, Cloneable, ManagedParameters { @@ -144,7 +145,7 @@ public class GreenridgeParams implements Serializable, Cloneable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/difar/trackedGroups/TrackedGroupSqlLogging.java b/src/difar/trackedGroups/TrackedGroupSqlLogging.java index 54bd708b..e3b8b15b 100644 --- a/src/difar/trackedGroups/TrackedGroupSqlLogging.java +++ b/src/difar/trackedGroups/TrackedGroupSqlLogging.java @@ -125,7 +125,7 @@ public class TrackedGroupSqlLogging extends SQLLogging { */ protected void updateData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) { - PamTableDefinition tableDef = getTableDefinition(); + PamTableDefinition tableDef = (PamTableDefinition) getTableDefinition(); PamTableItem tableItem; tableDef.getIndexItem().setValue(pamDataUnit.getDatabaseIndex()); diff --git a/src/effortmonitor/EffortParams.java b/src/effortmonitor/EffortParams.java index fcd5bcb5..d19d3e36 100644 --- a/src/effortmonitor/EffortParams.java +++ b/src/effortmonitor/EffortParams.java @@ -5,6 +5,7 @@ import java.util.LinkedList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class EffortParams implements Cloneable, Serializable, ManagedParameters { @@ -100,7 +101,7 @@ public class EffortParams implements Cloneable, Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/effortmonitor/swing/EffortDialog.java b/src/effortmonitor/swing/EffortDialog.java index 4f4d8b7f..6850415f 100644 --- a/src/effortmonitor/swing/EffortDialog.java +++ b/src/effortmonitor/swing/EffortDialog.java @@ -43,7 +43,7 @@ public class EffortDialog extends PamDialog { mainPanel.add(new JLabel("Observer name or initials"), c); c.gridx++; mainPanel.add(observer = new JComboBox(), c); - outerOnly = new JRadioButton("Log uter scroll only"); + outerOnly = new JRadioButton("Log outer scroll only"); allActions = new JRadioButton("Log all scroll actions"); ButtonGroup bg = new ButtonGroup(); bg.add(allActions); diff --git a/src/envelopeTracer/EnvelopeParams.java b/src/envelopeTracer/EnvelopeParams.java index 09b427f9..6076deb9 100644 --- a/src/envelopeTracer/EnvelopeParams.java +++ b/src/envelopeTracer/EnvelopeParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import Filters.FilterParams; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class EnvelopeParams implements Serializable, Cloneable, ManagedParameters { @@ -34,7 +35,7 @@ public class EnvelopeParams implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/fftFilter/FFTFilterParams.java b/src/fftFilter/FFTFilterParams.java index dd4d8ab0..bae3a3b6 100644 --- a/src/fftFilter/FFTFilterParams.java +++ b/src/fftFilter/FFTFilterParams.java @@ -8,6 +8,7 @@ import org.w3c.dom.Element; import Filters.FilterBand; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.FrequencyFormat; public class FFTFilterParams implements Serializable, Cloneable, ManagedParameters { @@ -62,7 +63,7 @@ public class FFTFilterParams implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/fftManager/Complex.java b/src/fftManager/Complex.java index 25b53edd..e2e13ded 100644 --- a/src/fftManager/Complex.java +++ b/src/fftManager/Complex.java @@ -25,6 +25,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Class definition for a Complex number type. @@ -349,7 +350,7 @@ public class Complex implements Cloneable, Serializable, Comparable, Ma @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/fftManager/FFTDataBlock.java b/src/fftManager/FFTDataBlock.java index db04f8d6..3bf0b7b1 100644 --- a/src/fftManager/FFTDataBlock.java +++ b/src/fftManager/FFTDataBlock.java @@ -4,6 +4,9 @@ import java.util.List; import java.util.ListIterator; import java.util.Vector; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import PamView.GeneralProjector.ParameterType; import PamView.GeneralProjector.ParameterUnits; import PamguardMVC.DataBlock2D; @@ -186,6 +189,13 @@ public class FFTDataBlock extends DataBlock2D { public DataTypeInfo getScaleInfo() { return dataTypeInfo; } + @Override + public Element getDataBlockXML(Document doc) { + Element el = super.getDataBlockXML(doc); + el.setAttribute("FFTLength", String.format("%d", getFftLength())); + el.setAttribute("FFTHop", String.format("%d", getFftHop())); + return el; + } diff --git a/src/fftManager/FFTDataDisplayOptions.java b/src/fftManager/FFTDataDisplayOptions.java index a6d17619..969a7a81 100644 --- a/src/fftManager/FFTDataDisplayOptions.java +++ b/src/fftManager/FFTDataDisplayOptions.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class FFTDataDisplayOptions implements Serializable, Cloneable, ManagedParameters { @@ -45,7 +46,7 @@ public class FFTDataDisplayOptions implements Serializable, Cloneable, ManagedPa @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("maxVal"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/fftManager/PamFFTProcess.java b/src/fftManager/PamFFTProcess.java index 34b45371..1d8cbb56 100644 --- a/src/fftManager/PamFFTProcess.java +++ b/src/fftManager/PamFFTProcess.java @@ -124,6 +124,7 @@ public class PamFFTProcess extends PamProcess { public synchronized void setupFFT() { + System.out.println("In call to setupFFT in " + getProcessName()); // need to find the existing source data block and remove from observing it. // then find the new one and subscribe to that instead. channelCounts = new int[PamConstants.MAX_CHANNELS]; @@ -390,28 +391,32 @@ public class PamFFTProcess extends PamProcess { } } } + TempOutputStore[] oldStores = tempStores; if (iChan == PamUtils.getHighestChannel(fftParameters.channelMap)) { // time to empty the stores - assume they all have the same // amount of data int[] chanList = PamUtils.getChannelArray(fftParameters.channelMap); try { - int n = tempStores[iChan].getN(); - for (int iF = 0; iF < n; iF++) { - for (int iC = 0; iC < chanList.length; iC++) { -// pu = tempStores[chanList[iC]].get(iF); - try { - outputData.addPamData(tempStores[chanList[iC]].get(iF)); + int n = tempStores[iChan].getN(); + for (int iF = 0; iF < n; iF++) { + for (int iC = 0; iC < chanList.length; iC++) { + // pu = tempStores[chanList[iC]].get(iF); + try { + outputData.addPamData(tempStores[chanList[iC]].get(iF)); + } + catch (ArrayIndexOutOfBoundsException e) { + // e.printStackTrace(); + System.err.printf("%s.newData: %s Store %s (was %s) iC: %d of %d iF: %d of %d\n", + this.getPamControlledUnit().getUnitName(), e.getMessage(), + tempStores[chanList[iC]], oldStores[chanList[iC]], + iC, chanList.length, iF, n); + } + // outputData.addPamData(null); } - catch (ArrayIndexOutOfBoundsException e) { -// e.printStackTrace(); - System.err.println("PAMFFTProcess.newData: " + e.getMessage() + " " + this.getPamControlledUnit().getUnitName() + " iC: " + iC + " iF: " + iF); - } -// outputData.addPamData(null); } - } - for (int iC = 0; iC < chanList.length; iC++) { - tempStores[chanList[iC]].clearStore(); - } + for (int iC = 0; iC < chanList.length; iC++) { + tempStores[chanList[iC]].clearStore(); + } } catch (Exception e) { e.printStackTrace(); @@ -539,6 +544,25 @@ public class PamFFTProcess extends PamProcess { return new ArrayList>(Arrays.asList(RawDataUnit.class)); } + @Override + public synchronized void dumpBufferStatus(String message, boolean sayEmpties) { + + super.dumpBufferStatus(message, sayEmpties); + int nTemp = 0; + if (tempStores != null) { + nTemp = tempStores.length; + } + for (int i = 0; i < nTemp; i++) { + if (tempStores[i] == null) { + continue; + } + int n = tempStores[i].tempUnits.size(); + if (n > 0 || sayEmpties) { + System.out.printf("FFT %s temp store %d has %d datas\n", getProcessName(), i, n); + } + } + } + // @Override // public boolean requestOfflineData(PamDataBlock dataBlock, long startMillis, // long endMillis) { diff --git a/src/fileOfflineData/OfflineFileControl.java b/src/fileOfflineData/OfflineFileControl.java index cb408652..45998aaf 100644 --- a/src/fileOfflineData/OfflineFileControl.java +++ b/src/fileOfflineData/OfflineFileControl.java @@ -54,6 +54,11 @@ public abstract class OfflineFileControl extends PamControlledUnit implements Of } + @Override + public String getDataLocation() { + return fileParams.offlineFolder; + } + /* (non-Javadoc) * @see PamController.PamControlledUnit#notifyModelChanged(int) */ diff --git a/src/fileOfflineData/OfflineFileParams.java b/src/fileOfflineData/OfflineFileParams.java index b31d547b..82e4d61a 100644 --- a/src/fileOfflineData/OfflineFileParams.java +++ b/src/fileOfflineData/OfflineFileParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class OfflineFileParams implements Serializable, Cloneable, ManagedParameters { @@ -28,7 +29,7 @@ public class OfflineFileParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/generalDatabase/DBControl.java b/src/generalDatabase/DBControl.java index 7e229fee..70e0d549 100644 --- a/src/generalDatabase/DBControl.java +++ b/src/generalDatabase/DBControl.java @@ -30,6 +30,7 @@ import org.apache.commons.io.FilenameUtils; import offlineProcessing.DataCopyTask; import offlineProcessing.OLProcessDialog; import offlineProcessing.OfflineTaskGroup; +import pamguard.GlobalArguments; import warnings.PamWarning; import warnings.WarningSystem; import PamController.PamConfiguration; @@ -577,10 +578,16 @@ PamSettingsSource { */ @Override public boolean saveStartSettings(long timeNow) { - return dbProcess.saveStartSettings(); + return dbProcess.saveStartSettings(timeNow); } + @Override + public boolean saveEndSettings(long timeNow) { + // TODO Auto-generated method stub + return true; + } + @Override public int getNumSettings() { if (dbSettingsStore == null) { @@ -698,9 +705,17 @@ PamSettingsSource { */ public boolean selectDatabase(Frame frame, String selectTitle) { + //this is a bit messy but difficult to figure this out in controller framework because //this is called before the controller has initialised properly. - if (PamGUIManager.getGUIType()==PamGUIManager.FX) { + // also have to allow for the database being passed as a command line option, in which case + // we don't want to open the dialog. + String currentDB = null; + DBParameters newParams = checkPassedDatabase(); + if (newParams != null) { + + } + else if (PamGUIManager.getGUIType()==PamGUIManager.FX) { //open FX return ((DBGuiFX) getGUI(PamGUIManager.FX)).selectDatabase(PamController.getMainStage(), selectTitle, true); } @@ -711,12 +726,13 @@ PamSettingsSource { // object and retrieving the name of the first database in the recently-used list. Double-check the connection // field - if it's null, it means we don't actually have the database loaded so just clear the name and continue // (this happens when starting Viewer mode) - String currentDB = databaseSystems.get(dbParameters.getDatabaseSystem()).getDatabaseName(); + currentDB = databaseSystems.get(dbParameters.getDatabaseSystem()).getDatabaseName(); if (connection==null) { currentDB = null; } - DBParameters newParams = DBDialog.showDialog(this, frame, dbParameters, selectTitle); + newParams = DBDialog.showDialog(this, frame, dbParameters, selectTitle); + } if (newParams != null) { // first, check if there is a Lookup table. If so, make sure to copy the contents over before // we lose the reference to the old database @@ -757,9 +773,29 @@ PamSettingsSource { PamController.getInstance().getUidManager().runStartupChecks(); // if we've loaded a new database, synch the datablocks with the UID info return true; } - } return false; } + + /** + * Check to see if a database has been passed to PAMGuard as a parameter from the command line. + * @return + */ + DBParameters checkPassedDatabase() { + String passedDatabase = GlobalArguments.getParam(DBControl.GlobalDatabaseNameArg); + if (passedDatabase != null) { + /* + * assume it's a file based database. Anything else is going to get more complicated and will require + * a fair amount of type checing, connecint to servers, etc. + */ + if (passedDatabase.endsWith(".sqlite3")) { + DBParameters newParams = dbParameters; + newParams.setDatabaseName(passedDatabase); + newParams.setDatabaseSystem(0); + return newParams; + } + } + return null; + } /** * Set dB paramaters diff --git a/src/generalDatabase/DBControlUnit.java b/src/generalDatabase/DBControlUnit.java index f3bc4b37..0b4239b8 100644 --- a/src/generalDatabase/DBControlUnit.java +++ b/src/generalDatabase/DBControlUnit.java @@ -50,6 +50,7 @@ public class DBControlUnit extends DBControl implements DataOutputStore { private boolean initialisationComplete; private BackupInformation backupInformation; + private CreateDataMap createDataMap; public DBControlUnit(String unitName) { this(null, unitName); @@ -188,8 +189,8 @@ public class DBControlUnit extends DBControl implements DataOutputStore { pamDataBlocks.get(i).removeOfflineDataMap(THIS); updateDataBlocks.add(pamDataBlocks.get(i)); } - - AWTScheduler.getInstance().scheduleTask(new CreateDataMap(updateDataBlocks)); + createDataMap = new CreateDataMap(updateDataBlocks); + AWTScheduler.getInstance().scheduleTask(createDataMap); } @@ -258,6 +259,7 @@ public class DBControlUnit extends DBControl implements DataOutputStore { */ public CreateDataMap(ArrayList loggingBlocks) { super(); + createDataMap = this; this.loggingBlocks = loggingBlocks; } @@ -379,6 +381,7 @@ public class DBControlUnit extends DBControl implements DataOutputStore { PamController.getInstance().notifyTaskProgress(new CreateMapInfo(PamTaskUpdate.STATUS_DONE)); PamController.getInstance().notifyModelChanged(PamControllerInterface.CHANGED_OFFLINE_DATASTORE); // System.out.println("Create datamap point: DONE2"); + createDataMap = null; } /* (non-Javadoc) @@ -408,6 +411,11 @@ public class DBControlUnit extends DBControl implements DataOutputStore { return getUnitName(); } + @Override + public String getDataLocation() { + return getDatabaseName(); + } + @Override public boolean loadData(PamDataBlock dataBlock, OfflineDataLoadInfo offlineDataLoadInfo, ViewLoadObserver loadObserver) { SQLLogging logging = dataBlock.getLogging(); @@ -508,5 +516,13 @@ public class DBControlUnit extends DBControl implements DataOutputStore { return getDbProcess().deleteDataFrom(timeMillis); } + @Override + public int getOfflineState() { + int state = super.getOfflineState(); + if (createDataMap != null) { + state = Math.max(state, PamController.PAM_MAPMAKING); + } + return state; + } } diff --git a/src/generalDatabase/DBParameters.java b/src/generalDatabase/DBParameters.java index ce8103d7..ab06c212 100644 --- a/src/generalDatabase/DBParameters.java +++ b/src/generalDatabase/DBParameters.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class DBParameters implements Cloneable, Serializable, ManagedParameters { @@ -75,7 +76,7 @@ public class DBParameters implements Cloneable, Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); if (databaseName != null) { try { Field field = this.getClass().getDeclaredField("databaseName"); diff --git a/src/generalDatabase/DBProcess.java b/src/generalDatabase/DBProcess.java index 167d49f5..597b1a10 100644 --- a/src/generalDatabase/DBProcess.java +++ b/src/generalDatabase/DBProcess.java @@ -102,6 +102,8 @@ public class DBProcess extends PamProcess { dbSpecials.add(logSettings = new LogSettings(databaseControll, "Pamguard Settings", false)); dbSpecials.add(logLastSettings = new LogSettings(databaseControll, "Pamguard Settings Last", true)); dbSpecials.add(logViewerSettings = new LogSettings(databaseControll, "Pamguard Settings Viewer", true)); + + dbSpecials.add(new LogXMLSettings(databaseControll)); } @@ -113,9 +115,13 @@ public class DBProcess extends PamProcess { } } - protected boolean saveStartSettings() { + protected boolean saveStartSettings(long timeNow) { PamConnection con = databaseControll.getConnection(); if (con != null) { + /** + * This first one is the 'old' pre 2022 method which saves a serialised lump of all + * the settings in the database. It ain't broke, so not fixing it. + */ for (int i = 0; i < dbSpecials.size(); i++) { dbSpecials.get(i).pamStart(con); } @@ -124,6 +130,11 @@ public class DBProcess extends PamProcess { return false; } + protected boolean saveEndSettings(long timeNow) { + + return true; + } + @Override public void pamStop() { PamConnection con = databaseControll.getConnection(); @@ -212,7 +223,7 @@ public class DBProcess extends PamProcess { } dataBlocks = PamController.getInstance().getDataBlocks(); - PamTableDefinition tableDefinition; + EmptyTableDefinition tableDefinition; SQLLogging logging; // for each datablock, check that the process can log (ignoring GPS process) diff --git a/src/generalDatabase/DBSchemaWriter.java b/src/generalDatabase/DBSchemaWriter.java index f602ad5c..a29a90b5 100644 --- a/src/generalDatabase/DBSchemaWriter.java +++ b/src/generalDatabase/DBSchemaWriter.java @@ -48,7 +48,7 @@ public class DBSchemaWriter { } - PamTableDefinition tableDef = logging.getTableDefinition(); + EmptyTableDefinition tableDef = logging.getTableDefinition(); tableDef = logging.getBaseTableDefinition(); if (tableDef instanceof PamTableDefinition) { @@ -63,13 +63,14 @@ public class DBSchemaWriter { return true; } - private void exportDatabaseSchema(File outputFolder, PamDataBlock dataBlock, SQLLogging logging, PamTableDefinition tableDef) { - - /** - * write a parent item, e.g. if tableDef is a sub class of PamTableDefinition - */ - // String parentName = writeParentTableSchema(outputFolder, dataBlock, tableDef); - + /** + * Generate an xml schema for a datablock. + * @param dataBlock + * @param logging + * @param tableDef + * @return + */ + public Document generateDatabaseSchema(PamDataBlock dataBlock, SQLLogging logging, EmptyTableDefinition tableDef) { String tableName = tableDef.getTableName(); Document doc = PamUtils.XMLUtils.createBlankDoc(); Element schemaEl = doc.createElement("xs:schema"); @@ -95,7 +96,20 @@ public class DBSchemaWriter { } } } + return doc; + } + + private void exportDatabaseSchema(File outputFolder, PamDataBlock dataBlock, SQLLogging logging, EmptyTableDefinition tableDef) { + /** + * write a parent item, e.g. if tableDef is a sub class of PamTableDefinition + */ + // String parentName = writeParentTableSchema(outputFolder, dataBlock, tableDef); + + Document doc = generateDatabaseSchema(dataBlock, logging, tableDef); + + String tableName = tableDef.getTableName(); + try { File outputFile = new File(outputFolder, tableName+".xsd"); XMLUtils.writeToFile(doc, outputFile); diff --git a/src/generalDatabase/DbSpecial.java b/src/generalDatabase/DbSpecial.java index 05400f7a..401eac1a 100644 --- a/src/generalDatabase/DbSpecial.java +++ b/src/generalDatabase/DbSpecial.java @@ -9,7 +9,7 @@ import PamguardMVC.PamDataUnit; * @author Doug Gillespie * */ -abstract public class DbSpecial extends SQLLogging{ +abstract public class DbSpecial extends SQLLogging { private DBControl dbControl; diff --git a/src/generalDatabase/EmptyTableDefinition.java b/src/generalDatabase/EmptyTableDefinition.java index 9e10753e..53cfd1fb 100644 --- a/src/generalDatabase/EmptyTableDefinition.java +++ b/src/generalDatabase/EmptyTableDefinition.java @@ -300,7 +300,7 @@ public class EmptyTableDefinition implements Cloneable { * @param tableName * @return reference to the database deinition if it exists, or null */ - static PamTableDefinition findTableDefinition(String tableName) { + static EmptyTableDefinition findTableDefinition(String tableName) { String searchName = EmptyTableDefinition.deblankString(tableName); SQLLogging log = SQLLogging.findLogger(searchName); if (log == null) return null; @@ -389,6 +389,15 @@ public class EmptyTableDefinition implements Cloneable { this.updatePolicy = updatePolicy; } + public PamConnection getCheckedConnection() { + return checkedConnection; + } + + public void setCheckedConnection(PamConnection checkedConnection) { + this.checkedConnection = checkedConnection; + } + + @Override protected EmptyTableDefinition clone() { try { diff --git a/src/generalDatabase/LogSettings.java b/src/generalDatabase/LogSettings.java index af5305e9..23b713be 100644 --- a/src/generalDatabase/LogSettings.java +++ b/src/generalDatabase/LogSettings.java @@ -23,7 +23,7 @@ import PamUtils.PamCalendar; import PamguardMVC.PamDataUnit; /** - * Functions for writing Pamguard Settings into any database as character data + * Functions for writing serialised Pamguard Settings into any database as character data * Runs at DAQ start, goes through the settings manager list and for each * set of settings, it serialises the settings data into a binary array, this * is then converted from binary data to 6 bit ascii data (using the character set @@ -185,6 +185,7 @@ public class LogSettings extends DbSpecial { DeserialisationWarning dsWarning = new DeserialisationWarning(getDbControl().getDatabaseName()); SQLTypes sqlTypes = con.getSqlTypes(); + boolean haveData; if (result != null) try { haveData = result.next(); @@ -193,7 +194,7 @@ public class LogSettings extends DbSpecial { // transfer data back into the tableItems store. transferDataFromResult(sqlTypes, result); - tableItem = getTableDefinition().getTimeStampItem(); + tableItem = tableDef.getTimeStampItem(); // timestamp = (Timestamp) tableItem.getTimestampValue(); timeMillis = sqlTypes.millisFromTimeStamp(tableItem.getValue()); diff --git a/src/generalDatabase/LogXMLDataUnit.java b/src/generalDatabase/LogXMLDataUnit.java new file mode 100644 index 00000000..63189784 --- /dev/null +++ b/src/generalDatabase/LogXMLDataUnit.java @@ -0,0 +1,75 @@ +package generalDatabase; + +import PamController.PamSettings; +import PamguardMVC.PamDataUnit; + +/** + * simple data unit for use with the LogXMLSettings class + * @author dg50 + * + */ +public class LogXMLDataUnit extends PamDataUnit { + + private long processTime; + private PamSettings pamSettings; + private String xml; + private Long dataEnd, processEnd; + + public LogXMLDataUnit(long timeMilliseconds, long processTime, PamSettings pamSettings, String xml) { + super(timeMilliseconds); + this.processTime = processTime; + this.pamSettings = pamSettings; + this.xml = xml; + } + + /** + * @return the dataEnd + */ + public Long getDataEnd() { + return dataEnd; + } + + /** + * @param dataEnd the dataEnd to set + */ + public void setDataEnd(Long dataEnd) { + this.dataEnd = dataEnd; + } + + /** + * @return the processEnd + */ + public Long getProcessEnd() { + return processEnd; + } + + /** + * @param processEnd the processEnd to set + */ + public void setProcessEnd(Long processEnd) { + this.processEnd = processEnd; + } + + /** + * @return the processTime + */ + public long getProcessTime() { + return processTime; + } + + /** + * @return the pamSettings + */ + public PamSettings getPamSettings() { + return pamSettings; + } + + /** + * @return the xml + */ + public String getXml() { + return xml; + } + + +} diff --git a/src/generalDatabase/LogXMLSettings.java b/src/generalDatabase/LogXMLSettings.java new file mode 100644 index 00000000..3f33c188 --- /dev/null +++ b/src/generalDatabase/LogXMLSettings.java @@ -0,0 +1,123 @@ +package generalDatabase; + +import java.io.Serializable; +import java.util.HashMap; + +import org.w3c.dom.Document; + +import PamController.PamControlledUnit; +import PamController.PamController; +import PamController.PamSettings; +import PamController.PamguardVersionInfo; +import PamController.settings.output.xml.PamguardXMLWriter; +import PamUtils.PamCalendar; +import PamguardMVC.PamDataUnit; +/** + * 2022 Additional way of saving settings for each module into the database in more human readable + * XML format.

+ * In other ways, similar to LogSettings which saves serialised Java. This will write a line + * per module. A main difference is that on pamStop it will update the end time for each line, so + * that we have a record of analysis effort for each module. Will therefore need to store the last + * index of the entry for each module, so that we can update the appropriate row. + * @author dg50 + * + */ +public class LogXMLSettings extends DbSpecial { + + private XMLSettingsTableDefinition xmlTableDef; + + private HashMap moduleRows; + + private PamguardXMLWriter xmlWriter; + + public LogXMLSettings(DBControl dbControl) { + super(dbControl); + xmlTableDef = new XMLSettingsTableDefinition("Module Effort"); + setTableDefinition(xmlTableDef); + moduleRows = new HashMap<>(); + xmlWriter = PamguardXMLWriter.getXMLWriter(); + } + + @Override + public void pamStart(PamConnection con) { + long time = PamCalendar.getTimeInMillis(); + saveModuleSettings(con, time); + } + + @Override + public void pamStop(PamConnection con) { + long time = PamCalendar.getTimeInMillis(); + updateModuleSettings(con, time); + } + + private void saveModuleSettings(PamConnection con, long dataTime) { + int n = PamController.getInstance().getNumControlledUnits(); + long now = System.currentTimeMillis(); + for (int i = 0; i < n; i++) { + saveModuleSettings(con, dataTime, now, PamController.getInstance().getControlledUnit(i)); + } + + } + + private void saveModuleSettings(PamConnection con, long dataTime, long now, PamControlledUnit controlledUnit) { + if (controlledUnit instanceof PamSettings == false) { + return; + } + PamSettings pamSettings = (PamSettings) controlledUnit; + Serializable settings = pamSettings.getSettingsReference(); + Document doc = xmlWriter.writeOneModule(pamSettings, dataTime); + String xmlString = xmlWriter.getAsString(doc, true); + LogXMLDataUnit logXMLDataUnit = new LogXMLDataUnit(dataTime, now, pamSettings, xmlString); + + logData(logXMLDataUnit); + int dbIndex = logXMLDataUnit.getDatabaseIndex(); + moduleRows.put(getModuleHash(pamSettings), logXMLDataUnit); + } + + private void updateModuleSettings(PamConnection con, long dataTime) { + int n = PamController.getInstance().getNumControlledUnits(); + long now = System.currentTimeMillis(); + for (int i = 0; i < n; i++) { + updateModuleSettings(con, dataTime, now, PamController.getInstance().getControlledUnit(i)); + } + + } + + private void updateModuleSettings(PamConnection con, long dataTime, long now, PamControlledUnit controlledUnit) { + if (controlledUnit instanceof PamSettings == false) { + return; + } + PamSettings pamSettings = (PamSettings) controlledUnit; + LogXMLDataUnit logXMLDataUnit = moduleRows.get(getModuleHash(pamSettings)); + if (logXMLDataUnit == null) { + return; + } + logXMLDataUnit.setDataEnd(dataTime); + logXMLDataUnit.setProcessEnd(now); + reLogData(con, logXMLDataUnit); + } + + private String getModuleHash(PamSettings pamSettings) { + if (pamSettings == null) { + return null; + } + return pamSettings.getUnitName()+pamSettings.getUnitType(); + } + + @Override + public void setTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) { + LogXMLDataUnit logXMLDataUnit = (LogXMLDataUnit) pamDataUnit; + PamSettings pamSettings = logXMLDataUnit.getPamSettings(); + + xmlTableDef.getDataStart().setValue(sqlTypes.getTimeStamp(pamDataUnit.getTimeMilliseconds())); + xmlTableDef.getDataEnd().setValue(sqlTypes.getTimeStamp(logXMLDataUnit.getDataEnd())); + xmlTableDef.getProcessStart().setValue(sqlTypes.getTimeStamp(logXMLDataUnit.getProcessTime())); + xmlTableDef.getProcessEnd().setValue(sqlTypes.getTimeStamp(logXMLDataUnit.getProcessEnd())); + xmlTableDef.getName().setValue(pamSettings.getUnitName()); + xmlTableDef.getType().setValue(pamSettings.getUnitType()); + xmlTableDef.getPamGuardVersion().setValue(PamguardVersionInfo.version); + xmlTableDef.getSettingsVersion().setValue(pamSettings.getSettingsVersion()); + xmlTableDef.getXmlSettings().setValue(logXMLDataUnit.getXml()); + } + +} diff --git a/src/generalDatabase/MySQLParameters.java b/src/generalDatabase/MySQLParameters.java index 9491a6da..cadd498f 100644 --- a/src/generalDatabase/MySQLParameters.java +++ b/src/generalDatabase/MySQLParameters.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class MySQLParameters implements Cloneable, Serializable, ManagedParameters { @@ -37,7 +38,7 @@ public class MySQLParameters implements Cloneable, Serializable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("databaseName"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/generalDatabase/PamSubtableDefinition.java b/src/generalDatabase/PamSubtableDefinition.java index 0aa20215..ec3780b0 100644 --- a/src/generalDatabase/PamSubtableDefinition.java +++ b/src/generalDatabase/PamSubtableDefinition.java @@ -51,6 +51,7 @@ public class PamSubtableDefinition extends PamTableDefinition { addTableItem(parentUID = new PamTableItem(PARENTUIDNAME, Types.BIGINT)); addTableItem(longName = new PamTableItem(LONGDATANAME, Types.CHAR, DATANAME_LENGTH)); addTableItem(binaryFilename = new PamTableItem(BINARYFILE, Types.CHAR, BINARY_FILE_NAME_LENGTH)); + setUseCheatIndexing(false); } public PamTableItem getParentID() { diff --git a/src/generalDatabase/PamTableDefinition.java b/src/generalDatabase/PamTableDefinition.java index e8a2b5dc..8424b683 100644 --- a/src/generalDatabase/PamTableDefinition.java +++ b/src/generalDatabase/PamTableDefinition.java @@ -192,14 +192,7 @@ public class PamTableDefinition extends EmptyTableDefinition implements Cloneabl public PamTableItem getUidItem() { return uid; } - public PamConnection getCheckedConnection() { - return checkedConnection; - } - - public void setCheckedConnection(PamConnection checkedConnection) { - this.checkedConnection = checkedConnection; - } - + public PamTableItem getUpdateReference() { return updateReference; } diff --git a/src/generalDatabase/PamTableItem.java b/src/generalDatabase/PamTableItem.java index 2a046623..e73772e8 100644 --- a/src/generalDatabase/PamTableItem.java +++ b/src/generalDatabase/PamTableItem.java @@ -377,7 +377,7 @@ public class PamTableItem implements Cloneable { * column for use in cross referencing. */ public static PamTableItem findTableItem(String tableName, String columnName) { - PamTableDefinition tableDef = EmptyTableDefinition. + EmptyTableDefinition tableDef = EmptyTableDefinition. findTableDefinition(EmptyTableDefinition.deblankString(tableName)); if (tableDef == null) return null; return tableDef.findTableItem(EmptyTableDefinition.deblankString(columnName)); diff --git a/src/generalDatabase/SQLLogging.java b/src/generalDatabase/SQLLogging.java index e9c094ed..905ee28f 100644 --- a/src/generalDatabase/SQLLogging.java +++ b/src/generalDatabase/SQLLogging.java @@ -190,7 +190,7 @@ public abstract class SQLLogging { ArrayList blockList = PamController.getInstance() .getDataBlocks(); SQLLogging logger; - PamTableDefinition tableDef; + EmptyTableDefinition tableDef; for (int i = 0; i < blockList.size(); i++) { if ((logger = blockList.get(i).getLogging()) != null) { tableDef = logger.getTableDefinition(); @@ -293,37 +293,42 @@ public abstract class SQLLogging { * @param superDetection */ protected void fillTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit, PamDataUnit superDetection) { + + EmptyTableDefinition emptyTableDef = getTableDefinition(); - PamTableDefinition tableDef = getTableDefinition(); PamTableItem tableItem; - tableDef.getIndexItem().setValue(pamDataUnit.getDatabaseIndex()); - /* - * All tables have a timestamp near the front of the table. And all data - * units have a time in milliseconds, so always fill this in ! - */ - tableDef.getTimeStampItem().setValue( - sqlTypes.getTimeStamp(pamDataUnit.getTimeMilliseconds())); + emptyTableDef.getIndexItem().setValue(pamDataUnit.getDatabaseIndex()); + + if (emptyTableDef instanceof PamTableDefinition) { + PamTableDefinition tableDef = (PamTableDefinition) emptyTableDef; + /* + * All tables have a timestamp near the front of the table. And all data + * units have a time in milliseconds, so always fill this in ! + */ + tableDef.getTimeStampItem().setValue( + sqlTypes.getTimeStamp(pamDataUnit.getTimeMilliseconds())); - tableDef.getTimeStampMillis().setValue((int) (pamDataUnit.getTimeMilliseconds()%1000)); + tableDef.getTimeStampMillis().setValue((int) (pamDataUnit.getTimeMilliseconds()%1000)); - tableDef.getLocalTimeItem().setValue(sqlTypes.getLocalTimeStamp(pamDataUnit.getTimeMilliseconds())); + tableDef.getLocalTimeItem().setValue(sqlTypes.getLocalTimeStamp(pamDataUnit.getTimeMilliseconds())); - tableDef.getPCTimeItem().setValue(sqlTypes.getTimeStamp(System.currentTimeMillis())); + tableDef.getPCTimeItem().setValue(sqlTypes.getTimeStamp(System.currentTimeMillis())); - tableDef.getUidItem().setValue(pamDataUnit.getUID()); + tableDef.getUidItem().setValue(pamDataUnit.getUID()); - tableDef.getChannelBitmap().setValue(pamDataUnit.getChannelBitmap()); + tableDef.getChannelBitmap().setValue(pamDataUnit.getChannelBitmap()); - tableDef.getSequenceBitmap().setValue(pamDataUnit.getSequenceBitmapObject()); + tableDef.getSequenceBitmap().setValue(pamDataUnit.getSequenceBitmapObject()); - if (tableDef.getUpdateReference() != null) { - tableDef.getUpdateReference().setValue(pamDataUnit.getDatabaseIndex()); + if (tableDef.getUpdateReference() != null) { + tableDef.getUpdateReference().setValue(pamDataUnit.getDatabaseIndex()); + } } - for (int i = 0; i < tableDef.getTableItemCount(); i++) { + for (int i = 0; i < emptyTableDef.getTableItemCount(); i++) { - tableItem = tableDef.getTableItem(i); + tableItem = emptyTableDef.getTableItem(i); // if (tableItem.isCounter()) { // tableItem.setValue(1); // } @@ -333,8 +338,8 @@ public abstract class SQLLogging { } } - if (tableDef instanceof PamSubtableDefinition) { - PamSubtableDefinition subTableDef = (PamSubtableDefinition) tableDef; + if (emptyTableDef instanceof PamSubtableDefinition) { + PamSubtableDefinition subTableDef = (PamSubtableDefinition) emptyTableDef; fillSubTableData(subTableDef, pamDataUnit, superDetection); } @@ -525,7 +530,7 @@ public abstract class SQLLogging { } // now put some sql into the statement // if (resultSet == null) { - PamTableDefinition tableDef = getTableDefinition(); + EmptyTableDefinition tableDef = getTableDefinition(); String sqlString = tableDef.getSQLSelectString(con.getSqlTypes()); // sqlString = "select \"comment\" from userinput"; try { @@ -546,6 +551,71 @@ public abstract class SQLLogging { // } return resultSet; } + + /** + * Find the data point which is closest in time to that given, or null + * returning whatever type of data unit this deals with. + * @param timeMillis + * @return + */ + public PamDataUnit findClosestDataPoint(PamConnection con, long timeMillis) { + + PamCursor pamCursor = loggingCursorFinder.getCursor(con, pamTableDefinition); + + // can't really do any math with the string based dates, so will have to query from + // a few s before the time we want. + PamDataUnit[] beforeNafter = new PamDataUnit[2]; + + SQLTypes sqlTypes = con.getSqlTypes(); + + for (int i = 0; i < 2; i++) { + String clause; + + if (i == 0) { + clause = String.format("WHERE UTC <= %s ORDER BY UTC DESC", sqlTypes.formatDBDateTimeQueryString(timeMillis)); + } + else { + clause = String.format("WHERE UTC >= %s ORDER BY UTC ASC", sqlTypes.formatDBDateTimeQueryString(timeMillis)); + } + + ResultSet result = pamCursor.openReadOnlyCursor(con, clause); + if (result==null) { + return null; + } + + PamTableItem tableItem; + try { + if (result.next()) { + // for (int i = 0; i < pamTableDefinition.getTableItemCount(); i++) { + // tableItem = pamTableDefinition.getTableItem(i); + // tableItem.setValue(result.getObject(i + 1)); + // } + // return true; + boolean ok = transferDataFromResult(con.getSqlTypes(), result); + result.close(); + beforeNafter[i] = createDataUnit(sqlTypes, lastTime, lastLoadIndex); + } + } catch (SQLException ex) { + ex.printStackTrace(); + continue; + } + } + // now pick the closest + if (beforeNafter[0] == null) { + return beforeNafter[1]; + } + if (beforeNafter[1] == null) { + return beforeNafter[0]; + } + long t1 = timeMillis-beforeNafter[0].getTimeMilliseconds(); + long t2 = beforeNafter[1].getTimeMilliseconds()-timeMillis; + if (t1 < t2) { + return beforeNafter[0]; + } + else { + return beforeNafter[1]; + } + } /** * Called when a new database is connected to read the last values back in @@ -1079,7 +1149,7 @@ public abstract class SQLLogging { public boolean transferDataFromResult(SQLTypes sqlTypes, ResultSet resultSet) { - PamTableDefinition tableDef = getTableDefinition(); + EmptyTableDefinition tableDef = getTableDefinition(); PamTableItem tableItem; try { for (int i = 0; i < tableDef.getTableItemCount(); i++) { @@ -1090,17 +1160,20 @@ public abstract class SQLLogging { // Timestamp ts = (Timestamp) getTableDefinition().getTimeStampItem().getValue(); // Timestamp ts = getTableDefinition().getTimeStampItem().getTimestampValue(); // lastTime = sqlTypes.millisFromTimeStamp(ts); - lastTime = sqlTypes.millisFromTimeStamp(getTableDefinition().getTimeStampItem().getValue()); - if (lastTime%1000 == 0) { - // some databases may have stored the milliseconds, in which - // case this next bit is redundant. - lastTime += getTableDefinition().getTimeStampMillis().getIntegerValue(); - } - lastLoadIndex = getTableDefinition().getIndexItem().getIntegerValue(); - lastLoadUID = getTableDefinition().getUidItem().getLongObject(); - lastChannelBitmap = getTableDefinition().getChannelBitmap().getIntegerValue(); - lastSequenceBitmap = getTableDefinition().getSequenceBitmap().getIntegerObject(); + if (tableDef instanceof PamTableDefinition) { + PamTableDefinition pamTableDef = (PamTableDefinition) tableDef; + lastTime = sqlTypes.millisFromTimeStamp(pamTableDef.getTimeStampItem().getValue()); + if (lastTime%1000 == 0) { + // some databases may have stored the milliseconds, in which + // case this next bit is redundant. + lastTime += pamTableDef.getTimeStampMillis().getIntegerValue(); + } + + lastLoadUID = pamTableDef.getUidItem().getLongObject(); + lastChannelBitmap = pamTableDef.getChannelBitmap().getIntegerValue(); + lastSequenceBitmap = pamTableDef.getSequenceBitmap().getIntegerObject(); + } return true; } catch (SQLException ex) { @@ -1929,7 +2002,7 @@ public abstract class SQLLogging { * * @param con database connection * @param parentLogging super detection logging instance. - * @param uidList list of UID's in the parent data that have been loaded. + * @param idList list of ID's in the parent data that have been loaded. Note Id, NOT UID * @return list of all PamSubtableData items */ public ArrayList loadSubtableData(PamConnection con, SQLLogging parentLogging, String idList, ViewLoadObserver loadObserver) { @@ -1961,6 +2034,13 @@ public abstract class SQLLogging { return loadSubtableData(con, subtableResults, loadObserver); } + /** + * Get a sub table result set. Note that this is based on ID, not UID + * @param con connection + * @param parentLogging parent logging system + * @param parentIdList ParentID list. Note that this is ID, not UID,
i.e. the query is WHERE ParentID IN ... + * @return child table result set + */ private ResultSet createSubTableResultSet(PamConnection con, SQLLogging parentLogging, String parentIdList) { String clause = String.format(" WHERE ParentID IN %s ORDER BY UTC, UTCMilliseconds", parentIdList); diff --git a/src/generalDatabase/SQLLoggingAddon.java b/src/generalDatabase/SQLLoggingAddon.java index 6d347fb4..ff8bd561 100644 --- a/src/generalDatabase/SQLLoggingAddon.java +++ b/src/generalDatabase/SQLLoggingAddon.java @@ -15,7 +15,7 @@ public interface SQLLoggingAddon { * Add a load of columns to an existing table definition * @param pamTableDefinition */ - public void addTableItems(PamTableDefinition pamTableDefinition); + public void addTableItems(EmptyTableDefinition pamTableDefinition); /** * Save data - that is transfer data from the pamDataUnit to the data objects @@ -24,7 +24,7 @@ public interface SQLLoggingAddon { * @param pamDataUnit data unit * @return true if successful */ - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit); + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit); /** * Load data - that is read data from the table definition and turn it into something sensible @@ -33,7 +33,7 @@ public interface SQLLoggingAddon { * @param pamDataUnit data unit * @return true if successful */ - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit); + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit); /** * Get a name for the SQLLogging Addon. this is used diff --git a/src/generalDatabase/SQLTypes.java b/src/generalDatabase/SQLTypes.java index a81edd89..fd8ccb56 100644 --- a/src/generalDatabase/SQLTypes.java +++ b/src/generalDatabase/SQLTypes.java @@ -387,6 +387,7 @@ public class SQLTypes { return timestamp.getTime() + tz.getOffset(timestamp.getTime()); } else if (timeValue instanceof String) { + timeValue = ((String) timeValue).replace("'", ""); return PamCalendar.millisFromDateString((String) timeValue, false); } if (timeValue instanceof Long) { diff --git a/src/generalDatabase/XMLSettingsTableDefinition.java b/src/generalDatabase/XMLSettingsTableDefinition.java new file mode 100644 index 00000000..8d40bc55 --- /dev/null +++ b/src/generalDatabase/XMLSettingsTableDefinition.java @@ -0,0 +1,94 @@ +package generalDatabase; + +import java.sql.Types; + +import PamguardMVC.PamConstants; + +public class XMLSettingsTableDefinition extends PamTableDefinition { + + private PamTableItem dataStart, dataEnd, processStart, processEnd, type, name, pamGuardVersion, settingsVersion, xmlSettings; + + public XMLSettingsTableDefinition(String tableName) { + super(tableName, SQLLogging.UPDATE_POLICY_WRITENEW); + pamTableItems.add(dataStart = new PamTableItem("Data Start", Types.TIMESTAMP, "Data start time")); + pamTableItems.add(dataEnd = new PamTableItem("Data End", Types.TIMESTAMP, "Data end time")); + pamTableItems.add(processStart = new PamTableItem("Process Start", Types.TIMESTAMP, "Process start time")); + pamTableItems.add(processEnd = new PamTableItem("Process End", Types.TIMESTAMP, "Process end time")); + addTableItem(type = new PamTableItem("unitType", Types.CHAR, PamConstants.MAX_ITEM_NAME_LENGTH)); + addTableItem(name = new PamTableItem("unitName", Types.CHAR, PamConstants.MAX_ITEM_NAME_LENGTH)); + addTableItem(pamGuardVersion = new PamTableItem("PAMGuardVersion", Types.INTEGER)); + addTableItem(settingsVersion = new PamTableItem("SettingsVersion", Types.INTEGER)); + addTableItem(xmlSettings = new PamTableItem("XMLSettings", Types.VARCHAR)); + setUseCheatIndexing(false); + } + + + /** + * @return the dataStart + */ + public PamTableItem getDataStart() { + return dataStart; + } + + + /** + * @return the dataEnd + */ + public PamTableItem getDataEnd() { + return dataEnd; + } + + + /** + * @return the processStart + */ + public PamTableItem getProcessStart() { + return processStart; + } + + + /** + * @return the processEnd + */ + public PamTableItem getProcessEnd() { + return processEnd; + } + + + /** + * @return the type + */ + public PamTableItem getType() { + return type; + } + + /** + * @return the name + */ + public PamTableItem getName() { + return name; + } + + /** + * @return the pamGuardVersion + */ + public PamTableItem getPamGuardVersion() { + return pamGuardVersion; + } + + /** + * @return the settingsVersion + */ + public PamTableItem getSettingsVersion() { + return settingsVersion; + } + + /** + * @return the xmlSettings + */ + public PamTableItem getXmlSettings() { + return xmlSettings; + } + + +} diff --git a/src/generalDatabase/dataExport/ValueFilterParams.java b/src/generalDatabase/dataExport/ValueFilterParams.java index 15ffdfbd..52c57cfd 100644 --- a/src/generalDatabase/dataExport/ValueFilterParams.java +++ b/src/generalDatabase/dataExport/ValueFilterParams.java @@ -6,6 +6,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Abstract class for ValueFilters for filtering database data tables. @@ -110,7 +111,7 @@ public abstract class ValueFilterParams implements Cloneable, Serializable, Mana @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/generalDatabase/lookupTables/LookUpTables.java b/src/generalDatabase/lookupTables/LookUpTables.java index daea762f..bd095eba 100644 --- a/src/generalDatabase/lookupTables/LookUpTables.java +++ b/src/generalDatabase/lookupTables/LookUpTables.java @@ -3,10 +3,13 @@ package generalDatabase.lookupTables; import java.awt.Color; import java.awt.Window; import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.ListIterator; +import java.util.Vector; import PamController.PamController; import PamView.dialog.warn.WarnOnce; @@ -101,9 +104,101 @@ public class LookUpTables { checkedTableConnection = null; if (dbControlUnit.getDbProcess().checkTable(lutTableDef)) { checkedTableConnection = con; - return true; } - return false; + + checkTableRepeats(con, lutTableDef); + + return checkedTableConnection != null; + } + + /** + * for some reason some repeats have got into the LUT and need to be removed + * or it really messes stuff up. So check it automatically. + * @param con + * @param lutTableDef2 + */ + private boolean checkTableRepeats(PamConnection con, EmptyTableDefinition lutTableDef) { + /* + * first get a list of unique topics, then check them one at a time. + */ + ArrayList topics = getTopicList(con, lutTableDef); + if (topics == null) { + return false; + } + + for (String topic : topics) { + checkTopicRepeats(con, lutTableDef, topic); + } + return true; + } + + private void checkTopicRepeats(PamConnection con, EmptyTableDefinition lutTableDef2, String topic) { + LookupList lutList = getLookupList(topic); + Vector list = lutList.getList(); + int n = list.size(); + boolean[] isRepeat = new boolean[n]; + int nRepeat = 0; + // search for repeats. + for (int i = 0; i < n-1; i++) { + String code = list.get(i).getCode().trim(); + for (int j = i+1; j < n; j++) { + String code2 = list.get(j).getCode().trim(); + if (code.equals(code2)) { + isRepeat[j] = true; + nRepeat++; + } + } + } + if (nRepeat == 0) { + return; + } + // make a clause to delete the repeats. + String sql = null; + for (int i = 0; i < n; i++) { + if (isRepeat[i] == false) { + continue; + } + if (sql == null) { + sql = String.format("DELETE FROM %s WHERE Id IN (%d", lutTableDef.getTableName(), list.get(i).getDatabaseId()); + } + else { + sql = sql + String.format(",%d", list.get(i).getDatabaseId()); + } + } + sql += ")"; + boolean ok = false; + try { + Statement stmt = con.getConnection().createStatement(); + ok = stmt.execute(sql); + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private ArrayList getTopicList(PamConnection con, EmptyTableDefinition lutTableDef) { + if (con == null) { + return null; + } + ArrayList topics = new ArrayList<>(); + String qStr = "SELECT DISTINCT Topic FROM " + lutTableDef.getTableName(); + try { + Statement stmt = con.getConnection().createStatement(); + boolean ok = stmt.execute(qStr); + if (ok == false) { + return null; + } + ResultSet results = stmt.getResultSet(); + while (results.next()) { + String topic = results.getString(1); + topics.add(topic); + } + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + return topics; } public LookupList createLookupList(PamCursor resultSet, String topic) { diff --git a/src/generalDatabase/lookupTables/LookupItem.java b/src/generalDatabase/lookupTables/LookupItem.java index 7115406e..9ee05094 100644 --- a/src/generalDatabase/lookupTables/LookupItem.java +++ b/src/generalDatabase/lookupTables/LookupItem.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.PamSymbol; import PamView.PamSymbolType; @@ -232,7 +233,7 @@ public class LookupItem implements Cloneable, Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/generalDatabase/lookupTables/LookupList.java b/src/generalDatabase/lookupTables/LookupList.java index 8e0a0e0c..7714cdd3 100644 --- a/src/generalDatabase/lookupTables/LookupList.java +++ b/src/generalDatabase/lookupTables/LookupList.java @@ -7,6 +7,7 @@ import java.util.Vector; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Handles information for a single list from the look up table @@ -253,7 +254,7 @@ public class LookupList implements Cloneable, Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/generalDatabase/parameterstore/ParameterDatabaseStore.java b/src/generalDatabase/parameterstore/ParameterDatabaseStore.java new file mode 100644 index 00000000..29c740eb --- /dev/null +++ b/src/generalDatabase/parameterstore/ParameterDatabaseStore.java @@ -0,0 +1,187 @@ +package generalDatabase.parameterstore; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import java.util.Arrays; +import java.util.Collection; + +import PamModel.parametermanager.ManagedParameters; +import PamModel.parametermanager.PamParameterData; +import PamModel.parametermanager.PamParameterSet; +import generalDatabase.DBControlUnit; +import generalDatabase.EmptyTableDefinition; +import generalDatabase.PamConnection; +import generalDatabase.PamTableItem; +import generalDatabase.SQLTypes; + +/** + * Store parameters from a managed parameter set in the PAMGuard database. These go into a dead simple table, which has + * two columns. The first is a name, the second a string value. Each parameter can only appear once. + * This works with ManagedParameters using the same names and field names that go into the xml output. + * @author dg50 + * + */ +public class ParameterDatabaseStore { + + + private EmptyTableDefinition tableDef; + private PamTableItem nameItem, dataItem; + + public ParameterDatabaseStore(String tableName) { + tableDef = new EmptyTableDefinition(tableName); + tableDef.addTableItem(nameItem = new PamTableItem("ParameterName", Types.VARCHAR)); + tableDef.addTableItem(dataItem = new PamTableItem("Value", Types.VARCHAR)); + } + + public boolean saveParameterSet(ManagedParameters managedParameters) { + if (managedParameters == null) { + return false; + } + return saveParameterSet(managedParameters.getClass().getSimpleName(), managedParameters); + } + + private boolean saveParameterSet(String name, ManagedParameters managedParameters) { + DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); + if (dbControl == null) { + return false; + } + PamConnection con = dbControl.getConnection(); + if (checkTable(con) == false) { + return false; + } + + String prefix; + if (name == null) { + prefix = ""; + } + else { + prefix = name + "."; + } + PamParameterSet paramSet = managedParameters.getParameterSet(); + Collection params = paramSet.getParameterCollection(); + for (PamParameterData paramData : params) { + String paramName = paramData.getFieldName(); + paramName = prefix + paramName; + Object data = null; + try { + data = paramData.getData();// .getField().get(managedParameters); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } +// System.out.printf("Store param \"%s\" as \"%s\"\n", paramName, data); + saveToDatabase(con, paramName, data); + } + dbControl.commitChanges(); + + return true; + } + + private boolean saveToDatabase(PamConnection con, String name, Object data) { + int[] existing = findExistingRows(con, name); + boolean ok = true; + if (existing == null || existing.length == 0) { + ok |= newRecord(con, name, data); + } + else { + ok |= updateRecord(con, existing[0], name, data); + if (existing.length > 1) { + for (int i = 1; i < existing.length; i++) { + ok |= deleteDuplicateRow(con, existing[i]); + } + } + } + return true; + } + + private int[] findExistingRows(PamConnection con, String name) { + /** + * Find existing rows with that name. + */ + int[] rows = new int[0]; + if (con == null) { + return rows; + } + String qStr = String.format("SELECT Id FROM %s WHERE %s='%s'", tableDef.getTableName(), nameItem.getName(), name); + try { + Statement stmt = con.getConnection().createStatement(); + ResultSet res = stmt.executeQuery(qStr); + while (res.next()) { + int rowId = res.getInt(1); + rows = Arrays.copyOf(rows, rows.length+1); + rows[rows.length-1] = rowId; + } + res.close(); + stmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return rows; + } + + private boolean newRecord(PamConnection con, String name, Object data) { + + String insertStr = tableDef.getSQLInsertString(con.getSqlTypes()); + try { + PreparedStatement stmt = con.getConnection().prepareStatement(insertStr); + stmt.setString(1, name); + if (data == null) { + stmt.setNull(2, Types.VARCHAR); + } + else { + stmt.setString(2, data.toString()); + } + stmt.executeUpdate(); + + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + + return true; + } + + private boolean updateRecord(PamConnection con, int iRow, String name, Object data) { + SQLTypes st = con.getSqlTypes(); + String updateString = String.format("UPDATE %s SET %s = '%s' WHERE Id = %d", tableDef.getTableName(), + st.formatColumnName(dataItem.getName()), data, iRow); + + try { + PreparedStatement stmt = con.getConnection().prepareStatement(updateString); + stmt.executeUpdate(); + + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + + return true; + } + + private boolean deleteDuplicateRow(PamConnection con, int rowId) { + + String delStr = String.format("DELETE FROM %s WHERE Id=%d", tableDef.getTableName(), rowId); + + try { + PreparedStatement stmt = con.getConnection().prepareStatement(delStr); + stmt.executeUpdate(); + + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + return true; + } + + private boolean checkTable(PamConnection con) { + DBControlUnit dbControl = DBControlUnit.findDatabaseControl(); + if (dbControl == null) { + return false; + } + dbControl.commitChanges(); + return dbControl.getDbProcess().checkTable(tableDef); + } + +} diff --git a/src/generalDatabase/sqlite/SqliteSQLTypes.java b/src/generalDatabase/sqlite/SqliteSQLTypes.java index 580c8c5e..4f2baf73 100644 --- a/src/generalDatabase/sqlite/SqliteSQLTypes.java +++ b/src/generalDatabase/sqlite/SqliteSQLTypes.java @@ -10,7 +10,7 @@ import PamUtils.PamCalendar; public class SqliteSQLTypes extends SQLTypes { - protected static final SQLiteConfig.DateClass dateClass = SQLiteConfig.DateClass.TEXT; + public static final SQLiteConfig.DateClass dateClass = SQLiteConfig.DateClass.TEXT; @Override public String typeToString(int sqlType, int length, boolean counter) { diff --git a/src/generalDatabase/ucanAccess/UCanAccessSystem.java b/src/generalDatabase/ucanAccess/UCanAccessSystem.java index 8f754aac..3937cf17 100644 --- a/src/generalDatabase/ucanAccess/UCanAccessSystem.java +++ b/src/generalDatabase/ucanAccess/UCanAccessSystem.java @@ -153,7 +153,7 @@ public class UCanAccessSystem extends BaseAccessSystem implements PamSettings { String conStr = "jdbc:ucanaccess://" + fl.getAbsolutePath() + passwordEntry+noMem; System.out.println("UCanAccess connection string = " + conStr); - conn = DriverManager.getConnection(conStr); + conn = DriverManager.getConnection(conStr,"",""); conn.setAutoCommit(false); } catch (Exception e) { e.printStackTrace(); diff --git a/src/gpl/GPLParameters.java b/src/gpl/GPLParameters.java index 666c559e..fcda34d9 100644 --- a/src/gpl/GPLParameters.java +++ b/src/gpl/GPLParameters.java @@ -6,6 +6,7 @@ import java.io.Serializable; import PamModel.parametermanager.FieldNotFoundException; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.blockprocess.PamBlockParams; import gpl.contour.ContourMerge; @@ -198,7 +199,7 @@ public class GPLParameters implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { ps.findParameterData("minPeakGap").setInfo("Minimum gap", "bins", "Minimum gap between peaks (FFT time bins)"); ps.findParameterData("minCallLengthSeconds").setInfo("Minimum length", "bins", "Minimum length of a detection in seconds"); diff --git a/src/gpl/io/GPLLogging.java b/src/gpl/io/GPLLogging.java index d8817bdc..c407193f 100644 --- a/src/gpl/io/GPLLogging.java +++ b/src/gpl/io/GPLLogging.java @@ -5,6 +5,7 @@ import java.sql.Types; import PamDetection.AcousticSQLLogging; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLTypes; @@ -22,7 +23,7 @@ public class GPLLogging extends AcousticSQLLogging { super(gplDetectionBlock, gplControlledUnit.getUnitName() + " Detections"); this.gplControlledUnit = gplControlledUnit; - PamTableDefinition pamTable = getTableDefinition(); + EmptyTableDefinition pamTable = getTableDefinition(); pamTable.addTableItem(peakValue = new PamTableItem("PeakValue", Types.REAL)); pamTable.addTableItem(contourArea = new PamTableItem("ContourArea", Types.REAL)); } diff --git a/src/group3dlocaliser/Group3DParams.java b/src/group3dlocaliser/Group3DParams.java index fbf75743..6467a9ad 100644 --- a/src/group3dlocaliser/Group3DParams.java +++ b/src/group3dlocaliser/Group3DParams.java @@ -6,6 +6,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import PamView.GroupedSourceParameters; import group3dlocaliser.algorithm.LocaliserAlgorithm3D; @@ -126,7 +127,7 @@ public class Group3DParams implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("algorithmSpecificParams"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java b/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java index 7f7e1371..735d70f1 100644 --- a/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java +++ b/src/group3dlocaliser/algorithm/gridsearch/MFPGridSearchParams.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class MFPGridSearchParams implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class MFPGridSearchParams implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("fftLength"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java b/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java index 6f2a0fb2..8c845ffe 100644 --- a/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java +++ b/src/group3dlocaliser/algorithm/gridsearch/TOADGridParams.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import group3dlocaliser.grids.SphericalGrid; import pamMaths.PamVector; @@ -49,7 +50,7 @@ public class TOADGridParams implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("gridType"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java b/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java index 1aa70f8a..b0e11190 100644 --- a/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java +++ b/src/group3dlocaliser/algorithm/toadbase/TOADBaseParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Parameters that apply to all TOAD based localisers. @@ -117,7 +118,7 @@ public class TOADBaseParams implements Cloneable, Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java b/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java index 879eae8b..86e2397d 100644 --- a/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java +++ b/src/group3dlocaliser/dataselector/Group3DDataSelectParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.dataSelector.DataSelectParams; public class Group3DDataSelectParams extends DataSelectParams implements Serializable, Cloneable, ManagedParameters { @@ -28,7 +29,7 @@ public class Group3DDataSelectParams extends DataSelectParams implements Seriali @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/group3dlocaliser/grids/SphericalGridParams.java b/src/group3dlocaliser/grids/SphericalGridParams.java index f323ee53..5ece7b39 100644 --- a/src/group3dlocaliser/grids/SphericalGridParams.java +++ b/src/group3dlocaliser/grids/SphericalGridParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class SphericalGridParams implements Serializable, Cloneable, ManagedParameters { @@ -88,7 +89,7 @@ public class SphericalGridParams implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/group3dlocaliser/grouper/DetectionGrouperParams.java b/src/group3dlocaliser/grouper/DetectionGrouperParams.java index fc8ea979..b3e40163 100644 --- a/src/group3dlocaliser/grouper/DetectionGrouperParams.java +++ b/src/group3dlocaliser/grouper/DetectionGrouperParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class DetectionGrouperParams implements Serializable, Cloneable, ManagedParameters { @@ -52,7 +53,7 @@ public class DetectionGrouperParams implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/help/JavaHelpSearch/DOCS b/src/help/JavaHelpSearch/DOCS index aece1f43..0ed73b13 100644 Binary files a/src/help/JavaHelpSearch/DOCS and b/src/help/JavaHelpSearch/DOCS differ diff --git a/src/help/JavaHelpSearch/DOCS.TAB b/src/help/JavaHelpSearch/DOCS.TAB index fcb0be96..47fba810 100644 Binary files a/src/help/JavaHelpSearch/DOCS.TAB and b/src/help/JavaHelpSearch/DOCS.TAB differ diff --git a/src/help/JavaHelpSearch/OFFSETS b/src/help/JavaHelpSearch/OFFSETS index 7aeaea18..6dd107ae 100644 Binary files a/src/help/JavaHelpSearch/OFFSETS and b/src/help/JavaHelpSearch/OFFSETS differ diff --git a/src/help/JavaHelpSearch/POSITIONS b/src/help/JavaHelpSearch/POSITIONS index 168a00c2..b960a5dc 100644 Binary files a/src/help/JavaHelpSearch/POSITIONS and b/src/help/JavaHelpSearch/POSITIONS differ diff --git a/src/help/JavaHelpSearch/SCHEMA b/src/help/JavaHelpSearch/SCHEMA index f1bcbb62..a7d9a08c 100644 --- a/src/help/JavaHelpSearch/SCHEMA +++ b/src/help/JavaHelpSearch/SCHEMA @@ -1,2 +1,2 @@ JavaSearch 1.0 -TMAP bs=2048 rt=1 fl=-1 id1=6700 id2=1 +TMAP bs=2048 rt=1 fl=-1 id1=6882 id2=1 diff --git a/src/help/JavaHelpSearch/TMAP b/src/help/JavaHelpSearch/TMAP index 0f4d546b..b0102e13 100644 Binary files a/src/help/JavaHelpSearch/TMAP and b/src/help/JavaHelpSearch/TMAP differ diff --git a/src/help/Map.jhm b/src/help/Map.jhm index 176022cb..69065281 100644 --- a/src/help/Map.jhm +++ b/src/help/Map.jhm @@ -54,6 +54,8 @@ + + @@ -138,6 +140,8 @@ + + @@ -198,6 +202,8 @@ + + @@ -288,6 +294,8 @@ + + @@ -386,6 +394,8 @@ + + @@ -454,6 +464,8 @@ + + @@ -528,6 +540,8 @@ + + @@ -588,6 +602,8 @@ + + @@ -644,6 +660,8 @@ + + diff --git a/src/help/PAMGUARDHelpProject.xml b/src/help/PAMGUARDHelpProject.xml index 69b52d84..fe06f32b 100644 --- a/src/help/PAMGUARDHelpProject.xml +++ b/src/help/PAMGUARDHelpProject.xml @@ -6,7 +6,7 @@ PAMGUARD - C:\Users\dg50\source\repos\PAMGuardDG\src\help + C:\Users\dg50\source\repos\PAMGuardDG_2\src\help index.html diff --git a/src/help/PAMGUARDIndex.xml b/src/help/PAMGUARDIndex.xml index 18d93123..7e8ea629 100644 --- a/src/help/PAMGUARDIndex.xml +++ b/src/help/PAMGUARDIndex.xml @@ -2,6 +2,12 @@ + + + + + + diff --git a/src/help/PAMGUARDTOC.xml b/src/help/PAMGUARDTOC.xml index 73590bca..e668ab2c 100644 --- a/src/help/PAMGUARDTOC.xml +++ b/src/help/PAMGUARDTOC.xml @@ -195,6 +195,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/help/pamHelpStylesheet.css b/src/help/pamHelpStylesheet.css index e2174daf..6cfd22db 100644 --- a/src/help/pamHelpStylesheet.css +++ b/src/help/pamHelpStylesheet.css @@ -52,7 +52,17 @@ ol { FONT-SIZE: 14; } + img.wrap {float: left} +img.wrapright {float: right} +img.wrapcenter {float: center} + +.center { + display: block; + margin-left: auto; + margin-right: auto; + width: 85%; +} table, th, td { border: 1px solid black; @@ -63,4 +73,4 @@ th, td { } tr { text-align: center; -} \ No newline at end of file +} diff --git a/src/help/utilities/tethys/docs/calibrations.html b/src/help/utilities/tethys/docs/calibrations.html new file mode 100644 index 00000000..619d33e4 --- /dev/null +++ b/src/help/utilities/tethys/docs/calibrations.html @@ -0,0 +1,147 @@ + + + + + +Instrument Calibration Information + + + + + + +

Instrument calibration information

+ +

+ Most of the calibration data is taken from the array manager and + from the sound acquisition module. However, PAMGuard will ask a + few questions about HOW the instrument was calibrated, when it was + done and who is responsible. +

+

+ There are two dialogs associated with calibration. The first + asks for a calibration method and has the following fields: +

+ +
    +
  • + Method: Must be one of the following options: +
      +
    • Reference hydrophone
    • +
    • Manufacturer’s specification
    • +
    • Piston phone
    • +
    • Other calibrated source
    • +
    • Unknown
    • +
    +
  • + +
  • + Serial number: Hydrophone serial number +
  • + +
  • + Quality: Quality assurance value: +
      +
    • unverified: The calibration has not been verified
    • +
    • valid: The calibration has been validated as per the quality assurance process
    • +
    • invalid: The calibration was found to be invalid during quality assurance
    • +
    +
  • + +
  • + QA Comment: Textual description of the quality assurance + process. +
  • + + +
  • + Calibration method: Textual description of the Method. +
  • +
+ +

+ The second calibrations dialog asks for: +

+ +
    +
  • + Calibration date: Date the calibration was performed. +
  • + +
  • + Update frequency: Must be one of the following: +
      +
    • + as-needed: No updates are planned, but if a change is needed the calibration will be updated (defaul)t +
    • +
    • + unplanned: There are no plans to ever update the record. +
    • +
    • + yearly: A yearly review will be conducted to ensure that the record is valid. +
    • +
    +
  • + +
  • + Technical Person / Data Manager: These two types of data have + the same fields and detail who was responsible for the + calibration and who is responsible for maintaining the record + of the calibration. In many cases, this may be the same + person and copy buttons allow the fields to be duplicated. + +
      +
    • + Name: Responsible party’s naem +
    • +
    • + Organisation: Organisation to which the party reports +
    • +
    • + Position: Responsible party’s title +
    • +
    • + Email: Email contact information +
    • +
    +
  • + +
+ +

+ Fill in as much information as you can! + If the export is successful, a record will show for each + hydrophone (or sensor) in your instrument array in the + calibration information table: +

+ +
+ Panel with information about instrument calibration +
+ + +
+
+ +
+ + + + diff --git a/src/help/utilities/tethys/docs/connection.html b/src/help/utilities/tethys/docs/connection.html new file mode 100644 index 00000000..7dc8b75e --- /dev/null +++ b/src/help/utilities/tethys/docs/connection.html @@ -0,0 +1,121 @@ + + + + +Tethys Connection and Project Details + + + + +

Connection and Project Details

+ +

+ Make sure you have a Tethys Server running. The PAMGuard interface will + only work with Tethys + 3 or later. The section below specifies how to set the + address of Tethys server address as well as determine if + PAMGuard can communicate successfully with Tethys. (The top + panel will be orange if communication is not working. +

+ +

Tethys Server

+ + +

+ The Tethys Server field next to the picture of the goddess Tethys + indicates the address of the Tehtys server. To change this field, + click on the gear icon. You will be prompted to provide a computer + address (URL) and a port. The address should start with http:// + followed by the machine name or internet protocol address unless + the Tethys server has been configured to use an encrypted + connection. In this case, start the address with https://. +

+ +

+ By default, PAMGuard will use http://localhost:9779 which + assumes that your Tethys server is running on the same computer as + PAMGuard and that it expects communication on port 9779, the + default port (administrators may change this). +

+ +

+ If PAMGuard can communicate with the Tethys server, the + Connection and Project panel will be light grey. If + communication is not possible, the panel will be colored + orange. Likely causes for communication failure are: +

+
    +
  • + The server address or port is incorrect. +
  • + +
  • + Tethys has not been started on the server machine. One of the + main reasons that we see this is when the administrator has + not configured Tethys to run automatically as a service. In + that case, when a machine reboots (e.g., for automatic + operaing system updates) the server will not start + automatically. The Tethys manual explains how to configure + Tethys as a service that starts automatically when the machine + boots. +
  • + +
  • + Firewall rules do not permit traffic between the machine + executing PAMGuard and the one hosting Tethys on the selected + port. If you do not have adminstrative privileges, you will + need to contact your support team for help. +
  • +
+ +

Project and Instrument Information

+ +

+ Projects are names used by Tethys to help track work that should + be considered together, such as a series of deployments designed + to answer a specific question or funded under a specific + grant. If you do not already have a project defined in your + PAMGuard database, you can click the "New Project" button in the + "Connection and Project details" section of the Tethys + module. This will start a dialog that asks for a case-sensitive + project name and a geographic region. The geographic region is + for convenience, PAMGuard and Tethys track information by + longitude and latitude, but sometimes it is helpful to query for + information with respect to a geographic name such as Channel + + Islands National Marine Sanctuary. +

+ +

+ The array instrumentation is selected from a drop-down menu next + to the Instruments label. A dropdown menu next to the label + “Instruments” shows the list of hydrophone arrays. These are + likely to have been previously established prior to starting + analysis of your data by using the menu Settings -> Hydrophone + Array. + +

+ +

+ If you are a long-time user of PAMGuard, you will notice + additional fields are required for instrumentation: Instrument + Type and Instrument Id. The type indicates what type of + instrument is being used and may be generic such as a mooring or + array or denote a specific instrument such as a HARP, Rock + Hopper, SoundTrap, etc. The Id is a unique identifier for the + instrument such as a serial number. Note that if you are using + an older PAMGuard database, you may see a blank entry in the + instruments list as these new fields will not have been + populated. Press new/edit to access the instrument settings + from the Tethys module page. +

+ +
+
+ + +
+ + diff --git a/src/help/utilities/tethys/docs/deployments.html b/src/help/utilities/tethys/docs/deployments.html new file mode 100644 index 00000000..afde0149 --- /dev/null +++ b/src/help/utilities/tethys/docs/deployments.html @@ -0,0 +1,143 @@ + + + + + +Deployments + + + + + +

Deployments

+ +

+ Tethys uses deployment records to register information about + when instruments have been deployed as well as their + characteristics. Examples of characteristics that are recorded + include sample rate and the number of quantization bits, + description of duty cycles (if applicable), hydrophone geometry, + and enough details to be able find calibration data for specific + hydrophones. +

+ +

+ PAMGuard will examine the + PAMGuard + database + and + binary Store to determine what records should be generated for + your instrumentation. +

+ +

+ Where data were collected continuously or on a regular duty + cycle, PAMGuard will create a single deployment record. If data + were collected on a more "ad-hoc" basis, where the instrument + has been deployed multiple times or has irregular recording, + PAMGuard will generate a deployment record for each period of + recording. +

+ +

+ The figure below shows an example of ad-hoc recording periods + identified by PAMGuard: +

+
+ Panel showing recording times/deployments for this PAMGuard database +
+ +

+ Occasionally, there may be short recording periods (e.g. while + you were testing kit on deck) that you do not want to export. Use + the select checkbox to pick all of the rows that you wish to + export, or right click on the table and "Select All." +

+ +

+ When one or more deployment records are selected, the + "Export..." button will become available. Selecting the export + button will start a dialog that asks for additional information + about the deployments and then write records to Tethys. +

+

+ The first page of the dialog asks for the project and geographic + region which will be automatically populated if they have been + previously specified. In addition, the following fields are + requested: +

+
    +
  • Cruise name - Optional name of the deployment cruise
  • +
  • Site - Case-sensitive name for the deployment site, + e.g. "Tanner Banks" or a letter designation "T". This can + provide a simple way to identify multiple deployments at the + same general location. +
  • +
  • Responsible Party - A set of fields describing who was + responsible for the deployment and how they may be + contacted. +
  • +
+ +

+ The next page of the dialog asks whether you would like to + export a single deployment document or multiple deployments. + todo: add more detail here +

+ + +

+ Finally, you are prompted to provide optional textual descriptions of: +

    +
  • Objectives - What were your objectives when deploying the + instrument? Example: Determine population estimates for + critically endangered populations of vaquita (Phocoena + sinus). +
  • +
  • Abstract - A textual description of the deployment. + Example: A set of high frequency recorders were deployed across the + northern portion of the Sea of Cortez in the historical range + of the vaquita (Phocoena sinus). These recordings will + support detection and density estimation efforts. +
  • +
  • + Method - A description of the methods used. Example: + Small boat deployment of bottom moored SoundTrap recorders + with acoustic releases. +
  • +
+ + Press Finish to export the records. Once the + document(s) have been successuflly exported, the document name + associated with each recording period will be shown in the + Tethys Deployment column. +

+ + + +

+

+ + + + + diff --git a/src/help/utilities/tethys/docs/detect_localize.html b/src/help/utilities/tethys/docs/detect_localize.html new file mode 100644 index 00000000..a79be4e5 --- /dev/null +++ b/src/help/utilities/tethys/docs/detect_localize.html @@ -0,0 +1,161 @@ + + + + + +Detections/Localizations + + + + + +

Exporting Detections/Localizations (PAMGuard data blocks)

+ +

+ The bottom left panel of the Tethys module shows a list of + different types of PAMGuard data that can be exported. The data + in this list correspond to the various PAMGuard modules that have + been configured. See the + + data model viewer + help for an example of how PAMGuard might be configured. +

+ +

Species information

+ +

+ Some of these data represent detections of specific species or + phenomena that must be translated to Tethys. A context menu + (right-click on most computers) will show the option "Species + info..." that will allow you to specify the + translation of events + to species identifiers and call/sound types. If you try to export + without having done this, the species info dialog will be started + automatically prior to export. +

+ +

Selecting data blocks for import

+ +

+ In the sample data blocks below, four modules have been + configured, but only one of them has been run. Column "N Pam + Data" indicates the number of data records that have been + produced, and "PAMGuard Time" tells us when the data were + processed. "Tethys Documents" indicates how many Tethys records + have been produced, and should be 0 until the data are exported. +

+ +
+ List of results showing detections and other module processing events +
+ +

+ Select the data blocks to be exported by clicking on them. + Multiple lines can be selected by using keyboard modifiers such as + holding the shift while clicking to select all data blocks between + the last clicked block and where you click. Holding the alternate + (ALT) key will allow selection or de-selection of a single item + without affecting the selection state of other blocks. +

+ +

+ + SUGGESTION: It looks like we have to highlight these by clicking + on them. As we use select boxes for recording periods, we might + want to do the same thing here... We might want to rename + N PAM Datas to N PAM Data as data are already plural. + +

+ +

Exporting data blocks

+ +

+ Once the data blocks have been selected, press export. A series + of dialogs will guide you through the export process. The first + set of dialogs simply display a summary of information about what + will be exported. +

+ +
+ List of details describing the mechanism, parameters, and version of modules used in processing +
+ +

+ There is nothing to change in this summary. Press Next once you + have reviewed it. The second panel allows specification of your + objectives, abstract, and method. Many modules will have + pre-populated the method for you. While it is recommended to populate + the objectives and abstract, these fields are optional. +

+ +

+ Press Next to proceed to the next step of the dialog. You will be asked + what details you wish to store within the parameters that were used to + produce these data. Your must select one of the following: +

+ +
    +
  • + None - Do not report any of parameters used to produce these + detections. This option is not recommended as + it severely limits your ability to reproduce your results at a + later date or know whether or not the results of different + studies can be used together. +
  • +
  • Data selector only - not sure what this is
  • +
  • + Module only - Report the parameters that were set with this + module. Only parameters associated with the specific module + will be reported. Examples include score and duration thresholds + as well as any other type of criterion used to determine whether + or not an event is associated with a specific phenomenon or species. +
  • +
  • + Full process chain (default) - This is the most verbose option. It includes the module + parameters as well as anything else that is part of the signal processing chain that leads + to the module. As an example, a module only setting would not report the parameters that were + used to generate a spectrogram that was presented to a module for classification, but the + full process chain would record these details as well. Use this option will dramatically + increase the potential to reproduce your results, but it will generate a large amount of data + about the signal processing chain, much of which might not be useful. +
  • +
+ +

+ The final page of the dialog has an "Export data" button. Press + this to export the data. The system will begin generating the + Tethys document and the "Export data" button will be relabeled "Export complete" + once it is done. At this point, you can press "Finish" to close + the dialog. + + Would it make more sense to export when the user presses + Finish (or change the Finish button Export)? +

+ + + + + + + diff --git a/src/help/utilities/tethys/docs/images/Tethys-200.png b/src/help/utilities/tethys/docs/images/Tethys-200.png new file mode 100644 index 00000000..19e3c48f Binary files /dev/null and b/src/help/utilities/tethys/docs/images/Tethys-200.png differ diff --git a/src/help/utilities/tethys/docs/images/TethysGUI_1.png b/src/help/utilities/tethys/docs/images/TethysGUI_1.png new file mode 100644 index 00000000..4a6f1adc Binary files /dev/null and b/src/help/utilities/tethys/docs/images/TethysGUI_1.png differ diff --git a/src/help/utilities/tethys/docs/images/calibration_information.png b/src/help/utilities/tethys/docs/images/calibration_information.png new file mode 100644 index 00000000..234ff348 Binary files /dev/null and b/src/help/utilities/tethys/docs/images/calibration_information.png differ diff --git a/src/help/utilities/tethys/docs/images/data_blocks.png b/src/help/utilities/tethys/docs/images/data_blocks.png new file mode 100644 index 00000000..ee80ccff Binary files /dev/null and b/src/help/utilities/tethys/docs/images/data_blocks.png differ diff --git a/src/help/utilities/tethys/docs/images/deploymentspanel.png b/src/help/utilities/tethys/docs/images/deploymentspanel.png new file mode 100644 index 00000000..8516c96b Binary files /dev/null and b/src/help/utilities/tethys/docs/images/deploymentspanel.png differ diff --git a/src/help/utilities/tethys/docs/images/species_codes.png b/src/help/utilities/tethys/docs/images/species_codes.png new file mode 100644 index 00000000..db8ce2ae Binary files /dev/null and b/src/help/utilities/tethys/docs/images/species_codes.png differ diff --git a/src/help/utilities/tethys/docs/images/species_search.png b/src/help/utilities/tethys/docs/images/species_search.png new file mode 100644 index 00000000..73b2c36f Binary files /dev/null and b/src/help/utilities/tethys/docs/images/species_search.png differ diff --git a/src/help/utilities/tethys/docs/images/stream_algo_info.png b/src/help/utilities/tethys/docs/images/stream_algo_info.png new file mode 100644 index 00000000..d9480428 Binary files /dev/null and b/src/help/utilities/tethys/docs/images/stream_algo_info.png differ diff --git a/src/help/utilities/tethys/docs/tethys_module.html b/src/help/utilities/tethys/docs/tethys_module.html new file mode 100644 index 00000000..e21ce748 --- /dev/null +++ b/src/help/utilities/tethys/docs/tethys_module.html @@ -0,0 +1,92 @@ + + + +Tethys Module Overview + + + +

Tethys Module Overview

+ +

+ It is assumed that you are familiar with PAMGuard and have some + knowledge about Tethys. + Documentation + and tutorials + are available at the Tethys + web site. +

+ +

Launch PAMGuard in viewer mode

+

+ Tethys export is only available in + PAMGuard + Viewer mode + and is used to archive project data to a centralised + database. It is NOT a replacement for the + existing PAMGuard + database. Open the PAMGuard database that you wish to use + in viewer mode. +

+ +

PAMGuard Tethys Module

+ +

+ Add a Tethys module to PAMGuard from the File / Add Modules / + Utilities menu. A new tab panel will show the Tethys interface +

+ +
+ +
+ +

+ The tab shows a number of panes for the connection to the server + and the various types of data that will be output to the + database. Some of these panes summarize information on what's in + the current PAMGuard dataset (consisting of your PAMGuard + database and binary store), others may be empty until you start + to export to Tethys. +

+ +

+ The Tethys module consists of several panels: +

+
    +
  • + Connection and Project Details - + Specifies the location of the Tethys server and metadata about + the project. +
  • +
    +
  • Data Export - There are several panes that are responsible + for exporting information about instrument deployments, their + calibrations, and what they detected/localized. + +
  • +
+ +
+
+ + +
+ + diff --git a/src/help/utilities/tethys/docs/tethys_overview.html b/src/help/utilities/tethys/docs/tethys_overview.html new file mode 100644 index 00000000..6e9e6515 --- /dev/null +++ b/src/help/utilities/tethys/docs/tethys_overview.html @@ -0,0 +1,88 @@ + + + + + +Tethys Module Overview + + + +

Tethys Interface

+

+

Overview

+ +
+ Tethys mosaic +
+ +

+ PAMGuard is compatible + with Tethys 3.0 or + later. + Tethys is a freely + available open source temporal-spatial database for metadata + related to acoustic recordings. The database is intended to house + the metadata from marine mammal detection and localization + studies, allowing the user to perform meta analyses or to + aggregate data from many experimental efforts based on a common + attribute. This resulting database can then be queried based on + time, space, or any desired attribute and the results can be + integrated with external datasets such as NASA's Ocean Color, + lunar illumination, etc. in a consistent manner. While Tethys is + designed primarily for acoustic metadata from marine mammals, the + design is general enough to permit use in other areas as well. +

+ + +

+ The Tethys database is not a replacement for the existing + PAMGuard + Database. Where the PAMGuard database only contains data from + a single instrument or cruise, the Tethys database contains data + from many cruises and projects and can be used to hold a summary + of all data from a lab or organisation. PAMGuard's Tethys module + provides an interface for exporting detailed or summary + information about acoustic detections to the Tethys database. +

+ +

+ Before using the module in PAMGuard, you should install the Tethys + Server. While clients that communicate with Tethys can run on a + variety of computer operating systems, there are a small number of + dependencies on Microsoft technologies that require the server to + be installed on a Microsoft Windows machine. + Instructions + for installing the Tethys Server can be found here.

+ +

+ +

+ Module help: +

+
    +
  1. The Tethys module (start here)
  2. +
  3. The Connecting to Tethys
  4. +
  5. The Instrument calibrations
  6. +
  7. The Instrument deployments
  8. +
  9. The Detections & Localizations
  10. +
  11. Guide to specifying species names
  12. +
+ + + + diff --git a/src/help/utilities/tethys/docs/tethys_server.html b/src/help/utilities/tethys/docs/tethys_server.html new file mode 100644 index 00000000..b9330ed2 --- /dev/null +++ b/src/help/utilities/tethys/docs/tethys_server.html @@ -0,0 +1,34 @@ + + + + + + + + Tethys Module Overview + + +

Tethys Interface

+

Tethys Server

+

+ Tethys is ... +

+ +
+
+
+
+
+
+ + diff --git a/src/help/utilities/tethys/docs/tethys_speciescodes.html b/src/help/utilities/tethys/docs/tethys_speciescodes.html new file mode 100644 index 00000000..d3b63a50 --- /dev/null +++ b/src/help/utilities/tethys/docs/tethys_speciescodes.html @@ -0,0 +1,192 @@ + + + +Species coding + + + + +

Species and Call Type Names

+ + When exporting data from PAMGuard to Tethys, some PAMGuard records + will require additional information indicating what type of animal + or phenomena were detected. If a specific call-type was detected, + e.g. "Clicks" or "Whistles", these should be noted as well. + +

Species Names

+

+ Tethys uses the Integrated Taxonomic + Information System (ITIS) to encode species names as taxonomic + serial numbers (TSNs), unique numeric identifiers for species. + These data conform with several international coding systems which + are described on the ITIS + standards page. +

+ +

+ It is not uncommon to be unable to describe a call to the genus + level. In such cases, one can use a higher taxonomic level. For + example, beaked whale echolocation clicks are distinctive from the + clicks of other toothed whales as their pulses have a + frequency-modulated component. While they can frequently be + associated with the family Hyperodontidae, it is not always + possible to associate a click to a specific species as many of the + at least twenty-two species remain understudied. In such a case, + we would use the TSN for Hyperodontidae, 770799. While not + currently supported by PAMGuard, each species identifier has an + optional Group attribute that can be used in an ad-hoc manner to + provide additional information. This can be used to add + population markers, tentative genus groups, etc. +

+ +

+ ITIS does not describe abiotic sounds, Tethys records such sounds as follows: +

    +
  1. + For anthropogenic signals, the Tethys convention is to + use Homo sapiens, TSN 180092, for the species code + and describe the human-generated signal via a call type, + e.g. ship, mid-frequency active sonar, etc. +
  2. +
  3. + Tethys reserves the TSN -10 for geophonic signals. + The call type is used to describe the source. Examples + include ambient sound, earthquake, rain, etc. Note that negative TSNs + are not part of the ITIS standard. +
  4. +
+

+ + Note that in general, you do not have to worry about remembering + TSNs. Tethys uses TSNs internally, but will translate TSNs to/from + Latin names or user-defined abbreviations both when querying and + presenting results. + +

Call types

+ +

+ Some detectors identify specific call types. When this is the + case, users will need to specify the call type name. While + species names are standardized in Tethys, call names do not have a + well-defined standard and experts frequently use different names + for the same type of call. Consequently, Tethys does not provide a + standard coding for call types and users are free to choose the call + type names with which they feel most comfortable. +

+ +

+ That said, the authors of Tethys do however provide a list of recommend call + types for many species. These recommendations can be accessed in the + + supplemental information of the open access article "Management of acoustic metadata + for bioacoustics," Roch et al. (2016), + (DOI:10.1016/j.ecoinf.2015.12.002). +

+ +

+ Export dialog +

+ +

+ During export of records that are species-specific, a dialog will + appear that lists the types of events that were found by PAMGuard + modules. This dialog permits users to specify how the ad-hoc species + species/call encoding scheme used by PAMGuard modules can be systematically + translated to the TSNs and call types are stored in Tethys. +

+ +

+ PAMGuard events typically are a short name that represents the + species and/or potentially a call. Knowledge of the PAMGuard + modules that were run and the data on which they executed will let + a user infer what should be recorded. + + The dialog below shows a sample set of events produced by one or more PAMGuard modules + using the names: HP, DO, SON, KW, UNK, and PHP: + +

+ +
+ + The dialog above was produced from detections on data that were + recorded near the mouth of the River Tay in Scotland. Consequently, + we can infer that the harbour porpoise that is denoted by "HP" is + Phocena phocena, the only harbour porpoise endemic to + Scottish waters. +

+ + An ITIS code and call/sound type can be associated with each event. The dialog lists: +
    +
  • + Name - The ad-hoc name given by the PAMGuard module. This may not be changed. +
  • + +
  • + ITIS code -This is the ITIS TSN that is associated with PAMGuard + event code. Click on Find to inovke the TSN + search dialog whose behavior is described in the next + section. +

    + If you happen to know the TSN, you + can enter it directly. Pressing Find after typing the TNS will + populate the Latin and English vernauclar names so that you may + verify your TSN was entered correctly. +

    +
  • + +
  • Call / sound type - This will default to the code provided by + the module but should be updated to specify an appropriate call + type or left blank to indicate that the detection is not related + to a specific call type. In the case of a porpoise detector, + the likely call type would be "Clicks". + We should double check that no Call element is generated when this is blank. +
  • +
+ +

+ Once all species names and call/sound types have been identified, press the Okay button. +

+ + + + +

Searching for ITIS Taxonomic Serial Numbers (TSNs)

+ +

+ As noted above, pressing Find without typing a TSN will bring up a + search dialog: +

+ +
+ +
+ +

+ The top of this dialog has a search box where one can enter either + a Latin name or the common name for a species. The Tethys server + will search for all species that match the search-box contents. + For many species, there are common name entries in languages + other than English, and these are searched as well. +

+

+ Once you press the search button, a list will appear with all + matches for your search term. If there are too many, a scroll bar + will permit you to look through the list. Select the entry that + you wish and press OK. The TSN on the species dialog will be + populated along with the Latin name and common names from the ITIS + database. +

+ + +

+

+ + + + + diff --git a/src/landMarks/LandmarkData.java b/src/landMarks/LandmarkData.java index 2be20e55..ef0cb561 100644 --- a/src/landMarks/LandmarkData.java +++ b/src/landMarks/LandmarkData.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamController.masterReference.MasterReferencePoint; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.LatLong; import PamView.PamSymbol; @@ -49,7 +50,7 @@ public class LandmarkData extends Object implements Serializable, Cloneable, Man @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/landMarks/LandmarkDatas.java b/src/landMarks/LandmarkDatas.java index d4cd386d..73fb4785 100644 --- a/src/landMarks/LandmarkDatas.java +++ b/src/landMarks/LandmarkDatas.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class LandmarkDatas implements Serializable, Cloneable, ManagedParameters { @@ -76,7 +77,7 @@ public class LandmarkDatas implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/levelMeter/LevelMeterParams.java b/src/levelMeter/LevelMeterParams.java index dd1b6752..c25860dc 100644 --- a/src/levelMeter/LevelMeterParams.java +++ b/src/levelMeter/LevelMeterParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class LevelMeterParams implements Cloneable, Serializable, ManagedParameters { @@ -35,7 +36,7 @@ public class LevelMeterParams implements Cloneable, Serializable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/likelihoodDetectionModule/AcquisitionSettings.java b/src/likelihoodDetectionModule/AcquisitionSettings.java index abf61481..10033395 100644 --- a/src/likelihoodDetectionModule/AcquisitionSettings.java +++ b/src/likelihoodDetectionModule/AcquisitionSettings.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * The AcquisitionSettings class provides a module-local storage object for holding @@ -48,7 +49,7 @@ public class AcquisitionSettings implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/likelihoodDetectionModule/ConfigurationDialogSettings.java b/src/likelihoodDetectionModule/ConfigurationDialogSettings.java index 6856e501..9011ffbd 100644 --- a/src/likelihoodDetectionModule/ConfigurationDialogSettings.java +++ b/src/likelihoodDetectionModule/ConfigurationDialogSettings.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * The Class ConfigurationDialogSettings holds parameters about the @@ -28,7 +29,7 @@ public class ConfigurationDialogSettings implements Serializable, ManagedParamet @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("expandedState"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/likelihoodDetectionModule/GuardBand.java b/src/likelihoodDetectionModule/GuardBand.java index ccd9a6c0..cb07df7b 100644 --- a/src/likelihoodDetectionModule/GuardBand.java +++ b/src/likelihoodDetectionModule/GuardBand.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Represents the parameters that make up a guard band, used as @@ -106,7 +107,7 @@ public class GuardBand implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java b/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java index 9c405cdd..9481c26c 100644 --- a/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java +++ b/src/likelihoodDetectionModule/LikelihoodDetectionParameters.java @@ -11,6 +11,7 @@ import java.util.Iterator; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * The Class LikelihoodDetectionParameters provides the standard PamGuard @@ -271,7 +272,7 @@ public class LikelihoodDetectionParameters implements Serializable, Cloneable, M @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/likelihoodDetectionModule/LikelihoodFFTParameters.java b/src/likelihoodDetectionModule/LikelihoodFFTParameters.java index e90e51c8..13b85fda 100644 --- a/src/likelihoodDetectionModule/LikelihoodFFTParameters.java +++ b/src/likelihoodDetectionModule/LikelihoodFFTParameters.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import fftManager.FFTParameters; import Spectrogram.WindowFunction; @@ -270,7 +271,7 @@ public class LikelihoodFFTParameters implements Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("sourceNumber"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/likelihoodDetectionModule/SignalBand.java b/src/likelihoodDetectionModule/SignalBand.java index 00e7af96..3b3150d6 100644 --- a/src/likelihoodDetectionModule/SignalBand.java +++ b/src/likelihoodDetectionModule/SignalBand.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Represents the parameters that make up a signal band, used as @@ -151,7 +152,7 @@ public class SignalBand implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/likelihoodDetectionModule/TargetConfiguration.java b/src/likelihoodDetectionModule/TargetConfiguration.java index 29c82890..0cc0e398 100644 --- a/src/likelihoodDetectionModule/TargetConfiguration.java +++ b/src/likelihoodDetectionModule/TargetConfiguration.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import likelihoodDetectionModule.normalizer.NormalizerProcess.NormalizerAlgorithm; /** @@ -453,7 +454,7 @@ public class TargetConfiguration implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/loc3d_Thode/TowedArray3DSQLLogging.java b/src/loc3d_Thode/TowedArray3DSQLLogging.java index c5a8b1f7..95bc98e6 100644 --- a/src/loc3d_Thode/TowedArray3DSQLLogging.java +++ b/src/loc3d_Thode/TowedArray3DSQLLogging.java @@ -1,5 +1,6 @@ package loc3d_Thode; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamDetectionLogging; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; @@ -17,7 +18,6 @@ public class TowedArray3DSQLLogging extends PamDetectionLogging { TowedArray3DController towedArray3DController; - PamTableDefinition tableDefinition; PamTableItem dateItem, range_boat_Item, range_f_Item, range_r_Item, depthItem, azi_boat_Item,azi_f_Item, azi_r_Item, tdd_Item, bearing_f_Item,bearing_r_Item, tds_f_Item, tds_r_Item, za_f_Item, za_r_Item; @@ -34,7 +34,7 @@ public class TowedArray3DSQLLogging extends PamDetectionLogging { this.towedArray3DController = towedArray3DController; // create the table definition. - tableDefinition = createTableDefinition(); + PamTableDefinition tableDefinition = createTableDefinition(); } public PamTableDefinition createTableDefinition() { diff --git a/src/loggerForms/FormDescription.java b/src/loggerForms/FormDescription.java index b3d55501..a212b94d 100644 --- a/src/loggerForms/FormDescription.java +++ b/src/loggerForms/FormDescription.java @@ -38,6 +38,14 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; +import Array.streamerOrigin.GPSOriginMethod; +import Array.streamerOrigin.GPSOriginSystem; +import Array.streamerOrigin.HydrophoneOriginMethod; +import Array.streamerOrigin.HydrophoneOriginMethods; +import Array.streamerOrigin.OriginIterator; +import Array.streamerOrigin.StaticOriginSystem; +import GPS.GpsData; + import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -49,6 +57,7 @@ import pamScrollSystem.ScrollPaneAddon; import PamView.PamTabPanel; import PamView.panel.PamPanel; import PamView.symbol.StandardSymbolManager; +import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; import PamController.PamControlledUnitSettings; import PamController.PamController; @@ -1589,7 +1598,9 @@ public class FormDescription implements Cloneable, Comparable { normalForm.destroyForm(); } if (hiddenForm != null) { - normalForm.destroyForm(); + if (normalForm != null) { + normalForm.destroyForm(); + } } if (subtabForms != null) { for (LoggerForm aForm:subtabForms) { @@ -2021,4 +2032,32 @@ public class FormDescription implements Cloneable, Comparable { public void setNeedsUDFSave(boolean needsUDFSave) { this.needsUDFSave = needsUDFSave; } + + public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) { + GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit); + if (gps != null) { + return gps; + } + gps = getOrigin(StaticOriginSystem.class, formsDataUnit); + return gps; + } + + private GpsData getOrigin(Class originClass, FormsDataUnit formsDataUnit) { + HydrophoneOriginMethods origins = HydrophoneOriginMethods.getInstance(); + HydrophoneOriginMethod origin = origins.getMethod(GPSOriginMethod.class, null, null); + if (origin == null) { + return null; + } + OriginIterator gpsIter = origin.getGpsDataIterator(PamDataBlock.ITERATOR_END); + GpsData prev = null; + while (gpsIter.hasPrevious()) { + prev = gpsIter.previous(); + if (prev.getTimeInMillis() < formsDataUnit.getTimeMilliseconds()) { + break; + } + } + return prev; + } + + } diff --git a/src/loggerForms/FormPlotOptions.java b/src/loggerForms/FormPlotOptions.java index 8f55f828..9763d8ba 100644 --- a/src/loggerForms/FormPlotOptions.java +++ b/src/loggerForms/FormPlotOptions.java @@ -6,6 +6,7 @@ import java.util.Arrays; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; /** @@ -95,7 +96,7 @@ public class FormPlotOptions implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("controlChoices"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/loggerForms/FormSettings.java b/src/loggerForms/FormSettings.java index 199edfe4..f7553e13 100644 --- a/src/loggerForms/FormSettings.java +++ b/src/loggerForms/FormSettings.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Manage a bit of persistent data for a single Logger form description.

@@ -32,7 +33,7 @@ public class FormSettings implements Cloneable, Serializable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/loggerForms/FormsControl.java b/src/loggerForms/FormsControl.java index e88c1343..94cf9112 100644 --- a/src/loggerForms/FormsControl.java +++ b/src/loggerForms/FormsControl.java @@ -614,6 +614,32 @@ public class FormsControl extends PamControlledUnit { return new ModuleStatus(ModuleStatus.STATUS_OK); } + + /** + * Some things that are meant to be boolean are coming out as int or string so + * need to do some type checking. + * @param value + * @return + */ + public static Boolean checkBadBoolean(Object value) { + if (value instanceof Boolean) { + return (Boolean) value; + } + if (value == null) { + return null; + } + if (value instanceof String) { + String str = (String) value; + str = str.strip(); + return str.equals("1") || str.toLowerCase().equals("false"); + } + if (value instanceof Integer) { + int val = (Integer) value; + return val != 0; + } + + return null; + } // @Override // public Serializable getSettingsReference() { // return (Serializable) dummyParams; diff --git a/src/loggerForms/FormsDataDisplayTable.java b/src/loggerForms/FormsDataDisplayTable.java index f30316fe..1300fc79 100644 --- a/src/loggerForms/FormsDataDisplayTable.java +++ b/src/loggerForms/FormsDataDisplayTable.java @@ -208,7 +208,15 @@ public class FormsDataDisplayTable { Object[] fd = pamDataUnit.getFormData(); int ctIndex = columnIndex-extraColumns.length; ControlDescription ctrlDescription = formDescription.getInputControlDescriptions().get(ctIndex); - return ctrlDescription.formatDataItem(fd[ctIndex]); + Object value = ctrlDescription.formatDataItem(fd[ctIndex]); + if (value == null) return null; + if (getColumnClass(columnIndex) == Boolean.class) { + if (value instanceof Boolean == false) { +// System.out.println("Bad boolean value: " + value); + return FormsControl.checkBadBoolean(value); + } + } + return value; // return fd[ctIndex]; } catch (Exception e) { @@ -252,6 +260,8 @@ public class FormsDataDisplayTable { } + + /** * Called when data have changed in the datablock. */ diff --git a/src/loggerForms/FormsDataUnit.java b/src/loggerForms/FormsDataUnit.java index 963c6374..32ab905d 100644 --- a/src/loggerForms/FormsDataUnit.java +++ b/src/loggerForms/FormsDataUnit.java @@ -87,7 +87,9 @@ public class FormsDataUnit extends PamDataUnit { * we want to as a reference, etc. */ if (recalculate || formOriginLatLong == null) { - formOriginLatLong = loggerForm.getOriginLatLong(this); + if (formDescription != null) { + formOriginLatLong = formDescription.getOriginLatLong(this); + } } return formOriginLatLong; } diff --git a/src/loggerForms/FormsLogging.java b/src/loggerForms/FormsLogging.java index 5420f3a9..64e0d8e6 100644 --- a/src/loggerForms/FormsLogging.java +++ b/src/loggerForms/FormsLogging.java @@ -112,7 +112,7 @@ public class FormsLogging extends SQLLogging { // } // } - +// formDescription.getf FormsDataUnit formsDataUnit = new FormsDataUnit(null, timeMilliseconds, formDescription, formData); formsDataUnit.setDatabaseIndex(databaseIndex); diff --git a/src/loggerForms/LoggerForm.java b/src/loggerForms/LoggerForm.java index 11f562a7..b31ae9a8 100644 --- a/src/loggerForms/LoggerForm.java +++ b/src/loggerForms/LoggerForm.java @@ -21,6 +21,7 @@ import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JOptionPane; +import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.JScrollPane; import javax.swing.Timer; @@ -104,7 +105,7 @@ public class LoggerForm{ private CounterControl counter; - private HydrophoneOriginMethods origins = HydrophoneOriginMethods.getInstance(); +// private HydrophoneOriginMethods origins = HydrophoneOriginMethods.getInstance(); /** * @return the hasCounter @@ -529,7 +530,10 @@ public class LoggerForm{ innerCenterPanel.add(currentRow); currentRow = new LoggerFormPanel(this, new FlowLayout(FlowLayout.LEFT)); }else{ - currentRow.add(c.makeComponent(this)); + JPanel component = c.makeComponent(this); + if (component != null) { + currentRow.add(component); + } } } @@ -911,30 +915,30 @@ public class LoggerForm{ return saveButton; } - public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) { - GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit); - if (gps != null) { - return gps; - } - gps = getOrigin(StaticOriginSystem.class, formsDataUnit); - return gps; - } - - private GpsData getOrigin(Class originClass, FormsDataUnit formsDataUnit) { - HydrophoneOriginMethod origin = origins.getMethod(GPSOriginMethod.class, null, null); - if (origin == null) { - return null; - } - OriginIterator gpsIter = origin.getGpsDataIterator(PamDataBlock.ITERATOR_END); - GpsData prev = null; - while (gpsIter.hasPrevious()) { - prev = gpsIter.previous(); - if (prev.getTimeInMillis() < formsDataUnit.getTimeMilliseconds()) { - break; - } - } - return prev; - } +// public GpsData getOriginLatLong(FormsDataUnit formsDataUnit) { +// GpsData gps = getOrigin(GPSOriginSystem.class, formsDataUnit); +// if (gps != null) { +// return gps; +// } +// gps = getOrigin(StaticOriginSystem.class, formsDataUnit); +// return gps; +// } +// +// private GpsData getOrigin(Class originClass, FormsDataUnit formsDataUnit) { +// HydrophoneOriginMethod origin = origins.getMethod(GPSOriginMethod.class, null, null); +// if (origin == null) { +// return null; +// } +// OriginIterator gpsIter = origin.getGpsDataIterator(PamDataBlock.ITERATOR_END); +// GpsData prev = null; +// while (gpsIter.hasPrevious()) { +// prev = gpsIter.previous(); +// if (prev.getTimeInMillis() < formsDataUnit.getTimeMilliseconds()) { +// break; +// } +// } +// return prev; +// } // /** diff --git a/src/loggerForms/controls/CheckboxControl.java b/src/loggerForms/controls/CheckboxControl.java index 3be6dd8f..a0ec06e0 100644 --- a/src/loggerForms/controls/CheckboxControl.java +++ b/src/loggerForms/controls/CheckboxControl.java @@ -9,6 +9,7 @@ import NMEA.NMEADataBlock; import NMEA.NMEADataUnit; import PamView.dialog.PamCheckBox; import PamView.dialog.PamLabel; +import loggerForms.FormsControl; import loggerForms.LoggerForm; import loggerForms.controlDescriptions.ControlDescription; @@ -41,7 +42,7 @@ public class CheckboxControl extends LoggerControl { return; } try { - checkBox.setSelected((Boolean) data); + checkBox.setSelected(FormsControl.checkBadBoolean(data)); } catch(ClassCastException e) { e.printStackTrace(); diff --git a/src/loggerForms/dataselect/FormDataSelector.java b/src/loggerForms/dataselect/FormDataSelector.java index de627d29..926e68cb 100644 --- a/src/loggerForms/dataselect/FormDataSelector.java +++ b/src/loggerForms/dataselect/FormDataSelector.java @@ -70,7 +70,7 @@ public class FormDataSelector extends DataSelector { @Override public double scoreData(PamDataUnit pamDataUnit) { if (controlDataSelector == null) { - return 0; + return 1; } Object[] formData = null; if (pamDataUnit instanceof FormsDataUnit) { diff --git a/src/loggerForms/monitor/FormsSelectorParams.java b/src/loggerForms/monitor/FormsSelectorParams.java index d691af0c..d1797798 100644 --- a/src/loggerForms/monitor/FormsSelectorParams.java +++ b/src/loggerForms/monitor/FormsSelectorParams.java @@ -7,6 +7,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.dataSelector.DataSelectParams; public class FormsSelectorParams extends DataSelectParams implements Cloneable, Serializable, ManagedParameters { @@ -30,7 +31,7 @@ public class FormsSelectorParams extends DataSelectParams implements Cloneable, @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("formSelection"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/ltsa/LtsaModuleHeader.java b/src/ltsa/LtsaModuleHeader.java index 0b5d888e..50c1034d 100644 --- a/src/ltsa/LtsaModuleHeader.java +++ b/src/ltsa/LtsaModuleHeader.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import binaryFileStorage.BinaryHeader; import binaryFileStorage.BinaryObjectData; import binaryFileStorage.ModuleHeader; @@ -37,7 +38,7 @@ public class LtsaModuleHeader extends ModuleHeader implements ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("fftLength"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/ltsa/LtsaParameters.java b/src/ltsa/LtsaParameters.java index 2dfd9a62..dbf62ec0 100644 --- a/src/ltsa/LtsaParameters.java +++ b/src/ltsa/LtsaParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class LtsaParameters implements Cloneable, Serializable, ManagedParameters { @@ -35,7 +36,7 @@ public class LtsaParameters implements Cloneable, Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/mapgrouplocaliser/MapGrouperSettings.java b/src/mapgrouplocaliser/MapGrouperSettings.java index 955542dc..440700b7 100644 --- a/src/mapgrouplocaliser/MapGrouperSettings.java +++ b/src/mapgrouplocaliser/MapGrouperSettings.java @@ -7,6 +7,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.paneloverlay.OverlayDataInfo; import PamView.paneloverlay.overlaymark.MarkDataSelectorParams; import PamView.paneloverlay.overlaymark.OverlayMarkDataInfo; @@ -64,7 +65,7 @@ public class MapGrouperSettings implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("markDataSelectorParams"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/matchedTemplateClassifer/MatchTemplate.java b/src/matchedTemplateClassifer/MatchTemplate.java index 7f758ddf..0990a22d 100644 --- a/src/matchedTemplateClassifer/MatchTemplate.java +++ b/src/matchedTemplateClassifer/MatchTemplate.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.RawDataHolder; import PamguardMVC.RawDataTransforms; @@ -51,7 +52,7 @@ public class MatchTemplate implements RawDataHolder, Serializable, Cloneable, Ma @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/matchedTemplateClassifer/MatchedTemplateParams.java b/src/matchedTemplateClassifer/MatchedTemplateParams.java index 05f8b107..edd2b912 100644 --- a/src/matchedTemplateClassifer/MatchedTemplateParams.java +++ b/src/matchedTemplateClassifer/MatchedTemplateParams.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamView.PamSymbolType; import PamView.symbol.SymbolData; import fftFilter.FFTFilterParams; @@ -150,7 +151,7 @@ public class MatchedTemplateParams implements Serializable, Cloneable, ManagedPa @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("fftFilterParams"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java b/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java index acf38f67..3b248ea9 100644 --- a/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java +++ b/src/matchedTemplateClassifer/annotation/MatchedClickAnnotationSQL.java @@ -7,6 +7,7 @@ import java.util.List; import PamUtils.PamArrayUtils; import PamguardMVC.PamDataUnit; import PamguardMVC.debug.Debug; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -49,7 +50,7 @@ public class MatchedClickAnnotationSQL implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(typeTable); pamTableDefinition.addTableItem(mtThresholdsTable); pamTableDefinition.addTableItem(mtMatchCorrsTable); @@ -58,7 +59,7 @@ public class MatchedClickAnnotationSQL implements SQLLoggingAddon { } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { MatchedClickAnnotation clickAnnotation = (MatchedClickAnnotation) pamDataUnit.findDataAnnotation(MatchedClickAnnotation.class); @@ -95,7 +96,7 @@ public class MatchedClickAnnotationSQL implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { String threshold = mtThresholdsTable.getDeblankedStringValue(); String mtMatchCorrs = mtMatchCorrsTable.getDeblankedStringValue(); diff --git a/src/mcc/mccacquisition/MCCDaqParams.java b/src/mcc/mccacquisition/MCCDaqParams.java index f1fc3450..ba44c99e 100644 --- a/src/mcc/mccacquisition/MCCDaqParams.java +++ b/src/mcc/mccacquisition/MCCDaqParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import Acquisition.DaqSystemXMLManager; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import analoginput.AnalogRangeData; import simulatedAcquisition.SimProcess; @@ -51,7 +52,7 @@ public class MCCDaqParams implements Serializable, Cloneable, ManagedParameters return null; } - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/metadata/MetaDataContol.java b/src/metadata/MetaDataContol.java new file mode 100644 index 00000000..98093b08 --- /dev/null +++ b/src/metadata/MetaDataContol.java @@ -0,0 +1,114 @@ +package metadata; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.Serializable; + +import javax.swing.JFrame; +import javax.swing.JMenuItem; + +import PamController.PamControlledUnit; +import PamController.PamControlledUnitSettings; +import PamController.PamController; +import PamController.PamSettingManager; +import PamController.PamSettings; +import metadata.swing.MetaDataDialog; + +/** + * Class to handle Project MetaData. Am making this a PAMControlledUnit, but may never + * register it with the model ? Will see what advantages and disadvantages there are. + * @author dg50 + * + */ +public class MetaDataContol extends PamControlledUnit implements PamSettings { + + public static final String unitType = "Meta Data"; + + private static MetaDataContol singleInstance; + + private PamguardMetaData pamguardMetaData = new PamguardMetaData(); + +// private ParameterSetManager deploymentSetManager; + + + private MetaDataContol(String unitName) { + super(unitType, unitName); +// deploymentSetManager = new ParameterSetManager(deploymentData, "Deployment Data"); + PamSettingManager.getInstance().registerSettings(this); + } + + /** + * Easy getter for singleton MetaData controller. + * @return meta data controller + */ + public static MetaDataContol getMetaDataControl() { + if (singleInstance == null) { + singleInstance = new MetaDataContol(unitType); + // add this line to add it to the main modules list. Then it will get menu's, etc. + PamController.getInstance().addControlledUnit(singleInstance); + } + return singleInstance; + } + + /** + * Get PAMGuard Metadata. This contains a nilus Deployment object wrapped up + * so that it can be serialised into other PAMGuard settings. + * @return PAMGuard meta data + */ + public PamguardMetaData getMetaData() { + return pamguardMetaData; + } + + /** + * Set the meta data object. + * @param metaData + */ + public void setMetaData(PamguardMetaData metaData) { + this.pamguardMetaData = metaData; + } + + @Override + public Serializable getSettingsReference() { + pamguardMetaData.checkSerialisation(); + return pamguardMetaData; + } + + @Override + public long getSettingsVersion() { + return PamguardMetaData.serialVersionUID; + } + + @Override + public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { + Object obj = pamControlledUnitSettings.getSettings(); + if (obj instanceof PamguardMetaData) { + pamguardMetaData = (PamguardMetaData) obj; + return true; + } + return false; + } + +// @Override + public JMenuItem createMenu(JFrame parentFrame) { + JMenuItem menuItem = new JMenuItem("Project information ..."); + menuItem.setToolTipText("General project objectives, region, etc."); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showDialog(parentFrame); + } + }); + return menuItem; + } + + protected void showDialog(JFrame parentFrame) { + PamguardMetaData newData = MetaDataDialog.showDialog(parentFrame, pamguardMetaData); + if (newData != null) { + this.pamguardMetaData = newData; + // send around a notification ? + } + } + + + +} diff --git a/src/metadata/PamguardMetaData.java b/src/metadata/PamguardMetaData.java new file mode 100644 index 00000000..ae4064ab --- /dev/null +++ b/src/metadata/PamguardMetaData.java @@ -0,0 +1,111 @@ +package metadata; + +import java.io.Serializable; + +import PamUtils.LatLong; +import nilus.ContactInfo; +import nilus.Deployment; +import nilus.DeploymentRecoveryDetails; +import nilus.DescriptionType; +import nilus.Helper; +import nilus.MetadataInfo; +import nilus.ResponsibleParty; +import tethys.niluswraps.NilusSettingsWrapper; + +/** + * Meta data for a PAMGuard data set. This is based around serialisable versions of + * nilus classes to be compliant with both Tethys and PAMGuard settings files. May only + * need a Deployment object, but scope for adding others / other fields if it's useful. + * @author dg50 + * + */ +public class PamguardMetaData implements Serializable { + + public static final long serialVersionUID = 1L; + + private NilusSettingsWrapper deploymentWrapper; + + public boolean useAudioForDeploymentTimes = true; + +// /** +// * Deployment time (used if different +// */ +// private Long deploymentMillis; +// +// private Long recoverMillis; +// +// private LatLong recoverLatLong; + + /** + * Get the deployment data + * @return nilus deployment + */ + public Deployment getDeployment() { + if (deploymentWrapper == null) { + deploymentWrapper = new NilusSettingsWrapper<>(); + } + Deployment deployment = deploymentWrapper.getNilusObject(Deployment.class); + if (deployment == null) { + deployment = new Deployment(); + try { + Helper.createRequiredElements(deployment); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + deploymentWrapper.setNilusObject(deployment); + } + // check some fields we know we'll need that the Helper may not have managed. + if (deployment.getDescription() == null) { + deployment.setDescription(new DescriptionType()); + } + if (deployment.getMetadataInfo() == null) { + deployment.setMetadataInfo(new MetadataInfo()); + } + if (deployment.getMetadataInfo().getContact() == null) { + deployment.getMetadataInfo().setContact(new ResponsibleParty()); + } + if (deployment.getMetadataInfo().getContact().getContactInfo() == null) { + deployment.getMetadataInfo().getContact().setContactInfo(new ContactInfo()); + } + + if (deployment.getDeploymentDetails() == null) { + deployment.setDeploymentDetails(new DeploymentRecoveryDetails()); + } + if (deployment.getRecoveryDetails() == null) { + deployment.setRecoveryDetails(new DeploymentRecoveryDetails()); + } + return deployment; + } + + /** + * Set the deployment data. + * @param deployment nilus deployment + */ + public void setDeployment(Deployment deployment) { + if (deploymentWrapper == null) { + deploymentWrapper = new NilusSettingsWrapper<>(); + } + deploymentWrapper.setNilusObject(deployment); + } + + /** + * @return the deploymentWrapper + */ + public NilusSettingsWrapper getDeploymentWrapper() { + if (deploymentWrapper == null) { + deploymentWrapper = new NilusSettingsWrapper<>(); + } + return deploymentWrapper; + } + + public void checkSerialisation() { + // check that all wrappers have their xml up to date. + if (deploymentWrapper == null) { + deploymentWrapper = new NilusSettingsWrapper<>(); + } + deploymentWrapper.reSerialise(); + } + + + +} diff --git a/src/metadata/swing/MetaDataDialog.java b/src/metadata/swing/MetaDataDialog.java new file mode 100644 index 00000000..9f744391 --- /dev/null +++ b/src/metadata/swing/MetaDataDialog.java @@ -0,0 +1,121 @@ +package metadata.swing; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Window; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.border.TitledBorder; + +import PamController.PamController; +import PamView.dialog.PamDialog; +import PamView.panel.PamNorthPanel; +import PamView.panel.WestAlignedPanel; +import metadata.PamguardMetaData; +import nilus.Deployment; +import tethys.TethysControl; +import tethys.TethysState; +import tethys.TethysState.StateType; +import tethys.deployment.swing.ProjectInformationPanel; +import tethys.swing.export.DeploymentPeriodPanel; +import tethys.swing.export.DescriptionTypePanel; +import tethys.swing.export.ResponsiblePartyPanel; + +public class MetaDataDialog extends PamDialog { + + private static MetaDataDialog singleInstance; + + private PamguardMetaData pamguardMetaData; + + private DescriptionTypePanel descriptionPanel; + + private ProjectInformationPanel projectInformationPanel; + + private DeploymentPeriodPanel deploymentPeriodPanel; + + private ResponsiblePartyPanel responsiblePanel; + + private TethysControl tethysControl; + + private MetaDataDialog(Window parentFrame) { + super(parentFrame, "Project information", false); + + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + JTabbedPane tabbedPane = new JTabbedPane(); + + tethysControl = (TethysControl) PamController.getInstance().findControlledUnit(TethysControl.unitType); + + projectInformationPanel = new ProjectInformationPanel(parentFrame, null); + descriptionPanel = new DescriptionTypePanel(null, false, false, false); + deploymentPeriodPanel = new DeploymentPeriodPanel(parentFrame); + descriptionPanel.getMainPanel().setPreferredSize(new Dimension(400,300)); + + responsiblePanel = new ResponsiblePartyPanel(); + JPanel northPanel = new JPanel(); + WestAlignedPanel wp; + northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.Y_AXIS)); + + northPanel.add(wp = new WestAlignedPanel(projectInformationPanel.getMainPanel())); + wp.setBorder(new TitledBorder("General project information")); + northPanel.add(wp = new WestAlignedPanel(responsiblePanel.getMainPanel())); + wp.setBorder(new TitledBorder("Contact information")); + + JPanel dpPanel = new WestAlignedPanel(deploymentPeriodPanel.getMainPanel()); + dpPanel.setBorder(new TitledBorder("Deployment period")); + + mainPanel.add(tabbedPane, BorderLayout.CENTER); + tabbedPane.add(northPanel, "General"); + tabbedPane.add(descriptionPanel.getMainPanel(), "Description"); + tabbedPane.add(dpPanel, "Deployment"); + + setResizable(true); + + setDialogComponent(mainPanel); + } + + + + + public static PamguardMetaData showDialog(Window frame, PamguardMetaData pamguardMetaData) { + singleInstance = new MetaDataDialog(frame); + singleInstance.setParams(pamguardMetaData); + singleInstance.setVisible(true); + return singleInstance.pamguardMetaData; + } + + private void setParams(PamguardMetaData pamguardMetaData) { + this.pamguardMetaData = pamguardMetaData; + Deployment deployment = pamguardMetaData.getDeployment(); + projectInformationPanel.setParams(deployment); + descriptionPanel.setParams(deployment.getDescription()); + responsiblePanel.setParams(deployment.getMetadataInfo().getContact()); + deploymentPeriodPanel.setParams(pamguardMetaData); + } + + @Override + public boolean getParams() { + Deployment deployment = pamguardMetaData.getDeployment(); + boolean ok = descriptionPanel.getParams(deployment.getDescription()); + ok &= responsiblePanel.getParams(deployment.getMetadataInfo().getContact()); + ok &= deploymentPeriodPanel.getParams(pamguardMetaData); + + if (tethysControl != null) { + tethysControl.sendStateUpdate(new TethysState(StateType.NEWPROJECTSELECTION)); + } + return ok; + } + + @Override + public void cancelButtonPressed() { + pamguardMetaData = null; + } + + @Override + public void restoreDefaultSettings() { + + } + +} diff --git a/src/networkTransfer/emulator/EmulatorParams.java b/src/networkTransfer/emulator/EmulatorParams.java index e4fe0f74..3f38266a 100644 --- a/src/networkTransfer/emulator/EmulatorParams.java +++ b/src/networkTransfer/emulator/EmulatorParams.java @@ -8,6 +8,7 @@ import PamController.PamControlledUnitSettings; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.LatLong; public class EmulatorParams implements Cloneable, Serializable, ManagedParameters { @@ -50,7 +51,7 @@ public class EmulatorParams implements Cloneable, Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("circleRadius"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/networkTransfer/receive/BuoyStatusData.java b/src/networkTransfer/receive/BuoyStatusData.java index 6b17a6ad..8138f4bf 100644 --- a/src/networkTransfer/receive/BuoyStatusData.java +++ b/src/networkTransfer/receive/BuoyStatusData.java @@ -5,6 +5,7 @@ import java.util.Hashtable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamCalendar; /** @@ -140,7 +141,7 @@ public class BuoyStatusData implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/networkTransfer/receive/BuoyStatusValue.java b/src/networkTransfer/receive/BuoyStatusValue.java index d73a5acd..a42ea7ff 100644 --- a/src/networkTransfer/receive/BuoyStatusValue.java +++ b/src/networkTransfer/receive/BuoyStatusValue.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamUtils.PamCalendar; public class BuoyStatusValue implements Serializable, ManagedParameters { @@ -53,7 +54,7 @@ public class BuoyStatusValue implements Serializable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/networkTransfer/receive/NetworkReceiveParams.java b/src/networkTransfer/receive/NetworkReceiveParams.java index f067c789..488899c5 100644 --- a/src/networkTransfer/receive/NetworkReceiveParams.java +++ b/src/networkTransfer/receive/NetworkReceiveParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class NetworkReceiveParams implements Cloneable, Serializable, ManagedParameters { @@ -40,7 +41,7 @@ public class NetworkReceiveParams implements Cloneable, Serializable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/networkTransfer/send/NetworkSendParams.java b/src/networkTransfer/send/NetworkSendParams.java index 9e0024d8..87e25b0c 100644 --- a/src/networkTransfer/send/NetworkSendParams.java +++ b/src/networkTransfer/send/NetworkSendParams.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamguardMVC.PamDataBlock; public class NetworkSendParams implements Serializable, Cloneable, ManagedParameters { @@ -108,7 +109,7 @@ public class NetworkSendParams implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("selectedDataBlocks"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/nidaqdev/networkdaq/NIDaqLogging.java b/src/nidaqdev/networkdaq/NIDaqLogging.java index dc12309b..75022e5c 100644 --- a/src/nidaqdev/networkdaq/NIDaqLogging.java +++ b/src/nidaqdev/networkdaq/NIDaqLogging.java @@ -3,6 +3,7 @@ package nidaqdev.networkdaq; import java.sql.Types; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -20,12 +21,12 @@ public class NIDaqLogging implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(crioTemperature); } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { Double lastTemp = niNetworkDaq.getLastTemperature(); if (lastTemp == null) { crioTemperature.setValue(null); @@ -38,7 +39,7 @@ public class NIDaqLogging implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { // TODO Auto-generated method stub return false; } diff --git a/src/nidaqdev/networkdaq/NINetworkDaqParams.java b/src/nidaqdev/networkdaq/NINetworkDaqParams.java index 7458739e..a7f67845 100644 --- a/src/nidaqdev/networkdaq/NINetworkDaqParams.java +++ b/src/nidaqdev/networkdaq/NINetworkDaqParams.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import Acquisition.DaqSystemXMLManager; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class NINetworkDaqParams implements Serializable, Cloneable, ManagedParameters { @@ -169,7 +170,7 @@ public class NINetworkDaqParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { if (DaqSystemXMLManager.isSelected(NINetworkDaq.systemName)) { - return PamParameterSet.autoGenerate(this); + return PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); } return null; } diff --git a/src/nmeaEmulator/NMEAEmulatorParams.java b/src/nmeaEmulator/NMEAEmulatorParams.java index 1889ca17..d7b89529 100644 --- a/src/nmeaEmulator/NMEAEmulatorParams.java +++ b/src/nmeaEmulator/NMEAEmulatorParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class NMEAEmulatorParams implements Serializable, Cloneable, ManagedParameters { @@ -23,7 +24,7 @@ public class NMEAEmulatorParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/noiseBandMonitor/NoiseBandSettings.java b/src/noiseBandMonitor/NoiseBandSettings.java index d905c536..8f00571c 100644 --- a/src/noiseBandMonitor/NoiseBandSettings.java +++ b/src/noiseBandMonitor/NoiseBandSettings.java @@ -7,6 +7,7 @@ import Filters.FilterType; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class NoiseBandSettings implements Serializable, Cloneable, ManagedParameters { @@ -59,7 +60,7 @@ public class NoiseBandSettings implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("showStandard"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/noiseMonitor/NoiseControl.java b/src/noiseMonitor/NoiseControl.java index 9a50ea6f..e1fbce42 100644 --- a/src/noiseMonitor/NoiseControl.java +++ b/src/noiseMonitor/NoiseControl.java @@ -13,6 +13,7 @@ import org.w3c.dom.Element; import PamController.PamControlledUnit; import PamController.PamControlledUnitSettings; +import PamController.PamController; import PamController.PamSettingManager; import PamController.PamSettings; import PamView.PamTabPanel; @@ -298,4 +299,15 @@ public class NoiseControl extends PamControlledUnit implements PamSettings { public NoiseSettings getNoiseSettings() { return noiseSettings; } + + @Override + public void notifyModelChanged(int changeType) { + super.notifyModelChanged(changeType); + switch (changeType) { + case PamController.INITIALIZATION_COMPLETE: + noiseProcess.setupProcess(); + sortBandEdges(); + } + } + } diff --git a/src/noiseMonitor/NoiseDataBlock.java b/src/noiseMonitor/NoiseDataBlock.java index b5e7f628..effbd591 100644 --- a/src/noiseMonitor/NoiseDataBlock.java +++ b/src/noiseMonitor/NoiseDataBlock.java @@ -2,11 +2,18 @@ package noiseMonitor; import noiseMonitor.alarm.NoiseAlarmCounter; import noiseMonitor.alarm.NoiseAlarmProvider; +import noiseMonitor.species.TethysNoiseDataProvider; +import tethys.TethysControl; +import tethys.pamdata.TethysDataProvider; +import tethys.species.DataBlockSpeciesManager; +import tethys.species.FixedSpeciesManager; import alarm.AlarmCounter; import alarm.AlarmCounterProvider; import alarm.AlarmDataSource; import PamUtils.FrequencyFormat; import PamUtils.PamUtils; +import PamguardMVC.DataAutomation; +import PamguardMVC.DataAutomationInfo; import PamguardMVC.PamDataBlock; import PamguardMVC.PamProcess; @@ -32,13 +39,15 @@ public class NoiseDataBlock extends PamDataBlock implements Alarm private NoiseAlarmProvider noiseAlarmCounter; /** - * These are the names used in the database columns, so dont' change them on pain of + * These are the names used in the database columns, so don't change them on pain of * nothing ever working ever again ! */ public static final String[] measureNames = {"mean", "median", "low95", "high95", "Min", "Max", "Peak"}; public static final String[] displayNames = {"Mean", "Median", "Lower 95%", "Upper 95%", "Minimum", "Maximim", "Peak"}; private int statisticTypes; + private TethysNoiseDataProvider tethysNoiseDataProvider; + private FixedSpeciesManager fixedSpeciesManager; public NoiseDataBlock(String dataName, PamProcess parentProcess, int channelMap) { @@ -244,6 +253,27 @@ public class NoiseDataBlock extends PamDataBlock implements Alarm } return noiseAlarmCounter; } + + @Override + public DataAutomationInfo getDataAutomationInfo() { + return new DataAutomationInfo(DataAutomation.AUTOMATIC); + } + + @Override + public TethysDataProvider getTethysDataProvider(TethysControl tethysControl) { + if (tethysNoiseDataProvider == null) { + tethysNoiseDataProvider = new TethysNoiseDataProvider(tethysControl, this); + } + return tethysNoiseDataProvider; + } + + @Override + public DataBlockSpeciesManager getDatablockSpeciesManager() { + if (fixedSpeciesManager == null) { + fixedSpeciesManager = new FixedSpeciesManager(this, -10, "anthropogenic", "noise"); + } + return fixedSpeciesManager; + } } diff --git a/src/noiseMonitor/NoiseDisplaySettings.java b/src/noiseMonitor/NoiseDisplaySettings.java index 7ef4f5de..b70db3ac 100644 --- a/src/noiseMonitor/NoiseDisplaySettings.java +++ b/src/noiseMonitor/NoiseDisplaySettings.java @@ -6,6 +6,7 @@ import java.util.Arrays; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class NoiseDisplaySettings implements Serializable, Cloneable, ManagedParameters { @@ -70,7 +71,7 @@ public class NoiseDisplaySettings implements Serializable, Cloneable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("displayLengthSeconds"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/noiseMonitor/NoiseLogging.java b/src/noiseMonitor/NoiseLogging.java index 4bbc0cfd..a3a62d61 100644 --- a/src/noiseMonitor/NoiseLogging.java +++ b/src/noiseMonitor/NoiseLogging.java @@ -116,5 +116,27 @@ public class NoiseLogging extends SQLLogging { } } } + + private long lastTime; + + @Override + protected PamDataUnit createDataUnit(SQLTypes sqlTypes, long timeMilliseconds, int databaseIndex) { + int chan = channelNumber.getIntegerValue(); + int nBands = noiseDataBlock.getBandLoEdges().length; + int nMeasures = noiseDataBlock.getUsedMeasureNames().length; + if (nMeasures * nBands != bandItems.length) { + return null; + } + double[][] bandData = new double[nBands][nMeasures]; + for (int iBand = 0, iCol = 0; iBand < nBands; iBand++) { + for (int iMeasure = 0; iMeasure < nMeasures; iMeasure++, iCol++) { + bandData[iBand][iMeasure] = bandItems[iCol].getDoubleValue(); + } + } + + NoiseDataUnit noiseDataUnit = new NoiseDataUnit(timeMilliseconds, 1< i) { diff --git a/src/noiseMonitor/alarm/NoiseAlarmParameters.java b/src/noiseMonitor/alarm/NoiseAlarmParameters.java index d2f7ec60..551d430c 100644 --- a/src/noiseMonitor/alarm/NoiseAlarmParameters.java +++ b/src/noiseMonitor/alarm/NoiseAlarmParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class NoiseAlarmParameters implements Serializable, Cloneable, ManagedParameters { @@ -26,7 +27,7 @@ public class NoiseAlarmParameters implements Serializable, Cloneable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } } diff --git a/src/noiseMonitor/species/TethysNoiseDataProvider.java b/src/noiseMonitor/species/TethysNoiseDataProvider.java new file mode 100644 index 00000000..eea8d6d3 --- /dev/null +++ b/src/noiseMonitor/species/TethysNoiseDataProvider.java @@ -0,0 +1,105 @@ +package noiseMonitor.species; + +import java.util.List; + +import PamUtils.PamUtils; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import nilus.Detection; +import nilus.Detection.Parameters; +import nilus.DetectionEffortKind; +import nilus.GranularityEnumType; +import nilus.Helper; +import noiseMonitor.NoiseDataBlock; +import noiseMonitor.NoiseDataUnit; +import tethys.TethysControl; +import tethys.niluswraps.PDeployment; +import tethys.output.StreamExportParams; +import tethys.output.TethysExportParams; +import tethys.pamdata.AutoTethysProvider; +import tethys.swing.export.ExportWizardCard; +import tethys.swing.export.GranularityCard; + +public class TethysNoiseDataProvider extends AutoTethysProvider { + + private NoiseDataBlock noiseDataBlock; + + public TethysNoiseDataProvider(TethysControl tethysControl, NoiseDataBlock noiseDataBlock) { + super(tethysControl, noiseDataBlock); + this.noiseDataBlock = noiseDataBlock; + } + + @Override + public GranularityEnumType[] getAllowedGranularities() { + GranularityEnumType[] allowed = {GranularityEnumType.CALL}; + return allowed; + } + + @Override + public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams, + StreamExportParams streamExportParams) { + Detection detection = super.createDetection(dataUnit, tethysExportParams, streamExportParams); + NoiseDataUnit noiseDataUnit = (NoiseDataUnit) dataUnit; + /* + * Now all the noise measurements, noting there may be several types. + */ + int statTypes = noiseDataBlock.getStatisticTypes(); + int nTypes = PamUtils.getNumChannels(statTypes); + Parameters params = detection.getParameters(); + List measurements = params.getFrequencyMeasurementsDB(); + double[][] noiseData = noiseDataUnit.getNoiseBandData(); + int meanIndex = -1; + for (int i = 0; i < nTypes; i++) { + int type = PamUtils.getNthChannel(i, statTypes); + String name = noiseDataBlock.getMeasureName(type); + if (1< effortKinds, + StreamExportParams exportParams) { + super.getEffortKinds(pDeployment, effortKinds, exportParams); + DetectionEffortKind kind = effortKinds.get(0); + nilus.DetectionEffortKind.Parameters params = kind.getParameters(); + if (params == null) { + params = new nilus.DetectionEffortKind.Parameters(); + try { + Helper.createRequiredElements(params); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + kind.setParameters(params); + } + List fMeasures = params.getFrequencyMeasurementsHz(); + double[] loEdges = noiseDataBlock.getBandLoEdges(); + double[] hiEdges = noiseDataBlock.getBandHiEdges(); + // put lot mean into the array + for (int i = 0; i < loEdges.length; i++) { + fMeasures.add(roundSignificantFigures(Math.sqrt(loEdges[i]*hiEdges[i]), 4)); + } + } + + @Override + public boolean wantExportDialogCard(ExportWizardCard wizPanel) { + if (wizPanel.getClass() == GranularityCard.class) { + return false; + } + return super.wantExportDialogCard(wizPanel); + } + +} diff --git a/src/noiseOneBand/OneBandAlarmParameters.java b/src/noiseOneBand/OneBandAlarmParameters.java index 90a1659c..3e4e5a69 100644 --- a/src/noiseOneBand/OneBandAlarmParameters.java +++ b/src/noiseOneBand/OneBandAlarmParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class OneBandAlarmParameters implements Serializable, Cloneable, ManagedParameters { @@ -37,7 +38,7 @@ public class OneBandAlarmParameters implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/noiseOneBand/OneBandDisplayParams.java b/src/noiseOneBand/OneBandDisplayParams.java index 04cf01d7..fe9b7a82 100644 --- a/src/noiseOneBand/OneBandDisplayParams.java +++ b/src/noiseOneBand/OneBandDisplayParams.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; public class OneBandDisplayParams implements Serializable, Cloneable, ManagedParameters { @@ -61,7 +62,7 @@ public class OneBandDisplayParams implements Serializable, Cloneable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("displayChannels"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/noiseOneBand/OneBandParameters.java b/src/noiseOneBand/OneBandParameters.java index b35e4f68..ea2f3320 100644 --- a/src/noiseOneBand/OneBandParameters.java +++ b/src/noiseOneBand/OneBandParameters.java @@ -10,6 +10,7 @@ import Filters.FilterType; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class OneBandParameters implements Serializable, Cloneable, ManagedParameters { @@ -235,7 +236,7 @@ public class OneBandParameters implements Serializable, Cloneable, ManagedParame @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("filterParams"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/noiseOneBand/offline/OneBandSummaryParams.java b/src/noiseOneBand/offline/OneBandSummaryParams.java index 7565c6e7..14e71708 100644 --- a/src/noiseOneBand/offline/OneBandSummaryParams.java +++ b/src/noiseOneBand/offline/OneBandSummaryParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class OneBandSummaryParams implements Serializable, Cloneable, ManagedParameters { @@ -23,7 +24,7 @@ public class OneBandSummaryParams implements Serializable, Cloneable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/offlineProcessing/OfflineTask.java b/src/offlineProcessing/OfflineTask.java index dab50a6b..ec63f39b 100644 --- a/src/offlineProcessing/OfflineTask.java +++ b/src/offlineProcessing/OfflineTask.java @@ -123,6 +123,16 @@ public abstract class OfflineTask { } } + /** + * Get a uniquely identifyng name for the task which consists of the + * pamControlledUnit type and name as well as the tasks shorter name from getName(); + * @return a long name which should be unique within a configuration. + */ + public String getLongName() { + PamControlledUnit tcu = getTaskControlledUnit(); + String str = String.format("%s:%s:%s", tcu.getUnitType(), tcu.getUnitName(), getName()); + return str; + } /** * * @return a name for the task, to be displayed in the dialog. diff --git a/src/offlineProcessing/OfflineTaskManager.java b/src/offlineProcessing/OfflineTaskManager.java index a88bfd1a..9c6485ce 100644 --- a/src/offlineProcessing/OfflineTaskManager.java +++ b/src/offlineProcessing/OfflineTaskManager.java @@ -17,6 +17,10 @@ public class OfflineTaskManager { private ArrayList globalTaskList = new ArrayList(); + public static final String commandFlag = "-offlinetask"; + + public ArrayList commandLineTasks = new ArrayList(); + public static OfflineTaskManager getManager() { if (singleInstance == null) { singleInstance = new OfflineTaskManager(); @@ -116,8 +120,9 @@ public class OfflineTaskManager { * @param offlineTask * @return matching task or null. */ + @SuppressWarnings("rawtypes") public OfflineTask findOfflineTask(OfflineTask offlineTask) { - return findOfflineTask(offlineTask.getUnitType(), offlineTask.getUnitName(), offlineTask.getName()); + return findOfflineTask(offlineTask.getLongName()); } /** @@ -128,6 +133,7 @@ public class OfflineTaskManager { * @param taskName * @return matching task or null. */ + @SuppressWarnings("rawtypes") public OfflineTask findOfflineTask(String unitType, String unitName, String taskName) { // could possibly also do a check on class type ???? for (OfflineTask aTask : globalTaskList) { @@ -143,4 +149,51 @@ public class OfflineTaskManager { } return null; } + + /** + * Another way of finding offline tasks based on their long name. This is basically + * the three names unitType, unitName and taskName concatenated together. Get's used + * for some task management such as passing batch processing instructions. + * @param taskLongName + * @return matching task or null. + */ + @SuppressWarnings("rawtypes") + public OfflineTask findOfflineTask(String taskLongName) { + for (OfflineTask aTask : globalTaskList) { + if (aTask.getLongName().equals(taskLongName)) { + return aTask; + } + } + return null; + } + + /** + * Add a task listed in the command line when PAMGuard was started. + * @param taskLongName + */ + public void addCommandLineTask(String taskLongName) { + commandLineTasks.add(taskLongName); + } + + /** + * The list of tasks from the command line. + * @return the commandLineTasks + */ + public ArrayList getCommandLineTasks() { + return commandLineTasks; + } + + /** + * Get the status of jobs to pass back to the batch process controller. + * @return + */ + public String getBatchStatus() { + /** + * this needs to largely follow the format of the data in folderinputsystem: + * String bs = String.format("%d,%d,%d,%s", nFiles,currentFile,generalStatus,currFile); + */ + int generalStatus = PamController.getInstance().getRealStatus(); + String bs = String.format("%d,%d,%d,%s", commandLineTasks.size(), 0, generalStatus, "Processing"); + return bs; + } } diff --git a/src/offlineProcessing/TaskGroupParams.java b/src/offlineProcessing/TaskGroupParams.java index 25497c24..c04a88cc 100644 --- a/src/offlineProcessing/TaskGroupParams.java +++ b/src/offlineProcessing/TaskGroupParams.java @@ -8,6 +8,7 @@ import java.util.Arrays; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Parameter control for offline task groups. @@ -137,7 +138,7 @@ public class TaskGroupParams implements Cloneable, Serializable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("taskSelection"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/pamScrollSystem/DataLoadQueData.java b/src/pamScrollSystem/DataLoadQueData.java index 77c143ab..93ed656c 100644 --- a/src/pamScrollSystem/DataLoadQueData.java +++ b/src/pamScrollSystem/DataLoadQueData.java @@ -1,5 +1,6 @@ package pamScrollSystem; +import PamUtils.PamCalendar; import PamguardMVC.PamDataBlock; /** @@ -68,6 +69,14 @@ public class DataLoadQueData { public void setDataEnd(long dataEnd) { this.dataEnd = dataEnd; } + + + @Override + public String toString() { + String str = String.format("%s %s - %s", pamDataBlock.getLongDataName(), + PamCalendar.formatDBDateTime(dataStart),PamCalendar.formatDBDateTime(dataEnd)); + return str; + } } diff --git a/src/pamguard/GlobalArguments.java b/src/pamguard/GlobalArguments.java index 4f601911..eea82ec8 100644 --- a/src/pamguard/GlobalArguments.java +++ b/src/pamguard/GlobalArguments.java @@ -9,6 +9,11 @@ import java.util.HashMap; * */ public class GlobalArguments { + + /** + * Put some common flags here for convenience. + */ + public static final String BATCHFLAG = "-batch"; static HashMap globalFlags = new HashMap<>(); @@ -43,4 +48,12 @@ public class GlobalArguments { return Integer.valueOf(val); } + /** + * Is the batch flag set ? + * @return + */ + public static boolean isBatch() { + return getParam(BATCHFLAG) != null; + } + } diff --git a/src/pamguard/Pamguard.java b/src/pamguard/Pamguard.java index a80c16cc..33009522 100644 --- a/src/pamguard/Pamguard.java +++ b/src/pamguard/Pamguard.java @@ -44,6 +44,7 @@ import binaryFileStorage.BinaryStore; import dataPlotsFX.JamieDev; import generalDatabase.DBControl; import networkTransfer.send.NetworkSender; +import offlineProcessing.OfflineTaskManager; import rocca.RoccaDev; import java.io.BufferedReader; @@ -154,6 +155,7 @@ public class Pamguard { } catch (Exception e) { e.printStackTrace(); } + boolean showSplash = true; if (args != null) { int nArgs = args.length; int iArg = 0; @@ -172,6 +174,14 @@ public class Pamguard { runMode = PamController.RUN_NETWORKRECEIVER; System.out.println("PAMGUARD Network Reciever Mode"); } + else if (anArg.equalsIgnoreCase("-nosplash")) { + showSplash = false; + } + else if (anArg.equalsIgnoreCase(GlobalArguments.BATCHFLAG)) { + // flag to say we're in batch processing mode. Can be used + // to avoid one or two dialogs that pop up in Viewer mode. + GlobalArguments.setParam(GlobalArguments.BATCHFLAG, Boolean.TRUE.toString()); + } // removed SEICHE switch when the two SEICHE modules were converted to plugins // else if (anArg.equalsIgnoreCase("-seiche")) { @@ -240,6 +250,10 @@ public class Pamguard { pamBuoyGlobals.setMultiportConfig(mAddr, mPort); System.out.printf("Setting multicast control addr %s port %d\n", mAddr, mPort); } + else if (anArg.equalsIgnoreCase(OfflineTaskManager.commandFlag)) { + String taskName = args[iArg++]; + OfflineTaskManager.getManager().addCommandLineTask(taskName); + } else if (anArg.equalsIgnoreCase("-nolog")) { System.out.println("Disabling log file from command line switch..."); ProxyPrintStream.disableLogFile(); @@ -383,7 +397,7 @@ public class Pamguard { if(runMode == PamController.RUN_REMOTE) { spashTime = 0; } - if (spashTime > 0 && (PamGUIManager.getGUIType() != PamGUIManager.NOGUI)) { + if (showSplash && spashTime > 0 && (PamGUIManager.getGUIType() != PamGUIManager.NOGUI)) { new Splash(spashTime, chosenRunMode); } // @@ -717,6 +731,47 @@ public class Pamguard { } } } + /* + * Some bits that need added to Maven POM. + * + + + org.eclipse.persistence + org.eclipse.persistence.moxy + 2.5.0 + + + javax.xml.bind + jaxb-api + 2.4.0-b180830.0359 + + + org.glassfish.jaxb + jaxb-runtime + 2.4.0-b180830.0438 + + + org.glassfish.jaxb + jaxb-xjc + 2.4.0-b180830.0438 + + + + */ } diff --git a/src/quickAnnotation/QuickAnnotationParameters.java b/src/quickAnnotation/QuickAnnotationParameters.java index fd8ed2a7..65e3b05b 100644 --- a/src/quickAnnotation/QuickAnnotationParameters.java +++ b/src/quickAnnotation/QuickAnnotationParameters.java @@ -9,6 +9,7 @@ import PamController.PamSettingManager; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import difar.DifarControl; import difar.DifarParameters; import generalDatabase.lookupTables.LookupItem; @@ -96,7 +97,7 @@ public class QuickAnnotationParameters implements Serializable, Cloneable, Manag @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("exportClips"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java b/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java index 7ad1ffb9..41ef495e 100644 --- a/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java +++ b/src/rawDeepLearningClassifier/dataPlotFX/DLPredDisplayParams.java @@ -3,6 +3,7 @@ package rawDeepLearningClassifier.dataPlotFX; import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import javafx.scene.paint.Color; /** @@ -25,7 +26,7 @@ public class DLPredDisplayParams implements Serializable, Cloneable, ManagedPara @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java b/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java index 72761199..b046b27b 100644 --- a/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java +++ b/src/rawDeepLearningClassifier/logging/DLAnnotationSQL.java @@ -1,6 +1,7 @@ package rawDeepLearningClassifier.logging; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.SQLLoggingAddon; import generalDatabase.SQLTypes; @@ -12,19 +13,19 @@ public class DLAnnotationSQL implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { // TODO Auto-generated method stub } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { // TODO Auto-generated method stub return false; } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { // TODO Auto-generated method stub return false; } diff --git a/src/rocca/RoccaParameters.java b/src/rocca/RoccaParameters.java index bec1fecb..c7db4aae 100644 --- a/src/rocca/RoccaParameters.java +++ b/src/rocca/RoccaParameters.java @@ -30,6 +30,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Parameters for Rocca
@@ -856,7 +857,7 @@ public class RoccaParameters implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("runAncCalcs4Clicks"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/seismicVeto/VetoParameters.java b/src/seismicVeto/VetoParameters.java index 0ca08357..e41907f7 100644 --- a/src/seismicVeto/VetoParameters.java +++ b/src/seismicVeto/VetoParameters.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class VetoParameters implements Serializable, Cloneable, ManagedParameters { @@ -40,7 +41,7 @@ public class VetoParameters implements Serializable, Cloneable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("backgroundConstant"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/serialComms/SerialPortParameters.java b/src/serialComms/SerialPortParameters.java index bb9d699c..373852fd 100644 --- a/src/serialComms/SerialPortParameters.java +++ b/src/serialComms/SerialPortParameters.java @@ -29,6 +29,7 @@ import com.fazecast.jSerialComm.SerialPort; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * @author David McLaren, Paul Redmond @@ -166,7 +167,7 @@ public class SerialPortParameters implements Serializable, Cloneable, ManagedPar @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/simulatedAcquisition/SimObject.java b/src/simulatedAcquisition/SimObject.java index 053c8a9b..335139fb 100644 --- a/src/simulatedAcquisition/SimObject.java +++ b/src/simulatedAcquisition/SimObject.java @@ -5,6 +5,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; import PamModel.parametermanager.PrivatePamParameterData; import simulatedAcquisition.movement.MovementModel; import simulatedAcquisition.movement.MovementModels; @@ -150,7 +151,7 @@ public class SimObject implements Serializable, Cloneable, ManagedParameters { @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); try { Field field = this.getClass().getDeclaredField("depth"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/simulatedAcquisition/movement/CircularMovementParams.java b/src/simulatedAcquisition/movement/CircularMovementParams.java index 4fe63e95..c956209e 100644 --- a/src/simulatedAcquisition/movement/CircularMovementParams.java +++ b/src/simulatedAcquisition/movement/CircularMovementParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class CircularMovementParams implements Serializable, Cloneable, ManagedParameters { @@ -84,7 +85,7 @@ public class CircularMovementParams implements Serializable, Cloneable, ManagedP @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/simulatedAcquisition/movement/GridMovementParams.java b/src/simulatedAcquisition/movement/GridMovementParams.java index 210ac943..72ae6cb2 100644 --- a/src/simulatedAcquisition/movement/GridMovementParams.java +++ b/src/simulatedAcquisition/movement/GridMovementParams.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class GridMovementParams implements Serializable, Cloneable, ManagedParameters { @@ -42,7 +43,7 @@ public class GridMovementParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("distRangeMetres"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/soundPlayback/PlaybackParameters.java b/src/soundPlayback/PlaybackParameters.java index 08c1e56a..2d7d22d1 100644 --- a/src/soundPlayback/PlaybackParameters.java +++ b/src/soundPlayback/PlaybackParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; /** * Parameters controlling sound playback @@ -165,7 +166,7 @@ public class PlaybackParameters implements Cloneable, Serializable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/soundPlayback/preprocess/EnvelopeParams.java b/src/soundPlayback/preprocess/EnvelopeParams.java index b3e0587c..7dd143e9 100644 --- a/src/soundPlayback/preprocess/EnvelopeParams.java +++ b/src/soundPlayback/preprocess/EnvelopeParams.java @@ -7,6 +7,7 @@ import Filters.FilterParams; import Filters.FilterType; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class EnvelopeParams implements Cloneable, Serializable, ManagedParameters { @@ -87,7 +88,7 @@ public class EnvelopeParams implements Cloneable, Serializable, ManagedParameter @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DISPLAY); return ps; } diff --git a/src/soundtrap/STClickControl.java b/src/soundtrap/STClickControl.java index 203357fe..8e7ca7b0 100644 --- a/src/soundtrap/STClickControl.java +++ b/src/soundtrap/STClickControl.java @@ -37,6 +37,7 @@ import javax.swing.JSeparator; import org.pamguard.x3.sud.SUDClickDetectorInfo; import Acquisition.AcquisitionControl; +import PamController.PamSensor; import PamController.PamControlledUnitSettings; import PamController.PamController; import PamController.PamSettingManager; @@ -54,7 +55,7 @@ import soundtrap.sud.SudFileDWVHandler; * @author mo55 * */ -public class STClickControl extends ClickControl { +public class STClickControl extends ClickControl implements PamSensor { private SUDClickDetectorInfo sudClickDetectorInfo; @@ -229,6 +230,17 @@ public class STClickControl extends ClickControl { public void setSudClickDetectorInfo(SUDClickDetectorInfo sudClickDetectorInfo) { this.sudClickDetectorInfo = sudClickDetectorInfo; } + + @Override + public String getSensorDescription() { + String desc = String.format("SoundTrap Click Detector at %dHz", (int) getClickDataBlock().getSampleRate()); + return desc; + } + + @Override + public String getSensorId() { + return null; + } /** * Class to handle SoundTrap click detector settings without messing up diff --git a/src/soundtrap/STToolsParams.java b/src/soundtrap/STToolsParams.java index 722c6fb6..514b96d6 100644 --- a/src/soundtrap/STToolsParams.java +++ b/src/soundtrap/STToolsParams.java @@ -5,6 +5,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class STToolsParams implements Serializable, Cloneable, ManagedParameters { @@ -62,7 +63,7 @@ public class STToolsParams implements Serializable, Cloneable, ManagedParameters @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java b/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java index 0931c963..9cfa3765 100644 --- a/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java +++ b/src/spectrogramNoiseReduction/SpectrogramNoiseSettings.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; import PamModel.parametermanager.PrivatePamParameterData; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class SpectrogramNoiseSettings implements Serializable, Cloneable, ManagedParameters { @@ -79,7 +80,7 @@ public class SpectrogramNoiseSettings implements Serializable, Cloneable, Manage @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); try { Field field = this.getClass().getDeclaredField("runMethod"); ps.put(new PrivatePamParameterData(this, field) { diff --git a/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java b/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java index 23e9f1f7..18f1811e 100644 --- a/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java +++ b/src/spectrogramNoiseReduction/averageSubtraction/AverageSubtractionParameters.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class AverageSubtractionParameters implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class AverageSubtractionParameters implements Serializable, Cloneable, Ma @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java b/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java index fe91beba..c24aed99 100644 --- a/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java +++ b/src/spectrogramNoiseReduction/medianFilter/MedianFilterParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class MedianFilterParams implements Serializable, Cloneable, ManagedParameters { @@ -25,7 +26,7 @@ public class MedianFilterParams implements Serializable, Cloneable, ManagedParam @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/spectrogramNoiseReduction/threshold/ThresholdParams.java b/src/spectrogramNoiseReduction/threshold/ThresholdParams.java index 8842e6e0..5674d577 100644 --- a/src/spectrogramNoiseReduction/threshold/ThresholdParams.java +++ b/src/spectrogramNoiseReduction/threshold/ThresholdParams.java @@ -4,6 +4,7 @@ import java.io.Serializable; import PamModel.parametermanager.ManagedParameters; import PamModel.parametermanager.PamParameterSet; +import PamModel.parametermanager.PamParameterSet.ParameterSetType; public class ThresholdParams implements Serializable, Cloneable, ManagedParameters { @@ -27,7 +28,7 @@ public class ThresholdParams implements Serializable, Cloneable, ManagedParamete @Override public PamParameterSet getParameterSet() { - PamParameterSet ps = PamParameterSet.autoGenerate(this); + PamParameterSet ps = PamParameterSet.autoGenerate(this, ParameterSetType.DETECTOR); return ps; } diff --git a/src/targetMotionOld/TargetMotionSQLLogging.java b/src/targetMotionOld/TargetMotionSQLLogging.java index 6017a12b..4f4f133e 100644 --- a/src/targetMotionOld/TargetMotionSQLLogging.java +++ b/src/targetMotionOld/TargetMotionSQLLogging.java @@ -15,6 +15,7 @@ import PamDetection.AbstractLocalisation; import PamDetection.LocContents; import PamUtils.LatLong; import PamguardMVC.PamDataUnit; +import generalDatabase.EmptyTableDefinition; import generalDatabase.PamTableDefinition; import generalDatabase.PamTableItem; import generalDatabase.SQLLoggingAddon; @@ -119,7 +120,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon { } @Override - public void addTableItems(PamTableDefinition pamTableDefinition) { + public void addTableItems(EmptyTableDefinition pamTableDefinition) { pamTableDefinition.addTableItem(modelName); @@ -146,7 +147,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon { } @Override - public boolean saveData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, + public boolean saveData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { AbstractLocalisation tmResult = pamDataUnit.getLocalisation(); clearEverything(); @@ -218,7 +219,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon { return true; } - private boolean saveGroupLocalisation(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, + private boolean saveGroupLocalisation(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit, GroupLocalisation groupLocalisation) { int nAmbiguities = groupLocalisation.getAmbiguityCount(); @@ -239,7 +240,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon { return true; } - private boolean saveGroupLocalisation(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, + private boolean saveGroupLocalisation(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit, int resultIndex, GroupLocResult tmResult) { @@ -323,7 +324,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon { } @Override - public boolean loadData(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, + public boolean loadData(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit) { GroupLocalisation tml = new GroupLocalisation(pamDataUnit, null); @@ -341,7 +342,7 @@ public class TargetMotionSQLLogging implements SQLLoggingAddon { return true; } - private GroupLocResult loadLocResult(SQLTypes sqlTypes, PamTableDefinition pamTableDefinition, + private GroupLocResult loadLocResult(SQLTypes sqlTypes, EmptyTableDefinition pamTableDefinition, PamDataUnit pamDataUnit, GroupLocalisation tml, int resultIndex) { double latVal, longVal; diff --git a/src/tethys/Collection.java b/src/tethys/Collection.java new file mode 100644 index 00000000..93a6acb2 --- /dev/null +++ b/src/tethys/Collection.java @@ -0,0 +1,136 @@ +package tethys; + +/** + * Names of Tethys Collections. These are the plural names, though contain functionality + * to get the document names, which are generally the singular of the enum + * @author dg50 + * + */ +public enum Collection { + + Deployments, Detections, Calibrations, Localizations, SpeciesAbbreviations, Ensembles, SourceMaps, ITIS, ITIS_ranks, OTHER; + + /** + * A list of the main collections in the database, i.e. ones the user will + * possibly want to interract with through the GUI. + * @return list of main collections. + */ + public static Collection[] mainList() { + Collection[] cs = {Deployments, Detections, Calibrations, Localizations, SpeciesAbbreviations, Ensembles}; + return cs; + } + /** + * Get the name of a document in this collection, this is generally the singular + * of the collection name. + * @return Document name, e.g. Detection for Detections + */ + public String documentName() { + switch (this) { + case Calibrations: + return "Calibration"; + case Deployments: + return "Deployment"; + case Detections: + return "Detections"; // this one is plural ! + case Localizations: + return "Localize"; + case SpeciesAbbreviations: + return "SpeciesAbbreviation"; + case Ensembles: + return "Ensemble"; + default: + break; + } + return null; + } + + public String collectionName() { + return this.toString(); + } + + /** + * Find a collection for the given name. This does + * a bit more than the simple 'valueof' since it also + * allows the user to input a documentname in place, which + * is just the collection name without the plural 's' on the end + * @param name Collection name. + * @return Collection or null. + */ + public static Collection fromName(String name) { + Collection c = Collection.valueOf(name); + if (c != null) { + return c; + } + /** + * Otherwise, may need to do a longer search to see if the user has passed + * the singular document name. + */ + if (name.endsWith("s") == false) { + c = Collection.valueOf(name+"s"); + if (c != null) { + return c; + } + } + return null; + } + /** + * get Tethys collection name from nilus collection objects + * @param className nilus object Class Name + * @return name of Tethys collection + */ + public static Collection fromClass(Class nilusClass) { + String className = nilusClass.getName(); + switch(className) { + case "nilus.Deployment": + return Deployments; + case "nilus.Detections": + return Detections; + case "nilus.Calibration": + return Calibrations; + case "nilus.Ensemble": + return Ensembles; + case "nilus.Localization": + return Localizations; + case "nilus.SpeciesAbbreviation": + return SpeciesAbbreviations; + case "nilus.SourceMap": + return SourceMaps; + case "nilus.ITIS": + return ITIS; + case "nilus.ranks": + return ITIS_ranks; + default: + return null; + } + } +// /** +// * get Tethys collection name from nilus collection objects +// * @param className nilus object Class Name +// * @return name of Tethys collection +// */ +// public static String getCollection(Class nilusClass) { +// String className = nilusClass.getName(); +// switch(className) { +// case "nilus.Deployment": +// return "Deployments"; +// case "nilus.Detections": +// return "Detections"; +// case "nilus.Calibration": +// return "Calibrations"; +// case "nilus.Ensemble": +// return "Ensembles"; +// case "nilus.Localization": +// return "Localizations"; +// case "nilus.SpeciesAbbreviation": +// return "SpeciesAbbreviations"; +// case "nilus.SourceMap": +// return "SourceMaps"; +// case "nilus.ITIS": +// return "ITIS"; +// case "nilus.ranks": +// return "ITIS_ranks"; +// default: +// return ""; +// } +// } +} diff --git a/src/tethys/DocumentInfo.java b/src/tethys/DocumentInfo.java new file mode 100644 index 00000000..7ad2d750 --- /dev/null +++ b/src/tethys/DocumentInfo.java @@ -0,0 +1,49 @@ +package tethys; + +/** + * Basic information about a document that can be used to + * make document lists. + * @author dg50 + * + */ +public class DocumentInfo implements Comparable { + + private Collection collection; + private String documentName; + private String documentId; + + /** + * @param collection + * @param documentName + * @param documentId + */ + public DocumentInfo(Collection collection, String documentName, String documentId) { + this.collection = collection; + this.documentName = documentName; + this.documentId = documentId; + } + @Override + public int compareTo(DocumentInfo o) { + return this.documentName.compareTo(o.documentName); + } + /** + * @return the collection + */ + public Collection getCollection() { + return collection; + } + /** + * @return the documentName + */ + public String getDocumentName() { + return documentName; + } + /** + * @return the documentId + */ + public String getDocumentId() { + return documentId; + } + + +} diff --git a/src/tethys/DocumentNilusObject.java b/src/tethys/DocumentNilusObject.java new file mode 100644 index 00000000..c6b5a402 --- /dev/null +++ b/src/tethys/DocumentNilusObject.java @@ -0,0 +1,32 @@ +package tethys; + +/** + * information about a document AND the nilus object to go with it. + * @author dg50 + * + * @param + */ +public class DocumentNilusObject extends DocumentInfo { + + private T nilusObject; + + public DocumentNilusObject(Collection collection, String documentName, String documentId, T nilusObject) { + super(collection, documentName, documentId); + this.nilusObject = nilusObject; + } + + /** + * @return the nilusObject + */ + public T getNilusObject() { + return nilusObject; + } + + /** + * @param nilusObject the nilusObject to set + */ + public void setNilusObject(T nilusObject) { + this.nilusObject = nilusObject; + } + +} diff --git a/src/tethys/TethysControl.java b/src/tethys/TethysControl.java new file mode 100644 index 00000000..83e445b7 --- /dev/null +++ b/src/tethys/TethysControl.java @@ -0,0 +1,722 @@ +package tethys; + +import java.awt.Desktop; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; + +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import javax.swing.Timer; + +import PamController.PamControlledUnit; +import PamController.PamControlledUnitSettings; +import PamController.PamController; +import PamController.PamControllerInterface; +import PamController.PamFolders; +import PamController.PamSettingManager; +import PamController.PamSettings; +import PamUtils.PamFileChooser; +import PamUtils.PamFileFilter; +import PamView.PamTabPanel; +import PamView.dialog.warn.WarnOnce; +import PamguardMVC.PamDataBlock; +import metadata.MetaDataContol; +import metadata.PamguardMetaData; +import nilus.Deployment; +import tethys.TethysState.StateType; +import tethys.calibration.CalibrationHandler; +import tethys.dbxml.DBXMLConnect; +import tethys.dbxml.DBXMLQueries; +import tethys.dbxml.ServerStatus; +import tethys.dbxml.TethysException; +import tethys.dbxml.TethysQueryException; +import tethys.deployment.DeploymentHandler; +import tethys.detection.DetectionsHandler; +import tethys.niluswraps.PDeployment; +import tethys.output.DatablockSynchInfo; +import tethys.output.TethysExportParams; +import tethys.species.ITISFunctions; +import tethys.species.SpeciesMapManager; +import tethys.swing.ProjectDeploymentsDialog; +import tethys.swing.TethysTabPanel; +import tethys.swing.XMLStringView; +import tethys.swing.documents.TethysDocumentsFrame; + +/** + * Quick play with a simple system for outputting data to Tethys. At it's start + * this is simply going to offer a dialog and have a few functions which show how + * to access data within PAMGuard. + * @author dg50 + * + */ +public class TethysControl extends PamControlledUnit implements PamSettings, TethysStateObserver { + + public static final String unitType = "Tethys Interface"; + public static String defaultName = "Tethys"; + public static String xmlNameSpace = "http://tethys.sdsu.edu/schema/1.0"; + + private TethysExportParams tethysExportParams = new TethysExportParams(); + + private DBXMLConnect dbxmlConnect; + + private TethysTabPanel tethysTabPanel; + + private DBXMLQueries dbxmlQueries; + + private ArrayList stateObservers; + + private Timer serverCheckTimer; + + private ServerStatus lastServerStatus; + + private ArrayList dataBlockSynchInfos; + + private DeploymentHandler deploymentHandler; + private DetectionsHandler detectionsHandler; + private CalibrationHandler calibrationHandler; + + private ITISFunctions itisFunctions; + + public TethysControl(String unitName) { + super(unitType, unitName); + stateObservers = new ArrayList(); + dbxmlConnect = new DBXMLConnect(this); + dbxmlQueries = new DBXMLQueries(this, dbxmlConnect); + deploymentHandler = new DeploymentHandler(this); + detectionsHandler = new DetectionsHandler(this); + calibrationHandler = new CalibrationHandler(this); + + serverCheckTimer = new Timer(10000, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + checkServer(); + } + }); + serverCheckTimer.setInitialDelay(0); + PamSettingManager.getInstance().registerSettings(this); + addStateObserver(this); + + if (PamController.getInstance().isInitializationComplete()) { + // must be adding module later on ... + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + initializationStuff(); + } + }); + } + } + + /** + * Get DBXML Connector. This class contains all the functions that are needed + * to talk to the database. + * @return DBXML functions. + */ + public DBXMLConnect getDbxmlConnect() { + return dbxmlConnect; + } + @Override + public JMenuItem createDetectionMenu(Frame parentFrame) { + return createTethysMenu(parentFrame); + } + + @Override + public JMenuItem createFileMenu(JFrame parentFrame) { + // TODO Auto-generated method stub + return super.createFileMenu(parentFrame); + } + + /** + * Make a menu. Can go either in File or Settings. TBD. + * @param parentFrame + * @return + */ + public JMenuItem createTethysMenu(Frame parentFrame) { + JMenu tethysMenu = new JMenu("Tethys"); +// JMenuItem tethysExport = new JMenuItem("Export ..."); +// tethysMenu.add(tethysExport); +// tethysExport.addActionListener(new ActionListener() { +// @Override +// public void actionPerformed(ActionEvent e) { +// tethysExport(parentFrame); +// } +// }); + JMenuItem menuItem; + menuItem = new JMenuItem("Open client in browser"); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + openTethysClient(); + } + }); + + tethysMenu.add(menuItem); + menuItem = new JMenuItem("Open temp document folder"); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + openTempDocuments(); + } + }); + tethysMenu.add(menuItem); + + + JMenuItem collections = new JMenu("Collections"); + Collection[] mainCollections = Collection.mainList(); + for (int i = 0; i < mainCollections.length; i++) { + Collection col = mainCollections[i]; + menuItem = new JMenuItem("Open " + col.collectionName() + " collection in browser"); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + openTethysCollection(col); + } + }); + collections.add(menuItem); + } + + tethysMenu.add(collections); + tethysMenu.addSeparator(); + JMenuItem showDeps = new JMenuItem("Show project deployments"); + showDeps.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showProjectDeploymentsDialog(); + } + }); + tethysMenu.add(showDeps); + + JMenuItem cals = new JMenuItem("Export calibrations"); + cals.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + calibrationHandler.exportAllCalibrations(); + } + }); + tethysMenu.add(cals); + + tethysMenu.addSeparator(); + JMenuItem mapItem = new JMenuItem("Export species maps ..."); + mapItem.setToolTipText("Export all species maps (PAMGuard codes to ITIS codes to file for import into other configurations"); + mapItem.addActionListener(SpeciesMapManager.getInstance().getExportAction(parentFrame)); + tethysMenu.add(mapItem); + + mapItem = new JMenuItem("Import species maps ..."); + mapItem.setToolTipText("Import species maps (PAMGuard codes to ITIS codes to file for import into other configurations"); + mapItem.addActionListener(SpeciesMapManager.getInstance().getImportAction(parentFrame)); + tethysMenu.add(mapItem); + + return tethysMenu; + } + + protected void openTempDocuments() { + File tempFolder = dbxmlConnect.checkTempFolder(); + if (tempFolder == null) { + WarnOnce.showWarning("Tethys Error", "Unable to obtain a temporary folder name", WarnOnce.WARNING_MESSAGE); + return; + } + try { +// String cmd = "explorer.exe /select," + tempFolder.getAbsolutePath() + File.separator; +// Runtime.getRuntime().exec(cmd); + Desktop.getDesktop().open(tempFolder); + } + catch(Exception e) { + e.printStackTrace(); + } + } + + public void showProjectDeploymentsDialog() { + ProjectDeploymentsDialog.showDialog(getGuiFrame(), this); + } + + public ArrayList getExportableDataBlocks() { + ArrayList sets = new ArrayList<>(); + ArrayList allDataBlocks = PamController.getInstance().getDataBlocks(); + for (PamDataBlock aDataBlock : allDataBlocks) { + if (aDataBlock.getTethysDataProvider(this) != null) { + sets.add(aDataBlock); + } + } + return sets; + } + + /** + * Get the synchronisation info for all datablocks. + * This list should be static, but check it in case something has been + * added or removed. + * @return + */ + public ArrayList getSynchronisationInfos() { + if (dataBlockSynchInfos == null) { + dataBlockSynchInfos = new ArrayList<>(); + } + ArrayList dataBlocks = getExportableDataBlocks(); + // check all datablocks are in there ... + for (PamDataBlock aBlock : dataBlocks) { + if (findDatablockSynchInfo(aBlock) == null) { + dataBlockSynchInfos.add(new DatablockSynchInfo(this, aBlock)); + } + } + // and remove any which are no longer there. + for (DatablockSynchInfo synchInfo : dataBlockSynchInfos) { + if (!dataBlocks.contains(synchInfo.getDataBlock())) { + dataBlockSynchInfos.remove(synchInfo); + } + } + + return dataBlockSynchInfos; + } + + public DatablockSynchInfo findDatablockSynchInfo(PamDataBlock dataBlock) { + if (dataBlockSynchInfos == null) { + return null; + } + for (DatablockSynchInfo synchInfo : dataBlockSynchInfos) { + if (synchInfo.getDataBlock() == dataBlock) { + return synchInfo; + } + } + return null; + } + + /** + * open client in the default web browser + */ + public void openTethysClient() { +// String urlString = tethysExportParams.getFullServerName() + "/Client"; +// System.out.println("Opening url " + urlString); +// URL url = null; +// try { +// url = new URL(urlString); +// } catch (MalformedURLException e) { +// e.printStackTrace(); +// } +// if (url == null) { +// return; +// } +// try { +// Desktop.getDesktop().browse(url.toURI()); +// } catch (IOException e) { +// e.printStackTrace(); +// } catch (URISyntaxException e) { +// e.printStackTrace(); +// } + openCollectionInBrowser("Client"); + } + /** + * open client in the default web browser + */ + public void openTethysCollection(Collection collection) { + if (collection == null) { + return; + } + if (getTethysExportParams().listDocsInPamguard) { + openCollectionInPAMGuard(collection); + } + else { + openCollectionInBrowser(collection.collectionName()); + } + } + public void openCollectionInPAMGuard(Collection collection) { + TethysDocumentsFrame.showTable(getGuiFrame(), this, collection); + } + + public void openCollectionInBrowser(String collectionName) { + String urlString = tethysExportParams.getFullServerName() + "/" + collectionName; +// System.out.println("Opening url " + urlString); + URL url = null; + try { + url = new URL(urlString); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + if (url == null) { + return; + } + try { + Desktop.getDesktop().browse(url.toURI()); + } catch (IOException e) { + e.printStackTrace(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + } + + @Override + public PamTabPanel getTabPanel() { + if (tethysTabPanel == null) { + tethysTabPanel = new TethysTabPanel(this); + } + return tethysTabPanel; + } + + /** + * @return the tethysExportParams + */ + public TethysExportParams getTethysExportParams() { + return tethysExportParams; + } + +// /** +// * We'll probably want to +// * @param parentFrame +// */ +// protected void tethysExport(JFrame parentFrame) { +// TethysExportParams newExportParams = TethysExportDialog.showDialog(parentFrame, this); +// if (newExportParams != null) { +// // dialog returns null if cancel was pressed. +// tethysExportParams = newExportParams; +// exportTethysData(tethysExportParams); +// } +// } +// +// /** +// * We'll arrive here if the dialog has been opened and we want to export Tethys data. +// * @param tethysExportParams2 +// */ +// private void exportTethysData(TethysExportParams tethysExportParams) { +// TethysExporter tethysExporter = new TethysExporter(this, tethysExportParams); +// tethysExporter.doExport(); +// +// sendStateUpdate(new TethysState(StateType.TRANSFERDATA)); +// countProjectDetections(); +// sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION)); +// } + + /** + * Get global deployment data. This is a bit of a mess, trying to use a separate module + * so that the rest of PAMGuard can use it, but creating the + * @return + */ + public Deployment getGlobalDeplopymentData() { + + MetaDataContol metaControl = MetaDataContol.getMetaDataControl(); + PamguardMetaData metaData = metaControl.getMetaData(); + return metaData.getDeployment(); +// Deployment deploymentData = metaControl != null ? metaData.getDeployment() : getTethysProjectData(); +// +//// deploymentData.setProject("thisIsAProject"); +////// deploymentData.setPlatform("Yay a platform"); +//// deploymentData.setCruise("cruisey"); +//// deploymentData.setDeploymentId(142536); +////// deploymentData.setInstrumentId("super instrument"); +//// deploymentData.setSite("in the ocean somewhere"); +//// deploymentData.setRegion("ocean water"); +////// deploymentData.setInstrumentType("sensor of sorts"); +// +// return deploymentData; + } + + /** + * Add a new state observer. + * @param stateObserver + */ + public void addStateObserver(TethysStateObserver stateObserver) { + stateObservers.add(stateObserver); + } + + /** + * Remove a state observer. + * @param stateObserver + * @return true if it existed. + */ + public boolean removeStateObserver(TethysStateObserver stateObserver) { + return stateObservers.remove(stateObserver); + } + + /** + * Send state updates around to all state observers. + * @param tethysState + */ + public void sendStateUpdate(TethysState tethysState) { + for (TethysStateObserver stateObserver : this.stateObservers) { + stateObserver.updateState(tethysState); + } + } + /** + * A name for any deta selectors. + * @return + */ + public String getDataSelectName() { + return getUnitName(); + } + + public DBXMLQueries getDbxmlQueries() { + return dbxmlQueries; + } + + @Override + public void notifyModelChanged(int changeType) { + super.notifyModelChanged(changeType); + switch (changeType) { + case PamControllerInterface.INITIALIZE_LOADDATA: +// case PamControllerInterface.INITIALIZATION_COMPLETE: + initializationStuff(); + break; + } + } + + /** + * Stuff to do on initial load (initialization complete or addition of + * a Tethys module after initialisation). + */ + private void initializationStuff() { + deploymentHandler.createPamguardOverview(); + serverCheckTimer.start(); + sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION)); + } + + /** + * Check the server. This will send around a notification if the state + * has changed since the last call to this function, so it's unlikely you'll + * need to use the return value + * @return server status. + */ + public ServerStatus checkServer() { + ServerStatus serverState = dbxmlConnect.pingServer(); + if (lastServerStatus == null || lastServerStatus.ok != serverState.ok) { + lastServerStatus = serverState; // set before sending notification! + sendStateUpdate(new TethysState(StateType.UPDATESERVER)); + } +// lastServerStatus = serverState; + return serverState; + } + + @Override + public Serializable getSettingsReference() { + return tethysExportParams; + } + + @Override + public long getSettingsVersion() { + return TethysExportParams.serialVersionUID; + } + + @Override + public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { + tethysExportParams = (TethysExportParams) pamControlledUnitSettings.getSettings(); + return true; + } + + @Override + public void updateState(TethysState tethysState) { + switch (tethysState.stateType) { + case NEWPROJECTSELECTION: + case EXPORTRDATA: + case DELETEDATA: + countProjectDetections(); + break; + } + } + + private void countProjectDetections() { + if (dataBlockSynchInfos == null) { + return; + } + Deployment deplData = getGlobalDeplopymentData(); + String[] dataPrefixes = new String[dataBlockSynchInfos.size()]; + int i = 0; + ArrayList matchedDeployments = deploymentHandler.getMatchedDeployments(); + for (DatablockSynchInfo synchInfo : dataBlockSynchInfos) { +// dataPrefixes[i] = DetectionsHandler.getDetectionsDocIdPrefix(deplData.getProject(), synchInfo.getDataBlock()); + int detectionCount = 0; + int documentCount = 0; + for (PDeployment pDepl : matchedDeployments) { + detectionCount += dbxmlQueries.countData(synchInfo.getDataBlock(), pDepl.deployment.getId()); + ArrayList detectionsNames = getDbxmlQueries().getDetectionsDocuments(synchInfo.getDataBlock(), pDepl.deployment.getId()); + if (detectionsNames != null) { + documentCount += detectionsNames.size(); + } + } + synchInfo.setDataCount(detectionCount); + synchInfo.setDetectionDocumentCount(documentCount); + + i++; + } +// int[] counts = dbxmlQueries.countDataForProject(deplData.getProject(), dataPrefixes); +// if (counts != null) { +// for ( i = 0; i < counts.length; i++ ) { +// dataBlockSynchInfos.get(i).setDataCount(counts[i]); +// } +// } + } + + /** + * One stop place to get Deployment information. Will provide + * both information on record periods in PAMGuard and also Deployment docs in Tethys. + * @return set of functions for handling deployments. + */ + public DeploymentHandler getDeploymentHandler() { + return deploymentHandler; + } + + public DetectionsHandler getDetectionsHandler() { + return detectionsHandler; + } + + public void showException(TethysException tethysException) { + String title = tethysException.getMessage(); + StackTraceElement[] stack = tethysException.getStackTrace(); + String msg = ""; + if (stack != null) { + msg = "Caused in"; + for (int i = 0; i < Math.min(stack.length, 3); i++) { + msg += "
" + stack[i].getClassName() + "." + stack[i].getMethodName(); + } + } + if (tethysException instanceof TethysQueryException) { + TethysQueryException tqe = (TethysQueryException) tethysException; +// msg += tqe. + } + + String xml = tethysException.getXmlError(); + if (xml != null) { + /** + * html can't handle the < and > in xml without getting very confused + * but it seems to work fine if they are replaced with their html codes. + */ + xml = xml.replace("<", "<"); + xml = xml.replace(">", ">"); + xml = xml.replace("\n", "
"); + msg += "

"+xml+"
"; + } + WarnOnce.showWarning(title, msg, WarnOnce.WARNING_MESSAGE); + } + + public void displayDocument(DocumentInfo docInfo) { + String collectionName = docInfo.getCollection().collectionName(); + String docId = docInfo.getDocumentName(); + displayDocument(collectionName, docId); + } + /** + * Load a document from the database and display it in a popup window + * @param collection + * @param documentId + */ + public void displayDocument(String collection, String documentId) { + String doc = getDbxmlQueries().getDocument(collection, documentId); + if (doc == null | doc.length() == 0) { + doc = String.format("Unable to retrieve document %s/%s from database\n", collection, documentId); + + } + XMLStringView.showDialog(getGuiFrame(), collection, documentId, doc); + } + + /** + * Load a document from the database and write to a file selected by the user + * @param collection + * @param documentId + */ + public void exportDocument(String collection, String documentId) { + String doc = getDbxmlQueries().getDocument(collection, documentId); + if (doc == null | doc.length() == 0) { + String msg = String.format("Unable to retrieve document %s/%s from database\n", collection, documentId); + WarnOnce.showWarning("Error", msg, WarnOnce.WARNING_MESSAGE); + } + + PamFileFilter fileFilter = new PamFileFilter("XML documents", ".xml"); +// fileFilter + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileFilter(fileFilter); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + // make a default name based on the document id and the dataset directory. + String defFolder = PamFolders.getDefaultProjectFolder(); + File defFile = null; + if (defFolder != null) { + defFolder = String.format("%s%s%s_%s.xml", defFolder,File.separator,collection,documentId); + defFile = new File(defFolder); + fileChooser.setAcceptAllFileFilterUsed(true); + fileChooser.setSelectedFile(defFile); + +// fileChooser.setSelectedFile(new File(String.format("%s.xml", documentId))); +// fileChooser.set + } + int state = fileChooser.showSaveDialog(getGuiFrame()); + if (state != JFileChooser.APPROVE_OPTION) return; + File newFile = fileChooser.getSelectedFile(); + if (newFile == null) return; + newFile = PamFileFilter.checkFileEnd(newFile, "xml", true); + if (newFile == null) { + return; + } + if (newFile.exists()) { + int ans2 = WarnOnce.showWarning(newFile.getAbsolutePath(), + "The file already exists. Do you want to overwrite it ?", WarnOnce.OK_CANCEL_OPTION); + if (ans2 == WarnOnce.CANCEL_OPTION) { + return; + } + } + try { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile)); + bos.write(doc.getBytes()); + bos.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * @return the itisFunctions + */ + public ITISFunctions getItisFunctions() { + if (itisFunctions == null) { + itisFunctions = new ITISFunctions(this); + } + return itisFunctions; + } + + /** + * Called when a detections document has been exported. + * @param dataBlock + */ + public void exportedDetections(PamDataBlock dataBlock) { + sendStateUpdate(new TethysState(StateType.EXPORTRDATA, Collection.Detections)); + countProjectDetections(); + sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION, Collection.Detections)); + } + + /** + * @return the calibrationHandler + */ + public CalibrationHandler getCalibrationHandler() { + return calibrationHandler; + } + + /** + * @return the lastServerStatus + */ + public ServerStatus getLastServerStatus() { + return lastServerStatus; + } + + /** + * Quick way for any controls to see that the server is probably OK + * without actually pinging it. + * @return true if last ping of server was OK + */ + public boolean isServerOk() { + if (lastServerStatus == null) { + return false; + } + return lastServerStatus.ok; + } + +} diff --git a/src/tethys/TethysLocationFuncs.java b/src/tethys/TethysLocationFuncs.java new file mode 100644 index 00000000..dbfa68d8 --- /dev/null +++ b/src/tethys/TethysLocationFuncs.java @@ -0,0 +1,83 @@ +package tethys; + +import Array.ArrayManager; +import Array.HydrophoneLocator; +import Array.PamArray; +import Array.Streamer; +import GPS.GPSControl; +import GPS.GpsDataUnit; +import PamUtils.LatLong; +import PamUtils.PamUtils; +import generalDatabase.DBControlUnit; +import generalDatabase.PamConnection; +import nilus.Deployment; +import nilus.DeploymentRecoveryDetails; + +/** + * Function(s) to get location information for Tethys in the required format. + * @author dg50 + * + */ +public class TethysLocationFuncs { + + + /** + * Get everything we need for a deployment document including the track # + * and the deployment / recovery information. Basically this means we + * have to load the GPS data, then potentially filter it. Slight risk this + * may all be too much for memory, but give it a go by loading GPS data for + * the deployment times. + * @param deployment + */ + public static void getTrackAndPositionData(Deployment deployment) { + long start = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp()); + long end = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getAudioTimeStamp()); + /* + * Need to load data for GPS, Hydrophones and Streamers datablocks for this time period. Can then use + * the snapshot geomentry classes to do the rest from the array manager ? + */ + boolean ok = true; + ok &= addPositionData(deployment.getDeploymentDetails()); + ok &= addPositionData(deployment.getRecoveryDetails()); + + } + + /** + * Add position data to DeploymentRecoveryDetails. + * @param drd + * @return + */ + public static boolean addPositionData(DeploymentRecoveryDetails drd) { + long timeMillis = TethysTimeFuncs.millisFromGregorianXML(drd.getAudioTimeStamp()); + LatLong pos = getLatLongData(timeMillis); + if (pos == null) { + return false; + } + drd.setLongitude(PamUtils.constrainedAngle(pos.getLongitude(), 360)); + drd.setLatitude(pos.getLatitude()); + drd.setElevationInstrumentM(pos.getHeight()); + drd.setDepthInstrumentM(-pos.getHeight()); + return true; + } + + public static LatLong getLatLongData(long timeMillis) { + // check the array time. + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + Streamer aStreamer = array.getStreamer(0); + GPSControl gpsControl = GPSControl.getGpsControl(); + PamConnection con = DBControlUnit.findConnection(); + if (gpsControl != null) { +// check GPS data are loaded for times around this. + GpsDataUnit gpsData = (GpsDataUnit) gpsControl.getGpsDataBlock().getLogging().findClosestDataPoint(con, timeMillis); + if (gpsData != null) { + return gpsData.getGpsData(); + } + } + HydrophoneLocator hydrophoneLocator = aStreamer.getHydrophoneLocator(); + if (hydrophoneLocator == null) { + return null; + } + return hydrophoneLocator.getStreamerLatLong(timeMillis); + } + +} diff --git a/src/tethys/TethysMenuActions.java b/src/tethys/TethysMenuActions.java new file mode 100644 index 00000000..625096a9 --- /dev/null +++ b/src/tethys/TethysMenuActions.java @@ -0,0 +1,70 @@ +package tethys; + + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import tethys.dbxml.TethysException; +import tethys.niluswraps.PDeployment; + +/* + * Some standard meny dirven functions which we may want to call from + * a few different places. + */ +public class TethysMenuActions { + + private TethysControl tethysControl; + + public TethysMenuActions(TethysControl tethysControl) { + super(); + this.tethysControl = tethysControl; + } + + public void deploymentMouseActions(MouseEvent e, PDeployment pDeployment) { + ArrayList detDocNames = tethysControl.getDbxmlQueries().getDetectionsDocuments(pDeployment.deployment.getId()); +// System.out.println("Detections for deployment " + pDeployment.deployment.getId()); +// for (String detName : detDocNames) { +// System.out.println(detName); +// } + JPopupMenu menu = new JPopupMenu(); + if (detDocNames.size() == 0) { + JMenuItem menuItem = new JMenuItem("Delete deployment " + pDeployment.deployment.getId()); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + deleteDeployment(pDeployment); + } catch (TethysException e1) { + tethysControl.showException(e1); + } + } + }); + menu.add(menuItem); + } + else { + String str = String.format("Delete deployment %s and %d Detections documents", pDeployment.deployment.getId(), detDocNames.size()); + JMenuItem menuItem = new JMenuItem(str); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + deleteDeployment(pDeployment); + } catch (TethysException e1) { + tethysControl.showException(e1); + } + } + }); + menu.add(menuItem); + } + menu.show(e.getComponent(), e.getX(), e.getY()); + } + + protected void deleteDeployment(PDeployment pDeployment) throws TethysException { + tethysControl.getDbxmlConnect().deleteDeployment(pDeployment.deployment.getId()); + } +} diff --git a/src/tethys/TethysState.java b/src/tethys/TethysState.java new file mode 100644 index 00000000..ea2f2746 --- /dev/null +++ b/src/tethys/TethysState.java @@ -0,0 +1,54 @@ +package tethys; + +/** + * Basis for a message system which will get passed around whenever something happens in + * Tethys, whether it be a new connection, progress during data output, etc. + * @author dg50 + * + */ +public class TethysState { + + public enum StateType {UPDATESERVER, // Server connection or status has changed + EXPORTRDATA, // data have been transferred from PAMGuard to Tethys + NEWPROJECTSELECTION, // a new Tethys project has been selected in the GUI + NEWPAMGUARDSELECTION, // new PAMGuard data are available (called once on first load) + UPDATEMETADATA, // META Data being prepared for output have changed (so may be able to enable output!) + EXPORTING, // currently exporting data. may be a while ... + DELETEDATA // data were deleted + } + + public StateType stateType; + + public Collection collection; + + public TethysState(StateType stateType) { + super(); + this.stateType = stateType; + collection = Collection.OTHER; + } + + public TethysState(StateType stateType, Collection collection) { + this.stateType = stateType; + this.collection = collection; + if (this.collection == null) { + this.collection = Collection.OTHER; + } + } + + /** + * @return the collection associated with this notification. Note that there is + * an OTHER category in Collections which is used for server / project updates, making + * it easier to switch on the collection type when notifications are received. + */ + public Collection getCollection() { + return collection; + } + + /** + * @return the stateType + */ + public StateType getStateType() { + return stateType; + } + +} diff --git a/src/tethys/TethysStateObserver.java b/src/tethys/TethysStateObserver.java new file mode 100644 index 00000000..33a9de5c --- /dev/null +++ b/src/tethys/TethysStateObserver.java @@ -0,0 +1,13 @@ +package tethys; + +public interface TethysStateObserver { + + /** + * Receive state updates when Tethys has done something (made a connection, moved some data, etc.)
+ * Note that this is for RECEIVING state updates, not for sending them. To avoid infinite notifications + * loops, use tethysControl.sendStateUpdate(TethysState) to send out state notifications. + * @param tethysState + */ + public void updateState(TethysState tethysState); + +} diff --git a/src/tethys/TethysTimeFuncs.java b/src/tethys/TethysTimeFuncs.java new file mode 100644 index 00000000..70d11704 --- /dev/null +++ b/src/tethys/TethysTimeFuncs.java @@ -0,0 +1,90 @@ +package tethys; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + +import PamUtils.PamCalendar; + +public class TethysTimeFuncs { + + private static TimeZone timeZone = TimeZone.getTimeZone("UTC"); + + /* + * Copied from http://www.java2s.com/Code/Java/Development-Class/ConvertsagiventimeinmillisecondsintoaXMLGregorianCalendarobject.htm + */ + public static XMLGregorianCalendar xmlGregCalFromMillis(long millis) { + try { + final GregorianCalendar calendar = new GregorianCalendar(); + calendar.setTimeZone(timeZone); + calendar.setTimeInMillis(millis); + return DatatypeFactory.newInstance().newXMLGregorianCalendar( + calendar); + } + catch (final DatatypeConfigurationException ex) { + System.out.println("Unable to convert date '%s' to an XMLGregorianCalendar object"); + return null; + } + } + + /** + * Convert a Gregorian calendar value back to milliseconds. + * @param xmlGregorian + * @return + */ + public static Long millisFromGregorianXML(XMLGregorianCalendar xmlGregorian) { + if (xmlGregorian == null) { + return null; + } + GregorianCalendar gc2 = xmlGregorian.toGregorianCalendar(); + gc2.setTimeZone(timeZone); + return gc2.getTimeInMillis(); + } + + /** + * Make a Gregorian calendar object from a returned XML string. + * @param gregorianString + * @return + */ + public static XMLGregorianCalendar fromGregorianXML(String gregorianString) { + // typical string is 2018-10-20T00:00:00Z + if (gregorianString == null) { + return null; + } +// GregorianCalendar gCal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + gregorianString = gregorianString.replace("T", " "); + gregorianString = gregorianString.replace("Z", ""); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = null; + try { + date = df.parse(gregorianString); + } catch (ParseException e) { + System.out.printf("Unparsable date string:\"%s\"", gregorianString); + e.printStackTrace(); + return null; + } + return xmlGregCalFromMillis(date.getTime()); +// gCal.setTimeInMillis(date.getTime()); +//// gCal.se +// return gCal; + } + + public static String formatGregorianTime(XMLGregorianCalendar gregCal) { + if (gregCal == null) { + return null; + } + Long millis = millisFromGregorianXML(gregCal); + if (millis == null) { + return gregCal.toString(); + } + return PamCalendar.formatDBDateTime(millis); + } +} diff --git a/src/tethys/calibration/CalibrationHandler.java b/src/tethys/calibration/CalibrationHandler.java new file mode 100644 index 00000000..37dc186e --- /dev/null +++ b/src/tethys/calibration/CalibrationHandler.java @@ -0,0 +1,573 @@ +package tethys.calibration; + +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import javax.xml.bind.JAXBException; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; + +import Acquisition.AcquisitionControl; +import Acquisition.AcquisitionParameters; +import Acquisition.AcquisitionProcess; +import Array.ArrayManager; +import Array.Hydrophone; +import Array.PamArray; +import Array.Preamplifier; +import PamController.PamController; +import PamController.soundMedium.GlobalMedium; +import PamController.soundMedium.GlobalMedium.SoundMedium; +import PamUtils.PamCalendar; +import PamView.dialog.warn.WarnOnce; +import dbxml.Queries; +import PamController.soundMedium.GlobalMediumManager; +import nilus.AlgorithmType.Parameters; +import nilus.Calibration; +import nilus.Calibration.FrequencyResponse; +import nilus.Calibration.QualityAssurance; +import nilus.Helper; +import nilus.MetadataInfo; +import nilus.QualityValueBasic; +import nilus.ResponsibleParty; +import tethys.Collection; +import tethys.DocumentInfo; +import tethys.DocumentNilusObject; +import tethys.TethysControl; +import tethys.TethysState; +import tethys.TethysStateObserver; +import tethys.TethysTimeFuncs; +import tethys.calibration.swing.CalibrationsExportWizard; +import tethys.dbxml.DBXMLConnect; +import tethys.dbxml.TethysException; +import tethys.niluswraps.NilusChecker; +import tethys.niluswraps.NilusSettingsWrapper; +import tethys.niluswraps.NilusUnpacker; +import tethys.pamdata.AutoTethysProvider; +import tethys.reporter.TethysReporter; + +public class CalibrationHandler implements TethysStateObserver { + + private TethysControl tethysControl; + + private ArrayList> calibrationsList; + + public static final String[] updateOptions = {"as-needed", "unplanned", "yearly"}; + + public static final String[] calibrationMethods = {"Reference hydrophone", "Manufacturers specification", "Piston phone", "Other calibrated source", "Unknown"}; + + public static final String[] qaTypes = {"unverified", "valid", "invalid"}; + + private Helper nilusHelper; + /** + * @param tethysControl + */ + public CalibrationHandler(TethysControl tethysControl) { + this.tethysControl = tethysControl; + calibrationsList = new ArrayList(); + tethysControl.addStateObserver(this); try { + nilusHelper = new Helper(); + } catch (JAXBException e) { + e.printStackTrace(); + } + } + + @Override + public void updateState(TethysState tethysState) { + switch (tethysState.stateType) { + case EXPORTING: + break; + case NEWPAMGUARDSELECTION: + case NEWPROJECTSELECTION: + case EXPORTRDATA: + case DELETEDATA: + case UPDATEMETADATA: + case UPDATESERVER: + if (isWantedState(tethysState)) { + updateDocumentsList(); + } + default: + break; + + } + } + + /** + * Is it a state notification we want to respond to + * @param state + * @return true if worth it. + */ + protected boolean isWantedState(TethysState state) { + if (state.collection == null) { + return true; + } + switch (state.collection) { + case OTHER: + case Calibrations: + return true; + } + return false; + } + + /** + * Update the list of documents associated with the selected instrument. + */ + private void updateDocumentsList() { + + calibrationsList.clear(); + + ArrayList docsList = getArrayCalibrations(); + // now immediately read the calibrations in again. + if (docsList == null) { + return; + } + NilusUnpacker unpacker = new NilusUnpacker(); + for (DocumentInfo aDoc : docsList) { + Queries queries = tethysControl.getDbxmlConnect().getTethysQueries(); + String result = null; + Calibration calObj = null; + try { + result = queries.getDocument(Collection.Calibrations.toString(), aDoc.getDocumentName()); + if (result != null) { + // create a document and convert it into a Nilus calibrations document. + Document doc = tethysControl.getDbxmlQueries().convertStringToXMLDocument(result); + if (doc == null) { + System.out.println("Unable to convert Calibration result to Document\n " + result); + continue; + } + calObj = (Calibration) unpacker.unpackDocument(doc, Calibration.class); + if (calObj == null) { + System.out.println("Unable to convert Calibration document to nilus object\n " + result); + continue; + } + } + long t = System.currentTimeMillis(); + try { + XMLGregorianCalendar gt = calObj.getMetadataInfo().getDate(); + if (gt != null) { + t = TethysTimeFuncs.millisFromGregorianXML(gt); + } + } + catch (Exception e) { + + } + DocumentNilusObject calDataUnit = new DocumentNilusObject(Collection.Calibrations, aDoc.getDocumentName(), calObj.getId(), calObj); + calibrationsList.add(calDataUnit); +// System.out.println(result); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + public int exportAllCalibrations() { + + Calibration sampleCal = new Calibration(); + try { + Helper.createRequiredElements(sampleCal); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e1) { + e1.printStackTrace(); + } + sampleCal = CalibrationsExportWizard.showWizard(tethysControl.getGuiFrame(), sampleCal); + if (sampleCal == null) { + return 0; + } + + NilusSettingsWrapper wrappedSample = new NilusSettingsWrapper(); + wrappedSample.setNilusObject(sampleCal); + + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + int nPhone = array.getHydrophoneCount(); + DBXMLConnect dbxml = tethysControl.getDbxmlConnect(); + int nExport = 0; + boolean overwrite = false; + boolean exists; + TethysReporter.getTethysReporter().clear(); + for (int i = 0; i < nPhone; i++) { +// String docName = getHydrophoneId(i); + NilusSettingsWrapper clonedWrap = wrappedSample.clone(); + sampleCal = clonedWrap.getNilusObject(Calibration.class); + Calibration calDoc = createCalibrationDocument(i); + if (sampleCal != null) { + calDoc.setMetadataInfo(sampleCal.getMetadataInfo()); + calDoc.setProcess(sampleCal.getProcess()); + calDoc.setQualityAssurance(sampleCal.getQualityAssurance()); + if (NilusChecker.isEmpty(sampleCal.getResponsibleParty()) == false) { + calDoc.setResponsibleParty(sampleCal.getResponsibleParty()); + } + calDoc.setTimeStamp(sampleCal.getTimeStamp()); + } + // check the contact info in the metadata. + // can't so because it's required. +// MetadataInfo metaData = calDoc.getMetadataInfo(); +// if (metaData != null) { +// if (NilusChecker.isEmpty(metaData.getContact())) { +// metaData.setContact(null); +// } +// } + + addParameterDetails(calDoc, i); + // run some checks of completeness of the data + NilusChecker.removeEmptyFields(calDoc); +// ArrayList emptyFields = NilusChecker.checkEmptyFields(calDoc); + + String calDocName = createDocumentName(calDoc, i); + exists = calDocumentExists(calDocName); + if (exists && overwrite == false) { + String msg = String.format("Calibration document %s already exists. Do you want to overwrite it and other documents from this date?", calDocName); + int ans = WarnOnce.showWarning("Calibration Export", msg, WarnOnce.OK_CANCEL_OPTION); + if (ans == WarnOnce.OK_OPTION) { + overwrite = true; + } + else { + return nExport; + } + } + boolean ok = false; + if (exists == true && overwrite == false) { + continue; + } + try { + if (exists) { + ok = dbxml.removeDocument(Collection.Calibrations, calDocName); + } + ok = dbxml.postAndLog(calDoc, calDocName); + } catch (TethysException e) { + e.printStackTrace(); + tethysControl.showException(e); + ok = false; + break; + } + if (ok) { + nExport++; + } + } + tethysControl.sendStateUpdate(new TethysState(TethysState.StateType.EXPORTRDATA, Collection.Calibrations)); + TethysReporter.getTethysReporter().showReport(true); + return nExport; + } + + /** + * Add the separate pamguard parameters to the document which are used + * to make up the overall calibration. + * @param calDoc + * @param i hydrophone number + */ + private void addParameterDetails(Calibration calDoc, int i) { + Parameters params = calDoc.getProcess().getParameters(); + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.unitType); + AcquisitionParameters daqParams = daqControl.getAcquisitionParameters(); + Hydrophone phone = array.getHydrophoneArray().get(i); + try { + nilusHelper.AddAnyElement(params.getAny(), "HydrophoneType", phone.getType()); + nilusHelper.AddAnyElement(params.getAny(), "Sensitivity", String.format("%3.1f", phone.getSensitivity())); + nilusHelper.AddAnyElement(params.getAny(), "PreampGain", String.format("%3.1f", phone.getPreampGain())); + nilusHelper.AddAnyElement(params.getAny(), "ADCp-p", String.format("%3.2fV", daqParams.getVoltsPeak2Peak())); + Preamplifier preamp = daqParams.preamplifier; + if (preamp != null) { + nilusHelper.AddAnyElement(params.getAny(), "ADCAmplifier", String.format("%3.2fdB", preamp.getGain())); + } + } catch (JAXBException e) { + e.printStackTrace(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } + + } + + /** + * Format the data in the dd MMMM yyyy format + * @param timeInMillis time in milliseconds + * @return formatted string. + */ + public static String formatDate(long timeInMillis) { + Calendar c = Calendar.getInstance(); + c.setTimeInMillis(timeInMillis); + c.setTimeZone(PamCalendar.defaultTimeZone); + DateFormat df = new SimpleDateFormat("yyMMdd"); + df.setTimeZone(PamCalendar.defaultTimeZone); + Date d = c.getTime(); + return df.format(d); + } + + + /** + * Get a name for the document, which is a bit like the id within + * the document, but also contain a yymmdd data string. + * @param calDoc + * @param i channel + * @return document name + */ + private String createDocumentName(Calibration calDoc, int iChan) { + long docDate = System.currentTimeMillis(); + XMLGregorianCalendar date = calDoc.getMetadataInfo().getDate(); + if (date != null) { + docDate = TethysTimeFuncs.millisFromGregorianXML(date); + } + String dateStr = formatDate(docDate); + String name = String.format("%s_%s_ch%d", createCalibrationDocumentRoot(), dateStr, iChan); + return name; + } + + /** + * Get a start of name for a calibration document. This will be used in the document name + * with a date and a channel, and the document Id just of the root and the channel. + * @return root string for document names and document id's. + */ + public String createCalibrationDocumentRoot() { + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + if (array == null) { + return null; + } + String root = String.format("%s %s", array.getInstrumentType(), array.getInstrumentId()); + root = root.replace(" ", "_"); + return root; + } + + /** + * Create a calibration document for a single hydrophone channel. + * @param pDeployment deployment, for cross referencing. + * @param channelIndex channel id. One document per channel for a multi hydrophone array. + * @return Calibration document. + */ + public Calibration createCalibrationDocument(int channelIndex) { + AcquisitionControl daqControl = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.unitType); + return createCalibrationDocument(daqControl, channelIndex); + } + + /** + * Create a calibration document for a single hydrophone channel. + * @param pDeployment deployment, for cross referencing. + * @param soundAcquisition Daq information - needed to get the ADC calibration information. + * @param channelIndex channel id. One document per channel for a multi hydrophone array. + * @return Calibration document. + */ + public Calibration createCalibrationDocument(AcquisitionControl soundAcquisition, int channelIndex) { + /** + * Calibrations document id and cross referencing to Deploymnet documents: + * Identifier of instrument, preamplifier, or hydrophone. + * Corresponds to elements in Deployment: + * Deployment/Instrument/Id, + * Deployment/Sensors/Audio/HydrophoneId, + * Deployment/Sensors/Audio[i]/PreampId. + * As instruments may be calibrated multiple times, it is not an error for duplicate Id values to appear. + * It is recommended that the three different types of identifiers (instrument, hydrophone, preamp) be distinct, + * but the Type element may be used to distinguish them if they are not. + */ + + /* + * very remote possibility that DAQ doesn't exist. What to do in this case ? It's also possible that some configurations may + * have to have >1 DAQ's ? + */ + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + if (array == null) { + return null; + } + if (channelIndex < 0 || channelIndex >= array.getHydrophoneCount()) { + return null; + } +// ArrayManager.getArrayManager().get +// hydrophones = array. + Hydrophone hydrophone = array.getHydrophoneArray().get(channelIndex); + double hSens = hydrophone.getSensitivity(); + double preampGain = hydrophone.getPreampGain(); + + GlobalMediumManager mediumManager = PamController.getInstance().getGlobalMediumManager(); + SoundMedium currentMedium = mediumManager.getCurrentMedium(); + double dbRef = GlobalMedium.getdBreference(currentMedium); // probably in Pa, so multiply by 1e6. 20 (air) or 0 (water) + + /** + * The calibration id can be a bit tricky, it will need to be cross referenced from the + * Deployment document, and it is likely that a deployment document will have to reference several + * calibration documents for different channels. + * Make the name from the Array name (new), the array Instrument Id (unique to the array) + * and the channel number. These will then all have to go into the Deployment document in + * the list of audio devices, cross referenced as the SensorId field. + * + */ + + Calibration calibration = new Calibration(); + + try { + Helper.createRequiredElements(calibration); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + String id = getHydrophoneId(channelIndex); +// id = String.format("%d", channelIndex); + calibration.setId(id); + calibration.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis())); +// calibration.setType(GlobalMedium.getRecieverString(currentMedium, false, false)); + calibration.setType("end-to-end"); + calibration.setIntensityReferenceUPa(AutoTethysProvider.roundSignificantFigures(dbRef*1e6,3)); +// String sensRef = GlobalMedium.getdBRefString(currentMedium); + // it doesn't like this since it has a unicode character. Leave it or change the micro to 'u' +// calibration.setSensitivityReference(sensRef); + calibration.setSensitivityDBV(hSens+preampGain); + if (soundAcquisition != null) { + AcquisitionProcess daqProcess = soundAcquisition.getAcquisitionProcess(); + double fullScale = daqProcess.rawAmplitude2dB(1, channelIndex, false); + calibration.setSensitivityDBFS(fullScale); + } + FrequencyResponse frs = calibration.getFrequencyResponse(); + List hz = frs.getHz(); + List db = frs.getDB(); + hz.add(Double.valueOf(0)); + db.add(Double.valueOf(hSens+preampGain)); + + if (NilusChecker.isEmpty(calibration.getResponsibleParty())) { + calibration.setResponsibleParty(null); + } + + MetadataInfo metaInf = calibration.getMetadataInfo(); + if (metaInf == null) { + metaInf = new MetadataInfo(); + calibration.setMetadataInfo(metaInf); + } + metaInf.setDate(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis())); + metaInf.setUpdateFrequency("as-needed"); + ResponsibleParty contact = metaInf.getContact(); + if (contact == null) { + contact = new ResponsibleParty(); + metaInf.setContact(contact); + } + if (NilusChecker.isEmpty(metaInf.getContact())) { + metaInf.setContact(null); + } + if (NilusChecker.isEmpty(metaInf)) { + calibration.setMetadataInfo(null); + } + contact.setIndividualName("Unknown"); + contact.setOrganizationName("unknown"); + + QualityAssurance qa = calibration.getQualityAssurance(); + if (qa == null) { + qa = new QualityAssurance(); + calibration.setQualityAssurance(qa); + } + qa.setQuality(QualityValueBasic.VALID); + qa.setComment("Unknown calibration"); + + + return calibration; + } + + /** + * See if a document already exists. This should only occur if you + * try to export the same document twice with the same calibration date. + * @param documentName + * @return true if a document already exists. + */ + public boolean calDocumentExists(String documentName) { + if (calibrationsList == null) { + return false; + } + for (int i = 0; i < calibrationsList.size(); i++) { + if (calibrationsList.get(i).getDocumentName().equalsIgnoreCase(documentName)) { + return true; + } + } + return false; + } + + /** + * Return if we have at least one document for every channel. + * @return true if all cal documents exist. + */ + public boolean haveAllChannelCalibrations() { + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + int nPhone = array.getHydrophoneCount(); + for (int i = 0; i < nPhone; i++) { + if (haveChannelCalibration(i) == false) { + return false; + } + } + return true; + } + + /** + * Find whether we have a document for this instrument and channel. + * @param iChan + * @return true if we have an appropriate doc. + */ + public boolean haveChannelCalibration(int iChan) { + if (calibrationsList == null) { + return false; + } + String seachPattern = makeChannelNamePart(iChan); + for (int i = 0; i < calibrationsList.size(); i++) { + String docName = calibrationsList.get(i).getDocumentName(); + if (docName.endsWith(seachPattern)) { + return true; + } + } + + return false; + } + + /** + * Get an id based on the instrument identifiers and channel number. + * This is the internal id of the document, not the document name which + * includes an additional date part in the name. + * @param channelIndex + * @return id string - instrument type + instrument id + channel + */ + public String getHydrophoneId(int channelIndex) { + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + if (array == null) { + return null; + } + String id = String.format("%s_%s", createCalibrationDocumentRoot(), makeChannelNamePart(channelIndex)); + id = id.replace(" ", "_"); + return id; + } + + /** + * Make the final part of the document name / id which is the channel number. + * @param channelIndex channel index + * @return string in the form ch%02d (e.g. ch03) + */ + public String makeChannelNamePart(int channelIndex) { + return String.format("ch%02d", channelIndex); + } + + /** + * @return the calibrationDataBlock + */ + public ArrayList> getCalibrationDataList() { + return calibrationsList; + } + + /** + * Make a list of document names associated with this instrument. + * @return list of calibration documents using this instrument, based on the start of the document name. + */ + private ArrayList getArrayCalibrations() { + ArrayList allCals = null; + try { + allCals = tethysControl.getDbxmlQueries().getCollectionDocumentList(Collection.Calibrations); + } + catch (Exception e) { + + } + if (allCals == null) { + return null; + } + String prefix = createCalibrationDocumentRoot(); // find doc names that have that root. + ArrayList theseCals = new ArrayList<>(); + for (DocumentInfo aDoc : allCals) { + if (aDoc.getDocumentName().startsWith(prefix)) { + theseCals.add(aDoc); + } + } + return theseCals; + } +} diff --git a/src/tethys/calibration/swing/CalibrationProcessCard.java b/src/tethys/calibration/swing/CalibrationProcessCard.java new file mode 100644 index 00000000..094d9d5d --- /dev/null +++ b/src/tethys/calibration/swing/CalibrationProcessCard.java @@ -0,0 +1,205 @@ +package tethys.calibration.swing; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; + +import PamView.dialog.PamDialog; +import PamView.dialog.PamGridBagContraints; +import PamView.panel.WestAlignedPanel; +import PamView.wizard.PamWizard; +import nilus.AlgorithmType; +import nilus.AlgorithmType.Parameters; +import nilus.AlgorithmType.SupportSoftware; +import nilus.Calibration; +import nilus.Calibration.QualityAssurance; +import nilus.Helper; +import nilus.QualityValueBasic; +import tethys.calibration.CalibrationHandler; +import tethys.niluswraps.NilusChecker; + +/** + * Calibrations Process card attempts to fill in the + * calibration data for the Quality Assurance and Process fields. + * @author dg50 + * + */ +public class CalibrationProcessCard extends CalibrationsCard { + + private JPanel processPanel; + + private JComboBox calMethod; + + private JTextArea software; + + private JTextField version; + + private JComboBox qaQuality; + + private JTextField qaComment; + + public CalibrationProcessCard(PamWizard pamWizard) { + super(pamWizard, "Calibration Process"); + this.setLayout(new BorderLayout()); + processPanel = new JPanel(new GridBagLayout()); + WestAlignedPanel wp; + this.add(BorderLayout.NORTH, wp = new WestAlignedPanel(processPanel)); + wp.setBorder(new TitledBorder("Calibration Process")); + + GridBagConstraints c = new PamGridBagContraints(); + + calMethod = new JComboBox(); + String[] meths = CalibrationHandler.calibrationMethods; + for (int i = 0; i < meths.length; i++) { + calMethod.addItem(meths[i]); + } + + qaQuality = new JComboBox<>(); + String[] vals = CalibrationHandler.qaTypes; + for (int i = 0; i < vals.length; i++) { + qaQuality.addItem(vals[i]); + } + + software = new JTextArea(5, 25); + software.setLineWrap(true); + software.setWrapStyleWord(true); + software.setToolTipText("Details of calibration method and software used"); + + version = new JTextField(20); + version.setToolTipText("Serial number of calibration device"); + + qaComment = new JTextField(20); + qaComment.setToolTipText("Comment on calibration quality"); + + processPanel.add(new JLabel("Method ", JLabel.RIGHT), c); + c.gridx++; + processPanel.add(calMethod, c); + c.gridx = 0; + c.gridy++; + c.gridwidth = 1; + processPanel.add(new JLabel("Serial number ", JLabel.RIGHT), c); + c.gridx++; + c.gridwidth = 2; + processPanel.add(version, c); + c.gridx = 0; + c.gridy++; + c.gridwidth = 1; + processPanel.add(new JLabel("Quality ", JLabel.RIGHT), c); + c.gridx++; + processPanel.add(qaQuality, c); + c.gridx = 0; + c.gridy++; + processPanel.add(new JLabel("QA Comment ", JLabel.RIGHT), c); + c.gridx++; + c.gridwidth = 2; + processPanel.add(qaComment, c); + + this.add(BorderLayout.CENTER, makeScrollablePanel(software, "Calibration method")); + + } + + private JScrollPane makeScrollablePanel(JTextArea textArea, String title) { + // TODO Auto-generated method stub +// mainPanel.add(new Label(title, JLabel.LEFT)); +// textArea.setMinimumSize(new Dimension(200, 200)); + JScrollPane scrollPane = new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setBorder(new TitledBorder(title)); + scrollPane.setPreferredSize(new Dimension(scrollPane.getPreferredSize().height/2, 0)); + return scrollPane; + } + + + @Override + public boolean getParams(Calibration calibration) { + if (calibration == null) { + return false; + } + AlgorithmType process = calibration.getProcess(); + if (process == null) { + process = new AlgorithmType(); + calibration.setProcess(process); + } + process.setMethod((String) calMethod.getSelectedItem()); + process.setVersion(version.getText()); + String soft = warnNotNull(getPamWizard(), software, "Calibration Method"); + if (soft == null) { + return false; + } + process.setSoftware(soft); + if (software.getText() == null) { + getPamWizard().showWarning("You must specify the calibration method used"); + } + + QualityAssurance qa = calibration.getQualityAssurance(); + if (qa == null) { + qa = new QualityAssurance(); + calibration.setQualityAssurance(qa); + } + String t = warnNotNull(getPamWizard(), qaComment, "QA Comment"); + if (t == null) { + return false; + } + qa.setComment(t); + qa.setQuality(QualityValueBasic.fromValue((String) qaQuality.getSelectedItem())); + + // need to add a few fixed things for this to work... +// List supportSoftware = process.getSupportSoftware(); + Parameters params = process.getParameters(); + if (params == null) { + params = new Parameters(); + process.setParameters(params); +// params.getAny(). + } + try { + Helper.createRequiredElements(params); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + +// if (checkEmptyFields(qa) == false) { +// return false; +// } +// if (checkEmptyFields(process) == false) { +//// return false; +// } + + return true; + } + + + + @Override + public void setParams(Calibration calibration) { + if (calibration == null) { + return; + } + AlgorithmType process = calibration.getProcess(); + if (process != null) { + calMethod.setSelectedItem(process.getMethod()); + version.setText(process.getVersion()); + software.setText(process.getSoftware()); + } + QualityAssurance qa = calibration.getQualityAssurance(); + if (qa != null) { + QualityValueBasic qb = qa.getQuality(); + if (qb != null) { + qaQuality.setSelectedItem(qb.value()); + } + qaComment.setText(qa.getComment()); + } + } +} diff --git a/src/tethys/calibration/swing/CalibrationsCard.java b/src/tethys/calibration/swing/CalibrationsCard.java new file mode 100644 index 00000000..a59482f4 --- /dev/null +++ b/src/tethys/calibration/swing/CalibrationsCard.java @@ -0,0 +1,14 @@ +package tethys.calibration.swing; + +import PamView.wizard.PamWizard; +import PamView.wizard.PamWizardCard; +import nilus.Calibration; +import tethys.swing.TethysWizardCard; + +abstract public class CalibrationsCard extends TethysWizardCard { + + public CalibrationsCard(PamWizard pamWizard, String title) { + super(pamWizard, title); + } + +} diff --git a/src/tethys/calibration/swing/CalibrationsContactCard.java b/src/tethys/calibration/swing/CalibrationsContactCard.java new file mode 100644 index 00000000..2dc6e581 --- /dev/null +++ b/src/tethys/calibration/swing/CalibrationsContactCard.java @@ -0,0 +1,208 @@ +package tethys.calibration.swing; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Date; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.jdesktop.swingx.JXDatePicker; + +import PamView.dialog.PamDialog; +import PamView.dialog.PamGridBagContraints; +import PamView.panel.WestAlignedPanel; +import PamView.wizard.PamWizard; +import nilus.Calibration; +import nilus.ContactInfo; +import nilus.MetadataInfo; +import nilus.ResponsibleParty; +import tethys.TethysTimeFuncs; +import tethys.calibration.CalibrationHandler; +import tethys.niluswraps.NilusChecker; +import tethys.swing.export.ResponsiblePartyPanel; + +public class CalibrationsContactCard extends CalibrationsCard { + + private JXDatePicker datePicker; + + private ResponsiblePartyPanel calibrator, dataManager; + + private JComboBox updateInterval; + + private MetadataInfo metaData; + + private JButton copyDown, copyUp; + + public CalibrationsContactCard(PamWizard pamWizard) { + super(pamWizard, "Contact Details"); + // TODO Auto-generated constructor stub +// setBorder(new TitledBorder("Contact")); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + updateInterval = new JComboBox<>(); + String[] vals = CalibrationHandler.updateOptions; + for (int i = 0; i < vals.length; i++) { + updateInterval.addItem(vals[i]); + } + + JPanel datePanel = new JPanel(new GridBagLayout()); + JPanel lp = new WestAlignedPanel(datePanel); + lp.setBorder(new TitledBorder("Calibration date")); + GridBagConstraints c = new PamGridBagContraints(); + datePanel.add(new JLabel("Calibration date: ", JLabel.RIGHT), c); + datePicker = new JXDatePicker(); + c.gridx++; + datePanel.add(datePicker, c); + c.gridx = 0; + c.gridy++; + datePanel.add(new JLabel("Update Frequency", JLabel.RIGHT), c); + c.gridx++; + datePanel.add(updateInterval, c); + + calibrator = new ResponsiblePartyPanel("Technical Person"); + dataManager = new ResponsiblePartyPanel("Data Manager"); + + JPanel copyPanel = new JPanel(new GridBagLayout()); + c = new PamGridBagContraints(); + copyPanel.add(copyDown = new JButton("Copy down"),c); + c.gridx++; + copyPanel.add(copyUp = new JButton("Copy up"), c); + + add(lp); + add(calibrator.getMainPanel()); + add(copyPanel); + add(dataManager.getMainPanel()); + + copyDown.setToolTipText("Copy technical person to data manager"); + copyUp.setToolTipText("Copy data manager to technical person"); + copyDown.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + copyRPDown(); + } + }); + copyUp.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + copyRPUp(); + } + + }); + } + + protected void copyRPDown() { + copyRPData(calibrator, dataManager); + } + private void copyRPUp() { + copyRPData(dataManager, calibrator); + } + + private void copyRPData(ResponsiblePartyPanel rFrom, ResponsiblePartyPanel rTo) { + ResponsibleParty rp = checkRPChildren(null); + rFrom.getParams(rp); + rTo.setParams(rp); + } + + @Override + public boolean getParams(Calibration cardParams) { + ResponsibleParty rp = checkRPChildren(cardParams.getResponsibleParty()); + cardParams.setResponsibleParty(rp); + calibrator.getParams(rp); + + metaData = cardParams.getMetadataInfo(); + if (metaData == null) { + metaData = new MetadataInfo(); + cardParams.setMetadataInfo(metaData); + } + metaData.setContact(checkRPChildren(metaData.getContact())); + dataManager.getParams(metaData.getContact()); + ResponsibleParty metaContact = metaData.getContact(); + NilusChecker.removeEmptyFields(metaData); + if (metaData.getContact() == null) { + return PamDialog.showWarning(getPamWizard(), "Missing data", "The Data Manager fields must be completed"); + } + + metaData.setUpdateFrequency((String) updateInterval.getSelectedItem()); + metaData.setDate(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis())); + + Date date = datePicker.getDate(); + if (date == null) { + return getPamWizard().showWarning("You must specify the data of the calibration"); + } + long millis = date.getTime(); + cardParams.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(millis)); + + + checkEmptyFields(rp); + checkEmptyFields(metaData); + + return true; + } + + private ResponsibleParty checkRPChildren(ResponsibleParty rp) { + if (rp == null) { + rp = new ResponsibleParty(); + } + if (rp.getContactInfo() == null) { + rp.setContactInfo(new ContactInfo()); + } + if (rp.getContactInfo().getAddress() == null) { +// rp.getContactInfo().setAddress(new Address()); + } + return rp; + } + + private ResponsibleParty findResponsibleParty(Calibration cal) { + if (cal == null) { + return null; + } + MetadataInfo metaInfo = cal.getMetadataInfo(); + if (metaInfo != null) { + ResponsibleParty resp = metaInfo.getContact(); + if (resp != null && resp.getIndividualName() != null) { + return resp; + } + } + return cal.getResponsibleParty(); + + } + + @Override + public void setParams(Calibration cardParams) { + // fill in as much as possible from the existing Calibration + ResponsibleParty resp = cardParams.getResponsibleParty(); + if (resp != null) { + calibrator.setParams(resp); + } + + MetadataInfo metaInf = cardParams.getMetadataInfo(); + if (metaInf != null) { + resp = metaInf.getContact(); + if (resp != null) { + dataManager.getParams(resp); + } + String uf = metaInf.getUpdateFrequency(); + if (uf != null) { + updateInterval.setSelectedItem(uf); + } + } + + XMLGregorianCalendar ts = cardParams.getTimeStamp(); + if (ts != null) { + datePicker.setDate(new Date(TethysTimeFuncs.millisFromGregorianXML(ts))); + } + + + } + +} diff --git a/src/tethys/calibration/swing/CalibrationsExportWizard.java b/src/tethys/calibration/swing/CalibrationsExportWizard.java new file mode 100644 index 00000000..74bb356a --- /dev/null +++ b/src/tethys/calibration/swing/CalibrationsExportWizard.java @@ -0,0 +1,42 @@ +package tethys.calibration.swing; + +import java.awt.Window; + +import PamView.wizard.PamWizard; +import PamView.wizard.PamWizardCard; +import nilus.Calibration; + +public class CalibrationsExportWizard extends PamWizard { + + private Calibration sampleDocument; + + private CalibrationsExportWizard(Window parentFrame, Calibration sampleDocument) { + super(parentFrame, "Calibrations Export"); + this.sampleDocument = sampleDocument; + addCard(new CalibrationProcessCard(this)); + addCard(new CalibrationsContactCard(this)); + } + + public static Calibration showWizard(Window parentFrame, Calibration sampleDocument) { + CalibrationsExportWizard wiz = new CalibrationsExportWizard(parentFrame, sampleDocument); + wiz.setParams(); + wiz.setVisible(true); + return wiz.sampleDocument; + } + + @Override + public void setCardParams(PamWizardCard wizardCard) { + wizardCard.setParams(sampleDocument); + } + + @Override + public boolean getCardParams(PamWizardCard wizardCard) { + return wizardCard.getParams(sampleDocument); + } + + @Override + public void cancelButtonPressed() { + sampleDocument = null; + } + +} diff --git a/src/tethys/calibration/swing/CalibrationsMainPanel.java b/src/tethys/calibration/swing/CalibrationsMainPanel.java new file mode 100644 index 00000000..e13365ef --- /dev/null +++ b/src/tethys/calibration/swing/CalibrationsMainPanel.java @@ -0,0 +1,77 @@ +package tethys.calibration.swing; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; + + +import PamView.panel.PamPanel; +import tethys.TethysControl; +import tethys.TethysState; +import tethys.calibration.CalibrationHandler; +import tethys.swing.TethysGUIPanel; + +public class CalibrationsMainPanel extends TethysGUIPanel { + + private CalibrationHandler calibrationHandler; + + private CalibrationsTable calibrationsTable; + + private JPanel mainPanel; + + private JPanel ctrlPanel; + + private JButton exportButton; + + private JLabel warning; + + public CalibrationsMainPanel(TethysControl tethysControl, CalibrationHandler calibrationHandler) { + super(tethysControl); + this.calibrationHandler = calibrationHandler; + mainPanel = new PamPanel(new BorderLayout()); + mainPanel.setBorder(new TitledBorder("Instrument calibration information")); + + calibrationsTable = new CalibrationsTable(tethysControl, calibrationHandler); + mainPanel.add(BorderLayout.CENTER, calibrationsTable.getComponent()); + + ctrlPanel = new PamPanel(new BorderLayout()); + exportButton = new JButton("Export ..."); + ctrlPanel.add(BorderLayout.WEST, exportButton); + warning = new JLabel(); + ctrlPanel.add(BorderLayout.CENTER, warning); + mainPanel.add(BorderLayout.NORTH, ctrlPanel); + exportButton.setToolTipText("Export calibration data to database"); + exportButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + exportCalibrations(); + } + }); + } + + protected void exportCalibrations() { + calibrationHandler.exportAllCalibrations(); + } + + @Override + public JComponent getComponent() { + return mainPanel; + } + + @Override + public void updateState(TethysState tethysState) { + super.updateState(tethysState); + enableControls(); + } + + private void enableControls() { + exportButton.setEnabled(getTethysControl().isServerOk()); + } + +} diff --git a/src/tethys/calibration/swing/CalibrationsTable.java b/src/tethys/calibration/swing/CalibrationsTable.java new file mode 100644 index 00000000..45b91f18 --- /dev/null +++ b/src/tethys/calibration/swing/CalibrationsTable.java @@ -0,0 +1,285 @@ +package tethys.calibration.swing; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.border.TitledBorder; +import javax.swing.table.AbstractTableModel; +import javax.xml.datatype.XMLGregorianCalendar; + +import PamController.PamController; +import PamController.soundMedium.GlobalMedium; +import PamController.soundMedium.GlobalMediumManager; +import PamUtils.PamCalendar; +import PamView.dialog.warn.WarnOnce; +import PamView.panel.PamPanel; +import PamView.tables.SwingTableColumnWidths; +import nilus.Calibration; +import tethys.Collection; +import tethys.DocumentNilusObject; +import tethys.TethysControl; +import tethys.TethysState; +import tethys.TethysState.StateType; +import tethys.TethysTimeFuncs; +import tethys.calibration.CalibrationHandler; +import tethys.dbxml.TethysException; +import tethys.swing.TethysGUIPanel; + +public class CalibrationsTable extends TethysGUIPanel { + + private CalibrationHandler calibrationHandler; + + private CalibrationsTableModel calTableModel; + + private JPanel mainPanel; + + private JTable calTable; + + private TethysControl tethysControl; + + /** + * @param calibrationHandler + */ + public CalibrationsTable(TethysControl tethysControl, CalibrationHandler calibrationHandler) { + super(tethysControl); + this.tethysControl = tethysControl; + this.calibrationHandler = calibrationHandler; + calTableModel = new CalibrationsTableModel(); + calTable = new JTable(calTableModel); + calTable.setRowSelectionAllowed(true); + calTable.addMouseListener(new TableMouse()); + + JScrollPane scrollPane = new JScrollPane(calTable); + + mainPanel = new PamPanel(new BorderLayout()); + mainPanel.add(BorderLayout.CENTER, scrollPane); + + calTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + new SwingTableColumnWidths(tethysControl.getUnitName()+"CalibrationsTable", calTable); + + } + + + @Override + public JComponent getComponent() { + return mainPanel; + } + + + @Override + public void updateState(TethysState tethysState) { + super.updateState(tethysState); + calTableModel.fireTableDataChanged(); + } + + private class TableMouse extends MouseAdapter { + + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopupMenu(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopupMenu(e); + } + } + + } + + public void showPopupMenu(MouseEvent e) { + int[] rows = calTable.getSelectedRows(); + if (rows == null || rows.length == 0) { + return; + } + int n = rows.length; + DocumentNilusObject doc = calibrationHandler.getCalibrationDataList().get(rows[0]); + + JPopupMenu popMenu = new JPopupMenu(); + JMenuItem menuItem; + if (n == 1) { + menuItem = new JMenuItem("Show document " + doc.getDocumentName()); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showCalibration(doc); + } + }); + popMenu.add(menuItem); + } + if (n > 1) { + menuItem = new JMenuItem("Delete selected documents"); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + deleteCalibrations(rows); + } + }); + popMenu.add(menuItem); + } + else { + menuItem = new JMenuItem("Delete document " + doc.getDocumentName()); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + deleteCalibration(doc); + } + }); + popMenu.add(menuItem); + } + popMenu.show(e.getComponent(), e.getX(), e.getY()); + } + + protected void deleteCalibration(DocumentNilusObject doc) { + String docName = doc.getDocumentName(); + int ans = WarnOnce.showNamedWarning("delete doc " + Collection.Calibrations.collectionName(), + PamController.getMainFrame(), "Delete document", + "Are you sure you want to delete the document " + docName, WarnOnce.OK_CANCEL_OPTION); + if (ans == WarnOnce.OK_OPTION) { + try { + tethysControl.getDbxmlConnect().removeDocument(Collection.Calibrations.collectionName(), docName); + } catch (TethysException e) { + System.out.println("Failed to delete " + docName); + System.out.println(e.getMessage()); + } + } + updateEverything(); + calTableModel.fireTableDataChanged(); + } + + + protected void showCalibration(DocumentNilusObject docInfo) { + tethysControl.displayDocument(docInfo); + + } + + + protected void deleteCalibrations(int[] rows) { + String msg = String.format("Are you sure you want to delete %d calibrations documents ?", rows.length); + int ans = WarnOnce.showNamedWarning("Deletemanycalibrations", PamController.getMainFrame(), "Delete multiple documents", msg, WarnOnce.OK_CANCEL_OPTION); + if (ans != WarnOnce.OK_OPTION) { + return; + } + for (int i = 0; i < rows.length; i++) { + String docName = null; + try { + DocumentNilusObject doc = calibrationHandler.getCalibrationDataList().get(rows[i]); + docName = doc.getDocumentName(); + tethysControl.getDbxmlConnect().removeDocument(Collection.Calibrations, docName); + } catch (TethysException e) { + System.out.println("Failed to delete " + docName); + System.out.println(e.getMessage()); + } + } + + updateEverything(); + + } + + private void updateEverything() { + getTethysControl().sendStateUpdate(new TethysState(StateType.DELETEDATA, Collection.Calibrations)); + } + + class CalibrationsTableModel extends AbstractTableModel { + + private static final long serialVersionUID = 1L; + + private String[] columnNames = {"Document", "Id", "Date", "End to End", "Hydrophone"}; + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DocumentNilusObject dataUnit = null; + try { + dataUnit = calibrationHandler.getCalibrationDataList().get(rowIndex); + } + catch (Exception e) { + return null; + } + if (dataUnit == null) { + return null; + } + Calibration cal = dataUnit.getNilusObject(); + switch (columnIndex) { + case 0: + return dataUnit.getDocumentName(); + case 1: + return cal.getId(); + case 2: + XMLGregorianCalendar ts = cal.getTimeStamp(); + if (ts == null) { + return null; + } + long ms = TethysTimeFuncs.millisFromGregorianXML(ts); + return PamCalendar.formatDBDate(ms); + case 3: + return getFSString(cal); + case 4: + return getPhoneString(cal); +// return String.format("%3.1fdB %s", cal.getSensitivityV(), cal.getType()); + } + return null; + } + + @Override + public int getRowCount() { + return calibrationHandler.getCalibrationDataList().size(); + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public String getColumnName(int column) { + if (column == 4) { + return PamController.getInstance().getGlobalMediumManager().getRecieverString(); + } + else { + return columnNames[column]; + } + } + } + + public String getFSString(Calibration cal) { + Double fs = cal.getSensitivityDBFS(); + if (fs == null) { + return null; + } + double ir = cal.getIntensityReferenceUPa(); + String str = String.format("%3.1fdB", fs); + if (ir != 0) { + str += String.format(" re%.0f\u00B5Pa", ir); + } + return str; + } + + public Object getPhoneString(Calibration cal) { + Double dbV = cal.getSensitivityV(); + if (dbV == null) { + dbV = cal.getSensitivityDBV(); + } + if (dbV == null) { + return null; + } + double ir = cal.getIntensityReferenceUPa(); + String str = String.format("%3.1fdB", dbV); + if (ir != 0) { + str += String.format(" re%.0fV/\u00B5Pa", ir); + } + return str; + } +} diff --git a/src/tethys/database/TethysActions.java b/src/tethys/database/TethysActions.java new file mode 100644 index 00000000..0c9ece36 --- /dev/null +++ b/src/tethys/database/TethysActions.java @@ -0,0 +1,27 @@ +package tethys.database; + +/** + * Possible document actions + * @author dg50 + * + */ +public enum TethysActions { + + ADDDOCUMENT, DELETEDOCUMENT, UPDATEDOCUMENT; + +// @Override +// public String toString() { +// switch (this) { +// case ADDDOCUMENT: +// return "Add document"; +// case DELETEDOCUMENT: +// return "Delete document"; +// case UPDATEDOCUMENT: +// return "Update document"; +// default: +// return null; +// } +// } + + +} diff --git a/src/tethys/database/TethysLogDataBlock.java b/src/tethys/database/TethysLogDataBlock.java new file mode 100644 index 00000000..7a3639d6 --- /dev/null +++ b/src/tethys/database/TethysLogDataBlock.java @@ -0,0 +1,16 @@ +package tethys.database; + +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamProcess; +import tethys.TethysControl; + +public class TethysLogDataBlock extends PamDataBlock { + + private TethysControl tethysControl; + + public TethysLogDataBlock(TethysControl tethysControl) { + super(TethysLogDataUnit.class, "Tethys Log", null, 0); + this.tethysControl = tethysControl; + } + +} diff --git a/src/tethys/database/TethysLogDataUnit.java b/src/tethys/database/TethysLogDataUnit.java new file mode 100644 index 00000000..e1998c2b --- /dev/null +++ b/src/tethys/database/TethysLogDataUnit.java @@ -0,0 +1,59 @@ +package tethys.database; + +import PamguardMVC.PamDataUnit; + +public class TethysLogDataUnit extends PamDataUnit { + + private String collection; + private String documentId; + private TethysActions action; + private String comment; + private boolean success; + + public TethysLogDataUnit(long timeMilliseconds, String collection, String documentId, TethysActions action, boolean success, String comment) { + super(timeMilliseconds); + this.collection = collection; + this.documentId = documentId; + this.action = action; + this.success = success; + this.comment = comment; + + } + + /** + * @return the collection + */ + public String getCollection() { + return collection; + } + + /** + * @return the documentId + */ + public String getDocumentId() { + return documentId; + } + + /** + * @return the action + */ + public TethysActions getAction() { + return action; + } + + /** + * @return the comment + */ + public String getComment() { + return comment; + } + + /** + * @return the success + */ + public boolean isSuccess() { + return success; + } + + +} diff --git a/src/tethys/database/TethysLogger.java b/src/tethys/database/TethysLogger.java new file mode 100644 index 00000000..9e7ae2ad --- /dev/null +++ b/src/tethys/database/TethysLogger.java @@ -0,0 +1,128 @@ +package tethys.database; + +import java.sql.Types; + +import PamguardMVC.PamDataUnit; +import generalDatabase.DBControlUnit; +import generalDatabase.DBProcess; +import generalDatabase.PamConnection; +import generalDatabase.PamTableDefinition; +import generalDatabase.PamTableItem; +import generalDatabase.SQLLogging; +import generalDatabase.SQLTypes; +import tethys.TethysControl; + +/** + * Logging everything we put into Tethys in our own database. + * @author dg50 + * + */ +public class TethysLogger extends SQLLogging { + + private static TethysLogger tethysLogger; + + private TethysControl tethysControl; + + private TethysLogDataBlock logDataBlock; + + private PamTableDefinition tableDefinition; + + private PamTableItem collection, documentId, action, status, comment; + + private boolean tableChecked = false; + + private TethysLogger(TethysControl tethysControl, TethysLogDataBlock pamDataBlock) { + super(pamDataBlock); + this.tethysControl = tethysControl; + this.logDataBlock = pamDataBlock; + tableDefinition = new PamTableDefinition("TethysLog"); + tableDefinition.addTableItem(collection = new PamTableItem("Collection", Types.VARCHAR)); + tableDefinition.addTableItem(documentId = new PamTableItem("DocumentId", Types.VARCHAR)); + tableDefinition.addTableItem(action = new PamTableItem("Action", Types.VARCHAR)); + tableDefinition.addTableItem(status = new PamTableItem("Status", Types.VARCHAR)); + tableDefinition.addTableItem(comment = new PamTableItem("Comment", Types.VARCHAR)); + tableDefinition.setUpdatePolicy(UPDATE_POLICY_OVERWRITE); + setTableDefinition(tableDefinition); + } + + public static TethysLogger getTethysLogger(TethysControl tethysControl) { + if (tethysLogger == null) { + tethysLogger = createTethysLogger(tethysControl); + } + return tethysLogger; + } + + private boolean checkTable() { + if (tableChecked == true) { + return true; + } + if (findDBProcess() == null) { + return false; + } + else { + tableChecked = findDBProcess().checkTable(tableDefinition); + } + return tableChecked; + } + + public boolean logAction(String collection, String documentId, TethysActions action, boolean success, String comment) { + PamConnection con = findDBConnection(); + if (con == null) { + return false; + } + if (checkTable() == false) { + return false; + } + + TethysLogDataUnit dataUnit = new TethysLogDataUnit(System.currentTimeMillis(), collection, documentId, action, success, comment); + return this.logData(con, dataUnit); + } + + private PamConnection findDBConnection() { + return DBControlUnit.findConnection(); + } + + /** + * Find the database controlled unit.
Must exist in viewer mode surely, but perhaps + * created after the Tethys module if the user is really crafty ! + * @return the DB controlled unit. + */ + private DBControlUnit findDBControl() { + return DBControlUnit.findDatabaseControl(); + } + + /** + * Fine the database process. Should exist. + * @return + */ + private DBProcess findDBProcess() { + DBControlUnit dbControl = findDBControl(); + if (dbControl == null) { + return null; + } + return dbControl.getDbProcess(); + } + + private static TethysLogger createTethysLogger(TethysControl tethysControl) { + TethysLogDataBlock datablock = new TethysLogDataBlock(tethysControl); + TethysLogger newLogger = new TethysLogger(tethysControl, datablock); + return newLogger; + } + + + @Override + public void setTableData(SQLTypes sqlTypes, PamDataUnit pamDataUnit) { + TethysLogDataUnit tldu = (TethysLogDataUnit) pamDataUnit; + collection.setValue(tldu.getCollection()); + documentId.setValue(tldu.getDocumentId()); + action.setValue(tldu.getAction().toString()); + status.setValue(tldu.isSuccess() ? "Success" : "Fail"); + comment.setValue(tldu.getComment()); + } + +// public TethysLogger(TethysControl tethysControl) { +// this.tethysControl = tethysControl; +// } + + +} diff --git a/src/tethys/dbxml/DBQueryResult.java b/src/tethys/dbxml/DBQueryResult.java new file mode 100644 index 00000000..80a27246 --- /dev/null +++ b/src/tethys/dbxml/DBQueryResult.java @@ -0,0 +1,62 @@ +package tethys.dbxml; + +import java.io.IOException; +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class DBQueryResult { + + public long queryTimeMillis; + + public String queryResult; + + public String schemaPlan; + + public Exception queryException; + + public DBQueryResult(long queryTimeMillis, String queryResult, String schemaPlan) { + super(); + this.queryTimeMillis = queryTimeMillis; + this.queryResult = queryResult; + this.schemaPlan = schemaPlan; + } + + public DBQueryResult(long queryTimeMillis, Exception queryException) { + super(); + this.queryTimeMillis = queryTimeMillis; + this.queryException = queryException; + } + + /** + * Get the result as an XML document. + * @return XML document + * @throws ParserConfigurationException + * @throws SAXException + * @throws IOException + */ + public Document getDocument() throws ParserConfigurationException, SAXException, IOException { + if (queryResult == null) { + return null; + } + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + //API to obtain DOM Document instance + DocumentBuilder builder = null; + + //Create DocumentBuilder with default configuration + builder = factory.newDocumentBuilder(); + + //Parse the content to Document object + Document doc = builder.parse(new InputSource(new StringReader(queryResult))); + return doc; + } + +} diff --git a/src/tethys/dbxml/DBXMLConnect.java b/src/tethys/dbxml/DBXMLConnect.java new file mode 100644 index 00000000..9b12ecd5 --- /dev/null +++ b/src/tethys/dbxml/DBXMLConnect.java @@ -0,0 +1,554 @@ +package tethys.dbxml; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.util.ArrayList; + +import javax.xml.bind.JAXBException; + +import dbxml.JerseyClient; +import dbxml.Queries; +import dbxml.uploader.Importer; +import nilus.MarshalXML; +import tethys.Collection; +import tethys.TethysControl; +import tethys.database.TethysActions; +import tethys.database.TethysLogger; +import tethys.niluswraps.NilusChecker; +import tethys.output.TethysExportParams; +import tethys.reporter.TethysReport; +import tethys.reporter.TethysReporter; + +/** + * Class containing functions for managing the database connection. Opening, closing, + * writing, keeping track of performance, etc. + * @author Doug Gillespie, Katie O'Laughlin + * + */ +public class DBXMLConnect { + + private TethysControl tethysControl; + private File tempDirectory; + + private JerseyClient jerseyClient; + + private Queries queries; + + private String currentSiteURL; + +// public static String[] collections = {"Deployments", "Detections", "Localizations", "Calibrations", "SpeciesAbbreviations"}; + + public DBXMLConnect(TethysControl tethysControl) { + this.tethysControl = tethysControl; + + checkTempFolder(); + } + + /** + * Check the jersey client and the queries. Need to recreate + * if the url has changed. + * @return + */ + private boolean checkClient() { + if (jerseyClient == null || queries == null || currentSiteURL == null) { + return false; + } + TethysExportParams params = tethysControl.getTethysExportParams(); + if (!currentSiteURL.equalsIgnoreCase(params.getFullServerName())) { + return false; + } + return true; + } + + + /** + * Get the client. The client will only be recreated if the url changes + * @return Jersy client + */ + public synchronized JerseyClient getJerseyClient() { + if (!checkClient()) { + openConnections(); + } + return jerseyClient; + } + + /** + * Get the Queries object. This will only be recreated if the client changes. + * @return + */ + public synchronized Queries getTethysQueries() { + if (!checkClient()) { + openConnections(); + } + return queries; + } + + /** + * Convert a nilus Object into a file + * @param nilusObject nilus object + * @param file file (should not exist) + * @return file (will be the same as input file) + * @throws TethysException + */ + public File createXMLDocument(Object nilusObject, File file) throws TethysException { + Class objClass = nilusObject.getClass(); + try { + MarshalXML marshal = new MarshalXML(); + marshal.createInstance(objClass); + marshal.marshal(nilusObject, file.toString()); + } catch(IllegalArgumentException e) { + throw new TethysException("IllegalArgumentException posting to Tethys: " + e.getMessage(), null); + } catch (IOException e) { + throw new TethysException("IOException posting to Tethys: " + e.getMessage(), null); + } catch (JAXBException e) { + throw new TethysException("JAXBException posting to Tethys: " + e.getMessage(), null); + } + return file; + } + + /** + * Create a temporary nilus file. + * @param nilusObject + * @return + * @throws TethysException + */ + public File createTempXMLDocument(Object nilusObject) throws TethysException { + String tempName = getTempFileName(nilusObject); + tempName = tempDirectory.getAbsolutePath() + File.separator + tempName + ".xml"; + File tempFile = new File(tempName); + File retFile = createXMLDocument(nilusObject, tempFile); + retFile.deleteOnExit(); + return retFile; + } + + + public boolean postAndLog(Object nilusObject) throws TethysException + { + return postAndLog(nilusObject, null); + } + + /** + * I don't think this should ever be used since everything goes a bit pear + * shaped if the documentName isn't the same as the Id. However, for Calibration + * documents this is no longer the case, since a Calibration can have multiple + * entries on different dates, so allow it ! + * @param nilusObject + * @param documentName + * @return + * @throws TethysException + */ + public boolean postAndLog(Object nilusObject, String documentName) throws TethysException + { + boolean ok = NilusChecker.warnEmptyFields(tethysControl.getGuiFrame(), nilusObject); + + + TethysException e = null; + boolean success = false; + try { + success = postToTethys(nilusObject, documentName); + } + catch (TethysException ex) { + e = ex; + } + TethysLogger logger = TethysLogger.getTethysLogger(tethysControl); + Class objClass = nilusObject.getClass(); + Collection collection = Collection.fromClass(objClass); + String documentId = getDocumentId(nilusObject); + logger.logAction(collection.collectionName(), documentId, TethysActions.ADDDOCUMENT, success, ""); + if (e != null) { + throw (e); + } + return success; + } + + /** + * take a nilus object loaded with PamGuard data and post it to the Tethys database + * + * @param pamGuardObjs a nilus object loaded with PamGuard data + * @return error string, null string means there are no errors + * @throws TethysException + */ + private boolean postToTethys(Object nilusObject, String documentName) throws TethysException + { + Class objClass = nilusObject.getClass(); + Collection collection = Collection.fromClass(nilusObject.getClass()); + TethysExportParams params = new TethysExportParams(); + String importReturn = null; + if (documentName == null) { + documentName = getTempFileName(nilusObject); + } + documentName = tempDirectory.getAbsolutePath() + File.separator + documentName + ".xml"; + File tempFile = new File(documentName); + String bodgeName = documentName;//"C:\\Users\\dg50\\AppData\\Local\\Temp\\PAMGuardTethys\\Meygen2022_10a.xml"; + try { + MarshalXML marshal = new MarshalXML(); + marshal.createInstance(objClass); + marshal.marshal(nilusObject, tempFile.toString()); + // tempFile = stripXMLHeader(tempFile); + importReturn = Importer.ImportFiles(params.getFullServerName(), collection.collectionName(), + new String[] { bodgeName }, "", "", false); + + + tempFile.deleteOnExit(); + } catch(IllegalArgumentException e) { + throw new TethysException("IllegalArgumentException posting to Tethys: " + e.getMessage(), null); + } catch (IOException e) { + throw new TethysException("IOException posting to Tethys: " + e.getMessage(), null); + } catch (JAXBException e) { + throw new TethysException("JAXBException posting to Tethys: " + e.getMessage(), null); + } + + /* + * The returned string consists of the file name, then an XML report. + * Quite hard to see much common structure in this, so just look for + * two words, and + */ + boolean error = importReturn.contains(""); + String name = tempFile.getName(); + TethysReporter.getTethysReporter().addReport(new TethysReport(success, collection, name, name)); +// error = !success; might be a better options. + if (error) { + throw new TethysException("Error posting to Tethys", importReturn); + } + return success; + } + + /** + * Update a document within Tethys. We're assuming that a + * document with the same name in the same collection already + * exists. If it doesn't / has a different name, then use + * the removedocument function + * @param nilusDocument + * @return + * @throws TethysException + */ + public boolean updateDocument(Object nilusDocument) throws TethysException { + deleteDocument(nilusDocument); + return postToTethys(nilusDocument, null); + } + + /** + * Delete a nilus document from the database. The only field which + * needs to be populated here is the Id. The code also uses the object + * class to identify the correct collection. + * @param nilusDocument + * @return + * @throws TethysException + */ + public boolean deleteDocument(Object nilusDocument) throws TethysException { + + Class objClass = nilusDocument.getClass(); + Collection collection = Collection.fromClass(objClass); + String docId = getDocumentId(nilusDocument); + String result = null; + try { + result = jerseyClient.removeDocument(collection.collectionName(), docId ); + /** + * Return from a sucessful delete is something like + * + deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId++, recordPeriod); + + ['ECoastNARW0'] + +An error will throw an exception. + */ + } + catch (Exception e) { +// System.out.printf("Error deleting %s %s: %s\n", collection, docId, e.getMessage()); + String msg = String.format("Error deleting %s:%s", collection, docId); + throw new TethysException(msg, e.getLocalizedMessage()); + } + // forceFlush(); + return true; + } + + /** + * Delete a Deploymnet and any contained Detections document. Doesn't work ! + * @param deploymentId + * @return + * @throws TethysException + */ + public boolean deleteDeployment(String deploymentId) throws TethysException { + ArrayList detDocNames = tethysControl.getDbxmlQueries().getDetectionsDocuments(deploymentId); + JerseyClient jerseyClient = getJerseyClient(); + Queries queries = null; + String result = null; + try { + result = jerseyClient.removeDocument("Deployments", deploymentId ); + } + catch (Exception e) { + throw new TethysException("Error deleting deployment document " + deploymentId, e.getMessage()); + } + return true; + } + + /** + * Remove a document based on a collection name and a cdocument Id. + * @param collection collection name. + * @param documentName document name (not the internal Document Id) + * @return + * @throws TethysException + */ + public boolean removeDocument(Collection collection, String documentName) throws TethysException { + return removeDocument(collection.collectionName(), documentName); + } + + /** + * Remove a document based on a collection name and a document namw. + * @param collectionName collection name. + * @param documentName document name (not the internal Document Id) + * @return + * @throws TethysException + */ + public boolean removeDocument(String collectionName, String documentName) throws TethysException { + try { + Object result = jerseyClient.removeDocument(collectionName, documentName ); + /** + * Return from a sucessful delete is something like + * + deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId++, recordPeriod); + + ['ECoastNARW0'] + + An error will throw an exception. + */ + } + catch (Exception e) { + String msg = String.format("Error deleting %s:%s", collectionName, documentName); + throw new TethysException(msg, e.getLocalizedMessage()); + } + return true; + } + + /** + * check the return string from importFiles and if it's an + * error, throw an exception. Otherwise do nothing. + * @param fileError + */ + private void checkReturnString(String fileError) { + /** + * Example good string is + * +C:\Users\dg50\AppData\Local\Temp\PAMGuardTethys\20080311_2DSimplex_0.xml: 7360 bytes + + + added + + + 20080311_2DSimplex_0 + + + + +Example error (file not existing) +C:\Users\dg50\AppData\Local\Temp\PAMGuardTethys\20080311_2DSimplex_0.xmlnot: 0 bytes + + + C:\Users\dg50\AppData\Local\Temp\PAMGuardTethys\20080311_2DSimplex_0.xmlnot + does not exist + + + + + + */ + + + } + + /** + * Seems we have to get rid of the line + * which is being put there by the marshaller ? + * @param tempFile + */ + private File stripXMLHeader(File tempFile) { + // TODO Auto-generated method stub + + File tempTemp = new File(tempFile.getAbsolutePath().replace(".temp.xml", ".xml")); + try { + BufferedReader reader = new BufferedReader(new FileReader(tempFile)); + BufferedWriter writer = new BufferedWriter(new FileWriter(tempTemp)); + String line = reader.readLine(); + while (line != null) { + // see if the line has any unicode in it + int len = line.length(); + byte[] bytes = line.getBytes(); + if (len == bytes.length) { + System.out.println(line); + } + + if (line.startsWith(" getCollectionDocumentList(Collection collection) { + if (collection == null) { + return null; + } + + /** + * xQuery string based on examples in email from MR on 27/9/2023 + */ +// String baseQuery = " {\r\n" + String baseQuery = " {\r\n" + + " for $doc in collection(\"COLLECTIONAME\")/DOCUMENTNAME\r\n" + + " return\r\n" + + " {\r\n" + + " base-uri($doc), \r\n" + + " $doc/Id\r\n" + + " }\r\n" + + " \r\n" + + "} \r\n" + + ""; + String xQuery = baseQuery.replace("COLLECTIONAME", collection.collectionName()); + xQuery = xQuery.replace("DOCUMENTNAME", collection.documentName()); + + Queries queries = dbXMLConnect.getTethysQueries(); + String result = null; + try { + result = queries.QueryTethys(xQuery); + } + catch (Exception e) { +// e.printStackTrace(); + } + if (result == null) { + return null; + } +// System.out.println(result); + ArrayList documentInfos = new ArrayList<>(); + + Document doc = convertStringToXMLDocument(result); + if (doc == null) { + return null; + } +// PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); +// System.out.println(pamXMLWriter.getAsString(doc)); + /** + * lots of elements along lines of + * dbxml:///Deployments/Meygen20229Meygen20229 + */ + NodeList returns = doc.getElementsByTagName("doc"); + int n = returns.getLength(); + String toStrip = "dbxml:///"+collection.collectionName()+"/"; + for (int i = 0; i < n; i++) { + Node aNode = returns.item(i); + String nameStr = null; + String id = null; + NodeList kids = aNode.getChildNodes(); + for (int k = 0; k < kids.getLength(); k++) { + Node kidNode = kids.item(k); + String name = kidNode.getNodeName(); + String cont = kidNode.getTextContent(); + switch(name) { + case "#text": + nameStr = cont; + nameStr = nameStr.replaceFirst(toStrip, ""); + break; + case "Id": + id = kidNode.getTextContent(); + break; + default: + System.out.printf("Uknonwn node in Collection list %s item %d, Node %d name %s content %s\n", + collection, i, k, name, cont); + } + } +// if (i > 428) { +// System.out.println("MARU cal doc"); +// } + // this is the doc name with a load of stuff in front, + // e.g. dbxml:///Deployments/1705_Array-2017-09-261705_Array-2017-09-26 + if (nameStr == null) { + nameStr = aNode.getTextContent(); + nameStr = nameStr.replaceFirst(toStrip, ""); + } +// if (aNode instanceof Element) { + // nameStr = getElementData((Element) aNode, "#text"); + // } + + if (id == null) { + if (aNode instanceof Element) { + id = getElementData((Element) aNode, "Id"); + } + } + + DocumentInfo docInfo = new DocumentInfo(collection, nameStr, id); + documentInfos.add(docInfo); +// System.out.println(nameStr + " : " + id); + } + return documentInfos; + + + + // if (collection.endsWith("s")) { + // collection = collection.substring(0, collection.length()-1); + // } +// String baseQuery = "{\"return\":[\"COLLECTIONNAME/Id\"],\"select\":[],\"enclose\":1}"; +// baseQuery = baseQuery.replace("COLLECTIONNAME", collection); +// String tagName = "Id"; +// +// if (collection.equals("SpeciesAbbreviations")) { +// baseQuery = "{\"return\":[\"Abbreviations/Name\"],\"select\":[],\"enclose\":1}"; +// tagName = "Name"; +// } +// +// DBQueryResult result; +// try { +// result = executeQuery(baseQuery); +// } catch (TethysQueryException e) { +// System.out.println("Error with query: " + baseQuery); +// tethysControl.showException(e); +// return null; +// } +// +// if (result == null || result.queryResult == null) { +// return null; +// } +// Document doc = convertStringToXMLDocument(result.queryResult); +// if (doc == null) { +// return null; +// } +// NodeList returns = doc.getElementsByTagName(tagName); +// ArrayList docIds = new ArrayList<>(); +// int n = returns.getLength(); +// for (int i = 0; i < n; i++) { +// Node aNode = returns.item(i); +// String docId = aNode.getTextContent(); +// docIds.add(docId); +// } +// +// return docIds; + } + + /** + * Get a list of project names. + * @return + */ + public ArrayList getProjectNames() { + + String projectQuery = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}"; + + DBQueryResult result; + try { + result = executeQuery(projectQuery); + } catch (TethysQueryException e) { + tethysControl.showException(e); + return null; + } + + if (result == null || result.queryResult == null) { + return null; + } + + // System.out.println("Project query execution time millis = " + result.queryTimeMillis); + + ArrayList projectNames = new ArrayList<>(); + // iterate through the document and make a list of names, then make them unique. + /* looking for elements like this: + * + * check out the jaxb unmarshaller ... + + + LJ + + + */ + Document doc = convertStringToXMLDocument(result.queryResult); + if (doc == null) { + return null; + } + NodeList returns = doc.getElementsByTagName("Project"); + // System.out.println("N projects = " + returns.getLength()); + int n = returns.getLength(); + for (int i = 0; i < n; i++) { + Node aNode = returns.item(i); + String projName = aNode.getTextContent(); + if (projName != null) { + if (!projectNames.contains(projName)) { + projectNames.add(projName); + } + } + // } + // if (aNode instanceof Element) { + // Node depEl = ((Element) aNode).getFirstChild(); + // if (depEl == null) { + // continue; + // } + // if (depEl instanceof Element) { + // Element projEl = (Element) ((Element) depEl).getFirstChild(); + // String projName = projEl.getTextContent(); + // if (projName != null) { + // if (!projectNames.contains(projName)) { + // projectNames.add(projName); + // } + // } + // } + // } + } + + Collections.sort(projectNames); + + return projectNames; + } + + /** + * Get project deployments that use a specific instrument id. More use than the call without this + * extra clause since it can handle overlapping deployments. + * @param projectName + * @param instrumentId + * @return + */ + public ArrayList getProjectDeployments(String projectName, String instrumentId) { + if (projectName == null) { + return null; + } + String qBase = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"%s\"],\"optype\":\"binary\"},{\"op\":\"=\"," + + "\"operands\":[\"Deployment/Instrument/InstrumentId\",\"%s\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String qStr = String.format(qBase, projectName, instrumentId); + + return runProjectDeploymentsQuery(projectName, qStr); + } + /** + * Get some basic (not all) data for deployments associated with a project. Note that + * this may include deployments which are NOT part of the current dataset. That requires + * a search on Instrument as well. + * @param projectName + * @return + */ + public ArrayList getProjectDeployments(String projectName) { + if (projectName == null) { + return null; + } + String qBase = "{\"return\":[\"Deployment\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"%s\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String qStr = String.format(qBase, projectName); + return runProjectDeploymentsQuery(projectName, qStr); + } + + /** + * Run the actual projects query from either of the two above functions. + * @param projectName + * @param qStr + * @return + */ + private ArrayList runProjectDeploymentsQuery(String projectName, String qStr) { + DBQueryResult result = null; + try { + result = executeQuery(qStr); + } catch (TethysQueryException e1) { + tethysControl.showException(e1); + } + if (result == null) { + return null; + } + // System.out.println("Deployment query execution time millis = " + result.queryTimeMillis); + + PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); + + Document doc = convertStringToXMLDocument(result.queryResult); + if (doc == null) { + return null; + } + + // System.out.println(pamXMLWriter.getAsString(doc)); + + ArrayList deployments = new ArrayList<>(); + + NodeList returns = doc.getElementsByTagName("Deployment"); + // if (returns.getLength() == 0) { + // // try REsult instead ! + // returns = doc.getElementsByTagName("Result"); + // } + // System.out.println("N projects = " + returns.getLength()); + int n = returns.getLength(); + + // Queries queries = new Queries(null) + for (int i = 0; i < n; i++) { + Node aNode = returns.item(i); + if (aNode instanceof Element) { + Element returnedEl = (Element) aNode; + + String Id = getElementData(returnedEl, "Id"); + String project = getElementData(returnedEl, "Project"); + String DeploymentId = getElementData(returnedEl, "DeploymentId"); + String instrType = getElementData(returnedEl, "Instrument.Type"); + String instrId = getElementData(returnedEl, "Instrument.InstrumentId"); + String geometry = getElementData(returnedEl, "Instrument.GeometryType"); + String audioStart = getElementData(returnedEl, "DeploymentDetails.AudioTimeStamp"); + String audioEnd = getElementData(returnedEl, "RecoveryDetails.AudioTimeStamp"); + String region = getElementData(returnedEl, "Region"); + Deployment deployment = new Deployment(); + try { + Helper.createRequiredElements(deployment); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + deployment.setId(Id); + deployment.setProject(projectName); + deployment.setDeploymentId(Integer.valueOf(DeploymentId)); + XMLGregorianCalendar gcStart = TethysTimeFuncs.fromGregorianXML(audioStart); + XMLGregorianCalendar gcEnd = TethysTimeFuncs.fromGregorianXML(audioEnd); + // System.out.printf("Converted %s to %s\n", audioStart, + // PamCalendar.formatDBDateTime(TethysTimeFuncs.millisFromGregorianXML(gcStart), true)); + deployment.getDeploymentDetails().setAudioTimeStamp(gcStart); + if (deployment.getRecoveryDetails() == null) { + deployment.setRecoveryDetails(new DeploymentRecoveryDetails()); + } + deployment.getRecoveryDetails().setAudioTimeStamp(gcEnd); + if (instrType != null || instrId != null) { + Instrument instrument = new Instrument(); + instrument.setType(instrType); + instrument.setInstrumentId(instrId); + instrument.setGeometryType(geometry); + deployment.setInstrument(instrument); + } + deployment.setRegion(region); + deployments.add(deployment); + } + } + return deployments; + } + + /** + * Get a list of Detections documents which associate with a datablock and a deploymentId. + * @param dataBlock + * @param deploymentId can be null to get all docs for data block + * @return + */ + public ArrayList getDetectionsDocuments(PamDataBlock dataBlock, String deploymentId) { + /** + * first query for Detections documents associated with this deployment and datablock. + * updated May 23 + */ + String queryNoDepl = "{\"species\":{\"query\":{\"op\":\"lib:completename2tsn\",\"optype\":\"function\",\"operands\":[\"%s\"]},\"return\":{\"op\":\"lib:tsn2completename\",\"optype\":\"function\",\"operands\":[\"%s\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String queryWithDepl = "{\"species\":{\"query\":{\"op\":\"lib:completename2tsn\",\"optype\":\"function\",\"operands\":[\"%s\"]},\"return\":{\"op\":\"lib:tsn2completename\",\"optype\":\"function\",\"operands\":[\"%s\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"TheDeploymentId\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String query; + if (deploymentId == null) { + query = queryNoDepl; + } + else { + query = queryWithDepl.replace("TheDeploymentId", deploymentId); + } + query = query.replace("LongDataName", dataBlock.getLongDataName()); + DBQueryResult queryResult = null; + try { + queryResult = executeQuery(query); + } catch (TethysQueryException e1) { + tethysControl.showException(e1); + return null; + } + if (queryResult ==null) { + return null; + } + Document doc; + try { + doc = queryResult.getDocument(); + } catch (ParserConfigurationException | SAXException | IOException e) { + e.printStackTrace(); + return null; + } + if (doc == null) { + return null; + } + ArrayList detectionsNames = new ArrayList(); + int count = 0; + NodeList returns = doc.getElementsByTagName("Detections"); + // if (returns.getLength() == 0) { + // returns = doc.getElementsByTagName("Result"); + // } + for (int i = 0; i < returns.getLength(); i++) { + Node aNode = returns.item(i); + String docName = aNode.getTextContent(); + detectionsNames.add(docName); + } + return detectionsNames; + } + + + /** + * Get the names of all detection documents for a given deployment for all data streams. + * @param deploymentId + * @return + */ + public ArrayList getDetectionsDocuments(String deploymentId) { + String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"SomeDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String queryStr = queryBase.replace("SomeDeploymentId", deploymentId); + DBQueryResult queryResult = null; + try { + queryResult = executeQuery(queryStr); + } catch (TethysQueryException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (queryResult == null || queryResult.queryException != null) { + return null; + } + + // PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); + + Document doc = convertStringToXMLDocument(queryResult.queryResult); + if (doc == null) { + return null; + } + + ArrayList detectionDocs = new ArrayList<>(); + + NodeList returns = doc.getElementsByTagName("Record"); + if (returns.getLength() == 0) { + returns = doc.getElementsByTagName("Record"); + } + for (int i = 0; i < returns.getLength(); i++) { + Node aNode = returns.item(i); + detectionDocs.add(aNode.getTextContent()); + } + return detectionDocs; + } + + public int countData(PamDataBlock dataBlock, String deploymentId) { + // /** + // * first query for Detections documents associated with this deployment and datablock. + // */ + // String queryNoDepl = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"}],\"enclose\":1}"; + // String queryWithDepl = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Algorithm/Software\",\"LongDataName\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"TheDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}"; + // String query; + // if (deploymentId == null) { + // query = queryNoDepl; + // } + // else { + // query = queryWithDepl.replace("TheDeploymentId", deploymentId); + // } + // query = query.replace("LongDataName", dataBlock.getLongDataName()); + // DBQueryResult queryResult = executeQuery(query); + // if (queryResult ==null) { + // return 0; + // } + // Document doc; + // try { + // doc = queryResult.getDocument(); + // } catch (ParserConfigurationException | SAXException | IOException e) { + // e.printStackTrace(); + // return 0; + // } + // + // int count = 0; + // NodeList returns = doc.getElementsByTagName("Return"); + ArrayList documentNames = getDetectionsDocuments(dataBlock, deploymentId); + if (documentNames == null) { + return 0; + } + int count = 0; + for (String docName : documentNames) { + // System.out.println(aNode.getTextContent()); + int count2 = countDetections2(docName); + count += count2; //countDetecionsData(docName); + + } + return count; + } + + public String getDocument(String collection, String documentId) { + // String queryBase = "return:(collection(\"replaceCollectionName\")/Detections[Id=\"ReplaceDocumentId\"])"; + // queryBase = queryBase.replace("replaceCollectionName", collection); + // queryBase = queryBase.replace("ReplaceDocumentId", documentId); + // + // String result = null; + // try { + // Queries queries = dbXMLConnect.getTethysQueries(); + // result = queries.QueryTethys(queryBase); + //// System.out.println(result); + // } + // catch (Exception e) { + // System.out.println("Error executing " + queryBase); + //// e.printStackTrace(); + // return null; + // } + // return result; + + Queries queries = dbXMLConnect.getTethysQueries(); + String result = null; + try { + result = queries.getDocument(collection, documentId); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return result; + + // String queryBase = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}"; + } + + /** + * Find out if a document exists ? + * @param collection + * @param documentId + * @return + */ + public boolean documentExists(String collection, String documentId) { + Queries queries = dbXMLConnect.getTethysQueries(); + String result = null; + try { + result = queries.getDocument(collection, documentId); + } catch (Exception e) { + return false; + } + if (result == null || result.length() == 0) { + return false; + } + + return result.contains(documentId); + } + + /** + * Count on effort detections in a Detections document + * @param docName + * @return + */ + public int countDetections2(String docName) { + TethysExportParams params = tethysControl.getTethysExportParams(); + String queryBase = "count(collection(\"Detections\")/Detections[Id=\"ReplaceDocumentId\"]/OnEffort/Detection)"; + String query = queryBase.replace("ReplaceDocumentId", docName); + + String result = null; + try { + Queries queries = dbXMLConnect.getTethysQueries(); + result = queries.QueryTethys(query); + // System.out.println(result); + } + catch (Exception e) { + System.out.println("Error executing " + query); + // e.printStackTrace(); + return -1; + } + int count = 0; + try { + count = Integer.valueOf(result); + } + catch (NumberFormatException e) { + System.out.println("Unable to interpret count data " + result); + return 0; + } + return count; + } + + // /** + // * Get a count of the detections in a detections document. + // * Only looking in onEffort so far. + // * @param deploymentId + // * @param detectionDocId + // * @param dataBlock + // * @return + // */ + // public int getDetectionsDetectionCount(String deploymentId, String detectionDocId, PamDataBlock dataBlock) { + // String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/OnEffort/Detection/Start\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Id\",\"SomeDetectionsId\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"SomeDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}"; + // String queryStr = queryBase.replace("SomeDetectionsId", detectionDocId); + // queryStr = queryStr.replace("SomeDeploymentId", deploymentId); + // DBQueryResult queryResult = executeQuery(queryStr); + // if (queryResult == null || queryResult.queryException != null) { + // return 0; + // } + //// System.out.println("Detections query time ms = " + queryResult.queryTimeMillis); + // + // PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); + // + // Document doc = convertStringToXMLDocument(queryResult.queryResult); + // if (doc == null) { + // return 0; + // } + // + //// System.out.println(pamXMLWriter.getAsString(doc)); + // + //// ArrayList detectionDocs = new ArrayList<>(); + // + // NodeList returns = doc.getElementsByTagName("Start"); + // int n = returns.getLength(); + // return n; + // } + + // /** + // * This is the quickest way of counting data in a project, but it will load the start + // * times for every detection in a project at once, so might use a lot of memory. Also + // * it wll probably get data for all deployments in a project, which may not be what we want. + // * @param projectName + // * @param dataPrefixes + // * @return + // */ + // public int[] countDataForProject(String projectName, String[] dataPrefixes) { + // int[] n = new int[dataPrefixes.length]; + // ArrayList matchedDeployments = tethysControl.getDeploymentHandler().getMatchedDeployments(); + //// ArrayList deployments = getProjectDeployments(projectName); + // if (matchedDeployments == null) { + // return null; + // } + // for (PDeployment aDeployment : matchedDeployments) { + //// ArrayList detectionsIds = getDetectionsDocsIds(aDeployment.getId()); + //// for (String detId : detectionsIds) { + //// n += getDetectionsDetectionCount(aDeployment.getId(), detId, dataBlock); + //// } + // int[] newN = countDataForDeployment(projectName, aDeployment.deployment.getId(), dataPrefixes); + // for (int i = 0; i < n.length; i++) { + // n[i] += newN[i]; + // } + // } + // return n; + // } + + /** + * Count data within a deployment document which is associated with a set of datablocks + * Since the detections all come back in one query, it's easier to count all datablocks at once so + * that it can all happen off a single query. + * @param id + * @param dataBlockPrefixes + * @return + */ + private int[] countDataForDeployment(String projectId, String deploymentId, String[] dataPrefixes) { + String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\",\"Detections/OnEffort/Detection/Start\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"ReplaceDeploymentIdString\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String queryString = queryBase.replace("ReplaceDeploymentIdString", deploymentId); + DBQueryResult result; + try { + result = executeQuery(queryString); + } catch (TethysQueryException e) { + tethysControl.showException(e); + return null; + } + if (result == null || result.queryResult == null) { + return null; + } + PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); + + Document doc = convertStringToXMLDocument(result.queryResult); + if (doc == null) { + return null; + } + + // System.out.println(pamXMLWriter.getAsString(doc)); + + NodeList detsDocs = doc.getElementsByTagName("Detections"); + int[] blockCounts = new int[dataPrefixes.length]; + + // String detDocPrefix = projectId + "_" + dataBlock.getDataName(); + + // int totalCalls = 0; + int detCount = 0; + int dataIndex; + for (int i = 0; i < detsDocs.getLength(); i++) { + Node detNode = detsDocs.item(i); + + NodeList childNodes = detNode.getChildNodes(); + detCount = childNodes.getLength()-1; + dataIndex = -1; + for (int n = 0; n < childNodes.getLength(); n++) { + Node aNode = childNodes.item(n); + if (aNode instanceof Element) { + Element el = (Element) aNode; + String nodeName = el.getNodeName(); + if (nodeName.equals("Id")) { + String id = el.getTextContent(); + for (int j = 0; j < dataPrefixes.length; j++) { + if (id != null && id.startsWith(dataPrefixes[j])) { + dataIndex = j; + } + } + // if (id != null && id.startsWith(detDocPrefix) == false) { + // detCount = 0; + // break; + // } + } + } + } + if (dataIndex >= 0) { + blockCounts[dataIndex] += detCount; + } + // System.out.printf("%d Added %d for new total %d\n",i, detCount, totalCalls); + } + + return blockCounts; + } + + public String getElementData(Element root, String elName) { + String[] tree = elName.split("\\."); + for (String element : tree) { + NodeList nodeList = root.getElementsByTagName(element); + // should only be one node for what we're unpacking. + if (nodeList == null || nodeList.getLength() == 0) { + return null; + } + int count = nodeList.getLength(); + for (int i = 0; i < count; i++) { + Node firstNode = nodeList.item(i); + if (firstNode instanceof Element) { + root = (Element) firstNode; + break; + } + } + } + return root.getTextContent(); + } + + + public String getElementAttribute(Element root, String elName, String attribute) { + String[] tree = elName.split("\\."); + for (String element : tree) { + NodeList nodeList = root.getElementsByTagName(element); + // should only be one node for what we're unpacking. + if (nodeList == null || nodeList.getLength() == 0) { + return null; + } + int count = nodeList.getLength(); + for (int i = 0; i < count; i++) { + Node firstNode = nodeList.item(i); + if (firstNode instanceof Element) { + root = (Element) firstNode; + break; + } + } + } + return root.getAttribute(attribute); + } + + public Document convertStringToXMLDocument(String xmlString) { + //Parser that produces DOM object trees from XML content + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + //API to obtain DOM Document instance + DocumentBuilder builder = null; + try { + //Create DocumentBuilder with default configuration + builder = factory.newDocumentBuilder(); + + //Parse the content to Document object + Document doc = builder.parse(new InputSource(new StringReader(xmlString))); + return doc; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Get the basic information about a Detections document. This is basically everything apart from + * the actual detections themselves. + * @param aDoc + * @return + */ + public Detections getDetectionsDocInfo(String detectionsDocName) { +// String oldqueryBase = "{\"species\":{\"query\":{\"op\":\"lib:abbrev2tsn\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]},\"return\":{\"op\":\"lib:tsn2abbrev\",\"optype\":\"function\",\"operands\":[\"%s\",\"SIO.SWAL.v1\"]}},\"return\":[\"Detections/Id\",\"Detections/Description\",\"Detections/DataSource\",\"Detections/Algorithm\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Id\",\"DetectionsDocName\"],\"optype\":\"binary\"}],\"enclose\":1}"; + // updated May 23 + String queryBase = "{\"species\":{\"query\":{\"op\":\"lib:completename2tsn\",\"optype\":\"function\",\"operands\":[\"%s\"]},\"return\":{\"op\":\"lib:tsn2completename\",\"optype\":\"function\",\"operands\":[\"%s\"]}},\"return\":[\"Detections/Id\",\"Detections/Description\",\"Detections/DataSource\",\"Detections/Algorithm\",\"Detections/QualityAssurance\",\"Detections/UserId\",\"Detections/MetadataInfo\",\"Detections/Effort\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Detections/Id\",\"DetectionsDocName\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String query = queryBase.replace("DetectionsDocName", detectionsDocName); + DBQueryResult queryResult; + try { + queryResult = executeQuery(query); + } catch (TethysQueryException e) { + tethysControl.showException(e); + return null; + } + Document doc; + try { + doc = queryResult.getDocument(); + } catch (ParserConfigurationException | SAXException | IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + // System.out.println(queryResult.queryResult); + + Detections detections = new Detections(); + try { + Helper.createRequiredElements(detections); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + e.printStackTrace(); + } + + NodeList returns = doc.getElementsByTagName("Result"); + // System.out.println("N projects = " + returns.getLength()); + int n = returns.getLength(); + if (n == 0) { + return null; + } + Element result = (Element) returns.item(0); + + DescriptionType description = detections.getDescription(); + if (description == null) { + description = new DescriptionType(); + detections.setDescription(description); + } + detections.setId(getElementData(result, "Id")); + description.setAbstract(getElementData(result, "Description.Abstract")); + description.setMethod(getElementData(result, "Description.Method")); + description.setObjectives(getElementData(result, "Description.Objectives")); + + String deployment = getElementData(result, "DataSource.DeploymentId"); + if (deployment != null) { + DataSourceType dataSource = detections.getDataSource(); + if (dataSource == null) { + dataSource = new DataSourceType(); + detections.setDataSource(dataSource); + } + dataSource.setDeploymentId(deployment); + } + + // get the effort start an end + String effStart = getElementData(result, "Effort.Start"); + String effEnd = getElementData(result, "Effort.End"); + detections.getEffort().setStart(TethysTimeFuncs.fromGregorianXML(effStart)); + detections.getEffort().setEnd(TethysTimeFuncs.fromGregorianXML(effEnd)); + // try to find the granularity. + String granularityString = getElementData(result, "Effort.Kind.Granularity"); + GranularityEnumType granularity = null; + if (granularityString != null) { + granularity = GranularityEnumType.fromValue(granularityString); + List kinds = detections.getEffort().getKind(); + DetectionEffortKind kind = new DetectionEffortKind(); + GranularityType granularityType = new GranularityType(); + granularityType.setValue(granularity); + kind.setGranularity(granularityType); + // try to find the rest of the granularity information. + String binSize_m = getElementAttribute(result, "Effort.Kind.Granularity", "BinSize_m"); + String encounterGap_m = getElementAttribute(result, "Effort.Kind.Granularity", "EncounterGap_m"); + String firstBinStart = getElementAttribute(result, "Effort.Kind.Granularity", "FirstBinStart"); + try { + granularityType.setBinSizeMin(Double.valueOf(binSize_m)); + } + catch (NumberFormatException e) { + } + try { + granularityType.setEncounterGapMin(Double.valueOf(encounterGap_m)); + } + catch (NumberFormatException e) { + } + + kinds.add(kind); + } + // String + + + + // TODO Auto-generated method stub + return detections; + } + +} diff --git a/src/tethys/dbxml/DMXMLQueryTest.java b/src/tethys/dbxml/DMXMLQueryTest.java new file mode 100644 index 00000000..e16e202a --- /dev/null +++ b/src/tethys/dbxml/DMXMLQueryTest.java @@ -0,0 +1,79 @@ +package tethys.dbxml; + +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +import PamController.settings.output.xml.PamguardXMLWriter; +import dbxml.JerseyClient; +import tethys.output.TethysExportParams; + +public class DMXMLQueryTest { + + public static void main(String[] args) { + new DMXMLQueryTest().runTest(); + } + + private void runTest() { + TethysExportParams params = new TethysExportParams(); + + JerseyClient jerseyClient = new JerseyClient(params.getFullServerName()); + +// String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/DeploymentId\",\"Deployment/Site\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\"],\"select\":[],\"enclose\":1}"; +// String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/Region\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/DeploymentId\",\"2\"],\"optype\":\"binary\"}],\"enclose\":1}"; + //String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/Region\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/DeploymentId\",\"2\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}"; +// String testJson = "{\"return\":[\"Deployment/Project\",\"Deployment/Region\",\"Deployment/DeploymentDetails/AudioTimeStamp\",\"Deployment/RecoveryDetails/AudioTimeStamp\",\"Deployment/DeploymentId\"],\"select\":[{\"op\":\"=\",\"operands\":[\"Deployment/DeploymentId\",\"2\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Deployment/Project\",\"DCLDE2022\"],\"optype\":\"binary\"}],\"enclose\":1}"; + String testJson = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}"; + // web browse to http://localhost:9779/Client + + String testResult = jerseyClient.queryJSON(testJson); + + Document doc = convertStringToXMLDocument(testResult); + + PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); + String formettedXML = pamXMLWriter.getAsString(doc, true); + + System.out.println(testResult); + System.out.println(formettedXML); +// try { +// Transformer serializer = SAXTransformerFactory.newInstance() +// .newTransformer(); +// Source source = new StreamSource(testResult); +// ByteArrayOutputStream bytes = new ByteArrayOutputStream(); +// StreamResult res = new StreamResult(bytes); +// serializer.transform(source, res); +// System.out.println(bytes.toString()); +// } catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) { +// e.printStackTrace(); +// } +// // System.err.println(testResult); +// catch (TransformerException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + + } + + private Document convertStringToXMLDocument(String xmlString) { + //Parser that produces DOM object trees from XML content + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + //API to obtain DOM Document instance + DocumentBuilder builder = null; + try { + //Create DocumentBuilder with default configuration + builder = factory.newDocumentBuilder(); + + //Parse the content to Document object + Document doc = builder.parse(new InputSource(new StringReader(xmlString))); + return doc; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/tethys/dbxml/ServerStatus.java b/src/tethys/dbxml/ServerStatus.java new file mode 100644 index 00000000..25c9ebbf --- /dev/null +++ b/src/tethys/dbxml/ServerStatus.java @@ -0,0 +1,35 @@ +package tethys.dbxml; + +public class ServerStatus { + + public boolean ok; + + public Exception error; + + public ServerStatus(boolean ok, Exception error) { + super(); + this.ok = ok; + this.error = error; + } + + public String getFormatted() { + if (ok) { + return "Server OK"; + } + if (error == null) { + return "Unknown error"; + } + String msg = error.getLocalizedMessage(); + if (msg.startsWith("Exception")) { + msg.substring(9); + } + return msg; + } + + @Override + public String toString() { + return getFormatted(); + } + + +} diff --git a/src/tethys/dbxml/TethysException.java b/src/tethys/dbxml/TethysException.java new file mode 100644 index 00000000..034a1970 --- /dev/null +++ b/src/tethys/dbxml/TethysException.java @@ -0,0 +1,18 @@ +package tethys.dbxml; + +public class TethysException extends Exception { + + private static final long serialVersionUID = 1L; + + private String xmlError; + + public TethysException(String message, String xmlError) { + super(message); + this.xmlError = xmlError; + } + + public String getXmlError() { + return xmlError; + } + +} diff --git a/src/tethys/dbxml/TethysQueryException.java b/src/tethys/dbxml/TethysQueryException.java new file mode 100644 index 00000000..7f46d7bc --- /dev/null +++ b/src/tethys/dbxml/TethysQueryException.java @@ -0,0 +1,19 @@ +package tethys.dbxml; + +public class TethysQueryException extends TethysException { + + + private static final long serialVersionUID = 1L; + + private String queryString; + + public TethysQueryException(String message, String queryString) { + super(message, null); + this.queryString = queryString; + } + + public String getQueryString() { + return queryString; + } + +} diff --git a/src/tethys/deployment/DeploymentExportOpts.java b/src/tethys/deployment/DeploymentExportOpts.java new file mode 100644 index 00000000..18fa461f --- /dev/null +++ b/src/tethys/deployment/DeploymentExportOpts.java @@ -0,0 +1,43 @@ +package tethys.deployment; + +import java.io.Serializable; + +/** + * options for Deployment export collected by the export Wizard. + * @author dg50 + * + */ +public class DeploymentExportOpts implements Serializable, Cloneable { + + public static final long serialVersionUID = 1L; + + public boolean separateDeployments; + + /** + * Minimum number of seconds between GPS points in a track. + */ + public double trackPointInterval; + + /** + * Max gap before recording periods are separated, potentially into + * separate Deployment documents + */ + public int maxRecordingGapSeconds = 60; + + /** + * A recording section after joining with max gap parameter is too short + * to be worth keeping. + */ + public int minRecordingLengthSeconds = 10; + + @Override + protected DeploymentExportOpts clone() { + try { + return (DeploymentExportOpts) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/tethys/deployment/DeploymentHandler.java b/src/tethys/deployment/DeploymentHandler.java new file mode 100644 index 00000000..0c435fc0 --- /dev/null +++ b/src/tethys/deployment/DeploymentHandler.java @@ -0,0 +1,1310 @@ +package tethys.deployment; + +import java.awt.Window; +import java.io.Serializable; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.ListIterator; + +import javax.xml.bind.JAXBException; +import javax.xml.datatype.XMLGregorianCalendar; + +import org.apache.commons.beanutils.converters.BigIntegerConverter; + +import Acquisition.AcquisitionControl; +import Acquisition.AcquisitionParameters; +import Acquisition.DaqStatusDataUnit; +import Acquisition.DaqSystem; +import Acquisition.FolderInputSystem; +import Array.ArrayManager; +import Array.Hydrophone; +import Array.HydrophoneLocator; +import Array.PamArray; +import Array.Streamer; +import Array.ThreadingHydrophoneLocator; +import GPS.GPSControl; +import GPS.GPSDataBlock; +import GPS.GpsData; +import GPS.GpsDataUnit; +import PamController.PamSensor; +import PamController.PamSettingManager; +import PamController.PamSettings; +import PamController.PamControlledUnit; +import PamController.PamControlledUnitSettings; +import PamController.PamController; +import PamUtils.PamUtils; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamRawDataBlock; +import binaryFileStorage.BinaryStore; +import dataMap.OfflineDataMap; +import dataMap.OfflineDataMapPoint; +import generalDatabase.DBControlUnit; +import metadata.MetaDataContol; +import metadata.PamguardMetaData; +import nilus.AcousticDataQAType; +import nilus.AcousticDataQAType.Quality; +import nilus.AcousticDataQAType.Quality.FrequencyRange; +import nilus.Audio; +import nilus.ChannelInfo; +import nilus.ChannelInfo.DutyCycle; +import nilus.ChannelInfo.DutyCycle.Regimen.RecordingDurationS; +import nilus.ChannelInfo.DutyCycle.Regimen.RecordingIntervalS; +import nilus.ChannelInfo.Sampling; +import nilus.ChannelInfo.Sampling.Regimen; +import nilus.Deployment; +import nilus.Deployment.Data; +import nilus.Deployment.Data.Tracks; +import nilus.Deployment.Data.Tracks.Track; +import nilus.Deployment.Data.Tracks.Track.Point; +import nilus.Deployment.Data.Tracks.Track.Point.BearingDegN; +import nilus.Deployment.Instrument; +import nilus.Deployment.SamplingDetails; +import nilus.Deployment.Sensors; +import nilus.DeploymentRecoveryDetails; +import nilus.DescriptionType; +import nilus.GeometryTypeM; +import nilus.Helper; +import nilus.MetadataInfo; +import nilus.UnknownSensor; +import pamMaths.PamVector; +import pamMaths.STD; +import tethys.Collection; +import tethys.TethysControl; +import tethys.TethysLocationFuncs; +import tethys.TethysState; +import tethys.TethysStateObserver; +import tethys.TethysTimeFuncs; +import tethys.calibration.CalibrationHandler; +import tethys.TethysState.StateType; +import tethys.dbxml.DBXMLConnect; +import tethys.dbxml.TethysException; +import tethys.deployment.swing.DeploymentWizard; +import tethys.deployment.swing.RecordingGapDialog; +import tethys.niluswraps.PDeployment; +import tethys.output.TethysExportParams; +import tethys.pamdata.AutoTethysProvider; +import tethys.reporter.TethysReporter; +import tethys.swing.DeploymentTableObserver; + +/** + * Functions to gather data for the deployment document from all around PAMGuard. + * There should be just one of these, available from TethysControl and it will try + * to sensible handle when and how it updates it's list of PAMGuard and Tethys information + *
Any part of PAMGuard wanting information on Deployments should come here. + * @author dg50 + * + */ +public class DeploymentHandler implements TethysStateObserver, DeploymentTableObserver { + + private TethysControl tethysControl; + + /** + * @return the tethysControl + */ + public TethysControl getTethysControl() { + return tethysControl; + } + + private EffortFunctions effortFunctions; + + private DeploymentOverview deploymentOverview; + + private ArrayList projectDeployments; + + private Helper nilusHelper; + + private DeploymentExportOpts deploymentExportOptions = new DeploymentExportOpts(); + + public DeploymentHandler(TethysControl tethysControl) { + super(); + + this.tethysControl = tethysControl; + + this.effortFunctions = new EffortFunctions(tethysControl); + + tethysControl.addStateObserver(this); + try { + nilusHelper = new Helper(); + } catch (JAXBException e) { + e.printStackTrace(); + } + + PamSettingManager.getInstance().registerSettings(new SettingsHandler()); + } + + /** + * Gather up all track information both from the GPS module (if it exists) and + * the type of hydrophone array (or many!) + * @return + */ + public TrackInformation getTrackInformation() { + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + int nStreamers = array.getStreamerCount(); + HydrophoneLocator locator = null; + for (int i = 0; i < nStreamers; i++) { + Streamer aStreamer = array.getStreamer(i); + locator = aStreamer.getHydrophoneLocator(); +// locator.getLocatorSettings(). + } + // try to find a GPS datablock and see what's in it's datamap. + OfflineDataMap gpsDataMap = null; + GPSControl gpsControl = (GPSControl) PamController.getInstance().findControlledUnit(GPSControl.gpsUnitType); + if (gpsControl != null) { + GPSDataBlock gpsDataBlock = gpsControl.getGpsDataBlock(); + gpsDataMap = gpsDataBlock.getPrimaryDataMap(); + } + TrackInformation trackInformation = new TrackInformation(gpsDataMap, locator); + return trackInformation; + } + + @Override + public void updateState(TethysState tethysState) { + switch (tethysState.stateType) { + case NEWPROJECTSELECTION: + updateProjectDeployments(); + break; + case EXPORTRDATA: + case DELETEDATA: + updateProjectDeployments(); + break; + case UPDATESERVER: + updateProjectDeployments(); + break; + default: + break; + } + } + + /** + * Update the list of Tethys deployments + * @return true if OK + */ + public boolean updateProjectDeployments() { + Deployment projData = tethysControl.getGlobalDeplopymentData(); + ArrayList tethysDocs = tethysControl.getDbxmlQueries().getProjectDeployments(projData.getProject(), getInstrumentId()); + if (tethysDocs == null) { + return false; + } + projectDeployments = new ArrayList<>(); + for (Deployment deployment : tethysDocs) { + projectDeployments.add(new PDeployment(deployment)); + } + matchPamguard2Tethys(deploymentOverview, projectDeployments); + tethysControl.sendStateUpdate(new TethysState(TethysState.StateType.NEWPAMGUARDSELECTION)); + return true; + } + + /** + * Get a list of Tethys deployment docs. Note that this + * doesn't update the list, but uses the one currently in memory + * so call updateTethysDeployments() first if necessary. + * @return list of (wrapped) nilus Deployment objects. + */ + public ArrayList getProjectDeployments() { + if (projectDeployments == null) { + updateProjectDeployments(); + } + return projectDeployments; + } + +// /** +// * Get an overview of all the deployments. +// * @return +// */ +// public DeploymentOverview createPamguardOverview() { +// // first find an acquisition module. +// PamControlledUnit aModule = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null); +// if (!(aModule instanceof AcquisitionControl)) { +// // will return if it's null. Impossible for it to be the wrong type. +// // but it's good practice to check anyway before casting. +// return null; +// } +// // cast it to the right type. +// AcquisitionControl daqControl = (AcquisitionControl) aModule; +// AcquisitionParameters daqParams = daqControl.getAcquisitionParameters(); +// /** +// * The daqParams class has most of what we need about the set up in terms of sample rate, +// * number of channels, instrument type, ADC input range (part of calibration), etc. +// * It also has a hydrophone list, which maps the input channel numbers to the hydrophon numbers. +// * Realistically, this list is always 0,1,2,etc or it goes horribly wrong ! +// */ +// // so write functions here to get information from the daqParams. +//// System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(), +//// daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak); +// /** +// * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map +// * but the datamap is a simple count of what's in the databasase which is not quite what we want. +// * we're going to have to query the database to get more detailed informatoin I think. +// * I'll do that here for now, but we may want to move this when we better organise the code. +// * It also seems that there are 'bad' dates in the database when it starts new files, which are the date +// * data were analysed at. So we really need to check the start and stop records only. +// */ +// PamDataBlock daqInfoDataBlock = daqControl.getAcquisitionProcess().getDaqStatusDataBlock(); +// // just load everything. Probably OK for the acqusition, but will bring down +// daqInfoDataBlock.loadViewerData(0, Long.MAX_VALUE, null); +// ArrayList allStatusData = daqInfoDataBlock.getDataCopy(); +// /** +// * Due to seird file overlaps we need to resort this by id if we can. +// * +// */ +// Collections.sort(allStatusData, new Comparator() { +// +// @Override +// public int compare(DaqStatusDataUnit o1, DaqStatusDataUnit o2) { +// if (o1.getDatabaseIndex() == 0) { +// return (int) (o1.getTimeMilliseconds()-o2.getTimeMilliseconds()); +// } +// return o1.getDatabaseIndex()-o2.getDatabaseIndex(); +// } +// }); +// +// ArrayList tempPeriods = null; +// +// if (allStatusData == null || allStatusData.size() == 0) { +// System.out.println("Data appear to have no logged recording periods. Try to extract from raw audio ..."); +// tempPeriods = extractTimesFromFiles(daqControl); +// } +// else { +// tempPeriods = extractTimesFromStatus(allStatusData); +// } +// if (tempPeriods == null || tempPeriods.size() == 0) { +// System.out.println("Data appear to have no logged recording periods available either from the database or the raw recordings."); +// tempPeriods = extractTimesFromOutputMaps(); +// } +// if (tempPeriods == null || tempPeriods.size() == 0) { +// System.out.println("Data appear to have no logged recording periods available either from the database or the raw recordings."); +// return null; +// } +// +// int nPeriods = tempPeriods.size(); +//// int i = 0; +//// for (RecordingPeriod aP : tempPeriods) { +//// System.out.printf("Pre merge %d : %s to %s\n", i++, PamCalendar.formatDBDateTime(aP.getRecordStart()), +//// PamCalendar.formatDBDateTime(aP.getRecordStop())); +//// } +// // now go through those and merge into longer periods where there is no gap between files. +// ListIterator iterator = tempPeriods.listIterator(); +// RecordingPeriod prevPeriod = null; +// while (iterator.hasNext()) { +// RecordingPeriod nextPeriod = iterator.next(); +// long nextDur = nextPeriod.getRecordStop()-nextPeriod.getRecordStart(); +// if (nextDur == 0) { +// continue; +// } +// if (prevPeriod != null) { +// long gap = nextPeriod.getRecordStart() - prevPeriod.getRecordStop(); +// long prevDur = prevPeriod.getRecordStop()-prevPeriod.getRecordStart(); +// if (gap < exportOptions.maxGapSeconds*1000) { +// // ignoring up to 3s gap or a sample error < 2%.Dunno if this is sensible or not. +// prevPeriod.setRecordStop(nextPeriod.getRecordStop()); +// iterator.remove(); +// nextPeriod = prevPeriod; +// } +// } +// prevPeriod = nextPeriod; +// } +// // now remove ones which are too short even after merging. +// iterator = tempPeriods.listIterator(); +// while (iterator.hasNext()) { +// RecordingPeriod nextPeriod = iterator.next(); +// long duration = nextPeriod.getDuration(); +// if (duration < exportOptions.minLengthSeconds*1000L) { +// iterator.remove(); +// } +// } +//// i = 0; +//// for (RecordingPeriod aP : tempPeriods) { +//// System.out.printf("Post merge %d : %s to %s\n", i++, PamCalendar.formatDBDateTime(aP.getRecordStart()), +//// PamCalendar.formatDBDateTime(aP.getRecordStop())); +//// } +//// System.out.printf("Data have %d distinct files, but only %d distinct recording periods\n", nPeriods, tempPeriods.size()); +// DutyCycleInfo dutyCycleinfo = assessDutyCycle(tempPeriods); +// // if it's duty cycles, then we only want a single entry. +// ArrayList deploymentPeriods; +// if (dutyCycleinfo.isDutyCycled == false) { +// deploymentPeriods = tempPeriods; +// } +// else { +// deploymentPeriods = new ArrayList<>(); +// deploymentPeriods.add(new RecordingPeriod(tempPeriods.get(0).getRecordStart(), tempPeriods.get(tempPeriods.size()-1).getRecordStop())); +// } +// /* +// * do another sort of the deploymentPeriods. The start stops were in the order they went into the +// * database in the hope that pairs were the right way round. Now check all data are/ +// */ +// Collections.sort(deploymentPeriods, new Comparator() { +// @Override +// public int compare(RecordingPeriod o1, RecordingPeriod o2) { +// return (int) (o1.getRecordStart()-o2.getRecordStart()); +// } +// }); +// +// DeploymentOverview deploymentOverview = new DeploymentOverview(dutyCycleinfo, deploymentPeriods); +// matchPamguard2Tethys(deploymentOverview, projectDeployments); +// this.deploymentOverview = deploymentOverview; +// return deploymentOverview; +// // find the number of times it started and stopped .... +//// System.out.printf("Input map of sound data indicates data from %s to %s with %d starts and %d stops over %d files\n", +//// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), nStart, nStop, nFile+1); +// // now work out where there are genuine gaps and make up a revised list of recording periods. +// +// +// } + + public void showOptions(Window parent) { + if (parent == null) { + parent = tethysControl.getGuiFrame(); + } + DeploymentExportOpts newOpts = RecordingGapDialog.showDiloag(parent, deploymentExportOptions); + if (newOpts != null) { + deploymentExportOptions = newOpts; + createPamguardOverview(); + } + } + + public void createPamguardOverview() { + deploymentOverview = effortFunctions.makeRecordingOverview(); + updateProjectDeployments(); + matchPamguard2Tethys(deploymentOverview, projectDeployments); + } + + /** + * Export button pressed on GUI. Run wizard.... + */ + public void exportDeployments() { + Deployment deployment = MetaDataContol.getMetaDataControl().getMetaData().getDeployment(); + DeploymentExportOpts exportOptions = DeploymentWizard.showWizard(getTethysControl().getGuiFrame(), tethysControl, deployment, this.deploymentExportOptions); + if (exportOptions != null) { + this.deploymentExportOptions = exportOptions; + deploymentOverview = getDeploymentOverview(); + ArrayList allPeriods = deploymentOverview.getRecordingPeriods(); + exportDeployments(allPeriods); + } + } + + /** + * Export deployments docs. Playing with a couple of different ways of doing this. + * @param selectedDeployments + */ + public void exportDeployments(ArrayList selectedDeployments) { + TethysReporter.getTethysReporter().clear(); + if (deploymentExportOptions.separateDeployments) { + exportSeparateDeployments(selectedDeployments); + } + else { + exportOneDeploymnet(selectedDeployments); + } + TethysReporter.getTethysReporter().showReport(tethysControl.getGuiFrame(), true); + } + + /** + * Make one big deployment document with all the recording periods in it. + */ + private void exportOneDeploymnet(ArrayList selectedDeployments) { + // do the lot, whatever ... + Float sampleRate = null; + AcquisitionControl daq = (AcquisitionControl) PamController.getInstance().findControlledUnit(AcquisitionControl.class, null); + if (daq != null) { + DaqSystem system = daq.findDaqSystem(null); + AcquisitionParameters daqParams = daq.acquisitionParameters; + sampleRate = daqParams.sampleRate; + } + + selectedDeployments = getDeploymentOverview().getRecordingPeriods(); + int freeId = getTethysControl().getDeploymentHandler().getFirstFreeDeploymentId(); + RecordingPeriod onePeriod = new RecordingPeriod(selectedDeployments.get(0).getRecordStart(), + selectedDeployments.get(selectedDeployments.size()-1).getRecordStop()); + TethysExportParams exportParams = tethysControl.getTethysExportParams(); + String id = String.format("%s_%s", exportParams.getDatasetName(), "all"); + Deployment deployment = createDeploymentDocument(freeId, onePeriod, id); + // fill in a few things from here + Deployment globalMeta = getTethysControl().getGlobalDeplopymentData(); + deployment.setCruise(globalMeta.getCruise()); + deployment.setSite(globalMeta.getSite()); + if (selectedDeployments.size() > 1) { +// // now need to remove the sampling details - don't though, add invalid periods instead. +// SamplingDetails samplingDetails = deployment.getSamplingDetails(); +// samplingDetails.getChannel().clear(); +// for (int i = 0; i < selectedDeployments.size(); i++) { +// addSamplingDetails(deployment, selectedDeployments.get(i)); +// } + /* + * Instead, we're putting invalid periods into the QA section. + */ + AcousticDataQAType qa = deployment.getQualityAssurance(); + if (qa == null) { + deployment.setQualityAssurance(qa = new AcousticDataQAType()); + } + List qualityList = qa.getQuality(); + for (int i = 1; i < selectedDeployments.size(); i++) { + long end = selectedDeployments.get(i-1).getRecordStop(); + long start = selectedDeployments.get(i).getRecordStart(); + Quality q = new Quality(); + q.setStart(TethysTimeFuncs.xmlGregCalFromMillis(end)); + q.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(start)); + q.setCategory("unusable"); + if (sampleRate != null) { + FrequencyRange f = q.getFrequencyRange(); + if (f == null) { + q.setFrequencyRange(f = new FrequencyRange()); + } + f.setLowHz(0); + f.setHighHz(sampleRate/2); + } + q.setComment("No data (probably off or out of water)"); + qualityList.add(q); + } + } + DBXMLConnect dbxmlConnect = getTethysControl().getDbxmlConnect(); + PDeployment exDeploymnet = onePeriod.getMatchedTethysDeployment(); + try { + if (exDeploymnet != null) { + deployment.setId(exDeploymnet.deployment.getId()); + dbxmlConnect.updateDocument(deployment); + } + else { + dbxmlConnect.postAndLog(deployment); + } + } + catch (TethysException e) { + getTethysControl().showException(e); + } + getTethysControl().sendStateUpdate(new TethysState(StateType.UPDATESERVER, Collection.Deployments)); + } + + /** + * Make a separate deployment document for every recording period. + */ + private void exportSeparateDeployments(ArrayList selectedDeployments) { + + int freeId = getTethysControl().getDeploymentHandler().getFirstFreeDeploymentId(); + // fill in a few things from here + Deployment globalMeta = getTethysControl().getGlobalDeplopymentData(); + TethysExportParams exportParams = tethysControl.getTethysExportParams(); + for (int i = 0; i < selectedDeployments.size(); i++) { + RecordingPeriod recordPeriod = selectedDeployments.get(i); + PDeployment exDeploymnet = recordPeriod.getMatchedTethysDeployment(); + Deployment deployment = null; + String id = String.format("%s_%d", exportParams.getDatasetName(), i); + if (exDeploymnet != null) { + deployment = createDeploymentDocument(freeId, recordPeriod, id); + deployment.setId(exDeploymnet.deployment.getId()); + } + if (deployment == null) { + deployment = createDeploymentDocument(freeId++, recordPeriod, id); + } + deployment.setCruise(globalMeta.getCruise()); + deployment.setSite(globalMeta.getSite()); + // also need to sort out track data here, etc. + DBXMLConnect dbxmlConnect = getTethysControl().getDbxmlConnect(); + try { + if (exDeploymnet != null) { + dbxmlConnect.updateDocument(deployment); + } + else { + dbxmlConnect.postAndLog(deployment); + } + } + catch (TethysException e) { + getTethysControl().showException(e); + } + } + getTethysControl().sendStateUpdate(new TethysState(StateType.UPDATESERVER, Collection.Deployments)); + } + + + + public DeploymentOverview getDeploymentOverview() { + return deploymentOverview; + } + + /** + * Match what we think the PAMGuard deployment times are with Tethys Deployments read back + * from the database. + * @param deploymentOverview + * @param deployments + */ + private void matchPamguard2Tethys(DeploymentOverview deploymentOverview, ArrayList deployments) { + if (deployments == null || deploymentOverview == null) { + return; + } + ArrayList recordingPeriods = deploymentOverview.getRecordingPeriods(); + for (RecordingPeriod aPeriod : recordingPeriods) { + PDeployment closestDeployment = findClosestDeployment(aPeriod, deployments); + aPeriod.setMatchedTethysDeployment(closestDeployment); + if (closestDeployment != null) { + closestDeployment.setMatchedPAMGaurdPeriod(aPeriod); + } + } + } + + /** + * find the Tethys deployment that most closely matches the PAMGuard recording period. + * @param aPeriod + * @param deployments + * @return + */ + private PDeployment findClosestDeployment(RecordingPeriod aPeriod, ArrayList deployments) { + double overlap = -1; + PDeployment bestDeployment = null; + for (PDeployment aDeployment : deployments) { + double newOverlap = getDeploymentOverlap(aDeployment, aPeriod); + if (newOverlap > overlap) { + bestDeployment = aDeployment; + overlap = newOverlap; + } + } + return bestDeployment; + } + + /** + * Get the overlap in mills between a nilus Deployment and a PAMGuard recording period + * @param aDeployment nilus Deployment from Tethys + * @param aPeriod PAMGuard recording period + * @return overlap in milliseconds + */ + public long getDeploymentOverlap(PDeployment aDeployment, RecordingPeriod aPeriod) { + long start = aPeriod.getRecordStart(); // recording period. + long stop = aPeriod.getRecordStop(); + Long depStart = aDeployment.getAudioStart(); + Long depStop = aDeployment.getAudioEnd(); + if (depStart == null || depStop == null) { + return -1; + } + long overlap = (Math.min(stop, depStop)-Math.max(start, depStart)); + return overlap; + } + + + + + /** + * Get a list of Tethys Deployment docs that match the current PAMGuard data. Watch for repeats + * if a single deployment doc covers many perdiods. + * @return + */ + public ArrayList getMatchedDeployments() { + ArrayList matched = new ArrayList<>(); + if (deploymentOverview == null) { + return matched; + } + for (RecordingPeriod period : deploymentOverview.getRecordingPeriods()) { + PDeployment deployment = period.getMatchedTethysDeployment(); + if (deployment != null) { + if (matched.contains(deployment) == false) { + matched.add(period.getMatchedTethysDeployment()); + } + } + } + return matched; + } + + /** + * Get a list of instruments from the current project deployments. + * This may be a shorter list than the list of deployments. + * @return + */ + public ArrayList getProjectInstruments() { + if (projectDeployments == null) { + return null; + } + ArrayList instruments = new ArrayList<>(); + for (PDeployment aDepl : projectDeployments) { + Instrument intr = aDepl.deployment.getInstrument(); + if (intr == null) { + continue; + } + PInstrument pInstr = new PInstrument(intr.getType(), intr.getInstrumentId()); + if (instruments.contains(pInstr) == false) { + instruments.add(pInstr); + } + } + return instruments; + } + //in each channel +// public ArrayList getDeployments() { +// +// DeploymentOverview recordingOverview = this.deploymentOverview; +// +// // first find an acquisition module. +// PamControlledUnit aModule = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null); +// if (!(aModule instanceof AcquisitionControl)) { +// // will return if it's null. Impossible for it to be the wrong type. +// // but it's good practice to check anyway before casting. +// return null; +// } +// // cast it to the right type. +// AcquisitionControl daqControl = (AcquisitionControl) aModule; +// AcquisitionParameters daqParams = daqControl.getAcquisitionParameters(); +// /** +// * The daqParams class has most of what we need about the set up in terms of sample rate, +// * number of channels, instrument type, ADC input range (part of calibration), etc. +// * It also has a hydrophone list, which maps the input channel numbers to the hydrophon numbers. +// * Realistically, this list is always 0,1,2,etc or it goes horribly wrong ! +// */ +// // so write functions here to get information from the daqParams. +//// System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(), +//// daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak); +// /** +// * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map +// * but the datamap is a simple count of what's in the databasase which is not quite what we want. +// * we're going to have to query the database to get more detailed informatoin I think. +// * I'll do that here for now, but we may want to move this when we better organise the code. +// * It also seems that there are 'bad' dates in the database when it starts new files, which are the date +// * data were analysed at. So we really need to check the start and stop records only. +// */ +// PamDataBlock daqInfoDataBlock = daqControl.getAcquisitionProcess().getDaqStatusDataBlock(); +// // just load everything. Probably OK for the acqusition, but will bring down +// daqInfoDataBlock.loadViewerData(0, Long.MAX_VALUE, null); +// ArrayList allStatusData = daqInfoDataBlock.getDataCopy(); +// long dataStart = Long.MAX_VALUE; +// long dataEnd = Long.MIN_VALUE; +// if (allStatusData != null && allStatusData.size() > 0) { +// // find the number of times it started and stopped .... +// int nStart = 0, nStop = 0, nFile=0; +// for (DaqStatusDataUnit daqStatus : allStatusData) { +// switch (daqStatus.getStatus()) { +// case "Start": +// nStart++; +// dataStart = Math.min(dataStart, daqStatus.getTimeMilliseconds()); +// break; +// case "Stop": +// nStop++; +// dataEnd = Math.max(dataEnd, daqStatus.getEndTimeInMilliseconds()); +// break; +// case "NextFile": +// nFile++; +// break; +// } +// } +// +//// System.out.printf("Input map of sound data indicates data from %s to %s with %d starts and %d stops over %d files\n", +//// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), nStart, nStop, nFile+1); +// +// } +// +//// // and we find the datamap within that ... +//// OfflineDataMap daqMap = daqInfoDataBlock.getOfflineDataMap(DBControlUnit.findDatabaseControl()); +//// if (daqMap != null) { +//// // iterate through it. +//// long dataStart = daqMap.getFirstDataTime(); +//// long dataEnd = daqMap.getLastDataTime(); +//// List mapPoints = daqMap.getMapPoints(); +//// System.out.printf("Input map of sound data indicates data from %s to %s with %d individual files\n", +//// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), mapPoints.size()); +//// /* +//// * clearly in the first database I've been looking at of Tinas data, this is NOT getting sensible start and +//// * end times. Print them out to see what's going on. +//// */ +////// for () +//// } +// DeploymentRecoveryPair pair = new DeploymentRecoveryPair(); +// DeploymentRecoveryDetails deployment = new DeploymentRecoveryDetails(); +// DeploymentRecoveryDetails recovery = new DeploymentRecoveryDetails(); +// pair.deploymentDetails = deployment; +// pair.recoveryDetails = recovery; +// +// deployment.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataStart)); +// deployment.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataStart)); +// recovery.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataEnd)); +// recovery.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(dataEnd)); +// +// ArrayList drPairs = new ArrayList<>(); +// drPairs.add(pair); +// return drPairs; +// +// } + + /** + * Get the first free deploymendId. This will get appended to + * the ProjectName to make and id for each Deployment document + * @return + */ + public int getFirstFreeDeploymentId() { + /** + * This is an integer used for the DeploymentId. Note that the String Id (currentl9) is just the Project name + * appended with this number. + */ + int firstFree = 0; + if (projectDeployments != null) { + for (PDeployment dep : projectDeployments) { + firstFree = Math.max(firstFree, dep.deployment.getDeploymentId()+1); + } + } + return firstFree; + } + + public Deployment createDeploymentDocument(int i, RecordingPeriod recordingPeriod, String deploymentId) { + Deployment deployment = new Deployment(); + try { + nilus.Helper.createRequiredElements(deployment); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + PamguardMetaData pamguardMetaData = MetaDataContol.getMetaDataControl().getMetaData(); + Deployment templateDeployment = pamguardMetaData.getDeployment(); + +// Deployment globalDeplData = tethysControl.getGlobalDeplopymentData(); + deployment.setId(deploymentId); + deployment.setDeploymentId(i); + + DeploymentRecoveryDetails deploymentDetails = deployment.getDeploymentDetails(); + if (deploymentDetails == null) { + deploymentDetails = new DeploymentRecoveryDetails(); + } + DeploymentRecoveryDetails recoveryDetails = deployment.getRecoveryDetails(); + if (recoveryDetails == null) { + recoveryDetails = new DeploymentRecoveryDetails(); + } + + deploymentDetails.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStart())); + recoveryDetails.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStop())); + // handle situation where deployment and recovery times are not the same as the audio times. + if (pamguardMetaData.useAudioForDeploymentTimes == false) { + if (templateDeployment.getDeploymentDetails().getAudioTimeStamp() != null) { + deploymentDetails.setTimeStamp(templateDeployment.getDeploymentDetails().getAudioTimeStamp()); + } + if (templateDeployment.getRecoveryDetails().getAudioTimeStamp() != null) { + recoveryDetails.setTimeStamp(templateDeployment.getRecoveryDetails().getAudioTimeStamp()); + } + } + + deploymentDetails.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStart())); + recoveryDetails.setAudioTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(recordingPeriod.getRecordStop())); + + deployment.setDeploymentDetails(deploymentDetails); + deployment.setRecoveryDetails(recoveryDetails); + + getProjectData(deployment); + + TethysLocationFuncs.getTrackAndPositionData(deployment); + + getTrackDetails(deployment); + + /** + * Get some of the meta data from the centralised source. + */ + MetadataInfo metaData = templateDeployment.getMetadataInfo(); + metaData.setDate(TethysTimeFuncs.xmlGregCalFromMillis(System.currentTimeMillis())); + metaData.setUpdateFrequency("as-needed"); + deployment.setMetadataInfo(metaData); + + deployment.setDescription(templateDeployment.getDescription()); +// DescriptionType description = deployment.getDescription(); +// if (description == null ) { +// description = new DescriptionType(); +// deployment.setDescription(description); +// description.setAbstract("No abstract"); +// description.setMethod("no methods"); +// description.setObjectives("No objectives"); +// } +// description.set + + addSamplingDetails(deployment, recordingPeriod); + + getSensorDetails(deployment); + + getSensors(deployment); + + /** + * Stuff that may need to be put into the UI: + * Audio: can easily get current loc of raw and binary data, but may need to override these. I think + * this may be for the export UI ? + * Tracks: trackline information. General problem in PAMGUard. + */ + getDataDetails(deployment); + + + return deployment; + } + + /** + * Add the track to the deployment, if there is one (i.e. not for + * a fixed sensor). + * @param deployment + */ + private void getTrackDetails(Deployment deployment) { + TrackInformation trackInfo = getTrackInformation(); + if (trackInfo.haveGPSTrack() == false) { + return; + } + GPSDataBlock gpsDataBlock = (GPSDataBlock) trackInfo.getGpsDataMap().getParentDataBlock(); + if (gpsDataBlock == null) { + return; + } + /* + * should have some track information. Do a load from the + * database for the whole deployment. this may be the entire GPS record, but + * we should be able to cope with that. + */ + long trackStart = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getTimeStamp()); + long trackEnd = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getTimeStamp()); + long dataWin =(long) (Math.max(1./trackInfo.getGPSDataRate(), deploymentExportOptions.trackPointInterval)); + + // get the tracks object. + Tracks tracks = deployment.getData().getTracks(); + if (tracks == null) { + tracks = new Tracks(); + deployment.getData().setTracks(tracks); + } + List trackList = tracks.getTrack(); // lists are usually there. + + Track aTrack = new Track(); + trackList.add(aTrack); + List points = aTrack.getPoint(); + + gpsDataBlock.loadViewerData(trackStart-dataWin, trackEnd+dataWin, null); + long lastPointTime = 0; + ListIterator it = gpsDataBlock.getListIterator(0); + while (it.hasNext()) { + GpsDataUnit gpsDataUnit = it.next(); + if (gpsDataUnit.getTimeMilliseconds()-lastPointTime < deploymentExportOptions.trackPointInterval*1000) { + continue; + } + GpsData gpsData = gpsDataUnit.getGpsData(); + Point gpsPoint = new Point(); + gpsPoint.setTimeStamp(TethysTimeFuncs.xmlGregCalFromMillis(gpsDataUnit.getTimeMilliseconds())); + gpsPoint.setLatitude(gpsData.getLatitude()); + gpsPoint.setLongitude(PamUtils.constrainedAngle(gpsData.getLongitude())); + BearingDegN bdn = gpsPoint.getBearingDegN(); + if (bdn == null) { + bdn = new BearingDegN(); + gpsPoint.setBearingDegN(bdn); + } + bdn.setValue(AutoTethysProvider.roundDecimalPlaces(PamUtils.constrainedAngle(gpsData.getHeading()),1)); + gpsPoint.setSpeedKn(AutoTethysProvider.roundDecimalPlaces(gpsData.getSpeed(),2)); + + points.add(gpsPoint); + lastPointTime = gpsDataUnit.getTimeMilliseconds(); + } + } + + public String getBinaryDataURI() { + BinaryStore binStore = BinaryStore.findBinaryStoreControl(); + if (binStore != null) { + return binStore.getBinaryStoreSettings().getStoreLocation(); + } + return null; + } + + public String getDatabaseURI() { + DBControlUnit databaseControl = DBControlUnit.findDatabaseControl(); + if (databaseControl != null) { + return databaseControl.getLongDatabaseName(); + } + return null; + } + + public String getRawDataURI() { + try { + PamControlledUnit daq = PamController.getInstance().findControlledUnit(AcquisitionControl.class, null); + if (daq instanceof AcquisitionControl) { + AcquisitionControl daqCtrl = (AcquisitionControl) daq; + DaqSystem system = daqCtrl.findDaqSystem(null);// getAcquisitionProcess().getRunningSystem(); + if (system instanceof FolderInputSystem) { + FolderInputSystem fip = (FolderInputSystem) system; + return fip.getFolderInputParameters().recentFiles.get(0); + } + } + } + catch (Exception e) { + } + return "unknown"; + } + + private void getDataDetails(Deployment deployment) { + Data data = deployment.getData(); + if (data == null) { + data = new Data(); + deployment.setData(data); + } + nilus.Deployment.Data.Audio audio = data.getAudio(); + if (audio == null) { + audio = new nilus.Deployment.Data.Audio(); + data.setAudio(audio); + } + audio.setURI(getRawDataURI()); + String processed = "Database:"+getDatabaseURI(); + String binary = getBinaryDataURI(); + if (binary != null) { + binary += ";Binary:"+binary; + } + audio.setProcessed(processed); + + } + + /** + * Get sensor information. The Soundtrap CTD will count as a sensor. + * Modules that are sensors will have to implement a PAMSensor interface + * @param deployment + */ + private void getSensors(Deployment deployment) { + ArrayList sensorModules = PamController.getInstance().findControlledUnits(PamSensor.class, true); + if (sensorModules == null || sensorModules.size() == 0) { + return; + } + Sensors sensors = deployment.getSensors(); + if (sensors == null) { + sensors = new Sensors(); + deployment.setSensors(sensors); + } + List sensorList = sensors.getSensor(); + for (PamControlledUnit aUnit : sensorModules) { + PamSensor pamSensor = (PamSensor) aUnit; + UnknownSensor nilusSensor = new UnknownSensor(); + try { + Helper.createRequiredElements(nilusSensor); + } catch (IllegalArgumentException | IllegalAccessException | InstantiationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } +// nilusSensor.setName(pamSensor.getUnitName()); + nilusSensor.setType(pamSensor.getUnitType()); + nilusSensor.setNumber(BigInteger.ZERO); + nilusSensor.setDescription(pamSensor.getSensorDescription()); + nilusSensor.setSensorId(pamSensor.getUnitType()); + + sensorList.add(nilusSensor); + } + } + + /** + * Add project Metadata to a Deploymnet document. This is currently being + * made available in the MetaDataControl module which should be added to PAMGuard + * as well as the Tethys output module. + * @param deployment + */ + private boolean getProjectData(Deployment deployment) { +// PamControlledUnit aUnit = PamController.getInstance().findControlledUnit(MetaDataContol.class, null); +// if (aUnit instanceof MetaDataContol == false || true) { +// deployment.setProject("thisIsAProject"); +// deployment.setPlatform("Yay a platform"); +// Instrument instrument = new Instrument(); +// instrument.setType("machiney"); +// instrument.setInstrumentId("12345555"); +// deployment.setInstrument(instrument); +// return false; +// } +// +// MetaDataContol metaControl = (MetaDataContol) aUnit; + PamguardMetaData metaData = MetaDataContol.getMetaDataControl().getMetaData(); + Deployment deploymentData = tethysControl.getGlobalDeplopymentData(); + deployment.setProject(deploymentData.getProject()); + deployment.setDeploymentAlias(deploymentData.getDeploymentAlias()); + deployment.setSite(deploymentData.getSite()); + deployment.setCruise(deploymentData.getCruise()); + deployment.setPlatform(getPlatform()); + deployment.setRegion(deploymentData.getRegion()); + Instrument instrument = new Instrument(); + instrument.setType(getInstrumentType()); + instrument.setInstrumentId(getInstrumentId()); + // get the geometry type from the array manager. + String geomType = getGeometryType(); + instrument.setGeometryType(geomType); + deployment.setInstrument(instrument); + + // overwrite the default deployment and recovery times if there is non null data + XMLGregorianCalendar depTime = deploymentData.getDeploymentDetails().getTimeStamp(); + if (depTime != null) { + deployment.getDeploymentDetails().setTimeStamp(depTime); + } + if (deploymentData.getRecoveryDetails() != null) { + XMLGregorianCalendar recMillis = deploymentData.getRecoveryDetails().getTimeStamp(); + if (recMillis != null) { + deployment.getRecoveryDetails().setTimeStamp(recMillis); + } + double recLat = deploymentData.getRecoveryDetails().getLatitude(); + double recLong = deploymentData.getRecoveryDetails().getLongitude(); + if (recLat != 0 & recLong != 0.) { + deployment.getRecoveryDetails().setLatitude(recLat); + deployment.getRecoveryDetails().setLongitude(PamUtils.constrainedAngle(recLong)); + } + } + + return true; + } + + /** + * Instrument identifier, e.g. serial number + * @return + */ + private String getInstrumentId() { + return ArrayManager.getArrayManager().getCurrentArray().getInstrumentId(); + } + + /** + * Test to see if it's possible to export Deployment documents. This is basically a test of + * various metadata fields that are required, such as instrument id's. + * @return null if OK, or a string describing the first encountered error + */ + public String canExportDeployments() { + + Deployment globalDeplData = tethysControl.getGlobalDeplopymentData(); + if (globalDeplData.getProject() == null) { + return "You must set a project name"; + } + + PInstrument arrayInstrument = getCurrentArrayInstrument(); + if (arrayInstrument == null) { + return "No 'Instrument' set. Goto array manager"; + } + return null; + } + + /** + * Get the Instrument info for the current array. + * @return + */ + public PInstrument getCurrentArrayInstrument() { + PamArray currentArray = ArrayManager.getArrayManager().getCurrentArray(); + String currType = currentArray.getInstrumentType(); + String currId = currentArray.getInstrumentId(); + PInstrument currentInstrument = null; + if (currType != null || currId != null) { + currentInstrument = new PInstrument(currType, currId); + } + return currentInstrument; + } + + /** + * On what platform is the instrument deployed? (e.g. mooring, tag) + * @return + */ + private String getPlatform() { + return getGeometryType(); + } + /** + * Instrument type, e.g. HARP, EAR, Popup, DMON, Rock Hopper, etc. + * @return + */ + private String getInstrumentType() { + return ArrayManager.getArrayManager().getCurrentArray().getInstrumentType(); + } + + /** + * Get a geometry type string for Tethys based on information in the array manager. + * @return + */ + private String getGeometryType() { + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + int nStreamer = array.getStreamerCount(); + for (int i = 0; i < nStreamer; i++) { + Streamer streamer = array.getStreamer(i); + HydrophoneLocator locator = streamer.getHydrophoneLocator(); + if (locator == null) { + continue; + } + if (locator instanceof ThreadingHydrophoneLocator) { + return "cabled"; + } + else { + return "rigid"; + } + } + return "unknown"; + } + + private boolean getSensorDetails(Deployment deployment) { + PamArray array = ArrayManager.getArrayManager().getCurrentArray(); + Sensors sensors = new Sensors(); + List