summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js305
1 files changed, 305 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js b/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js
new file mode 100644
index 000000000..ed888b9e0
--- /dev/null
+++ b/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+WebInspector.OverviewTimelineView = class OverviewTimelineView extends WebInspector.TimelineView
+{
+ constructor(recording, extraArguments)
+ {
+ super(recording, extraArguments);
+
+ this._recording = recording;
+
+ let columns = {name: {}, graph: {}};
+
+ columns.name.title = WebInspector.UIString("Name");
+ columns.name.width = "20%";
+ columns.name.icon = true;
+ columns.name.disclosure = true;
+
+ this._timelineRuler = new WebInspector.TimelineRuler;
+ this._timelineRuler.allowsClippedLabels = true;
+
+ columns.graph.width = "80%";
+ columns.graph.headerView = this._timelineRuler;
+
+ this._dataGrid = new WebInspector.DataGrid(columns);
+
+ this.setupDataGrid(this._dataGrid);
+
+ this._currentTimeMarker = new WebInspector.TimelineMarker(0, WebInspector.TimelineMarker.Type.CurrentTime);
+ this._timelineRuler.addMarker(this._currentTimeMarker);
+
+ this.element.classList.add("overview");
+ this.addSubview(this._dataGrid);
+
+ this._networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network);
+ if (this._networkTimeline)
+ this._networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this);
+
+ recording.addEventListener(WebInspector.TimelineRecording.Event.SourceCodeTimelineAdded, this._sourceCodeTimelineAdded, this);
+ recording.addEventListener(WebInspector.TimelineRecording.Event.MarkerAdded, this._markerAdded, this);
+ recording.addEventListener(WebInspector.TimelineRecording.Event.Reset, this._recordingReset, this);
+
+ this._pendingRepresentedObjects = [];
+ this._resourceDataGridNodeMap = new Map;
+ }
+
+ // Public
+
+ get secondsPerPixel()
+ {
+ return this._timelineRuler.secondsPerPixel;
+ }
+
+ set secondsPerPixel(x)
+ {
+ this._timelineRuler.secondsPerPixel = x;
+ }
+
+ shown()
+ {
+ super.shown();
+
+ this._timelineRuler.updateLayout(WebInspector.View.LayoutReason.Resize);
+ }
+
+ closed()
+ {
+ if (this._networkTimeline)
+ this._networkTimeline.removeEventListener(null, null, this);
+ this._recording.removeEventListener(null, null, this);
+ }
+
+ get selectionPathComponents()
+ {
+ let dataGridNode = this._dataGrid.selectedNode;
+ if (!dataGridNode || dataGridNode.hidden)
+ return null;
+
+ let pathComponents = [];
+
+ while (dataGridNode && !dataGridNode.root) {
+ console.assert(dataGridNode instanceof WebInspector.TimelineDataGridNode);
+ if (dataGridNode.hidden)
+ return null;
+
+ let pathComponent = new WebInspector.TimelineDataGridNodePathComponent(dataGridNode);
+ pathComponent.addEventListener(WebInspector.HierarchicalPathComponent.Event.SiblingWasSelected, this.dataGridNodePathComponentSelected, this);
+ pathComponents.unshift(pathComponent);
+ dataGridNode = dataGridNode.parent;
+ }
+
+ return pathComponents;
+ }
+
+ reset()
+ {
+ super.reset();
+
+ this._dataGrid.removeChildren();
+
+ this._pendingRepresentedObjects = [];
+ }
+
+ // Protected
+
+ dataGridNodePathComponentSelected(event)
+ {
+ let dataGridNode = event.data.pathComponent.timelineDataGridNode;
+ console.assert(dataGridNode.dataGrid === this._dataGrid);
+
+ dataGridNode.revealAndSelect();
+ }
+
+ layout()
+ {
+ let oldZeroTime = this._timelineRuler.zeroTime;
+ let oldStartTime = this._timelineRuler.startTime;
+ let oldEndTime = this._timelineRuler.endTime;
+ let oldCurrentTime = this._currentTimeMarker.time;
+
+ this._timelineRuler.zeroTime = this.zeroTime;
+ this._timelineRuler.startTime = this.startTime;
+ this._timelineRuler.endTime = this.endTime;
+ this._currentTimeMarker.time = this.currentTime;
+
+ // The TimelineDataGridNode graphs are positioned with percentages, so they auto resize with the view.
+ // We only need to refresh the graphs when the any of the times change.
+ if (this.zeroTime !== oldZeroTime || this.startTime !== oldStartTime || this.endTime !== oldEndTime || this.currentTime !== oldCurrentTime) {
+ let dataGridNode = this._dataGrid.children[0];
+ while (dataGridNode) {
+ dataGridNode.refreshGraph();
+ dataGridNode = dataGridNode.traverseNextNode(true, null, true);
+ }
+ }
+
+ this._processPendingRepresentedObjects();
+ }
+
+ // Private
+
+ _compareDataGridNodesByStartTime(a, b)
+ {
+ function getStartTime(dataGridNode)
+ {
+ if (dataGridNode instanceof WebInspector.ResourceTimelineDataGridNode)
+ return dataGridNode.resource.firstTimestamp;
+ if (dataGridNode instanceof WebInspector.SourceCodeTimelineTimelineDataGridNode)
+ return dataGridNode.sourceCodeTimeline.startTime;
+
+ console.error("Unknown data grid node.", dataGridNode);
+ return 0;
+ }
+
+ let result = getStartTime(a) - getStartTime(b);
+ if (result)
+ return result;
+
+ // Fallback to comparing titles.
+ return a.displayName().localeCompare(b.displayName());
+ }
+
+ _insertDataGridNode(dataGridNode, parentDataGridNode)
+ {
+ console.assert(dataGridNode);
+ console.assert(!dataGridNode.parent);
+
+ if (parentDataGridNode)
+ parentDataGridNode.insertChild(dataGridNode, insertionIndexForObjectInListSortedByFunction(dataGridNode, parentDataGridNode.children, this._compareDataGridNodesByStartTime.bind(this)));
+ else
+ this._dataGrid.appendChild(dataGridNode);
+ }
+
+ _addResourceToDataGridIfNeeded(resource)
+ {
+ console.assert(resource);
+ if (!resource)
+ return null;
+
+ // FIXME: replace with this._dataGrid.findDataGridNode(resource) once <https://webkit.org/b/155305> is fixed.
+ let dataGridNode = this._resourceDataGridNodeMap.get(resource);
+ if (dataGridNode)
+ return dataGridNode;
+
+ let parentFrame = resource.parentFrame;
+ if (!parentFrame)
+ return null;
+
+ let resourceTimelineRecord = this._networkTimeline ? this._networkTimeline.recordForResource(resource) : null;
+ if (!resourceTimelineRecord)
+ resourceTimelineRecord = new WebInspector.ResourceTimelineRecord(resource);
+
+ const includesGraph = true;
+ const shouldShowPopover = false;
+ let resourceDataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, includesGraph, this, shouldShowPopover);
+ this._resourceDataGridNodeMap.set(resource, resourceDataGridNode);
+
+ let expandedByDefault = false;
+ if (parentFrame.mainResource === resource || parentFrame.provisionalMainResource === resource) {
+ parentFrame = parentFrame.parentFrame;
+ expandedByDefault = !parentFrame; // Main frame expands by default.
+ }
+
+ if (expandedByDefault)
+ resourceDataGridNode.expand();
+
+ let parentDataGridNode = null;
+ if (parentFrame) {
+ // Find the parent main resource, adding it if needed, to append this resource as a child.
+ let parentResource = parentFrame.provisionalMainResource || parentFrame.mainResource;
+
+ parentDataGridNode = this._addResourceToDataGridIfNeeded(parentResource);
+ console.assert(parentDataGridNode);
+ if (!parentDataGridNode)
+ return null;
+ }
+
+ this._insertDataGridNode(resourceDataGridNode, parentDataGridNode);
+
+ return resourceDataGridNode;
+ }
+
+ _addSourceCodeTimeline(sourceCodeTimeline)
+ {
+ let parentDataGridNode = sourceCodeTimeline.sourceCodeLocation ? this._addResourceToDataGridIfNeeded(sourceCodeTimeline.sourceCode) : null;
+ let sourceCodeTimelineDataGridNode = new WebInspector.SourceCodeTimelineTimelineDataGridNode(sourceCodeTimeline, this);
+ this._resourceDataGridNodeMap.set(sourceCodeTimeline, sourceCodeTimelineDataGridNode);
+
+ this._insertDataGridNode(sourceCodeTimelineDataGridNode, parentDataGridNode);
+ }
+
+ _processPendingRepresentedObjects()
+ {
+ if (!this._pendingRepresentedObjects.length)
+ return;
+
+ for (var representedObject of this._pendingRepresentedObjects) {
+ if (representedObject instanceof WebInspector.Resource)
+ this._addResourceToDataGridIfNeeded(representedObject);
+ else if (representedObject instanceof WebInspector.SourceCodeTimeline)
+ this._addSourceCodeTimeline(representedObject);
+ else
+ console.error("Unknown represented object");
+ }
+
+ this._pendingRepresentedObjects = [];
+ }
+
+ _networkTimelineRecordAdded(event)
+ {
+ var resourceTimelineRecord = event.data.record;
+ console.assert(resourceTimelineRecord instanceof WebInspector.ResourceTimelineRecord);
+
+ this._pendingRepresentedObjects.push(resourceTimelineRecord.resource);
+
+ this.needsLayout();
+
+ // We don't expect to have any source code timelines yet. Those should be added with _sourceCodeTimelineAdded.
+ console.assert(!this._recording.sourceCodeTimelinesForSourceCode(resourceTimelineRecord.resource).length);
+ }
+
+ _sourceCodeTimelineAdded(event)
+ {
+ var sourceCodeTimeline = event.data.sourceCodeTimeline;
+ console.assert(sourceCodeTimeline);
+ if (!sourceCodeTimeline)
+ return;
+
+ this._pendingRepresentedObjects.push(sourceCodeTimeline);
+
+ this.needsLayout();
+ }
+
+ _markerAdded(event)
+ {
+ this._timelineRuler.addMarker(event.data.marker);
+ }
+
+ _recordingReset(event)
+ {
+ this._timelineRuler.clearMarkers();
+ this._timelineRuler.addMarker(this._currentTimeMarker);
+ }
+};