moved to root
This commit is contained in:
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2015 University of Washington.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
WI.TimelineView = class TimelineView extends WI.ContentView
|
||||
{
|
||||
constructor(representedObject)
|
||||
{
|
||||
super(representedObject);
|
||||
|
||||
// This class should not be instantiated directly. Create a concrete subclass instead.
|
||||
console.assert(this.constructor !== WI.TimelineView && this instanceof WI.TimelineView);
|
||||
console.assert(this.constructor.ReferencePage, this);
|
||||
|
||||
this.element.classList.add("timeline-view");
|
||||
|
||||
this._zeroTime = 0;
|
||||
this._startTime = 0;
|
||||
this._endTime = 5;
|
||||
this._currentTime = 0;
|
||||
}
|
||||
|
||||
// Public
|
||||
|
||||
get scrollableElements()
|
||||
{
|
||||
if (!this._timelineDataGrid)
|
||||
return [];
|
||||
return [this._timelineDataGrid.scrollContainer];
|
||||
}
|
||||
|
||||
get showsLiveRecordingData()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return true;
|
||||
}
|
||||
|
||||
get showsImportedRecordingMessage()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return false;
|
||||
}
|
||||
|
||||
get showsFilterBar()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return true;
|
||||
}
|
||||
|
||||
get navigationItems()
|
||||
{
|
||||
return this._scopeBar ? [this._scopeBar] : [];
|
||||
}
|
||||
|
||||
get selectionPathComponents()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return null;
|
||||
}
|
||||
|
||||
get zeroTime()
|
||||
{
|
||||
return this._zeroTime;
|
||||
}
|
||||
|
||||
set zeroTime(x)
|
||||
{
|
||||
x = x || 0;
|
||||
|
||||
if (this._zeroTime === x)
|
||||
return;
|
||||
|
||||
this._zeroTime = x;
|
||||
|
||||
this._timesDidChange();
|
||||
}
|
||||
|
||||
get startTime()
|
||||
{
|
||||
return this._startTime;
|
||||
}
|
||||
|
||||
set startTime(x)
|
||||
{
|
||||
x = x || 0;
|
||||
|
||||
if (this._startTime === x)
|
||||
return;
|
||||
|
||||
this._startTime = x;
|
||||
|
||||
this._timesDidChange();
|
||||
this._scheduleFilterDidChange();
|
||||
}
|
||||
|
||||
get endTime()
|
||||
{
|
||||
return this._endTime;
|
||||
}
|
||||
|
||||
set endTime(x)
|
||||
{
|
||||
x = x || 0;
|
||||
|
||||
if (this._endTime === x)
|
||||
return;
|
||||
|
||||
this._endTime = x;
|
||||
|
||||
this._timesDidChange();
|
||||
this._scheduleFilterDidChange();
|
||||
}
|
||||
|
||||
get currentTime()
|
||||
{
|
||||
return this._currentTime;
|
||||
}
|
||||
|
||||
set currentTime(x)
|
||||
{
|
||||
x = x || 0;
|
||||
|
||||
if (this._currentTime === x)
|
||||
return;
|
||||
|
||||
let oldCurrentTime = this._currentTime;
|
||||
|
||||
this._currentTime = x;
|
||||
|
||||
function checkIfLayoutIsNeeded(currentTime)
|
||||
{
|
||||
// Include some wiggle room since the current time markers can be clipped off the ends a bit and still partially visible.
|
||||
const wiggleTime = 0.05; // 50ms
|
||||
return this._startTime - wiggleTime <= currentTime && currentTime <= this._endTime + wiggleTime;
|
||||
}
|
||||
|
||||
if (checkIfLayoutIsNeeded.call(this, oldCurrentTime) || checkIfLayoutIsNeeded.call(this, this._currentTime))
|
||||
this._timesDidChange();
|
||||
}
|
||||
|
||||
get filterStartTime()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return this.startTime;
|
||||
}
|
||||
|
||||
get filterEndTime()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return this.endTime;
|
||||
}
|
||||
|
||||
setupDataGrid(dataGrid)
|
||||
{
|
||||
if (this._timelineDataGrid) {
|
||||
this._timelineDataGrid.filterDelegate = null;
|
||||
this._timelineDataGrid.removeEventListener(WI.DataGrid.Event.SelectedNodeChanged, this._timelineDataGridSelectedNodeChanged, this);
|
||||
this._timelineDataGrid.removeEventListener(WI.DataGrid.Event.NodeWasFiltered, this._timelineDataGridNodeWasFiltered, this);
|
||||
this._timelineDataGrid.removeEventListener(WI.DataGrid.Event.FilterDidChange, this.filterDidChange, this);
|
||||
}
|
||||
|
||||
this._timelineDataGrid = dataGrid;
|
||||
this._timelineDataGrid.filterDelegate = this;
|
||||
this._timelineDataGrid.addEventListener(WI.DataGrid.Event.SelectedNodeChanged, this._timelineDataGridSelectedNodeChanged, this);
|
||||
this._timelineDataGrid.addEventListener(WI.DataGrid.Event.NodeWasFiltered, this._timelineDataGridNodeWasFiltered, this);
|
||||
this._timelineDataGrid.addEventListener(WI.DataGrid.Event.FilterDidChange, this.filterDidChange, this);
|
||||
}
|
||||
|
||||
selectRecord(record)
|
||||
{
|
||||
if (!this._timelineDataGrid)
|
||||
return;
|
||||
|
||||
let selectedDataGridNode = this._timelineDataGrid.selectedNode;
|
||||
if (!record) {
|
||||
if (selectedDataGridNode)
|
||||
selectedDataGridNode.deselect();
|
||||
return;
|
||||
}
|
||||
|
||||
let dataGridNode = this._timelineDataGrid.findNode((node) => node.record === record);
|
||||
console.assert(dataGridNode, "Timeline view has no grid node for record selected in timeline overview.", this, record);
|
||||
if (!dataGridNode || dataGridNode.selected)
|
||||
return;
|
||||
|
||||
// Don't select the record's grid node if one of it's children is already selected.
|
||||
if (selectedDataGridNode && selectedDataGridNode.hasAncestor(dataGridNode))
|
||||
return;
|
||||
|
||||
dataGridNode.revealAndSelect();
|
||||
}
|
||||
|
||||
reset()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
}
|
||||
|
||||
updateFilter(filters)
|
||||
{
|
||||
if (!this._timelineDataGrid)
|
||||
return;
|
||||
|
||||
this._timelineDataGrid.filterText = filters ? filters.text : "";
|
||||
}
|
||||
|
||||
matchDataGridNodeAgainstCustomFilters(node)
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
return true;
|
||||
}
|
||||
|
||||
// DataGrid filter delegate
|
||||
|
||||
dataGridMatchNodeAgainstCustomFilters(node)
|
||||
{
|
||||
console.assert(node);
|
||||
if (!this.matchDataGridNodeAgainstCustomFilters(node))
|
||||
return false;
|
||||
|
||||
let startTime = this.filterStartTime;
|
||||
let endTime = this.filterEndTime;
|
||||
let currentTime = this.currentTime;
|
||||
|
||||
function checkTimeBounds(itemStartTime, itemEndTime)
|
||||
{
|
||||
itemStartTime = itemStartTime || currentTime;
|
||||
itemEndTime = itemEndTime || currentTime;
|
||||
|
||||
return startTime <= itemEndTime && itemStartTime <= endTime;
|
||||
}
|
||||
|
||||
if (node instanceof WI.ResourceTimelineDataGridNode) {
|
||||
let resource = node.resource;
|
||||
return checkTimeBounds(resource.requestSentTimestamp, resource.finishedOrFailedTimestamp);
|
||||
}
|
||||
|
||||
if (node instanceof WI.SourceCodeTimelineTimelineDataGridNode) {
|
||||
let sourceCodeTimeline = node.sourceCodeTimeline;
|
||||
|
||||
// Do a quick check of the timeline bounds before we check each record.
|
||||
if (!checkTimeBounds(sourceCodeTimeline.startTime, sourceCodeTimeline.endTime))
|
||||
return false;
|
||||
|
||||
for (let record of sourceCodeTimeline.records) {
|
||||
if (checkTimeBounds(record.startTime, record.endTime))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node instanceof WI.ProfileNodeDataGridNode) {
|
||||
let profileNode = node.profileNode;
|
||||
if (checkTimeBounds(profileNode.startTime, profileNode.endTime))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node instanceof WI.TimelineDataGridNode) {
|
||||
let record = node.record;
|
||||
return checkTimeBounds(record.startTime, record.endTime);
|
||||
}
|
||||
|
||||
if (node instanceof WI.ProfileDataGridNode)
|
||||
return node.callingContextTreeNode.hasStackTraceInTimeRange(startTime, endTime);
|
||||
|
||||
console.error("Unknown DataGridNode, can't filter by time.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Protected
|
||||
|
||||
initialLayout()
|
||||
{
|
||||
super.initialLayout();
|
||||
|
||||
this.element.appendChild(this.constructor.ReferencePage.createLinkElement());
|
||||
}
|
||||
|
||||
filterDidChange()
|
||||
{
|
||||
// Implemented by sub-classes if needed.
|
||||
}
|
||||
|
||||
// Private
|
||||
|
||||
_timelineDataGridSelectedNodeChanged(event)
|
||||
{
|
||||
this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
|
||||
}
|
||||
|
||||
_timelineDataGridNodeWasFiltered(event)
|
||||
{
|
||||
let node = event.data.node;
|
||||
if (!(node instanceof WI.TimelineDataGridNode))
|
||||
return;
|
||||
|
||||
this.dispatchEventToListeners(WI.TimelineView.Event.RecordWasFiltered, {record: node.record, filtered: node.hidden});
|
||||
}
|
||||
|
||||
_timesDidChange()
|
||||
{
|
||||
if (!WI.timelineManager.isCapturing() || this.showsLiveRecordingData)
|
||||
this.needsLayout();
|
||||
}
|
||||
|
||||
_scheduleFilterDidChange()
|
||||
{
|
||||
if (!this._timelineDataGrid || this._updateFilterTimeout)
|
||||
return;
|
||||
|
||||
this._updateFilterTimeout = setTimeout(() => {
|
||||
this._updateFilterTimeout = undefined;
|
||||
this._timelineDataGrid.filterDidChange();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
WI.TimelineView.Event = {
|
||||
RecordWasFiltered: "timeline-view-record-was-filtered",
|
||||
RecordWasSelected: "timeline-view-record-was-selected",
|
||||
ScannerShow: "timeline-view-scanner-show",
|
||||
ScannerHide: "timeline-view-scanner-hide",
|
||||
NeedsEntireSelectedRange: "timeline-view-needs-entire-selected-range",
|
||||
NeedsFiltersCleared: "timeline-view-needs-filters-cleared",
|
||||
};
|
||||
Reference in New Issue
Block a user