/*
* LocationsPanel.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.app.mapper.application;
import dr.app.gui.FileDrop;
import dr.app.gui.table.DateCellEditor;
import dr.app.gui.table.TableEditorStopper;
import dr.app.gui.table.TableSorter;
import dr.app.gui.util.LongTask;
import dr.app.mapper.application.mapper.Layer;
import dr.inference.trace.LogFileTraces;
import dr.inference.trace.TraceException;
import dr.inference.trace.TraceList;
import jam.framework.Exportable;
import jam.panels.ActionPanel;
import jam.table.HeaderRenderer;
import jam.table.TableRenderer;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.BorderUIResource;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import java.awt.*;
import java.awt.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.*;
import java.util.*;
/**
* @author Andrew Rambaut
* @version $Id: StrainsPanel.java,v 1.17 2006/09/05 13:29:34 rambaut Exp $
*/
public class LocationsPanel extends JPanel implements Exportable, MapperDocument.Listener {
private JTable traceTable = null;
private TraceTableModel traceTableModel = null;
private JSplitPane splitPane1 = null;
private JPanel topPanel = null;
private JTable layerTable = null;
private LayerTableModel layerTableModel = null;
private JTable dataTable = null;
private DataTableModel dataTableModel = null;
private final MapperFrame frame;
private final MapperDocument document;
private JScrollPane scrollPane1;
private JLabel progressLabel;
private JProgressBar progressBar;
private final java.util.List<LogFileTraces> traceLists = new ArrayList<LogFileTraces>();
private final java.util.List<Layer> layers = new ArrayList<Layer>();
String message = "";
private int dividerLocation = -1;
public LocationsPanel(final MapperFrame parent, final MapperDocument document) {
this.frame = parent;
this.document = document;
traceTableModel = new TraceTableModel();
traceTable = new JTable(traceTableModel);
TableRenderer renderer = new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4));
traceTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
traceTable.getColumnModel().getColumn(1).setPreferredWidth(50);
traceTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
traceTable.getColumnModel().getColumn(2).setPreferredWidth(50);
traceTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
traceTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
traceTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
traceTableSelectionChanged();
}
});
scrollPane1 = new JScrollPane(traceTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
ActionPanel actionPanel1 = new ActionPanel(false);
actionPanel1.setAddAction(frame.getImportLocationsAction());
actionPanel1.setRemoveAction(frame.getDeleteItemAction());
frame.getDeleteItemAction().setEnabled(false);
JPanel controlPanel1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
controlPanel1.add(actionPanel1);
topPanel = new JPanel(new BorderLayout(0, 0));
topPanel.setBorder(new BorderUIResource.EmptyBorderUIResource(new java.awt.Insets(0, 0, 6, 0)));
topPanel.add(new JLabel("Trace Files:"), BorderLayout.NORTH);
topPanel.add(scrollPane1, BorderLayout.CENTER);
topPanel.add(controlPanel1, BorderLayout.SOUTH);
layerTableModel = new LayerTableModel();
layerTable = new JTable(layerTableModel) {
//Implement table header tool tips.
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(columnModel) {
// public String getToolTipText(MouseEvent e) {
// java.awt.Point p = e.getPoint();
// int index = columnModel.getColumnIndexAtX(p.x);
// int realIndex = columnModel.getColumn(index).getModelIndex();
// return columnToolTips[realIndex];
// }
};
}
};
layerTable.getColumnModel().getColumn(0).setPreferredWidth(150);
layerTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
layerTable.getColumnModel().getColumn(1).setPreferredWidth(70);
layerTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
// layerTable.getColumnModel().getColumn(2).setPreferredWidth(70);
// layerTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
// ComboBoxRenderer comboBoxRenderer = new ComboBoxRenderer(TraceFactory.TraceType.values());
// comboBoxRenderer.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
// layerTable.getColumnModel().getColumn(3).setPreferredWidth(20);
// layerTable.getColumnModel().getColumn(3).setCellRenderer(renderer);
layerTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
layerTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
layerTableSelectionChanged();
}
});
TableEditorStopper.ensureEditingStopWhenTableLosesFocus(layerTable);
JScrollPane scrollPane2 = new JScrollPane(layerTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
JPanel bottomPanel = new JPanel(new BorderLayout(0, 0));
bottomPanel.add(new JLabel("Layers:"), BorderLayout.NORTH);
bottomPanel.add(scrollPane2, BorderLayout.CENTER);
dataTableModel = new DataTableModel();
TableSorter sorter = new TableSorter(dataTableModel);
dataTable = new JTable(sorter);
sorter.setTableHeader(dataTable.getTableHeader());
dataTable.getTableHeader().setReorderingAllowed(false);
dataTable.getTableHeader().setDefaultRenderer(
new HeaderRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4)));
dataTable.getColumnModel().getColumn(0).setCellRenderer(
new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4)));
dataTable.getColumnModel().getColumn(0).setPreferredWidth(80);
dataTable.getColumnModel().getColumn(1).setCellRenderer(
new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4)));
dataTable.getColumnModel().getColumn(1).setPreferredWidth(80);
dataTable.getColumnModel().getColumn(1).setCellEditor(
new DateCellEditor());
dataTable.getColumnModel().getColumn(2).setCellRenderer(
new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4)));
dataTable.getColumnModel().getColumn(2).setPreferredWidth(80);
TableEditorStopper.ensureEditingStopWhenTableLosesFocus(dataTable);
dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
selectionChanged();
}
});
JScrollPane scrollPane = new JScrollPane(dataTable,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane.setOpaque(false);
JToolBar toolBar1 = new JToolBar();
toolBar1.setFloatable(false);
toolBar1.setOpaque(false);
// toolBar1.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
// JButton button = new JButton(clearDatesAction);
// PanelUtils.setupComponent(button);
// toolBar1.add(button);
// button = new JButton(guessDatesAction);
// PanelUtils.setupComponent(button);
// toolBar1.add(button);
// toolBar1.add(new JToolBar.Separator(new Dimension(12, 12)));
// final JLabel unitsLabel = new JLabel("Dates specified as ");
// toolBar1.add(unitsLabel);
// toolBar1.add(unitsCombo);
// toolBar1.add(directionCombo);
setOpaque(false);
setBorder(new BorderUIResource.EmptyBorderUIResource(new Insets(12, 12, 12, 12)));
setLayout(new BorderLayout(0, 0));
JPanel leftPanel = new JPanel(new BorderLayout(0, 0));
leftPanel.setPreferredSize(new Dimension(400, 300));
splitPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, topPanel, bottomPanel);
splitPane1.setBorder(null);
JPanel progressPanel = new JPanel(new BorderLayout(0, 0));
progressLabel = new JLabel("");
progressBar = new JProgressBar();
progressPanel.add(progressLabel, BorderLayout.NORTH);
progressPanel.add(progressBar, BorderLayout.CENTER);
progressPanel.setBorder(new BorderUIResource.EmptyBorderUIResource(new java.awt.Insets(6, 0, 0, 0)));
leftPanel.add(splitPane1, BorderLayout.CENTER);
leftPanel.add(progressPanel, BorderLayout.SOUTH);
leftPanel.setBorder(new BorderUIResource.EmptyBorderUIResource(new java.awt.Insets(12, 12, 12, 6)));
JSplitPane splitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, leftPanel, scrollPane);
splitPane2.setBorder(null);
splitPane2.setDividerLocation(350);
Color focusColor = UIManager.getColor("Focus.color");
Border focusBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, focusColor);
splitPane1.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
new FileDrop(null, splitPane1, focusBorder, new FileDrop.Listener() {
public void filesDropped(java.io.File[] files) {
frame.importLocationFiles(files);
} // end filesDropped
}); // end FileDrop.Listener
add(toolBar1, "North");
add(splitPane2, "Center");
}
@Override
public void taxaChanged() {
dataTableModel.fireTableDataChanged();
}
public void addTraceList(LogFileTraces traceList) {
int[] selRows = traceTable.getSelectedRows();
traceLists.add(traceList);
// setAnalysesEnabled(true);
traceTableModel.fireTableDataChanged();
int newRow = traceLists.size() - 1;
traceTable.getSelectionModel().setSelectionInterval(newRow, newRow);
if (selRows.length > 1) {
for (int row : selRows) {
if (row == traceLists.size() - 1) {
row = traceLists.size();
}
traceTable.getSelectionModel().addSelectionInterval(row, row);
}
}
// setupDividerLocation();
}
private void removeTraceList() {
int[] selRows = traceTable.getSelectedRows();
LogFileTraces[] tls = new LogFileTraces[selRows.length];
int i = 0;
for (int row : selRows) {
tls[i] = traceLists.get(row);
i++;
}
for (LogFileTraces tl : tls) {
traceLists.remove(tl);
}
traceTableModel.fireTableDataChanged();
// layerTableModel.fireTableDataChanged();
if (traceLists.size() == 0) {
frame.getDeleteItemAction().setEnabled(false);
// setAnalysesEnabled(false);
// layerTableModel.fireTableDataChanged();
}
if (traceLists.size() > 0) {
int row = selRows[0];
if (row >= traceLists.size()) {
row = traceLists.size() - 1;
}
traceTable.getSelectionModel().addSelectionInterval(row, row);
}
// setupDividerLocation();
}
public void setBurnIn(int index, int burnIn) {
LogFileTraces trace = traceLists.get(index);
trace.setBurnIn(burnIn);
analyseTraceList(trace);
updateTraceTables();
}
public void updateTraceTables() {
int[] selectedTraces = traceTable.getSelectedRows();
// int[] selectedStatistics = layerTable.getSelectedRows();
traceTableModel.fireTableDataChanged();
// layerTableModel.fireTableDataChanged();
traceTable.getSelectionModel().clearSelection();
for (int row : selectedTraces) {
traceTable.getSelectionModel().addSelectionInterval(row, row);
}
// layerTable.getSelectionModel().clearSelection();
// for (int row : selectedStatistics) {
// layerTable.getSelectionModel().addSelectionInterval(row, row);
// }
}
public void traceTableSelectionChanged() {
int[] selRows = traceTable.getSelectedRows();
if (selRows.length == 0) {
frame.getDeleteItemAction().setEnabled(false);
// setAnalysesEnabled(false);
return;
}
// setAnalysesEnabled(true);
frame.getDeleteItemAction().setEnabled(true);
// int[] rows = layerTable.getSelectedRows();
// layerTableModel.fireTableDataChanged();
//
// if (rows.length > 0) {
// for (int row : rows) {
// layerTable.getSelectionModel().addSelectionInterval(row, row);
// }
// } else {
// layerTable.getSelectionModel().setSelectionInterval(0, 0);
// }
}
public void layerTableSelectionChanged() {
}
public void analyseTraceList(TraceList job) {
if (analyseTask == null) {
analyseTask = new AnalyseTraceTask();
javax.swing.Timer timer = new javax.swing.Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
progressBar.setMaximum(analyseTask.getLengthOfTask());
progressBar.setValue(analyseTask.getCurrent());
}
});
analyseTask.go();
timer.start();
}
analyseTask.add(job);
}
AnalyseTraceTask analyseTask = null;
class AnalyseTraceTask extends LongTask {
class AnalysisStack<T> {
private final java.util.List<T> jobs = new ArrayList<T>();
public synchronized void add(T job) {
jobs.add(job);
}
public synchronized int getCount() {
return jobs.size();
}
public synchronized T get(int index) {
return jobs.get(index);
}
public synchronized void remove(int index) {
jobs.remove(index);
}
}
private final AnalysisStack<TraceList> analysisStack = new AnalysisStack<TraceList>();
public AnalyseTraceTask() {
}
public void add(TraceList job) {
analysisStack.add(job);
current = 0;
}
public int getCurrent() {
return current;
}
public int getLengthOfTask() {
int count = 0;
for (int i = 0; i < analysisStack.getCount(); i++) {
count += analysisStack.get(i).getTraceCount();
}
return count;
}
public void stop() {
}
public boolean done() {
return false;
}
public String getDescription() {
return "Analysing Trace File...";
}
public String getMessage() {
return null;
}
public Object doWork() {
current = 0;
boolean textCleared = true;
do {
if (analysisStack.getCount() > 0) {
Object job = analysisStack.get(0);
TraceList tl = (TraceList) job;
try {
for (int i = 0; i < tl.getTraceCount(); i++) {
progressLabel.setText("Analysing " + tl.getName() + ":");
textCleared = false;
tl.analyseTrace(i);
repaint();
current += 1;
}
} catch (final Exception ex) {
// do nothing. An exception is sometimes fired when burnin is changed whilst in the
// middle of an analysis. This doesn't seem to matter as the analysis is restarted.
ex.printStackTrace();
// EventQueue.invokeLater (
// new Runnable () {
// public void run () {
// JOptionPane.showMessageDialog(TracerFrame.this, "Fatal exception: " + ex.getMessage(),
// "Error reading file",
// JOptionPane.ERROR_MESSAGE);
// }
// });
}
analysisStack.remove(0);
} else {
if (!textCleared) {
progressLabel.setText("");
textCleared = true;
}
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
// do nothing
}
}
} while (true);
}
//private int lengthOfTask = 0;
private int current = 0;
//private String message;
}
public JComponent getExportableComponent() {
return dataTable;
}
public void selectionChanged() {
// nothing to do
}
class TraceTableModel extends AbstractTableModel {
final String[] columnNames = {"Trace File", "States", "Burn-In"};
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
int n = traceLists.size();
if (n == 0) n++;
return n;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
TraceList traceList;
if (traceLists.size() == 0) {
switch (col) {
case 0:
return "No files loaded";
case 1:
return "";
case 2:
return "";
}
} else {
traceList = traceLists.get(row);
switch (col) {
case 0:
return traceList.getName();
case 1:
return traceList.getMaxState();
case 2:
return traceList.getBurnIn();
}
}
return null;
}
public void setValueAt(Object value, int row, int col) {
if (col == 2) {
setBurnIn(row, (Integer) value);
}
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) {
return col == 2 && row < traceLists.size();
}
}
class LayerTableModel extends AbstractTableModel {
final String[] columnNames = {"Layer", "Type"};
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return layers.size();
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
Layer layer = layers.get(row);
if (col == 0) return layer.getName();
if (col == 1) return layer.getType().toString();
return "";
}
public boolean isCellEditable(int row, int col) {
return true;
}
public Class getColumnClass(int c) {
if (getRowCount() == 0) {
return Object.class;
}
return getValueAt(0, c).getClass();
}
}
class DataTableModel extends AbstractTableModel {
String[] columnNames = {"Serum", "Virus", "Titre", "Table"};
public DataTableModel() {
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
// java.util.List<Taxon> taxonList = document.getTaxa();
//
// if (taxonList == null) return 0;
//
// return taxonList.size();
return 0;
}
public Object getValueAt(int row, int col) {
// java.util.List<Taxon> taxonList = document.getTaxa();
//
// switch (col) {
// case 0:
// return taxonList.get(row);
// case 1:
// Date date = taxonList.get(row).getDate();
// if (date != null) {
// return date.getTimeValue();
// } else {
// return "-";
// }
// case 2:
// if (heights != null) {
// return heights[row];
// } else {
// return "0.0";
// }
// }
return null;
}
public void setValueAt(Object aValue, int row, int col) {
// java.util.List<Taxon> taxonList = document.getTaxa();
//
// if (col == 0) {
// taxonList.get(row).setId(aValue.toString());
// } else if (col == 1) {
// Date date = taxonList.get(row).getDate();
// if (date != null) {
// double d = (Double) aValue;
// Date newDate = createDate(d, date.getUnits(), date.isBackwards(), date.getOrigin());
// taxonList.get(row).setDate(newDate);
// }
// }
//
// timeScaleChanged();
}
public boolean isCellEditable(int row, int col) {
// if (col == 0) return true;
// if (col == 1) {
// Date date = document.getTaxa().get(row).getDate();
// return (date != null);
// }
return false;
}
public String getColumnName(int column) {
return columnNames[column];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(getColumnName(0));
for (int j = 1; j < getColumnCount(); j++) {
buffer.append("\t");
buffer.append(getColumnName(j));
}
buffer.append("\n");
for (int i = 0; i < getRowCount(); i++) {
buffer.append(getValueAt(i, 0));
for (int j = 1; j < getColumnCount(); j++) {
buffer.append("\t");
buffer.append(getValueAt(i, j));
}
buffer.append("\n");
}
return buffer.toString();
}
}
}