Web Inspector: hook up grid row filtering in the new Timelines UI
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ScriptDetailsTimelineView.js
1 /*
2  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ScriptDetailsTimelineView = class ScriptDetailsTimelineView extends WebInspector.TimelineView
27 {
28     constructor(timeline, extraArguments)
29     {
30         super(timeline, extraArguments);
31
32         console.assert(timeline.type === WebInspector.TimelineRecord.Type.Script);
33
34         let columns = {name: {}, location: {}, callCount: {}, startTime: {}, totalTime: {}, selfTime: {}, averageTime: {}};
35
36         columns.name.title = WebInspector.UIString("Name");
37         columns.name.width = "10%";
38         columns.name.icon = true;
39         columns.name.disclosure = true;
40
41         columns.location.title = WebInspector.UIString("Location");
42         columns.location.icon = true;
43         columns.location.width = "15%";
44
45         let isSamplingProfiler = !!window.ScriptProfilerAgent;
46         if (isSamplingProfiler)
47             columns.callCount.title = WebInspector.UIString("Samples");
48         else {
49             // COMPATIBILITY(iOS 9): ScriptProfilerAgent did not exist yet, we had call counts, not samples.
50             columns.callCount.title = WebInspector.UIString("Calls");
51         }
52         columns.callCount.width = "5%";
53         columns.callCount.aligned = "right";
54
55         columns.startTime.title = WebInspector.UIString("Start Time");
56         columns.startTime.width = "10%";
57         columns.startTime.aligned = "right";
58
59         columns.totalTime.title = WebInspector.UIString("Total Time");
60         columns.totalTime.width = "10%";
61         columns.totalTime.aligned = "right";
62
63         columns.selfTime.title = WebInspector.UIString("Self Time");
64         columns.selfTime.width = "10%";
65         columns.selfTime.aligned = "right";
66
67         columns.averageTime.title = WebInspector.UIString("Average Time");
68         columns.averageTime.width = "10%";
69         columns.averageTime.aligned = "right";
70
71         for (var column in columns)
72             columns[column].sortable = true;
73
74         this._dataGrid = new WebInspector.ScriptTimelineDataGrid(columns);
75         this._dataGrid.sortDelegate = this;
76         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("script-timeline-view-sort", "startTime");
77         this._dataGrid.sortOrderSetting = new WebInspector.Setting("script-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
78
79         this.setupDataGrid(this._dataGrid);
80
81         this.element.classList.add("script");
82         this.addSubview(this._dataGrid);
83
84         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
85         timeline.addEventListener(WebInspector.Timeline.Event.Refreshed, this._scriptTimelineRecordRefreshed, this);
86
87         this._pendingRecords = [];
88     }
89
90     // Public
91
92     shown()
93     {
94         super.shown();
95
96         this._dataGrid.shown();
97     }
98
99     hidden()
100     {
101         this._dataGrid.hidden();
102
103         super.hidden();
104     }
105
106     closed()
107     {
108         console.assert(this.representedObject instanceof WebInspector.Timeline);
109         this.representedObject.removeEventListener(null, null, this);
110
111         this._dataGrid.closed();
112     }
113
114     get selectionPathComponents()
115     {
116         var dataGridNode = this._dataGrid.selectedNode;
117         if (!dataGridNode)
118             return null;
119
120         var pathComponents = [];
121
122         while (dataGridNode && !dataGridNode.root) {
123             console.assert(dataGridNode instanceof WebInspector.TimelineDataGridNode);
124             if (dataGridNode.hidden)
125                 return null;
126
127             let representedObject = null;
128             if (dataGridNode instanceof WebInspector.ProfileNodeDataGridNode)
129                 representedObject = dataGridNode.profileNode;
130
131             let pathComponent = new WebInspector.TimelineDataGridNodePathComponent(dataGridNode);
132             pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.dataGridNodePathComponentSelected, this);
133             pathComponents.unshift(pathComponent);
134             dataGridNode = dataGridNode.parent;
135         }
136
137         return pathComponents;
138     }
139
140     reset()
141     {
142         super.reset();
143
144         this._dataGrid.reset();
145
146         this._pendingRecords = [];
147     }
148
149     // TimelineDataGrid sort delegate
150
151     dataGridSortComparator(sortColumnIdentifier, sortDirection, node1, node2)
152     {
153         if (sortColumnIdentifier !== "name")
154             return null;
155
156         let displayName1 = node1.displayName();
157         let displayName2 = node2.displayName();
158         if (displayName1 !== displayName2)
159             return displayName1.localeCompare(displayName2) * sortDirection;
160
161         return node1.subtitle.localeCompare(node2.subtitle) * sortDirection;
162     }
163
164     // Protected
165
166     dataGridNodePathComponentSelected(event)
167     {
168         let dataGridNode = event.data.pathComponent.timelineDataGridNode;
169         console.assert(dataGridNode.dataGrid === this._dataGrid);
170
171         dataGridNode.revealAndSelect();
172     }
173
174     layout()
175     {
176         if (this.startTime !== this._oldStartTime || this.endTime !== this._oldEndTime) {
177             let dataGridNode = this._dataGrid.children[0];
178             while (dataGridNode) {
179                 dataGridNode.updateRangeTimes(this.startTime, this.endTime);
180                 if (dataGridNode.revealed)
181                     dataGridNode.refreshIfNeeded();
182                 dataGridNode = dataGridNode.traverseNextNode(false, null, true);
183             }
184
185             this._oldStartTime = this.startTime;
186             this._oldEndTime = this.endTime;
187         }
188
189         this._processPendingRecords();
190     }
191
192     // Private
193
194     _processPendingRecords()
195     {
196         if (WebInspector.timelineManager.scriptProfilerIsTracking())
197             return;
198
199         if (!this._pendingRecords.length)
200             return;
201
202         let zeroTime = this.zeroTime;
203         let startTime = this.startTime;
204         let endTime = this.endTime;
205
206         for (let scriptTimelineRecord of this._pendingRecords) {
207             let rootNodes = [];
208             if (scriptTimelineRecord.profile) {
209                 // FIXME: Support using the bottom-up tree once it is implemented.
210                 rootNodes = scriptTimelineRecord.profile.topDownRootNodes;
211             }
212
213             let dataGridNode = new WebInspector.ScriptTimelineDataGridNode(scriptTimelineRecord, zeroTime);
214             this._dataGrid.addRowInSortOrder(null, dataGridNode);
215
216             for (let profileNode of rootNodes) {
217                 let profileNodeDataGridNode = new WebInspector.ProfileNodeDataGridNode(profileNode, zeroTime, startTime, endTime);
218                 this._dataGrid.addRowInSortOrder(null, profileNodeDataGridNode, dataGridNode);
219             }
220         }
221
222         this._pendingRecords = [];
223     }
224
225     _scriptTimelineRecordAdded(event)
226     {
227         var scriptTimelineRecord = event.data.record;
228         console.assert(scriptTimelineRecord instanceof WebInspector.ScriptTimelineRecord);
229
230         this._pendingRecords.push(scriptTimelineRecord);
231
232         this.needsLayout();
233     }
234
235     _scriptTimelineRecordRefreshed(event)
236     {
237         this.needsLayout();
238     }
239 };