Added more query utils, aggregate stats, and randomized testing data.
This commit is contained in:
parent
581eebadbd
commit
bb5370e92a
|
@ -1,7 +1,7 @@
|
||||||
package com.github.andrewlalis.running_every_day;
|
package com.github.andrewlalis.running_every_day;
|
||||||
|
|
||||||
import com.formdev.flatlaf.FlatLightLaf;
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
import com.github.andrewlalis.running_every_day.data.DataSource;
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
import com.github.andrewlalis.running_every_day.view.RecorderAppWindow;
|
import com.github.andrewlalis.running_every_day.view.RecorderAppWindow;
|
||||||
import com.github.andrewlalis.running_every_day.view.WindowDataSourceCloser;
|
import com.github.andrewlalis.running_every_day.view.WindowDataSourceCloser;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.github.andrewlalis.running_every_day.data;
|
package com.github.andrewlalis.running_every_day.data;
|
||||||
|
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.ResultSetMapper;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
@ -46,6 +48,16 @@ public record RunRecord(
|
||||||
return weightKg.multiply(BigDecimal.valueOf(1000));
|
return weightKg.multiply(BigDecimal.valueOf(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Duration averagePacePerKm() {
|
||||||
|
long msPerKm = (long) Math.floor(duration.toMillis() / distanceKm.doubleValue());
|
||||||
|
return Duration.ofMillis(msPerKm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String averagePacePerKmFormatted() {
|
||||||
|
var dur = averagePacePerKm();
|
||||||
|
return String.format("%02d:%02d.%03d", dur.toMinutesPart(), dur.toSecondsPart(), dur.toMillisPart());
|
||||||
|
}
|
||||||
|
|
||||||
public static class Mapper implements ResultSetMapper<RunRecord> {
|
public static class Mapper implements ResultSetMapper<RunRecord> {
|
||||||
@Override
|
@Override
|
||||||
public RunRecord map(ResultSet rs) throws SQLException {
|
public RunRecord map(ResultSet rs) throws SQLException {
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
package com.github.andrewlalis.running_every_day.data;
|
package com.github.andrewlalis.running_every_day.data;
|
||||||
|
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.Page;
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.Pagination;
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.Queries;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data access object for interacting with run records in the database.
|
||||||
|
* @param conn The database connection.
|
||||||
|
*/
|
||||||
public record RunRecordRepository(Connection conn) {
|
public record RunRecordRepository(Connection conn) {
|
||||||
public Page<RunRecord> findAll(Pagination pagination) throws SQLException {
|
public Page<RunRecord> findAll(Pagination pagination) throws SQLException {
|
||||||
String query = "SELECT * FROM run ORDER BY date ASC";
|
String query = "SELECT * FROM run ORDER BY date ASC";
|
||||||
|
@ -62,22 +73,20 @@ public record RunRecordRepository(Connection conn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long countAll() throws SQLException {
|
public long pageCount(int pageSize) throws SQLException {
|
||||||
String query = "SELECT COUNT(id) FROM run";
|
return Queries.pageCount(conn, "SELECT COUNT(id) FROM run", pageSize);
|
||||||
try (
|
|
||||||
var stmt = conn.prepareStatement(query);
|
|
||||||
var rs = stmt.executeQuery()
|
|
||||||
) {
|
|
||||||
if (rs.next()) {
|
|
||||||
return rs.getLong(1);
|
|
||||||
} else {
|
|
||||||
throw new SQLException("Missing count.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long pageCount(int size) throws SQLException {
|
// Aggregate stats:
|
||||||
long recordCount = countAll();
|
|
||||||
return (recordCount / size) + (recordCount % size != 0 ? 1 : 0);
|
public BigDecimal getTotalDistanceKm() throws SQLException {
|
||||||
|
long totalDistanceMeters = Queries.getLong(conn, "SELECT SUM(distance) FROM run");
|
||||||
|
return BigDecimal.valueOf(totalDistanceMeters, 3)
|
||||||
|
.divide(BigDecimal.valueOf(1000, 3), RoundingMode.UNNECESSARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Duration getTotalDuration() throws SQLException {
|
||||||
|
long totalDurationSeconds = Queries.getLong(conn, "SELECT SUM(duration) FROM run");
|
||||||
|
return Duration.ofSeconds(totalDurationSeconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
package com.github.andrewlalis.running_every_day.data;
|
package com.github.andrewlalis.running_every_day.data.db;
|
||||||
|
|
||||||
|
import com.github.andrewlalis.running_every_day.data.RunRecordRepository;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
@ -6,8 +8,6 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single object that serves as the application's data source.
|
* A single object that serves as the application's data source.
|
||||||
|
@ -24,14 +24,8 @@ public class DataSource {
|
||||||
return new RunRecordRepository(this.conn);
|
return new RunRecordRepository(this.conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> List<T> query(String query, ResultSetMapper<T> mapper) throws SQLException {
|
public Connection conn() {
|
||||||
try (var stmt = conn.prepareStatement(query); var rs = stmt.executeQuery()) {
|
return conn;
|
||||||
List<T> items = new ArrayList<>();
|
|
||||||
while (rs.next()) {
|
|
||||||
items.add(mapper.map(rs));
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws SQLException {
|
public void close() throws SQLException {
|
||||||
|
@ -64,7 +58,7 @@ public class DataSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String readResource(String name) {
|
public static String readResource(String name) {
|
||||||
try (var in = DataSource.class.getClassLoader().getResourceAsStream(name)) {
|
try (var in = DataSource.class.getClassLoader().getResourceAsStream(name)) {
|
||||||
if (in == null) {
|
if (in == null) {
|
||||||
throw new RuntimeException("Missing resource: " + name);
|
throw new RuntimeException("Missing resource: " + name);
|
|
@ -1,4 +1,4 @@
|
||||||
package com.github.andrewlalis.running_every_day.data;
|
package com.github.andrewlalis.running_every_day.data.db;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
|
@ -1,4 +1,4 @@
|
||||||
package com.github.andrewlalis.running_every_day.data;
|
package com.github.andrewlalis.running_every_day.data.db;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.github.andrewlalis.running_every_day.data.db;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class Queries {
|
||||||
|
private Queries() {}
|
||||||
|
|
||||||
|
public static <T> Optional<T> findOne(
|
||||||
|
Connection c,
|
||||||
|
String query,
|
||||||
|
StatementModifier modifier,
|
||||||
|
ResultSetMapper<T> mapper
|
||||||
|
) throws SQLException {
|
||||||
|
try (var stmt = c.prepareStatement(query)) {
|
||||||
|
modifier.apply(stmt);
|
||||||
|
try (var rs = stmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return Optional.of(mapper.map(rs));
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Optional<T> findOne(Connection c, String query, ResultSetMapper<T> mapper) throws SQLException {
|
||||||
|
try (var stmt = c.prepareStatement(query)) {
|
||||||
|
try (var rs = stmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return Optional.of(mapper.map(rs));
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getOne(Connection c, String query, ResultSetMapper<T> mapper) throws SQLException {
|
||||||
|
return findOne(c, query, mapper).orElseThrow(() -> new SQLException("Missing required SQL result."));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getLong(Connection c, String query) throws SQLException {
|
||||||
|
return getOne(c, query, rs -> rs.getLong(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getString(Connection c, String query) throws SQLException {
|
||||||
|
return getOne(c, query, rs -> rs.getString(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long count(Connection c, String query) throws SQLException {
|
||||||
|
try (var stmt = c.prepareStatement(query); var rs = stmt.executeQuery()) {
|
||||||
|
if (rs.next()) {
|
||||||
|
return rs.getLong(1);
|
||||||
|
} else {
|
||||||
|
throw new SQLException("Result set for count query is empty.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long pageCount(Connection c, String query, int pageSize) throws SQLException {
|
||||||
|
long recordCount = count(c, query);
|
||||||
|
long pageCount = recordCount / pageSize;
|
||||||
|
if (recordCount % pageSize != 0) {
|
||||||
|
pageCount++;
|
||||||
|
}
|
||||||
|
return pageCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int update(Connection c, String query) throws SQLException {
|
||||||
|
try (var stmt = c.prepareStatement(query)) {
|
||||||
|
return stmt.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.github.andrewlalis.running_every_day.data;
|
package com.github.andrewlalis.running_every_day.data.db;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.github.andrewlalis.running_every_day.data.db;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface StatementModifier {
|
||||||
|
void apply(PreparedStatement stmt) throws SQLException;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package com.github.andrewlalis.running_every_day.view;
|
package com.github.andrewlalis.running_every_day.view;
|
||||||
|
|
||||||
import com.github.andrewlalis.running_every_day.data.DataSource;
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
import com.github.andrewlalis.running_every_day.data.RunRecord;
|
import com.github.andrewlalis.running_every_day.data.RunRecord;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -15,7 +15,6 @@ import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class AddRunRecordDialog extends JDialog {
|
public class AddRunRecordDialog extends JDialog {
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
|
|
|
@ -1,4 +1,55 @@
|
||||||
package com.github.andrewlalis.running_every_day.view;
|
package com.github.andrewlalis.running_every_day.view;
|
||||||
|
|
||||||
public class AggregateStatisticsPanel {
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class AggregateStatisticsPanel extends JPanel {
|
||||||
|
private final DataSource dataSource;
|
||||||
|
|
||||||
|
private final JTextField totalDistanceField;
|
||||||
|
private final JTextField totalDurationField;
|
||||||
|
|
||||||
|
public AggregateStatisticsPanel(DataSource dataSource) {
|
||||||
|
super(new BorderLayout());
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
|
||||||
|
totalDistanceField = new JTextField();
|
||||||
|
totalDistanceField.setEditable(false);
|
||||||
|
totalDurationField = new JTextField();
|
||||||
|
totalDurationField.setEditable(false);
|
||||||
|
|
||||||
|
JPanel statsPanel = new JPanel(new GridLayout(2, 2));
|
||||||
|
statsPanel.add(new JLabel("Total Distance (Km)"));
|
||||||
|
statsPanel.add(totalDistanceField);
|
||||||
|
statsPanel.add(new JLabel("Total Duration"));
|
||||||
|
statsPanel.add(totalDurationField);
|
||||||
|
this.add(statsPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel controlsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
|
JButton refreshButton = new JButton("Refresh");
|
||||||
|
refreshButton.addActionListener(e -> refreshStats());
|
||||||
|
controlsPanel.add(refreshButton);
|
||||||
|
this.add(controlsPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(this::refreshStats);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshStats() {
|
||||||
|
try {
|
||||||
|
totalDistanceField.setText(dataSource.runRecords().getTotalDistanceKm().toPlainString() + " Km");
|
||||||
|
var totalDuration = dataSource.runRecords().getTotalDuration();
|
||||||
|
String durationStr = String.format(
|
||||||
|
"%d days, %d hours, %d minutes",
|
||||||
|
totalDuration.toDaysPart(),
|
||||||
|
totalDuration.toHoursPart(),
|
||||||
|
totalDuration.toMinutesPart()
|
||||||
|
);
|
||||||
|
totalDurationField.setText(durationStr);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.github.andrewlalis.running_every_day.view;
|
package com.github.andrewlalis.running_every_day.view;
|
||||||
|
|
||||||
import com.github.andrewlalis.running_every_day.data.DataSource;
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
@ -18,7 +18,7 @@ public class RecorderAppWindow extends JFrame {
|
||||||
private Container buildGui(DataSource dataSource) {
|
private Container buildGui(DataSource dataSource) {
|
||||||
JTabbedPane tabbedPane = new JTabbedPane();
|
JTabbedPane tabbedPane = new JTabbedPane();
|
||||||
tabbedPane.addTab("Run Records", new RunRecordsPanel(dataSource));
|
tabbedPane.addTab("Run Records", new RunRecordsPanel(dataSource));
|
||||||
tabbedPane.addTab("Aggregate Statistics", new JPanel());
|
tabbedPane.addTab("Aggregate Statistics", new AggregateStatisticsPanel(dataSource));
|
||||||
tabbedPane.addTab("Charts", new ChartsPanel());
|
tabbedPane.addTab("Charts", new ChartsPanel());
|
||||||
return tabbedPane;
|
return tabbedPane;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package com.github.andrewlalis.running_every_day.view;
|
package com.github.andrewlalis.running_every_day.view;
|
||||||
|
|
||||||
import com.github.andrewlalis.running_every_day.data.DataSource;
|
|
||||||
import com.github.andrewlalis.running_every_day.data.Pagination;
|
|
||||||
import com.github.andrewlalis.running_every_day.data.RunRecord;
|
import com.github.andrewlalis.running_every_day.data.RunRecord;
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.Pagination;
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
@ -88,7 +88,7 @@ public class RunRecordTableModel extends AbstractTableModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getColumnCount() {
|
public int getColumnCount() {
|
||||||
return 7;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,8 +101,9 @@ public class RunRecordTableModel extends AbstractTableModel {
|
||||||
case 2 -> r.startTime().toString();
|
case 2 -> r.startTime().toString();
|
||||||
case 3 -> r.distanceKm().toPlainString();
|
case 3 -> r.distanceKm().toPlainString();
|
||||||
case 4 -> r.durationFormatted();
|
case 4 -> r.durationFormatted();
|
||||||
case 5 -> r.weightKg().toPlainString();
|
case 5 -> r.averagePacePerKmFormatted();
|
||||||
case 6 -> r.comment();
|
case 6 -> r.weightKg().toPlainString();
|
||||||
|
case 7 -> r.comment();
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -115,8 +116,9 @@ public class RunRecordTableModel extends AbstractTableModel {
|
||||||
case 2 -> "Start Time";
|
case 2 -> "Start Time";
|
||||||
case 3 -> "Distance (Km)";
|
case 3 -> "Distance (Km)";
|
||||||
case 4 -> "Duration";
|
case 4 -> "Duration";
|
||||||
case 5 -> "Weight (Kg)";
|
case 5 -> "Pace (Min/Km)";
|
||||||
case 6 -> "Comment";
|
case 6 -> "Weight (Kg)";
|
||||||
|
case 7 -> "Comment";
|
||||||
default -> "Unknown Value";
|
default -> "Unknown Value";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
package com.github.andrewlalis.running_every_day.view;
|
package com.github.andrewlalis.running_every_day.view;
|
||||||
|
|
||||||
import com.github.andrewlalis.running_every_day.data.DataSource;
|
import com.github.andrewlalis.running_every_day.data.RunRecord;
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
|
import com.github.andrewlalis.running_every_day.data.db.Queries;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A panel for displaying a table view of run records, and various controls for
|
* A panel for displaying a table view of run records, and various controls for
|
||||||
* navigating the data.
|
* navigating the data.
|
||||||
*/
|
*/
|
||||||
public class RunRecordsPanel extends JPanel {
|
public class RunRecordsPanel extends JPanel {
|
||||||
|
private final DataSource dataSource;
|
||||||
|
|
||||||
private final RunRecordTableModel tableModel;
|
private final RunRecordTableModel tableModel;
|
||||||
private final JTextField currentPageField;
|
private final JTextField currentPageField;
|
||||||
private final JButton firstPageButton;
|
private final JButton firstPageButton;
|
||||||
|
@ -19,19 +30,22 @@ public class RunRecordsPanel extends JPanel {
|
||||||
|
|
||||||
public RunRecordsPanel(DataSource dataSource) {
|
public RunRecordsPanel(DataSource dataSource) {
|
||||||
super(new BorderLayout());
|
super(new BorderLayout());
|
||||||
|
this.dataSource = dataSource;
|
||||||
this.tableModel = new RunRecordTableModel(dataSource);
|
this.tableModel = new RunRecordTableModel(dataSource);
|
||||||
|
|
||||||
var table = new JTable(tableModel);
|
var table = new JTable(tableModel);
|
||||||
table.getTableHeader().setReorderingAllowed(false);
|
table.getTableHeader().setReorderingAllowed(false);
|
||||||
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||||
table.getColumnModel().getColumn(0).setMaxWidth(40);
|
table.getColumnModel().getColumn(0).setMaxWidth(50);
|
||||||
table.getColumnModel().getColumn(1).setMaxWidth(80);
|
table.getColumnModel().getColumn(1).setMaxWidth(80);
|
||||||
table.getColumnModel().getColumn(2).setMaxWidth(80);
|
table.getColumnModel().getColumn(2).setMaxWidth(70);
|
||||||
table.getColumnModel().getColumn(3).setMaxWidth(100);
|
table.getColumnModel().getColumn(3).setMaxWidth(100);
|
||||||
table.getColumnModel().getColumn(3).setPreferredWidth(100);
|
table.getColumnModel().getColumn(3).setPreferredWidth(100);
|
||||||
table.getColumnModel().getColumn(4).setMaxWidth(80);
|
table.getColumnModel().getColumn(4).setMaxWidth(60);
|
||||||
table.getColumnModel().getColumn(5).setMaxWidth(80);
|
table.getColumnModel().getColumn(5).setMaxWidth(100);
|
||||||
for (int i = 0; i < 6; i++) {
|
table.getColumnModel().getColumn(5).setPreferredWidth(100);
|
||||||
|
table.getColumnModel().getColumn(6).setMaxWidth(80);
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
table.getColumnModel().getColumn(i).setResizable(false);
|
table.getColumnModel().getColumn(i).setResizable(false);
|
||||||
}
|
}
|
||||||
var scrollPane = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
var scrollPane = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||||
|
@ -98,6 +112,9 @@ public class RunRecordsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
actionsPanel.add(addActionButton);
|
actionsPanel.add(addActionButton);
|
||||||
|
JButton generateRandomDataButton = new JButton("Generate Random Data");
|
||||||
|
generateRandomDataButton.addActionListener(e -> generateRandomData());
|
||||||
|
actionsPanel.add(generateRandomDataButton);
|
||||||
this.add(actionsPanel, BorderLayout.NORTH);
|
this.add(actionsPanel, BorderLayout.NORTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,4 +125,39 @@ public class RunRecordsPanel extends JPanel {
|
||||||
lastPageButton.setEnabled(tableModel.canGoToLastPage());
|
lastPageButton.setEnabled(tableModel.canGoToLastPage());
|
||||||
currentPageField.setText(String.valueOf(tableModel.getPagination().page() + 1));
|
currentPageField.setText(String.valueOf(tableModel.getPagination().page() + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateRandomData() {
|
||||||
|
try {
|
||||||
|
var c = dataSource.conn();
|
||||||
|
Queries.update(c, "DELETE FROM run");
|
||||||
|
final int daysToDo = 1000;
|
||||||
|
LocalDate date = LocalDate.now().minusDays(daysToDo);
|
||||||
|
Random rand = new Random();
|
||||||
|
c.setAutoCommit(false);
|
||||||
|
for (int i = 0; i < daysToDo; i++) {
|
||||||
|
LocalTime startTime = LocalTime.of(rand.nextInt(5, 22), rand.nextInt(60));
|
||||||
|
BigDecimal distance = BigDecimal.valueOf(rand.nextInt(1000, 15000), 3)
|
||||||
|
.divide(BigDecimal.valueOf(1000, 3), RoundingMode.UNNECESSARY);
|
||||||
|
double avgPage = rand.nextDouble(300.0, 700.0);
|
||||||
|
BigDecimal weight = BigDecimal.valueOf(rand.nextInt(75000, 110000), 3)
|
||||||
|
.divide(BigDecimal.valueOf(1000, 3), RoundingMode.UNNECESSARY);
|
||||||
|
dataSource.runRecords().save(new RunRecord(
|
||||||
|
0,
|
||||||
|
date,
|
||||||
|
startTime,
|
||||||
|
distance,
|
||||||
|
Duration.ofSeconds((long) Math.floor(avgPage * distance.doubleValue())),
|
||||||
|
weight,
|
||||||
|
"Bleh"
|
||||||
|
));
|
||||||
|
date = date.plusDays(1);
|
||||||
|
}
|
||||||
|
c.commit();
|
||||||
|
c.setAutoCommit(true);
|
||||||
|
tableModel.firstPage();
|
||||||
|
updateButtonStates();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.github.andrewlalis.running_every_day.view;
|
package com.github.andrewlalis.running_every_day.view;
|
||||||
|
|
||||||
import com.github.andrewlalis.running_every_day.data.DataSource;
|
import com.github.andrewlalis.running_every_day.data.db.DataSource;
|
||||||
|
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
|
|
Loading…
Reference in New Issue