Web Inspector: Elements: Styles: add icons for various CSS rule types
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / ScriptProfileTimelineView.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 WI.ScriptProfileTimelineView = class ScriptProfileTimelineView extends WI.TimelineView
27 {
28     constructor(timeline, extraArguments)
29     {
30         super(timeline, extraArguments);
31
32         console.assert(timeline.type === WI.TimelineRecord.Type.Script);
33
34         this.element.classList.add("script");
35
36         this._recording = extraArguments.recording;
37
38         this._forceNextLayout = false;
39         this._lastLayoutStartTime = undefined;
40         this._lastLayoutEndTime = undefined;
41
42         this._sharedProfileViewData = {
43             selectedNodeHash: null,
44         };
45
46         if (!WI.ScriptProfileTimelineView.profileOrientationSetting)
47             WI.ScriptProfileTimelineView.profileOrientationSetting = new WI.Setting("script-profile-timeline-view-profile-orientation-setting", WI.ScriptProfileTimelineView.ProfileOrientation.TopDown);
48         if (!WI.ScriptProfileTimelineView.profileTypeSetting)
49             WI.ScriptProfileTimelineView.profileTypeSetting = new WI.Setting("script-profile-timeline-view-profile-type-setting", WI.ScriptProfileTimelineView.ProfileViewType.Hierarchy);
50
51         this._showProfileViewForOrientation(WI.ScriptProfileTimelineView.profileOrientationSetting.value, WI.ScriptProfileTimelineView.profileTypeSetting.value);
52
53         let clearTooltip = WI.UIString("Clear focus");
54         this._clearFocusNodesButtonItem = new WI.ButtonNavigationItem("clear-profile-focus", clearTooltip, "Images/Close.svg", 16, 16);
55         this._clearFocusNodesButtonItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._clearFocusNodes, this);
56         this._updateClearFocusNodesButtonItem();
57
58         this._profileOrientationButton = new WI.TextToggleButtonNavigationItem("profile-orientation", WI.UIString("Inverted"));
59         this._profileOrientationButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._profileOrientationButtonClicked, this);
60         if (WI.ScriptProfileTimelineView.profileOrientationSetting.value === WI.ScriptProfileTimelineView.ProfileOrientation.TopDown)
61             this._profileOrientationButton.activated = false;
62         else
63             this._profileOrientationButton.activated = true;
64
65         this._topFunctionsButton = new WI.TextToggleButtonNavigationItem("top-functions", WI.UIString("Top Functions"));
66         this._topFunctionsButton.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._topFunctionsButtonClicked, this);
67         if (WI.ScriptProfileTimelineView.profileTypeSetting.value === WI.ScriptProfileTimelineView.ProfileViewType.Hierarchy)
68             this._topFunctionsButton.activated = false;
69         else
70             this._topFunctionsButton.activated = true;
71
72         timeline.addEventListener(WI.Timeline.Event.Refreshed, this._scriptTimelineRecordRefreshed, this);
73     }
74
75     // Public
76
77     get scrollableElements() { return this._profileView.scrollableElements; }
78
79     get showsLiveRecordingData() { return false; }
80
81     // Protected
82
83     closed()
84     {
85         console.assert(this.representedObject instanceof WI.Timeline);
86         this.representedObject.removeEventListener(null, null, this);
87     }
88
89     get navigationItems()
90     {
91         return [this._clearFocusNodesButtonItem, this._profileOrientationButton, this._topFunctionsButton];
92     }
93
94     get selectionPathComponents()
95     {
96         return this._profileView.selectionPathComponents;
97     }
98
99     layout()
100     {
101         if (!this._forceNextLayout && (this._lastLayoutStartTime === this.startTime && this._lastLayoutEndTime === this.endTime))
102             return;
103
104         this._forceNextLayout = false;
105         this._lastLayoutStartTime = this.startTime;
106         this._lastLayoutEndTime = this.endTime;
107
108         this._profileView.setStartAndEndTime(this.startTime, this.endTime);
109     }
110
111     // Private
112
113     _callingContextTreeForOrientation(profileOrientation, profileViewType)
114     {
115         switch (profileOrientation) {
116         case WI.ScriptProfileTimelineView.ProfileOrientation.TopDown:
117             return profileViewType === WI.ScriptProfileTimelineView.ProfileViewType.Hierarchy ? this._recording.topDownCallingContextTree : this._recording.topFunctionsTopDownCallingContextTree;
118         case WI.ScriptProfileTimelineView.ProfileOrientation.BottomUp:
119             return profileViewType === WI.ScriptProfileTimelineView.ProfileViewType.Hierarchy ? this._recording.bottomUpCallingContextTree : this._recording.topFunctionsBottomUpCallingContextTree;
120         }
121
122         console.assert(false, "Should not be reached.");
123         return this._recording.topDownCallingContextTree;
124     }
125
126     _profileViewSelectionPathComponentsDidChange(event)
127     {
128         this._updateClearFocusNodesButtonItem();
129         this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
130     }
131
132     _scriptTimelineRecordRefreshed(event)
133     {
134         this._forceNextLayout = true;
135         this.needsLayout();
136     }
137
138     _profileOrientationButtonClicked()
139     {
140         this._profileOrientationButton.activated = !this._profileOrientationButton.activated;
141         let isInverted = this._profileOrientationButton.activated;
142         let newOrientation;
143         if (isInverted)
144             newOrientation = WI.ScriptProfileTimelineView.ProfileOrientation.BottomUp;
145         else
146             newOrientation = WI.ScriptProfileTimelineView.ProfileOrientation.TopDown;
147
148         WI.ScriptProfileTimelineView.profileOrientationSetting.value = newOrientation;
149         this._showProfileViewForOrientation(newOrientation, WI.ScriptProfileTimelineView.profileTypeSetting.value);
150
151         this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
152
153         this._forceNextLayout = true;
154         this.needsLayout();
155     }
156
157     _topFunctionsButtonClicked()
158     {
159         this._topFunctionsButton.activated = !this._topFunctionsButton.activated;
160         let isTopFunctionsEnabled = this._topFunctionsButton.activated;
161         let newOrientation;
162         if (isTopFunctionsEnabled)
163             newOrientation = WI.ScriptProfileTimelineView.ProfileViewType.TopFunctions;
164         else
165             newOrientation = WI.ScriptProfileTimelineView.ProfileViewType.Hierarchy;
166
167         WI.ScriptProfileTimelineView.profileTypeSetting.value = newOrientation;
168         this._showProfileViewForOrientation(WI.ScriptProfileTimelineView.profileOrientationSetting.value, newOrientation);
169
170         this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
171
172         this._forceNextLayout = true;
173         this.needsLayout();
174     }
175
176     _showProfileViewForOrientation(profileOrientation, profileViewType)
177     {
178         let filterText;
179         if (this._profileView) {
180             this._profileView.removeEventListener(WI.ContentView.Event.SelectionPathComponentsDidChange, this._profileViewSelectionPathComponentsDidChange, this);
181             this.removeSubview(this._profileView);
182             filterText = this._profileView.dataGrid.filterText;
183         }
184
185         let callingContextTree = this._callingContextTreeForOrientation(profileOrientation, profileViewType);
186         this._profileView = new WI.ProfileView(callingContextTree, this._sharedProfileViewData);
187         this._profileView.addEventListener(WI.ContentView.Event.SelectionPathComponentsDidChange, this._profileViewSelectionPathComponentsDidChange, this);
188
189         this.addSubview(this._profileView);
190         this.setupDataGrid(this._profileView.dataGrid);
191
192         if (filterText)
193             this._profileView.dataGrid.filterText = filterText;
194     }
195
196     _updateClearFocusNodesButtonItem()
197     {
198         this._clearFocusNodesButtonItem.enabled = this._profileView.hasFocusNodes();
199     }
200
201     _clearFocusNodes()
202     {
203         this._profileView.clearFocusNodes();
204     }
205 };
206
207 WI.ScriptProfileTimelineView.ProfileOrientation = {
208     BottomUp: "bottom-up",
209     TopDown: "top-down",
210 };
211
212 WI.ScriptProfileTimelineView.ProfileViewType = {
213     Hierarchy: "hierarchy",
214     TopFunctions: "top-functions",
215 };