diff --git a/src/PamController/settings/output/xml/PamguardXMLWriter.java b/src/PamController/settings/output/xml/PamguardXMLWriter.java index b943f2d6..ec656589 100644 --- a/src/PamController/settings/output/xml/PamguardXMLWriter.java +++ b/src/PamController/settings/output/xml/PamguardXMLWriter.java @@ -520,6 +520,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. @@ -567,8 +575,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(); 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/dataSelector/DataSelector.java b/src/PamguardMVC/dataSelector/DataSelector.java index 0503479f..a91712b5 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/tethys/TethysControl.java b/src/tethys/TethysControl.java index b5ef662d..7fe79466 100644 --- a/src/tethys/TethysControl.java +++ b/src/tethys/TethysControl.java @@ -38,6 +38,7 @@ import tethys.output.DatablockSynchInfo; import tethys.output.TethysExportParams; import tethys.output.TethysExporter; import tethys.output.swing.TethysExportDialog; +import tethys.swing.ProjectDeploymentsDialog; import tethys.swing.TethysTabPanel; /** @@ -75,7 +76,7 @@ public class TethysControl extends PamControlledUnit implements PamSettings, Tet super(unitType, unitName); stateObservers = new ArrayList(); dbxmlConnect = new DBXMLConnect(this); - dbxmlQueries = new DBXMLQueries(this); + dbxmlQueries = new DBXMLQueries(this, dbxmlConnect); deploymentHandler = new DeploymentHandler(this); serverCheckTimer = new Timer(10000, new ActionListener() { @Override @@ -126,9 +127,21 @@ public class TethysControl extends PamControlledUnit implements PamSettings, Tet } }); tethysMenu.add(openClient); + JMenuItem showDeps = new JMenuItem("Show project deployments"); + showDeps.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showProjectDeploymentsDialog(); + } + }); + tethysMenu.add(showDeps); return tethysMenu; } + public void showProjectDeploymentsDialog() { + ProjectDeploymentsDialog.showDialog(getGuiFrame(), this); + } + public ArrayList getExportableDataBlocks() { ArrayList sets = new ArrayList<>(); ArrayList allDataBlocks = PamController.getInstance().getDataBlocks(); @@ -182,7 +195,7 @@ public class TethysControl extends PamControlledUnit implements PamSettings, Tet /** * open client in the default web browser */ - protected void openTethysClient() { + public void openTethysClient() { String urlString = tethysExportParams.getFullServerName() + "/Client"; System.out.println("Opening url " + urlString); URL url = null; @@ -340,7 +353,7 @@ public class TethysControl extends PamControlledUnit implements PamSettings, Tet private void initializationStuff() { deploymentHandler.createPamguardOverview(); serverCheckTimer.start(); - updateState(new TethysState(StateType.NEWPAMGUARDSELECTION)); + sendStateUpdate(new TethysState(StateType.NEWPAMGUARDSELECTION)); } /** diff --git a/src/tethys/TethysTimeFuncs.java b/src/tethys/TethysTimeFuncs.java index 922ebd1f..569f6f3d 100644 --- a/src/tethys/TethysTimeFuncs.java +++ b/src/tethys/TethysTimeFuncs.java @@ -14,6 +14,8 @@ 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 @@ -21,6 +23,7 @@ public class TethysTimeFuncs { public static XMLGregorianCalendar xmlGregCalFromMillis(long millis) { try { final GregorianCalendar calendar = new GregorianCalendar(); + calendar.setTimeZone(timeZone); calendar.setTimeInMillis(millis); return DatatypeFactory.newInstance().newXMLGregorianCalendar( calendar); @@ -41,6 +44,7 @@ public class TethysTimeFuncs { return null; } GregorianCalendar gc2 = xmlGregorian.toGregorianCalendar(); + gc2.setTimeZone(timeZone); return gc2.getTimeInMillis(); } diff --git a/src/tethys/dbxml/DBXMLConnect.java b/src/tethys/dbxml/DBXMLConnect.java index 55884926..f1347d99 100644 --- a/src/tethys/dbxml/DBXMLConnect.java +++ b/src/tethys/dbxml/DBXMLConnect.java @@ -33,6 +33,12 @@ public class DBXMLConnect { private TethysControl tethysControl; private File tempDirectory; + + private JerseyClient jerseyClient; + + private Queries queries; + + private String currentSiteURL; public DBXMLConnect(TethysControl tethysControl) { this.tethysControl = tethysControl; @@ -41,20 +47,97 @@ public class DBXMLConnect { } + /** + * 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()) == false) { + return false; + } + return true; + } /** - * take list of nilus objects loaded with PamGuard data and post them to the Tethys database - * all objects must be of the same nilus object - * TethysExportParams obj used from UI inputs + * Get the client. The client will only be recreated if the url changes + * @return Jersy client + */ + public synchronized JerseyClient getJerseyClient() { + if (checkClient() == false) { + openConnections(); + } + return jerseyClient; + } + + /** + * Get the Queries object. This will only be recreated if the client changes. + * @return + */ + public synchronized Queries getTethysQueries() { + if (checkClient() == false) { + openConnections(); + } + return queries; + } + + /** + * 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 + */ + public String updateDocument(Object nilusDocument) { + deleteDocument(nilusDocument); + return postToTethys(nilusDocument); + } + + /** + * 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 + */ + public boolean deleteDocument(Object nilusDocument) { + + Class objClass = nilusDocument.getClass(); + String collection = getTethysCollection(objClass.getName()); + String docId = getDocumentId(nilusDocument); + String result = null; + try { + result = jerseyClient.removeDocument(collection, docId ); + /** + * Return from a sucessful delete is something like + * + deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId++, recordPeriod); + + ['ECoastNARW0'] + + */ + } + catch (Exception e) { + System.out.printf("Error deleting %s %s: %s\n", collection, docId, e.getMessage()); + } + return result == null; + } + + /** + * take a nilus object loaded with PamGuard data and post it to the Tethys database * - * @param pamGuardObjs all nilus objects loaded with PamGuard data + * @param pamGuardObjs a nilus object loaded with PamGuard data * @return error string, null string means there are no errors */ public String postToTethys(Object nilusObject) { Class objClass = nilusObject.getClass(); String collection = getTethysCollection(objClass.getName()); - PamDataBlock defaultPamBlock = null; TethysExportParams params = new TethysExportParams(); String fileError = null; String tempName = getTempFileName(nilusObject); @@ -95,63 +178,57 @@ public class DBXMLConnect { File tempDir = new File(javaTmpDirs); if (tempDir.exists() == false) { - if (tempDir.mkdirs()) { - tempDirectory = tempDir; - }; + tempDir.mkdirs(); } + if (tempDir.exists()) { + tempDirectory = tempDir; + }; if (tempDirectory == null) { tempDirectory = new File(System.getProperty("java.io.tmpdir")); } } - /** - * needs to be based on the document id, but the getter for this can vary by type, so time - * to start casting ! + * Get a document Id string. All Document objects should have a getId() function + * however they do not have a type hierarchy, so it can't be accessed directly. + * instead go via the class.getDeclaredMethod function and it should be possible to find + * it. * @param nilusObject - * @return + * @return document Id for any type of document, or null if the document doesn't have a getID function */ - private String getTempFileName(Object nilusObject) { - /** - * While all nilus objects should have a getId function, they have no - * common root, so try to get the function via the class declared methods. - */ - String tempName = "PamguardTethys"; + private String getDocumentId(Object nilusObject) { + String tempName = null; Class nilusClass = nilusObject.getClass(); + Method getId; try { - Method getId = nilusClass.getDeclaredMethod("getId", null); + getId = nilusClass.getDeclaredMethod("getId", null); Object[] inputs = new Object[0]; Object res = getId.invoke(nilusObject, inputs); if (res instanceof String) { tempName = (String) res; return tempName; } - } catch (NoSuchMethodException e) { - // TODO Auto-generated catch block + } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); - } catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (nilusObject instanceof nilus.Deployment) { - tempName = ((Deployment) nilusObject).getId(); - } - else if (nilusObject instanceof nilus.Detections) { - tempName = ((nilus.Detections) nilusObject).getId(); } return tempName; } + /** + * needs to be based on the document id, + * @param nilusObject + * @return + */ + private String getTempFileName(Object nilusObject) { + + String docId = getDocumentId(nilusObject); + if (docId == null || docId.length() == 0) { + docId = "PamguardTethys"; + } + return docId; + } + /** * get Tethys collection name from nilus collection objects @@ -190,16 +267,8 @@ public class DBXMLConnect { */ public boolean deleteDeployment(String deploymentId) { ArrayList detDocNames = tethysControl.getDbxmlQueries().getDetectionsDocsIds(deploymentId); - JerseyClient jerseyClient = null; + JerseyClient jerseyClient = getJerseyClient(); Queries queries = null; - try { - jerseyClient = new JerseyClient(tethysControl.getTethysExportParams().getFullServerName()); - queries = new Queries(jerseyClient); - } - catch (Exception e) { - e.printStackTrace(); - return false; - } String result; // for (int i = 0; i < detDocNames.size(); i++) { // try { @@ -225,13 +294,19 @@ public class DBXMLConnect { } - public boolean openDatabase() { - - return true; + public synchronized boolean openConnections() { + TethysExportParams params = tethysControl.getTethysExportParams(); + currentSiteURL = params.getFullServerName(); + jerseyClient = new JerseyClient(currentSiteURL); + queries = new Queries(jerseyClient); + ServerStatus state = pingServer(); + return state.ok; } - public void closeDatabase() { - + public synchronized void closeConnections() { + jerseyClient = null; + queries = null; + currentSiteURL = null; } /** @@ -239,10 +314,10 @@ public class DBXMLConnect { * @return Server state ? */ public ServerStatus pingServer() { - JerseyClient jerseyClient = new JerseyClient(tethysControl.getTethysExportParams().getFullServerName()); + boolean ok = false; try { - ok = jerseyClient.ping(); + ok = getJerseyClient().ping(); } catch (Exception ex) { return new ServerStatus(false, ex); diff --git a/src/tethys/dbxml/DBXMLQueries.java b/src/tethys/dbxml/DBXMLQueries.java index 6eb81359..76b236a0 100644 --- a/src/tethys/dbxml/DBXMLQueries.java +++ b/src/tethys/dbxml/DBXMLQueries.java @@ -36,10 +36,12 @@ import tethys.output.TethysExportParams; public class DBXMLQueries { private TethysControl tethysControl; - - public DBXMLQueries(TethysControl tethysControl) { + private DBXMLConnect dbXMLConnect; + + public DBXMLQueries(TethysControl tethysControl, DBXMLConnect dbXMLConnect) { super(); this.tethysControl = tethysControl; + this.dbXMLConnect = dbXMLConnect; } /** @@ -64,7 +66,8 @@ public class DBXMLQueries { TethysExportParams params = tethysControl.getTethysExportParams(); try { - JerseyClient jerseyClient = new JerseyClient(params.getFullServerName()); + JerseyClient jerseyClient = dbxmlConnect.getJerseyClient(); +// String url = jerseyClient.getURL(); Queries queries = new Queries(jerseyClient); @@ -210,6 +213,9 @@ public class DBXMLQueries { } 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/Description/Method\",\"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/Description/Method\",\"LongDataName\"],\"optype\":\"binary\"},{\"op\":\"=\",\"operands\":[\"Detections/DataSource/DeploymentId\",\"TheDeploymentId\"],\"optype\":\"binary\"}],\"enclose\":1}"; String query; @@ -235,11 +241,40 @@ public class DBXMLQueries { Node aNode = returns.item(i); String docName = aNode.getTextContent(); // System.out.println(aNode.getTextContent()); - count += countDetecionsData(docName); + int count2 = countDetections2(docName); + count += count2; //countDetecionsData(docName); + } return count; } + private 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; + } + /** * Count the data in a detections document. * @param detectionDocId diff --git a/src/tethys/images/Tethys-200.png b/src/tethys/images/Tethys-200.png new file mode 100644 index 00000000..19e3c48f Binary files /dev/null and b/src/tethys/images/Tethys-200.png differ diff --git a/src/tethys/niluswraps/PDeployment.java b/src/tethys/niluswraps/PDeployment.java index 364a9a46..4652329c 100644 --- a/src/tethys/niluswraps/PDeployment.java +++ b/src/tethys/niluswraps/PDeployment.java @@ -50,6 +50,10 @@ public class PDeployment { public void setMatchedPAMGaurdPeriod(RecordingPeriod matchedPAMGaurdPeriod) { this.matchedPAMGaurdPeriod = matchedPAMGaurdPeriod; } + + public String getShortDescription() { + return String.format("%s %s", deployment.getId(), PamCalendar.formatDBDate(getAudioStart())); + } } diff --git a/src/tethys/niluswraps/PGranularityType.java b/src/tethys/niluswraps/PGranularityType.java new file mode 100644 index 00000000..ee898d64 --- /dev/null +++ b/src/tethys/niluswraps/PGranularityType.java @@ -0,0 +1,58 @@ +package tethys.niluswraps; + +import nilus.GranularityEnumType; +import nilus.GranularityType; + +/** + * Decorate GranularityType + * @author dg50 + * + */ +public class PGranularityType { + + /** + * Nicer formatted name for a dialog. + * @param granularity + * @return + */ + public static String prettyString(GranularityEnumType granularity) { + switch (granularity) { + case BINNED: + return "Binned"; + case CALL: + return "Call"; + case ENCOUNTER: + return "Encounter"; + case GROUPED: + return "Grouped"; + default: + break; + + } + return granularity.toString(); + } + + /** + * Tool tip for display in a dialog. + * @param granularity + * @return + */ + public static String toolTip(GranularityEnumType granularity) { + switch (granularity) { + case BINNED: + return "Output of counts in regular time periods"; + case CALL: + return "Call level output"; + case ENCOUNTER: + return "Encounter level output"; + case GROUPED: + return "Grouped output (whatever that is?)"; + default: + break; + + } + return prettyString(granularity); + } + + +} diff --git a/src/tethys/output/StreamExportParams.java b/src/tethys/output/StreamExportParams.java index d4842e64..2ba4f2fd 100644 --- a/src/tethys/output/StreamExportParams.java +++ b/src/tethys/output/StreamExportParams.java @@ -2,6 +2,9 @@ package tethys.output; import java.io.Serializable; +import nilus.DescriptionType; +import nilus.GranularityEnumType; + /** * Parameters controlling export of a single stream. * Starts just with a boolean 'selected', but may grow. @@ -23,5 +26,16 @@ public class StreamExportParams implements Serializable { public String longDataName; public boolean selected; + + public GranularityEnumType granularity = GranularityEnumType.CALL; + + public nilus.DescriptionType detectionDescription; + + public DescriptionType getDetectionDescription() { + if (detectionDescription == null) { + detectionDescription = new DescriptionType(); + } + return detectionDescription; + } } diff --git a/src/tethys/output/TethysExporter.java b/src/tethys/output/TethysExporter.java index e2bcb980..35733a2d 100644 --- a/src/tethys/output/TethysExporter.java +++ b/src/tethys/output/TethysExporter.java @@ -218,7 +218,6 @@ public class TethysExporter { * Then do whatever else is needed to complete the document. */ - dbxmlConnect.closeDatabase(); return true; } diff --git a/src/tethys/swing/DatablockDetectionsPanel.java b/src/tethys/swing/DatablockDetectionsPanel.java new file mode 100644 index 00000000..bf2ee42e --- /dev/null +++ b/src/tethys/swing/DatablockDetectionsPanel.java @@ -0,0 +1,89 @@ +package tethys.swing; + +import java.awt.BorderLayout; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.TitledBorder; +import javax.swing.table.AbstractTableModel; + +import PamView.tables.SwingTableColumnWidths; +import PamguardMVC.PamDataBlock; +import tethys.TethysControl; + +/** + * Table of Detections documents for a single PAMGuard datablock. + * Generally, this should only have a smallish number of entries in it + * so may not need too much real estate on the display. + * @author dg50 + * + */ +public class DatablockDetectionsPanel extends TethysGUIPanel implements StreamTableObserver { + + private JPanel mainPanel; + + private JLabel dataBlockName; + + private TableModel tableModel; + + private JTable table; + + private PamDataBlock dataBlock; + + public DatablockDetectionsPanel(TethysControl tethysControl) { + super(tethysControl); + mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(BorderLayout.NORTH, dataBlockName = new JLabel("PAMGUard data stream", JLabel.LEFT)); + mainPanel.setBorder(new TitledBorder("Data stream Tethys Detections documents")); + + tableModel = new TableModel(); + table = new JTable(tableModel); + JScrollPane scrollPane = new JScrollPane(table); + mainPanel.add(BorderLayout.CENTER, scrollPane); + + new SwingTableColumnWidths(tethysControl.getUnitName() + getClass().getName(), table); + + } + + @Override + public JComponent getComponent() { + return mainPanel; + } + + @Override + public void selectDataBlock(PamDataBlock dataBlock) { + this.dataBlock = dataBlock; + dataBlockName.setText(dataBlock.getLongDataName()); + } + + private class TableModel extends AbstractTableModel { + + private String[] colNames = {"Person", "Name", "Abstract"}; + + @Override + public int getRowCount() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int getColumnCount() { + return colNames.length; + } + + @Override + public String getColumnName(int column) { + return colNames[column]; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + // TODO Auto-generated method stub + return null; + } + + } +} diff --git a/src/tethys/swing/DatablockSynchPanel.java b/src/tethys/swing/DatablockSynchPanel.java index 0049587b..8da66a90 100644 --- a/src/tethys/swing/DatablockSynchPanel.java +++ b/src/tethys/swing/DatablockSynchPanel.java @@ -1,6 +1,12 @@ package tethys.swing; import java.awt.BorderLayout; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import java.util.ArrayList; import javax.swing.JComponent; @@ -10,9 +16,11 @@ import javax.swing.JTable; import javax.swing.border.TitledBorder; import javax.swing.table.AbstractTableModel; + import PamUtils.PamCalendar; import PamView.panel.PamPanel; import PamView.tables.SwingTableColumnWidths; +import PamguardMVC.PamDataBlock; import dataMap.OfflineDataMap; import tethys.TethysControl; import tethys.TethysState; @@ -27,6 +35,8 @@ public class DatablockSynchPanel extends TethysGUIPanel { private SynchTableModel synchTableModel; private ArrayList dataBlockSynchInfo; + + private ArrayList tableObservers = new ArrayList<>(); public DatablockSynchPanel(TethysControl tethysControl) { super(tethysControl); @@ -37,6 +47,8 @@ public class DatablockSynchPanel extends TethysGUIPanel { new SwingTableColumnWidths(tethysControl.getUnitName()+"SynchTable", synchTable); JScrollPane scrollPane = new JScrollPane(synchTable); mainPanel.add(BorderLayout.CENTER, scrollPane); + synchTable.addMouseListener(new MouseActions()); + synchTable.addKeyListener(new KeyActions()); } @Override @@ -44,11 +56,47 @@ public class DatablockSynchPanel extends TethysGUIPanel { return mainPanel; } + private class KeyActions extends KeyAdapter { + @Override + public void keyReleased(KeyEvent e) { + if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) { + selectRow(); + } + } + + } + private class MouseActions extends MouseAdapter { + @Override + public void mouseClicked(MouseEvent e) { + selectRow(); + } + + } + + private void selectRow() { + int row = synchTable.getSelectedRow(); + if (row < 0) { + return; + } + DatablockSynchInfo synchInfo = dataBlockSynchInfo.get(row); +// datablockDetectionsPanel.setDataBlock(synchInfo.getDataBlock()); + notifyObservers(synchInfo.getDataBlock()); + } @Override public void updateState(TethysState tethysState) { synchTableModel.fireTableDataChanged(); } + + public void addTableObserver(StreamTableObserver observer) { + tableObservers.add(observer); + } + + public void notifyObservers(PamDataBlock dataBlock) { + for (StreamTableObserver obs : tableObservers) { + obs.selectDataBlock(dataBlock); + } + } private ArrayList getSychInfos() { if (dataBlockSynchInfo == null) { diff --git a/src/tethys/swing/DeploymentExportPanel.java b/src/tethys/swing/DeploymentExportPanel.java new file mode 100644 index 00000000..dd9a7ce0 --- /dev/null +++ b/src/tethys/swing/DeploymentExportPanel.java @@ -0,0 +1,268 @@ +package tethys.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.ArrayList; + +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; + +import Acquisition.AcquisitionControl; +import Acquisition.DaqSystem; +import Acquisition.FolderInputSystem; +import PamController.PamControlledUnit; +import PamController.PamController; +import PamUtils.PamCalendar; +import PamView.dialog.PamGridBagContraints; +import PamView.dialog.warn.WarnOnce; +import PamView.panel.PamAlignmentPanel; +import PamView.panel.WestAlignedPanel; +import binaryFileStorage.BinaryStore; +import generalDatabase.DBControlUnit; +import metadata.deployment.DeploymentData; +import nilus.Deployment; +import nilus.Deployment.Data; +import tethys.TethysControl; +import tethys.TethysState; +import tethys.dbxml.DBXMLConnect; +import tethys.deployment.RecordingPeriod; +import tethys.niluswraps.PDeployment; + +public class DeploymentExportPanel extends TethysGUIPanel implements DeploymentTableObserver { + + private JPanel mainPanel; + + private JButton showAllDeployments, bigExportButton; + + private JTextField site, cruise; +// , region; don't inlude region here - it's set with the NewProject along with the project name. + // the stuff here may vary within a project. + private JTextField rawURI, binaryURI, databaseURI; + private JTextField contact, date; + + private JComboBox projectDeployments; + + private ArrayList tethysDeploys; + + private PAMGuardDeploymentsTable pamDeploymentsTable; + + private ArrayList selectedDeployments; + + public DeploymentExportPanel(TethysControl tethysControl, PAMGuardDeploymentsTable pamDeploymentsTable) { + super(tethysControl); + this.pamDeploymentsTable = pamDeploymentsTable; + mainPanel = new PamAlignmentPanel(BorderLayout.NORTH); + mainPanel.setLayout(new GridBagLayout()); + mainPanel.setBorder(new TitledBorder("Deployment Detail")); + GridBagConstraints c = new PamGridBagContraints(); + showAllDeployments = new JButton("Show project deployments"); + showAllDeployments.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tethysControl.showProjectDeploymentsDialog(); + } + }); + site = new JTextField(40); + cruise = new JTextField(20); + rawURI = new JTextField(20); + binaryURI = new JTextField(20); + databaseURI = new JTextField(20); + contact = new JTextField(20); + date = new JTextField(20); + date.setEditable(false); + projectDeployments = new JComboBox(); + projectDeployments.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + selectExistingDeployment(); + } + }); + +// c.gridx = 1; +// mainPanel.add(showAllDeployments, c); +// c.gridwidth = 1; + addPair("Site ", site, c); + addPair("Cruise ", cruise, c); + addPair("Raw data URI ", rawURI, c); + addPair("Binary data URI ", binaryURI, c); + addPair("Datbase URI ", databaseURI, c); + addPair("Contact ", contact, c); + addPair("Date ", date, c); + addPair("Set from ", projectDeployments, c); + + bigExportButton = new JButton("Export selection"); + bigExportButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + exportButtonPressed(); + } + }); + c.gridx = 1; + c.gridy++; + mainPanel.add(bigExportButton, c); + + + } + + protected void selectExistingDeployment() { + int row = projectDeployments.getSelectedIndex(); + if (row < 0 || tethysDeploys == null) { + return; + } + + if (row >= tethysDeploys.size()) { + return; + } + PDeployment deployment = tethysDeploys.get(row); + String msg = "Do you want to copy settings from deploymnet document " + deployment.deployment.getId(); + int ans = WarnOnce.showWarning("Deployment data", msg, WarnOnce.OK_CANCEL_OPTION); + if (ans == WarnOnce.OK_OPTION) { + copyDeploymentData(deployment.deployment); + } + } + + private void copyDeploymentData(Deployment deployment) { + DeploymentData globalMeta = getTethysControl().getGlobalDeplopymentData(); + globalMeta.setSite(deployment.getSite()); + globalMeta.setCruise(deployment.getCruise()); + globalMeta.setRegion(deployment.getRegion()); + setInternal(); + } + + @Override + public void updateState(TethysState tethysState) { + super.updateState(tethysState); + switch (tethysState.stateType) { + case NEWPAMGUARDSELECTION: + setInternal(); + setDefaultStores(); + enableControls(); + break; + case NEWPROJECTSELECTION: + updateDeployments(); + enableControls(); + } + } + + private void updateDeployments() { + tethysDeploys = null; + projectDeployments.removeAllItems(); + ArrayList deploys = getTethysControl().getDeploymentHandler().getProjectDeployments(); + if (deploys == null) { + return; + } + for (PDeployment aDep : deploys) { + projectDeployments.addItem(aDep.getShortDescription()); + } + tethysDeploys = deploys; + } + + private void addPair(String label, JComponent component, GridBagConstraints c) { + c.gridy++; + c.gridx = 0; + mainPanel.add(new JLabel(label, JLabel.RIGHT), c); + c.gridx++; + mainPanel.add(component, c); + } + + @Override + public JComponent getComponent() { + // TODO Auto-generated method stub + return mainPanel; + } + + /** + * Set the parms from internally stored data. + */ + private void setInternal() { + DeploymentData globalMeta = getTethysControl().getGlobalDeplopymentData(); + site.setText(globalMeta.getSite()); + cruise.setText(globalMeta.getCruise()); +// region.setText(globalMeta.getRegion()); + date.setText(PamCalendar.formatDBDateTime(System.currentTimeMillis())); + } + + private void setDefaultStores() { + + + BinaryStore binStore = BinaryStore.findBinaryStoreControl(); + if (binStore != null) { + binaryURI.setText(binStore.getBinaryStoreSettings().getStoreLocation()); + } + + DBControlUnit databaseControl = DBControlUnit.findDatabaseControl(); + if (databaseControl != null) { + databaseURI.setText(databaseControl.getLongDatabaseName()); + } + + 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; + rawURI.setText(fip.getFolderInputParameters().recentFiles.get(0)); + } + } + } + catch (Exception e) { + rawURI.setText("unknown"); + } + + } + + @Override + public void selectionChanged() { + selectedDeployments = pamDeploymentsTable.getSelectedDeployments(); + enableControls(); + } + + protected void exportButtonPressed() { + if (selectedDeployments == null || selectedDeployments.size() == 0) { + return; + }; + int freeId = getTethysControl().getDeploymentHandler().getFirstFreeDeploymentId(); + for (int i = 0; i < selectedDeployments.size(); i++) { + RecordingPeriod recordPeriod = selectedDeployments.get(i); + PDeployment exDeploymnet = recordPeriod.getMatchedTethysDeployment(); + Deployment deployment = null; + if (exDeploymnet != null) { + deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId, recordPeriod); + deployment.setId(exDeploymnet.deployment.getId()); + } + if (deployment == null) { + deployment = getTethysControl().getDeploymentHandler().createDeploymentDocument(freeId++, recordPeriod); + } + // fill in a few things from here + deployment.setCruise(cruise.getText()); + deployment.setSite(site.getText()); + // also need to sort out track data here, etc. +// Should really tidy this up a lot and move functionality to DeploymentHandler with all +// the metadata in a object ? +// Data data = new nilus.Deployment.Data(); +// d + DBXMLConnect dbxmlConnect = getTethysControl().getDbxmlConnect(); + if (exDeploymnet != null) { + dbxmlConnect.updateDocument(deployment); + } + else { + dbxmlConnect.postToTethys(deployment); + } + } + } + + private void enableControls() { + boolean enable = selectedDeployments != null && selectedDeployments.size() > 0; + bigExportButton.setEnabled(enable); + } + +} diff --git a/src/tethys/swing/DeploymentTableObserver.java b/src/tethys/swing/DeploymentTableObserver.java new file mode 100644 index 00000000..1eda9db4 --- /dev/null +++ b/src/tethys/swing/DeploymentTableObserver.java @@ -0,0 +1,7 @@ +package tethys.swing; + +public interface DeploymentTableObserver { + + public void selectionChanged(); + +} diff --git a/src/tethys/swing/DeploymentsPanel.java b/src/tethys/swing/DeploymentsPanel.java index 73e238fd..c41d7465 100644 --- a/src/tethys/swing/DeploymentsPanel.java +++ b/src/tethys/swing/DeploymentsPanel.java @@ -17,25 +17,30 @@ public class DeploymentsPanel extends TethysGUIPanel { private PAMGuardDeploymentsTable pamDeploymentsTable; - private TethysDeploymentsTable tethysDeploymentsTable; + DeploymentExportPanel exportPanel; +// private TethysDeploymentsTable tethysDeploymentsTable; public DeploymentsPanel(TethysControl tethysControl) { super(tethysControl); pamDeploymentsTable = new PAMGuardDeploymentsTable(tethysControl); - tethysDeploymentsTable = new TethysDeploymentsTable(tethysControl); + exportPanel = new DeploymentExportPanel(tethysControl, pamDeploymentsTable); + pamDeploymentsTable.addObserver(exportPanel); +// tethysDeploymentsTable = new TethysDeploymentsTable(tethysControl); mainPanel = new PamPanel(new BorderLayout()); mainPanel.setBorder(new TitledBorder("Deployment information")); - JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - splitPane.add(pamDeploymentsTable.getComponent()); - splitPane.add(tethysDeploymentsTable.getComponent()); - mainPanel.add(splitPane,BorderLayout.CENTER); - SwingUtilities.invokeLater(new Runnable() { - - @Override - public void run() { - splitPane.setDividerLocation(0.6); - } - }); +// JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); +// splitPane.add(pamDeploymentsTable.getComponent()); +// splitPane.add(tethysDeploymentsTable.getComponent()); +// mainPanel.add(splitPane,BorderLayout.CENTER); +// SwingUtilities.invokeLater(new Runnable() { +// +// @Override +// public void run() { +// splitPane.setDividerLocation(0.6); +// } +// }); + mainPanel.add(BorderLayout.CENTER, pamDeploymentsTable.getComponent()); + mainPanel.add(BorderLayout.EAST, exportPanel.getComponent()); } @Override diff --git a/src/tethys/swing/DetectionsExportPanel.java b/src/tethys/swing/DetectionsExportPanel.java new file mode 100644 index 00000000..eda59aaa --- /dev/null +++ b/src/tethys/swing/DetectionsExportPanel.java @@ -0,0 +1,64 @@ +package tethys.swing; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; + +import PamView.dialog.PamGridBagContraints; +import PamView.panel.PamAlignmentPanel; +import PamguardMVC.PamDataBlock; +import tethys.TethysControl; +import tethys.swing.export.DetectionsExportWizard; + +public class DetectionsExportPanel extends TethysGUIPanel implements StreamTableObserver { + + private JPanel mainPanel; + + private JButton exportButton; + + private PamDataBlock selectedDataBlock; + + public DetectionsExportPanel(TethysControl tethysControl) { + super(tethysControl); + mainPanel = new PamAlignmentPanel(BorderLayout.NORTH); + mainPanel.setLayout(new GridBagLayout()); + mainPanel.setBorder(new TitledBorder("Export")); + exportButton = new JButton("Export"); + exportButton.setToolTipText("Export PAMGaurd data to Tethys"); + exportButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + doExport(); + } + }); + exportButton.setEnabled(false); + GridBagConstraints c = new PamGridBagContraints(); + mainPanel.add(exportButton, c); + } + + @Override + public JComponent getComponent() { + return mainPanel; + } + + private void doExport() { + if (selectedDataBlock == null) { + return; + } + DetectionsExportWizard.showDilaog(getTethysControl().getGuiFrame(), getTethysControl(), selectedDataBlock); + } + + @Override + public void selectDataBlock(PamDataBlock dataBlock) { + this.selectedDataBlock = dataBlock; + exportButton.setEnabled(selectedDataBlock != null); + } + +} diff --git a/src/tethys/swing/Images.java b/src/tethys/swing/Images.java new file mode 100644 index 00000000..1d73e710 --- /dev/null +++ b/src/tethys/swing/Images.java @@ -0,0 +1,24 @@ +package tethys.swing; + +import java.awt.Image; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; + +public class Images { + + private static final String imageRes = "tethys/images/Tethys-200.png"; + public static ImageIcon getTethysImage() { + ImageIcon tethysImage = null; + try { + tethysImage = new ImageIcon(ClassLoader.getSystemResource(imageRes)); + } + catch (Exception e) { + System.out.println(e.getMessage()); +// System.out.println("Unable to load file " + file.getAbsolutePath()); + } + return tethysImage; + } +} diff --git a/src/tethys/swing/NewProjectDialog.java b/src/tethys/swing/NewProjectDialog.java index 353ad732..03f64318 100644 --- a/src/tethys/swing/NewProjectDialog.java +++ b/src/tethys/swing/NewProjectDialog.java @@ -22,7 +22,7 @@ public class NewProjectDialog extends PamView.dialog.PamDialog { private JTextField projectName; private JTextField projectRegion; - + private DeploymentData deploymentData; private NewProjectDialog(Window parentFrame, TethysControl tethysControl) { diff --git a/src/tethys/swing/PAMGuardDeploymentsTable.java b/src/tethys/swing/PAMGuardDeploymentsTable.java index 25e93601..59a8d354 100644 --- a/src/tethys/swing/PAMGuardDeploymentsTable.java +++ b/src/tethys/swing/PAMGuardDeploymentsTable.java @@ -5,7 +5,9 @@ import java.awt.Color; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; +import java.util.Arrays; +import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -39,6 +41,10 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { private JPanel mainPanel; private DeploymentOverview deploymentOverview; + + private boolean[] selection = new boolean[0]; + + private ArrayList observers = new ArrayList<>(); public PAMGuardDeploymentsTable(TethysControl tethysControl) { super(tethysControl); @@ -47,7 +53,7 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { mainPanel.setBorder(new TitledBorder("PAMGuard recording periods")); tableModel = new TableModel(); table = new JTable(tableModel); - table.setRowSelectionAllowed(true); +// table.setRowSelectionAllowed(true); table.addMouseListener(new TableMouse()); JScrollPane scrollPane = new JScrollPane(table); mainPanel.add(BorderLayout.CENTER, scrollPane); @@ -76,6 +82,18 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { } } + @Override + public void mouseClicked(MouseEvent e) { + int aRow = table.getSelectedRow(); + int col = table.getSelectedColumn(); + if (aRow >= 0 && aRow < selection.length && col == 6) { + selection[aRow] = !selection[aRow]; + for (DeploymentTableObserver obs : observers) { + obs.selectionChanged(); + } + } + } + } public void showPopup() { @@ -107,6 +125,24 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { */ } + + /** + * Get a list of selected recording periods. + * @return list of selected periods. + */ + public ArrayList getSelectedDeployments() { + if (deploymentOverview == null) { + return null; + } + ArrayList selDeps = new ArrayList<>(); + int n = Math.min(selection.length, deploymentOverview.getRecordingPeriods().size()); + for (int i = 0; i < n; i++) { + if (selection[i]) { + selDeps.add(deploymentOverview.getRecordingPeriods().get(i)); + } + } + return selDeps; + } @Override public void updateState(TethysState tethysState) { @@ -136,15 +172,28 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { private void updateDeployments() { DeploymentHandler deploymentHandler = getTethysControl().getDeploymentHandler(); deploymentOverview = deploymentHandler.getDeploymentOverview(); + int n = deploymentOverview.getRecordingPeriods().size(); + if (selection.length < n) { + selection = Arrays.copyOf(selection, n); +// for (int i = 0; i < setDefaultStores.length; i++) { +// if (selectBoxes[i] == null) { +// selectBoxes[i] = new JCheckBox(); +// } +// } + } tableModel.fireTableDataChanged(); // DeploymentData deplData = getTethysControl().getGlobalDeplopymentData(); // ArrayList projectDeployments = getTethysControl().getDbxmlQueries().getProjectDeployments(deplData.getProject()); // deploymentHandler.matchPamguard2Tethys(deploymentOverview, projectDeployments); } + + public void addObserver(DeploymentTableObserver observer) { + observers.add(observer); + } private class TableModel extends AbstractTableModel { - private String[] columnNames = {"Id", "Start", "Stop", "Duration", "Cycle", "Tethys Deployment"}; + private String[] columnNames = {"Id", "Start", "Stop", "Duration", "Cycle", "Tethys Deployment", "Select"}; @Override public int getRowCount() { @@ -165,6 +214,15 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { public int getColumnCount() { return columnNames.length; } + + @Override + public Class getColumnClass(int columnIndex) { + if (columnIndex == 6) { + return Boolean.class; +// return JCheckBox.class; + } + return super.getColumnClass(columnIndex); + } @Override public Object getValueAt(int rowIndex, int columnIndex) { @@ -176,6 +234,11 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { return getValueAt(period, rowIndex, columnIndex); } + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == 6; + } + private Object getValueAt(RecordingPeriod period, int rowIndex, int columnIndex) { switch (columnIndex) { case 0: @@ -193,6 +256,9 @@ public class PAMGuardDeploymentsTable extends TethysGUIPanel { case 5: PDeployment deployment = period.getMatchedTethysDeployment(); return makeDeplString(period, deployment); + case 6: +// return selectBoxes[rowIndex]; + return selection[rowIndex]; } return null; diff --git a/src/tethys/swing/ProjectDeploymentsDialog.java b/src/tethys/swing/ProjectDeploymentsDialog.java new file mode 100644 index 00000000..fed3041e --- /dev/null +++ b/src/tethys/swing/ProjectDeploymentsDialog.java @@ -0,0 +1,57 @@ +package tethys.swing; + +import java.awt.Window; + +import PamView.dialog.PamDialog; +import tethys.TethysControl; +import tethys.TethysState; +import tethys.TethysState.StateType; + +/** + * Modeless dialog showing all project deployments. + * @author dg50 + * + */ +public class ProjectDeploymentsDialog extends PamDialog { + + private TethysDeploymentsTable deploymentsPanel; + private TethysControl tethysControl; + private static ProjectDeploymentsDialog singleInstance; + + private ProjectDeploymentsDialog(Window parentFrame, TethysControl tethysControl) { + super(parentFrame, "Project deployments", false); + this.tethysControl = tethysControl; + deploymentsPanel = new TethysDeploymentsTable(tethysControl); + setDialogComponent(deploymentsPanel.getComponent()); + setModal(false); + setResizable(true); + getCancelButton().setVisible(false); + } + + public static void showDialog(Window parentFrame, TethysControl tethysControl) { + if (singleInstance == null) { + singleInstance = new ProjectDeploymentsDialog(parentFrame, tethysControl); + } + singleInstance.setVisible(true); + singleInstance.deploymentsPanel.updateState(new TethysState(StateType.NEWPROJECTSELECTION)); +// if (singleInstance.is) + } + + @Override + public boolean getParams() { + // TODO Auto-generated method stub + return true; + } + + @Override + public void cancelButtonPressed() { + // TODO Auto-generated method stub + + } + + @Override + public void restoreDefaultSettings() { + // TODO Auto-generated method stub + + } +} diff --git a/src/tethys/swing/StreamTableObserver.java b/src/tethys/swing/StreamTableObserver.java new file mode 100644 index 00000000..cd0f3b13 --- /dev/null +++ b/src/tethys/swing/StreamTableObserver.java @@ -0,0 +1,9 @@ +package tethys.swing; + +import PamguardMVC.PamDataBlock; + +public interface StreamTableObserver { + + public void selectDataBlock(PamDataBlock dataBlock); + +} diff --git a/src/tethys/swing/TethysConnectionPanel.java b/src/tethys/swing/TethysConnectionPanel.java index c13efd54..95837d6a 100644 --- a/src/tethys/swing/TethysConnectionPanel.java +++ b/src/tethys/swing/TethysConnectionPanel.java @@ -62,6 +62,8 @@ public class TethysConnectionPanel extends TethysGUIPanel { private JButton newInstrument; + private JButton openClient; + public TethysConnectionPanel(TethysControl tethysControl) { super(tethysControl); mainPanel = new WestAlignedPanel(new GridBagLayout()); @@ -71,6 +73,8 @@ public class TethysConnectionPanel extends TethysGUIPanel { serverSelButton.setToolTipText("Select server"); serverStatus = new ScrollingPamLabel(SERVERSTATUSLENGTH); serverName.setEditable(false); + openClient = new JButton("Open Client"); + openClient.setToolTipText("Open Tethys client in web browser"); // serverStatus.setEditable(false); serverSelButton.addActionListener(new ActionListener() { @Override @@ -78,6 +82,12 @@ public class TethysConnectionPanel extends TethysGUIPanel { selectServer(); } }); + openClient.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tethysControl.openTethysClient(); + } + }); newProjectButton = new JButton("New project"); newProjectButton.setToolTipText("Create new project information"); newProjectButton.addActionListener(new ActionListener() { @@ -121,6 +131,9 @@ public class TethysConnectionPanel extends TethysGUIPanel { c.gridx++; c.gridwidth = 2; mainPanel.add(serverStatus, c); + c.gridx += c.gridwidth; + c.gridwidth = 1; + mainPanel.add(openClient, c); c.gridx =0; c.gridy++; diff --git a/src/tethys/swing/TethysImagePanel.java b/src/tethys/swing/TethysImagePanel.java new file mode 100644 index 00000000..b0a74610 --- /dev/null +++ b/src/tethys/swing/TethysImagePanel.java @@ -0,0 +1,50 @@ +package tethys.swing; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import javax.swing.border.BevelBorder; + + +public class TethysImagePanel extends JPanel { + + private static final long serialVersionUID = 1L; + private ImageIcon image; + private int prefWidth; + private int prefHeight; + private int size; + + public TethysImagePanel(int size) { + this.size = size; + image = Images.getTethysImage(); + if (image != null) { + prefWidth = image.getIconWidth(); + prefHeight = image.getIconHeight(); + } +// setBorder(new BevelBorder(BevelBorder.RAISED)); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + if (image == null) { + return; + } + int inset = 2; + g.drawImage(image.getImage(), inset, inset, getWidth()-inset*2, getHeight()-inset*2, + 0, 0, prefWidth, prefHeight, null); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(size, size); + } + + + + + +} diff --git a/src/tethys/swing/TethysMainPanel.java b/src/tethys/swing/TethysMainPanel.java index 72e07590..49b01c0b 100644 --- a/src/tethys/swing/TethysMainPanel.java +++ b/src/tethys/swing/TethysMainPanel.java @@ -21,21 +21,39 @@ public class TethysMainPanel extends TethysGUIPanel { private DeploymentsPanel deploymentsPanel; + private DatablockDetectionsPanel datablockDetectionsPanel; + + private DetectionsExportPanel detectionsExportPanel; + public TethysMainPanel(TethysControl tethysControl) { super(tethysControl); this.tethysControl = tethysControl; mainPanel = new JPanel(new BorderLayout()); connectionPanel = new TethysConnectionPanel(tethysControl); + datablockDetectionsPanel = new DatablockDetectionsPanel(tethysControl); datablockSynchPanel = new DatablockSynchPanel(tethysControl); deploymentsPanel = new DeploymentsPanel(tethysControl); + detectionsExportPanel = new DetectionsExportPanel(tethysControl); + datablockSynchPanel.addTableObserver(detectionsExportPanel); + datablockSynchPanel.addTableObserver(datablockDetectionsPanel); - mainPanel.add(BorderLayout.NORTH, connectionPanel.getComponent()); + JSplitPane southwestSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + JPanel southEastPanel = new JPanel(new BorderLayout()); + + JPanel northPanel = new JPanel(new BorderLayout()); + northPanel.add(BorderLayout.CENTER, connectionPanel.getComponent()); + northPanel.add(BorderLayout.WEST, new TethysImagePanel(100)); + mainPanel.add(BorderLayout.NORTH, northPanel); JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); // splitPane.set mainPanel.add(BorderLayout.CENTER, splitPane); // mainPanel.add(BorderLayout.CENTER, datablockSynchPanel.getComponent()); splitPane.add(deploymentsPanel.getComponent()); - splitPane.add(datablockSynchPanel.getComponent()); + southwestSplit.add(datablockSynchPanel.getComponent()); + southwestSplit.add(southEastPanel); + southEastPanel.add(datablockDetectionsPanel.getComponent(), BorderLayout.CENTER); + southEastPanel.add(detectionsExportPanel.getComponent(), BorderLayout.EAST); + splitPane.add(southwestSplit); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { diff --git a/src/tethys/swing/export/DescriptionCard.java b/src/tethys/swing/export/DescriptionCard.java new file mode 100644 index 00000000..13b13ee3 --- /dev/null +++ b/src/tethys/swing/export/DescriptionCard.java @@ -0,0 +1,30 @@ +package tethys.swing.export; + +import java.awt.BorderLayout; + +import PamguardMVC.PamDataBlock; +import tethys.TethysControl; +import tethys.output.StreamExportParams; + +public class DescriptionCard extends ExportWizardCard { + + private DescriptionTypePanel descriptionPanel; + + public DescriptionCard(TethysControl tethysControl, PamDataBlock dataBlock) { + super(tethysControl, "Description", dataBlock); + this.setLayout(new BorderLayout()); + descriptionPanel = new DescriptionTypePanel("Description data", true, true, true); + this.add(BorderLayout.CENTER, descriptionPanel.getMainPanel()); + } + + @Override + public boolean getParams(StreamExportParams streamExportParams) { + return descriptionPanel.getParams(streamExportParams.getDetectionDescription()); + } + + @Override + public void setParams(StreamExportParams streamExportParams) { + descriptionPanel.setParams(streamExportParams.getDetectionDescription()); + } + +} diff --git a/src/tethys/swing/export/DescriptionTypePanel.java b/src/tethys/swing/export/DescriptionTypePanel.java new file mode 100644 index 00000000..2fc968cb --- /dev/null +++ b/src/tethys/swing/export/DescriptionTypePanel.java @@ -0,0 +1,104 @@ +package tethys.swing.export; + +import java.awt.Dimension; +import java.awt.Label; + +import javax.swing.BoxLayout; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.border.TitledBorder; + +import PamView.dialog.PamDialog; +import nilus.DescriptionType; + +/** + * Panel containing the three test entry fields for nilus.DescriptionType + * @author dg50 + * + */ +public class DescriptionTypePanel { + + private JTextArea tObjectives, tAbstract, tMethod; + + private JPanel mainPanel; + + private boolean requireObjective; + + private boolean requireAbstract; + + private boolean requireMethod; + + private static final int ctrlWidth = 40; + + public DescriptionTypePanel(String bordertitle, boolean requireObjective, boolean requireAbstract, boolean requireMethod) { + this.requireObjective = requireObjective; + this.requireAbstract = requireAbstract; + this.requireMethod = requireMethod; + + mainPanel = new JPanel(); + if (bordertitle != null) { + mainPanel.setBorder(new TitledBorder(bordertitle)); + } + tObjectives = new JTextArea(12, ctrlWidth); + tAbstract = new JTextArea(8, ctrlWidth); + tMethod = new JTextArea(9, ctrlWidth); + + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + addScrollablePanel(tObjectives, "Objectives"); + addScrollablePanel(tAbstract, "Abstract"); + addScrollablePanel(tMethod, "Method"); + } + + private void addScrollablePanel(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)); + mainPanel.add(scrollPane); + } + + public JPanel getMainPanel() { + return mainPanel; + } + + public void setParams(DescriptionType description) { + if (description == null) { + tObjectives.setText(null); + tAbstract.setText(null); + tMethod.setText(null); + } + } + + public boolean getParams(DescriptionType description) { + if (checkField(requireObjective, tObjectives) == false) { + return PamDialog.showWarning(null, "Objectives", "The objectives field must be competed"); + } + if (checkField(requireAbstract, tAbstract) == false) { + return PamDialog.showWarning(null, "Abstract", "The abstract field must be competed"); + } + if (checkField(requireMethod, tMethod) == false) { + return PamDialog.showWarning(null, "Method", "The method field must be competed"); + } + + description.setObjectives(tObjectives.getText()); + description.setAbstract(tAbstract.getText()); + description.setMethod(tMethod.getText()); + + return true; + } + + private boolean checkField(boolean required, JTextArea field) { + if (required == false) { + return true; + } + String txt = field.getText(); + if (txt == null || txt.length() == 0) { + return false; + } + return true; + } +} diff --git a/src/tethys/swing/export/DetectionsExportWizard.java b/src/tethys/swing/export/DetectionsExportWizard.java new file mode 100644 index 00000000..1e67d67d --- /dev/null +++ b/src/tethys/swing/export/DetectionsExportWizard.java @@ -0,0 +1,146 @@ +package tethys.swing.export; + +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 javax.swing.JTextArea; +import javax.swing.border.TitledBorder; + +import PamView.dialog.PamDialog; +import PamguardMVC.PamDataBlock; +import tethys.TethysControl; +import tethys.output.StreamExportParams; + +public class DetectionsExportWizard extends PamDialog { + + private PamDataBlock dataBlock; + private CardLayout cardLayout; + private JPanel mainPanel; + private GranularityCard granularityCard; + private DescriptionCard descriptionCard; + private JButton prevButton; + private StreamExportParams streamExportParams; + + private ArrayList wizardCards = new ArrayList(); + + private DetectionsExportWizard(Window parentFrame, TethysControl tethysControl, PamDataBlock dataBlock) { + super(parentFrame, "Detections Export", false); + this.dataBlock = dataBlock; + cardLayout = new CardLayout(); + mainPanel = new JPanel(cardLayout); + + addCard(granularityCard = new GranularityCard(tethysControl, dataBlock)); + addCard(descriptionCard = new DescriptionCard(tethysControl, dataBlock)); + + streamExportParams = tethysControl.getTethysExportParams().getStreamParams(dataBlock); + + cardLayout.first(mainPanel); + + setDialogComponent(mainPanel); + + getOkButton().setText("Next"); + prevButton = new JButton("Previous"); + getButtonPanel().add(prevButton, 0); + prevButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + previousButton(); + } + }); + + setResizable(true); + } + + private void addCard(ExportWizardCard wizPanel) { + mainPanel.add(wizPanel, wizPanel.getTitle()); + wizardCards.add(wizPanel); + } + + public static void showDilaog(Window parentFrame, TethysControl tethysControl, PamDataBlock dataBlock) { + DetectionsExportWizard wiz = new DetectionsExportWizard(parentFrame, tethysControl, dataBlock); + wiz.setParams(); + wiz.setVisible(true); + } + + private void setParams() { + for (ExportWizardCard wizCard : wizardCards) { + wizCard.setParams(streamExportParams); + } +// granularityCard.setParams(streamExportParams); + } + + /** + * Called when 'previous' button is clicked. + */ + protected void previousButton() { + cardLayout.previous(mainPanel); + enableControls(); + } + + @Override + public boolean getParams() { + int iCard = getCardIndex(); + if (iCard < wizardCards.size()-1) { + if (checkCurrentCard()) { + cardLayout.next(mainPanel); + enableControls(); + } + return false; + } + +// if (cardLayout.) +// cardLayout.next(mainPanel); +// System.out.println(mainPanel.getComponent(0).isShowing()); + /* + * there seems to be no obvious way of knowing which card is showing except + * to go through and see which one has isShowing() == true, then test for first and + * last, etc. + */ + enableControls(); + return false; + } + + @Override + public void cancelButtonPressed() { + // TODO Auto-generated method stub + + } + + @Override + public void restoreDefaultSettings() { + // TODO Auto-generated method stub + + } + + private void enableControls() { + int iCard = getCardIndex(); + prevButton.setEnabled(iCard > 0); + boolean isLast = iCard == wizardCards.size()-1; + getOkButton().setText(isLast ? "Export" : "Next"); + } + + private boolean checkCurrentCard() { + int iCard = getCardIndex(); + if (iCard < 0) { + return true; + } + return wizardCards.get(iCard).getParams(streamExportParams); + } + + private int getCardIndex() { + for (int i = 0; i < mainPanel.getComponentCount(); i++) { + Component component = mainPanel.getComponent(i); + if (component.isVisible()) { + return i; + } + } + return -1; + } +} diff --git a/src/tethys/swing/export/ExportWizardCard.java b/src/tethys/swing/export/ExportWizardCard.java new file mode 100644 index 00000000..f81c7b12 --- /dev/null +++ b/src/tethys/swing/export/ExportWizardCard.java @@ -0,0 +1,43 @@ +package tethys.swing.export; + +import javax.swing.JPanel; + +import PamguardMVC.PamDataBlock; +import tethys.TethysControl; +import tethys.output.StreamExportParams; + +/** + * Slightly standardised panels to put into the export wizard + * so that it's easy to work out which 'card' we're on, etc. + * @author dg50 + * + */ +abstract class ExportWizardCard extends JPanel { + + private String title; + private PamDataBlock dataBlock; + private TethysControl tethysControl; + + public ExportWizardCard(TethysControl tethysControl, String title, PamDataBlock dataBlock) { + this.tethysControl = tethysControl; + this.title = title; + this.dataBlock = dataBlock; + } + + public PamDataBlock getDataBlock() { + return dataBlock; + } + + public TethysControl getTethysControl() { + return tethysControl; + } + + public abstract boolean getParams(StreamExportParams streamExportParams); + + public abstract void setParams(StreamExportParams streamExportParams); + + public String getTitle() { + return title; + } + +} diff --git a/src/tethys/swing/export/GranularityCard.java b/src/tethys/swing/export/GranularityCard.java new file mode 100644 index 00000000..768119aa --- /dev/null +++ b/src/tethys/swing/export/GranularityCard.java @@ -0,0 +1,144 @@ +package tethys.swing.export; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; + +import org.w3c.dom.Document; + +import PamController.settings.output.xml.PamguardXMLWriter; +import PamView.dialog.PamGridBagContraints; +import PamguardMVC.PamDataBlock; +import PamguardMVC.dataSelector.DataSelectParams; +import PamguardMVC.dataSelector.DataSelector; +import PamguardMVC.dataSelector.DataSelectorChangeListener; +import nilus.GranularityEnumType; +import tethys.TethysControl; +import tethys.niluswraps.PGranularityType; +import tethys.output.StreamExportParams; + +public class GranularityCard extends ExportWizardCard { + + private JRadioButton[] granularities; + + private JTextArea dataSelectionText; + + private JTextField binLength, encounterGap; + + private DataSelector dataSelector; + + public GranularityCard(TethysControl tethysControl, PamDataBlock dataBlock) { + super(tethysControl, "Granularity", dataBlock); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + // granularity + GranularityEnumType[] grans = GranularityEnumType.values(); + granularities = new JRadioButton[grans.length]; + JPanel granPanel = new JPanel(new GridBagLayout()); + GridBagConstraints c = new PamGridBagContraints(); + granPanel.setBorder(new TitledBorder("Granularity")); + ButtonGroup granGroup = new ButtonGroup(); + for (int i = 0; i < grans.length; i++) { + c.gridx = 0; + granularities[i] = new JRadioButton(PGranularityType.prettyString(grans[i])); + granularities[i].setToolTipText(PGranularityType.toolTip(grans[i])); + granPanel.add(granularities[i], c); + granGroup.add(granularities[i]); + if (grans[i] == GranularityEnumType.BINNED) { + c.gridx++; + granPanel.add(new JLabel(" bin duration ", JLabel.RIGHT), c); + c.gridx++; + granPanel.add(binLength = new JTextField(5), c); + c.gridx++; + granPanel.add(new JLabel(" (s) ", JLabel.LEFT), c); + + } + if (grans[i] == GranularityEnumType.ENCOUNTER) { + c.gridx++; + granPanel.add(new JLabel(" min gap ", JLabel.RIGHT), c); + c.gridx++; + granPanel.add(encounterGap = new JTextField(5), c); + c.gridx++; + granPanel.add(new JLabel(" (s) ", JLabel.LEFT), c); + + } + c.gridy++; + } + this.add(granPanel); + + // data selection + dataSelector = dataBlock.getDataSelector(tethysControl.getDataSelectName(), false); + if (dataSelector != null) { + dataSelectionText = new JTextArea(8, 40); + JPanel dataPanel = new JPanel(new BorderLayout()); + JPanel nPanel = new JPanel(new BorderLayout()); + dataPanel.add(BorderLayout.NORTH, nPanel); + JButton selectorButton = dataSelector.getDialogButton(tethysControl.getGuiFrame(), new DataSelectorChangeListener() { + @Override + public void selectorChange(DataSelector changedSelector) { + newDataSelection(); + } + }); + nPanel.add(BorderLayout.EAST, selectorButton); + newDataSelection(); + nPanel.add(BorderLayout.CENTER, new JLabel("Data selection filter ", JLabel.RIGHT)); + dataPanel.setBorder(new TitledBorder("Data selection filter")); + JScrollPane sp = new JScrollPane(dataSelectionText, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + dataPanel.add(BorderLayout.CENTER, sp); + this.add(dataPanel); + } + + } + + protected void newDataSelection() { + if (dataSelector == null) { + return; + } + DataSelectParams params = dataSelector.getParams(); + if (params == null) { + return; + } + if (params.getCombinationFlag() == 2) { + dataSelectionText.setText("Not enabled"); + return; + } + String txt = dataSelector.getDescription(); + dataSelectionText.setText(txt); + } + + @Override + public boolean getParams(StreamExportParams streamExportParams) { + GranularityEnumType[] grans = GranularityEnumType.values(); + for (int i = 0; i < grans.length; i++) { + if (granularities[i].isSelected()) { + streamExportParams.granularity = grans[i]; + break; + } + } + + return streamExportParams.granularity != null; + } + + @Override + public void setParams(StreamExportParams streamExportParams) { + GranularityEnumType[] grans = GranularityEnumType.values(); + for (int i = 0; i < grans.length; i++) { + granularities[i].setSelected(streamExportParams.granularity == grans[i]); + } + newDataSelection(); + } + +}