Web Inspector: scrolled Snapshot list is reset to top and drawn blank after switching...
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ScriptClusterTimelineView.js
1 /*
2  * Copyright (C) 2016 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.ScriptClusterTimelineView = class ScriptClusterTimelineView extends WebInspector.ClusterContentView
27 {
28     constructor(timeline, extraArguments)
29     {
30         super(timeline);
31
32         console.assert(timeline.type === WebInspector.TimelineRecord.Type.Script);
33
34         this._currentContentViewSetting = new WebInspector.Setting("script-cluster-timeline-view-current-view", WebInspector.ScriptClusterTimelineView.EventsIdentifier);
35
36         let showSelectorArrows = this._canShowProfileView();
37         function createPathComponent(displayName, className, identifier)
38         {
39             let pathComponent = new WebInspector.HierarchicalPathComponent(displayName, className, identifier, false, showSelectorArrows);
40             pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this._pathComponentSelected, this);
41             return pathComponent;
42         }
43
44         this._eventsPathComponent = createPathComponent.call(this, WebInspector.UIString("Events"), "events-icon", WebInspector.ScriptClusterTimelineView.EventsIdentifier);
45         this._profilePathComponent = createPathComponent.call(this, WebInspector.UIString("Call Trees"), "call-trees-icon", WebInspector.ScriptClusterTimelineView.ProfileIdentifier);
46
47         if (this._canShowProfileView()) {
48             this._eventsPathComponent.nextSibling = this._profilePathComponent;
49             this._profilePathComponent.previousSibling = this._eventsPathComponent;
50         }
51
52         // FIXME: We should be able to create these lazily.
53         this._eventsContentView = new WebInspector.ScriptDetailsTimelineView(this.representedObject, extraArguments);
54         this._profileContentView = this._canShowProfileView() ? new WebInspector.ScriptProfileTimelineView(this.representedObject, extraArguments) : null;
55
56         this._showContentViewForIdentifier(this._currentContentViewSetting.value);
57
58         this.contentViewContainer.addEventListener(WebInspector.ContentViewContainer.Event.CurrentContentViewDidChange, this._scriptClusterViewCurrentContentViewDidChange, this)
59     }
60
61     // TimelineView
62
63     // FIXME: Determine a better way to bridge TimelineView methods to the sub-timeline views.
64     get showsLiveRecordingData() { return this._contentViewContainer.currentContentView.showsLiveRecordingData; }
65     get showsFilterBar() { return this._contentViewContainer.currentContentView.showsFilterBar; }
66     get zeroTime() { return this._contentViewContainer.currentContentView.zeroTime; }
67     set zeroTime(x) { this._contentViewContainer.currentContentView.zeroTime = x; }
68     get startTime() { return this._contentViewContainer.currentContentView.startTime; }
69     set startTime(x) { this._contentViewContainer.currentContentView.startTime = x; }
70     get endTime() { return this._contentViewContainer.currentContentView.endTime; }
71     set endTime(x) { this._contentViewContainer.currentContentView.endTime = x; }
72     get currentTime() { return this._contentViewContainer.currentContentView.currentTime; }
73     set currentTime(x) { this._contentViewContainer.currentContentView.currentTime = x; }
74     selectRecord(record) { this._contentViewContainer.currentContentView.selectRecord(record); }
75     updateFilter(filters) { return this._contentViewContainer.currentContentView.updateFilter(filters); }
76     filterDidChange() { return this._contentViewContainer.currentContentView.filterDidChange(); }
77     matchDataGridNodeAgainstCustomFilters(node) { return this._contentViewContainer.currentContentView.matchDataGridNodeAgainstCustomFilters(node); }
78
79     reset()
80     {
81         this._eventsContentView.reset();
82
83         if (this._profileContentView)
84             this._profileContentView.reset();
85     }
86
87     // Public
88
89     get eventsContentView()
90     {
91         return this._eventsContentView;
92     }
93
94     get profileContentView()
95     {
96         return this._profileContentView;
97     }
98
99     get selectionPathComponents()
100     {
101         let currentContentView = this._contentViewContainer.currentContentView;
102         if (!currentContentView)
103             return [];
104
105         let components = [this._pathComponentForContentView(currentContentView)];
106         let subComponents = currentContentView.selectionPathComponents;
107         if (subComponents)
108             return components.concat(subComponents);
109         return components;
110     }
111
112     saveToCookie(cookie)
113     {
114         cookie[WebInspector.ScriptClusterTimelineView.ContentViewIdentifierCookieKey] = this._currentContentViewSetting.value;
115     }
116
117     restoreFromCookie(cookie)
118     {
119         this._showContentViewForIdentifier(cookie[WebInspector.ScriptClusterTimelineView.ContentViewIdentifierCookieKey]);
120     }
121
122     showEvents()
123     {
124         return this._showContentViewForIdentifier(WebInspector.ScriptClusterTimelineView.EventsIdentifier);
125     }
126
127     showProfile()
128     {
129         if (!this._canShowProfileView())
130             return this.showEvents();
131
132         return this._showContentViewForIdentifier(WebInspector.ScriptClusterTimelineView.ProfileIdentifier);
133     }
134
135     // Private
136
137     _canShowProfileView()
138     {
139         // COMPATIBILITY (iOS 9): Legacy backends did not include CallingContextTree ScriptProfiler data.
140         return window.ScriptProfilerAgent;
141     }
142
143     _pathComponentForContentView(contentView)
144     {
145         console.assert(contentView);
146         if (!contentView)
147             return null;
148         if (contentView === this._eventsContentView)
149             return this._eventsPathComponent;
150         if (contentView === this._profileContentView)
151             return this._profilePathComponent;
152         console.error("Unknown contentView.");
153         return null;
154     }
155
156     _identifierForContentView(contentView)
157     {
158         console.assert(contentView);
159         if (!contentView)
160             return null;
161         if (contentView === this._eventsContentView)
162             return WebInspector.ScriptClusterTimelineView.EventsIdentifier;
163         if (contentView === this._profileContentView)
164             return WebInspector.ScriptClusterTimelineView.ProfileIdentifier;
165         console.error("Unknown contentView.");
166         return null;
167     }
168
169     _showContentViewForIdentifier(identifier)
170     {
171         let contentViewToShow = null;
172
173         switch (identifier) {
174         case WebInspector.ScriptClusterTimelineView.EventsIdentifier:
175             contentViewToShow = this.eventsContentView;
176             break;
177         case WebInspector.ScriptClusterTimelineView.ProfileIdentifier:
178             contentViewToShow = this.profileContentView;
179             break;
180         }
181
182         if (!contentViewToShow)
183             contentViewToShow = this.eventsContentView;
184
185         console.assert(contentViewToShow);
186
187         this._currentContentViewSetting.value = this._identifierForContentView(contentViewToShow);
188
189         return this.contentViewContainer.showContentView(contentViewToShow);
190     }
191
192     _pathComponentSelected(event)
193     {
194         this._showContentViewForIdentifier(event.data.pathComponent.representedObject);
195     }
196
197     _scriptClusterViewCurrentContentViewDidChange(event)
198     {
199         let currentContentView = this._contentViewContainer.currentContentView;
200         if (!currentContentView)
201             return;
202
203         let previousContentView = currentContentView === this._eventsContentView ? this._profileContentView : this._eventsContentView;
204
205         currentContentView.zeroTime = previousContentView.zeroTime;
206         currentContentView.startTime = previousContentView.startTime;
207         currentContentView.endTime = previousContentView.endTime;
208         currentContentView.currentTime = previousContentView.currentTime;
209     }
210 };
211
212 WebInspector.ScriptClusterTimelineView.ContentViewIdentifierCookieKey = "script-cluster-timeline-view-identifier";
213
214 WebInspector.ScriptClusterTimelineView.EventsIdentifier = "events";
215 WebInspector.ScriptClusterTimelineView.ProfileIdentifier = "profile";