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    }