1/*
2 * Copyright (C) 2013 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
26WebInspector.TimelineView = function()
27{
28    WebInspector.Object.call(this);
29
30    this._contentTreeOutline = WebInspector.timelineSidebarPanel.createContentTreeOutline();
31
32    this.element = document.createElement("div");
33    this.element.classList.add(WebInspector.TimelineView.StyleClassName);
34
35    this._zeroTime = 0;
36    this._startTime = 0;
37    this._endTime = 5;
38    this._currentTime = 0;
39};
40
41WebInspector.TimelineView.StyleClassName = "timeline-view";
42
43WebInspector.TimelineView.Event = {
44    SelectionPathComponentsDidChange: "timeline-view-selection-path-components-did-change"
45};
46
47WebInspector.TimelineView.prototype = {
48    constructor: WebInspector.TimelineView,
49    __proto__: WebInspector.Object.prototype,
50
51    // Public
52
53    get navigationSidebarTreeOutline()
54    {
55        return this._contentTreeOutline;
56    },
57
58    get navigationSidebarTreeOutlineLabel()
59    {
60        // Implemented by sub-classes if needed.
61        return null;
62    },
63
64    get selectionPathComponents()
65    {
66        if (!this._contentTreeOutline.selectedTreeElement || this._contentTreeOutline.selectedTreeElement.hidden)
67            return null;
68
69        var pathComponent = new WebInspector.GeneralTreeElementPathComponent(this._contentTreeOutline.selectedTreeElement);
70        pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.treeElementPathComponentSelected, this);
71        return [pathComponent];
72    },
73
74    get zeroTime()
75    {
76        return this._zeroTime;
77    },
78
79    set zeroTime(x)
80    {
81        if (this._zeroTime === x)
82            return;
83
84        this._zeroTime = x || 0;
85
86        this.needsLayout();
87    },
88
89    get startTime()
90    {
91        return this._startTime;
92    },
93
94    set startTime(x)
95    {
96        if (this._startTime === x)
97            return;
98
99        this._startTime = x || 0;
100
101        this.needsLayout();
102    },
103
104    get endTime()
105    {
106        return this._endTime;
107    },
108
109    set endTime(x)
110    {
111        if (this._endTime === x)
112            return;
113
114        this._endTime = x || 0;
115
116        this.needsLayout();
117    },
118
119    get currentTime()
120    {
121        return this._currentTime;
122    },
123
124    set currentTime(x)
125    {
126        if (this._currentTime === x)
127            return;
128
129        var oldCurrentTime = this._currentTime;
130
131        this._currentTime = x || 0;
132
133        function checkIfLayoutIsNeeded(currentTime)
134        {
135            // Include some wiggle room since the current time markers can be clipped off the ends a bit and still partially visible.
136            const wiggleTime = 0.05; // 50ms
137            return this._startTime - wiggleTime <= currentTime && currentTime <= this._endTime + wiggleTime;
138        }
139
140        if (checkIfLayoutIsNeeded.call(this, oldCurrentTime) || checkIfLayoutIsNeeded.call(this, this._currentTime))
141            this.needsLayout();
142    },
143
144    get visible()
145    {
146        return this._visible;
147    },
148
149    reset: function()
150    {
151        this._contentTreeOutline.removeChildren();
152    },
153
154    shown: function()
155    {
156        this._visible = true;
157
158        // Implemented by sub-classes if needed.
159    },
160
161    hidden: function()
162    {
163        // Implemented by sub-classes if needed.
164
165        this._visible = false;
166    },
167
168    matchTreeElementAgainstCustomFilters: function(treeElement)
169    {
170        // Implemented by sub-classes if needed.
171        return true;
172    },
173
174    updateLayout: function()
175    {
176        if (this._scheduledLayoutUpdateIdentifier) {
177            cancelAnimationFrame(this._scheduledLayoutUpdateIdentifier);
178            delete this._scheduledLayoutUpdateIdentifier;
179        }
180
181        // Implemented by sub-classes if needed.
182    },
183
184    updateLayoutIfNeeded: function()
185    {
186        if (!this._scheduledLayoutUpdateIdentifier)
187            return;
188        this.updateLayout();
189    },
190
191    // Protected
192
193    treeElementPathComponentSelected: function(event)
194    {
195        // Implemented by sub-classes if needed.
196    },
197
198    needsLayout: function()
199    {
200        if (!this._visible)
201            return;
202
203        if (this._scheduledLayoutUpdateIdentifier)
204            return;
205
206        this._scheduledLayoutUpdateIdentifier = requestAnimationFrame(this.updateLayout.bind(this));
207    }
208};
209