/* * Open-Source tuning tools * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package com.vgi.mafscaling; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Rectangle2D; import java.util.HashSet; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIDefaults; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import quick.dbtable.DBTable; public class LogPlay extends JFrame implements ActionListener { private static final long serialVersionUID = -1614821051358033847L; public class TableHolder { public int xColIdx; public int yColIdx; public int zColIdx; public LogPlayTable table; TableHolder(int x, int y, int z, LogPlayTable t) { xColIdx = x; yColIdx = y; zColIdx = z; table = t; table.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { int size; synchronized (lock) { tables.remove(new TableHolder(xColIdx, yColIdx, zColIdx, table)); size = tables.size(); } if (size == 0) stop(); } }); } @Override public int hashCode() { return table.hashCode() ^ (31 * xColIdx) ^ (31 * yColIdx); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TableHolder other = (TableHolder) obj; if (xColIdx != other.xColIdx) return false; if (yColIdx != other.yColIdx) return false; if (table != other.table) return false; return true; } } private final int step = 20; private Timer timer = null; private LogView logView = null; private JPanel playerPanel = null; private DBTable logDataTable = null; private JButton playButton = null; private JButton stopButton = null; private JButton ffwButton = null; private JButton rewButton = null; private JButton newPlayButton = null; private JComboBox<String> xAxisColumn = null; private JComboBox<String> yAxisColumn = null; private JComboBox<String> zAxisColumn = null; private JCheckBox showIntepCells = null; private JCheckBox showSignifCells = null; private JCheckBox showTraceLine = null; private JCheckBox showTraceMarker = null; private JSlider progressBar = null; private HashSet<TableHolder> tables = new HashSet<TableHolder>(); private Object lock = new Object(); private volatile boolean playing = false; private volatile boolean showMarker = false; private boolean paused = false; private int lastRow = 0; private int startPlay = -1; private int endPlay = -1; private int timerDelay = 200; private AtomicInteger playNext = null; private ImageIcon playIcon = null; private ImageIcon pauseIcon = null; private Insets insets0 = new Insets(0, 0, 0, 0); private Insets insets3 = new Insets(3, 3, 3, 3); private UIDefaults zeroInsets = new UIDefaults(); public LogPlay(LogView logView) { // super(SwingUtilities.windowForComponent(logView)); super("Log Play"); this.logView = logView; logDataTable = logView.getLogDataTable(); initialize(); } private void initialize() { lastRow = logDataTable.getRowCount() - 1; playNext = new AtomicInteger(1); playIcon = new ImageIcon(getClass().getResource("/play.png")); pauseIcon = new ImageIcon(getClass().getResource("/pause.png")); zeroInsets.put("Button.contentMargins", insets0); timer = new Timer(timerDelay, new ActionListener() { public void actionPerformed(ActionEvent e) { progressBar.setValue(progressBar.getValue() + playNext.get()); } }); JPanel dataPanel = new JPanel(); GridBagLayout gbl_dataPanel = new GridBagLayout(); gbl_dataPanel.columnWidths = new int[] {0}; gbl_dataPanel.rowHeights = new int[] {0, 1}; gbl_dataPanel.columnWeights = new double[]{1.0}; gbl_dataPanel.rowWeights = new double[]{0.0, 1.0}; dataPanel.setLayout(gbl_dataPanel); getContentPane().add(dataPanel); createSelectionPanel(dataPanel); createPlayer(dataPanel); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { timer.stop(); synchronized (lock) { for (TableHolder t : tables) t.table.dispose(); tables.clear(); } logView.disposeLogView(); } }); pack(); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setIconImage((new ImageIcon(getClass().getResource("/player.png"))).getImage()); setResizable(false); setLocationRelativeTo(SwingUtilities.windowForComponent(logView)); setVisible(true); } private void createSelectionPanel(JPanel panel) { JPanel selectionPanel = new JPanel(); GridBagLayout gbl_selectionPanel = new GridBagLayout(); gbl_selectionPanel.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0}; gbl_selectionPanel.rowHeights = new int[]{0}; gbl_selectionPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0}; gbl_selectionPanel.rowWeights = new double[]{0.0}; selectionPanel.setLayout(gbl_selectionPanel); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = insets3; gbc.anchor = GridBagConstraints.WEST; gbc.gridx = 0; gbc.gridy = 0; selectionPanel.add(new JLabel("X-Axis"), gbc); gbc.gridx++; xAxisColumn = new JComboBox<String>(); selectionPanel.add(xAxisColumn, gbc); gbc.gridx++; selectionPanel.add(new JLabel("Y-Axis"), gbc); gbc.gridx++; yAxisColumn = new JComboBox<String>(); selectionPanel.add(yAxisColumn, gbc); gbc.gridx++; selectionPanel.add(new JLabel("Data*"), gbc); gbc.gridx++; zAxisColumn = new JComboBox<String>(); selectionPanel.add(zAxisColumn, gbc); gbc.gridx++; gbc.weightx = 1.0; newPlayButton = new JButton("New Play Table"); newPlayButton.addActionListener(this); selectionPanel.add(newPlayButton, gbc); xAxisColumn.addItem(""); yAxisColumn.addItem(""); zAxisColumn.addItem("Optional"); for (int i = 0; i < logDataTable.getColumnCount(); ++i) { String colName = logDataTable.getColumn(i).getHeaderValue().toString(); xAxisColumn.addItem(colName); yAxisColumn.addItem(colName); zAxisColumn.addItem(colName); } zAxisColumn.setSelectedIndex(0); gbc.insets = insets0; gbc.gridx = 0; gbc.anchor = GridBagConstraints.PAGE_START; gbc.fill = GridBagConstraints.HORIZONTAL; panel.add(selectionPanel, gbc); } private void createPlayer(JPanel panel) { playerPanel = new JPanel(); GridBagLayout gbl_playerPanel = new GridBagLayout(); gbl_playerPanel.columnWidths = new int[] {0, 0, 0, 0, 0, 0, 0, 0}; gbl_playerPanel.rowHeights = new int[] {0, 0, 0, 0}; gbl_playerPanel.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0}; gbl_playerPanel.rowWeights = new double[]{0.0, 0.0}; playerPanel.setLayout(gbl_playerPanel); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = insets0; gbc.anchor = GridBagConstraints.PAGE_START; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridx = 0; gbc.gridy = 0; progressBar = new JSlider(0, 0, 0); progressBar.setMinimum(0); progressBar.setMaximum(lastRow); setProgressBar(logDataTable.getSelectedRow()); progressBar.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { int row = progressBar.getValue(); if (playing) { if (row == lastRow || (endPlay >= 0 && endPlay < row)) { stop(); return; } if (showMarker) { Rectangle2D dataArea = logView.getChartPanel().getChartRenderingInfo().getPlotInfo().getDataArea(); XYPlot plot = (XYPlot) logView.getChartPanel().getChart().getPlot(); double x = plot.getDomainAxis().valueToJava2D(row, dataArea, plot.getDomainAxisEdge()); boolean isLeft = (x < (dataArea.getMaxX() - dataArea.getMinX()) / 2) ? true : false; logView.setMarkers(row, isLeft); } } logDataTable.getTable().setRowSelectionInterval(row, row); logDataTable.getTable().changeSelection(row, logDataTable.getSelectedColumn(), false, false); double x, y, z; int origXCol, origYCol, origZCol; synchronized (lock) { for (TableHolder tableHolder : tables) { try { origXCol = logDataTable.getCurrentIndexForOriginalColumn(tableHolder.xColIdx); origYCol = logDataTable.getCurrentIndexForOriginalColumn(tableHolder.yColIdx); origZCol = logDataTable.getCurrentIndexForOriginalColumn(tableHolder.zColIdx); x = Double.valueOf(logDataTable.getValueAt(row, origXCol).toString()); y = Double.valueOf(logDataTable.getValueAt(row, origYCol).toString()); if (origZCol > 0) z = Double.valueOf(logDataTable.getValueAt(row, origZCol).toString()); else z = Double.NaN; tableHolder.table.setCurrentPoint(x, y, z); } catch (Exception ex) { JOptionPane.showMessageDialog(null, "Invalid numeric value in column " + (tableHolder.xColIdx + 1) + ", row " + (row + 1), "Invalid value", JOptionPane.ERROR_MESSAGE); return; } } } } }); gbc.weightx = 1.0; gbc.gridwidth = gbl_playerPanel.columnWidths.length; playerPanel.add(progressBar, gbc); stopButton = addPlayerButton(0, new ImageIcon(getClass().getResource("/stop.png"))); rewButton = addPlayerButton(1, new ImageIcon(getClass().getResource("/rew.png"))); playButton = addPlayerButton(2, playIcon); ffwButton = addPlayerButton(3, new ImageIcon(getClass().getResource("/ffw.png"))); showIntepCells = addCheckBox(4, "Show interpolation cells"); showSignifCells = addCheckBox(5, "Show significant cell"); showTraceLine = addCheckBox(6, "Show trace line"); showTraceMarker = addCheckBox(7, "Show plot trace marker"); gbc.weightx = 0.0; gbc.gridwidth = 0; gbc.gridy = 1; panel.add(playerPanel, gbc); } ////////////////////////////////////////////////////////////////////////////////////// // WORK FUNCTIONS ////////////////////////////////////////////////////////////////////////////////////// void createPlayTable() { int x, y, z; x = xAxisColumn.getSelectedIndex() - 1; if (x < 0) { JOptionPane.showMessageDialog(null, "Please select 'X-Axis column' from drop-down list", "Error", JOptionPane.ERROR_MESSAGE); return; } y = yAxisColumn.getSelectedIndex() - 1; if (y < 0) { JOptionPane.showMessageDialog(null, "Please select 'X-Axis column' from drop-down list", "Error", JOptionPane.ERROR_MESSAGE); return; } z = zAxisColumn.getSelectedIndex() - 1; // no need to lock as og isn't being played yet LogPlayTable lpt = new LogPlayTable(this, "X-Axis: " + xAxisColumn.getSelectedItem() + "; Y-Axis: " + yAxisColumn.getSelectedItem()); lpt.setShowInterpolationCells(showIntepCells.isSelected()); lpt.setShowSignificantCell(showSignifCells.isSelected()); lpt.setShowTraceLine(showTraceLine.isSelected()); TableHolder th = new TableHolder(x, y, z, lpt); tables.add(th); } private JButton addPlayerButton(int column, ImageIcon icon) { JButton button = new JButton(icon); button.putClientProperty("Nimbus.Overrides", zeroInsets); button.setMargin(insets0); button.setBorderPainted(false); button.setContentAreaFilled(false); button.addActionListener(this); GridBagConstraints gbc_button = new GridBagConstraints(); gbc_button.insets = insets0; gbc_button.anchor = GridBagConstraints.WEST; gbc_button.gridx = column; gbc_button.gridy = 1; playerPanel.add(button, gbc_button); return button; } private JCheckBox addCheckBox(int column, String text) { JCheckBox check = new JCheckBox(text); check.addActionListener(this); GridBagConstraints gbc_check = new GridBagConstraints(); gbc_check.insets = insets0; gbc_check.anchor = GridBagConstraints.WEST; gbc_check.gridx = column; gbc_check.gridy = 1; playerPanel.add(check, gbc_check); return check; } private void play() { // no need to lock yet if (tables.size() == 0) { JOptionPane.showMessageDialog(null, "Please create at least one play table", "Error", JOptionPane.ERROR_MESSAGE); return; } if (playing) return; if (startPlay >= 0 && !paused) { logDataTable.getTable().setRowSelectionInterval(startPlay, startPlay); int col = logDataTable.getSelectedColumn(); logDataTable.getTable().changeSelection(startPlay, (col > 0 ? col : 0), false, false); } paused = false; setProgressBar(logDataTable.getSelectedRow()); timer.setDelay(timerDelay); playNext.set(1); playing = true; timer.start(); playButton.setIcon(pauseIcon); newPlayButton.setEnabled(false); logDataTable.setEditable(false); logView.disableMouseListener(); synchronized (lock) { for (TableHolder t : tables) t.table.setEditable(false); } } private void pause() { if (!playing) return; playing = false; paused = true; timer.stop(); timer.setDelay(timerDelay); playButton.setIcon(playIcon); playNext.set(1); } private void stop() { if (playing) pause(); if (paused) paused = false; else return; setProgressBar(startPlay); logDataTable.setEditable(true); logView.enableMouseListener(); newPlayButton.setEnabled(true); synchronized (lock) { for (TableHolder t : tables) t.table.setEditable(true); } } private void rewind() { playNext.set(-1); if (timer.getDelay() > 0) timer.setDelay(timer.getDelay() - step); } private void forward() { playNext.set(1); if (timer.getDelay() > 0) timer.setDelay(timer.getDelay() - step); } private void setShowInterpolationCells() { synchronized (lock) { for (TableHolder t : tables) t.table.setShowInterpolationCells(showIntepCells.isSelected()); } } private void setShowSignificantCell() { synchronized (lock) { for (TableHolder t : tables) t.table.setShowSignificantCell(showSignifCells.isSelected()); } } private void setShowTraceLine() { synchronized (lock) { for (TableHolder t : tables) t.table.setShowTraceLine(showTraceLine.isSelected()); } } public void setStartEndArea(ValueMarker startMarker, ValueMarker endMarker) { int start = (startMarker == null ? -1 : (int)startMarker.getValue()); int end = (endMarker == null ? -1 : (int)endMarker.getValue()); if (start == -1 || end == -1) startPlay = Math.max(start, end); else { startPlay = Math.min(start, end); endPlay = Math.max(start, end); } if (startPlay > lastRow) startPlay = lastRow; if (endPlay > lastRow) endPlay = lastRow; setProgressBar(startPlay); } public void setProgressBar(int val) { if (val >= 0 && val <= lastRow) progressBar.setValue(val); else progressBar.setValue(0); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == newPlayButton) createPlayTable(); else if (e.getSource() == playButton) { if (playing) pause(); else play(); } else if (e.getSource() == rewButton) { rewind(); } else if (e.getSource() == ffwButton) { forward(); } else if (e.getSource() == stopButton) { stop(); } else if (e.getSource() == showIntepCells) { setShowInterpolationCells(); } else if (e.getSource() == showSignifCells) { setShowSignificantCell(); } else if (e.getSource() == showTraceLine) { setShowTraceLine(); } else if (e.getSource() == showTraceMarker) { showMarker = showTraceMarker.isSelected(); } } }