001 package org.shiftone.jrat.provider.tree.ui.summary; 002 003 import org.jdesktop.swingx.JXHyperlink; 004 import org.jdesktop.swingx.JXTable; 005 import org.jdesktop.swingx.JXTaskPane; 006 import org.jdesktop.swingx.JXTaskPaneContainer; 007 import org.shiftone.jrat.desktop.util.JXTableWatcher; 008 import org.shiftone.jrat.desktop.util.Table; 009 import org.shiftone.jrat.provider.tree.ui.summary.action.AllColumnVisibilityAction; 010 import org.shiftone.jrat.provider.tree.ui.summary.action.ResetColumnVisibilityAction; 011 import org.shiftone.jrat.provider.tree.ui.summary.action.ShowSystemPropertiesAction; 012 import org.shiftone.jrat.provider.tree.ui.summary.action.SortAndShowColumnAction; 013 import org.shiftone.jrat.ui.util.PercentTableCellRenderer; 014 015 import javax.swing.*; 016 import javax.swing.event.ListSelectionEvent; 017 import javax.swing.event.ListSelectionListener; 018 import java.awt.*; 019 import java.text.DateFormat; 020 import java.text.DecimalFormat; 021 import java.text.NumberFormat; 022 import java.text.SimpleDateFormat; 023 import java.util.Date; 024 import java.util.Properties; 025 import java.util.prefs.Preferences; 026 027 /** 028 * @author jeff@shiftone.org (Jeff Drost) 029 */ 030 public class SummaryPanel extends JPanel { 031 032 private final JXTable table; 033 private final JXTaskPane tasks; 034 private final JXTaskPane details; 035 private final JXTaskPane summary; 036 private final JLabel detailLabel; 037 private final SummaryTableModel summaryTableModel; 038 private final long totalMethodDuration; 039 040 041 public SummaryPanel( 042 SummaryTableModel summaryTableModel, 043 long totalMethodDuration, 044 long sessionStartMs, 045 long sessionEndMs, 046 Properties systemProperties, 047 String hostName, 048 String hostAddress) { 049 050 JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 051 052 this.summaryTableModel = summaryTableModel; 053 this.totalMethodDuration = totalMethodDuration; 054 055 table = new JXTable(); 056 table.setModel(summaryTableModel); 057 table.setColumnControlVisible(true); 058 //table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); 059 060 table.getSelectionModel().addListSelectionListener(new SelectionListener()); 061 062 splitPane.setRightComponent(new JScrollPane(table)); 063 064 JXTableWatcher.initialize( 065 table, 066 Preferences.userNodeForPackage(SummaryPanel.class).node("columns"), 067 SummaryTableModel.getColumns()); 068 069 PercentTableCellRenderer.setDefaultRenderer(table); 070 071 { 072 073 detailLabel = new JLabel(); 074 075 JXTaskPaneContainer taskPaneContainer = new JXTaskPaneContainer(); 076 077 taskPaneContainer.add(tasks = createTasksPane(table)); 078 taskPaneContainer.add(details = createDetailPane(detailLabel)); 079 taskPaneContainer.add(summary = createSummaryPane(sessionStartMs, sessionEndMs, systemProperties, hostName, hostAddress)); 080 081 splitPane.setLeftComponent(taskPaneContainer); 082 } 083 084 085 setLayout(new BorderLayout()); 086 087 add(splitPane, BorderLayout.CENTER); 088 089 } 090 091 private JXTaskPane createDetailPane(Component component) { 092 JXTaskPane details = new JXTaskPane(); 093 details.setVisible(false); 094 details.add(component); 095 //details.add(new JXHyperlink(new ExportToCsvAction())); 096 return details; 097 } 098 099 private JXTaskPane createTasksPane(JXTable table) { 100 101 JXTaskPane pane = new JXTaskPane(); 102 pane.setTitle("Tasks"); 103 104 pane.add(new JXHyperlink(new SortAndShowColumnAction( 105 "Sort by Total Method Duration", 106 table, 107 SummaryTableModel.TOTAL_METHOD))); 108 109 pane.add(new JXHyperlink(new SortAndShowColumnAction( 110 "Sort by Exception Rate", 111 table, 112 SummaryTableModel.EXCEPTION_RATE))); 113 114 pane.add(new JXHyperlink( 115 new ResetColumnVisibilityAction(table, SummaryTableModel.getColumns()) 116 )); 117 118 pane.add(new JXHyperlink( 119 new AllColumnVisibilityAction(table) 120 )); 121 122 return pane; 123 } 124 125 private JXTaskPane createSummaryPane( 126 long sessionStartMs, 127 long sessionEndMs, 128 Properties systemProperties, 129 String hostName, 130 String hostAddress) { 131 132 DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG); 133 134 // honestly I don't feel great about this, but 135 // laying this out is such a pain any other way (that I know). 136 JXTaskPane pane = new JXTaskPane(); 137 pane.setTitle("Session Details"); 138 139 140 StringBuffer sb = new StringBuffer("<html><table>"); 141 142 sb.append("<tr><td>Start</td><td>"); 143 sb.append(dateFormat.format(new Date(sessionStartMs))); 144 sb.append("</td></tr>"); 145 146 sb.append("<tr><td>End</td><td>"); 147 sb.append(dateFormat.format(new Date(sessionEndMs))); 148 sb.append("</td></tr>"); 149 150 sb.append("<tr><td>Duration</td><td>"); 151 sb.append(sessionEndMs - sessionStartMs + " ms"); 152 sb.append("</td></tr>"); 153 154 sb.append("<tr><td>Host</td><td>"); 155 sb.append(hostName); 156 sb.append("</td></tr>"); 157 158 sb.append("<tr><td>Address</td><td>"); 159 sb.append(hostAddress); 160 sb.append("</td></tr>"); 161 162 163 sb.append("</table></html>"); 164 pane.add(new JLabel(sb.toString())); 165 166 167 pane.add(new JXHyperlink( 168 new ShowSystemPropertiesAction(this, systemProperties) 169 )); 170 171 return pane; 172 } 173 174 175 private class SelectionListener implements ListSelectionListener { 176 177 private final NumberFormat percentFormat; 178 179 public SelectionListener() { 180 percentFormat = DecimalFormat.getPercentInstance(); 181 percentFormat.setMinimumFractionDigits(1); 182 } 183 184 public void valueChanged(ListSelectionEvent e) { 185 186 if (!e.getValueIsAdjusting()) { 187 int[] rows = table.getSelectedRows(); 188 189 if (rows.length == 0) { 190 hide(); 191 } else { 192 show(rows); 193 } 194 } 195 } 196 197 private void hide() { 198 details.setVisible(false); 199 } 200 201 private void show(int[] rows) { 202 203 long methodTime = getTotal(rows, SummaryTableModel.TOTAL_METHOD); 204 long totalErrors = getTotal(rows, SummaryTableModel.EXCEPTIONS); 205 long totalExists = getTotal(rows, SummaryTableModel.EXITS); 206 long uncompleted = getTotal(rows, SummaryTableModel.UNCOMPLETED); 207 208 StringBuffer sb = new StringBuffer("<html><table>"); 209 210 sb.append("<tr><td>Total Exits</td><td>"); 211 sb.append(totalExists); 212 sb.append("</td></tr>"); 213 214 sb.append("<tr><td>Method Time</td><td>"); 215 sb.append(methodTime); 216 sb.append("ms ("); 217 sb.append(percentFormat.format((double) methodTime / (double) totalMethodDuration)); 218 sb.append(")</td></tr>"); 219 220 sb.append("<tr><td>Exceptions</td><td>"); 221 sb.append(totalErrors); 222 sb.append("</td></tr>"); 223 224 if (totalExists > 0) { 225 sb.append("<tr><td>Exception Rate</td><td>"); 226 sb.append(percentFormat.format((double) totalErrors / (double) totalExists)); 227 sb.append("</td></tr>"); 228 } 229 230 if (uncompleted > 0) { 231 sb.append("<tr><td>Uncompleted</td><td>"); 232 sb.append(uncompleted); 233 sb.append("</td></tr>"); 234 } 235 236 237 if (rows.length == 1) { 238 details.setTitle(getMethod(rows[0])); 239 } else { 240 details.setTitle(rows.length + " methods selected"); 241 } 242 243 sb.append("</table></html>"); 244 details.setVisible(true); 245 detailLabel.setText(sb.toString()); 246 } 247 248 249 private String getMethod(int row) { 250 int r = table.convertRowIndexToModel(row); 251 return (String) summaryTableModel.getValueAt(r, SummaryTableModel.METHOD.getIndex()); 252 } 253 254 private long getTotal(int[] rows, Table.Column column) { 255 256 long value = 0; 257 for (int i = 0; i < rows.length; i++) { 258 int r = table.convertRowIndexToModel(rows[i]); 259 Long v = (Long) summaryTableModel.getValueAt(r, column.getIndex()); 260 if (v != null) { 261 value += v.longValue(); 262 } 263 } 264 return value; 265 } 266 } 267 }