Skip to content

Commit de35730

Browse files
committed
cluster data panel - table view
1 parent ed998b0 commit de35730

3 files changed

Lines changed: 272 additions & 181 deletions

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
package cbit.plot.gui;
2+
3+
import cbit.vcell.parser.ExpressionException;
4+
import cbit.vcell.solver.ode.ODESolverResultSet;
5+
import cbit.vcell.solver.ode.gui.ClusterSpecificationPanel;
6+
import cbit.vcell.util.ColumnDescription;
7+
import org.apache.logging.log4j.LogManager;
8+
import org.apache.logging.log4j.Logger;
9+
import org.vcell.util.gui.NonEditableDefaultTableModel;
10+
import org.vcell.util.gui.ScrollTable;
11+
import org.vcell.util.gui.SpecialtyTableRenderer;
12+
13+
import javax.swing.*;
14+
import javax.swing.event.ChangeEvent;
15+
import javax.swing.event.ChangeListener;
16+
import javax.swing.table.DefaultTableCellRenderer;
17+
import javax.swing.table.TableCellRenderer;
18+
import javax.swing.table.TableColumn;
19+
import java.awt.*;
20+
import java.awt.event.ActionEvent;
21+
import java.awt.event.ActionListener;
22+
import java.awt.event.MouseEvent;
23+
import java.awt.event.MouseListener;
24+
import java.beans.PropertyChangeEvent;
25+
import java.beans.PropertyChangeListener;
26+
27+
public class ClusterDataPanel extends JPanel {
28+
29+
private static final Logger LG = LogManager.getLogger(ClusterDataPanel.class);
30+
31+
private ScrollTable scrollPaneTable;
32+
private NonEditableDefaultTableModel nonEditableDefaultTableModel = null;
33+
34+
private final IvjEventHandler ivjEventHandler = new IvjEventHandler();
35+
36+
class IvjEventHandler implements ActionListener, MouseListener, PropertyChangeListener, ChangeListener {
37+
38+
@Override
39+
public void mouseClicked(MouseEvent e) {
40+
if (e.getSource() == getScrollPaneTable()) {
41+
int row = getScrollPaneTable().rowAtPoint(e.getPoint());
42+
int col = getScrollPaneTable().columnAtPoint(e.getPoint());
43+
System.out.println("ClusterDataPanel: clicked row=" + row + " col=" + col);
44+
}
45+
}
46+
47+
@Override public void mousePressed(MouseEvent e) {}
48+
@Override public void mouseReleased(MouseEvent e) {}
49+
@Override public void mouseEntered(MouseEvent e) {}
50+
@Override public void mouseExited(MouseEvent e) {}
51+
52+
@Override
53+
public void actionPerformed(ActionEvent e) {
54+
// reserved for future buttons or context menu actions
55+
}
56+
57+
@Override
58+
public void propertyChange(PropertyChangeEvent evt) {
59+
// reserved for future dynamic formatting
60+
}
61+
62+
@Override
63+
public void stateChanged(ChangeEvent e) {
64+
// reserved for future slider/spinner interactions
65+
}
66+
}
67+
68+
private class ClusterHeaderRenderer extends DefaultTableCellRenderer {
69+
70+
private final TableCellRenderer base;
71+
public ClusterHeaderRenderer(TableCellRenderer base) {
72+
this.base = base;
73+
}
74+
75+
@Override
76+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
77+
boolean hasFocus, int row, int column) {
78+
// First let ScrollTable’s renderer do its work
79+
Component c = base.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
80+
if (!(c instanceof JLabel)) {
81+
return c; // safety
82+
}
83+
JLabel lbl = (JLabel) c;
84+
String name = value == null ? "" : value.toString();
85+
86+
// Read mode from table metadata
87+
ClusterSpecificationPanel.DisplayMode mode = (ClusterSpecificationPanel.DisplayMode)
88+
((JComponent)table).getClientProperty("ClusterDisplayMode");
89+
90+
// First-time creation: no mode yet
91+
if (mode == null) {
92+
lbl.setToolTipText(null);
93+
return lbl; // leave ScrollTable’s default header styling intact
94+
}
95+
96+
String unit = "";
97+
String tooltip = "";
98+
if (column == 0) {
99+
unit = "seconds";
100+
tooltip = "Simulation time in seconds";
101+
} else {
102+
switch (mode) {
103+
case COUNTS:
104+
unit = "molecules";
105+
tooltip = "Number of clusters of size " + name + " molecules";
106+
break;
107+
case MEAN:
108+
unit = "value";
109+
tooltip = "Cluster mean statistic for " + name;
110+
break;
111+
case OVERALL:
112+
unit = "value";
113+
tooltip = "Cluster overall statistic for " + name;
114+
break;
115+
}
116+
}
117+
lbl.setText("<html>" + name + "<font color=\"#8B0000\"> [" + unit + "]</font></html>");
118+
lbl.setToolTipText(tooltip);
119+
return lbl;
120+
}
121+
}
122+
123+
public ClusterDataPanel() {
124+
super();
125+
initialize();
126+
}
127+
private void initialize() {
128+
try {
129+
setName("ClusterDataPanel");
130+
setLayout(new java.awt.BorderLayout());
131+
setSize(541, 348);
132+
add(getScrollPaneTable().getEnclosingScrollPane(), BorderLayout.CENTER);
133+
JLabel lblNewLabel = new JLabel("<html>To <b>Copy</b> table data or <b>Export</b> as HDF5, select rows/cells and use the right mouse button menu.</html>");
134+
add(lblNewLabel, BorderLayout.SOUTH);
135+
initConnections();
136+
// controlKeys();
137+
} catch (Throwable exc) {
138+
handleException(exc);
139+
}
140+
}
141+
private void initConnections() throws java.lang.Exception {
142+
this.addPropertyChangeListener(ivjEventHandler);
143+
getScrollPaneTable().addMouseListener(ivjEventHandler);
144+
getScrollPaneTable().setModel(getNonEditableDefaultTableModel());
145+
getScrollPaneTable().createDefaultColumnsFromModel();
146+
TableCellRenderer baseHeaderRenderer = getScrollPaneTable().getTableHeader().getDefaultRenderer();
147+
getScrollPaneTable().getTableHeader().setDefaultRenderer(new ClusterHeaderRenderer(baseHeaderRenderer));
148+
149+
}
150+
private void handleException(java.lang.Throwable exception) {
151+
System.out.println("--------- UNCAUGHT EXCEPTION ---------");
152+
exception.printStackTrace(System.out);
153+
}
154+
155+
// -----------------------------------------------------------
156+
private ScrollTable getScrollPaneTable() {
157+
if (scrollPaneTable == null) {
158+
try {
159+
scrollPaneTable = new ScrollTable();
160+
scrollPaneTable.setName("ScrollPaneTable");
161+
scrollPaneTable.setCellSelectionEnabled(true);
162+
scrollPaneTable.setBounds(0, 0, 200, 200);
163+
} catch (java.lang.Throwable ivjExc) {
164+
handleException(ivjExc);
165+
}
166+
}
167+
return scrollPaneTable;
168+
}
169+
170+
private NonEditableDefaultTableModel getNonEditableDefaultTableModel() {
171+
if (nonEditableDefaultTableModel == null) {
172+
try {
173+
nonEditableDefaultTableModel = new NonEditableDefaultTableModel();
174+
} catch (java.lang.Throwable ivjExc) {
175+
handleException(ivjExc);
176+
}
177+
}
178+
return nonEditableDefaultTableModel;
179+
}
180+
181+
public void setSpecialityRenderer(SpecialtyTableRenderer str) {
182+
// TODO: write some appropriate renderer when we decide what to show in the tooltip
183+
// use RendererViewerDoubleWithTooltip for inspiration
184+
// getScrollPaneTable().setSpecialityRenderer(str);
185+
}
186+
187+
188+
public void updateData(ClusterSpecificationPanel.ClusterSelection sel) throws ExpressionException {
189+
if(sel == null) {
190+
getScrollPaneTable().putClientProperty("ClusterDisplayMode", null);
191+
} else {
192+
getScrollPaneTable().putClientProperty("ClusterDisplayMode", sel.mode);
193+
}
194+
if (sel == null || sel.resultSet == null || sel.columns == null || sel.columns.isEmpty()) {
195+
getNonEditableDefaultTableModel().setDataVector(new Object[][]{}, new Object[]{"No data"});
196+
getScrollPaneTable().createDefaultColumnsFromModel();
197+
revalidate();
198+
repaint();
199+
return;
200+
}
201+
ODESolverResultSet srs = sel.resultSet;
202+
java.util.List<ColumnDescription> columns = sel.columns;
203+
204+
int timeIndex = srs.findColumn("t");
205+
double[] times = srs.extractColumn(timeIndex);
206+
int rowCount = times.length;
207+
208+
// column names
209+
String[] columnNames = new String[1 + columns.size()];
210+
columnNames[0] = "t";
211+
for (int i = 0; i < columns.size(); i++) {
212+
columnNames[i + 1] = columns.get(i).getName();
213+
}
214+
215+
// data
216+
Object[][] data = new Object[rowCount][columnNames.length];
217+
for (int r = 0; r < rowCount; r++) {
218+
int c = 0;
219+
data[r][c++] = times[r];
220+
for (ColumnDescription cd : columns) {
221+
int idx = srs.findColumn(cd.getName());
222+
double[] y = srs.extractColumn(idx);
223+
data[r][c++] = y[r];
224+
}
225+
}
226+
227+
// update existing model
228+
getNonEditableDefaultTableModel().setDataVector(data, columnNames);
229+
230+
// refresh table columns
231+
getScrollPaneTable().createDefaultColumnsFromModel();
232+
autoSizeTableColumns(getScrollPaneTable());
233+
234+
revalidate();
235+
repaint();
236+
}
237+
238+
private void autoSizeTableColumns(JTable table) {
239+
final int margin = 12;
240+
241+
for (int col = 0; col < table.getColumnCount(); col++) {
242+
TableColumn column = table.getColumnModel().getColumn(col);
243+
244+
int maxWidth = 0;
245+
246+
// header
247+
TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
248+
Component headerComp = headerRenderer.getTableCellRendererComponent(
249+
table, column.getHeaderValue(), false, false, 0, col);
250+
maxWidth = Math.max(maxWidth, headerComp.getPreferredSize().width);
251+
252+
// cells
253+
for (int row = 0; row < table.getRowCount(); row++) {
254+
TableCellRenderer cellRenderer = table.getCellRenderer(row, col);
255+
Component comp = table.prepareRenderer(cellRenderer, row, col);
256+
maxWidth = Math.max(maxWidth, comp.getPreferredSize().width);
257+
}
258+
259+
column.setPreferredWidth(maxWidth + margin);
260+
}
261+
}
262+
}

0 commit comments

Comments
 (0)