]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/gui/profile/ProfileChart.java
Version 15.2, November 2013
[GpsPrune.git] / tim / prune / gui / profile / ProfileChart.java
index 17ea32b2a4c004328b1ce1afcaf592b97423780c..0dcabcb66785b06f1dd9730fc7f3a7025e34d89e 100644 (file)
@@ -15,6 +15,8 @@ import javax.swing.JPopupMenu;
 import tim.prune.I18nManager;
 import tim.prune.config.ColourScheme;
 import tim.prune.config.Config;
+import tim.prune.data.Field;
+import tim.prune.data.FieldList;
 import tim.prune.data.TrackInfo;
 import tim.prune.gui.GenericDisplay;
 
@@ -23,6 +25,17 @@ import tim.prune.gui.GenericDisplay;
  */
 public class ProfileChart extends GenericDisplay implements MouseListener
 {
+       /** Inner class to handle popup menu clicks */
+       class MenuClicker implements ActionListener
+       {
+               private Field _field = null;
+               MenuClicker(Field inField) {_field = inField;}
+               /** React to menu click by changing the field */
+               public void actionPerformed(ActionEvent arg0) {
+                       changeView(_field);
+               }
+       }
+
        /** Current scale factor in x direction*/
        private double _xScaleFactor = 0.0;
        /** Data to show on chart */
@@ -33,15 +46,13 @@ public class ProfileChart extends GenericDisplay implements MouseListener
        private JPopupMenu _popup = null;
 
        /** Possible scales to use */
-       private static final int[] LINE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5};
+       private static final int[] LINE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5, 2, 1};
        /** Border width around black line */
        private static final int BORDER_WIDTH = 6;
        /** Minimum size for profile chart in pixels */
        private static final Dimension MINIMUM_SIZE = new Dimension(200, 110);
        /** Colour to use for text if no data found */
        private static final Color COLOR_NODATA_TEXT = Color.GRAY;
-       /** Chart type */
-       private static enum ChartType {ALTITUDE, SPEED};
 
 
        /**
@@ -54,7 +65,7 @@ public class ProfileChart extends GenericDisplay implements MouseListener
                _data = new AltitudeData(inTrackInfo.getTrack());
                addMouseListener(this);
                setLayout(new FlowLayout(FlowLayout.LEFT));
-               _label = new JLabel("Altitude");
+               _label = new JLabel("Altitude"); // text will be replaced later
                add(_label);
                makePopup();
        }
@@ -79,7 +90,6 @@ public class ProfileChart extends GenericDisplay implements MouseListener
                paintBackground(g, colourScheme);
                if (_track != null && _track.getNumPoints() > 0)
                {
-                       _data.init();
                        _label.setText(_data.getLabel());
                        int width = getWidth();
                        int height = getHeight();
@@ -121,11 +131,14 @@ public class ProfileChart extends GenericDisplay implements MouseListener
                        // horizontal lines for scale - set to round numbers eg 500
                        int lineScale = getLineScale(minValue, maxValue);
                        int scaleValue = (int) (minValue/lineScale + 1) * lineScale;
+                       if (minValue < 0.0) {scaleValue -= lineScale;}
                        int x = 0, y = 0;
+                       final int zeroY = height - BORDER_WIDTH - (int) (yScaleFactor * (0.0 - minValue));
+
                        double value = 0.0;
-                       if (lineScale > 1)
+                       g.setColor(lineColour);
+                       if (lineScale >= 1)
                        {
-                               g.setColor(lineColour);
                                while (scaleValue < maxValue)
                                {
                                        y = height - BORDER_WIDTH - (int) (yScaleFactor * (scaleValue - minValue));
@@ -133,6 +146,12 @@ public class ProfileChart extends GenericDisplay implements MouseListener
                                        scaleValue += lineScale;
                                }
                        }
+                       else if (minValue < 0.0)
+                       {
+                               // just draw zero line
+                               y = zeroY;
+                               g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
+                       }
 
                        try
                        {
@@ -148,8 +167,22 @@ public class ProfileChart extends GenericDisplay implements MouseListener
                                        if (_data.hasData(p))
                                        {
                                                value = _data.getData(p);
-                                               y = (int) (yScaleFactor * (value - minValue));
-                                               g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+                                               // Normal case is the minimum value greater than zero
+                                               if (minValue >= 0)
+                                               {
+                                                       y = (int) (yScaleFactor * (value - minValue));
+                                                       g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+                                               }
+                                               else if (value >= 0.0) {
+                                                       // Bar upwards from the zero line
+                                                       y = height-BORDER_WIDTH - (int) (yScaleFactor * (value - minValue));
+                                                       g.fillRect(BORDER_WIDTH+x, y, barWidth, zeroY - y);
+                                               }
+                                               else {
+                                                       // Bar downwards from the zero line
+                                                       int barHeight = (int) (yScaleFactor * value);
+                                                       g.fillRect(BORDER_WIDTH+x, zeroY, barWidth, -barHeight);
+                                               }
                                        }
                                }
                                // current point (make sure it's drawn last)
@@ -170,10 +203,11 @@ public class ProfileChart extends GenericDisplay implements MouseListener
                        catch (NullPointerException npe) { // ignore, probably due to data being changed
                        }
                        // Draw numbers on top of the graph to mark scale
-                       if (lineScale > 1)
+                       if (lineScale >= 1)
                        {
                                int textHeight = g.getFontMetrics().getHeight();
                                scaleValue = (int) (minValue / lineScale + 1) * lineScale;
+                               if (minValue < 0.0) {scaleValue -= lineScale;}
                                y = 0;
                                g.setColor(currentColour);
                                while (scaleValue < maxValue)
@@ -225,23 +259,45 @@ public class ProfileChart extends GenericDisplay implements MouseListener
        /**
         * Make the popup menu for right-clicking the chart
         */
