Start Tethys GUI

This commit is contained in:
Douglas Gillespie 2023-03-17 21:26:13 +00:00
parent b344b775ec
commit f51a519d82
13 changed files with 678 additions and 2 deletions

View File

@ -1,7 +1,12 @@
package tethys;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.JFrame;
@ -10,17 +15,20 @@ import javax.swing.JMenuItem;
import PamController.PamControlledUnit;
import PamController.PamController;
import PamView.PamTabPanel;
import PamguardMVC.PamDataBlock;
import metadata.MetaDataContol;
import metadata.deployment.DeploymentData;
import nilus.Deployment.Instrument;
import tethys.dbxml.DBXMLConnect;
import tethys.dbxml.DBXMLQueries;
//import nilus.Deployment;
//import nilus.Deployment.Instrument;
import tethys.output.StreamExportParams;
import tethys.output.TethysExportParams;
import tethys.output.TethysExporter;
import tethys.output.swing.TethysExportDialog;
import tethys.swing.TethysTabPanel;
/**
* Quick play with a simple system for outputting data to Tethys. At it's start
@ -39,10 +47,18 @@ public class TethysControl extends PamControlledUnit {
private TethysExportParams tethysExportParams = new TethysExportParams();
private DBXMLConnect dbxmlConnect;
private TethysTabPanel tethysTabPanel;
private DBXMLQueries dbxmlQueries;
private ArrayList<TethysStateObserver> stateObservers;
public TethysControl(String unitName) {
super(unitType, unitName);
stateObservers = new ArrayList();
dbxmlConnect = new DBXMLConnect(this);
dbxmlQueries = new DBXMLQueries(this);
}
/**
@ -60,15 +76,51 @@ public class TethysControl extends PamControlledUnit {
JMenuItem tethysExport = new JMenuItem("Export ...");
tethysMenu.add(tethysExport);
tethysExport.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tethysExport(parentFrame);
}
});
JMenuItem openClient = new JMenuItem("Open client in browser");
openClient.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
openTethysClient();
}
});
tethysMenu.add(openClient);
return tethysMenu;
}
protected 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();
}
}
@Override
public PamTabPanel getTabPanel() {
if (tethysTabPanel == null) {
tethysTabPanel = new TethysTabPanel(this);
}
return tethysTabPanel;
}
/**
* @return the tethysExportParams
*/
@ -124,7 +176,33 @@ public class TethysControl extends PamControlledUnit {
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
@ -133,4 +211,8 @@ public class TethysControl extends PamControlledUnit {
return getUnitName();
}
public DBXMLQueries getDbxmlQueries() {
return dbxmlQueries;
}
}

View File

@ -0,0 +1,19 @@
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, TRANSFERDATA};
public StateType stateType;
public TethysState(StateType stateType) {
super();
this.stateType = stateType;
}
}

View File

@ -0,0 +1,13 @@
package tethys;
public interface TethysStateObserver {
/**
* Receive state updates when Tethys has done something (made a connection, moved some data, etc.)<br>
* Note that this is for RECEIVING state updates, not for sending them. To avoid infinite notifications
* loops, use tethysControl.sendStateUpdate(TethysState) if this component knows something.
* @param tethysState
*/
public void updateState(TethysState tethysState);
}

View File

@ -9,6 +9,7 @@ import javax.xml.bind.JAXBException;
import java.nio.file.Files;
import java.nio.file.Path;
import dbxml.JerseyClient;
import dbxml.uploader.Importer;
import nilus.Deployment;
import nilus.MarshalXML;
@ -113,6 +114,22 @@ public class DBXMLConnect {
public void closeDatabase() {
}
/**
* Get the server state via a ping ?
* @return String descritption of state ?
*/
public ServerStatus pingServer() {
JerseyClient jerseyClient = new JerseyClient(tethysControl.getTethysExportParams().getFullServerName());
boolean ok = false;
try {
ok = jerseyClient.ping();
}
catch (Exception ex) {
return new ServerStatus(false, ex);
}
return new ServerStatus(ok, null);
}
// add whatever calls are necessary ...

View File

@ -0,0 +1,119 @@
package tethys.dbxml;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import dbxml.JerseyClient;
import tethys.TethysControl;
import tethys.output.TethysExportParams;
/**
* Some standard queries we're going to want to make from various
* parts of the system as the user interracts with the GUI.
* @author dg50
*
*/
public class DBXMLQueries {
private TethysControl tethysControl;
public DBXMLQueries(TethysControl tethysControl) {
super();
this.tethysControl = tethysControl;
}
public ArrayList<String> getProjectNames() {
DBXMLConnect dbxmlConnect = tethysControl.getDbxmlConnect();
ServerStatus serverStatus = dbxmlConnect.pingServer();
if (serverStatus.ok == false) {
return null;
}
Document doc = null;
TethysExportParams params = tethysControl.getTethysExportParams();
try {
JerseyClient jerseyClient = new JerseyClient(params.getFullServerName());
String testJson = "{\"return\":[\"Deployment/Project\"],\"select\":[],\"enclose\":1}";
// web browse to http://localhost:9779/Client
String testResult = jerseyClient.queryJSON(testJson);
doc = convertStringToXMLDocument(testResult);
}
catch (Exception e) {
e.printStackTrace();
}
if (doc == null) {
return null;
}
ArrayList<String> 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 ...
<Return>
<Deployment>
<Project>LJ</Project>
</Deployment>
</Return>
*/
NodeList returns = doc.getElementsByTagName("Return");
// System.out.println("N projects = " + returns.getLength());
int n = returns.getLength();
for (int i = 0; i < n; i++) {
Node aNode = returns.item(i);
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) == false) {
projectNames.add(projName);
}
}
}
}
}
Collections.sort(projectNames);
return projectNames;
}
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;
}
}

