package gui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FileDialog; import java.awt.Font; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.border.EmptyBorder; import javax.swing.border.TitledBorder; import javax.swing.JButton; import java.awt.FlowLayout; import javax.swing.Box; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.BoxLayout; import javax.swing.JOptionPane; import javax.swing.JTextField; import common.Config; import common.Location; import common.Log; import common.TlmServer; import java.awt.GridLayout; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; /** * * FOX 1 Telemetry Decoder * @author chris.e.thompson g0kla/ac2cz * * Copyright (C) 2015 amsat.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ @SuppressWarnings("serial") public class SettingsFrame extends JDialog implements ActionListener, ItemListener, FocusListener, WindowListener { public static final int MAX_CALLSIGN_LEN = 32; public static final int MAX_STATION_LEN = 50; private JPanel contentPane; private JTextField txtDisplayModuleFontSize; private JTextField txtGraphAxisFontSize; //private JCheckBox cbHtmlFormatting; private JTextField txtLogFileDirectory; private JTextField txtServerUrl; private JTextField txtCallsign; private JTextField txtLatitude; private JTextField txtLongitude; private JTextField txtMaidenhead; private JTextField txtStation; private JTextField txtAltitude; private JTextField txtPrimaryServer; private JTextField txtSecondaryServer; private JCheckBox cbUploadToServer; private JCheckBox rdbtnTrackSignal; // private JCheckBox cbUseUDP; // private JCheckBox storePayloads; private JCheckBox saveFcdParams; private JCheckBox useLeftStereoChannel; private JCheckBox swapIQ; // private JCheckBox insertMissingBits; // private JCheckBox useLongPRN; private JCheckBox cbUseDDEAzEl; private JCheckBox cbUseDDEFreq; private JCheckBox cbFoxTelemCalcsPosition; private JCheckBox cbFoxTelemCalcsDoppler; private JCheckBox cbWhenAboveHorizon; // private JCheckBox useNCO; // private JCheckBox useCostas; boolean useUDP; private JPanel serverPanel; OptionsPanel optionsPanel; JButton btnSave; JButton btnCancel; JButton btnBrowse; /** * Create the Dialog */ public SettingsFrame(JFrame owner, boolean modal) { super(owner, modal); setTitle("Settings"); addWindowListener(this); // setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); loadProperties(); //this.setResizable(false); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0)); setContentPane(contentPane); // South panel for the buttons JPanel southpanel = new JPanel(); contentPane.add(southpanel, BorderLayout.SOUTH); southpanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); btnSave = new JButton("Save"); btnSave.addActionListener(this); southpanel.add(btnSave); getRootPane().setDefaultButton(btnSave); btnCancel = new JButton("Cancel"); btnCancel.addActionListener(this); southpanel.add(btnCancel); // North panel for settings that span across the window JPanel northpanel = new JPanel(); contentPane.add(northpanel, BorderLayout.NORTH); //JPanel northcolumnpanel = addColumn(northpanel); //txtLogFileDirectory = addSettingsRow(northpanel, 20, "Log files directory", Config.logFileDirectory); //JPanel panel = new JPanel(); //northpanel.add(panel); northpanel.setLayout(new BorderLayout()); JPanel northpanel1 = new JPanel(); JPanel northpanel2 = new JPanel(); JPanel northpanelA = new JPanel(); JPanel northpanelB = new JPanel(); northpanel.add(northpanel1, BorderLayout.NORTH); northpanel1.setLayout(new BorderLayout()); northpanel1.add(northpanelA, BorderLayout.NORTH); northpanel1.add(northpanelB, BorderLayout.SOUTH); northpanel.add(northpanel2, BorderLayout.SOUTH); northpanel2.setLayout(new BorderLayout()); northpanelA.setLayout(new BorderLayout()); northpanelB.setLayout(new BorderLayout()); JLabel lblHomeDir = new JLabel("Home directory "); lblHomeDir.setToolTipText("This is the directory that contains the settings file"); lblHomeDir.setBorder(new EmptyBorder(5, 2, 5, 5) ); northpanelA.add(lblHomeDir, BorderLayout.WEST); JLabel lblHomeDir2 = new JLabel(Config.homeDirectory); northpanelA.add(lblHomeDir2, BorderLayout.CENTER); JLabel lblServerUrl = new JLabel("Server Data URL "); lblServerUrl.setToolTipText("This sets the URL we use to fetch and download server data"); lblServerUrl.setBorder(new EmptyBorder(5, 2, 5, 5) ); northpanelB.add(lblServerUrl, BorderLayout.WEST); txtServerUrl = new JTextField(Config.webSiteUrl); northpanelB.add(txtServerUrl, BorderLayout.CENTER); txtServerUrl.setColumns(30); txtServerUrl.addActionListener(this); JLabel lblLogFilesDir = new JLabel("Log files directory"); lblLogFilesDir.setToolTipText("This sets the directory that the downloaded telemetry data is stored in"); lblLogFilesDir.setBorder(new EmptyBorder(5, 2, 5, 5) ); northpanel2.add(lblLogFilesDir, BorderLayout.WEST); txtLogFileDirectory = new JTextField(Config.logFileDirectory); northpanel2.add(txtLogFileDirectory, BorderLayout.CENTER); txtLogFileDirectory.setColumns(30); txtLogFileDirectory.addActionListener(this); btnBrowse = new JButton("Browse"); btnBrowse.addActionListener(this); northpanel2.add(btnBrowse, BorderLayout.EAST); if (Config.logDirFromPassedParam) { txtLogFileDirectory.setEnabled(false); btnBrowse.setVisible(false); JLabel lblPassedParam = new JLabel(" (Fixed at Startup)"); northpanel2.add(lblPassedParam, BorderLayout.EAST); } // TitledBorder eastTitle1 = new TitledBorder(null, "<html><body> <h3>Files and Directories</h3></body></html>", TitledBorder.LEADING, TitledBorder.TOP, null, null); TitledBorder eastTitle1 = title("Files and Directories"); northpanel.setBorder(eastTitle1); // Center panel for 2 columns of settings JPanel centerpanel = new JPanel(); contentPane.add(centerpanel, BorderLayout.CENTER); //centerpanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); centerpanel.setLayout(new BoxLayout(centerpanel, BoxLayout.X_AXIS)); // Add left column with 3 panels in it JPanel leftcolumnpanel = new JPanel(); JScrollPane leftscrollPane = new JScrollPane (leftcolumnpanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); leftscrollPane.setBorder(new EmptyBorder(5, 2, 5, 5) ); centerpanel.add(leftscrollPane); leftcolumnpanel.setLayout(new BoxLayout(leftcolumnpanel, BoxLayout.PAGE_AXIS)); serverPanel = addColumn(leftcolumnpanel,6); TitledBorder eastTitle2 = title("Ground Station Params"); serverPanel.setBorder(eastTitle2); txtCallsign = addSettingsRow(serverPanel, 5, "Groundstation Name", "Ground station name is the unique identifier that you will use to store data on the AMSAT telemetry server", Config.callsign); txtPrimaryServer = addSettingsRow(serverPanel, 5, "Primary Server", "The address of the Amsat Telemetry server. " + "Should not need to be changed", Config.primaryServer); txtSecondaryServer = addSettingsRow(serverPanel, 5, "Secondary Server", "The backup address of the Amsat Telemetry server. " + "Should not need to be changed",Config.secondaryServer); txtLatitude = addSettingsRow(serverPanel, 4, "Lat (S is -ve)", "Latitude / Longitude or Locator need to be specified if you supply decoded data to AMSAT", Config.latitude); // South is negative txtLongitude = addSettingsRow(serverPanel, 4, "Long (W is -ve)", "Latitude / Longitude or Locator need to be specified if you supply decoded data to AMSAT", Config.longitude); // West is negative JPanel locatorPanel = new JPanel(); JLabel lblLoc = new JLabel("Lat Long gives Locator: "); txtMaidenhead = new JTextField(Config.maidenhead); txtMaidenhead.addActionListener(this); txtMaidenhead.addFocusListener(this); txtMaidenhead.setColumns(7); serverPanel.add(locatorPanel); locatorPanel.add(lblLoc); locatorPanel.add(txtMaidenhead); txtAltitude = addSettingsRow(serverPanel, 5, "Altitude (m)", "Altitude will be supplied to AMSAT along with your data if you specify it", Config.altitude); txtStation = addSettingsRow(serverPanel, 5, "RF-Receiver Description", "RF-Receiver can be specified to give us an idea of the types of stations that are in operation", Config.stationDetails); // min, pref, max - each is Hor, Vert serverPanel.add(new Box.Filler(new Dimension(100,0), new Dimension(100,0), new Dimension(100,0))); // serverPanel.add(new Box.Filler(new Dimension(10,10), new Dimension(100,400), new Dimension(100,500))); JPanel leftcolumnpanel2 = addColumn(leftcolumnpanel,6); TitledBorder eastTitle3 = title("Formatting"); leftcolumnpanel2.setBorder(eastTitle3); txtDisplayModuleFontSize = addSettingsRow(leftcolumnpanel2, 3, "Health Module Font Size", "Change the size of the font on the Satellite tabs so that it is more readable or so that it fits in the space available", Integer.toString(Config.displayModuleFontSize)); txtGraphAxisFontSize = addSettingsRow(leftcolumnpanel2, 3, "Graph Font Size", "Change the size of the font on the graph axis", Integer.toString(Config.graphAxisFontSize)); //JPanel cb = new JPanel(); //leftcolumnpanel2.add(cb); //cbHtmlFormatting = addCheckBoxRow("Use HTML Formatting", Config.htmlFormatting, cb ); // min, pref, max - each is Hor, Vert leftcolumnpanel2.add(new Box.Filler(new Dimension(250,0), new Dimension(250,0), new Dimension(1000,0))); JPanel leftcolumnpanel3 = addColumn(leftcolumnpanel,6); TitledBorder measureTitle = title("Measurements"); leftcolumnpanel3.setBorder(measureTitle); if (Config.useDDEforAzEl) Config.foxTelemCalcsPosition = false; cbUseDDEFreq = addCheckBoxRow("Log Freq from SatPC32 in AF mode", "In AF mode FoxTelem can read the CAT frequency from SatPC32. It is stored alongside other measurements", Config.useDDEforFreq, leftcolumnpanel3 ); cbUseDDEAzEl = addCheckBoxRow("Read position from SatPC32", "FoxTelem can read the position of the satellite from SatPC32. It is stored alongside other measurements", Config.useDDEforAzEl, leftcolumnpanel3 ); if (Config.isWindowsOs()) { cbUseDDEFreq.setVisible(true); cbUseDDEAzEl.setVisible(true); } else { cbUseDDEFreq.setVisible(false); cbUseDDEAzEl.setVisible(false); } cbFoxTelemCalcsPosition = addCheckBoxRow("FoxTelem Calculates Position", "FoxTelem can calculate the position of the spacecraft and store it for analysis", Config.foxTelemCalcsPosition, leftcolumnpanel3 ); cbFoxTelemCalcsDoppler = addCheckBoxRow("FoxTelem Calculates Doppler", "FoxTelem can calculate the doppler shift of the downlink and tune the decoder", Config.foxTelemCalcsDoppler, leftcolumnpanel3 ); cbWhenAboveHorizon = addCheckBoxRow("Auto Start Decoder when above horizon", "FoxTelem can start/stop the decoder when the spacecraft is above/below the horizon", Config.whenAboveHorizon, leftcolumnpanel3 ); if (!Config.foxTelemCalcsPosition) { cbFoxTelemCalcsDoppler.setEnabled(false); } // min, pref, max - each is Hor, Vert leftcolumnpanel3.add(new Box.Filler(new Dimension(250,0), new Dimension(250,0), new Dimension(1000,0))); // min, pref, max - each is Hor, Vert leftcolumnpanel.add(new Box.Filler(new Dimension(0,0), new Dimension(0,0), new Dimension(0,1000))); // Add a right column with two panels in it JPanel rightcolumnpanel = new JPanel(); JScrollPane rightscrollPane = new JScrollPane (rightcolumnpanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); rightscrollPane.setBorder(new EmptyBorder(5, 2, 5, 5) ); centerpanel.add(rightscrollPane); //rightcolumnpanel.setLayout(new GridLayout(2,1,10,10)); rightcolumnpanel.setLayout(new BoxLayout(rightcolumnpanel, BoxLayout.Y_AXIS)); JPanel rightcolumnpanel0 = addColumn(rightcolumnpanel,3); rightcolumnpanel0.setLayout(new BoxLayout(rightcolumnpanel0, BoxLayout.Y_AXIS)); TitledBorder eastTitle4 = title("Decoder Options"); rightcolumnpanel0.setBorder(eastTitle4); cbUploadToServer = addCheckBoxRow("Upload to Server", "Select this if you want to send your collected data to the AMSAT telemetry server", Config.uploadToServer, rightcolumnpanel0 ); rdbtnTrackSignal = addCheckBoxRow("Find Signal","Find and follow the signal. Record the frequency of the downlink. Useful if you are trying to measure the actual spacecraft downlink frequency.", Config.findSignal, rightcolumnpanel0); useUDP = true; if (Config.serverProtocol == TlmServer.TCP) useUDP = false; // cbUseUDP = addCheckBoxRow("Use UDP", "Use UDP (vs TCP) to send data to the AMSAT telemetry server", // useUDP, rightcolumnpanel0 ); // storePayloads = addCheckBoxRow("Store Payloads", "Uncheck this if you do not want to store the decoded payloads on disk", Config.storePayloads, rightcolumnpanel0 ); saveFcdParams = addCheckBoxRow("Store FCD Params", "Save the FCD settings to disk and restore at start up. May conflict with other programs or other copies of FoxTelem.", Config.saveFcdParams, rightcolumnpanel0 ); useLeftStereoChannel = addCheckBoxRow("Use Left Stereo Channel", "The default is for FoxTelem to read audio from the left stereo channel of your soundcard. " + "If you uncheck this it will read from the right", Config.useLeftStereoChannel, rightcolumnpanel0 ); swapIQ = addCheckBoxRow("Swap IQ", "Swap the I and Q channels in IQ deocder mode", Config.swapIQ, rightcolumnpanel0 ); // insertMissingBits = addCheckBoxRow("Fix Dropped Bits", "Fix bits dropped in the audio channel (may fix frames but use more CPU)", // Config.insertMissingBits, rightcolumnpanel0 ); // useNCO = addCheckBoxRow("FSK: Use NCO", "Use Experimental Polyphase filters and numerically controlled oscillator for SDR vs FFT Filter", // Config.useNCO, rightcolumnpanel0 ); // useCostas = addCheckBoxRow("PSK: Use Costas", "Use a coherent Costas Loop Decoder for PSK (better decoder but worse with fading)", // Config.useCostas, rightcolumnpanel0 ); // rightcolumnpanel0.add(new Box.Filler(new Dimension(10,10), new Dimension(150,400), new Dimension(500,500))); // min, pref, max - each is Hor, Vert rightcolumnpanel0.add(new Box.Filler(new Dimension(0,0), new Dimension(100,0), new Dimension(1000,0))); //JPanel rightcolumnpanel1 = addColumn(rightcolumnpanel,3); //txtGraphAxisFontSize = addSettingsRow(rightcolumnpanel, 5, "Graph Font Size", Integer.toString(Config.graphAxisFontSize)); optionsPanel = new OptionsPanel(); rightcolumnpanel.add(optionsPanel); // rightcolumnpanel.add(new Box.Filler(new Dimension(10,10), new Dimension(100,400), new Dimension(100,500))); // min, pref, max - each is Hor, Vert rightcolumnpanel.add(new Box.Filler(new Dimension(0,0), new Dimension(0,0), new Dimension(0,1000))); setServerPanelEnabled(Config.uploadToServer); // cbUseUDP.setEnabled(false); txtPrimaryServer.setEnabled(false); txtSecondaryServer.setEnabled(false); enableDependentParams(); } public void saveProperties() { Config.saveGraphIntParam("Global", 0, 0, "settingsWindow", "windowHeight", this.getHeight()); Config.saveGraphIntParam("Global", 0, 0, "settingsWindow", "windowWidth", this.getWidth()); Config.saveGraphIntParam("Global", 0, 0, "settingsWindow", "windowX", this.getX()); Config.saveGraphIntParam("Global", 0, 0, "settingsWindow", "windowY", this.getY()); } public void loadProperties() { int windowX = Config.loadGraphIntValue("Global", 0, 0, "settingsWindow", "windowX"); int windowY = Config.loadGraphIntValue("Global", 0, 0, "settingsWindow", "windowY"); int windowWidth = Config.loadGraphIntValue("Global", 0, 0, "settingsWindow", "windowWidth"); int windowHeight = Config.loadGraphIntValue("Global", 0, 0, "settingsWindow", "windowHeight"); if (windowX == 0 ||windowY == 0 ||windowWidth == 0 ||windowHeight == 0) { setBounds(100, 100, 725, 700); } else { setBounds(windowX, windowY, windowWidth, windowHeight); } } private TitledBorder title(String s) { TitledBorder title = new TitledBorder(null, s, TitledBorder.LEADING, TitledBorder.TOP, null, null); title.setTitleFont(new Font("SansSerif", Font.BOLD, 14)); return title; } private void setServerPanelEnabled(boolean en) { //serverPanel.setEnabled(en); //txtCallsign.setEnabled(en); // txtPrimaryServer.setEnabled(en); // txtSecondaryServer.setEnabled(en); // cbUseUDP.setEnabled(en); //txtLatitude.setEnabled(en); //txtLongitude.setEnabled(en); } private boolean validLatLong() { float lat = 0, lon = 0; try { lat = Float.parseFloat(txtLatitude.getText()); lon = Float.parseFloat(txtLongitude.getText()); if (lat == Float.parseFloat(Config.DEFAULT_LATITUDE) || txtLatitude.getText().equals("")) return false; if (lon == Float.parseFloat(Config.DEFAULT_LONGITUDE) || txtLongitude.getText().equals("")) return false; } catch (NumberFormatException n) { JOptionPane.showMessageDialog(this, "Only numerical values are valid for the latitude and longitude.", "Format Error\n", JOptionPane.ERROR_MESSAGE); return false; } if ((Float.isNaN(lon)) || (Math.abs(lon) > 180) || (Float.isNaN(lat)) || (Math.abs(lat) == 90.0) || (Math.abs(lat) > 90)) { JOptionPane.showMessageDialog(this, "Invalid latitude or longitude.", "Error\n", JOptionPane.ERROR_MESSAGE); return false; } return true; } private boolean validLocator() { if (txtMaidenhead.getText().equalsIgnoreCase(Config.DEFAULT_LOCATOR) || txtMaidenhead.getText().equals("")) { JOptionPane.showMessageDialog(this, "Enter a latitude/longitude or set the locator to a valid value", "Format Error\n", JOptionPane.ERROR_MESSAGE); return false; } return true; } private boolean validCallsign() { if (txtCallsign.getText().equalsIgnoreCase(Config.DEFAULT_CALLSIGN) || txtCallsign.getText().equals("")) return false; return true; } private boolean validServerParams() { if (!validCallsign()) return false; if (!validLocator()) return false; if (!validLatLong()) return false; if (!validAltitude()) return false; return true; } private JPanel addColumn(JPanel parent, int rows) { JPanel columnpanel = new JPanel(); parent.add(columnpanel); //columnpanel.setLayout(new GridLayout(rows,1,10,10)); columnpanel.setLayout(new BoxLayout(columnpanel, BoxLayout.Y_AXIS)); return columnpanel; } private JCheckBox addCheckBoxRow(String name, String tip, boolean value, JPanel parent) { JCheckBox checkBox = new JCheckBox(name); checkBox.setEnabled(true); checkBox.addItemListener(this); checkBox.setToolTipText(tip); parent.add(checkBox); if (value) checkBox.setSelected(true); else checkBox.setSelected(false); return checkBox; } private JTextField addSettingsRow(JPanel column, int length, String name, String tip, String value) { JPanel panel = new JPanel(); column.add(panel); panel.setLayout(new GridLayout(1,2,5,5)); JLabel lblDisplayModuleFont = new JLabel(name); lblDisplayModuleFont.setToolTipText(tip); panel.add(lblDisplayModuleFont); JTextField textField = new JTextField(value); panel.add(textField); textField.setColumns(length); textField.addActionListener(this); textField.addFocusListener(this); // column.add(new Box.Filler(new Dimension(10,5), new Dimension(10,5), new Dimension(10,5))); return textField; } private boolean validAltitude() { int alt = 0; try { alt = Integer.parseInt(txtAltitude.getText()); } catch (NumberFormatException n) { JOptionPane.showMessageDialog(this, "Only integer values are valid for the altitude. Specify it to the nearest meter, but with no units.", "Format Error\n", JOptionPane.ERROR_MESSAGE); return false; } if ((alt < 0) ||(alt > 8484)) { JOptionPane.showMessageDialog(this, "Invalid altitude. Must be between 0 and 8484m.", "Format Error\n", JOptionPane.ERROR_MESSAGE); return false; } return true; } private void updateLocator() { if (validLatLong()) { Location l = new Location(txtLatitude.getText(), txtLongitude.getText()); txtMaidenhead.setText(l.maidenhead); } } private void updateLatLong() { if (validLocator()) { Location l = new Location(txtMaidenhead.getText()); txtLatitude.setText(Float.toString(l.latitude)); txtLongitude.setText(Float.toString(l.longitude)); } } private void enableDependentParams() { if (validLatLong() && validAltitude()) { if (validCallsign()) cbUploadToServer.setEnabled(true); else cbUploadToServer.setEnabled(false); cbFoxTelemCalcsPosition.setEnabled(true); if (cbFoxTelemCalcsPosition.isSelected()) cbFoxTelemCalcsDoppler.setEnabled(true); else cbFoxTelemCalcsDoppler.setEnabled(false); cbWhenAboveHorizon.setEnabled(true); } else { cbUploadToServer.setEnabled(false); cbFoxTelemCalcsPosition.setEnabled(false); cbFoxTelemCalcsDoppler.setEnabled(false); cbWhenAboveHorizon.setEnabled(false); } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == btnCancel) { this.dispose(); } if (e.getSource() == txtLatitude || e.getSource() == txtLongitude ) { updateLocator(); enableDependentParams(); } if (e.getSource() == txtMaidenhead) { updateLatLong(); enableDependentParams(); } if (e.getSource() == txtAltitude) { validAltitude(); enableDependentParams(); } if (e.getSource() == btnSave) { boolean dispose = true; boolean refreshTabs = false; boolean refreshGraphs = false; Config.uploadToServer = cbUploadToServer.isSelected(); if (Config.uploadToServer && !validServerParams()) { JOptionPane.showMessageDialog(this, "You need to specify a Groundstation name to upload to the server.\n" + "Use an amateur radio callsign or something like 'Sunnytown Primary School'.\n" + "You also need to specify a valid latitude and longitude or a Maidenhead locator.\n" + "If you specify an altitude, then it needs to be a valid value.", "Missing Server Upload Settings", JOptionPane.ERROR_MESSAGE); this.cbUploadToServer.setSelected(false); Config.uploadToServer = cbUploadToServer.isSelected(); } else { // grab all the latest settings Config.callsign = txtCallsign.getText(); Log.println("Setting callsign: " + Config.callsign); if (validLatLong()) { Config.latitude = txtLatitude.getText(); Config.longitude = txtLongitude.getText(); } else { if (txtLatitude.getText().equalsIgnoreCase(Config.DEFAULT_LATITUDE) && txtLongitude.getText().equalsIgnoreCase(Config.DEFAULT_LONGITUDE)) dispose = true; else dispose = false; } if (validLocator()) { Config.maidenhead = txtMaidenhead.getText(); } else dispose = false; if (validAltitude()) { Config.altitude = txtAltitude.getText(); } else dispose = false; Config.stationDetails = txtStation.getText(); Config.primaryServer = txtPrimaryServer.getText(); Config.secondaryServer = txtSecondaryServer.getText(); Config.webSiteUrl = txtServerUrl.getText(); // Config.storePayloads = storePayloads.isSelected(); Config.saveFcdParams = saveFcdParams.isSelected(); Config.useLeftStereoChannel = useLeftStereoChannel.isSelected(); Config.swapIQ = swapIQ.isSelected(); // Config.insertMissingBits = insertMissingBits.isSelected(); // if (Config.useNCO != useNCO.isSelected()) // Log.errorDialog("CHANGED Decoder", "The decoder needs to be stopped and restarted.\n" // + "You do not need to exit FoxTelem."); // Config.useNCO = useNCO.isSelected(); // if (Config.useCostas != useCostas.isSelected()) // Log.errorDialog("CHANGED Decoder", "The decoder needs to be stopped and restarted.\n" // + "You do not need to exit FoxTelem."); // Config.useCostas = useCostas.isSelected(); if (Config.isWindowsOs()) { Config.useDDEforFreq = cbUseDDEFreq.isSelected(); Config.useDDEforAzEl = cbUseDDEAzEl.isSelected(); } if (cbFoxTelemCalcsPosition.isSelected() && !Config.foxTelemCalcsPosition) Config.satManager.fetchTLEFile(); // we are enabling this, better make sure we have a TLE Config.foxTelemCalcsPosition = cbFoxTelemCalcsPosition.isSelected(); Config.foxTelemCalcsDoppler = cbFoxTelemCalcsDoppler.isSelected(); Config.whenAboveHorizon = cbWhenAboveHorizon.isSelected(); Config.findSignal = rdbtnTrackSignal.isSelected(); /* if (cbUseUDP.isSelected()) { Config.serverPort = Config.udpPort; Config.serverProtocol = TlmServer.UDP; } else { Config.serverPort = Config.tcpPort; Config.serverProtocol = TlmServer.TCP; } */ if (Config.displayModuleFontSize != parseIntTextField(txtDisplayModuleFontSize)) { Config.displayModuleFontSize = parseIntTextField(txtDisplayModuleFontSize); Log.println("Setting Health Tab font to: " + Config.displayModuleFontSize); //MainWindow.refreshTabs(false); refreshTabs = true; } if (Config.graphAxisFontSize != parseIntTextField(txtGraphAxisFontSize)) { Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog( MainWindow.frame, "Are you sure you want to change the font size? It will close any open graphs.", "Do you want to continue?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (n == JOptionPane.YES_OPTION) { Config.graphAxisFontSize = parseIntTextField(txtGraphAxisFontSize); Log.println("Setting Graph font to: " + Config.displayModuleFontSize); //MainWindow.refreshTabs(true); refreshTabs = true; refreshGraphs = true; } } if (!Config.logFileDirectory.equalsIgnoreCase(txtLogFileDirectory.getText())) { boolean currentDir = false; if (txtLogFileDirectory.getText().equalsIgnoreCase("")) currentDir = true; File file = new File(txtLogFileDirectory.getText()); //if (!file.isDirectory()) // file = file.getParentFile(); if (!currentDir && (!file.isDirectory() || file == null || !file.exists())){ Log.errorDialog("Invalid directory", "Can not find the specified directory: " + txtLogFileDirectory.getText()); dispose = false; refreshGraphs=false; } else { Object[] options = {"Yes", "No"}; int n = JOptionPane.showOptionDialog( MainWindow.frame, "Do you want to switch log file directories? It will close any open graphs.", "Do you want to continue?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[1]); if (n == JOptionPane.YES_OPTION) { Config.logFileDirectory = txtLogFileDirectory.getText(); Log.println("Setting log file directory to: " + Config.logFileDirectory); Config.totalFrames = 0; Config.initSatelliteManager(); Config.initPayloadStore(); Config.initPassManager(); Config.initSequence(); Config.initServerQueue(); Config.mainWindow.initSatMenu(); refreshTabs = true; refreshGraphs = true; } } } } if (dispose) { Config.save(); Config.storeGroundStation(); this.dispose(); } if (refreshTabs) MainWindow.refreshTabs(refreshGraphs); // We are fully up, remove the database loading message Config.fileProgress.updateProgress(100); } if (e.getSource() == btnBrowse) { File dir = null; if (!Config.logFileDirectory.equalsIgnoreCase("")) { dir = new File(Config.logFileDirectory); } if(Config.isMacOs()) { // not on Linx/windows because native dir chooser does not work) { // use the native file DIR dialog on the mac by default System.setProperty("apple.awt.fileDialogForDirectories", "true"); FileDialog fd = new FileDialog(this, "Choose Directory for Log Files",FileDialog.LOAD); if (dir != null) { fd.setDirectory(dir.getAbsolutePath()); } fd.setVisible(true); System.setProperty("apple.awt.fileDialogForDirectories", "false"); String filename = fd.getFile(); String dirname = fd.getDirectory(); if (filename == null) Log.println("You cancelled the choice"); else { Log.println("File: " + filename); Log.println("DIR: " + dirname); File selectedFile = new File(dirname + filename); txtLogFileDirectory.setText(selectedFile.getAbsolutePath()); } } else { JFileChooser fc = new JFileChooser(); fc.setApproveButtonText("Choose"); if (dir != null) { fc.setCurrentDirectory(dir); } fc.setDialogTitle("Choose Directory for Log Files"); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); fc.setPreferredSize(new Dimension(Config.windowFcWidth, Config.windowFcHeight)); int returnVal = fc.showOpenDialog(this); Config.windowFcHeight = fc.getHeight(); Config.windowFcWidth = fc.getWidth(); if (returnVal == JFileChooser.APPROVE_OPTION) { txtLogFileDirectory.setText(fc.getSelectedFile().getAbsolutePath()); } else { System.out.println("No Selection "); } } } } private int parseIntTextField(JTextField text) { int value = 0; try { value = Integer.parseInt(text.getText()); if (value > 30) { value = 30; text.setText(Integer.toString(30)); } } catch (NumberFormatException ex) { } return value; } @Override public void itemStateChanged(ItemEvent e) { Object source = e.getItemSelectable(); if (source == cbUploadToServer) { if (e.getStateChange() == ItemEvent.DESELECTED) { setServerPanelEnabled(false); } else { setServerPanelEnabled(true); } } if (source == cbUseDDEAzEl) { if (e.getStateChange() == ItemEvent.SELECTED) { cbFoxTelemCalcsPosition.setSelected(false); cbFoxTelemCalcsDoppler.setSelected(false); } } if (source == cbFoxTelemCalcsPosition) { if (e.getStateChange() == ItemEvent.SELECTED) { cbUseDDEAzEl.setSelected(false); cbFoxTelemCalcsDoppler.setEnabled(true); } else { if (cbWhenAboveHorizon.isSelected()) cbWhenAboveHorizon.setSelected(false); if (cbFoxTelemCalcsDoppler.isSelected()) cbFoxTelemCalcsDoppler.setSelected(false); cbFoxTelemCalcsDoppler.setEnabled(false); } } if (source == cbFoxTelemCalcsDoppler) { if (e.getStateChange() == ItemEvent.SELECTED) { rdbtnTrackSignal.setSelected(false); } else { } } if (source == cbWhenAboveHorizon) { if (e.getStateChange() == ItemEvent.SELECTED) { if (!cbFoxTelemCalcsPosition.isSelected() && !cbUseDDEAzEl.isSelected()) cbFoxTelemCalcsPosition.setSelected(true); MainWindow.inputTab.rdbtnFindSignal.setSelected(true); } } if (e.getSource() == rdbtnTrackSignal) { if (e.getStateChange() == ItemEvent.DESELECTED) { Config.findSignal=false; //Config.save(); } else { Config.findSignal=true; cbFoxTelemCalcsDoppler.setSelected(false); //Config.save(); } } } @Override public void focusGained(FocusEvent arg0) { // TODO Auto-generated method stub } @Override public void focusLost(FocusEvent e) { if (e.getSource() == txtCallsign) { if (txtCallsign.getText().length() > MAX_CALLSIGN_LEN) txtCallsign.setText(txtCallsign.getText().substring(0, MAX_CALLSIGN_LEN)); enableDependentParams(); } if (e.getSource() == txtStation) { if (txtStation.getText().length() > MAX_STATION_LEN) txtStation.setText(txtStation.getText().substring(0, MAX_STATION_LEN)); } if (e.getSource() == txtLatitude || e.getSource() == txtLongitude ) { updateLocator(); enableDependentParams(); } if (e.getSource() == txtMaidenhead) { updateLatLong(); enableDependentParams(); } if (e.getSource() == txtAltitude) { validAltitude(); enableDependentParams(); } } @Override public void windowActivated(WindowEvent arg0) { // TODO Auto-generated method stub } @Override public void windowClosed(WindowEvent arg0) { saveProperties(); } @Override public void windowClosing(WindowEvent arg0) { // TODO Auto-generated method stub } @Override public void windowDeactivated(WindowEvent arg0) { // TODO Auto-generated method stub } @Override public void windowDeiconified(WindowEvent arg0) { // TODO Auto-generated method stub } @Override public void windowIconified(WindowEvent arg0) { // TODO Auto-generated method stub } @Override public void windowOpened(WindowEvent arg0) { // TODO Auto-generated method stub } }