package com.github.pfichtner.jrunalyser.ui.tracklist; import static com.github.pfichtner.jrunalyser.ui.tracklist.TrackListPlugin.getI18n; import static com.google.common.collect.Iterables.getFirst; import java.awt.Component; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.concurrent.TimeUnit; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; import javax.swing.table.TableRowSorter; import com.github.pfichtner.jrunalyser.base.data.DefaultDistance; import com.github.pfichtner.jrunalyser.base.data.DefaultDuration; import com.github.pfichtner.jrunalyser.base.data.Distance; import com.github.pfichtner.jrunalyser.base.data.DistanceUnit; import com.github.pfichtner.jrunalyser.base.data.Duration; import com.github.pfichtner.jrunalyser.base.data.LinkedTrackPoint; import com.github.pfichtner.jrunalyser.base.data.Pace; import com.github.pfichtner.jrunalyser.base.data.Speed; import com.github.pfichtner.jrunalyser.base.data.stat.Statistics; import com.github.pfichtner.jrunalyser.base.data.track.Id; import com.github.pfichtner.jrunalyser.base.data.track.Track; import com.github.pfichtner.jrunalyser.ui.table.renderers.DistanceRenderer; import com.github.pfichtner.jrunalyser.ui.table.renderers.DurationRenderer; import com.github.pfichtner.jrunalyser.ui.table.renderers.PaceRenderer; import com.github.pfichtner.jrunalyser.ui.table.renderers.SpeedRenderer; import com.google.common.collect.Lists; public class TrackTableModel extends AbstractTableModel { private static class ElevationRenderer extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setFont(null); setText(value == null ? null : ((MinMaxElevation) value) .getTextLong()); setBackground(isSelected ? table.getSelectionBackground() : null); return this; } } // TODO Add amount of breaks public static final int COL_STARTDATE = 0; public static final int COL_NAME = 1; public static final int COL_DESC = 2; public static final int COL_DURATION = 3; public static final int COL_DISTANCE = 4; public static final int COL_ELEVATION = 5; public static final int COL_SPEED = 6; public static final int COL_PACE = 7; public static final int COL_SIM_COUNT = 8; public static final int COL_400M = 9; public static final int COL_12MIN = 10; public static final int COL_HALF_MILE = 11; public static final int COL_1000M = 12; public static final int COL_1MILE = 13; public static final int COL_2MILES = 14; public static final int COL_5000M = 15; public static final int COL_10000M = 16; public static final int COL_IS_AWAY_EQ_RETURN = 17; private static final long serialVersionUID = 8199955700069773640L; private static TableCellRenderer headerRenderer = new TableHeaderRenderer(); private final List<TrackRow> data = Lists.newArrayList(); @Override public int getRowCount() { return this.data.size(); } public TrackRow getRowAt(int idx) { return this.data.get(idx); } @Override public int getColumnCount() { return 17; } @Override public Class<?> getColumnClass(int columnIndex) { switch (columnIndex) { case COL_STARTDATE: return Date.class; case COL_NAME: return String.class; case COL_DESC: return String.class; case COL_DURATION: return Duration.class; case COL_DISTANCE: return Distance.class; case COL_ELEVATION: return MinMaxElevation.class; case COL_SPEED: return Speed.class; case COL_PACE: return Pace.class; case COL_SIM_COUNT: return Integer.class; case COL_400M: return Duration.class; case COL_12MIN: return Distance.class; case COL_HALF_MILE: case COL_1000M: case COL_1MILE: case COL_2MILES: case COL_5000M: case COL_10000M: return Duration.class; case COL_IS_AWAY_EQ_RETURN: return Boolean.class; default: throw new IllegalStateException("Unknown column " + columnIndex); //$NON-NLS-1$ } } @Override public Object getValueAt(int rowIndex, int columnIndex) { Track track = getTrack(rowIndex); switch (columnIndex) { case COL_STARTDATE: LinkedTrackPoint first = getFirst(track.getTrackpoints(), null); return first == null ? null : new Date(first.getTime().longValue()); case COL_NAME: return track.getMetadata().getName(); case COL_DESC: return track.getMetadata().getDescription(); case COL_DURATION: return track.getStatistics().getDuration(); case COL_DISTANCE: return track.getStatistics().getDistance(); case COL_ELEVATION: return this.data.get(rowIndex).getMinMaxElevation(); case COL_SPEED: case COL_PACE: return track.getStatistics().getAvgSpeed(); case COL_SIM_COUNT: return this.data.get(rowIndex).getSimCount(); case COL_12MIN: return getDistance((Duration) getHeaderValue(columnIndex), this.data.get(rowIndex)); case COL_400M: case COL_HALF_MILE: case COL_1000M: case COL_1MILE: case COL_2MILES: case COL_5000M: case COL_10000M: return getDuration((Distance) getHeaderValue(columnIndex), this.data.get(rowIndex)); case COL_IS_AWAY_EQ_RETURN: return this.data.get(rowIndex).isAwayEqReturn(); default: throw new IllegalStateException("Unknown column " + columnIndex); //$NON-NLS-1$ } } public Object getHeaderValue(int columnIndex) { Object headerValue = getColumnModel().getColumn(columnIndex) .getHeaderValue(); return headerValue; } private static Distance getDistance(Duration duration, TrackRow trackRow) { Statistics statistics = trackRow.getBestSegment(duration).orNull(); return statistics == null ? null : statistics.getDistance(); } private static Duration getDuration(Distance distance, TrackRow trackRow) { Statistics statistics = trackRow.getBestSegment(distance).orNull(); return statistics == null ? null : statistics.getDuration(); } private Track getTrack(int rowIndex) { return this.data.get(rowIndex).getTrack(); } public void clear() { this.data.clear(); fireTableDataChanged(); } public void addRow(TrackRow trackRow) { int cnt = this.data.size(); this.data.add(trackRow); fireTableRowsInserted(cnt, cnt); } public void addRows(List<TrackRow> trackRows) { int cnt = this.data.size(); this.data.addAll(trackRows); fireTableRowsInserted(cnt, cnt + trackRows.size() - 1); } public void removeRow(Id id) { int cnt = 0; for (Iterator<TrackRow> it = this.data.iterator(); it.hasNext();) { if (it.next().getTrack().getId().equals(id)) { it.remove(); fireTableRowsDeleted(cnt, cnt); } else { cnt++; } } } // ---------------------------------------------------------------------------------- public TableColumnModel getColumnModel() { DefaultTableColumnModel columnModel = new DefaultTableColumnModel(); columnModel .addColumn(createColumn( COL_STARTDATE, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colStartdate.title"))); //$NON-NLS-1$ columnModel .addColumn(createColumn( COL_NAME, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colName.title"))); //$NON-NLS-1$ columnModel .addColumn(createColumn( COL_DESC, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colDescription.title"))); //$NON-NLS-1$ columnModel .addColumn(createColumn( COL_DURATION, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colDuration.title"), //$NON-NLS-1$ new MedalRendererDecorator(new DurationRenderer()))); columnModel .addColumn(createColumn( COL_DISTANCE, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colDistance.title"), //$NON-NLS-1$ new MedalRendererDecorator(new DistanceRenderer()))); columnModel .addColumn(createColumn( COL_ELEVATION, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colElevation.title"), //$NON-NLS-1$ new MedalRendererDecorator(new ElevationRenderer()))); columnModel .addColumn(createColumn( COL_SPEED, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colSpeed.title"), //$NON-NLS-1$ new MedalRendererDecorator(new SpeedRenderer()))); columnModel .addColumn(createColumn( COL_PACE, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colPace.title"), //$NON-NLS-1$ new MedalRendererDecorator(new PaceRenderer()))); columnModel .addColumn(createColumn( COL_SIM_COUNT, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colSimCount.title"))); //$NON-NLS-1$ columnModel.addColumn(createColumn(COL_400M, DefaultDistance.of(400, DistanceUnit.METERS), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel.addColumn(createColumn(COL_12MIN, DefaultDuration.of(12, TimeUnit.MINUTES), new MedalRendererDecorator(new DistanceRenderer()))); columnModel.addColumn(createColumn(COL_HALF_MILE, DefaultDistance.of(0.5, DistanceUnit.MILES), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel.addColumn(createColumn(COL_1000M, DefaultDistance.of(1, DistanceUnit.KILOMETERS), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel.addColumn(createColumn(COL_1MILE, DefaultDistance.of(1, DistanceUnit.MILES), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel.addColumn(createColumn(COL_2MILES, DefaultDistance.of(2, DistanceUnit.MILES), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel.addColumn(createColumn(COL_5000M, DefaultDistance.of(5, DistanceUnit.KILOMETERS), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel.addColumn(createColumn(COL_10000M, DefaultDistance.of(10, DistanceUnit.KILOMETERS), new MedalRendererDecorator(new DurationRenderer()).reverse())); columnModel .addColumn(createColumn( COL_IS_AWAY_EQ_RETURN, getI18n() .getText( "com.github.pfichtner.jrunalyser.ui.tracklist.TrackTableModel.colAwayIsReturn.title"))); //$NON-NLS-1$ return columnModel; } private static TableColumn createColumn(int modeIdx, Object value) { TableColumn column = new TableColumn(modeIdx); column.setHeaderValue(value); column.setHeaderRenderer(headerRenderer); return column; } private static TableColumn createColumn(int modelIdx, Object value, TableCellRenderer cellRenderer) { TableColumn column = createColumn(modelIdx, value); column.setCellRenderer(cellRenderer); return column; } // ---------------------------------------------------------------------------------- public TableRowSorter<TableModel> createTableRowSorter() { TableModel tm = this; TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tm); // reverse all Durations (shown in Distance columns) (but to the // COL_DURATION) for (int i = 0; i < tm.getColumnCount(); i++) { if (i != COL_DURATION && Duration.class.isAssignableFrom(tm.getColumnClass(i))) { reverse(sorter, i); } } return sorter; } private static TableRowSorter<TableModel> reverse( TableRowSorter<TableModel> sorter, int column) { sorter.setComparator(column, Collections.reverseOrder(sorter.getComparator(column))); return sorter; } }