View File

@ -1,5 +1,24 @@
package tethys.dbxml;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import PamController.settings.output.xml.PamguardXMLWriter;
import PamUtils.XMLUtils;
import dbxml.JerseyClient;
import tethys.output.TethysExportParams;
@ -14,9 +33,57 @@ public class DMXMLQueryTest {
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;
}
}

View File

@ -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();
}
}

View File

@ -20,7 +20,7 @@ public class TethysExportParams implements Serializable, Cloneable{
*/
public String serverName = "http://localhost";
public String port = "9779";
public int port = 9779;
public String getFullServerName() {
return serverName + ":" + port;

View File

@ -0,0 +1,89 @@
package tethys.swing;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Window;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import PamView.dialog.PamDialog;
import PamView.dialog.PamGridBagContraints;
import tethys.TethysControl;
import tethys.output.TethysExportParams;
public class SelectServerdDialog extends PamDialog {
private static final long serialVersionUID = 1L;
private JTextField serverHost, serverPort;
private TethysExportParams exportParams;
private static SelectServerdDialog singleInstance;
private SelectServerdDialog(TethysControl tethysControl, Window parentFrame) {
super(parentFrame, "Tethys Server", true);
JPanel mainPanel = new JPanel(new GridBagLayout());
mainPanel.setBorder(new TitledBorder("Tethys Server"));
GridBagConstraints c = new PamGridBagContraints();
mainPanel.add(new JLabel("Host: ", JLabel.RIGHT), c);
c.gridx++;
mainPanel.add(serverHost = new JTextField(20), c);
c.gridx = 0;
c.gridy++;
c.fill = GridBagConstraints.NONE;
mainPanel.add(new JLabel("Port: ", JLabel.RIGHT), c);
c.gridx++;
mainPanel.add(serverPort = new JTextField(4), c);
setDialogComponent(mainPanel);
}
public static final TethysExportParams showDialog(TethysControl tethysControl, Window parentFrame, TethysExportParams exportParams) {
if (singleInstance == null) {
singleInstance = new SelectServerdDialog(tethysControl, parentFrame);
}
singleInstance.setParams(exportParams);
singleInstance.setVisible(true);
return singleInstance.exportParams;
}
private void setParams(TethysExportParams exportParams) {
this.exportParams = exportParams;
serverHost.setText(exportParams.serverName);
serverPort.setText(String.format("%d", exportParams.port));
}
@Override
public boolean getParams() {
String newHost = serverHost.getText();
int newPort = 0;
try {
newPort = Integer.valueOf(serverPort.getText());
}
catch (NumberFormatException e) {
return showWarning("Server port must be a valid integer number");
}
exportParams.serverName = newHost;
exportParams.port = newPort;
return true;
}
@Override
public void cancelButtonPressed() {
exportParams = null;
}
@Override
public void restoreDefaultSettings() {
TethysExportParams defaultParams = new TethysExportParams();
exportParams.serverName = defaultParams.serverName;
exportParams.port = defaultParams.port;
setParams(exportParams);
}
}

View File

@ -0,0 +1,128 @@
package tethys.swing;
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.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
import PamView.dialog.PamGridBagContraints;
import PamView.dialog.ScrollingPamLabel;
import PamView.dialog.SettingsButton;
import PamView.panel.PamPanel;
import PamView.panel.WestAlignedPanel;
import pamViewFX.fxNodes.PamComboBox;
import tethys.TethysControl;
import tethys.TethysState;
import tethys.TethysState.StateType;
import tethys.dbxml.ServerStatus;
import tethys.output.TethysExportParams;
/**
* Top strip of main Tethys GUI for connection and project information
* @author dg50
*
*/
public class TethysConnectionPanel extends TethysGUIPanel {
private static final int SERVERNAMELENGTH = 30;
private static final int SERVERSTATUSLENGTH = 20;
private JPanel mainPanel;
private JTextField serverName;
private SettingsButton serverSelButton;
private ScrollingPamLabel serverStatus;
private JComboBox<String> projectList;
public TethysConnectionPanel(TethysControl tethysControl) {
super(tethysControl);
mainPanel = new WestAlignedPanel(new GridBagLayout());
mainPanel.setBorder(new TitledBorder("Connection and project details"));
serverName = new JTextField(SERVERNAMELENGTH);
serverSelButton = new SettingsButton();
serverSelButton.setToolTipText("Select server");
serverStatus = new ScrollingPamLabel(SERVERSTATUSLENGTH);
serverName.setEditable(false);
// serverStatus.setEditable(false);
serverSelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectServer();
}
});
GridBagConstraints c = new PamGridBagContraints();
mainPanel.add(new JLabel("Tethys Server "), c);
c.gridx++;
mainPanel.add(serverName, c);
c.gridx++;
mainPanel.add(serverSelButton, c);
c.gridx++;
mainPanel.add(serverStatus, c);
c.gridx++;
c.gridx =0;
c.gridy++;
mainPanel.add(new JLabel("Projects "), c);
c.gridx++;
mainPanel.add(projectList = new JComboBox<>(), c);
fillServerControl();
}
protected void selectServer() {
// will return the same object at the moment, so no need to do anything.
TethysExportParams newParams = SelectServerdDialog.showDialog(getTethysControl(), getTethysControl().getGuiFrame(), getTethysControl().getTethysExportParams());
if (newParams != null) {
getTethysControl().sendStateUpdate(new TethysState(TethysState.StateType.UPDATESERVER));
}
}
private void fillServerControl() {
TethysExportParams exportParams = getTethysControl().getTethysExportParams();
serverName.setText(exportParams.getFullServerName());
ServerStatus status = getTethysControl().getDbxmlConnect().pingServer();
serverStatus.setText(status.toString());
}
@Override
public JComponent getComponent() {
return mainPanel;
}
@Override
public void updateState(TethysState tethysState) {
super.updateState(tethysState);
if (tethysState.stateType == StateType.UPDATESERVER) {
fillServerControl();
updateProjectList();
}
}
private void updateProjectList() {
projectList.removeAllItems();
ArrayList<String> dbNames = getTethysControl().getDbxmlQueries().getProjectNames();
if (dbNames == null || dbNames.size() == 0) {
System.out.println("No existing projects");
return;
}
for (int i = 0; i < dbNames.size(); i++) {
projectList.addItem(dbNames.get(i));
}
}
}

