Web Inspector: Timelines UI redesign: remove navigation sidebar
[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(null, columns, this);
75         this._dataGrid.addEventListener(WebInspector.TimelineDataGrid.Event.FiltersDidChange, this._dataGridFiltersDidChange, this);
76         this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
77         this._dataGrid.sortColumnIdentifierSetting = new WebInspector.Setting("script-timeline-view-sort", "startTime");
78         this._dataGrid.sortOrderSetting = new WebInspector.Setting("script-timeline-view-sort-order", WebInspector.DataGrid.SortOrder.Ascending);
79
80         this.element.classList.add("script");
81         this.addSubview(this._dataGrid);
82
83         timeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
84         timeline.addEventListener(WebInspector.Timeline.Event.Refreshed, this._scriptTimelineRecordRefreshed, this);
85
86         this._pendingRecords = [];
87     }
88
89     // Public
90
91     shown()
92     {
93         super.shown();
94
95         this._dataGrid.shown();
96     }
97
98     hidden()
99     {
100         this._dataGrid.hidden();
101
102         super.hidden();
103     }
104
105     closed()
106     {
107         console.assert(this.representedObject instanceof WebInspector.Timeline);
108         this.representedObject.removeEventListener(null, null, this);
109
110         this._dataGrid.closed();
111     }
112
113     get selectionPathComponents()
114     {
115         var dataGridNode = this._dataGrid.selectedNode;
116         if (!dataGridNode)
117             return null;
118
119         var pathComponents = [];
120
121         while (dataGridNode && !dataGridNode.root) {
122             console.assert(dataGridNode instanceof WebInspector.TimelineDataGridNode);
123             if (dataGridNode.hidden)
124                 return null;
125
126             let representedObject = null;
127             if (dataGridNode instanceof WebInspector.ProfileNodeDataGridNode)
128                 representedObject = dataGridNode.profileNode;
129
130             let pathComponent = new WebInspector.TimelineDataGridNodePathComponent(dataGridNode);
131             pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.dataGridNodePathComponentSelected, this);
132             pathComponents.unshift(pathComponent);
133             dataGridNode = dataGridNode.parent;
134         }
135
136         return pathComponents;
137     }
138
139     reset()
140     {
141         super.reset();
142
143         this._dataGrid.reset();
144
145         this._pendingRecords = [];
146     }
147
148     // Protected
149
150     canShowContentViewForTreeElement(treeElement)
151     {
152         if (treeElement instanceof WebInspector.ProfileNodeTreeElement)
153             return !!treeElement.profileNode.sourceCodeLocation;
154         return super.canShowContentViewForTreeElement(treeElement);
155     }
156
157     showContentViewForTreeElement(treeElement)
158     {
159         if (treeElement instanceof WebInspector.ProfileNodeTreeElement) {
160             if (treeElement.profileNode.sourceCodeLocation)
161                 WebInspector.showOriginalOrFormattedSourceCodeLocation(treeElement.profileNode.sourceCodeLocation);
162             return;
163         }
164
165         super.showContentViewForTreeElement(treeElement);
166     }
167
168     dataGridNodePathComponentSelected(event)
169     {
170         let dataGridNode = event.data.pathComponent.timelineDataGridNode;
171         console.assert(dataGridNode.dataGrid === this._dataGrid);
172
173         dataGridNode.revealAndSelect();
174     }
175
176     layout()
177     {
178         if (this.startTime !== this._oldStartTime || this.endTime !== this._oldEndTime) {
179             let dataGridNode = this._dataGrid.children[0];
180             while (dataGridNode) {
181                 dataGridNode.updateRangeTimes(this.startTime, this.endTime);
182                 if (dataGridNode.revealed)
183                     dataGridNode.refreshIfNeeded();
184                 dataGridNode = dataGridNode.traverseNextNode(false, null, true);
185             }
186
187             this._oldStartTime = this.startTime;
188             this._oldEndTime = this.endTime;
189         }
190
191         this._processPendingRecords();
192     }
193
194     // Private
195
196     _processPendingRecords()
197     {
198         if (WebInspector.timelineManager.scriptProfilerIsTracking())
199             return;
200
201         if (!this._pendingRecords.length)
202             return;
203
204         let zeroTime = this.zeroTime;
205         let startTime = this.startTime;
206         let endTime = this.endTime;
207
208         for (let scriptTimelineRecord of this._pendingRecords) {
209             let rootNodes = [];
210             if (scriptTimelineRecord.profile) {
211                 // FIXME: Support using the bottom-up tree once it is implemented.
212                 rootNodes = scriptTimelineRecord.profile.topDownRootNodes;
213             }
214
215             let dataGridNode = new WebInspector.ScriptTimelineDataGridNode(scriptTimelineRecord, zeroTime);
216             this._dataGrid.addRowInSortOrder(null, dataGridNode);
217
218             for (let profileNode of rootNodes) {
219                 let profileNodeDataGridNode = new WebInspector.ProfileNodeDataGridNode(profileNode, zeroTime, startTime, endTime);
220                 this._dataGrid.addRowInSortOrder(null, profileNodeDataGridNode, dataGridNode);
221             }
222         }
223
224         this._pendingRecords = [];
225     }
226
227     _scriptTimelineRecordAdded(event)
228     {
229         var scriptTimelineRecord = event.data.record;
230         console.assert(scriptTimelineRecord instanceof WebInspector.ScriptTimelineRecord);
231
232         this._pendingRecords.push(scriptTimelineRecord);
233
234         this.needsLayout();
235     }
236
237     _scriptTimelineRecordRefreshed(event)
238     {
239         this.needsLayout();
240     }
241
242     _dataGridFiltersDidChange(event)
243     {
244         // FIXME: <https://webkit.org/b/154924> Web Inspector: hook up grid row filtering in the new Timelines UI
245     }
246
247     _dataGridNodeSelected(event)
248     {
249         this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
250     }
251 };