-       private void makePopup()
+       private synchronized void makePopup()
        {
                _popup = new JPopupMenu();
                JMenuItem altItem = new JMenuItem(I18nManager.getText("fieldname.altitude"));
                altItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               changeView(ChartType.ALTITUDE);
+                               changeView(Field.ALTITUDE);
                        }});
                _popup.add(altItem);
                JMenuItem speedItem = new JMenuItem(I18nManager.getText("fieldname.speed"));
                speedItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               changeView(ChartType.SPEED);
+                               changeView(Field.SPEED);
                        }});
                _popup.add(speedItem);
+               JMenuItem vertSpeedItem = new JMenuItem(I18nManager.getText("fieldname.verticalspeed"));
+               vertSpeedItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               changeView(Field.VERTICAL_SPEED);
+                       }});
+               _popup.add(vertSpeedItem);
+               // Go through track's master field list, see if any other fields to list
+               boolean addSeparator = true;
+               FieldList fields = _track.getFieldList();
+               for (int i=0; i<fields.getNumFields(); i++)
+               {
+                       Field field = fields.getField(i);
+                       if (!field.isBuiltIn())
+                       {
+                               if (addSeparator) {_popup.addSeparator();}
+                               addSeparator = false;
+                               JMenuItem item = new JMenuItem(field.getName());
+                               item.addActionListener(new MenuClicker(field));
+                               _popup.add(item);
+                       }
+               }
        }
 
        /**
@@ -252,7 +308,7 @@ public class ProfileChart extends GenericDisplay implements MouseListener
         */
        private int getLineScale(double inMin, double inMax)
        {
-               if ((inMax - inMin) < 5 || inMax < 0) {
+               if ((inMax - inMin) < 2.0) {
                        return -1;
                }
                int numScales = LINE_SCALES.length;
@@ -275,7 +331,14 @@ public class ProfileChart extends GenericDisplay implements MouseListener
         */
        public void dataUpdated(byte inUpdateType)
        {
-               _data.init();
+               // Try not to recalculate all the values unless necessary
+               if (inUpdateType != SELECTION_CHANGED) {
+                       _data.init(Config.getUnitSet());
+               }
+               // Update the menu if necessary
+               if ((inUpdateType & DATA_ADDED_OR_REMOVED) > 0) {
+                       makePopup();
+               }
                repaint();
        }
 
@@ -313,18 +376,33 @@ public class ProfileChart extends GenericDisplay implements MouseListener
 
        /**
         * Called by clicking on popup menu to change the view
-        * @param inType selected chart type
+        * @param inField field to show
         */
-       private void changeView(ChartType inType)
+       private void changeView(Field inField)
        {
-               if (inType == ChartType.ALTITUDE && !(_data instanceof AltitudeData))
+               if (inField == Field.ALTITUDE)
                {
-                       _data = new AltitudeData(_track);
+                       if (!(_data instanceof AltitudeData)) {
+                               _data = new AltitudeData(_track);
+                       }
                }
-               else if (inType == ChartType.SPEED && !(_data instanceof SpeedData)) {
-                       _data = new SpeedData(_track);
+               else if (inField == Field.SPEED) {
+                       if (!(_data instanceof SpeedData)) {
+                               _data = new SpeedData(_track);
+                       }
+               }
+               else if (inField == Field.VERTICAL_SPEED) {
+                       if (!(_data instanceof VerticalSpeedData)) {
+                               _data = new VerticalSpeedData(_track);
+                       }
+               }
+               else
+               {
+                       if (!(_data instanceof ArbitraryData) || ((ArbitraryData)_data).getField() != inField) {
+                               _data = new ArbitraryData(_track, inField);
+                       }
                }
-               _data.init();
+               _data.init(Config.getUnitSet());
                repaint();
        }