View File

@ -0,0 +1,31 @@
package tethys.swing;
import javax.swing.JComponent;
import tethys.TethysControl;
import tethys.TethysState;
import tethys.TethysStateObserver;
public abstract class TethysGUIPanel implements TethysStateObserver {
private TethysControl tethysControl;
public TethysGUIPanel(TethysControl tethysControl) {
super();
this.tethysControl = tethysControl;
tethysControl.addStateObserver(this);
}
public TethysControl getTethysControl() {
return tethysControl;
}
public abstract JComponent getComponent();
@Override
public void updateState(TethysState tethysState) {
}
}

View File

@ -0,0 +1,36 @@
package tethys.swing;
import java.awt.BorderLayout;
import javax.swing.JComponent;
import javax.swing.JPanel;
import tethys.TethysControl;
public class TethysMainPanel extends TethysGUIPanel {
private TethysControl tethysControl;
private JPanel mainPanel;
private TethysConnectionPanel connectionPanel;
public TethysMainPanel(TethysControl tethysControl) {
super(tethysControl);
this.tethysControl = tethysControl;
mainPanel = new JPanel(new BorderLayout());
connectionPanel = new TethysConnectionPanel(tethysControl);
mainPanel.add(BorderLayout.NORTH, connectionPanel.getComponent());
}
public JPanel getMainPanel() {
return mainPanel;
}
@Override
public JComponent getComponent() {
return getMainPanel();
}
}

View File

@ -0,0 +1,40 @@
package tethys.swing;
import java.awt.Frame;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JToolBar;
import PamView.PamTabPanel;
import tethys.TethysControl;
public class TethysTabPanel implements PamTabPanel {
private TethysControl tethysContol;
private TethysMainPanel tethysMainPanel;
@Override
public JMenu createMenu(Frame parentFrame) {
return null;
}
public TethysTabPanel(TethysControl tethysContol) {
super();
this.tethysContol = tethysContol;
tethysMainPanel = new TethysMainPanel(tethysContol);
}
@Override
public JComponent getPanel() {
return tethysMainPanel.getMainPanel();
}
@Override
public JToolBar getToolBar() {
// TODO Auto-generated method stub
return null;
}
}