]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/function/weather/GetWeatherForecastFunction.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / tim / prune / function / weather / GetWeatherForecastFunction.java
diff --git a/tim/prune/function/weather/GetWeatherForecastFunction.java b/tim/prune/function/weather/GetWeatherForecastFunction.java
deleted file mode 100644 (file)
index 970d022..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-package tim.prune.function.weather;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.ScrollPaneConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.table.TableCellRenderer;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import tim.prune.App;
-import tim.prune.GenericFunction;
-import tim.prune.GpsPrune;
-import tim.prune.I18nManager;
-import tim.prune.data.DataPoint;
-import tim.prune.data.NumberUtils;
-import tim.prune.data.Track;
-import tim.prune.function.browser.BrowserLauncher;
-
-/**
- * Function to display a weather forecast for the current location
- * using the services of openweathermap.org
- */
-public class GetWeatherForecastFunction extends GenericFunction implements Runnable
-{
-       /** Dialog object */
-       private JDialog _dialog = null;
-       /** Label for location */
-       private JLabel _locationLabel = null;
-       /** Label for the forecast update time */
-       private JLabel _updateTimeLabel = null;
-       /** Label for the sunrise and sunset times */
-       private JLabel _sunriseLabel = null;
-       /** Radio button for selecting current weather */
-       private JRadioButton _currentForecastRadio = null;
-       /** Radio button for selecting daily forecasts */
-       private JRadioButton _dailyForecastRadio = null;
-       /** Dropdown for selecting celsius / fahrenheit */
-       private JComboBox<String> _tempUnitsDropdown = null;
-       /** Table to hold the forecasts */
-       private JTable _forecastsTable = null;
-       /** Table model */
-       private WeatherTableModel _tableModel = new WeatherTableModel();
-       /** Set of previously obtained results, to avoid repeating calls */
-       private ResultSet _resultSet = new ResultSet();
-       /** Location id obtained from current forecast */
-       private String _locationId = null;
-       /** Flag to show that forecast is currently running, don't start another */
-       private boolean _isRunning = false;
-
-       /** True to just simulate the calls and read files instead, false to call real API */
-       private static final boolean SIMULATE_WITH_FILES = false;
-       /** Unique API key for GpsPrune */
-       private static final String OPENWEATHERMAP_API_KEY = "d1c5d792362f5a5c2eacf70a3b72ecd6";
-
-
-       /**
-        * Inner class to pass results asynchronously to the table model
-        */
-       private class ResultUpdater implements Runnable
-       {
-               private WeatherResults _results;
-               public ResultUpdater(WeatherResults inResults) {
-                       _results = inResults;
-               }
-               public void run() {
-                       _tableModel.setResults(_results);
-                       adjustTable();
-               }
-       }
-
-
-       /** Constructor */
-       public GetWeatherForecastFunction(App inApp)
-       {
-               super(inApp);
-       }
-
-       /** @return name key */
-       public String getNameKey() {
-               return "function.getweatherforecast";
-       }
-
-       /**
-        * Begin the function
-        */
-       public void begin()
-       {
-               // Initialise dialog, show empty list
-               if (_dialog == null)
-               {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
-                       _dialog.setLocationRelativeTo(_parentFrame);
-                       _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
-                       _dialog.getContentPane().add(makeDialogComponents());
-                       _dialog.pack();
-               }
-               // Clear results
-               _locationId = null;
-               _tableModel.clear();
-               _locationLabel.setText(I18nManager.getText("confirm.running"));
-               _updateTimeLabel.setText("");
-               _sunriseLabel.setText("");
-               _currentForecastRadio.setSelected(true);
-
-               // Start new thread to load list asynchronously
-               new Thread(this).start();
-
-               _dialog.setVisible(true);
-       }
-
-       /**
-        * Create dialog components
-        * @return Panel containing all gui elements in dialog
-        */
-       private Component makeDialogComponents()
-       {
-               JPanel dialogPanel = new JPanel();
-               dialogPanel.setLayout(new BorderLayout(0, 4));
-
-               JPanel topPanel = new JPanel();
-               topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.Y_AXIS));
-               _locationLabel = new JLabel(I18nManager.getText("confirm.running"));
-               _locationLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
-               topPanel.add(_locationLabel);
-               _updateTimeLabel = new JLabel(" ");
-               _updateTimeLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
-               topPanel.add(_updateTimeLabel);
-               _sunriseLabel = new JLabel(" ");
-               _sunriseLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
-               topPanel.add(_sunriseLabel);
-               JPanel radioPanel = new JPanel();
-               radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.X_AXIS));
-               radioPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
-               ButtonGroup forecastTypeGroup = new ButtonGroup();
-               _currentForecastRadio = new JRadioButton(I18nManager.getText("dialog.weather.currentforecast"));
-               _dailyForecastRadio = new JRadioButton(I18nManager.getText("dialog.weather.dailyforecast"));
-               JRadioButton threeHourlyRadio = new JRadioButton(I18nManager.getText("dialog.weather.3hourlyforecast"));
-               forecastTypeGroup.add(_currentForecastRadio);
-               forecastTypeGroup.add(_dailyForecastRadio);
-               forecastTypeGroup.add(threeHourlyRadio);
-               radioPanel.add(_currentForecastRadio);
-               radioPanel.add(_dailyForecastRadio);
-               radioPanel.add(threeHourlyRadio);
-               _currentForecastRadio.setSelected(true);
-               ActionListener radioListener = new ActionListener() {
-                       public void actionPerformed(ActionEvent arg0) {
-                               if (!_isRunning) new Thread(GetWeatherForecastFunction.this).start();
-                       }
-               };
-               _currentForecastRadio.addActionListener(radioListener);
-               _dailyForecastRadio.addActionListener(radioListener);
-               threeHourlyRadio.addActionListener(radioListener);
-               radioPanel.add(Box.createHorizontalGlue());
-               radioPanel.add(Box.createHorizontalStrut(40));
-
-               // Dropdown for temperature units
-               radioPanel.add(new JLabel(I18nManager.getText("dialog.weather.temperatureunits") + ": "));
-               _tempUnitsDropdown = new JComboBox<String>(new String[] {
-                       I18nManager.getText("units.degreescelsius"), I18nManager.getText("units.degreesfahrenheit")
-               });
-               _tempUnitsDropdown.setMaximumSize(_tempUnitsDropdown.getPreferredSize());
-               _tempUnitsDropdown.addActionListener(radioListener);
-               radioPanel.add(_tempUnitsDropdown);
-               radioPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
-               topPanel.add(radioPanel);
-               dialogPanel.add(topPanel, BorderLayout.NORTH);
-
-               final IconRenderer iconRenderer = new IconRenderer();
-               _forecastsTable = new JTable(_tableModel)
-               {
-                       public TableCellRenderer getCellRenderer(int row, int column) {
-                               if ((row == WeatherTableModel.ROW_ICON)) {
-                                       return iconRenderer;
-                               }
-                               return super.getCellRenderer(row, column);
-                       }
-               };
-               _forecastsTable.setRowSelectionAllowed(false);
-               _forecastsTable.setRowHeight(2, 55); // make just that row high enough to see icons
-               _forecastsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
-               _forecastsTable.getTableHeader().setReorderingAllowed(false);
-               _forecastsTable.setShowHorizontalLines(false);
-
-               JScrollPane scroller = new JScrollPane(_forecastsTable);
-               scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
-               scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
-               scroller.setPreferredSize(new Dimension(500, 210));
-               scroller.getViewport().setBackground(Color.white);
-
-               dialogPanel.add(scroller, BorderLayout.CENTER);
-
-               // button panel at bottom
-               JPanel buttonPanel = new JPanel();
-               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-               JButton launchButton = new JButton(I18nManager.getText("button.showwebpage"));
-               launchButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent arg0) {
-                               BrowserLauncher.launchBrowser("http://openweathermap.org/city/" + (_locationId == null ? "" : _locationId));
-                       }
-               });
-               buttonPanel.add(launchButton);
-               // close
-               JButton closeButton = new JButton(I18nManager.getText("button.close"));
-               closeButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _dialog.dispose();
-                       }
-               });
-               buttonPanel.add(closeButton);
-               // Add a holder panel with a static label to credit openweathermap
-               JPanel southPanel = new JPanel();
-               southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.Y_AXIS));
-               southPanel.add(new JLabel(I18nManager.getText("dialog.weather.creditnotice")));
-               southPanel.add(buttonPanel);
-               dialogPanel.add(southPanel, BorderLayout.SOUTH);
-               dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
-               return dialogPanel;
-       }
-
-       /**
-        * Get the weather forecast in a separate thread
-        */
-       public void run()
-       {
-               if (_isRunning) {return;} // don't run twice
-               _isRunning = true;
-
-               // Are we getting the current details, or getting a forecast?
-               final boolean isCurrent = _locationId == null || _currentForecastRadio.isSelected();
-               final boolean isDailyForecast = _dailyForecastRadio.isSelected() && !isCurrent;
-               final boolean isHourlyForecast = !isCurrent && !isDailyForecast;
-               final boolean isUsingCelsius  = _tempUnitsDropdown.getSelectedIndex() == 0;
-
-               // Have we got these results already?  Look in store
-               WeatherResults results = _resultSet.getWeather(_locationId, isCurrent, isDailyForecast, isHourlyForecast, isUsingCelsius);
-               if (results == null)
-               {
-                       if (isCurrent)
-                       {
-                               // Get the current details using either lat/long or locationId
-                               results = getCurrentWeather(isUsingCelsius);
-                               // If the current radio isn't selected, select it
-                               if (!_currentForecastRadio.isSelected()) {
-                                       _currentForecastRadio.setSelected(true);
-                               }
-                       }
-                       else
-                       {
-                               // Get the specified forecast using the retrieved locationId
-                               results = getWeatherForecast(isDailyForecast, isUsingCelsius);
-                       }
-                       // If it's a valid answer, store it for later
-                       if (results != null)
-                       {
-                               _resultSet.setWeather(results, _locationId, isCurrent, isDailyForecast, isHourlyForecast, isUsingCelsius);
-                       }
-               }
-
-               // update table contents and labels
-               if (results != null)
-               {
-                       SwingUtilities.invokeLater(new ResultUpdater(results));
-                       _locationLabel.setText(I18nManager.getText("dialog.weather.location") + ": " + results.getLocationName());
-                       final String ut = results.getUpdateTime();
-                       _updateTimeLabel.setText(I18nManager.getText("dialog.weather.update") + ": " + (ut == null ? "" : ut));
-                       if (results.getSunriseTime() != null && results.getSunsetTime() != null)
-                       {
-                               _sunriseLabel.setText(I18nManager.getText("dialog.weather.sunrise") + ": " + results.getSunriseTime()
-                                       + ", " + I18nManager.getText("dialog.weather.sunset") + ": " + results.getSunsetTime());
-                       }
-                       else {
-                               _sunriseLabel.setText("");
-                       }
-               }
-
-               // finished running
-               _isRunning = false;
-       }
-
-
-       /**
-        * Adjust the column widths and row heights to fit the displayed data
-        */
-       private void adjustTable()
-       {
-               if (!_tableModel.isEmpty())
-               {
-                       // adjust column widths for all columns
-                       for (int i=0; i<_forecastsTable.getColumnCount(); i++)
-                       {
-                               double maxWidth = 0.0;
-                               for (int j=0; j<_forecastsTable.getRowCount(); j++)
-                               {
-                                       final String value = _tableModel.getValueAt(j, i).toString();
-                                       maxWidth = Math.max(maxWidth, _forecastsTable.getCellRenderer(0, 0).getTableCellRendererComponent(
-                                               _forecastsTable, value, false, false, 0, 0).getPreferredSize().getWidth());
-                               }
-                               _forecastsTable.getColumnModel().getColumn(i).setMinWidth((int) maxWidth + 2);
-                       }
-                       // Set minimum row heights
-                       final int labelHeight = (int) (_forecastsTable.getCellRenderer(0, 0).getTableCellRendererComponent(
-                               _forecastsTable, "M", false, false, 0, 0).getMinimumSize().getHeight() * 1.2f + 4);
-                       for (int i=0; i<_forecastsTable.getRowCount(); i++)
-                       {
-                               if (i == WeatherTableModel.ROW_ICON) {
-                                       _forecastsTable.setRowHeight(i, 55);
-                               }
-                               else {
-                                       _forecastsTable.setRowHeight(i, labelHeight);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Get the current weather using the lat/long and populate _results
-        * @param inUseCelsius true for celsius, false for fahrenheit
-        * @return weather results
-        */
-       private WeatherResults getCurrentWeather(boolean inUseCelsius)
-       {
-               final Track track = _app.getTrackInfo().getTrack();
-               if (track.getNumPoints() < 1) {return null;}
-               // Get coordinates to lookup
-               double lat = 0.0, lon = 0.0;
-               // See if a point is selected, if so use that
-               DataPoint currPoint = _app.getTrackInfo().getCurrentPoint();
-               if (currPoint != null)
-               {
-                       // Use selected point
-                       lat = currPoint.getLatitude().getDouble();
-                       lon = currPoint.getLongitude().getDouble();
-               }
-               else
-               {
-                       lat = track.getLatRange().getMidValue();
-                       lon = track.getLonRange().getMidValue();
-               }
-
-               InputStream inStream = null;
-               // Build url either with coordinates or with location id if available
-               final String urlString = "http://api.openweathermap.org/data/2.5/weather?"
-                       + (_locationId == null ? ("lat=" + NumberUtils.formatNumberUk(lat, 5) + "&lon=" + NumberUtils.formatNumberUk(lon, 5))
-                               : ("id=" + _locationId))
-                       + "&lang=" + I18nManager.getText("openweathermap.lang")
-                       + "&mode=xml&units=" + (inUseCelsius ? "metric" : "imperial")
-                       + "&APPID=" + OPENWEATHERMAP_API_KEY;
-               // System.out.println(urlString);
-
-               // Parse the returned XML with a special handler
-               OWMCurrentHandler xmlHandler = new OWMCurrentHandler();
-               try
-               {
-                       URL url = new URL(urlString);
-                       SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
-                       // DEBUG: Simulate the call in case of no network connection
-                       if (SIMULATE_WITH_FILES)
-                       {
-                               inStream = new FileInputStream(new File("tim/prune/test/examplecurrentweather.xml"));
-                               try {
-                                       Thread.sleep(2000);
-                               } catch (InterruptedException tie) {}
-                       }
-                       else
-                       {
-                               URLConnection conn = url.openConnection();
-                               conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
-                               inStream = conn.getInputStream();
-                       }
-
-                       saxParser.parse(inStream, xmlHandler);
-               }
-               catch (Exception e)
-               {
-                       // Show error message but don't close dialog
-                       _app.showErrorMessageNoLookup(getNameKey(), e.getClass().getName() + " - " + e.getMessage());
-                       _isRunning = false;
-                       return null;
-               }
-               // Close stream and ignore errors
-               try {
-                       inStream.close();
-               } catch (Exception e) {}
-
-               // Save the location id
-               if (xmlHandler.getLocationId() != null) {
-                       _locationId = xmlHandler.getLocationId();
-               }
-               // Get the results from the handler and return
-               WeatherResults results = new WeatherResults();
-               results.setForecast(xmlHandler.getCurrentWeather());
-               results.setLocationName(xmlHandler.getLocationName());
-               results.setUpdateTime(xmlHandler.getUpdateTime());
-               results.setSunriseSunsetTimes(xmlHandler.getSunriseTime(), xmlHandler.getSunsetTime());
-               results.setTempsCelsius(inUseCelsius);
-               return results;
-       }
-
-
-       /**
-        * Get the weather forecast for the current location id and populate in _results
-        * @param inDaily true for daily, false for 3-hourly
-        * @param inCelsius true for celsius, false for fahrenheit
-        * @return weather results
-        */
-       private WeatherResults getWeatherForecast(boolean inDaily, boolean inCelsius)
-       {
-               InputStream inStream = null;
-               // Build URL
-               final String forecastCount = inDaily ? "8" : "3";
-               final String urlString = "http://api.openweathermap.org/data/2.5/forecast"
-                       + (inDaily ? "/daily" : "") + "?id=" + _locationId + "&lang=" + I18nManager.getText("openweathermap.lang")
-                       + "&mode=xml&units=" + (inCelsius ? "metric" : "imperial") + "&cnt=" + forecastCount
-                       + "&APPID=" + OPENWEATHERMAP_API_KEY;
-               // System.out.println(urlString);
-
-               // Parse the returned XML with a special handler
-               OWMForecastHandler xmlHandler = new OWMForecastHandler();
-               try
-               {
-                       URL url = new URL(urlString);
-                       SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
-                       // DEBUG: Simulate the call in case of no network connection
-                       if (SIMULATE_WITH_FILES)
-                       {
-                               inStream = new FileInputStream(new File("tim/prune/test/exampleweatherforecast.xml"));
-                               try {
-                                       Thread.sleep(2000);
-                               } catch (InterruptedException tie) {}
-                       }
-                       else
-                       {
-                               URLConnection conn = url.openConnection();
-                               conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
-                               inStream = conn.getInputStream();
-                       }
-
-                       saxParser.parse(inStream, xmlHandler);
-               }
-               catch (Exception e)
-               {
-                       // Show error message but don't close dialog
-                       _app.showErrorMessageNoLookup(getNameKey(), e.getClass().getName() + " - " + e.getMessage());
-                       _isRunning = false;
-                       return null;
-               }
-               // Close stream and ignore errors
-               try {
-                       inStream.close();
-               } catch (Exception e) {}
-
-               // Get results from handler, put in model
-               WeatherResults results = new WeatherResults();
-               results.setForecasts(xmlHandler.getForecasts());
-               results.setLocationName(xmlHandler.getLocationName());
-               results.setUpdateTime(xmlHandler.getUpdateTime());
-               results.setTempsCelsius(inCelsius);
-               return results;
-       }
-}