f211e3952aac0d61dd2ab7be70eb0f98a32c8234
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / TimelineView.js
1 /*
2  * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
3  * Copyright (C) 2015 University of Washington.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 WebInspector.TimelineView = class TimelineView extends WebInspector.ContentView
28 {
29     constructor(representedObject)
30     {
31         super(representedObject);
32
33         // This class should not be instantiated directly. Create a concrete subclass instead.
34         console.assert(this.constructor !== WebInspector.TimelineView && this instanceof WebInspector.TimelineView);
35
36         this.element.classList.add("timeline-view");
37
38         this._zeroTime = 0;
39         this._startTime = 0;
40         this._endTime = 5;
41         this._currentTime = 0;
42     }
43
44     // Public
45
46     get navigationSidebarTreeOutlineScopeBar()
47     {
48         return this._scopeBar;
49     }
50
51     get selectionPathComponents()
52     {
53         // Implemented by sub-classes if needed.
54         return null;
55     }
56
57     get zeroTime()
58     {
59         return this._zeroTime;
60     }
61
62     set zeroTime(x)
63     {
64         x = x || 0;
65
66         if (this._zeroTime === x)
67             return;
68
69         this._zeroTime = x;
70
71         this.needsLayout();
72     }
73
74     get startTime()
75     {
76         return this._startTime;
77     }
78
79     set startTime(x)
80     {
81         x = x || 0;
82
83         if (this._startTime === x)
84             return;
85
86         this._startTime = x;
87
88         this.needsLayout();
89     }
90
91     get endTime()
92     {
93         return this._endTime;
94     }
95
96     set endTime(x)
97     {
98         x = x || 0;
99
100         if (this._endTime === x)
101             return;
102
103         this._endTime = x;
104
105         this.needsLayout();
106     }
107
108     get currentTime()
109     {
110         return this._currentTime;
111     }
112
113     set currentTime(x)
114     {
115         x = x || 0;
116
117         if (this._currentTime === x)
118             return;
119
120         let oldCurrentTime = this._currentTime;
121
122         this._currentTime = x;
123
124         function checkIfLayoutIsNeeded(currentTime)
125         {
126             // Include some wiggle room since the current time markers can be clipped off the ends a bit and still partially visible.
127             const wiggleTime = 0.05; // 50ms
128             return this._startTime - wiggleTime <= currentTime && currentTime <= this._endTime + wiggleTime;
129         }
130
131         if (checkIfLayoutIsNeeded.call(this, oldCurrentTime) || checkIfLayoutIsNeeded.call(this, this._currentTime))
132             this.needsLayout();
133     }
134
135     reset()
136     {
137         // Implemented by sub-classes if needed.
138     }
139
140     filterDidChange()
141     {
142         // Implemented by sub-classes if needed.
143     }
144
145     selectRecord(record)
146     {
147         if (!this._timelineDataGrid)
148             return;
149
150         let selectedDataGridNode = this._timelineDataGrid.selectedNode;
151         if (!record) {
152             if (selectedDataGridNode)
153                 selectedDataGridNode.deselect();
154             return;
155         }
156
157         let dataGridNode = this._timelineDataGrid.findNode((node) => node.record === record);
158         console.assert(dataGridNode, "Timeline view has no grid node for record selected in timeline overview.", this, record);
159         if (!dataGridNode || dataGridNode.selected)
160             return;
161
162         // Don't select the record's grid node if one of it's children is already selected.
163         if (selectedDataGridNode && selectedDataGridNode.hasAncestor(dataGridNode))
164             return;
165
166         dataGridNode.revealAndSelect();
167     }
168
169     matchTreeElementAgainstCustomFilters(treeElement)
170     {
171         // Implemented by sub-classes if needed.
172         return true;
173     }
174
175     filterUpdated()
176     {
177         this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
178     }
179
180     needsLayout()
181     {
182         // FIXME: needsLayout can be removed once <https://webkit.org/b/150741> is fixed.
183         if (!this.visible)
184             return;
185
186         super.needsLayout();
187     }
188
189     // Protected
190
191     userSelectedRecordFromOverview(timelineRecord)
192     {
193         // Implemented by sub-classes if needed.
194     }
195 };