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 }