diff --git a/properties/MessageBundle.properties b/properties/MessageBundle.properties index fd02447..d6ac522 100644 --- a/properties/MessageBundle.properties +++ b/properties/MessageBundle.properties @@ -61,6 +61,8 @@ maxhr=Max HeartRate fthr=Functional Threshold HeartRate avehr=Average HeartRate avepow=Average Power +avecad=Average Cadence +maxcad=Maximum Cadence maxpow=Max Power qpow=Quadratic Power cftp=Current FTP @@ -95,8 +97,8 @@ personal_data=Your Information your_weight=Your Weight bike_weight=Bike Weight wheel_size=Wheel Diameter -fthr=Functional Threshold Heart Rate -ftp=Functional Threshold Power +fthr=FT Heart Rate +ftp=FT Power metric= trainer=Trainer resistance=Resistance Levels @@ -106,6 +108,7 @@ profile=Select your trainer error=Error warning=Warning +ftpWarning=Set Threshold Power in Preferences start=Start stop=Stop diff --git a/src/com/wattzap/model/DataStore.java b/src/com/wattzap/model/DataStore.java index 0a4460f..bd98670 100644 --- a/src/com/wattzap/model/DataStore.java +++ b/src/com/wattzap/model/DataStore.java @@ -220,8 +220,6 @@ public void updateWorkout(String user, WorkoutData data) { psUpdate.setString(17, data.getTcxFile()); int i = psUpdate.executeUpdate(); - - System.out.println("i " + i); conn.commit(); } catch (SQLException e) { diff --git a/src/com/wattzap/model/GPXReader.java b/src/com/wattzap/model/GPXReader.java index 5589ea6..8861822 100644 --- a/src/com/wattzap/model/GPXReader.java +++ b/src/com/wattzap/model/GPXReader.java @@ -108,6 +108,7 @@ public double getDistanceMeters() { * */ public void load(String filename) { + points = null; gpxFile = new GPXFile(new File(filename)); fileName = filename.substring(0, filename.lastIndexOf('.')); diff --git a/src/com/wattzap/model/UserPreferences.java b/src/com/wattzap/model/UserPreferences.java index e000e3f..cef47ae 100644 --- a/src/com/wattzap/model/UserPreferences.java +++ b/src/com/wattzap/model/UserPreferences.java @@ -135,7 +135,7 @@ public double getWeight() { return getDouble("weight", 80.0); } else { // convert to lbs - return getDouble("weight", 80.0) / 0.45359237; + return getDouble("weight", 80.0) / LBSTOKG; } } diff --git a/src/com/wattzap/model/ant/AdvancedSpeedCadenceListener.java b/src/com/wattzap/model/ant/AdvancedSpeedCadenceListener.java index ec0a93f..097ab65 100644 --- a/src/com/wattzap/model/ant/AdvancedSpeedCadenceListener.java +++ b/src/com/wattzap/model/ant/AdvancedSpeedCadenceListener.java @@ -201,7 +201,7 @@ public void receiveMessage(BroadcastDataMessage message) { double ratio = (powerWatts / p.getPower()); // speed is video speed * power ratio speed = p.getSpeed() * ratio; - System.out.println("speed " + speed + " ratio " + ratio + " power " + powerWatts + " tpower " + p.getPower()); + // System.out.println("speed " + speed + " ratio " + ratio + " power " + powerWatts + " tpower " + p.getPower()); distanceKM = (speed / 3600) * timeS; diff --git a/src/com/wattzap/view/AboutPanel.java b/src/com/wattzap/view/AboutPanel.java index 16b8311..278c01b 100644 --- a/src/com/wattzap/view/AboutPanel.java +++ b/src/com/wattzap/view/AboutPanel.java @@ -58,7 +58,7 @@ public class AboutPanel extends JFrame implements ActionListener { private static final String decodeKey = "CAFEBABE"; // WattzAp Virtual Turbo Trainer

Version: x.x.x //
Date: xx xxx xxx
(c) xxxx, All rights reserved
- private static final String blurb = "fykyKC5/FSQ3NTwEMmEWMDEjKWUWMyMsLSQ0ZREuJDE0IDQgfiMwan19JDdtfxQgMTIvKix7Yndtc2h0fiMwan0FJzEne2JyNylmCiE1LScmM3onMG58bSBoZndycHZpYwAqKWIzKyIrNTVlMCQxIDE3IyF+IzBqfQ=="; + private static final String blurb = "fykyKC5/FSQ3NTwEMmEWMDEjKWUWMyMsLSQ0ZREuJDE0IDQgfiMwan19JDdtfxQgMTIvKix7YndtcnonMG58ASI1I39ieDYtYw8pMycsICAxfSQ3bX9qJmphdHVzdW5lAi0qZTAoJS03MmY3JzInNzUkInkgM217"; // Your software is registered private static final String registered = "Gi4zN2IyLSM3Nic3J2ErNmMzIyIrMjYgMSQi"; // Incorrect registration key diff --git a/src/com/wattzap/view/ControlPanel.java b/src/com/wattzap/view/ControlPanel.java index db94b39..2b5e81a 100644 --- a/src/com/wattzap/view/ControlPanel.java +++ b/src/com/wattzap/view/ControlPanel.java @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License * along with Wattzap. If not, see . -*/ + */ package com.wattzap.view; import java.awt.Color; @@ -21,9 +21,12 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import javax.swing.BorderFactory; import javax.swing.JButton; +import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSlider; +import javax.swing.border.Border; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -34,6 +37,8 @@ import com.wattzap.model.UserPreferences; /** + * Control button panel at bottom of main screen to start/stop routes + * * (c) 2014 David George / Wattzap.com * * @author David George @@ -42,15 +47,16 @@ public class ControlPanel extends JPanel implements ActionListener, ChangeListener, MessageCallback { private static final long serialVersionUID = 1L; + private final static UserPreferences userPrefs = UserPreferences.INSTANCE; private JSlider startPosition; private int start; public ControlPanel() { - JButton stopButton = new JButton(UserPreferences.INSTANCE.messages - .getString("stop")); + JButton stopButton = new JButton( + UserPreferences.INSTANCE.messages.getString("stop")); stopButton.setActionCommand("stop"); - JButton startButton = new JButton(UserPreferences.INSTANCE.messages - .getString("start")); + JButton startButton = new JButton( + UserPreferences.INSTANCE.messages.getString("start")); startButton.setActionCommand("start"); startButton.addActionListener(this); @@ -62,14 +68,25 @@ public ControlPanel() { MessageBus.INSTANCE.register(Messages.GPXLOAD, this); MessageBus.INSTANCE.register(Messages.CLOSE, this); - - + + // Border b = BorderFactory.createLineBorder( Color.black, 10 ); + Border b = BorderFactory.createEmptyBorder(10, 0, 10, 0); + this.setBorder(b); + } @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if ("start".equals(command)) { + if (!userPrefs.isAntEnabled() && userPrefs.getMaxPower() == 0) { + JOptionPane.showMessageDialog(this, + UserPreferences.INSTANCE.messages + .getString("ftpWarning"), + UserPreferences.INSTANCE.messages.getString("warning"), + JOptionPane.WARNING_MESSAGE); + } + MessageBus.INSTANCE.send(Messages.START, new Double(start)); } else { MessageBus.INSTANCE.send(Messages.STOP, null); @@ -96,6 +113,7 @@ public void callback(Messages message, Object o) { remove(startPosition); } startPosition = new JSlider(JSlider.HORIZONTAL, 0, 0, 0); + startPosition.addChangeListener(this); startPosition.setPreferredSize(new Dimension(500, 40)); Font font = new Font("Serif", Font.ITALIC, 15); diff --git a/src/com/wattzap/view/Map.java b/src/com/wattzap/view/Map.java index 0c01563..c94eb9e 100644 --- a/src/com/wattzap/view/Map.java +++ b/src/com/wattzap/view/Map.java @@ -95,7 +95,7 @@ public void callback(Messages message, Object o) { this.removeGPXFile(gpxFile); } setVisible(false); - frame.invalidate(); + //frame.invalidate(); frame.validate(); // frame.revalidate(); JDK 1.7 ONLY } @@ -118,6 +118,11 @@ public void callback(Messages message, Object o) { count = 0; frame.remove(this); RouteReader routeData = (RouteReader) o; + + if (gpxFile != null) { + // remove any previously loaded GPX file + this.removeGPXFile(gpxFile); + } gpxFile = routeData.getGpxFile(); // TODO - change load message: gpxload, rlvload? diff --git a/src/com/wattzap/view/Workouts.java b/src/com/wattzap/view/Workouts.java index dcede27..e90d51b 100644 --- a/src/com/wattzap/view/Workouts.java +++ b/src/com/wattzap/view/Workouts.java @@ -28,14 +28,13 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; -import java.util.Set; import java.util.TimeZone; import java.util.TreeMap; +import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JMenu; @@ -110,6 +109,8 @@ public class Workouts extends JPanel implements ActionListener { public Workouts() { super(new GridLayout(1, 0)); + + this.setBorder(BorderFactory.createEmptyBorder(0,10,10,10)); selectedRows = null; DefaultTableModel model = new DefaultTableModel(columnNames, 0); @@ -348,7 +349,6 @@ public void actionPerformed(ActionEvent e) { ActivityReader ar = new ActivityReader(); File dir = new File(workoutDir); - Set fileTree = new HashSet(); for (File entry : dir.listFiles()) { if (entry.isFile()) { try { @@ -381,7 +381,7 @@ public void actionPerformed(ActionEvent e) { } JOptionPane.showMessageDialog(this, importedFiles.toString(), "Import", JOptionPane.INFORMATION_MESSAGE); - + return; } @@ -504,7 +504,6 @@ private boolean load() { int count = 0; for (int i : selectedRows) { workoutData = workoutList.get(i); - System.out.println(workoutData); String fileName = workoutData.getTcxFile(); try { telemetry[count] = ActivityReader.readTelemetry(workoutDir @@ -540,7 +539,6 @@ void reanalyze() { int count = 0; for (int i : selectedRows) { workoutData = workoutList.get(i); - System.out.println(">> " + workoutData); String fileName = workoutData.getTcxFile(); int ftp = workoutData.getFtp(); try { @@ -550,9 +548,8 @@ void reanalyze() { workoutData = TrainingAnalysis.analyze(telemetry[count]); workoutData.setTcxFile(fileName); workoutData.setFtp(ftp); - System.out.println(workoutData); - - userPrefs.updateWorkout(workoutData); + userPrefs.updateWorkout(workoutData); // saves data to RDBMS + workoutList.set(i, workoutData); // FIXME updates local cache of workouts but won't fire list changed event? } catch (Exception e1) { logger.error(e1.getLocalizedMessage()); } @@ -704,7 +701,8 @@ private void CSScatterPlot() { }// for }// for - GenericScatterGraph mmp = new GenericScatterGraph(series, userPrefs.messages.getString("poWtt"), + GenericScatterGraph mmp = new GenericScatterGraph(series, + userPrefs.messages.getString("poWtt"), userPrefs.messages.getString("cDrpm")); JFrame frame = new JFrame("Cadence Power Scatter Plot"); ImageIcon img = new ImageIcon("icons/turbo.jpg"); @@ -733,7 +731,8 @@ public void HRWattsScatterPlot() { }// for }// for - GenericScatterGraph mmp = new GenericScatterGraph(series, userPrefs.messages.getString("poWtt"), + GenericScatterGraph mmp = new GenericScatterGraph(series, + userPrefs.messages.getString("poWtt"), userPrefs.messages.getString("hrBpm")); JFrame frame = new JFrame("Heart Rate / Power Scatter Plot"); ImageIcon img = new ImageIcon("icons/turbo.jpg"); diff --git a/src/com/wattzap/view/graphs/InfoPanel.java b/src/com/wattzap/view/graphs/InfoPanel.java index 3298d34..f716dd3 100644 --- a/src/com/wattzap/view/graphs/InfoPanel.java +++ b/src/com/wattzap/view/graphs/InfoPanel.java @@ -41,30 +41,125 @@ public class InfoPanel extends JPanel { private final static UserPreferences userPrefs = UserPreferences.INSTANCE; private final static String COLGAP = "gapright 10"; + // Cadence + private JLabel maxCadence; + private JLabel aveCadence; + + // Heart Rate + private JLabel ftHeartRate; + private JLabel maxHeartRate; + private JLabel aveHeartRate; + + private JLabel distance; + // Power private JLabel totalPower; private JLabel avePower; private JLabel maxPower; + private JLabel qPower; + private JLabel ftPower; + private JLabel ft1Power; + private JLabel ft20Power; - // Heart Rate - private JLabel ftHeartRate; + private JLabel fiveSecondPower; + private JLabel fiveSecondWKG; + + private JLabel oneMinutePower; + private JLabel oneMinuteWKG; + + private JLabel fiveMinutePower; + private JLabel fiveMinuteWKG; + + private JLabel twentyMinutePower; + private JLabel twentyMinuteWKG; + + private JLabel load; + private JLabel stress; + + private JLabel time; public InfoPanel() { - MigLayout layout = new MigLayout( - ); + MigLayout layout = new MigLayout(); this.setLayout(layout); setBackground(Color.LIGHT_GRAY); - JLabel ftpLabel = new JLabel(); - ftpLabel.setFont(font1); - ftpLabel.setText(userPrefs.messages.getString("fthr")); - add(ftpLabel); + // time + JLabel timeLabel = new JLabel(); + timeLabel.setFont(font1); + timeLabel.setText("Time"); + add(timeLabel); + + time = new JLabel(); + time.setFont(font1); + time.setForeground(Color.DARK_GRAY); + add(time, COLGAP); + + // distance + JLabel distanceLabel = new JLabel(); + distanceLabel.setFont(font1); + distanceLabel.setText(userPrefs.messages.getString("distance")); + add(distanceLabel); + + distance = new JLabel(); + distance.setFont(font1); + distance.setForeground(Color.DARK_GRAY); + add(distance, "wrap"); + + // Max Heart Rate + JLabel maxHeartRateLabel = new JLabel(); + maxHeartRateLabel.setFont(font1); + maxHeartRateLabel.setText(userPrefs.messages.getString("maxhr")); + add(maxHeartRateLabel); + + maxHeartRate = new JLabel(); + maxHeartRate.setFont(font1); + maxHeartRate.setForeground(Color.DARK_GRAY); + add(maxHeartRate, COLGAP); + + // Average Heartrate + JLabel aveHeartRateLabel = new JLabel(); + aveHeartRateLabel.setFont(font1); + aveHeartRateLabel.setText(userPrefs.messages.getString("avehr")); + add(aveHeartRateLabel); + + aveHeartRate = new JLabel(); + aveHeartRate.setFont(font1); + aveHeartRate.setForeground(Color.DARK_GRAY); + add(aveHeartRate, COLGAP); + + // Functional Threshold Heartrate + JLabel fthrLabel = new JLabel(); + fthrLabel.setFont(font1); + fthrLabel.setText(userPrefs.messages.getString("fthr")); + add(fthrLabel); ftHeartRate = new JLabel(); ftHeartRate.setFont(font1); ftHeartRate.setForeground(Color.DARK_GRAY); add(ftHeartRate, COLGAP); + // Average Cadence + JLabel aveCadenceLabel = new JLabel(); + aveCadenceLabel.setFont(font1); + aveCadenceLabel.setText(userPrefs.messages.getString("avecad")); + add(aveCadenceLabel); + + aveCadence = new JLabel(); + aveCadence.setFont(font1); + aveCadence.setForeground(Color.DARK_GRAY); + add(aveCadence, COLGAP); + + JLabel maxCadenceLabel = new JLabel(); + maxCadenceLabel.setFont(font1); + maxCadenceLabel.setText(userPrefs.messages.getString("maxcad")); + add(maxCadenceLabel); + + maxCadence = new JLabel(); + maxCadence.setFont(font1); + maxCadence.setForeground(Color.DARK_GRAY); + add(maxCadence, "wrap"); + + // Total Power JLabel powerLabel = new JLabel(); powerLabel.setFont(font1); powerLabel.setText(userPrefs.messages.getString("power")); @@ -75,6 +170,7 @@ public InfoPanel() { totalPower.setForeground(Color.DARK_GRAY); add(totalPower, COLGAP); + // Average Power JLabel aveLabel = new JLabel(); aveLabel.setFont(font1); aveLabel.setText(userPrefs.messages.getString("avepow")); @@ -85,6 +181,7 @@ public InfoPanel() { avePower.setForeground(Color.DARK_GRAY); add(avePower, COLGAP); + // Max Power JLabel maxLabel = new JLabel(); maxLabel.setFont(font1); maxLabel.setText(userPrefs.messages.getString("maxpow")); @@ -93,7 +190,71 @@ public InfoPanel() { maxPower = new JLabel(); maxPower.setFont(font1); maxPower.setForeground(Color.DARK_GRAY); - add(maxPower); + add(maxPower, COLGAP); + + // Quadratic Power + JLabel qLabel = new JLabel(); + qLabel.setFont(font1); + qLabel.setText(userPrefs.messages.getString("qpow")); + add(qLabel); + + qPower = new JLabel(); + qPower.setFont(font1); + qPower.setForeground(Color.DARK_GRAY); + add(qPower, "wrap"); + + // Current FTP + JLabel ftpLabel = new JLabel(); + ftpLabel.setFont(font1); + ftpLabel.setText(userPrefs.messages.getString("cftp")); + add(ftpLabel); + + ftPower = new JLabel(); + ftPower.setFont(font1); + ftPower.setForeground(Color.DARK_GRAY); + add(ftPower, COLGAP); + + JLabel ftp1Label = new JLabel(); + ftp1Label.setFont(font1); + ftp1Label.setText(userPrefs.messages.getString("1minftp")); + add(ftp1Label); + + ft1Power = new JLabel(); + ft1Power.setFont(font1); + ft1Power.setForeground(Color.DARK_GRAY); + add(ft1Power, COLGAP); + + JLabel ftp2Label = new JLabel(); + ftp2Label.setFont(font1); + ftp2Label.setText(userPrefs.messages.getString("20minftp")); + add(ftp2Label); + + ft20Power = new JLabel(); + ft20Power.setFont(font1); + ft20Power.setForeground(Color.DARK_GRAY); + add(ft20Power, COLGAP); + + // Load + JLabel loadLabel = new JLabel(); + loadLabel.setFont(font1); + loadLabel.setText(userPrefs.messages.getString("load")); + add(loadLabel); + + load = new JLabel(); + load.setFont(font1); + load.setForeground(Color.DARK_GRAY); + add(load, COLGAP); + + JLabel stressLabel = new JLabel(); + stressLabel.setFont(font1); + stressLabel.setText(userPrefs.messages.getString("stress")); + add(stressLabel); + + stress = new JLabel(); + stress.setFont(font1); + stress.setForeground(Color.DARK_GRAY); + add(stress, COLGAP); + } public void update(WorkoutData data) { @@ -101,13 +262,28 @@ public void update(WorkoutData data) { return; } + maxHeartRate.setText(data.getMaxHR() + " bpm"); + aveHeartRate.setText(data.getAveHR() + " bpm"); + ftHeartRate.setText(data.getFtHR() + " bpm"); + + aveCadence.setText(data.getAveCadence() + " rpm"); + maxCadence.setText(data.getMaxCadence() + " rpm"); + avePower.setText(data.getAvePower() + " Watts"); maxPower.setText(data.getMaxPower() + " Watts"); totalPower.setText(data.getTotalPower() + " Watts"); + qPower.setText(data.getQuadraticPower() + " Watts"); + ftPower.setText(UserPreferences.INSTANCE.getMaxPower() + " Watts"); + ft1Power.setText((int) (data.getOneMinutePwr()*0.75) + " Watts"); + ft20Power.setText((int) (data.getTwentyMinutePwr()*0.95) + " Watts"); - ftHeartRate.setText(data.getFtHR() + " bpm"); + load.setText("" + (int)(data.getIntensity()*100)); + stress.setText("" + data.getStress()); + time.setText(data.getDateAsString()); + distance.setText(String.format("%.3f", data.getDistanceMeters() / 1000) + + " km"); } - + private static final long serialVersionUID = 1L; } diff --git a/test/com/wattzap/utils/StringXORerTest.java b/test/com/wattzap/utils/StringXORerTest.java index 714defa..d739883 100644 --- a/test/com/wattzap/utils/StringXORerTest.java +++ b/test/com/wattzap/utils/StringXORerTest.java @@ -23,7 +23,7 @@ public class StringXORerTest { @Test public void encodeString() { String s = StringXORer - .encode("WattzAp Turbo Trainer Software

Version: 2.2.1
Date: 7th October
(c) 2014, All rights reserved
", + .encode("WattzAp Turbo Trainer Software

Version: 2.3
Date: 9th November
(c) 2014, All rights reserved
", cryptKey); System.out.println(s); s = StringXORer.decode(s, cryptKey); diff --git a/wattzap.sh b/wattzap.sh index d50d732..070145a 100755 --- a/wattzap.sh +++ b/wattzap.sh @@ -1,4 +1,3 @@ -LIBS="lib/wattzap.jar:properties:lib/log4j-1.2.17.jar:lib/derby.jar:lib/opencsv-2.3.jar:lib/com-sun-tools-visualvm-charts.jar:lib/com-sun-tools-visualvm-uisupport.jar:lib/gpx-creator-0.1-beta.jar:lib/hamcrest-core-1.3.jar:lib/jcommon-1.0.17.jar:lib/jcommon-1.0.18.jar:lib/jformica_core.jar:lib/jformica_jsr80.jar:lib/jfreechart-1.0.14.jar:lib/jna-3.5.1.jar:lib/junit-4.11.jar:lib/miglayout-core-4.2.jar:lib/miglayout-swing-4.2.jar:lib/org-netbeans-lib-profiler-charts.jar:lib/org-netbeans-lib-profiler-ui.jar:lib/org-openide-util-lookup.jar:lib/org-openide-util.jar:lib/usb-api-1.0.2.jar:lib/usb4java-1.2.0.jar:lib/vlcj-2.2.0.jar:lib/usb4java-javax-1.2.0.jar:lib/commons-lang3-3.2.1.jar " +LIBS="lib:properties:lib/derby.jar:lib/opencsv-2.3.jar:lib/com-sun-tools-visualvm-charts.jar:lib/com-sun-tools-visualvm-uisupport.jar:lib/commons-lang3-3.2.1.jar:lib/gpx-creator-0.1-beta.jar:lib/hamcrest-core-1.3.jar:lib/jcommon-1.0.17.jar:lib/jcommon-1.0.18.jar:lib/jformica_core.jar:lib/jformica_jsr80.jar:lib/jfreechart-1.0.14.jar:lib/jna-3.5.1.jar:lib/junit-4.11.jar:lib/miglayout-core-4.2.jar:lib/miglayout-swing-4.2.jar:lib/org-netbeans-lib-profiler-charts.jar:lib/org-netbeans-lib-profiler-ui.jar:lib/org-openide-util-lookup.jar:lib/org-openide-util.jar:lib/usb-api-1.0.2.jar:lib/usb4java-1.2.0.jar:lib/usb4java-javax-1.2.0.jar:lib/vlcj-2.2.0.jar:lib/log4j-1.2.17.jar:lib/wattzap.jar" -#java -cp $LIBS -Dlog4j.logger.level=DEBUG com.wattzap.Main -java -cp $LIBS com.wattzap.Main +java -Djna.library.path=/Applications/VLC.app/Contents/MacOS/lib -cp $LIBS -Dlog4j.logger.level=INFO com.wattzap.Main